// Tests suport for index annotations applied to CharSequence and related indices.

import java.io.IOException;
import java.io.StringWriter;
import org.checkerframework.checker.index.qual.IndexFor;
import org.checkerframework.checker.index.qual.IndexOrHigh;
import org.checkerframework.common.value.qual.MinLen;
import org.checkerframework.common.value.qual.StringVal;

public class CharSequenceTest {
  // Tests that minlen is correctly applied to CharSequence assigned from String, but not
  // StringBuilder
  void minLenCharSequence() {
    @MinLen(10) CharSequence str = "0123456789";
    // :: error: (assignment)
    @MinLen(10) CharSequence sb = new StringBuilder("0123456789");
  }

  // Tests the subSequence method
  void testSubSequence() {
    // Local variable used because of https://github.com/kelloggm/checker-framework/issues/165
    String str = "0123456789";
    str.subSequence(5, 8);
    // :: error: (argument)
    str.subSequence(5, 13);
  }

  // Dummy method that takes a CharSequence and its index
  void sink(CharSequence cs, @IndexOrHigh("#1") int i) {}

  // Tests passing sequences as CharSequence
  void argumentPassing() {
    String s = "0123456789";
    sink(s, 8);
    StringBuilder sb = new StringBuilder("0123456789");
    // :: error: (argument)
    sink(sb, 8);
  }

  // Tests forwardning sequences as CharSequence
  void agumentForwarding(String s, @IndexOrHigh("#1") int i) {
    sink(s, i);
  }

  // Tests concatenation of CharSequence and String
  void concat() {
    CharSequence a = "a";
    @StringVal({"nullb", "ab"}) CharSequence ab = a + "b";
    sink(ab, 2);
  }

  // Tests that length retrieved from CharSequence can be used as an index
  void getLength(CharSequence cs, int i) {
    if (i >= 0 && i < cs.length()) {
      cs.charAt(i);
    }

    @IndexOrHigh("cs") int l = cs.length();
  }

  void testCharAt(CharSequence cs, int i, @IndexFor("#1") int j) {
    cs.charAt(j);
    cs.subSequence(j, j);
    // :: error: (argument)
    cs.charAt(i);
    // :: error: (argument)
    cs.subSequence(i, j);
  }

  void testAppend(Appendable app, CharSequence cs, @IndexFor("#2") int i) throws IOException {
    app.append(cs, i, i);
    // :: error: (argument)
    app.append(cs, 1, 2);
  }

  void testAppend(StringWriter app, CharSequence cs, @IndexFor("#2") int i) throws IOException {
    app.append(cs, i, i);
    // :: error: (argument)
    app.append(cs, 1, 2);
  }
}
