1 /* 2 * Copyright (C) 2018 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.model.testing; 18 19 import static com.google.common.collect.Iterables.getOnlyElement; 20 import static com.google.common.truth.Truth.assertAbout; 21 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 22 23 import com.google.common.collect.ImmutableSet; 24 import com.google.common.truth.FailureMetadata; 25 import com.google.common.truth.Subject; 26 import dagger.model.Binding; 27 import dagger.model.BindingGraph; 28 import javax.lang.model.type.TypeMirror; 29 import org.checkerframework.checker.nullness.compatqual.NullableDecl; 30 31 /** A Truth subject for making assertions on a {@link BindingGraph}. */ 32 public final class BindingGraphSubject extends Subject { 33 34 /** Starts a fluent assertion about a {@link BindingGraph}. */ assertThat(BindingGraph bindingGraph)35 public static BindingGraphSubject assertThat(BindingGraph bindingGraph) { 36 return assertAbout(BindingGraphSubject::new).that(bindingGraph); 37 } 38 39 private final BindingGraph actual; 40 BindingGraphSubject(FailureMetadata metadata, @NullableDecl BindingGraph actual)41 private BindingGraphSubject(FailureMetadata metadata, @NullableDecl BindingGraph actual) { 42 super(metadata, actual); 43 this.actual = actual; 44 } 45 46 /** 47 * Asserts that the graph has at least one binding with an unqualified key. 48 * 49 * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()} 50 */ hasBindingWithKey(String type)51 public void hasBindingWithKey(String type) { 52 bindingWithKey(type); 53 } 54 55 /** 56 * Asserts that the graph has at least one binding with a qualified key. 57 * 58 * @param qualifier the canonical string form of the qualifier, as returned by {@link 59 * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()} 60 * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()} 61 */ hasBindingWithKey(String qualifier, String type)62 public void hasBindingWithKey(String qualifier, String type) { 63 bindingWithKey(qualifier, type); 64 } 65 66 /** 67 * Returns a subject for testing the binding for an unqualified key. 68 * 69 * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()} 70 */ bindingWithKey(String type)71 public BindingSubject bindingWithKey(String type) { 72 return bindingWithKeyString(keyString(type)); 73 } 74 75 /** 76 * Returns a subject for testing the binding for a qualified key. 77 * 78 * @param qualifier the canonical string form of the qualifier, as returned by {@link 79 * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()} 80 * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()} 81 */ bindingWithKey(String qualifier, String type)82 public BindingSubject bindingWithKey(String qualifier, String type) { 83 return bindingWithKeyString(keyString(qualifier, type)); 84 } 85 bindingWithKeyString(String keyString)86 private BindingSubject bindingWithKeyString(String keyString) { 87 ImmutableSet<Binding> bindings = getBindingNodes(keyString); 88 // TODO(dpb): Handle multiple bindings for the same key. 89 check("bindingsWithKey(%s)", keyString).that(bindings).hasSize(1); 90 return check("bindingWithKey(%s)", keyString) 91 .about(BindingSubject::new) 92 .that(getOnlyElement(bindings)); 93 } 94 getBindingNodes(String keyString)95 private ImmutableSet<Binding> getBindingNodes(String keyString) { 96 return actual.bindings().stream() 97 .filter(binding -> binding.key().toString().equals(keyString)) 98 .collect(toImmutableSet()); 99 } 100 keyString(String type)101 private static String keyString(String type) { 102 return type; 103 } 104 keyString(String qualifier, String type)105 private static String keyString(String qualifier, String type) { 106 return String.format("%s %s", qualifier, type); 107 } 108 109 /** A Truth subject for a {@link Binding}. */ 110 public final class BindingSubject extends Subject { 111 112 private final Binding actual; 113 BindingSubject(FailureMetadata metadata, @NullableDecl Binding actual)114 BindingSubject(FailureMetadata metadata, @NullableDecl Binding actual) { 115 super(metadata, actual); 116 this.actual = actual; 117 } 118 119 /** 120 * Asserts that the binding depends on a binding with an unqualified key. 121 * 122 * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()} 123 */ dependsOnBindingWithKey(String type)124 public void dependsOnBindingWithKey(String type) { 125 dependsOnBindingWithKeyString(keyString(type)); 126 } 127 128 /** 129 * Asserts that the binding depends on a binding with a qualified key. 130 * 131 * @param qualifier the canonical string form of the qualifier, as returned by {@link 132 * javax.lang.model.element.AnnotationMirror AnnotationMirror.toString()} 133 * @param type the canonical name of the type, as returned by {@link TypeMirror#toString()} 134 */ dependsOnBindingWithKey(String qualifier, String type)135 public void dependsOnBindingWithKey(String qualifier, String type) { 136 dependsOnBindingWithKeyString(keyString(qualifier, type)); 137 } 138 dependsOnBindingWithKeyString(String keyString)139 private void dependsOnBindingWithKeyString(String keyString) { 140 if (actualBindingGraph().requestedBindings(actual).stream() 141 .noneMatch(binding -> binding.key().toString().equals(keyString))) { 142 failWithActual("expected to depend on binding with key", keyString); 143 } 144 } 145 actualBindingGraph()146 private BindingGraph actualBindingGraph() { 147 return BindingGraphSubject.this.actual; 148 } 149 } 150 } 151