View Javadoc
1   /*
2    * Portions of this software was developed by employees of the National Institute
3    * of Standards and Technology (NIST), an agency of the Federal Government and is
4    * being made available as a public service. Pursuant to title 17 United States
5    * Code Section 105, works of NIST employees are not subject to copyright
6    * protection in the United States. This software may be subject to foreign
7    * copyright. Permission in the United States and in foreign countries, to the
8    * extent that NIST may hold copyright, to use, copy, modify, create derivative
9    * works, and distribute this software and its documentation without fee is hereby
10   * granted on a non-exclusive basis, provided that this notice and disclaimer
11   * of warranty appears in all copies.
12   *
13   * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
14   * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
15   * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
17   * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
18   * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
19   * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
20   * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
21   * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
22   * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
23   * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
24   * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
25   */
26  
27  package gov.nist.secauto.metaschema.core.metapath.item.node;
28  
29  import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
30  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
31  
32  import org.hamcrest.Description;
33  import org.jmock.Expectations;
34  import org.jmock.Mockery;
35  import org.jmock.api.Action;
36  import org.jmock.api.Invocation;
37  
38  import java.net.URI;
39  import java.util.LinkedHashMap;
40  import java.util.LinkedList;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.UUID;
44  import java.util.concurrent.atomic.AtomicInteger;
45  import java.util.stream.Stream;
46  
47  import edu.umd.cs.findbugs.annotations.NonNull;
48  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
49  
50  // TODO: Integrate with classes in gov.nist.secauto.metaschema.core.testing
51  @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT")
52  public class MockNodeItemFactory {
53  
54    @NonNull
55    private final Mockery context;
56  
57    @SuppressWarnings("exports")
58    public MockNodeItemFactory(@NonNull Mockery ctx) {
59      this.context = ctx;
60    }
61  
62    protected Mockery getContext() {
63      return context;
64    }
65  
66    @SuppressWarnings("null")
67    @NonNull
68    protected <T extends INodeItem> T newMock(@NonNull Class<T> clazz, @NonNull String name) {
69      String mockName = new StringBuilder()
70          .append(clazz.getSimpleName())
71          .append('-')
72          .append(name)
73          .append('-')
74          .append(UUID.randomUUID().toString())
75          .toString();
76      return getContext().mock(clazz, mockName);
77    }
78  
79    public IDocumentNodeItem document(@NonNull URI documentURI, @NonNull String name,
80        @NonNull List<IFlagNodeItem> flags,
81        @NonNull List<IModelNodeItem<?, ?>> modelItems) {
82      IDocumentNodeItem document = newMock(IDocumentNodeItem.class, name);
83      IRootAssemblyNodeItem root = newMock(IRootAssemblyNodeItem.class, name);
84  
85      getContext().checking(new Expectations() {
86        { // NOPMD - intentional
87          allowing(document).modelItems();
88          will(returnValue(Stream.of(root)));
89          allowing(document).getDocumentUri();
90          will(returnValue(documentURI));
91          allowing(document).getNodeItem();
92          will(returnValue(document));
93          allowing(document).getParentNodeItem();
94          will(returnValue(null));
95          allowing(document).ancestorOrSelf();
96          will(returnValue(Stream.of(document)));
97  
98          allowing(root).getName();
99          will(returnValue(name));
100         allowing(root).getNodeItem();
101         will(returnValue(root));
102         allowing(root).getDocumentNodeItem();
103         will(returnValue(document));
104       }
105     });
106 
107     handleChildren(document, CollectionUtil.emptyList(), CollectionUtil.singletonList(root));
108     handleChildren(root, flags, modelItems);
109 
110     return document;
111   }
112 
113   @SuppressWarnings("null")
114   protected <T extends INodeItem> void handleChildren(
115       @NonNull T item,
116       @NonNull List<IFlagNodeItem> flags,
117       @NonNull List<IModelNodeItem<?, ?>> modelItems) {
118     getContext().checking(new Expectations() {
119       { // NOPMD - intentional
120         allowing(item).getFlags();
121         will(returnValue(flags));
122         flags.forEach(flag -> {
123           // handle each flag child
124           allowing(item).getFlagByName(with(equal(flag.getName())));
125           will(returnValue(flag));
126           // link parent
127           allowing(flag).getParentNodeItem();
128           will(returnValue(item));
129         });
130 
131         Map<String, List<IModelNodeItem<?, ?>>> modelItemsMap = toModelItemsMap(modelItems);
132         allowing(item).getModelItems();
133         will(returnValue(modelItemsMap.values()));
134         modelItemsMap.entrySet().forEach(entry -> {
135           allowing(item).getModelItemsByName(with(equal(entry.getKey())));
136           will(returnValue(entry.getValue()));
137 
138           AtomicInteger position = new AtomicInteger(1);
139           entry.getValue().forEach(modelItem -> {
140             // handle each model item child
141             // link parent
142             allowing(modelItem).getParentNodeItem();
143             will(returnValue(item));
144 
145             // establish position
146             allowing(modelItem).getPosition();
147             will(returnValue(position.getAndIncrement()));
148           });
149         });
150 
151         allowing(item).modelItems();
152         will(new Action() {
153 
154           @Override
155           public void describeTo(Description description) {
156             description.appendText("returns stream");
157           }
158 
159           @Override
160           public Object invoke(Invocation invocation) {
161             return modelItemsMap.values().stream()
162                 .flatMap(children -> children.stream());
163           }
164         });
165       }
166     });
167   }
168 
169   @SuppressWarnings("static-method")
170   @NonNull
171   private Map<String, List<IModelNodeItem<?, ?>>>
172       toModelItemsMap(@NonNull List<IModelNodeItem<?, ?>> modelItems) {
173 
174     Map<String, List<IModelNodeItem<?, ?>>> retval = new LinkedHashMap<>(); // NOPMD - intentional
175     for (IModelNodeItem<?, ?> item : modelItems) {
176       String name = item.getName();
177       List<IModelNodeItem<?, ?>> namedItems = retval.get(name);
178       if (namedItems == null) {
179         namedItems = new LinkedList<>(); // NOPMD - intentional
180         retval.put(name, namedItems);
181       }
182       namedItems.add(item);
183     }
184     return CollectionUtil.unmodifiableMap(retval);
185   }
186 
187   @NonNull
188   public IFlagNodeItem flag(@NonNull String name, @NonNull IAnyAtomicItem value) {
189     IFlagNodeItem retval = newMock(IFlagNodeItem.class, name);
190 
191     getContext().checking(new Expectations() {
192       { // NOPMD - intentional
193         allowing(retval).getName();
194         will(returnValue(name));
195 
196         allowing(retval).hasValue();
197         will(returnValue(true));
198 
199         allowing(retval).toAtomicItem();
200         will(returnValue(value));
201 
202         allowing(retval).getNodeItem();
203         will(returnValue(retval));
204       }
205     });
206 
207     handleChildren(retval, CollectionUtil.emptyList(), CollectionUtil.emptyList());
208 
209     return retval;
210   }
211 
212   @NonNull
213   public IFieldNodeItem field(@NonNull String name, @NonNull IAnyAtomicItem value) {
214     return field(name, value, CollectionUtil.emptyList());
215   }
216 
217   @NonNull
218   public IFieldNodeItem field(@NonNull String name, @NonNull IAnyAtomicItem value,
219       @NonNull List<IFlagNodeItem> flags) {
220     IFieldNodeItem retval = newMock(IFieldNodeItem.class, name);
221 
222     getContext().checking(new Expectations() {
223       { // NOPMD - intentional
224         allowing(retval).getName();
225         will(returnValue(name));
226 
227         allowing(retval).hasValue();
228         will(returnValue(true));
229 
230         allowing(retval).toAtomicItem();
231         will(returnValue(value));
232 
233         allowing(retval).getNodeItem();
234         will(returnValue(retval));
235       }
236     });
237 
238     handleChildren(retval, flags, CollectionUtil.emptyList());
239     return retval;
240   }
241 
242   @NonNull
243   public IAssemblyNodeItem assembly(@NonNull String name, @NonNull List<IFlagNodeItem> flags,
244       @NonNull List<IModelNodeItem<?, ?>> modelItems) {
245     IAssemblyNodeItem retval = newMock(IAssemblyNodeItem.class, name);
246 
247     getContext().checking(new Expectations() {
248       { // NOPMD - intentional
249         allowing(retval).getName();
250         will(returnValue(name));
251 
252         allowing(retval).getNodeItem();
253         will(returnValue(retval));
254       }
255     });
256 
257     handleChildren(retval, flags, modelItems);
258 
259     return retval;
260   }
261 
262 }