View Javadoc
1   /*
2    * Copyright © 2017, Salesforce.com, Inc
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *     * Redistributions of source code must retain the above copyright
8    *       notice, this list of conditions and the following disclaimer.
9    *     * Redistributions in binary form must reproduce the above copyright
10   *       notice, this list of conditions and the following disclaimer in the
11   *       documentation and/or other materials provided with the distribution.
12   *     * Neither the name of the <organization> nor the
13   *       names of its contributors may be used to endorse or promote products
14   *       derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  package com.salesforce.apt.graph.processing;
28  
29  import static org.assertj.core.api.Assertions.assertThat;
30  
31  import java.io.File;
32  import java.util.Arrays;
33  import java.util.List;
34  import java.util.Set;
35  
36  import org.junit.Rule;
37  import org.junit.Test;
38  import org.junit.rules.TemporaryFolder;
39  
40  import com.salesforce.apt.graph.model.DefinitionModel;
41  import com.salesforce.apt.graph.model.ExpectedModel;
42  import com.salesforce.apt.graph.model.InstanceDependencyModel;
43  import com.salesforce.apt.graph.model.InstanceModel;
44  import com.salesforce.apt.graph.model.errors.ErrorType;
45  import com.salesforce.apt.graph.model.storage.DefinitionModelStore;
46  import com.salesforce.apt.graph.model.storage.ResourceLoader;
47  import com.salesforce.apt.graph.model.storage.classpath.ClasspathUrlResourceLoader;
48  import com.salesforce.apt.graph.model.storage.classpath.GsonDefinitionModelStore;
49  import com.salesforce.apt.graph.model.storage.classpath.TestFileStore;
50  import com.salesforce.apt.graph.test.cycle.definitions.TestErrorListener;
51  import com.salesforce.apt.graph.types.impl.ReflectionAssignabilityUtils;
52  
53  public class TestObjectGraphInspector {
54    
55    
56    private static final String TEST_DEF1 = "test.Def1";
57    private static final String TEST_DEF2 = "test.Def2";
58    //private static final String TEST_DEF3 = "test.Def3";
59    //private static final String TEST_DEF4 = "test.Def4";
60    
61    private static final String OBJECT1 = "object1";
62    private static final String OBJECT1_SOURCE = "test.Def1.object1(...)";
63    
64    private static final String OBJECT2 = "object2";
65    private static final String OBJECT2_SOURCE = "test.Def2.object2(...)";
66    
67    private static final String OBJECT3 = "object3";
68    //private static final String OBJECT3_SOURCE = "test.Def3.object3(...)";
69    
70    //private static final String TYPE_CHARSEQUENCE = "java.lang.CharSequence";
71    private static final String TYPE_STRING = "java.lang.String";
72    //private static final String TYPE_STRINGBUILDER = "java.lang.StringBuilder";
73  
74    @Rule
75    public TemporaryFolder testFolder = new TemporaryFolder();
76  
77    private static DefinitionModelStore getDefinitionModelStore(File root) {
78      TestFileStore fileStore = new TestFileStore(root);
79      ResourceLoader loader = new ClasspathUrlResourceLoader(root);
80      return new GsonDefinitionModelStore(loader, fileStore);
81    }
82    
83    @Test
84    public void inspectGraphProperlyListsExpectedEntities() {
85      DefinitionModel model1 = new DefinitionModel(TEST_DEF1);
86      model1.addDefinition(new ExpectedModel(OBJECT2));
87      model1.addDefinition(new InstanceModel(OBJECT1, TEST_DEF1, OBJECT1_SOURCE, TYPE_STRING,
88          Arrays.asList(new InstanceDependencyModel(OBJECT2, TYPE_STRING)), Arrays.asList()));
89      DefinitionModel model2 = new DefinitionModel(TEST_DEF2);
90      model2.addDependencyNames(TEST_DEF1);
91      model2.addDefinition(new InstanceModel(OBJECT2, TEST_DEF2, OBJECT2_SOURCE, TYPE_STRING, Arrays.asList(), Arrays.asList()));
92      TestErrorListenercle/definitions/TestErrorListener.html#TestErrorListener">TestErrorListener el = new TestErrorListener();
93      List<DefinitionModel> definitions = Arrays.asList(model1, model2);
94      DefinitionModelStore store = getDefinitionModelStore(testFolder.getRoot());
95      new DefinitionJoiner().joinDefinitions(definitions, store, el);
96      assertThat(el.getErrors()).isEmpty();
97      Set<DefinitionModel> heads = new DefinitionGraphInpector().inspectDefinitionGraph(definitions, el);
98      assertThat(el.getErrors()).isEmpty();
99      new DefinitionContentInspector().inspectDefinitionGraph(heads, el, new ReflectionAssignabilityUtils(), store);
100     assertThat(el.getErrors()).hasSize(0);
101   }
102   
103   @Test
104   public void inspectGraphWithDuplicateIdentities() {
105     DefinitionModel model1 = new DefinitionModel(TEST_DEF1);
106     InstanceModel instance1 = new InstanceModel(OBJECT1, TEST_DEF1, OBJECT1_SOURCE, TYPE_STRING, Arrays.asList(), Arrays.asList());
107     model1.addDefinition(instance1);
108     DefinitionModel model2 = new DefinitionModel(TEST_DEF2);
109     model2.addDependencyNames(TEST_DEF1);
110     InstanceModel instance2 = new InstanceModel(OBJECT1, TEST_DEF2, OBJECT2_SOURCE, TYPE_STRING, Arrays.asList(), Arrays.asList());
111     model2.addDefinition(instance2);
112     TestErrorListenercle/definitions/TestErrorListener.html#TestErrorListener">TestErrorListener el = new TestErrorListener();
113     List<DefinitionModel> definitions = Arrays.asList(model1, model2);
114     DefinitionModelStore store = getDefinitionModelStore(testFolder.getRoot());
115     new DefinitionJoiner().joinDefinitions(definitions, store, el);
116     assertThat(el.getErrors()).isEmpty();
117     Set<DefinitionModel> heads = new DefinitionGraphInpector().inspectDefinitionGraph(definitions, el);
118     assertThat(el.getErrors()).isEmpty();
119     new DefinitionContentInspector().inspectDefinitionGraph(heads, el, new ReflectionAssignabilityUtils(), store);
120     assertThat(el.getErrors()).hasSize(1);
121     /*
122      * Since model2 depends on model1 and model2 has the duplicate bean name,
123      * the error will always be reported on model2, and model1 if it has a SourceElement.
124      */
125     assertThat(el.getErrors().get(0).getMessage()).isEqualTo(ErrorType.DUPLICATE_OBJECT_DEFINITIONS);
126     assertThat(el.getErrors().get(0).getInvolved()).containsOnly(model2); 
127     assertThat(el.getErrors().get(0).getCauses()).containsOnly(instance1, instance2);
128   }
129   
130   @Test
131   public void inspectWithMissingExpectedIdentities() {
132     DefinitionModelStore store = getDefinitionModelStore(testFolder.getRoot());
133 
134     DefinitionModel model1 = new DefinitionModel(TEST_DEF1);
135     InstanceModel instance1 = new InstanceModel(OBJECT1, TEST_DEF1, OBJECT1_SOURCE, TYPE_STRING,
136         Arrays.asList(new InstanceDependencyModel(OBJECT2, TYPE_STRING)), Arrays.asList());
137     model1.addDefinition(instance1);
138     TestErrorListenercle/definitions/TestErrorListener.html#TestErrorListener">TestErrorListener el = new TestErrorListener();
139     List<DefinitionModel> definitions = Arrays.asList(model1);
140     new DefinitionJoiner().joinDefinitions(definitions, store, el);
141     assertThat(el.getErrors()).isEmpty();
142     Set<DefinitionModel> heads = new DefinitionGraphInpector().inspectDefinitionGraph(definitions, el);
143     assertThat(el.getErrors()).isEmpty();
144     new DefinitionContentInspector().inspectDefinitionGraph(heads, el, new ReflectionAssignabilityUtils(), store);
145     /*
146      * Since model1 has an instance, object1 that depends on and expected object2, that is not
147      * declared by model1 as an expected instance.
148      */
149     assertThat(el.getErrors()).hasSize(1);
150     assertThat(el.getErrors().get(0).getMessage()).isEqualTo(ErrorType.MISSING_BEAN_DEFINITIONS);
151     assertThat(el.getErrors().get(0).getInvolved()).containsOnly(model1); 
152     assertThat(el.getErrors().get(0).getCauses()).hasSize(1);
153     assertThat(el.getErrors().get(0).getCauses().get(0).getIdentity()).isEqualTo(OBJECT2);
154   }
155   
156   @Test
157   public void inspectWithUnneccessartExpectedIdentities() {
158     DefinitionModelStore store = getDefinitionModelStore(testFolder.getRoot());
159     
160     DefinitionModel model1 = new DefinitionModel(TEST_DEF1);
161     ExpectedModel expected1 = new ExpectedModel("OBJECT2");
162     model1.addDefinition(expected1);
163     InstanceModel instance1 = new InstanceModel(OBJECT1, TEST_DEF1, OBJECT1_SOURCE, TYPE_STRING,
164         Arrays.asList(), Arrays.asList());
165     model1.addDefinition(instance1);
166     TestErrorListenercle/definitions/TestErrorListener.html#TestErrorListener">TestErrorListener el = new TestErrorListener();
167     List<DefinitionModel> definitions = Arrays.asList(model1);
168     new DefinitionJoiner().joinDefinitions(definitions, store, el);
169     assertThat(el.getErrors()).isEmpty();
170     Set<DefinitionModel> heads = new DefinitionGraphInpector().inspectDefinitionGraph(definitions, el);
171     assertThat(el.getErrors()).isEmpty();
172     new DefinitionContentInspector().inspectDefinitionGraph(heads, el, new ReflectionAssignabilityUtils(), store);
173     /*
174      * Since model1 has an instance, object1 that depends on and expected object2, that is not
175      * declared by model1 as an expected instance.
176      */
177     assertThat(el.getErrors()).hasSize(1);
178     assertThat(el.getErrors().get(0).getMessage()).isEqualTo(ErrorType.UNUSED_EXPECTED);
179     assertThat(el.getErrors().get(0).getInvolved()).containsOnly(model1); 
180     assertThat(el.getErrors().get(0).getCauses()).containsOnly(expected1);
181   }
182   
183   @Test
184   public void inspectWithAliasesFulfillingUsage() {
185     DefinitionModel model1 = new DefinitionModel(TEST_DEF1);
186     InstanceModel instance1 = new InstanceModel(OBJECT1, TEST_DEF1, OBJECT1_SOURCE, TYPE_STRING,
187         Arrays.asList(new InstanceDependencyModel(OBJECT3, TYPE_STRING)), Arrays.asList());
188     InstanceModel instance2 = new InstanceModel(OBJECT2, TEST_DEF1, OBJECT2_SOURCE, TYPE_STRING,
189         Arrays.asList(), Arrays.asList(OBJECT3));
190     model1.addDefinition(instance1);
191     model1.addDefinition(instance2);
192     TestErrorListenercle/definitions/TestErrorListener.html#TestErrorListener">TestErrorListener el = new TestErrorListener();
193     List<DefinitionModel> definitions = Arrays.asList(model1);
194     DefinitionModelStore store = getDefinitionModelStore(testFolder.getRoot());
195     new DefinitionJoiner().joinDefinitions(definitions, store, el);
196     assertThat(el.getErrors()).isEmpty();
197     Set<DefinitionModel> heads = new DefinitionGraphInpector().inspectDefinitionGraph(definitions, el);
198     assertThat(el.getErrors()).isEmpty();
199     new DefinitionContentInspector().inspectDefinitionGraph(heads, el, new ReflectionAssignabilityUtils(), store);
200     assertThat(el.getErrors()).hasSize(0);
201   }
202 
203   @Test
204   public void inspectWithAliasesCauseDuplicateObjects() {
205     DefinitionModel model1 = new DefinitionModel(TEST_DEF1);
206     InstanceModel instance1 = new InstanceModel(OBJECT1, TEST_DEF1, OBJECT1_SOURCE, TYPE_STRING,
207         Arrays.asList(new InstanceDependencyModel(OBJECT3, TYPE_STRING)), Arrays.asList());
208     InstanceModel instance2 = new InstanceModel(OBJECT2, TEST_DEF1, OBJECT2_SOURCE, TYPE_STRING,
209         Arrays.asList(), Arrays.asList(OBJECT1));
210     model1.addDefinition(instance1);
211     model1.addDefinition(instance2);
212     TestErrorListenercle/definitions/TestErrorListener.html#TestErrorListener">TestErrorListener el = new TestErrorListener();
213     List<DefinitionModel> definitions = Arrays.asList(model1);
214     DefinitionModelStore store = getDefinitionModelStore(testFolder.getRoot());
215     new DefinitionJoiner().joinDefinitions(definitions, store, el);
216     assertThat(el.getErrors()).isEmpty();
217     Set<DefinitionModel> heads = new DefinitionGraphInpector().inspectDefinitionGraph(definitions, el);
218     assertThat(el.getErrors()).isEmpty();
219     new DefinitionContentInspector().inspectDefinitionGraph(heads, el, new ReflectionAssignabilityUtils(), store);
220     /*
221      * Since model1 has an instance, object1 that depends on and expected object2, that is not
222      * declared by model1 as an expected instance.
223      */
224     assertThat(el.getErrors()).hasSize(1);
225     assertThat(el.getErrors().get(0).getMessage()).isEqualTo(ErrorType.DUPLICATE_OBJECT_DEFINITIONS);
226     assertThat(el.getErrors().get(0).getInvolved()).containsOnly(model1); 
227     assertThat(el.getErrors().get(0).getCauses()).containsOnly(instance1, instance2);
228   }
229 }