// Copyright 2017 Google Inc. 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.api.ads.adwords.axis.utils.v201702.shopping; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import com.google.api.ads.adwords.axis.v201702.cm.ProductAdwordsGrouping; import com.google.api.ads.adwords.axis.v201702.cm.ProductAdwordsLabels; import com.google.api.ads.adwords.axis.v201702.cm.ProductBiddingCategory; import com.google.api.ads.adwords.axis.v201702.cm.ProductBrand; import com.google.api.ads.adwords.axis.v201702.cm.ProductCanonicalCondition; import com.google.api.ads.adwords.axis.v201702.cm.ProductCanonicalConditionCondition; import com.google.api.ads.adwords.axis.v201702.cm.ProductChannel; import com.google.api.ads.adwords.axis.v201702.cm.ProductChannelExclusivity; import com.google.api.ads.adwords.axis.v201702.cm.ProductCustomAttribute; import com.google.api.ads.adwords.axis.v201702.cm.ProductDimension; import com.google.api.ads.adwords.axis.v201702.cm.ProductDimensionType; import com.google.api.ads.adwords.axis.v201702.cm.ProductLegacyCondition; import com.google.api.ads.adwords.axis.v201702.cm.ProductOfferId; import com.google.api.ads.adwords.axis.v201702.cm.ProductType; import com.google.api.ads.adwords.axis.v201702.cm.ProductTypeFull; import com.google.api.ads.adwords.axis.v201702.cm.ShoppingProductChannel; import com.google.api.ads.adwords.axis.v201702.cm.ShoppingProductChannelExclusivity; import com.google.api.ads.adwords.axis.v201702.cm.UnknownProductDimension; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.reflect.ClassPath; import com.google.common.reflect.ClassPath.ClassInfo; import java.lang.reflect.Method; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Tests for {@link ProductDimensions}. */ @RunWith(JUnit4.class) public class ProductDimensionsTest { @Rule public ExpectedException thrown = ExpectedException.none(); private static final String STRING_VALUE = "dummy"; /** * Set of {@link ProductDimension} subclasses to ignore because they either are not supported by * shopping campaigns or are not ADD-able. */ private static final ImmutableSet<Class<? extends ProductDimension>> DIMENSION_TYPES_TO_IGNORE = ImmutableSet .<Class<? extends ProductDimension>>builder() .add(ProductAdwordsGrouping.class) .add(ProductAdwordsLabels.class) .add(ProductLegacyCondition.class) .add(ProductTypeFull.class) .add(UnknownProductDimension.class) .build(); /** * Test method for createType. */ @Test public void testCreateType() { ProductType type = ProductDimensions.createType(ProductDimensionType.PRODUCT_TYPE_L1, STRING_VALUE); assertEquals(STRING_VALUE, type.getValue()); } /** * Test method for createType with a null product type level. This should fail. */ @Test public void testCreateType_nullTypeLevel_fails() { thrown.expect(NullPointerException.class); ProductDimensions.createType(null, STRING_VALUE); } /** * Test method for createCanonicalCondition. */ @Test public void testCreateCanonicalCondition() { ProductCanonicalCondition condition = ProductDimensions.createCanonicalCondition(ProductCanonicalConditionCondition.NEW); assertEquals(ProductCanonicalConditionCondition.NEW, condition.getCondition()); } /** * Test method for createBiddingCategory. */ @Test public void testCreateBiddingCategory() { ProductBiddingCategory category = ProductDimensions.createBiddingCategory(ProductDimensionType.BIDDING_CATEGORY_L1, 1L); assertEquals(ProductDimensionType.BIDDING_CATEGORY_L1, category.getType()); assertEquals(Long.valueOf(1), category.getValue()); } /** * Test method for testCreateBiddingCategory with a null category level. This should fail. */ @Test public void testCreateBiddingCategory_nullCategoryLevel_fails() { thrown.expect(NullPointerException.class); ProductDimensions.createBiddingCategory(null, 1L); } /** * Test method for createOfferId. */ @Test public void testCreateOfferId() { ProductOfferId offerId = ProductDimensions.createOfferId(STRING_VALUE); assertEquals(STRING_VALUE, offerId.getValue()); } /** * Test method for createBrand. */ @Test public void testCreateBrand() { ProductBrand brand = ProductDimensions.createBrand(STRING_VALUE); assertEquals(STRING_VALUE, brand.getValue()); } /** * Test method for createCustomAttribute. */ @Test public void testCreateCustomAttribute() { ProductCustomAttribute attribute = ProductDimensions.createCustomAttribute( ProductDimensionType.CUSTOM_ATTRIBUTE_2, STRING_VALUE); assertEquals(ProductDimensionType.CUSTOM_ATTRIBUTE_2, attribute.getType()); assertEquals(STRING_VALUE, attribute.getValue()); } /** * Test method for testCreateBiddingCategory with a null category level. This should fail. */ @Test public void testCreateCustomAttribute_nullAttributeLevel_fails() { thrown.expect(NullPointerException.class); ProductDimensions.createCustomAttribute(null, STRING_VALUE); } /** * Test method for createChannel. */ @Test public void testCreateChannel() { ProductChannel channel = ProductDimensions.createChannel(ShoppingProductChannel.LOCAL); assertEquals(ShoppingProductChannel.LOCAL, channel.getChannel()); } /** * Test method for createChannelExclusivity. */ @Test public void testCreateChannelExclusivity() { ProductChannelExclusivity channelExclusivity = ProductDimensions.createChannelExclusivity(ShoppingProductChannelExclusivity.MULTI_CHANNEL); assertEquals(ShoppingProductChannelExclusivity.MULTI_CHANNEL, channelExclusivity.getChannelExclusivity()); } /** * Test that verifies that {@link ProductDimensions} has a {@code createX} method for every * subclass {@code X} of {@link ProductDimension}. */ @SuppressWarnings("unchecked") @Test public void testCreateMethodExistsForEveryDimensionSubclass() throws Exception { String basePackageNameForVersion = ProductDimension.class.getPackage().getName() .substring(0, ProductDimension.class.getPackage().getName().length() - ".cm".length()); ClassPath classPath = ClassPath.from(ProductDimension.class.getClassLoader()); Set<Class<? extends ProductDimension>> dimensionSubclasses = Sets.newHashSet(); for (ClassInfo classInfo : classPath.getTopLevelClassesRecursive(basePackageNameForVersion)) { Class<?> classInfoClass = classInfo.load(); if (ProductDimension.class.isAssignableFrom(classInfoClass) && ProductDimension.class != classInfoClass) { dimensionSubclasses.add((Class<? extends ProductDimension>) classInfoClass); } } Map<Class<? extends ProductDimension>, Method> factoryMethodsMap = getAllProductDimensionFactoryMethods(); for (Class<? extends ProductDimension> dimensionSubclass : dimensionSubclasses) { if (!DIMENSION_TYPES_TO_IGNORE.contains(dimensionSubclass)) { assertThat( "No factory method exists for subclass " + dimensionSubclass + " of ProductDimension", dimensionSubclass, Matchers.isIn(factoryMethodsMap.keySet())); } } } /** * Test that verifies that this test class has a test method for every {@code createX} method of * {@link ProductDimensions}. */ @Test public void testCoverageOfAllCreateMethods() throws Exception { // Collect all of the testCreateX methods from this test class. Set<String> actualTestMethodNames = Sets.newHashSet(); for (Method method : getClass().getMethods()) { String methodName = method.getName(); if (methodName.startsWith("testCreate") && !methodName.contains("_")) { actualTestMethodNames.add(methodName); } } // Assert that each createX method of ProductDimensions has a corresponding // testCreateX method in this test class. for (Entry<Class<? extends ProductDimension>, Method> methodEntry : getAllProductDimensionFactoryMethods().entrySet()) { Method method = methodEntry.getValue(); String methodName = method.getName(); if (methodName.startsWith("create")) { String expectedTestMethodName = "testCreate" + methodName.substring("create".length()); assertThat("No test exists for factory method", expectedTestMethodName, Matchers.isIn(actualTestMethodNames)); } } } /** * Returns a map of return type to {@code createX} method from {@link ProductDimensions}. */ @SuppressWarnings("unchecked") static Map<Class<? extends ProductDimension>, Method> getAllProductDimensionFactoryMethods() { Map<Class<? extends ProductDimension>, Method> methodsMap = Maps.newHashMap(); for (Method method : ProductDimensions.class.getMethods()) { String methodName = method.getName(); if (methodName.startsWith("create")) { Class<?> returnType = method.getReturnType(); assertTrue(String.format("Return type %s of %s is not a subclass of ProductDimension", returnType, methodName), ProductDimension.class.isAssignableFrom(returnType)); methodsMap.put((Class<? extends ProductDimension>) returnType, method); } } return methodsMap; } }