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 com.google.common.annotations.GwtIncompatible;
020import com.google.common.collect.testing.features.CollectionSize;
021import com.google.common.collect.testing.features.Feature;
022import com.google.common.collect.testing.features.FeatureUtil;
023import java.lang.reflect.Method;
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.List;
027import java.util.Set;
028import java.util.logging.Logger;
029import junit.framework.TestSuite;
030
031/**
032 * This builder creates a composite test suite, containing a separate test suite for each {@link
033 * CollectionSize} present in the features specified by {@link #withFeatures(Feature...)}.
034 *
035 * @param <B> The concrete type of this builder (the 'self-type'). All the Builder methods of this
036 *     class (such as {@link #named(String)}) return this type, so that Builder methods of more
037 *     derived classes can be chained onto them without casting.
038 * @param <G> The type of the generator to be passed to testers in the generated test suite. An
039 *     instance of G should somehow provide an instance of the class under test, plus any other
040 *     information required to parameterize the test.
041 * @see FeatureSpecificTestSuiteBuilder
042 * @author George van den Driessche
043 */
044@GwtIncompatible
045public abstract class PerCollectionSizeTestSuiteBuilder<
046        B extends PerCollectionSizeTestSuiteBuilder<B, G, T, E>,
047        G extends TestContainerGenerator<T, E>,
048        T,
049        E>
050    extends FeatureSpecificTestSuiteBuilder<B, G> {
051  private static final Logger logger =
052      Logger.getLogger(PerCollectionSizeTestSuiteBuilder.class.getName());
053
054  /** Creates a runnable JUnit test suite based on the criteria already given. */
055  @Override
056  public TestSuite createTestSuite() {
057    checkCanCreate();
058
059    String name = getName();
060    // Copy this set, so we can modify it.
061    Set<Feature<?>> features = Helpers.copyToSet(getFeatures());
062    List<Class<? extends AbstractTester>> testers = getTesters();
063
064    logger.fine(" Testing: " + name);
065
066    // Split out all the specified sizes.
067    Set<Feature<?>> sizesToTest = Helpers.<Feature<?>>copyToSet(CollectionSize.values());
068    sizesToTest.retainAll(features);
069    features.removeAll(sizesToTest);
070
071    FeatureUtil.addImpliedFeatures(sizesToTest);
072    sizesToTest.retainAll(
073        Arrays.asList(CollectionSize.ZERO, CollectionSize.ONE, CollectionSize.SEVERAL));
074
075    logger.fine("   Sizes: " + formatFeatureSet(sizesToTest));
076
077    if (sizesToTest.isEmpty()) {
078      throw new IllegalStateException(
079          name
080              + ": no CollectionSizes specified (check the argument to "
081              + "FeatureSpecificTestSuiteBuilder.withFeatures().)");
082    }
083
084    TestSuite suite = new TestSuite(name);
085    for (Feature<?> collectionSize : sizesToTest) {
086      String oneSizeName =
087          Platform.format(
088              "%s [collection size: %s]", name, collectionSize.toString().toLowerCase());
089      OneSizeGenerator<T, E> oneSizeGenerator =
090          new OneSizeGenerator<>(getSubjectGenerator(), (CollectionSize) collectionSize);
091      Set<Feature<?>> oneSizeFeatures = Helpers.copyToSet(features);
092      oneSizeFeatures.add(collectionSize);
093      Set<Method> oneSizeSuppressedTests = getSuppressedTests();
094
095      OneSizeTestSuiteBuilder<T, E> oneSizeBuilder =
096          new OneSizeTestSuiteBuilder<T, E>(testers)
097              .named(oneSizeName)
098              .usingGenerator(oneSizeGenerator)
099              .withFeatures(oneSizeFeatures)
100              .withSetUp(getSetUp())
101              .withTearDown(getTearDown())
102              .suppressing(oneSizeSuppressedTests);
103      TestSuite oneSizeSuite = oneSizeBuilder.createTestSuite();
104      suite.addTest(oneSizeSuite);
105
106      for (TestSuite derivedSuite : createDerivedSuites(oneSizeBuilder)) {
107        oneSizeSuite.addTest(derivedSuite);
108      }
109    }
110    return suite;
111  }
112
113  protected List<TestSuite> createDerivedSuites(
114      FeatureSpecificTestSuiteBuilder<?, ? extends OneSizeTestContainerGenerator<T, E>>
115          parentBuilder) {
116    return new ArrayList<>();
117  }
118
119  /** Builds a test suite for one particular {@link CollectionSize}. */
120  private static final class OneSizeTestSuiteBuilder<T, E>
121      extends FeatureSpecificTestSuiteBuilder<
122          OneSizeTestSuiteBuilder<T, E>, OneSizeGenerator<T, E>> {
123    private final List<Class<? extends AbstractTester>> testers;
124
125    public OneSizeTestSuiteBuilder(List<Class<? extends AbstractTester>> testers) {
126      this.testers = testers;
127    }
128
129    @Override
130    protected List<Class<? extends AbstractTester>> getTesters() {
131      return testers;
132    }
133  }
134}