<?xml version="1.0" encoding="UTF-8"?>
<test-data
    xmlns="http://pmd.sourceforge.net/rule-tests"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">

    <test-code>
        <description>copy index into array</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar() {
        int[] a = new int[10];
        for (int i=0;i<10;i++) {
            a[i] = i;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>copy one array to another</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>4</expected-linenumbers>
        <code><![CDATA[
public class Foo {
    public void bar(int[] b) {
        int[] a = new int[10];
        for (int i=0;i<10;i++) {
            a[i] = b[i];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>copy via while loop</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>5</expected-linenumbers>
        <code><![CDATA[
public class Foo {
    public void bar(int[] b) {
        int i = 0;
        int[] a = new int[10];
        while (i < 10) {
            a[i] = b[i];
            i++;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>copy via do-while loop #4091</description>
        <expected-problems>1</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar() {
        int i = 0;
        do {
            a[i] = b[i];
            i++;
        } while (i < 10);
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>copy involving multiple arrays is ok</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar(int[] a, int[] b) {
        int[] x = new int[10];
        int[] y = new int[10];
        for (int i = 0; i < 10; i++) {
            x[i] = b[i] + 1;
            y[i] = a[i] + 2;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>copy involving method invocation on array element is ok</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar(int[] b) {
        int[] a = new int[10];
        for (int i=0;i<10;i++) {
            a[i] = b[i].size();
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>using an offset, still bad</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>4</expected-linenumbers>
        <code><![CDATA[
public class Foo {
    public void bar(int[] a) {
        int[] b = new int[10];
        for (int i=0;i<10;i++) {
            b[i]=a[i+6];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>nested arrays on LHS, ok</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar(int[] a, int[] c) {
        int[] b = new int[10];
        for (int i=0;i<10;i++) {
            b[c[i]] = a[i];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>adding to array is ok</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Foo {
    public void bar1() {
        for (int i = 0; i < 10; i++) {
            a[i] += b[i];
        }
    }
    public void bar2() {
        int i = 0;
        for (i = 0; i < 10; i++) {
            a[i] += b[i];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Example code</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>7</expected-linenumbers>
        <code><![CDATA[
public class Test {
    public void bar() {
        int[] a = new int[10];
        int[] b = new int[10];

        // instead of this loop
        for (int i = 0; i < 10; i++) {
            b[i] = a[i];
        }
        // use: System.arraycopy(a, 0, b, 0, 10);

        int[] c = new int[10];
        // this won't trigger the rule
        for (int i = 0; i < 10; i++) {
            b[i] = a[c[i]];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>False positive with calculated array index</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class AvoidArrayLoops {
    public void test() {
        String[] table = new String[10];
        String[] labels = new String[10];
        for (int i = 0; i < 10; i++) {
            table[i] = labels[getIndex()];
        }
    }

    private int getIndex() { return 0; }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>False positive with same array</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class AvoidArrayLoops {
    public void test() {
        String[] array = new String[10];
        for (int i = 0, j = 1; i < 9; i++, j++) {
            array[i] = array[j];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>Correct example - System.arraycopy can be used</description>
        <expected-problems>1</expected-problems>
        <expected-linenumbers>4</expected-linenumbers>
        <code><![CDATA[
public class AvoidArrayLoops {
    public void test(byte[] time) {
        byte[] blob = new byte[time.length + 8];
        for (int i=0; i<time.length; i++) {
            blob[8+time.length-i-1] = time[i];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>False positive with break/continue in loop</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class AvoidArrayLoops {
    public void test(String[] in) {
        String[] array = new String[10];
        for (int i = 0; i < in.length; i++) {
            if (i % 2) {
                continue;
            }
            array[i] = in[i];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>False positive with linked list</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class AvoidArrayLoops {
    public void test(int[] uValues) {
        int[] a = new int[10];
        int headp = 0;
        for (int i = 0; i < uValues.length; i++) {
            int nextp = a[headp];
            a[headp] = uValues[i];
            headp = nextp;
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>False positive with increment by 2</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class AvoidArrayLoops {
    public void test(int[] value) {
        int[] dst = new int[10];
        int dstBegin = 0;
        for (int i = 0; i < value.length; i += 2) {
            dst[dstBegin++] = value[i];
        }
    }
}
        ]]></code>
    </test-code>

    <test-code>
        <description>[java] AvoidArrayLoops false positive on double assignment #1167</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
public class Test {
  public static void main( String[] args ) {
    double[] foo = new double[100];
    double bar = 0.0;
    int[] exps = new int[10];

    for (int i = 0; i < exps.length; i++) {
      double value = Math.random();
      foo[i] = Math.exp(value);
      bar += foo[i];
    }
  }
}
]]></code>
    </test-code>

    <test-code>
        <description>Nested array on RHS</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
class AvoidArrayLoops {
  void copy_a_to_b(int[] a, int[] b) {
        int[] c = new int[10];
        // this will not trigger the rule
        for (int i = 0; i < 10; i++) {
            b[i] = a[c[i]];
        }
  }
}
]]></code>
    </test-code>

    <test-code>
        <description>Ignore multi-dim array assignment #1167</description>
        <expected-problems>0</expected-problems>
        <code><![CDATA[
import java.util.Random;
class AvoidArrayLoops {
    void bar1(int[][] target, int[] source) {
        for (int i = 0; i < 10; i++) {
            for(int j = 0; j < 10; j++) {
                target[i][j] = source[i * 10 + j];
            }
        }
    }
    void bar2(int[][] target, int[] source) {
        for (int i = 0; i < 10; i++) {
            for(int j = 0; j < 10; j++) {
                int sourceIndex = new Random().nextInt(source.length);
                target[i][j] = source[sourceIndex];
            }
        }
    }
}
]]></code>
    </test-code>

    <test-code>
        <description>[java] AvoidArrayLoops should consider final variables #3847</description>
        <expected-problems>3</expected-problems>
        <expected-linenumbers>6,10,13</expected-linenumbers>
        <code><![CDATA[
class AvoidArrayLoops {
    void sample() {
        int[] a = new int[10];
        int[] b = new int[10];
        final int c = 6;
        for (int i = 0; i < 10; i++) {
            b[i] = a[i + c];  // should report a warning at this line
            // b[i] = a[i + 6];  // This line can be detected
        }
        for (int i = 0; i < 10; i++) {
            b[i + c] = a[i];  // should report a warning at this line
        }
        for (int i = 0; i < 10; i++) {
            b[i + c] = a[i + c];  // should report a warning at this line
        }
    }
}
]]></code>
    </test-code>

    <test-code>
        <description>Shifting left and right #2692</description>
        <expected-problems>2</expected-problems>
        <expected-linenumbers>10,20</expected-linenumbers>
        <code><![CDATA[
import java.util.Arrays;
class Scratch {
    public static void main(String[] args) {
        int[] ints;
        ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        System.out.println(Arrays.toString(ints)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

        // shift left
        ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        for (int i = 0; i < ints.length - 1; i++) {
            ints[i] = ints[i + 1];
        }
        System.out.println(Arrays.toString(ints)); // [2, 3, 4, 5, 6, 7, 8, 9, 10, 10]
        ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        System.arraycopy(ints, 1, ints, 0, ints.length - 1);
        System.out.println(Arrays.toString(ints)); // [2, 3, 4, 5, 6, 7, 8, 9, 10, 10]

        // shift right
        ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        for (int i = ints.length - 1; i > 0; i--) {
            ints[i] = ints[i - 1];
        }
        System.out.println(Arrays.toString(ints)); // [1, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        System.arraycopy(ints, 0, ints, 1, ints.length - 1);
        System.out.println(Arrays.toString(ints)); // [1, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    }
}
]]></code>
    </test-code>

    <test-code>
        <description>[java] AvoidArrayLoops regression: from false negative to false positive with final variables #4183</description>
        <expected-problems>3</expected-problems>
        <expected-linenumbers>22,29,38</expected-linenumbers>
        <code><![CDATA[
class AvoidArrayLoopsSamples {
    public static void sample1() {
        final int[] a = new int[10];
        final int[] b = new int[10];
        for (int i = 0; i < 10; i++) { // line 5 - no violation (false positive)
            final int c = i;           // it's final but not a constant during the loop
            b[i] = a[i + c];
        }
    }
    public static void sample2() {
        final int[] a = new int[10];
        final int[] b = new int[10];
        for (int i = 0; i < 10; i++) { // line 13 - no violation (false positive)
            int c = i;                 // not final, not a constant (literal)
            b[i] = a[i + c];
        }
    }
    public static void sample3() {
        final int[] a = new int[10];
        final int[] b = new int[10];
        final int c = 6;
        for (int i = 0; i < 10; i++) { // line 22 - violation
            b[i] = a[i + c];           // using c, which is a final and a constant
        }
    }
    public static void sample4() {
        final int[] a = new int[10];
        final int[] b = new int[10];
        for (int i = 0; i < 10; i++) { // line 29 - violation
            final int c = 6;           // using c, which is a final and a constant
            b[i] = a[i + c];
        }
    }
    private static final int OFFSET = 5;
    public static void sample5() {
        final int[] a = new int[10];
        final int[] b = new int[10];
        for (int i = 0; i < 10; i++) { // line 38 - violation
            b[i] = a[i + OFFSET];      // using OFFSET, a constant field
        }
    }
}
]]></code>
    </test-code>
</test-data>
