import "copyright.stg"
import "primitiveLiteral.stg"

isTest() ::= "true"

targetPath() ::= "org/eclipse/collections/impl/set/mutable/primitive"

fileName(primitive) ::= "<primitive.name>HashSetTest"

class(primitive) ::= <<
<body(primitive.type, primitive.wrapperName, primitive.name, primitive.charPrimitive, primitive.shortPrimitive)>
>>

body(type, wrapperName, name, charPrimitive, shortPrimitive) ::= <<
<copyright()>

package org.eclipse.collections.impl.set.mutable.primitive;

import java.lang.reflect.Field;

import org.eclipse.collections.api.iterator.Mutable<name>Iterator;
import org.eclipse.collections.api.set.primitive.Mutable<name>Set;
import org.eclipse.collections.impl.factory.primitive.<name>Sets;
import org.eclipse.collections.impl.list.mutable.primitive.<name>ArrayList;
import org.eclipse.collections.impl.test.Verify;
import org.junit.Assert;
import org.junit.Test;

/**
 * JUnit test for {@link <name>HashSet}.
 * This file was automatically generated from template file primitiveHashSetTest.stg.
 */
public class <name>HashSetTest extends Abstract<name>SetTestCase
{
    @Override
    protected final <name>HashSet classUnderTest()
    {
        return <name>HashSet.newSetWith(<["1", "2", "3"]:(literal.(type))(); separator=", ">);
    }

    @Override
    protected <name>HashSet newWith(<type>... elements)
    {
        return (<name>HashSet) <name>Sets.mutable.of(elements);
    }

    @Test
    public void defaultInitialCapacity() throws NoSuchFieldException, IllegalAccessException
    {
        Field table = <name>HashSet.class.getDeclaredField("table");
        table.setAccessible(true);
        <name>HashSet hashSet = new <name>HashSet();
        Assert.assertEquals(16L, ((<type>[]) table.get(hashSet)).length);
    }

    @Test
    public void newWithInitialCapacity() throws NoSuchFieldException, IllegalAccessException
    {
        Field table = <name>HashSet.class.getDeclaredField("table");
        table.setAccessible(true);
        <name>HashSet hashSet = new <name>HashSet(3);
        Assert.assertEquals(8L, ((<type>[]) table.get(hashSet)).length);

        <name>HashSet hashSet2 = new <name>HashSet(10);
        Assert.assertEquals(32L, ((<type>[]) table.get(hashSet2)).length);
    }

    @Test(expected = IllegalArgumentException.class)
    public void newWithInitialCapacity_negative_throws()
    {
        new <name>HashSet(-1);
    }

    @Override
    @Test
    public void newCollection()
    {
        super.newCollection();
        <name>HashSet set = <name>HashSet.newSetWith(<["0", "1", "31"]:(literal.(type))(); separator=", ">, Abstract<name>SetTestCase.generateCollisions1().getFirst(), Abstract<name>SetTestCase.generateCollisions1().get(1));
        <name>HashSet hashSetFromList = <name>HashSet.newSet(<name>ArrayList.newListWith(<["0", "0", "1", "31"]:(literal.(type))(); separator=", ">, Abstract<name>SetTestCase.generateCollisions1().getFirst(), Abstract<name>SetTestCase.generateCollisions1().get(1)));
        <name>HashSet hashSetFromSet = <name>HashSet.newSet(set);
        Assert.assertEquals(set, hashSetFromList);
        Assert.assertEquals(set, hashSetFromSet);
    }

    @Test
    public void addAndCheckField() throws NoSuchFieldException, IllegalAccessException
    {
        <name>HashSet hashSet = new <name>HashSet();
        Assert.assertTrue(hashSet.add(<(literal.(type))("14")>));
        Assert.assertFalse(hashSet.add(<(literal.(type))("14")>));
        Assert.assertTrue(hashSet.add(<(literal.(type))("2")>));
        Assert.assertFalse(hashSet.add(<(literal.(type))("2")>));
        Assert.assertTrue(hashSet.add(<(literal.(type))("35")>));
        Assert.assertFalse(hashSet.add(<(literal.(type))("35")>));
        Assert.assertTrue(hashSet.add(<(literal.(type))("31")>));
        Assert.assertFalse(hashSet.add(<(literal.(type))("31")>));
        Assert.assertTrue(hashSet.add(<(literal.(type))("32")>));
        Assert.assertFalse(hashSet.add(<(literal.(type))("32")>));
        Assert.assertTrue(hashSet.add(<(literal.(type))("0")>));
        Assert.assertFalse(hashSet.add(<(literal.(type))("0")>));
        Assert.assertTrue(hashSet.add(<(literal.(type))("1")>));
        Assert.assertFalse(hashSet.add(<(literal.(type))("1")>));
        Field zeroToThirtyOne = <name>HashSet.class.getDeclaredField("zeroToThirtyOne");
        zeroToThirtyOne.setAccessible(true);
        Assert.assertEquals(-2147467257L, ((Integer) zeroToThirtyOne.get(hashSet)).longValue());
        Assert.assertEquals(<name>HashSet.newSetWith(<["14", "2", "31", "32", "35", "0", "1"]:(literal.(type))(); separator=", ">), hashSet);
    }

    @Test
    public void addWithRehash() throws NoSuchFieldException, IllegalAccessException
    {
        <name>HashSet hashSet = new <name>HashSet();
        Assert.assertTrue(hashSet.addAll(<["32", "33", "34", "35", "36", "37", "38", "39"]:(literal.(type))(); separator=", ">));

        Field table = <name>HashSet.class.getDeclaredField("table");
        table.setAccessible(true);
        Assert.assertEquals(16L, ((<type>[]) table.get(hashSet)).length);

        Field occupiedWithData = <name>HashSet.class.getDeclaredField("occupiedWithData");
        Field occupiedWithSentinels = <name>HashSet.class.getDeclaredField("occupiedWithSentinels");
        occupiedWithData.setAccessible(true);
        occupiedWithSentinels.setAccessible(true);
        Assert.assertEquals(8, occupiedWithData.get(hashSet));
        Assert.assertEquals(0, occupiedWithSentinels.get(hashSet));

        Assert.assertEquals(<name>HashSet.newSetWith(<["32", "33", "34", "35", "36", "37", "38", "39"]:(literal.(type))(); separator=", ">), hashSet);

        hashSet.remove(<(literal.(type))("32")>);
        Assert.assertEquals(7, occupiedWithData.get(hashSet));
        Assert.assertEquals(1, occupiedWithSentinels.get(hashSet));

        hashSet.add(<(literal.(type))("32")>); //adding to a REMOVED slot
        Assert.assertEquals(8, occupiedWithData.get(hashSet));
        Assert.assertEquals(0, occupiedWithSentinels.get(hashSet));

        Assert.assertTrue(hashSet.add(<(literal.(type))("43")>));
        Assert.assertEquals(32L, ((<type>[]) table.get(hashSet)).length);
        Assert.assertEquals(9, occupiedWithData.get(hashSet));
    }

    @Test
    public void removeWithRehash() throws NoSuchFieldException, IllegalAccessException
    {
        <name>HashSet hashSet = new <name>HashSet();
        Assert.assertTrue(hashSet.addAll(<["32", "33", "34", "35", "36", "37", "38", "39"]:(literal.(type))(); separator=", ">));

        Field table = <name>HashSet.class.getDeclaredField("table");
        table.setAccessible(true);
        Assert.assertEquals(16L, ((<type>[]) table.get(hashSet)).length);

        Field occupiedWithData = <name>HashSet.class.getDeclaredField("occupiedWithData");
        occupiedWithData.setAccessible(true);
        Assert.assertEquals(8, occupiedWithData.get(hashSet));

        Field occupiedWithSentinels = <name>HashSet.class.getDeclaredField("occupiedWithSentinels");
        occupiedWithSentinels.setAccessible(true);
        Assert.assertEquals(0, occupiedWithSentinels.get(hashSet));

        for (int i = 0; i \< 4; i++)
        {
            hashSet.remove(<(castIntToNarrowTypeWithParens.(type))("i + 32")>);
            Assert.assertEquals(7 - i, occupiedWithData.get(hashSet));
            Assert.assertEquals(i + 1, occupiedWithSentinels.get(hashSet));
        }

        Assert.assertEquals(<name>HashSet.newSetWith(<["36", "37", "38", "39"]:(literal.(type))(); separator=", ">), hashSet);
        Assert.assertTrue(hashSet.remove(<(literal.(type))("36")>));
        Assert.assertEquals(16L, ((<type>[]) table.get(hashSet)).length);
        Assert.assertEquals(3, occupiedWithData.get(hashSet));
        Assert.assertEquals(5, occupiedWithSentinels.get(hashSet));

        Assert.assertFalse(hashSet.remove(<(literal.(type))("36")>));
        Assert.assertEquals(3, occupiedWithData.get(hashSet));
        Assert.assertEquals(5, occupiedWithSentinels.get(hashSet));

        Assert.assertFalse(hashSet.remove(<(literal.(type))("1")>));
        Assert.assertEquals(3, occupiedWithData.get(hashSet));
        Assert.assertEquals(5, occupiedWithSentinels.get(hashSet));

        <name>HashSet setForCopyTable = <name>HashSet.newSetWith(<["36", "37", "38", "39"]:(literal.(type))(); separator=", ">);
        setForCopyTable.freeze();
        Assert.assertTrue(setForCopyTable.remove(<(literal.(type))("36")>));
    }

    @Test
    public void iterator_remove()
    {
        Mutable<name>Set set1 = <name>Sets.mutable.empty();

        int <if(shortPrimitive)>max = 65_536<elseif(charPrimitive)>max = 10<else>max = 100_000<endif>;
        for (Integer i = 0; i \< max; i++)
        {
            <if(charPrimitive)>set1.add(i.toString().charAt(0));<else>set1.add(i.<type>Value());<endif>
        }

        // set2 to verify copyTable()
        Mutable<name>Set set2 = <name>Sets.mutable.withAll(set1);
        set2.freeze();

        this.assertIteratorRemove(set1, max);
        this.assertIteratorRemove(set2, max);
    }

    private void assertIteratorRemove(Mutable<name>Set set, int max)
    {
        Verify.assertSize(max, set);
        Mutable<name>Iterator iterator = set.<type>Iterator();
        Assert.assertThrows(IllegalStateException.class, () -> iterator.remove());

        while (iterator.hasNext())
        {
            iterator.next();
            iterator.remove();
            Verify.assertSize(--max, set);
        }
    }

    @Test
    public void addEverySlot()
    {
        this.addAndRemoveData(new <name>HashSet());
        this.addAndRemoveData(new <name>HashSet(4));
        this.addAndRemoveData(new <name>HashSet(2));
        this.addAndRemoveData(new <name>HashSet(1));
        this.addAndRemoveData(new <name>HashSet(0));
    }

    private void addAndRemoveData(<name>HashSet hashSet)
    {
        for (<type> i = <(literal.(type))("100")>; i \< <(literal.(type))("200")>; i++)
        {
            Assert.assertFalse(hashSet.contains(i));
            Assert.assertTrue(hashSet.add(i));
            Assert.assertTrue(hashSet.remove(i));
        }
    }

    @Test
    public void addDuplicateWithRemovedSlot()
    {
        <type> collision1 = Abstract<name>SetTestCase.generateCollisions1().getFirst();
        <type> collision2 = Abstract<name>SetTestCase.generateCollisions1().get(1);
        <type> collision3 = Abstract<name>SetTestCase.generateCollisions1().get(2);
        <type> collision4 = Abstract<name>SetTestCase.generateCollisions1().get(3);

        <name>HashSet hashSet = new <name>HashSet();
        Assert.assertTrue(hashSet.add(collision1));
        Assert.assertTrue(hashSet.add(collision2));
        Assert.assertTrue(hashSet.add(collision3));
        Assert.assertTrue(hashSet.remove(collision2));
        Assert.assertTrue(hashSet.add(collision4));
        Assert.assertEquals(<name>HashSet.newSetWith(collision1, collision3, collision4), hashSet);

        <name>HashSet hashSet2 = new <name>HashSet();
        Assert.assertTrue(hashSet2.add(collision1));
        Assert.assertTrue(hashSet2.add(collision2));
        Assert.assertTrue(hashSet2.add(collision3));
        Assert.assertTrue(hashSet2.remove(collision1));
        Assert.assertTrue(hashSet2.add(collision4));
        Assert.assertEquals(<name>HashSet.newSetWith(collision2, collision3, collision4), hashSet2);

        <name>HashSet hashSet3 = new <name>HashSet();
        Assert.assertTrue(hashSet3.add(collision1));
        Assert.assertTrue(hashSet3.add(collision2));
        Assert.assertTrue(hashSet3.add(collision3));
        Assert.assertTrue(hashSet3.remove(collision3));
        Assert.assertTrue(hashSet3.add(collision4));
        Assert.assertEquals(<name>HashSet.newSetWith(collision1, collision2, collision4), hashSet3);
    }

    @Test
    public void addWithCollision()
    {
        <name>HashSet hashSet = new <name>HashSet();
        <type> collision1 = Abstract<name>SetTestCase.generateCollisions1().getFirst();
        <type> collision2 = Abstract<name>SetTestCase.generateCollisions1().get(1);
        Assert.assertTrue(hashSet.add(collision1));
        Assert.assertTrue(hashSet.add(collision2));
        Assert.assertEquals(<name>HashSet.newSetWith(collision1, collision2), hashSet);
    }

    @Test
    public void addWithCollisionWithRemovedSlot()
    {
        <type> collision1 = Abstract<name>SetTestCase.generateCollisions1().getFirst();
        <type> collision2 = Abstract<name>SetTestCase.generateCollisions1().get(1);
        <type> collision3 = Abstract<name>SetTestCase.generateCollisions1().get(2);
        <type> collision4 = Abstract<name>SetTestCase.generateCollisions1().get(3);
        <type> collision5 = Abstract<name>SetTestCase.generateCollisions1().get(4);

        <name>HashSet hashSet = <name>HashSet.newSetWith(collision1, collision2, collision4);
        Assert.assertTrue(hashSet.remove(collision1));
        Assert.assertTrue(hashSet.add(collision3));
        Assert.assertEquals(<name>HashSet.newSetWith(collision3, collision2, collision4), hashSet);
        Assert.assertTrue(hashSet.remove(collision2));
        Assert.assertTrue(hashSet.add(collision5));
        Assert.assertEquals(<name>HashSet.newSetWith(collision3, collision5, collision4), hashSet);
        Assert.assertTrue(hashSet.remove(collision4));
        Assert.assertTrue(hashSet.add(collision1));
        Assert.assertEquals(<name>HashSet.newSetWith(collision3, collision5, collision1), hashSet);
    }

    @Test
    public void addZeroToThirtyOne()
    {
        <name>HashSet hashSet = <name>HashSet.newSetWith();
        for (<type> i = <(literal.(type))("0")>; i \<= <(literal.(type))("31")>; i++)
        {
            Assert.assertTrue(hashSet.add(i));
            Assert.assertFalse(hashSet.add(i));
        }
        for (<type> i = <(literal.(type))("0")>; i \<= <(literal.(type))("31")>; i++)
        {
            Assert.assertTrue(hashSet.contains(i));
        }

        for (<type> i = <(literal.(type))("0")>; i \<= <(literal.(type))("31")>; i++)
        {
            Assert.assertTrue(hashSet.contains(i));
            Assert.assertTrue(hashSet.remove(i));
            Assert.assertFalse(hashSet.contains(i));
            Assert.assertFalse(hashSet.remove(i));
        }

        Assert.assertEquals(new <name>HashSet(), hashSet);
    }

    @Test
    public void classIsNonInstantiable()
    {
        Verify.assertClassNonInstantiable(<name>Sets.class);
    }
}

>>
