001/*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.collect.testing;
018
019import static com.google.common.collect.testing.Helpers.copyToSet;
020import static com.google.common.collect.testing.features.FeatureUtil.addImpliedFeatures;
021import static java.util.Arrays.asList;
022
023import com.google.common.annotations.GwtIncompatible;
024import com.google.common.collect.testing.features.CollectionSize;
025import com.google.common.collect.testing.features.Feature;
026import java.lang.reflect.Method;
027import java.util.ArrayList;
028import java.util.List;
029import java.util.Set;
030import java.util.logging.Logger;
031import junit.framework.TestSuite;
032
033/**
034 * This builder creates a composite test suite, containing a separate test suite for each {@link
035 * CollectionSize} present in the features specified by {@link #withFeatures(Feature...)}.
036 *
037 * @param <B> The concrete type of this builder (the 'self-type'). All the Builder methods of this
038 *     class (such as {@link #named(String)}) return this type, so that Builder methods of more
039 *     derived classes can be chained onto them without casting.
040 * @param <G> The type of the generator to be passed to testers in the generated test suite. An
041 *     instance of G should somehow provide an instance of the class under test, plus any other
042 *     information required to parameterize the test.
043 * @see FeatureSpecificTestSuiteBuilder
044 * @author George van den Driessche
045 */
046@GwtIncompatible
047public abstract class PerCollectionSizeTestSuiteBuilder<
048        B extends PerCollectionSizeTestSuiteBuilder<B, G, T, E>,
049        G extends TestContainerGenerator<T, E>,
050        T,
051        E>
052    extends FeatureSpecificTestSuiteBuilder<B, G> {
053  private static final Logger logger =
054      Logger.getLogger(PerCollectionSizeTestSuiteBuilder.class.getName());
055
056  /** Creates a runnable JUnit test suite based on the criteria already given. */
057  @Override
058  public TestSuite createTestSuite() {
059    checkCanCreate();
060
061    String name = getName();
062    // Copy this set, so we can modify it.
063    Set<Feature<?>> features = copyToSet(getFeatures());
064    @SuppressWarnings("rawtypes") // class literals
065    List<Class<? extends AbstractTester>> testers = getTesters();
066
067    logger.fine(" Testing: " + name);
068
069    // Split out all the specified sizes.
070    Set<Feature<?>> sizesToTest = Helpers.<Feature<?>>copyToSet(CollectionSize.values());
071    sizesToTest.retainAll(features);
072    features.removeAll(sizesToTest);
073
074    addImpliedFeatures(sizesToTest);
075    sizesToTest.retainAll(asList(CollectionSize.ZERO, CollectionSize.ONE, CollectionSize.SEVERAL));
076
077    logger.fine("   Sizes: " + formatFeatureSet(sizesToTest));
078
079    if (sizesToTest.isEmpty()) {
080      throw new IllegalStateException(
081          name
082              + ": no CollectionSizes specified (check the argument to "
083              + "FeatureSpecificTestSuiteBuilder.withFeatures().)");
084    }
085
086    TestSuite suite = new TestSuite(name);
087    for (Feature<?> collectionSize : sizesToTest) {
088      String oneSizeName =
089          Platform.format(
090              "%s [collection size: %s]", name, collectionSize.toString().toLowerCase());
091      OneSizeGenerator<T, E> oneSizeGenerator =
092          new OneSizeGenerator<>(getSubjectGenerator(), (CollectionSize) collectionSize);
093      Set<Feature<?>> oneSizeFeatures = copyToSet(features);
094      oneSizeFeatures.add(collectionSize);
095      Set<Method> oneSizeSuppressedTests = getSuppressedTests();
096
097      OneSizeTestSuiteBuilder<T, E> oneSizeBuilder =
098          new OneSizeTestSuiteBuilder<T, E>(testers)
099              .named(oneSizeName)
100              .usingGenerator(oneSizeGenerator)
101              .withFeatures(oneSizeFeatures)
102              .withSetUp(getSetUp())
103              .withTearDown(getTearDown())
104              .suppressing(oneSizeSuppressedTests);
105      TestSuite oneSizeSuite = oneSizeBuilder.createTestSuite();
106      suite.addTest(oneSizeSuite);
107
108      for (TestSuite derivedSuite : createDerivedSuites(oneSizeBuilder)) {
109        oneSizeSuite.addTest(derivedSuite);
110      }
111    }
112    return suite;
113  }
114
115  protected List<TestSuite> createDerivedSuites(
116      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<T, E>>
117          parentBuilder) {
118    return new ArrayList<>();
119  }
120
121  /** Builds a test suite for one particular {@link CollectionSize}. */
122  private static final class OneSizeTestSuiteBuilder<T, E>
123      extends FeatureSpecificTestSuiteBuilder<
124          OneSizeTestSuiteBuilder<T, E>, OneSizeGenerator<T, E>> {
125    @SuppressWarnings("rawtypes") // class literals
126    private final List<Class<? extends AbstractTester>> testers;
127
128    @SuppressWarnings("rawtypes") // class literals
129    public OneSizeTestSuiteBuilder(List<Class<? extends AbstractTester>> testers) {
130      this.testers = testers;
131    }
132
133    @SuppressWarnings("rawtypes") // class literals
134    @Override
135    protected List<Class<? extends AbstractTester>> getTesters() {
136      return testers;
137    }
138  }
139}