blob: 5728a1699b170cba7c95643f7799c70986d3ce9d [file] [log] [blame]
/*
* 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 java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
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
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
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
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);
}
@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);
}
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.assertTrue("Type of property '" + property + "' should have changed", valueMap.get(property).getClass().equals(testResult.expectedNewType));
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.assertEquals("Final map entries do NOT match", expectedMap.entrySet(), valueMap.entrySet());
Assert.assertEquals("Final map keys do NOT match", expectedMap.keySet(), valueMap.keySet());
Assert.assertTrue("Final map values do NOT match expected: <" + expectedMap.values() + "> but was: <" + valueMap.values() + ">", CollectionUtils.isEqualCollection(expectedMap.values(), valueMap.values()));
}
/**
* <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;
}
}
}