/*
 * Copyright (C) 2008 The Guava Authors
 *
 * 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.common.collect;

import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.newLinkedList;
import static java.util.Arrays.asList;
import static java.util.Collections.nCopies;
import static org.truth0.Truth.ASSERT;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.testing.CollectionTestSuiteBuilder;
import com.google.common.collect.testing.TestStringCollectionGenerator;
import com.google.common.collect.testing.features.CollectionFeature;
import com.google.common.collect.testing.features.CollectionSize;
import com.google.common.testing.NullPointerTester;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * Tests for {@link Collections2}.
 *
 * @author Chris Povirk
 * @author Jared Levy
 */
@GwtCompatible(emulated = true)
public class Collections2Test extends TestCase {
  @GwtIncompatible("suite")
  public static Test suite() {
    TestSuite suite = new TestSuite(Collections2Test.class.getSimpleName());
    suite.addTest(testsForFilter());
    suite.addTest(testsForFilterAll());
    suite.addTest(testsForFilterLinkedList());
    suite.addTest(testsForFilterNoNulls());
    suite.addTest(testsForFilterFiltered());
    suite.addTest(testsForTransform());
    suite.addTestSuite(Collections2Test.class);
    return suite;
  }

  static final Predicate<String> NOT_YYY_ZZZ = new Predicate<String>() {
      @Override
      public boolean apply(String input) {
        return !"yyy".equals(input) && !"zzz".equals(input);
      }
  };

  static final Predicate<String> LENGTH_1 = new Predicate<String>() {
    @Override
    public boolean apply(String input) {
      return input.length() == 1;
    }
  };

  static final Predicate<String> STARTS_WITH_VOWEL = new Predicate<String>() {
    @Override
    public boolean apply(String input) {
      return asList('a', 'e', 'i', 'o', 'u').contains(input.charAt(0));
    }
  };

  @GwtIncompatible("suite")
  private static Test testsForFilter() {
    return CollectionTestSuiteBuilder.using(
        new TestStringCollectionGenerator() {
          @Override public Collection<String> create(String[] elements) {
            List<String> unfiltered = newArrayList();
            unfiltered.add("yyy");
            Collections.addAll(unfiltered, elements);
            unfiltered.add("zzz");
            return Collections2.filter(unfiltered, NOT_YYY_ZZZ);
          }
        })
        .named("Collections2.filter")
        .withFeatures(
            CollectionFeature.SUPPORTS_ADD,
            CollectionFeature.SUPPORTS_REMOVE,
            CollectionFeature.ALLOWS_NULL_VALUES,
            CollectionFeature.KNOWN_ORDER,
            CollectionSize.ANY)
        .createTestSuite();
  }

  @GwtIncompatible("suite")
  private static Test testsForFilterAll() {
    return CollectionTestSuiteBuilder.using(
        new TestStringCollectionGenerator() {
          @Override public Collection<String> create(String[] elements) {
            List<String> unfiltered = newArrayList();
            Collections.addAll(unfiltered, elements);
            return Collections2.filter(unfiltered, NOT_YYY_ZZZ);
          }
        })
        .named("Collections2.filter")
        .withFeatures(
            CollectionFeature.SUPPORTS_ADD,
            CollectionFeature.SUPPORTS_REMOVE,
            CollectionFeature.ALLOWS_NULL_VALUES,
            CollectionFeature.KNOWN_ORDER,
            CollectionSize.ANY)
        .createTestSuite();
  }

  @GwtIncompatible("suite")
  private static Test testsForFilterLinkedList() {
    return CollectionTestSuiteBuilder.using(
        new TestStringCollectionGenerator() {
          @Override public Collection<String> create(String[] elements) {
            List<String> unfiltered = newLinkedList();
            unfiltered.add("yyy");
            Collections.addAll(unfiltered, elements);
            unfiltered.add("zzz");
            return Collections2.filter(unfiltered, NOT_YYY_ZZZ);
          }
        })
        .named("Collections2.filter")
        .withFeatures(
            CollectionFeature.SUPPORTS_ADD,
            CollectionFeature.SUPPORTS_REMOVE,
            CollectionFeature.ALLOWS_NULL_VALUES,
            CollectionFeature.KNOWN_ORDER,
            CollectionSize.ANY)
        .createTestSuite();
  }

  @GwtIncompatible("suite")
  private static Test testsForFilterNoNulls() {
    return CollectionTestSuiteBuilder.using(
        new TestStringCollectionGenerator() {
          @Override public Collection<String> create(String[] elements) {
            List<String> unfiltered = newArrayList();
            unfiltered.add("yyy");
            unfiltered.addAll(ImmutableList.copyOf(elements));
            unfiltered.add("zzz");
            return Collections2.filter(unfiltered, LENGTH_1);
          }
        })
        .named("Collections2.filter, no nulls")
        .withFeatures(
            CollectionFeature.SUPPORTS_ADD,
            CollectionFeature.SUPPORTS_REMOVE,
            CollectionFeature.ALLOWS_NULL_QUERIES,
            CollectionFeature.KNOWN_ORDER,
            CollectionSize.ANY)
        .createTestSuite();
  }

  @GwtIncompatible("suite")
  private static Test testsForFilterFiltered() {
    return CollectionTestSuiteBuilder.using(
        new TestStringCollectionGenerator() {
          @Override public Collection<String> create(String[] elements) {
            List<String> unfiltered = newArrayList();
            unfiltered.add("yyy");
            unfiltered.addAll(ImmutableList.copyOf(elements));
            unfiltered.add("zzz");
            unfiltered.add("abc");
            return Collections2.filter(
                Collections2.filter(unfiltered, LENGTH_1), NOT_YYY_ZZZ);
          }
        })
        .named("Collections2.filter, filtered input")
        .withFeatures(
            CollectionFeature.SUPPORTS_ADD,
            CollectionFeature.SUPPORTS_REMOVE,
            CollectionFeature.KNOWN_ORDER,
            CollectionFeature.ALLOWS_NULL_QUERIES,
            CollectionSize.ANY)
        .createTestSuite();
  }

  private static final Function<String, String> REMOVE_FIRST_CHAR
      = new Function<String, String>() {
        @Override
        public String apply(String from) {
          return ((from == null) || "".equals(from))
              ? null : from.substring(1);
        }
      };

  @GwtIncompatible("suite")
  private static Test testsForTransform() {
    return CollectionTestSuiteBuilder.using(
        new TestStringCollectionGenerator() {
          @Override public Collection<String> create(String[] elements) {
            List<String> list = newArrayList();
            for (String element : elements) {
              list.add((element == null) ? null : "q" + element);
            }
            return Collections2.transform(list, REMOVE_FIRST_CHAR);
          }
        })
        .named("Collections2.transform")
        .withFeatures(
            CollectionFeature.REMOVE_OPERATIONS,
            CollectionFeature.ALLOWS_NULL_VALUES,
            CollectionFeature.KNOWN_ORDER,
            CollectionSize.ANY)
        .createTestSuite();
  }

  @GwtIncompatible("NullPointerTester")
  public void testNullPointerExceptions() {
    NullPointerTester tester = new NullPointerTester();
    tester.testAllPublicStaticMethods(Collections2.class);
  }

  public void testOrderedPermutationSetEmpty() {
    List<Integer> list = newArrayList();
    Collection<List<Integer>> permutationSet =
        Collections2.orderedPermutations(list);

    assertEquals(1, permutationSet.size());
    ASSERT.that(permutationSet).has().item(list);

    Iterator<List<Integer>> permutations = permutationSet.iterator();

    assertNextPermutation(Lists.<Integer>newArrayList(), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testOrderedPermutationSetOneElement() {
    List<Integer> list = newArrayList(1);
    Iterator<List<Integer>> permutations =
        Collections2.orderedPermutations(list).iterator();

    assertNextPermutation(newArrayList(1), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testOrderedPermutationSetThreeElements() {
    List<String> list = newArrayList("b", "a", "c");
    Iterator<List<String>> permutations =
        Collections2.orderedPermutations(list).iterator();

    assertNextPermutation(newArrayList("a", "b", "c"), permutations);
    assertNextPermutation(newArrayList("a", "c", "b"), permutations);
    assertNextPermutation(newArrayList("b", "a", "c"), permutations);
    assertNextPermutation(newArrayList("b", "c", "a"), permutations);
    assertNextPermutation(newArrayList("c", "a", "b"), permutations);
    assertNextPermutation(newArrayList("c", "b", "a"), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testOrderedPermutationSetRepeatedElements() {
    List<Integer> list = newArrayList(1, 1, 2, 2);
    Iterator<List<Integer>> permutations =
        Collections2.orderedPermutations(list, Ordering.natural()).iterator();

    assertNextPermutation(newArrayList(1, 1, 2, 2), permutations);
    assertNextPermutation(newArrayList(1, 2, 1, 2), permutations);
    assertNextPermutation(newArrayList(1, 2, 2, 1), permutations);
    assertNextPermutation(newArrayList(2, 1, 1, 2), permutations);
    assertNextPermutation(newArrayList(2, 1, 2, 1), permutations);
    assertNextPermutation(newArrayList(2, 2, 1, 1), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testOrderedPermutationSetRepeatedElementsSize() {
    List<Integer> list = newArrayList(1, 1, 1, 1, 2, 2, 3);
    Collection<List<Integer>> permutations =
        Collections2.orderedPermutations(list, Ordering.natural());

    assertPermutationsCount(105, permutations);
  }

  public void testOrderedPermutationSetSizeOverflow() {
    // 12 elements won't overflow
    assertEquals(479001600 /*12!*/, Collections2.orderedPermutations(
        newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)).size());
    // 13 elements overflow an int
    assertEquals(Integer.MAX_VALUE, Collections2.orderedPermutations(
        newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)).size());
    // 21 elements overflow a long
    assertEquals(Integer.MAX_VALUE, Collections2.orderedPermutations(
        newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
            16, 17, 18, 19, 20, 21)).size());

    // Almost force an overflow in the binomial coefficient calculation
    assertEquals(1391975640 /*C(34,14)*/, Collections2.orderedPermutations(
        concat(nCopies(20, 1), nCopies(14, 2))).size());
    // Do force an overflow in the binomial coefficient calculation
    assertEquals(Integer.MAX_VALUE, Collections2.orderedPermutations(
        concat(nCopies(21, 1), nCopies(14, 2))).size());
  }

  public void testOrderedPermutationSetContains() {
    List<Integer> list = newArrayList(3, 2, 1);
    Collection<List<Integer>> permutationSet =
        Collections2.orderedPermutations(list);

    assertTrue(permutationSet.contains(newArrayList(1, 2, 3)));
    assertTrue(permutationSet.contains(newArrayList(2, 3, 1)));
    assertFalse(permutationSet.contains(newArrayList(1, 2)));
    assertFalse(permutationSet.contains(newArrayList(1, 1, 2, 3)));
    assertFalse(permutationSet.contains(newArrayList(1, 2, 3, 4)));
    assertFalse(permutationSet.contains(null));
  }

  public void testPermutationSetEmpty() {
    Collection<List<Integer>> permutationSet =
        Collections2.permutations(Collections.<Integer>emptyList());

    assertEquals(1, permutationSet.size());
    assertTrue(permutationSet.contains(Collections.<Integer> emptyList()));

    Iterator<List<Integer>> permutations = permutationSet.iterator();
    assertNextPermutation(Collections.<Integer> emptyList(), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testPermutationSetOneElement() {
    Iterator<List<Integer>> permutations =
        Collections2.permutations(Collections.<Integer> singletonList(1))
        .iterator();
    assertNextPermutation(newArrayList(1), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testPermutationSetTwoElements() {
    Iterator<List<Integer>> permutations = Collections2.permutations(
        newArrayList(1, 2)).iterator();
    assertNextPermutation(newArrayList(1, 2), permutations);
    assertNextPermutation(newArrayList(2, 1), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testPermutationSetThreeElements() {
    Iterator<List<Integer>> permutations = Collections2.permutations(
        newArrayList(1, 2, 3)).iterator();
    assertNextPermutation(newArrayList(1, 2, 3), permutations);
    assertNextPermutation(newArrayList(1, 3, 2), permutations);
    assertNextPermutation(newArrayList(3, 1, 2), permutations);

    assertNextPermutation(newArrayList(3, 2, 1), permutations);
    assertNextPermutation(newArrayList(2, 3, 1), permutations);
    assertNextPermutation(newArrayList(2, 1, 3), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testPermutationSetThreeElementsOutOfOrder() {
    Iterator<List<Integer>> permutations = Collections2.permutations(
        newArrayList(3, 2, 1)).iterator();
    assertNextPermutation(newArrayList(3, 2, 1), permutations);
    assertNextPermutation(newArrayList(3, 1, 2), permutations);
    assertNextPermutation(newArrayList(1, 3, 2), permutations);

    assertNextPermutation(newArrayList(1, 2, 3), permutations);
    assertNextPermutation(newArrayList(2, 1, 3), permutations);
    assertNextPermutation(newArrayList(2, 3, 1), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testPermutationSetThreeRepeatedElements() {
    Iterator<List<Integer>> permutations = Collections2.permutations(
        newArrayList(1, 1, 2)).iterator();
    assertNextPermutation(newArrayList(1, 1, 2), permutations);
    assertNextPermutation(newArrayList(1, 2, 1), permutations);
    assertNextPermutation(newArrayList(2, 1, 1), permutations);
    assertNextPermutation(newArrayList(2, 1, 1), permutations);
    assertNextPermutation(newArrayList(1, 2, 1), permutations);
    assertNextPermutation(newArrayList(1, 1, 2), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testPermutationSetFourElements() {
    Iterator<List<Integer>> permutations = Collections2.permutations(
        newArrayList(1, 2, 3, 4)).iterator();
    assertNextPermutation(newArrayList(1, 2, 3, 4), permutations);
    assertNextPermutation(newArrayList(1, 2, 4, 3), permutations);
    assertNextPermutation(newArrayList(1, 4, 2, 3), permutations);
    assertNextPermutation(newArrayList(4, 1, 2, 3), permutations);

    assertNextPermutation(newArrayList(4, 1, 3, 2), permutations);
    assertNextPermutation(newArrayList(1, 4, 3, 2), permutations);
    assertNextPermutation(newArrayList(1, 3, 4, 2), permutations);
    assertNextPermutation(newArrayList(1, 3, 2, 4), permutations);

    assertNextPermutation(newArrayList(3, 1, 2, 4), permutations);
    assertNextPermutation(newArrayList(3, 1, 4, 2), permutations);
    assertNextPermutation(newArrayList(3, 4, 1, 2), permutations);
    assertNextPermutation(newArrayList(4, 3, 1, 2), permutations);

    assertNextPermutation(newArrayList(4, 3, 2, 1), permutations);
    assertNextPermutation(newArrayList(3, 4, 2, 1), permutations);
    assertNextPermutation(newArrayList(3, 2, 4, 1), permutations);
    assertNextPermutation(newArrayList(3, 2, 1, 4), permutations);

    assertNextPermutation(newArrayList(2, 3, 1, 4), permutations);
    assertNextPermutation(newArrayList(2, 3, 4, 1), permutations);
    assertNextPermutation(newArrayList(2, 4, 3, 1), permutations);
    assertNextPermutation(newArrayList(4, 2, 3, 1), permutations);

    assertNextPermutation(newArrayList(4, 2, 1, 3), permutations);
    assertNextPermutation(newArrayList(2, 4, 1, 3), permutations);
    assertNextPermutation(newArrayList(2, 1, 4, 3), permutations);
    assertNextPermutation(newArrayList(2, 1, 3, 4), permutations);
    assertNoMorePermutations(permutations);
  }

  public void testPermutationSetSize() {
    assertPermutationsCount(1,
        Collections2.permutations(Collections.<Integer>emptyList()));
    assertPermutationsCount(1, Collections2.permutations(newArrayList(1)));
    assertPermutationsCount(2, Collections2.permutations(newArrayList(1, 2)));
    assertPermutationsCount(6,
        Collections2.permutations(newArrayList(1, 2, 3)));
    assertPermutationsCount(5040,
        Collections2.permutations(newArrayList(1, 2, 3, 4, 5, 6, 7)));
    assertPermutationsCount(40320,
        Collections2.permutations(newArrayList(1, 2, 3, 4, 5, 6, 7, 8)));
  }

  public void testPermutationSetSizeOverflow() {
    // 13 elements overflow an int
    assertEquals(Integer.MAX_VALUE, Collections2.permutations(newArrayList(
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)).size());
    // 21 elements overflow a long
    assertEquals(Integer.MAX_VALUE, Collections2.orderedPermutations(
        newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
            16, 17, 18, 19, 20)).size());
    assertEquals(Integer.MAX_VALUE, Collections2.orderedPermutations(
        newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
            16, 17, 18, 19, 20, 21)).size());
  }

  public void testPermutationSetContains() {
    List<Integer> list = newArrayList(3, 2, 1);
    Collection<List<Integer>> permutationSet =
        Collections2.permutations(list);

    assertTrue(permutationSet.contains(newArrayList(1, 2, 3)));
    assertTrue(permutationSet.contains(newArrayList(2, 3, 1)));
    assertFalse(permutationSet.contains(newArrayList(1, 2)));
    assertFalse(permutationSet.contains(newArrayList(1, 1, 2, 3)));
    assertFalse(permutationSet.contains(newArrayList(1, 2, 3, 4)));
    assertFalse(permutationSet.contains(null));
  }

  private <T> void assertNextPermutation(List<T> expectedPermutation,
      Iterator<List<T>> permutations) {
    assertTrue("Expected another permutation, but there was none.",
        permutations.hasNext());
    assertEquals(expectedPermutation, permutations.next());
  }

  private <T> void assertNoMorePermutations(
      Iterator<List<T>> permutations) {
    assertFalse("Expected no more permutations, but there was one.",
        permutations.hasNext());
    try {
      permutations.next();
      fail("Expected NoSuchElementException.");
    } catch (NoSuchElementException expected) {}
  }

  private <T> void assertPermutationsCount(int expected,
      Collection<List<T>> permutationSet) {
    assertEquals(expected, permutationSet.size());
    Iterator<List<T>> permutations = permutationSet.iterator();
    for (int i = 0; i < expected; i++) {
      assertTrue(permutations.hasNext());
      permutations.next();
    }
    assertNoMorePermutations(permutations);
  }

  public void testToStringImplWithNullEntries() throws Exception {
    List<String> list = Lists.newArrayList();
    list.add("foo");
    list.add(null);

    assertEquals(list.toString(), Collections2.toStringImpl(list));
  }

}
