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