| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.sling.api.wrappers; |
| |
| import static org.hamcrest.Matchers.containsInAnyOrder; |
| |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.sling.api.resource.ValueMap; |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| public class CompositeValueMapTest { |
| |
| // Test property names |
| private static final String PROP_NAME_UNCHANGED = "unchangedProp"; |
| private static final String PROP_NAME_OVERRIDDEN = "overriddenProp"; |
| private static final String PROP_NAME_NEW_TYPE = "newTypeProp"; |
| private static final String PROP_NAME_ADDED = "addedProp"; |
| private static final String PROP_NAME_DOES_NOT_EXIST = "doesNotExistProp"; |
| |
| // Default resource's property values |
| private static final String PROP_DEFAULT_UNCHANGED = "Default value of property '" + PROP_NAME_UNCHANGED + "'"; |
| private static final String PROP_DEFAULT_OVERRIDDEN = "Default value of property '" + PROP_NAME_OVERRIDDEN + "'"; |
| private static final String PROP_DEFAULT_NEW_TYPE = "10"; |
| |
| // Extended resource's property values |
| private static final String PROP_EXTENDED_OVERRIDDEN = "Extended value of property '" + PROP_NAME_OVERRIDDEN + "'"; |
| private static final Long PROP_EXTENDED_NEW_TYPE = 10L; |
| private static final String PROP_EXTENDED_ADDED = "Extended value of property '" + PROP_NAME_ADDED + "'"; |
| |
| private Map<String, Object> defaultProps = getDefaultProps(); |
| private Map<String, Object> extendedProps = getExtendedProps(); |
| |
| @Test |
| public void testMerge() throws Exception { |
| // Get value map for extended node using default node as defaults |
| @SuppressWarnings("deprecation") |
| CompositeValueMap valueMap = new CompositeValueMap( |
| getExtendedProps(), |
| getDefaultProps() |
| ); |
| |
| Set<CompositeValueMapTestResult> expectations = new HashSet<CompositeValueMapTestResult>(); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_UNCHANGED)); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_OVERRIDDEN)); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_NEW_TYPE, false, PROP_EXTENDED_NEW_TYPE.getClass())); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_ADDED)); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_DOES_NOT_EXIST)); |
| |
| verifyResults(valueMap, expectations); |
| } |
| |
| @Test |
| public void testMergeNoDefaults() throws Exception { |
| // Get value map for extended node using an empty default |
| @SuppressWarnings("deprecation") |
| CompositeValueMap valueMap = new CompositeValueMap( |
| getExtendedProps(), |
| null |
| ); |
| |
| Set<CompositeValueMapTestResult> expectations = new HashSet<CompositeValueMapTestResult>(); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_UNCHANGED, true)); // Property won't exist as there is no default |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_OVERRIDDEN)); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_NEW_TYPE, false, PROP_EXTENDED_NEW_TYPE.getClass())); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_ADDED)); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_DOES_NOT_EXIST)); |
| |
| verifyResults(valueMap, expectations); |
| } |
| |
| @Test |
| public void testOverride() throws Exception { |
| // Get value map for extended node using default node as defaults |
| // and override only mode |
| @SuppressWarnings("deprecation") |
| CompositeValueMap valueMap = new CompositeValueMap( |
| getExtendedProps(), |
| getDefaultProps(), |
| false |
| ); |
| |
| Set<CompositeValueMapTestResult> expectations = new HashSet<CompositeValueMapTestResult>(); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_UNCHANGED)); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_OVERRIDDEN)); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_NEW_TYPE, false, PROP_EXTENDED_NEW_TYPE.getClass())); |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_ADDED, true)); // Property won't exist as there is no default and it's an override |
| expectations.add(new CompositeValueMapTestResult(PROP_NAME_DOES_NOT_EXIST)); |
| |
| verifyResults(valueMap, expectations); |
| } |
| |
| @SuppressWarnings("deprecation") |
| @Test |
| public void testOverrideNoDefaults() throws Exception { |
| // Get value map for extended node using an empty default |
| // and override only mode |
| CompositeValueMap valueMap = new CompositeValueMap( |
| getExtendedProps(), |
| null, |
| false |
| ); |
| |
| Assert.assertTrue("Final map should be empty", valueMap.isEmpty()); |
| } |
| |
| private ValueMap getDefaultProps() { |
| final Map<String, Object> defaultProps = new HashMap<String, Object>(); |
| |
| defaultProps.put(PROP_NAME_UNCHANGED, PROP_DEFAULT_UNCHANGED); |
| defaultProps.put(PROP_NAME_OVERRIDDEN, PROP_DEFAULT_OVERRIDDEN); |
| defaultProps.put(PROP_NAME_NEW_TYPE, PROP_DEFAULT_NEW_TYPE); |
| |
| return new ValueMapDecorator(defaultProps); |
| } |
| |
| private ValueMap getExtendedProps() { |
| final Map<String, Object> defaultProps = new HashMap<String, Object>(); |
| |
| defaultProps.put(PROP_NAME_OVERRIDDEN, PROP_EXTENDED_OVERRIDDEN); |
| defaultProps.put(PROP_NAME_NEW_TYPE, PROP_EXTENDED_NEW_TYPE); |
| defaultProps.put(PROP_NAME_ADDED, PROP_EXTENDED_ADDED); |
| |
| return new ValueMapDecorator(defaultProps); |
| } |
| |
| @SuppressWarnings("deprecation") |
| private void verifyResults(CompositeValueMap valueMap, Set<CompositeValueMapTestResult> expectations) { |
| Map<String, Object> expectedMap = new HashMap<String, Object>(); |
| |
| int expectedSize = 0; |
| for (CompositeValueMapTestResult testResult : expectations) { |
| String property = testResult.propertyName; |
| |
| if (testResult.doesNotExist()) { |
| Assert.assertFalse("Property '" + property + "' should NOT exist", valueMap.containsKey(property)); |
| |
| } else if (testResult.shouldBeDeleted()) { |
| Assert.assertFalse("Property '" + property + "' should NOT be part of the final map", valueMap.containsKey(property)); |
| Assert.assertNull("Property '" + property + "' should be null", valueMap.get(property)); |
| |
| } else { |
| Assert.assertTrue("Property '" + property + "' should be part of the final map", valueMap.containsKey(property)); |
| expectedSize++; |
| |
| if (testResult.shouldBeUnchanged()) { |
| Assert.assertEquals("Property '" + property + "' should NOT have changed", testResult.defaultValue, valueMap.get(property)); |
| expectedMap.put(property, testResult.defaultValue); |
| } |
| |
| if (testResult.shouldBeOverriden()) { |
| Assert.assertEquals("Property '" + property + "' should have changed", testResult.extendedValue, valueMap.get(property)); |
| expectedMap.put(property, testResult.extendedValue); |
| } |
| |
| if (testResult.shouldHaveNewType()) { |
| Assert.assertEquals("Type of property '" + property + "' should have changed",testResult.expectedNewType, valueMap.get(property).getClass()); |
| expectedMap.put(property, testResult.extendedValue); |
| } |
| |
| if (testResult.shouldBeAdded()) { |
| Assert.assertEquals("Property '" + property + "' should have been added", testResult.extendedValue, valueMap.get(property)); |
| expectedMap.put(property, testResult.extendedValue); |
| } |
| } |
| } |
| |
| Assert.assertEquals("Final map size does NOT match", expectedSize, valueMap.size()); |
| Assert.assertThat("Final map keys do NOT match", valueMap.keySet(), containsInAnyOrder(expectedMap.keySet().toArray())); |
| Assert.assertThat("Final map values do NOT match", valueMap.values(), containsInAnyOrder(expectedMap.values().toArray())); |
| Assert.assertThat("Final map entries do NOT match", valueMap.entrySet(), containsInAnyOrder(expectedMap.entrySet().toArray())); |
| } |
| |
| /** |
| * <code>CompositeValueMapTestResult</code> is an internal helper to analyze |
| * test result and check if the value retrieved from the map matches the |
| * expected value. |
| */ |
| private class CompositeValueMapTestResult { |
| private final String propertyName; |
| private final Object defaultValue; |
| private final Object extendedValue; |
| private final boolean shouldBeDeleted; |
| private final Class<?> expectedNewType; |
| |
| private CompositeValueMapTestResult(String propertyName) { |
| this(propertyName, false); |
| } |
| |
| private CompositeValueMapTestResult(String propertyName, boolean shouldBeDeleted) { |
| this(propertyName, shouldBeDeleted, null); |
| } |
| |
| private CompositeValueMapTestResult(String propertyName, boolean shouldBeDeleted, Class<?> expectedNewType) { |
| this.propertyName = propertyName; |
| this.defaultValue = defaultProps.get(propertyName); |
| this.extendedValue = extendedProps.get(propertyName); |
| this.shouldBeDeleted = shouldBeDeleted; |
| this.expectedNewType = expectedNewType; |
| } |
| |
| /** |
| * Checks if the value should not have changed |
| * @return <code>true</code> if the value should not have changed |
| */ |
| boolean shouldBeUnchanged() { |
| return defaultValue != null && extendedValue == null; |
| } |
| |
| /** |
| * Checks if the value should have been overridden |
| * @return <code>true</code> if the value should have been overridden |
| */ |
| boolean shouldBeOverriden() { |
| return defaultValue != null && extendedValue != null; |
| } |
| |
| /** |
| * Checks if the value should have a new type |
| * @return <code>true</code> if the value should have a new type |
| */ |
| boolean shouldHaveNewType() { |
| return expectedNewType != null; |
| } |
| |
| /** |
| * Checks if the property should have been added |
| * @return <code>true</code> if the property should have been added |
| */ |
| boolean shouldBeAdded() { |
| return defaultValue == null && extendedValue != null; |
| } |
| |
| /** |
| * Checks if the property should have been deleted |
| * @return <code>true</code> if the property should have been deleted |
| */ |
| boolean shouldBeDeleted() { |
| return shouldBeDeleted; |
| } |
| |
| /** |
| * Checks if the property should not exist |
| * @return <code>true</code> if the property should not exist |
| */ |
| boolean doesNotExist() { |
| return defaultValue == null && extendedValue == null; |
| } |
| |
| } |
| |
| } |