Request for review : 7121314 : Behavior mismatch between AbstractCollection.toArray(T[] ) and its spec

Ulf Zibis Ulf.Zibis at gmx.de
Wed Mar 28 18:48:59 UTC 2012


Hi David, Sean,

I have made little changes to make understanding little easier, see attachment...

-Ulf


Am 28.03.2012 07:29, schrieb David Holmes:
> Hi Ulf,
>
> I understand your point about ensuring we test AbstractCollection.toArray but I find this revised 
> test much harder to understand.
>
> Also in the name setPseudoConcurrentSizeCourse the word "Course" doesn't fit. I'm not sure what 
> you were meaning here? Perhaps just modifySize or emulateConcurrentSizeChange ?
>
> Thanks,
> David
>
-------------- next part --------------
import java.util.*;

/**
 *
 * @author Ulf Zibis
 */
public class TestCollection<E> extends AbstractCollection<E> {

    private static final int[] FIXED_SIZE = new int[1];
    private final E[] elements;
    private int[] sizes;
    private int nextSize;

    public TestCollection(E[] elements) {
        this.elements = elements;
        FIXED_SIZE[0] = elements.length;
        setPseudoConcurrentChronologicalSizeSequence(FIXED_SIZE);
    }

    void setPseudoConcurrentChronologicalSizeSequence(int... sizes) {
        this.sizes = sizes;
        nextSize = 0;
    }

    /** can change collection's size after each invocation */
    @Override
    public int size() {
        return sizes[nextSize == sizes.length-1 ? nextSize : nextSize++];
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int pos = 0;
            public boolean hasNext() {
                return pos < sizes[nextSize];
            }
            public E next() {
                return elements[pos++];
            }
            public void remove() {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
    }
}
-------------- next part --------------
import java.util.*;

/**
 * @test
 * @summary check result, especially if the collection concurrently changes size
 * @bug 7121314
 * @author Ulf Zibis
 */
public class ToArray extends InfraStructure {

    static final Object[] OBJECTS = { new Object(), new Object(), new Object() };
    static final TestCollection<?> CANDIDATE = new TestCollection<Object>(OBJECTS);
    static final int CAP = OBJECTS.length; // capacity of the CANDIDATE
    static final int LAST = CAP - 1; // last possible array index
    Object[] a;
    Object[] res;

    int last() { return a.length - 1; }

    @Override
    protected void test() throws Throwable {
        // Check array type conversion
        res = new TestCollection(new Object[]{"1", "2"}).toArray(new String[0]);
        check(res instanceof String[]);
        check(res.length == 2);
        check(res[1] == "2");

        // Check incompatible type of target array
        try {
            res = CANDIDATE.toArray(new String[CAP]);
            check(false);
        } catch (Throwable t) {
            check(t instanceof ArrayStoreException);
        }

        // Check more elements than a.length
        a = new Object[CAP-1]; // appears too small
        res = CANDIDATE.toArray(a);
        check(res != a);
        check(res[LAST] != null);

        // Check equal elements as a.length
        a = new Object[CAP]; // appears to match
        res = CANDIDATE.toArray(a);
        check(res == a);
        check(res[last()] != null);

        // Check equal elements as a.length
        a = new Object[CAP+1]; // appears too big
        res = CANDIDATE.toArray(a);
        check(res == a);
        check(res[last()] == null);

        // Check less elements than expected, but more than a.length
        a = new Object[CAP-2]; // appears too small
        CANDIDATE.setPseudoConcurrentChronologicalSizeSequence(CAP, CAP-1);
        res = CANDIDATE.toArray(a);
        check(res != a);
        check(res.length == CAP-1);
        check(res[LAST-1] != null);

        // Check less elements than expected, but equal as a.length
        a = Arrays.copyOf(OBJECTS, CAP); // appears to match
        CANDIDATE.setPseudoConcurrentChronologicalSizeSequence(CAP, CAP-1);
        res = CANDIDATE.toArray(a);
        check(res == a);
        check(res[last()] == null);

        // Check more elements than expected and more than a.length
        a = new Object[CAP-1]; // appears to match
        CANDIDATE.setPseudoConcurrentChronologicalSizeSequence(CAP-1, CAP);
        res = CANDIDATE.toArray(a);
        check(res != a);
        check(res[LAST] != null);

        // Check more elements than expected, but equal as a.length
        a = new Object[CAP-1]; // appears to match
        CANDIDATE.setPseudoConcurrentChronologicalSizeSequence(CAP-2, CAP-1);
        res = CANDIDATE.toArray(a);
        check(res == a);
        check(res[last()] != null);

        // Check more elements than expected, but less than a.length
        a = Arrays.copyOf(OBJECTS, CAP); // appears to match
        CANDIDATE.setPseudoConcurrentChronologicalSizeSequence(CAP-2, CAP-1);
        res = CANDIDATE.toArray(a);
        check(res == a);
        check(res[last()] == null);

        test_7121314();
     }

    /**
     * @bug 7121314
     * @summary return the original array if the collection concurrently shrinks and will fit
     */
    protected void test_7121314() throws Throwable {
        // Check equal elements as a.length, but less than expected
        a = new Object[CAP-1]; // appears too small
        CANDIDATE.setPseudoConcurrentChronologicalSizeSequence(CAP, CAP-1);
        res = CANDIDATE.toArray(a);
        check(res == a);
        check(res[last()] != null);

        // Check less elements than a.length and less than expected
        a = Arrays.copyOf(OBJECTS, CAP-1); // appears too small
        CANDIDATE.setPseudoConcurrentChronologicalSizeSequence(CAP, CAP-2);
        res = CANDIDATE.toArray(a);
        check(res == a);
        check(res[last()] == null);
    }

    public static void main(String[] args) throws Throwable {
        run(new ToArray());
    }
}


More information about the core-libs-dev mailing list