// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.collect;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Tests for {@link CollectionUtils}.
 */

@RunWith(JUnit4.class)
public class CollectionUtilsTest {

  @Test
  public void testDuplicatedElementsOf() {
    assertDups(ImmutableList.<Integer>of(), ImmutableSet.<Integer>of());
    assertDups(ImmutableList.of(0), ImmutableSet.<Integer>of());
    assertDups(ImmutableList.of(0, 0, 0), ImmutableSet.of(0));
    assertDups(ImmutableList.of(1, 2, 3, 1, 2, 3), ImmutableSet.of(1, 2, 3));
    assertDups(ImmutableList.of(1, 2, 3, 1, 2, 3, 4), ImmutableSet.of(1, 2, 3));
    assertDups(ImmutableList.of(1, 2, 3, 4), ImmutableSet.<Integer>of());
  }

  private static void assertDups(List<Integer> collection, Set<Integer> dups) {
    assertEquals(dups, CollectionUtils.duplicatedElementsOf(collection));
  }

  @Test
  public void testIsImmutable() throws Exception {
    assertTrue(CollectionUtils.isImmutable(ImmutableList.of(1, 2, 3)));
    assertTrue(CollectionUtils.isImmutable(ImmutableSet.of(1, 2, 3)));

    NestedSet<Integer> ns = NestedSetBuilder.<Integer>compileOrder()
        .add(1).add(2).add(3).build();
    assertTrue(CollectionUtils.isImmutable(ns));

    NestedSet<Integer> ns2 = NestedSetBuilder.<Integer>linkOrder().add(1).add(2).add(3).build();
    assertTrue(CollectionUtils.isImmutable(ns2));

    IterablesChain<Integer> chain = IterablesChain.<Integer>builder().addElement(1).build();

    assertTrue(CollectionUtils.isImmutable(chain));

    assertFalse(CollectionUtils.isImmutable(Lists.newArrayList()));
    assertFalse(CollectionUtils.isImmutable(Lists.newLinkedList()));
    assertFalse(CollectionUtils.isImmutable(Sets.newHashSet()));
    assertFalse(CollectionUtils.isImmutable(Sets.newLinkedHashSet()));

    // The result of Iterables.concat() actually is immutable, but we have no way of checking if
    // a given Iterable comes from concat().
    assertFalse(CollectionUtils.isImmutable(Iterables.concat(ns, ns2)));

    // We can override the check by using the ImmutableIterable wrapper.
    assertTrue(CollectionUtils.isImmutable(
        ImmutableIterable.from(Iterables.concat(ns, ns2))));
  }

  @Test
  public void testCheckImmutable() throws Exception {
    CollectionUtils.checkImmutable(ImmutableList.of(1, 2, 3));
    CollectionUtils.checkImmutable(ImmutableSet.of(1, 2, 3));

    try {
      CollectionUtils.checkImmutable(Lists.newArrayList(1, 2, 3));
    } catch (IllegalStateException e) {
      return;
    }
    fail();
  }

  @Test
  public void testMakeImmutable() throws Exception {
    Iterable<Integer> immutableList = ImmutableList.of(1, 2, 3);
    assertSame(immutableList, CollectionUtils.makeImmutable(immutableList));

    Iterable<Integer> mutableList = Lists.newArrayList(1, 2, 3);
    Iterable<Integer> converted = CollectionUtils.makeImmutable(mutableList);
    assertNotSame(mutableList, converted);
    assertEquals(mutableList, ImmutableList.copyOf(converted));
  }

  private static enum Small { ALPHA, BRAVO }
  private static enum Large {
    L0, L1, L2, L3, L4, L5, L6, L7, L8, L9,
    L10, L11, L12, L13, L14, L15, L16, L17, L18, L19,
    L20, L21, L22, L23, L24, L25, L26, L27, L28, L29,
    L30, L31,
  }

  private static enum TooLarge {
    T0, T1, T2, T3, T4, T5, T6, T7, T8, T9,
    T10, T11, T12, T13, T14, T15, T16, T17, T18, T19,
    T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
    T30, T31, T32,
  }

  private static enum Medium {
    ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
  }

  private <T extends Enum<T>> void assertAllDifferent(Class<T> clazz) throws Exception {
    Set<EnumSet<T>> allSets = new HashSet<>();

    int maxBits = 1 << clazz.getEnumConstants().length;
    for (int i = 0; i < maxBits; i++) {
      EnumSet<T> set = CollectionUtils.fromBits(i, clazz);
      int back = CollectionUtils.toBits(set);
      assertEquals(back, i);  // Assert that a roundtrip is idempotent
      allSets.add(set);
    }

    assertThat(allSets).hasSize(maxBits); // Assert that every decoded value is different
  }

  @Test
  public void testEnumBitfields() throws Exception {
    assertEquals(0, CollectionUtils.<Small>toBits());
    assertEquals(EnumSet.noneOf(Small.class), CollectionUtils.fromBits(0, Small.class));
    assertEquals(3, CollectionUtils.toBits(Small.ALPHA, Small.BRAVO));
    assertEquals(10, CollectionUtils.toBits(Medium.TWO, Medium.FOUR));
    assertEquals(EnumSet.of(Medium.SEVEN, Medium.EIGHT),
        CollectionUtils.fromBits(192, Medium.class));

    assertAllDifferent(Small.class);
    assertAllDifferent(Medium.class);
    assertAllDifferent(Large.class);

    try {
      CollectionUtils.toBits(TooLarge.T32);
      fail();
    } catch (IllegalArgumentException e) {
      // good
    }

    try {
      CollectionUtils.fromBits(0, TooLarge.class);
      fail();
    } catch (IllegalArgumentException e) {
      // good
    }
  }
}
