summaryrefslogtreecommitdiffstats
path: root/sangria-core
diff options
context:
space:
mode:
Diffstat (limited to 'sangria-core')
-rw-r--r--sangria-core/pom.xml2
-rw-r--r--sangria-core/src/main/java/com/tavianator/sangria/core/DelayedError.java9
-rw-r--r--sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java241
-rw-r--r--sangria-core/src/main/java/com/tavianator/sangria/core/Priority.java148
-rw-r--r--sangria-core/src/main/java/com/tavianator/sangria/core/TypeLiterals.java90
-rw-r--r--sangria-core/src/main/java/com/tavianator/sangria/core/package-info.java2
-rw-r--r--sangria-core/src/test/java/com/tavianator/sangria/core/DelayedErrorTest.java29
-rw-r--r--sangria-core/src/test/java/com/tavianator/sangria/core/PotentialAnnotationTest.java126
-rw-r--r--sangria-core/src/test/java/com/tavianator/sangria/core/PriorityTest.java100
-rw-r--r--sangria-core/src/test/java/com/tavianator/sangria/core/TypeLiteralsTest.java81
10 files changed, 823 insertions, 5 deletions
diff --git a/sangria-core/pom.xml b/sangria-core/pom.xml
index 59a7c31..8c58c49 100644
--- a/sangria-core/pom.xml
+++ b/sangria-core/pom.xml
@@ -7,7 +7,7 @@
<parent>
<groupId>com.tavianator.sangria</groupId>
<artifactId>sangria</artifactId>
- <version>1.0</version>
+ <version>1.1-SNAPSHOT</version>
</parent>
<artifactId>sangria-core</artifactId>
diff --git a/sangria-core/src/main/java/com/tavianator/sangria/core/DelayedError.java b/sangria-core/src/main/java/com/tavianator/sangria/core/DelayedError.java
index d6f86a8..2aeabca 100644
--- a/sangria-core/src/main/java/com/tavianator/sangria/core/DelayedError.java
+++ b/sangria-core/src/main/java/com/tavianator/sangria/core/DelayedError.java
@@ -25,6 +25,8 @@ import com.google.inject.CreationException;
import com.google.inject.Injector;
import com.google.inject.spi.Message;
+import static com.google.common.base.Preconditions.*;
+
/**
* Similar to {@link Binder#addError(String, Object...)}, but can be canceled later. Useful for enforcing correct usage
* of fluent APIs.
@@ -35,6 +37,7 @@ import com.google.inject.spi.Message;
*/
public class DelayedError {
private Throwable error;
+ private boolean reported = false;
/**
* Create a {@link DelayedError}.
@@ -85,11 +88,13 @@ public class DelayedError {
* Cancel this error.
*/
public void cancel() {
- this.error = null;
+ checkState(!reported, "This error has already been reported");
+ error = null;
}
@Inject
- void inject(Injector injector) throws Throwable {
+ void reportErrors(Injector injector) throws Throwable {
+ reported = true;
if (error != null) {
throw error;
}
diff --git a/sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java b/sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java
new file mode 100644
index 0000000..302e5e1
--- /dev/null
+++ b/sangria-core/src/main/java/com/tavianator/sangria/core/PotentialAnnotation.java
@@ -0,0 +1,241 @@
+/****************************************************************************
+ * Sangria *
+ * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * 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.tavianator.sangria.core;
+
+import java.lang.annotation.Annotation;
+import java.util.*;
+
+import com.google.inject.CreationException;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.Message;
+
+/**
+ * A record of stored annotations, perfect for builders with {@code annotatedWith()} methods.
+ *
+ * @author Tavian Barnes (tavianator@tavianator.com)
+ * @version 1.1
+ * @since 1.1
+ */
+public abstract class PotentialAnnotation {
+ /**
+ * A visitor interface to examine a {@link PotentialAnnotation}'s annotation, if it exists.
+ *
+ * @param <T> The type to return.
+ * @author Tavian Barnes (tavianator@tavianator.com)
+ * @version 1.1
+ * @since 1.1
+ */
+ public interface Visitor<T> {
+ /**
+ * Called when there is no annotation.
+ *
+ * @return Any value.
+ */
+ T visitNoAnnotation();
+
+ /**
+ * Called when an annotation type is stored.
+ *
+ * @param annotationType The annotation type.
+ * @return Any value.
+ */
+ T visitAnnotationType(Class<? extends Annotation> annotationType);
+
+ /**
+ * Called when an annotation instance is stored.
+ *
+ * @param annotation The annotation instance.
+ * @return Any value.
+ */
+ T visitAnnotationInstance(Annotation annotation);
+ }
+
+ private static final PotentialAnnotation NONE = new NoAnnotation();
+
+ /**
+ * @return A {@link PotentialAnnotation} with no annotation.
+ */
+ public static PotentialAnnotation none() {
+ return NONE;
+ }
+
+ private PotentialAnnotation() {
+ }
+
+ /**
+ * Add an annotation.
+ *
+ * @param annotationType The annotation type to add.
+ * @return A new {@link PotentialAnnotation} associated with the given annotation type.
+ * @throws CreationException If an annotation is already present.
+ */
+ public PotentialAnnotation annotatedWith(Class<? extends Annotation> annotationType) {
+ throw annotationAlreadyPresent();
+ }
+
+ /**
+ * Add an annotation.
+ *
+ * @param annotation The annotation instance to add.
+ * @return A new {@link PotentialAnnotation} associated with the given annotation instance.
+ * @throws CreationException If an annotation is already present.
+ */
+ public PotentialAnnotation annotatedWith(Annotation annotation) {
+ throw annotationAlreadyPresent();
+ }
+
+ private CreationException annotationAlreadyPresent() {
+ Message message = new Message("An annotation was already present");
+ return new CreationException(Collections.singletonList(message));
+ }
+
+ /**
+ * @return Whether an annotation is present.
+ */
+ public abstract boolean hasAnnotation();
+
+ /**
+ * Create a {@link Key} with the given type and the stored annotation.
+ *
+ * @param type The type of the key to create.
+ * @param <T> The type of the key to create.
+ * @return A {@link Key}.
+ */
+ public <T> Key<T> getKey(Class<T> type) {
+ return getKey(TypeLiteral.get(type));
+ }
+
+ /**
+ * Create a {@link Key} with the given type and the stored annotation.
+ *
+ * @param type The type of the key to create.
+ * @param <T> The type of the key to create.
+ * @return A {@link Key}.
+ */
+ public abstract <T> Key<T> getKey(TypeLiteral<T> type);
+
+ /**
+ * Accept a {@link Visitor}.
+ *
+ * @param visitor The visitor to accept.
+ * @param <T> The type for the visitor to return.
+ * @return The value produced by the visitor.
+ */
+ public abstract <T> T accept(Visitor<T> visitor);
+
+ @Override
+ public abstract String toString();
+
+ /**
+ * Implementation of {@link #none()}.
+ */
+ private static class NoAnnotation extends PotentialAnnotation {
+ @Override
+ public PotentialAnnotation annotatedWith(Class<? extends Annotation> annotationType) {
+ return new AnnotationType(annotationType);
+ }
+
+ @Override
+ public PotentialAnnotation annotatedWith(Annotation annotation) {
+ return new AnnotationInstance(annotation);
+ }
+
+ @Override
+ public boolean hasAnnotation() {
+ return false;
+ }
+
+ @Override
+ public <T> Key<T> getKey(TypeLiteral<T> type) {
+ return Key.get(type);
+ }
+
+ @Override
+ public <T> T accept(Visitor<T> visitor) {
+ return visitor.visitNoAnnotation();
+ }
+
+ @Override
+ public String toString() {
+ return "[no annotation]";
+ }
+ }
+
+ /**
+ * Implementation of {@link #annotatedWith(Class)}.
+ */
+ private static class AnnotationType extends PotentialAnnotation {
+ private final Class<? extends Annotation> annotationType;
+
+ AnnotationType(Class<? extends Annotation> annotationType) {
+ this.annotationType = annotationType;
+ }
+
+ @Override
+ public boolean hasAnnotation() {
+ return true;
+ }
+
+ @Override
+ public <T> Key<T> getKey(TypeLiteral<T> type) {
+ return Key.get(type, annotationType);
+ }
+
+ @Override
+ public <T> T accept(Visitor<T> visitor) {
+ return visitor.visitAnnotationType(annotationType);
+ }
+
+ @Override
+ public String toString() {
+ return "@" + annotationType.getCanonicalName();
+ }
+ }
+
+ /**
+ * Implementation of {@link #annotatedWith(Annotation)}.
+ */
+ private static class AnnotationInstance extends PotentialAnnotation {
+ private final Annotation annotation;
+
+ AnnotationInstance(Annotation annotation) {
+ this.annotation = annotation;
+ }
+
+ @Override
+ public boolean hasAnnotation() {
+ return true;
+ }
+
+ @Override
+ public <T> Key<T> getKey(TypeLiteral<T> type) {
+ return Key.get(type, annotation);
+ }
+
+ @Override
+ public <T> T accept(Visitor<T> visitor) {
+ return visitor.visitAnnotationInstance(annotation);
+ }
+
+ @Override
+ public String toString() {
+ return annotation.toString();
+ }
+ }
+}
diff --git a/sangria-core/src/main/java/com/tavianator/sangria/core/Priority.java b/sangria-core/src/main/java/com/tavianator/sangria/core/Priority.java
new file mode 100644
index 0000000..a833883
--- /dev/null
+++ b/sangria-core/src/main/java/com/tavianator/sangria/core/Priority.java
@@ -0,0 +1,148 @@
+/****************************************************************************
+ * Sangria *
+ * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * 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.tavianator.sangria.core;
+
+import java.util.*;
+
+import com.google.common.collect.ComparisonChain;
+import com.google.common.primitives.Ints;
+
+/**
+ * A loosely-coupled, infinitely divisible priority/weight system.
+ *
+ * <p>
+ * This class implements an extensible priority system based on lexicographical ordering. In its simplest use, {@code
+ * Priority.create(0)} is ordered before {@code Priority.create(1)}, then {@code Priority.create(2)}, etc.
+ * </p>
+ *
+ * <p>
+ * To create a priority that is ordered between two existing ones, simply add another parameter: {@code
+ * Priority.create(1, 1)} comes after {@code Priority.create(1)}, but before {@code Priority.create(2)}. In this way,
+ * priorities can always be inserted anywhere in a sequence.
+ * </p>
+ *
+ * <p>
+ * The {@link #next()} method creates a priority that is ordered immediately following the current one, and is distinct
+ * from all priorities obtained by any other means. This provides a convenient way to order entire segments of lists.
+ * </p>
+ *
+ * <p>
+ * A special priority, obtained by {@code Priority.getDefault()}, sorts before all other priorities.
+ * </p>
+ *
+ * @author Tavian Barnes (tavianator@tavianator.com)
+ * @version 1.1
+ * @since 1.1
+ */
+public class Priority implements Comparable<Priority> {
+ private static final Priority DEFAULT = new Priority(new int[0], 0);
+ private static final Comparator<int[]> COMPARATOR = Ints.lexicographicalComparator();
+
+ private final int[] weights;
+ private final int seq;
+
+ /**
+ * @return The default priority, which comes before all other priorities.
+ */
+ public static Priority getDefault() {
+ return DEFAULT;
+ }
+
+ /**
+ * Create a {@link Priority} with the given sequence.
+ *
+ * @param weight The first value of the weight sequence.
+ * @param weights An integer sequence. These sequences are sorted lexicographically, so {@code Priority.create(1)}
+ * sorts before {@code Priority.create(1, 1)}, which sorts before {@code Priority.create(2)}.
+ * @return A new {@link Priority}.
+ */
+ public static Priority create(int weight, int... weights) {
+ int[] newWeights = new int[weights.length + 1];
+ newWeights[0] = weight;
+ System.arraycopy(weights, 0, newWeights, 1, weights.length);
+ return new Priority(newWeights, 0);
+ }
+
+ private Priority(int[] weights, int seq) {
+ this.weights = weights;
+ this.seq = seq;
+ }
+
+ /**
+ * @return Whether this priority originated in a call to {@link #getDefault()}.
+ */
+ public boolean isDefault() {
+ return weights.length == 0;
+ }
+
+ /**
+ * @return A new {@link Priority} which immediately follows this one, and which is distinct from all other
+ * priorities obtained by {@link #create(int, int...)}.
+ */
+ public Priority next() {
+ return new Priority(weights, seq + 1);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ } else if (!(obj instanceof Priority)) {
+ return false;
+ }
+
+ Priority other = (Priority)obj;
+ return Arrays.equals(weights, other.weights)
+ && seq == other.seq;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(weights) + seq;
+ }
+
+ @Override
+ public int compareTo(Priority o) {
+ return ComparisonChain.start()
+ .compare(weights, o.weights, COMPARATOR)
+ .compare(seq, o.seq)
+ .result();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (weights.length == 0) {
+ builder.append("default priority");
+ } else {
+ builder.append("priority [");
+ for (int i = 0; i < weights.length; ++i) {
+ if (i != 0) {
+ builder.append(", ");
+ }
+ builder.append(weights[i]);
+ }
+ builder.append("]");
+ }
+ if (seq != 0) {
+ builder.append(" + ")
+ .append(seq);
+ }
+ return builder.toString();
+ }
+}
diff --git a/sangria-core/src/main/java/com/tavianator/sangria/core/TypeLiterals.java b/sangria-core/src/main/java/com/tavianator/sangria/core/TypeLiterals.java
new file mode 100644
index 0000000..ff42790
--- /dev/null
+++ b/sangria-core/src/main/java/com/tavianator/sangria/core/TypeLiterals.java
@@ -0,0 +1,90 @@
+/****************************************************************************
+ * Sangria *
+ * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * 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.tavianator.sangria.core;
+
+import java.util.*;
+
+import javax.inject.Provider;
+
+import com.google.inject.TypeLiteral;
+import com.google.inject.util.Types;
+
+/**
+ * Static utility functions for working with {@link TypeLiteral}s.
+ *
+ * @author Tavian Barnes (tavianator@tavianator.com)
+ * @version 1.1
+ * @since 1.1
+ */
+public class TypeLiterals {
+ private TypeLiterals() {
+ // Not for instantiating
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> TypeLiteral<List<T>> listOf(Class<T> type) {
+ return (TypeLiteral<List<T>>)TypeLiteral.get(Types.listOf(type));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> TypeLiteral<List<T>> listOf(TypeLiteral<T> type) {
+ return (TypeLiteral<List<T>>)TypeLiteral.get(Types.listOf(type.getType()));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> TypeLiteral<Set<T>> setOf(Class<T> type) {
+ return (TypeLiteral<Set<T>>)TypeLiteral.get(Types.setOf(type));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> TypeLiteral<Set<T>> setOf(TypeLiteral<T> type) {
+ return (TypeLiteral<Set<T>>)TypeLiteral.get(Types.setOf(type.getType()));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <K, V> TypeLiteral<Map<K, V>> mapOf(Class<K> keyType, Class<V> valueType) {
+ return (TypeLiteral<Map<K, V>>)TypeLiteral.get(Types.mapOf(keyType, valueType));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <K, V> TypeLiteral<Map<K, V>> mapOf(Class<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, V>>)TypeLiteral.get(Types.mapOf(keyType, valueType.getType()));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <K, V> TypeLiteral<Map<K, V>> mapOf(TypeLiteral<K> keyType, Class<V> valueType) {
+ return (TypeLiteral<Map<K, V>>)TypeLiteral.get(Types.mapOf(keyType.getType(), valueType));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <K, V> TypeLiteral<Map<K, V>> mapOf(TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, V>>)TypeLiteral.get(Types.mapOf(keyType.getType(), valueType.getType()));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> TypeLiteral<Provider<T>> providerOf(Class<T> type) {
+ // Can't use Types.providerOf() because we want to stick to JSR-330 Providers
+ return (TypeLiteral<Provider<T>>)TypeLiteral.get(Types.newParameterizedType(Provider.class, type));
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> TypeLiteral<Provider<T>> providerOf(TypeLiteral<T> type) {
+ // Can't use Types.providerOf() because we want to stick to JSR-330 Providers
+ return (TypeLiteral<Provider<T>>)TypeLiteral.get(Types.newParameterizedType(Provider.class, type.getType()));
+ }
+}
diff --git a/sangria-core/src/main/java/com/tavianator/sangria/core/package-info.java b/sangria-core/src/main/java/com/tavianator/sangria/core/package-info.java
index 6d416d3..009aa5e 100644
--- a/sangria-core/src/main/java/com/tavianator/sangria/core/package-info.java
+++ b/sangria-core/src/main/java/com/tavianator/sangria/core/package-info.java
@@ -19,7 +19,7 @@
* {@code sangria-core}: Common code for Sangria.
*
* @author Tavian Barnes (tavianator@tavianator.com)
- * @version 1.0
+ * @version 1.1
* @since 1.0
*/
package com.tavianator.sangria.core;
diff --git a/sangria-core/src/test/java/com/tavianator/sangria/core/DelayedErrorTest.java b/sangria-core/src/test/java/com/tavianator/sangria/core/DelayedErrorTest.java
index 349dced..f27aea8 100644
--- a/sangria-core/src/test/java/com/tavianator/sangria/core/DelayedErrorTest.java
+++ b/sangria-core/src/test/java/com/tavianator/sangria/core/DelayedErrorTest.java
@@ -32,7 +32,7 @@ import static org.hamcrest.Matchers.*;
* Tests for {@link DelayedError}.
*
* @author Tavian Barnes (tavianator@tavianator.com)
- * @version 1.0
+ * @version 1.1
* @since 1.0
*/
public class DelayedErrorTest {
@@ -83,4 +83,31 @@ public class DelayedErrorTest {
}
});
}
+
+ @Test
+ public void testCancel() {
+ Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ DelayedError error = DelayedError.create(binder(), "Message");
+ error.cancel();
+ }
+ });
+ }
+
+ @Test
+ public void testLateCancel() {
+ final DelayedError[] errorHolder = new DelayedError[1];
+
+ Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ errorHolder[0] = DelayedError.create(binder(), "Message");
+ errorHolder[0].cancel();
+ }
+ });
+
+ thrown.expect(IllegalStateException.class);
+ errorHolder[0].cancel();
+ }
}
diff --git a/sangria-core/src/test/java/com/tavianator/sangria/core/PotentialAnnotationTest.java b/sangria-core/src/test/java/com/tavianator/sangria/core/PotentialAnnotationTest.java
new file mode 100644
index 0000000..c4ccc36
--- /dev/null
+++ b/sangria-core/src/test/java/com/tavianator/sangria/core/PotentialAnnotationTest.java
@@ -0,0 +1,126 @@
+/****************************************************************************
+ * Sangria *
+ * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * 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.tavianator.sangria.core;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.inject.Qualifier;
+
+import com.google.inject.CreationException;
+import com.google.inject.Key;
+import com.google.inject.name.Names;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link PotentialAnnotation}s.
+ *
+ * @author Tavian Barnes (tavianator@tavianator.com)
+ * @version 1.1
+ * @since 1.1
+ */
+public class PotentialAnnotationTest {
+ @Retention(RetentionPolicy.RUNTIME)
+ @Qualifier
+ private @interface Simple {
+ }
+
+ private final PotentialAnnotation none = PotentialAnnotation.none();
+ private final Annotation nameAnnotation = Names.named("name");
+
+ @Test
+ public void testHasAnnotation() {
+ assertThat(none.hasAnnotation(), is(false));
+ assertThat(none.annotatedWith(Simple.class).hasAnnotation(), is(true));
+ assertThat(none.annotatedWith(nameAnnotation).hasAnnotation(), is(true));
+ }
+
+ @Test(expected = CreationException.class)
+ public void testInvalidAnnotatedWithType() {
+ none.annotatedWith(Simple.class)
+ .annotatedWith(Simple.class);
+ }
+
+ @Test(expected = CreationException.class)
+ public void testInvalidAnnotatedWithInstance() {
+ none.annotatedWith(Names.named("name"))
+ .annotatedWith(Names.named("name"));
+ }
+
+ @Test
+ public void testGetKey() {
+ assertThat(none.getKey(String.class),
+ equalTo(new Key<String>() { }));
+ assertThat(none.annotatedWith(Simple.class).getKey(String.class),
+ equalTo(new Key<String>(Simple.class) { }));
+ assertThat(none.annotatedWith(nameAnnotation).getKey(String.class),
+ equalTo(new Key<String>(nameAnnotation) { }));
+ }
+
+ @Test
+ public void testVisitor() {
+ PotentialAnnotation.Visitor<String> visitor = new PotentialAnnotation.Visitor<String>() {
+ @Override
+ public String visitNoAnnotation() {
+ return "none";
+ }
+
+ @Override
+ public String visitAnnotationType(Class<? extends Annotation> annotationType) {
+ assertThat((Object)annotationType, equalTo((Object)Simple.class));
+ return "type";
+ }
+
+ @Override
+ public String visitAnnotationInstance(Annotation annotation) {
+ assertThat(annotation, equalTo(nameAnnotation));
+ return "instance";
+ }
+ };
+
+ assertThat(none.accept(visitor), equalTo("none"));
+ assertThat(none.annotatedWith(Simple.class).accept(visitor), equalTo("type"));
+ assertThat(none.annotatedWith(nameAnnotation).accept(visitor), equalTo("instance"));
+ }
+
+ @Test
+ public void testToString() {
+ assertThat(none.toString(),
+ equalTo("[no annotation]"));
+ assertThat(none.annotatedWith(Simple.class).toString(),
+ equalTo("@com.tavianator.sangria.core.PotentialAnnotationTest.Simple"));
+ assertThat(none.annotatedWith(nameAnnotation).toString(),
+ equalTo("@com.google.inject.name.Named(value=name)"));
+ }
+
+ /**
+ * Needed to avoid compilation error to to inferred type being anonymous class.
+ */
+ private static <T> Matcher<Key<T>> equalTo(Key<T> key) {
+ return Matchers.equalTo(key);
+ }
+
+ private static <T> Matcher<T> equalTo(T object) {
+ return Matchers.equalTo(object);
+ }
+}
diff --git a/sangria-core/src/test/java/com/tavianator/sangria/core/PriorityTest.java b/sangria-core/src/test/java/com/tavianator/sangria/core/PriorityTest.java
new file mode 100644
index 0000000..0869565
--- /dev/null
+++ b/sangria-core/src/test/java/com/tavianator/sangria/core/PriorityTest.java
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * Sangria *
+ * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * 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.tavianator.sangria.core;
+
+import java.util.*;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link Priority}s.
+ *
+ * @author Tavian Barnes (tavianator@tavianator.com)
+ * @version 1.1
+ * @since 1.1
+ */
+public class PriorityTest {
+ private final Priority defaultPriority = Priority.getDefault();
+ private final Priority one = Priority.create(1);
+ private final Priority oneTwo = Priority.create(1, 2);
+ private final Priority two = Priority.create(2);
+
+ @Test
+ public void testOrdering() {
+ List<Priority> list = Arrays.asList(
+ defaultPriority.next(),
+ two,
+ oneTwo.next(),
+ oneTwo,
+ two.next(),
+ defaultPriority,
+ defaultPriority.next().next(),
+ one,
+ one.next());
+ Collections.sort(list);
+ assertThat(list, contains(
+ defaultPriority,
+ defaultPriority.next(),
+ defaultPriority.next().next(),
+ one,
+ one.next(),
+ oneTwo,
+ oneTwo.next(),
+ two,
+ two.next()));
+
+ assertThat(defaultPriority, equalTo(Priority.getDefault()));
+ assertThat(defaultPriority.next(), equalTo(Priority.getDefault().next()));
+ assertThat(defaultPriority, not(equalTo(Priority.getDefault().next())));
+
+ assertThat(one, equalTo(Priority.create(1)));
+ assertThat(oneTwo, equalTo(Priority.create(1, 2)));
+ assertThat(two, equalTo(Priority.create(2)));
+
+ assertThat(oneTwo.hashCode(), equalTo(Priority.create(1, 2).hashCode()));
+ }
+
+ @Test
+ public void testIsDefault() {
+ assertThat(defaultPriority.isDefault(), is(true));
+ assertThat(defaultPriority.next().isDefault(), is(true));
+
+ assertThat(one.isDefault(), is(false));
+ assertThat(oneTwo.isDefault(), is(false));
+ assertThat(two.isDefault(), is(false));
+ assertThat(two.next().isDefault(), is(false));
+ }
+
+ @Test
+ public void testToString() {
+ assertThat(Priority.getDefault().toString(), equalTo("default priority"));
+ assertThat(Priority.getDefault().next().toString(), equalTo("default priority + 1"));
+ assertThat(Priority.getDefault().next().next().toString(), equalTo("default priority + 2"));
+
+ assertThat(Priority.create(1).toString(), equalTo("priority [1]"));
+ assertThat(Priority.create(1).next().toString(), equalTo("priority [1] + 1"));
+ assertThat(Priority.create(1).next().next().toString(), equalTo("priority [1] + 2"));
+
+ assertThat(Priority.create(1, 2).toString(), equalTo("priority [1, 2]"));
+ assertThat(Priority.create(1, 2).next().toString(), equalTo("priority [1, 2] + 1"));
+ assertThat(Priority.create(1, 2).next().next().toString(), equalTo("priority [1, 2] + 2"));
+ }
+}
diff --git a/sangria-core/src/test/java/com/tavianator/sangria/core/TypeLiteralsTest.java b/sangria-core/src/test/java/com/tavianator/sangria/core/TypeLiteralsTest.java
new file mode 100644
index 0000000..3e7cdb8
--- /dev/null
+++ b/sangria-core/src/test/java/com/tavianator/sangria/core/TypeLiteralsTest.java
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * Sangria *
+ * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * 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.tavianator.sangria.core;
+
+import java.util.*;
+
+import javax.inject.Provider;
+
+import com.google.inject.TypeLiteral;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link TypeLiterals}.
+ *
+ * @author Tavian Barnes (tavianator@tavianator.com)
+ * @version 1.1
+ * @since 1.1
+ */
+public class TypeLiteralsTest {
+ @Test
+ public void testListOf() {
+ assertThat(TypeLiterals.listOf(String.class),
+ equalTo(new TypeLiteral<List<String>>() { }));
+ assertThat(TypeLiterals.listOf(new TypeLiteral<Class<?>>() { }),
+ equalTo(new TypeLiteral<List<Class<?>>>() { }));
+ }
+
+ @Test
+ public void testSetOf() {
+ assertThat(TypeLiterals.setOf(String.class),
+ equalTo(new TypeLiteral<Set<String>>() { }));
+ assertThat(TypeLiterals.setOf(new TypeLiteral<Class<?>>() { }),
+ equalTo(new TypeLiteral<Set<Class<?>>>() { }));
+ }
+
+ @Test
+ public void testMapOf() {
+ assertThat(TypeLiterals.mapOf(String.class, String.class),
+ equalTo(new TypeLiteral<Map<String, String>>() { }));
+ assertThat(TypeLiterals.mapOf(String.class, new TypeLiteral<Class<?>>() { }),
+ equalTo(new TypeLiteral<Map<String, Class<?>>>() { }));
+ assertThat(TypeLiterals.mapOf(new TypeLiteral<Class<?>>() { }, String.class),
+ equalTo(new TypeLiteral<Map<Class<?>, String>>() { }));
+ assertThat(TypeLiterals.mapOf(new TypeLiteral<Class<?>>() { }, new TypeLiteral<Class<?>>() { }),
+ equalTo(new TypeLiteral<Map<Class<?>, Class<?>>>() { }));
+ }
+
+ @Test
+ public void testProviderOf() {
+ assertThat(TypeLiterals.providerOf(String.class),
+ equalTo(new TypeLiteral<Provider<String>>() { }));
+ assertThat(TypeLiterals.providerOf(new TypeLiteral<Class<?>>() { }),
+ equalTo(new TypeLiteral<Provider<Class<?>>>() { }));
+ }
+
+ /**
+ * Needed to avoid compilation error to to inferred type being anonymous class.
+ */
+ private static <T> Matcher<TypeLiteral<T>> equalTo(TypeLiteral<T> type) {
+ return Matchers.equalTo(type);
+ }
+}