From 73347b398dce6853724b8357b2b8376dcbbc8e36 Mon Sep 17 00:00:00 2001 From: Johannes Link Date: Mon, 18 Jan 2016 09:58:26 +0100 Subject: [PATCH 1/3] Suggestion implemented --- .../descriptor/ExtensionContextTests.java | 38 ++--- .../descriptor/ExtensionValuesStoreTest.java | 115 ++++++------- .../gen5/api/extension/ExtensionContext.java | 153 +++++++++--------- .../descriptor/AbstractExtensionContext.java | 52 +----- .../descriptor/ExtensionValuesStore.java | 49 +----- .../junit5/descriptor/NamespacedStore.java | 46 ++++++ .../com/example/mockito/MockitoExtension.java | 8 +- .../com/example/timing/TimingExtension.java | 10 +- 8 files changed, 208 insertions(+), 263 deletions(-) create mode 100644 junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java diff --git a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java index 07bf6d063d7..62153c99bf8 100644 --- a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java +++ b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionContextTests.java @@ -122,45 +122,25 @@ public void reportEntriesArePublishedToExecutionContext() { } @Test - public void storingAttributesWithDefaultNamespace() { + public void usingStore() { MethodTestDescriptor methodTestDescriptor = methodDescriptor(); ClassTestDescriptor classTestDescriptor = outerClassDescriptor(methodTestDescriptor); ExtensionContext parentContext = new ClassBasedContainerExtensionContext(null, null, classTestDescriptor); MethodBasedTestExtensionContext childContext = new MethodBasedTestExtensionContext(parentContext, null, methodTestDescriptor, new OuterClass()); - childContext.put("a key", "a value"); - assertEquals("a value", childContext.get("a key")); + ExtensionContext.Store store = childContext.getStore(); - assertEquals("other value", childContext.getOrComputeIfAbsent("other key", key -> "other value")); + store.put("a key", "a value"); + assertEquals("a value", store.get("a key")); - childContext.remove("a key"); - assertNull(childContext.get("a key")); + assertEquals("other value", store.getOrComputeIfAbsent("other key", key -> "other value")); - parentContext.put("parent key", "parent value"); - assertEquals("parent value", childContext.get("parent key")); - } - - @Test - public void storingAttributesWithNamespace() { - MethodTestDescriptor methodTestDescriptor = methodDescriptor(); - ClassTestDescriptor classTestDescriptor = outerClassDescriptor(methodTestDescriptor); - ExtensionContext parentContext = new ClassBasedContainerExtensionContext(null, null, classTestDescriptor); - MethodBasedTestExtensionContext childContext = new MethodBasedTestExtensionContext(parentContext, null, - methodTestDescriptor, new OuterClass()); - - String namespace = "a namespace"; - - childContext.put("a key", "a value", namespace); - assertEquals("a value", childContext.get("a key", namespace)); - - assertEquals("other value", childContext.getOrComputeIfAbsent("other key", key -> "other value"), namespace); - - childContext.remove("a key", namespace); - assertNull(childContext.get("a key", namespace)); + assertEquals("a value", store.remove("a key")); + assertNull(store.get("a key")); - parentContext.put("parent key", "parent value", namespace); - assertEquals("parent value", childContext.get("parent key", namespace)); + store.put("parent key", "parent value"); + assertEquals("parent value", store.get("parent key")); } private ClassTestDescriptor nestedClassDescriptor() { diff --git a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java index 7bd154a121e..9f8a476053c 100644 --- a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java +++ b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java @@ -15,7 +15,7 @@ import org.junit.gen5.api.BeforeEach; import org.junit.gen5.api.Nested; import org.junit.gen5.api.Test; -import org.junit.gen5.engine.junit5.descriptor.ExtensionValuesStore.Namespace; +import org.junit.gen5.api.extension.ExtensionContext.*; /** * Microtests for {@link ExtensionValuesStore} @@ -29,6 +29,8 @@ class ExtensionValuesStoreTests { private Object value = createObject("value"); + private Namespace namespace = Namespace.of("ns"); + @BeforeEach void initializeStore() { parentStore = new ExtensionValuesStore(); @@ -36,124 +38,125 @@ void initializeStore() { } @Nested - class UsingDefaultNamespaceTests { + class StoringValuesTests { @Test void getWithUnknownKeyReturnsNull() { - assertNull(store.get("unknown key")); + assertNull(store.get("unknown key", namespace)); } @Test void putAndGetWithSameKey() { - store.put(key, value); - assertEquals(value, store.get(key)); + store.put(key, value, namespace); + assertEquals(value, store.get(key, namespace)); } @Test void valueCanBeReplaced() { - store.put(key, value); + store.put(key, value, namespace); Object newValue = new Object(); - store.put(key, newValue); + store.put(key, newValue, namespace); - assertEquals(newValue, store.get(key)); + assertEquals(newValue, store.get(key, namespace)); } @Test void valueIsComputedIfAbsent() { - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value)); - assertEquals(value, store.get(key)); + assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value, namespace)); + assertEquals(value, store.get(key, namespace)); } @Test void valueIsNotComputedIfPresent() { - store.put(key, value); + store.put(key, value, namespace); - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> "a different value")); - assertEquals(value, store.get(key)); + assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> "a different value", namespace)); + assertEquals(value, store.get(key, namespace)); } @Test void nullIsAValidValueToPut() { - store.put(key, null); + store.put(key, null, namespace); - assertEquals(null, store.getOrComputeIfAbsent(key, innerKey -> "a different value")); - assertEquals(null, store.get(key)); + assertEquals(null, store.getOrComputeIfAbsent(key, innerKey -> "a different value", namespace)); + assertEquals(null, store.get(key, namespace)); } @Test void keysCanBeRemoved() { - store.put(key, value); - store.remove(key); + store.put(key, value, namespace); + assertEquals(value, store.remove(key, namespace)); - assertNull(store.get(key)); - assertEquals("a different value", store.getOrComputeIfAbsent(key, innerKey -> "a different value")); + assertNull(store.get(key, namespace)); + assertEquals("a different value", + store.getOrComputeIfAbsent(key, innerKey -> "a different value", namespace)); } - } + @Test + void sameKeyWithDifferentNamespaces() { + Object value1 = createObject("value1"); + Namespace namespace1 = Namespace.of("ns1"); - @Nested - class InheritedValuesTests { + Object value2 = createObject("value2"); + Namespace namespace2 = Namespace.of("ns2"); - @Test - void valueFromParentIsVisible() { - parentStore.put(key, value); - assertEquals(value, store.get(key)); + store.put(key, value1, namespace1); + store.put(key, value2, namespace2); + + assertEquals(value1, store.get(key, namespace1)); + assertEquals(value2, store.get(key, namespace2)); } @Test - void valueFromParentCanBeOverriddenInChild() { - parentStore.put(key, value); + void valueIsComputedIfAbsentInDifferentNamespace() { + Namespace namespace1 = Namespace.of("ns1"); + Namespace namespace2 = Namespace.of("ns2"); - Object otherValue = new Object(); - store.put(key, otherValue); - assertEquals(otherValue, store.get(key)); + assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value, namespace1)); + assertEquals(value, store.get(key, namespace1)); - assertEquals(value, parentStore.get(key)); + assertNull(store.get(key, namespace2)); } - } - - @Nested - class UsingExplicitNamespaceTests { @Test - void sameKeyWithDifferentNamespaces() { - Object value1 = createObject("value1"); - Namespace namespace1 = Namespace.sharedWith("ns1"); + void keyIsOnlyRemovedInGivenNamespace() { + Namespace namespace1 = Namespace.of("ns1"); + Namespace namespace2 = Namespace.of("ns2"); + Object value1 = createObject("value1"); Object value2 = createObject("value2"); - Namespace namespace2 = Namespace.sharedWith("ns2"); store.put(key, value1, namespace1); store.put(key, value2, namespace2); + store.remove(key, namespace1); - assertEquals(value1, store.get(key, namespace1)); + assertNull(store.get(key, namespace1)); assertEquals(value2, store.get(key, namespace2)); } + } + + @Nested + class InheritedValuesTests { + @Test - void valueIsComputedIfAbsentInDifferentNamespace() { - Namespace namespace = Namespace.sharedWith("ns"); - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value, namespace)); + void valueFromParentIsVisible() { + parentStore.put(key, value, namespace); assertEquals(value, store.get(key, namespace)); - - assertNull(store.get(key)); } @Test - void keyIsOnlyRemovedInGivenNamespace() { - Namespace namespace = Namespace.sharedWith("ns"); - Object valueInNamespace = createObject("valueInNamespace"); + void valueFromParentCanBeOverriddenInChild() { + parentStore.put(key, value, namespace); - store.put(key, value); - store.put(key, valueInNamespace, namespace); - store.remove(key, namespace); + Object otherValue = new Object(); + store.put(key, otherValue, namespace); + assertEquals(otherValue, store.get(key, namespace)); - assertNull(store.get(key, namespace)); - assertEquals(value, store.get(key)); + assertEquals(value, parentStore.get(key, namespace)); } - } private Object createObject(final String display) { diff --git a/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java b/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java index 8841dab880a..1870cef074d 100644 --- a/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java +++ b/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java @@ -15,6 +15,8 @@ import java.util.Optional; import java.util.function.Function; +import org.junit.gen5.commons.util.Preconditions; + /** * {@code ExtensionContext} encapsulates the context in which the * current test or container is being executed. @@ -55,82 +57,6 @@ public interface ExtensionContext { AnnotatedElement getElement(); - // Storing methods. - - /** - * Get an object that has been stored using a {@code key} - * - * @param key the key - * @return the value - */ - Object get(Object key); - - /** - * Store a {@code value} for later retrieval using a {@code key}. {@code null} is a valid value. - * - * @param key the key - * @param value the value - */ - void put(Object key, Object value); - - /** - * Get an object that has been stored using a {@code key}. If no value has been store using that {@code key} - * the value will be computed by the {@code defaultCreator} and be stored. - * - * @param key the key - * @param defaultCreator the function called to create the value - * @return the value - */ - Object getOrComputeIfAbsent(Object key, Function defaultCreator); - - /** - * Remove a value that was previously stored using {@code key} so that {@code key} can be used anew. - * - * @param key the key - * @return the previous value or {@code null} if no value was present - * for the specified key - */ - Object remove(Object key); - - /** - * Get an object that has been stored using a {@code key} - * - * @param key the key - * @param namespace the namespace - * @return the value - */ - Object get(Object key, String namespace); - - /** - * Store a {@code value} for later retrieval using a {@code key}. {@code null} is a valid value. - * - * @param key the key - * @param value the value - * @param namespace the namespace - */ - void put(Object key, Object value, String namespace); - - /** - * Get an object that has been stored using a {@code key}. If no value has been store using that {@code key} - * the value will be computed by the {@code defaultCreator} and be stored. - * - * @param key the key - * @param defaultCreator the function called to create the value - * @param namespace the namespace - * @return the value - */ - Object getOrComputeIfAbsent(Object key, Function defaultCreator, String namespace); - - /** - * Remove a value that was previously stored using {@code key} so that {@code key} can be used anew. - * - * @param key the key - * @param namespace the namespace - * @return the previous value or {@code null} if no value was present - * for the specified key and namespace - */ - Object remove(Object key, String namespace); - // Attributes will be removed when storing methods are done Object getAttribute(String key); @@ -139,4 +65,79 @@ public interface ExtensionContext { Object removeAttribute(String key); + default Store getStore() { + return getStore(Namespace.DEFAULT); + } + + Store getStore(Namespace namespace); + + interface Store { + /** + * Get an object that has been stored using a {@code key} + * + * @param key the key + * @return the value + */ + Object get(Object key); + + /** + * Store a {@code value} for later retrieval using a {@code key}. {@code null} is a valid value. + * + * @param key the key + * @param value the value + */ + void put(Object key, Object value); + + /** + * Get an object that has been stored using a {@code key}. If no value has been store using that {@code key} + * the value will be computed by the {@code defaultCreator} and be stored. + * + * @param key the key + * @param defaultCreator the function called to create the value + * @return the value + */ + Object getOrComputeIfAbsent(Object key, Function defaultCreator); + + /** + * Remove a value that was previously stored using {@code key} so that {@code key} can be used anew. + * + * @param key the key + * @return the previous value or {@code null} if no value was present + * for the specified key + */ + Object remove(Object key); + } + + public static class Namespace { + + public static Namespace DEFAULT = Namespace.of(new Object()); + + public static Namespace of(Object ref) { + Preconditions.notNull(ref, "A local must not be null"); + + return new Namespace(ref); + } + + private final Object local; + + private Namespace(Object local) { + this.local = local; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Namespace namespace = (Namespace) o; + return local != null ? local.equals(namespace.local) : namespace.local == null; + } + + @Override + public int hashCode() { + return local != null ? local.hashCode() : 0; + } + } + } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java index 4aef26fcbaa..bc70a303a24 100644 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/AbstractExtensionContext.java @@ -13,19 +13,17 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.function.Function; import org.junit.gen5.api.extension.ExtensionContext; import org.junit.gen5.engine.EngineExecutionListener; import org.junit.gen5.engine.TestDescriptor; -import org.junit.gen5.engine.junit5.descriptor.ExtensionValuesStore.Namespace; abstract class AbstractExtensionContext implements ExtensionContext { private final Map attributes = new HashMap<>(); //Will replace attributes if done - private final ExtensionValuesStore store; + private final ExtensionValuesStore valuesStore; private final ExtensionContext parent; private final EngineExecutionListener engineExecutionListener; @@ -36,13 +34,13 @@ abstract class AbstractExtensionContext implements ExtensionContext { this.parent = parent; this.engineExecutionListener = engineExecutionListener; this.testDescriptor = testDescriptor; - this.store = createStore(parent); + this.valuesStore = createStore(parent); } private final ExtensionValuesStore createStore(ExtensionContext parent) { ExtensionValuesStore parentStore = null; if (parent != null) { - parentStore = ((AbstractExtensionContext) parent).store; + parentStore = ((AbstractExtensionContext) parent).valuesStore; } return new ExtensionValuesStore(parentStore); } @@ -79,48 +77,8 @@ protected TestDescriptor getTestDescriptor() { return testDescriptor; } - //Storing methods. All delegate to the store. - //TODO: Remove duplication between these methods and ExtensionValuesStore - // as soon as we have a decision if methods should be exposed on store object instead of via delegation - - @Override - public Object get(Object key) { - return store.get(key); - } - - @Override - public void put(Object key, Object value) { - store.put(key, value); - } - - @Override - public Object getOrComputeIfAbsent(Object key, Function defaultCreator) { - return store.getOrComputeIfAbsent(key, defaultCreator); - } - @Override - public Object remove(Object key) { - return store.remove(key); + public Store getStore(Namespace namespace) { + return new NamespacedStore(valuesStore, namespace); } - - @Override - public Object get(Object key, String namespace) { - return store.get(key, Namespace.sharedWith(namespace)); - } - - @Override - public void put(Object key, Object value, String namespace) { - store.put(key, value, Namespace.sharedWith(namespace)); - } - - @Override - public Object getOrComputeIfAbsent(Object key, Function defaultCreator, String namespace) { - return store.getOrComputeIfAbsent(key, defaultCreator, Namespace.sharedWith(namespace)); - } - - @Override - public Object remove(Object key, String namespace) { - return store.remove(key, Namespace.sharedWith(namespace)); - } - } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java index edc3759c1a7..97eebf2235a 100644 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.function.Function; +import org.junit.gen5.api.extension.ExtensionContext.Namespace; import org.junit.gen5.commons.util.Preconditions; /** @@ -33,10 +34,6 @@ public ExtensionValuesStore(ExtensionValuesStore parentStore) { this.parentStore = parentStore; } - public Object get(Object key) { - return get(key, Namespace.DEFAULT); - } - public Object get(Object key, Namespace namespace) { StoredValue storedValue = getStoredValue(key, namespace); if (storedValue != null) @@ -52,10 +49,6 @@ private StoredValue getStoredValue(Object key, Namespace namespace) { return storedValues.get(composedKey); } - public void put(Object key, Object value) { - put(key, value, Namespace.DEFAULT); - } - public void put(Object key, Object value, Namespace namespace) { Preconditions.notNull(key, "A key must not be null"); Preconditions.notNull(namespace, "A namespace must not be null"); @@ -68,10 +61,6 @@ private void putStoredValue(Object key, Namespace namespace, StoredValue storedV storedValues.put(composedKey, storedValue); } - public Object getOrComputeIfAbsent(Object key, Function defaultCreator) { - return getOrComputeIfAbsent(key, defaultCreator, Namespace.DEFAULT); - } - public Object getOrComputeIfAbsent(Object key, Function defaultCreator, Namespace namespace) { StoredValue storedValue = getStoredValue(key, namespace); if (storedValue == null) { @@ -81,10 +70,6 @@ public Object getOrComputeIfAbsent(Object key, Function defaultC return storedValue.value; } - public Object remove(Object key) { - return remove(key, Namespace.DEFAULT); - } - public Object remove(Object key, Namespace namespace) { ComposedKey composedKey = new ComposedKey(key, namespace); StoredValue previous = storedValues.remove(composedKey); @@ -126,36 +111,4 @@ private StoredValue(Object value) { } } - public static class Namespace { - - public static Namespace DEFAULT = Namespace.sharedWith(new Object()); - - public static Namespace sharedWith(Object local) { - Preconditions.notNull(local, "A local must not be null"); - - return new Namespace(local); - } - - private final Object local; - - private Namespace(Object local) { - this.local = local; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - Namespace namespace = (Namespace) o; - return local != null ? local.equals(namespace.local) : namespace.local == null; - } - - @Override - public int hashCode() { - return local != null ? local.hashCode() : 0; - } - } - } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java new file mode 100644 index 00000000000..6e0ba62515b --- /dev/null +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2016 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution and is available at + * + * http://www.eclipse.org/legal/epl-v10.html + */ + +package org.junit.gen5.engine.junit5.descriptor; + +import java.util.function.Function; + +import org.junit.gen5.api.extension.ExtensionContext.Namespace; +import org.junit.gen5.api.extension.ExtensionContext.Store; + +public class NamespacedStore implements Store { + private final ExtensionValuesStore valuesStore; + private final Namespace namespace; + + public NamespacedStore(ExtensionValuesStore valuesStore, Namespace namespace) { + this.valuesStore = valuesStore; + this.namespace = namespace; + } + + @Override + public Object get(Object key) { + return valuesStore.get(key, namespace); + } + + @Override + public void put(Object key, Object value) { + valuesStore.put(key, value, namespace); + } + + @Override + public Object getOrComputeIfAbsent(Object key, Function defaultCreator) { + return valuesStore.getOrComputeIfAbsent(key, defaultCreator, namespace); + } + + @Override + public Object remove(Object key) { + return valuesStore.remove(key, namespace); + } +} diff --git a/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java b/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java index 3ff10dd6201..7a79992fbe8 100644 --- a/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java +++ b/sample-extension/src/main/java/com/example/mockito/MockitoExtension.java @@ -49,12 +49,12 @@ public boolean supports(Parameter parameter, MethodInvocationContext methodInvoc @Override public Object resolve(Parameter parameter, MethodInvocationContext methodInvocationContext, ExtensionContext extensionContext) throws ParameterResolutionException { - return getMock(parameter.getType(), extensionContext); + ExtensionContext.Store mocks = extensionContext.getStore(ExtensionContext.Namespace.of(getClass())); + return getMock(parameter.getType(), mocks); } - private Object getMock(Class mockType, ExtensionContext extensionContext) { - return extensionContext.getOrComputeIfAbsent(mockType, type -> mock(mockType), - MockitoExtension.class.getName()); + private Object getMock(Class mockType, ExtensionContext.Store mocks) { + return mocks.getOrComputeIfAbsent(mockType, type -> mock(mockType)); } } diff --git a/sample-extension/src/main/java/com/example/timing/TimingExtension.java b/sample-extension/src/main/java/com/example/timing/TimingExtension.java index 47013f48354..560ec54c07c 100644 --- a/sample-extension/src/main/java/com/example/timing/TimingExtension.java +++ b/sample-extension/src/main/java/com/example/timing/TimingExtension.java @@ -16,6 +16,8 @@ import org.junit.gen5.api.extension.AfterEachExtensionPoint; import org.junit.gen5.api.extension.BeforeEachExtensionPoint; +import org.junit.gen5.api.extension.ExtensionContext; +import org.junit.gen5.api.extension.ExtensionContext.Namespace; import org.junit.gen5.api.extension.ExtensionPointRegistry; import org.junit.gen5.api.extension.ExtensionRegistrar; import org.junit.gen5.api.extension.TestExtensionContext; @@ -35,17 +37,19 @@ public void registerExtensions(ExtensionPointRegistry registry) { private static class TestMethodInvocationWrapper implements BeforeEachExtensionPoint, AfterEachExtensionPoint { - private final String namespace = getClass().getName(); + private final Namespace namespace = Namespace.of(getClass()); @Override public void beforeEach(TestExtensionContext context) throws Exception { - context.put(context.getTestMethod(), System.currentTimeMillis(), namespace); + ExtensionContext.Store times = context.getStore(namespace); + times.put(context.getTestMethod(), System.currentTimeMillis()); } @Override public void afterEach(TestExtensionContext context) throws Exception { + ExtensionContext.Store times = context.getStore(namespace); Method testMethod = context.getTestMethod(); - long start = (long) context.remove(testMethod, namespace); + long start = (long) times.remove(testMethod); long duration = System.currentTimeMillis() - start; System.out.println(String.format("Method [%s] took %s ms.", testMethod, duration)); From affc4be6f518247372da05003347dfcd4b2c237c Mon Sep 17 00:00:00 2001 From: Johannes Link Date: Tue, 19 Jan 2016 12:01:33 +0100 Subject: [PATCH 2/3] Namespace can be created with several parts. --- .../descriptor/ExtensionValuesStoreTest.java | 34 +++++++++++++++++++ .../gen5/api/extension/ExtensionContext.java | 20 ++++++----- .../com/example/timing/TimingExtension.java | 8 +++-- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java index 9f8a476053c..4c9488b7845 100644 --- a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java +++ b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java @@ -159,6 +159,40 @@ void valueFromParentCanBeOverriddenInChild() { } } + @Nested + class CompositNamespaceTests { + + @Test + void additionNamespacePartMakesADifferenc() { + + Namespace ns1 = Namespace.of("part1", "part2"); + Namespace ns2 = Namespace.of("part1"); + Namespace ns3 = Namespace.of("part1", "part2"); + + Object value2 = createObject("value2"); + + parentStore.put(key, value, ns1); + parentStore.put(key, value2, ns2); + + assertEquals(value, store.get(key, ns1)); + assertEquals(value, store.get(key, ns3)); + assertEquals(value2, store.get(key, ns2)); + } + + @Test + void orderOfNamespacePartsDoesNotMatter() { + + Namespace ns1 = Namespace.of("part1", "part2"); + Namespace ns2 = Namespace.of("part2", "part1"); + + parentStore.put(key, value, ns1); + + assertEquals(value, store.get(key, ns1)); + assertEquals(value, store.get(key, ns2)); + } + + } + private Object createObject(final String display) { return new Object() { @Override diff --git a/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java b/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java index 1870cef074d..5b4220aa8d6 100644 --- a/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java +++ b/junit5-api/src/main/java/org/junit/gen5/api/extension/ExtensionContext.java @@ -11,8 +11,11 @@ package org.junit.gen5.api.extension; import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; +import java.util.HashSet; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import org.junit.gen5.commons.util.Preconditions; @@ -112,16 +115,17 @@ public static class Namespace { public static Namespace DEFAULT = Namespace.of(new Object()); - public static Namespace of(Object ref) { - Preconditions.notNull(ref, "A local must not be null"); + public static Namespace of(Object... parts) { + Preconditions.notEmpty(Arrays.asList(parts), + "There must be at least one reference object to create a namespace"); - return new Namespace(ref); + return new Namespace(parts); } - private final Object local; + private final Set parts; - private Namespace(Object local) { - this.local = local; + private Namespace(Object... parts) { + this.parts = new HashSet<>(Arrays.asList(parts)); } @Override @@ -131,12 +135,12 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Namespace namespace = (Namespace) o; - return local != null ? local.equals(namespace.local) : namespace.local == null; + return parts.equals(namespace.parts); } @Override public int hashCode() { - return local != null ? local.hashCode() : 0; + return parts.hashCode(); } } diff --git a/sample-extension/src/main/java/com/example/timing/TimingExtension.java b/sample-extension/src/main/java/com/example/timing/TimingExtension.java index 560ec54c07c..7394c89dace 100644 --- a/sample-extension/src/main/java/com/example/timing/TimingExtension.java +++ b/sample-extension/src/main/java/com/example/timing/TimingExtension.java @@ -41,13 +41,17 @@ private static class TestMethodInvocationWrapper implements BeforeEachExtensionP @Override public void beforeEach(TestExtensionContext context) throws Exception { - ExtensionContext.Store times = context.getStore(namespace); + ExtensionContext.Store times = context.getStore(getNamespace(context)); times.put(context.getTestMethod(), System.currentTimeMillis()); } + private Namespace getNamespace(TestExtensionContext context) { + return Namespace.of(getClass(), context); + } + @Override public void afterEach(TestExtensionContext context) throws Exception { - ExtensionContext.Store times = context.getStore(namespace); + ExtensionContext.Store times = context.getStore(getNamespace(context)); Method testMethod = context.getTestMethod(); long start = (long) times.remove(testMethod); long duration = System.currentTimeMillis() - start; From c59bfae8162a8a1049a45edfe6613357c625770e Mon Sep 17 00:00:00 2001 From: Johannes Link Date: Tue, 19 Jan 2016 15:45:13 +0100 Subject: [PATCH 3/3] Reversed parameter positions in ExtensionValuesStore according to team decision --- .../descriptor/ExtensionValuesStoreTest.java | 88 +++++++++---------- .../descriptor/ExtensionValuesStore.java | 30 +++---- .../junit5/descriptor/NamespacedStore.java | 8 +- 3 files changed, 63 insertions(+), 63 deletions(-) diff --git a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java index 4c9488b7845..0b2efd466d1 100644 --- a/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java +++ b/junit-tests/src/test/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStoreTest.java @@ -42,56 +42,56 @@ class StoringValuesTests { @Test void getWithUnknownKeyReturnsNull() { - assertNull(store.get("unknown key", namespace)); + assertNull(store.get(namespace, "unknown key")); } @Test void putAndGetWithSameKey() { - store.put(key, value, namespace); - assertEquals(value, store.get(key, namespace)); + store.put(namespace, key, value); + assertEquals(value, store.get(namespace, key)); } @Test void valueCanBeReplaced() { - store.put(key, value, namespace); + store.put(namespace, key, value); Object newValue = new Object(); - store.put(key, newValue, namespace); + store.put(namespace, key, newValue); - assertEquals(newValue, store.get(key, namespace)); + assertEquals(newValue, store.get(namespace, key)); } @Test void valueIsComputedIfAbsent() { - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value, namespace)); - assertEquals(value, store.get(key, namespace)); + assertEquals(value, store.getOrComputeIfAbsent(namespace, key, innerKey -> value)); + assertEquals(value, store.get(namespace, key)); } @Test void valueIsNotComputedIfPresent() { - store.put(key, value, namespace); + store.put(namespace, key, value); - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> "a different value", namespace)); - assertEquals(value, store.get(key, namespace)); + assertEquals(value, store.getOrComputeIfAbsent(namespace, key, innerKey -> "a different value")); + assertEquals(value, store.get(namespace, key)); } @Test void nullIsAValidValueToPut() { - store.put(key, null, namespace); + store.put(namespace, key, null); - assertEquals(null, store.getOrComputeIfAbsent(key, innerKey -> "a different value", namespace)); - assertEquals(null, store.get(key, namespace)); + assertEquals(null, store.getOrComputeIfAbsent(namespace, key, innerKey -> "a different value")); + assertEquals(null, store.get(namespace, key)); } @Test void keysCanBeRemoved() { - store.put(key, value, namespace); - assertEquals(value, store.remove(key, namespace)); + store.put(namespace, key, value); + assertEquals(value, store.remove(namespace, key)); - assertNull(store.get(key, namespace)); + assertNull(store.get(namespace, key)); assertEquals("a different value", - store.getOrComputeIfAbsent(key, innerKey -> "a different value", namespace)); + store.getOrComputeIfAbsent(namespace, key, innerKey -> "a different value")); } @Test @@ -102,11 +102,11 @@ void sameKeyWithDifferentNamespaces() { Object value2 = createObject("value2"); Namespace namespace2 = Namespace.of("ns2"); - store.put(key, value1, namespace1); - store.put(key, value2, namespace2); + store.put(namespace1, key, value1); + store.put(namespace2, key, value2); - assertEquals(value1, store.get(key, namespace1)); - assertEquals(value2, store.get(key, namespace2)); + assertEquals(value1, store.get(namespace1, key)); + assertEquals(value2, store.get(namespace2, key)); } @Test @@ -114,10 +114,10 @@ void valueIsComputedIfAbsentInDifferentNamespace() { Namespace namespace1 = Namespace.of("ns1"); Namespace namespace2 = Namespace.of("ns2"); - assertEquals(value, store.getOrComputeIfAbsent(key, innerKey -> value, namespace1)); - assertEquals(value, store.get(key, namespace1)); + assertEquals(value, store.getOrComputeIfAbsent(namespace1, key, innerKey -> value)); + assertEquals(value, store.get(namespace1, key)); - assertNull(store.get(key, namespace2)); + assertNull(store.get(namespace2, key)); } @Test @@ -128,12 +128,12 @@ void keyIsOnlyRemovedInGivenNamespace() { Object value1 = createObject("value1"); Object value2 = createObject("value2"); - store.put(key, value1, namespace1); - store.put(key, value2, namespace2); - store.remove(key, namespace1); + store.put(namespace1, key, value1); + store.put(namespace2, key, value2); + store.remove(namespace1, key); - assertNull(store.get(key, namespace1)); - assertEquals(value2, store.get(key, namespace2)); + assertNull(store.get(namespace1, key)); + assertEquals(value2, store.get(namespace2, key)); } } @@ -143,19 +143,19 @@ class InheritedValuesTests { @Test void valueFromParentIsVisible() { - parentStore.put(key, value, namespace); - assertEquals(value, store.get(key, namespace)); + parentStore.put(namespace, key, value); + assertEquals(value, store.get(namespace, key)); } @Test void valueFromParentCanBeOverriddenInChild() { - parentStore.put(key, value, namespace); + parentStore.put(namespace, key, value); Object otherValue = new Object(); - store.put(key, otherValue, namespace); - assertEquals(otherValue, store.get(key, namespace)); + store.put(namespace, key, otherValue); + assertEquals(otherValue, store.get(namespace, key)); - assertEquals(value, parentStore.get(key, namespace)); + assertEquals(value, parentStore.get(namespace, key)); } } @@ -171,12 +171,12 @@ void additionNamespacePartMakesADifferenc() { Object value2 = createObject("value2"); - parentStore.put(key, value, ns1); - parentStore.put(key, value2, ns2); + parentStore.put(ns1, key, value); + parentStore.put(ns2, key, value2); - assertEquals(value, store.get(key, ns1)); - assertEquals(value, store.get(key, ns3)); - assertEquals(value2, store.get(key, ns2)); + assertEquals(value, store.get(ns1, key)); + assertEquals(value, store.get(ns3, key)); + assertEquals(value2, store.get(ns2, key)); } @Test @@ -185,10 +185,10 @@ void orderOfNamespacePartsDoesNotMatter() { Namespace ns1 = Namespace.of("part1", "part2"); Namespace ns2 = Namespace.of("part2", "part1"); - parentStore.put(key, value, ns1); + parentStore.put(ns1, key, value); - assertEquals(value, store.get(key, ns1)); - assertEquals(value, store.get(key, ns2)); + assertEquals(value, store.get(ns1, key)); + assertEquals(value, store.get(ns2, key)); } } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java index 97eebf2235a..b8fd206e063 100644 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/ExtensionValuesStore.java @@ -34,44 +34,44 @@ public ExtensionValuesStore(ExtensionValuesStore parentStore) { this.parentStore = parentStore; } - public Object get(Object key, Namespace namespace) { - StoredValue storedValue = getStoredValue(key, namespace); + public Object get(Namespace namespace, Object key) { + StoredValue storedValue = getStoredValue(namespace, key); if (storedValue != null) return storedValue.value; else if (parentStore != null) - return parentStore.get(key, namespace); + return parentStore.get(namespace, key); else return null; } - private StoredValue getStoredValue(Object key, Namespace namespace) { - ComposedKey composedKey = new ComposedKey(key, namespace); + private StoredValue getStoredValue(Namespace namespace, Object key) { + ComposedKey composedKey = new ComposedKey(namespace, key); return storedValues.get(composedKey); } - public void put(Object key, Object value, Namespace namespace) { + public void put(Namespace namespace, Object key, Object value) { Preconditions.notNull(key, "A key must not be null"); Preconditions.notNull(namespace, "A namespace must not be null"); - putStoredValue(key, namespace, new StoredValue(value)); + putStoredValue(namespace, key, new StoredValue(value)); } - private void putStoredValue(Object key, Namespace namespace, StoredValue storedValue) { - ComposedKey composedKey = new ComposedKey(key, namespace); + private void putStoredValue(Namespace namespace, Object key, StoredValue storedValue) { + ComposedKey composedKey = new ComposedKey(namespace, key); storedValues.put(composedKey, storedValue); } - public Object getOrComputeIfAbsent(Object key, Function defaultCreator, Namespace namespace) { - StoredValue storedValue = getStoredValue(key, namespace); + public Object getOrComputeIfAbsent(Namespace namespace, Object key, Function defaultCreator) { + StoredValue storedValue = getStoredValue(namespace, key); if (storedValue == null) { storedValue = new StoredValue(defaultCreator.apply(key)); - putStoredValue(key, namespace, storedValue); + putStoredValue(namespace, key, storedValue); } return storedValue.value; } - public Object remove(Object key, Namespace namespace) { - ComposedKey composedKey = new ComposedKey(key, namespace); + public Object remove(Namespace namespace, Object key) { + ComposedKey composedKey = new ComposedKey(namespace, key); StoredValue previous = storedValues.remove(composedKey); return (previous != null ? previous.value : null); } @@ -81,7 +81,7 @@ private static class ComposedKey { private final Object key; private final Namespace namespace; - private ComposedKey(Object key, Namespace namespace) { + private ComposedKey(Namespace namespace, Object key) { this.key = key; this.namespace = namespace; } diff --git a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java index 6e0ba62515b..1a5fa914ebc 100644 --- a/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java +++ b/junit5-engine/src/main/java/org/junit/gen5/engine/junit5/descriptor/NamespacedStore.java @@ -26,21 +26,21 @@ public NamespacedStore(ExtensionValuesStore valuesStore, Namespace namespace) { @Override public Object get(Object key) { - return valuesStore.get(key, namespace); + return valuesStore.get(namespace, key); } @Override public void put(Object key, Object value) { - valuesStore.put(key, value, namespace); + valuesStore.put(namespace, key, value); } @Override public Object getOrComputeIfAbsent(Object key, Function defaultCreator) { - return valuesStore.getOrComputeIfAbsent(key, defaultCreator, namespace); + return valuesStore.getOrComputeIfAbsent(namespace, key, defaultCreator); } @Override public Object remove(Object key) { - return valuesStore.remove(key, namespace); + return valuesStore.remove(namespace, key); } }