1 package com.atlassian.plugins.codegen;
2
3 import com.atlassian.plugins.codegen.ComponentDeclaration.Visibility;
4 import com.atlassian.plugins.codegen.XmlMatchers.XmlWrapper;
5
6 import com.google.common.collect.ImmutableMap;
7
8 import org.apache.commons.io.FileUtils;
9 import org.junit.Before;
10 import org.junit.Test;
11
12 import static com.atlassian.fugue.Option.some;
13 import static com.atlassian.plugins.codegen.ClassId.fullyQualified;
14 import static com.atlassian.plugins.codegen.I18nString.i18nString;
15 import static com.atlassian.plugins.codegen.ModuleDescriptor.moduleDescriptor;
16 import static com.atlassian.plugins.codegen.PluginParameter.pluginParameter;
17 import static com.atlassian.plugins.codegen.PluginProjectChangeset.changeset;
18 import static com.atlassian.plugins.codegen.XmlMatchers.node;
19 import static com.atlassian.plugins.codegen.XmlMatchers.nodeCount;
20 import static com.atlassian.plugins.codegen.XmlMatchers.nodeName;
21 import static com.atlassian.plugins.codegen.XmlMatchers.nodeTextEquals;
22 import static com.atlassian.plugins.codegen.XmlMatchers.nodes;
23 import static org.hamcrest.MatcherAssert.assertThat;
24 import static org.hamcrest.Matchers.equalTo;
25 import static org.hamcrest.Matchers.notNullValue;
26 import static org.hamcrest.Matchers.nullValue;
27
28 public class PluginXmlRewriterTest
29 {
30 protected static final String CLASS = "com.atlassian.test.MyClass";
31 protected static final String INTERFACE = "com.atlassian.test.MyInterface";
32 protected static final String INTERFACE2 = "com.atlassian.test.MyInterface2";
33 protected static final ComponentImport IMPORT = ComponentImport.componentImport(fullyQualified(INTERFACE));
34 protected static final ComponentImport IMPORT2 = ComponentImport.componentImport(fullyQualified(INTERFACE2));
35
36 protected ComponentDeclaration.Builder componentBuilder = ComponentDeclaration.builder(fullyQualified(CLASS), "my-key");
37
38 protected ProjectHelper helper;
39 protected PluginXmlRewriter rewriter;
40
41 @Before
42 public void setup() throws Exception
43 {
44 helper = new ProjectHelper();
45 usePluginXml("empty-plugin.xml");
46 }
47
48 private void usePluginXml(String path) throws Exception
49 {
50 helper.usePluginXml(path);
51 rewriter = new PluginXmlRewriter(helper.location);
52 }
53
54 @Test
55 public void i18nResourceIsNotAddedByDefault() throws Exception
56 {
57 assertThat(applyChanges(addPluginParam()),
58 nodes("//resource[@type='i18n']", nodeCount(0)));
59 }
60
61 @Test
62 public void i18nResourceIsAddedIfI18nPropertiesArePresent() throws Exception
63 {
64 assertThat(applyChanges(addI18nProperty()),
65 nodes("//resource[@type='i18n']", nodeCount(1)));
66 }
67
68 @Test
69 public void i18nResourceHasDefaultName() throws Exception
70 {
71 assertThat(applyChanges(addI18nProperty()),
72 node("//resource[@type='i18n']/@name", nodeTextEquals("i18n")));
73 }
74
75 @Test
76 public void i18nResourceHasDefaultLocation() throws Exception
77 {
78 assertThat(applyChanges(addI18nProperty()),
79 node("//resource[@type='i18n']/@location", nodeTextEquals(ProjectHelper.PLUGIN_KEY)));
80 }
81
82 @Test
83 public void i18nResourceWithSameNameIsNotAdded() throws Exception
84 {
85 usePluginXml("plugin-with-same-i18n-name.xml");
86
87 assertThat(applyChanges(addI18nProperty()),
88 nodes("//resource[@type='i18n']", nodeCount(1)));
89 }
90
91 @Test
92 public void i18nResourceWithSameNameIsNotOverwritten() throws Exception
93 {
94 usePluginXml("plugin-with-same-i18n-name.xml");
95
96 assertThat(applyChanges(addI18nProperty()),
97 node("//resource[@type='i18n']/@location", nodeTextEquals("nonstandard-location")));
98 }
99
100 @Test
101 public void i18nResourceWithSameLocationIsNotAdded() throws Exception
102 {
103 usePluginXml("plugin-with-same-i18n-location.xml");
104
105 assertThat(applyChanges(addI18nProperty()),
106 nodes("//resource[@type='i18n']", nodeCount(1)));
107 }
108
109 @Test
110 public void i18nResourceWithSameLocationIsNotOverwritten() throws Exception
111 {
112 usePluginXml("plugin-with-same-i18n-location.xml");
113
114 assertThat(applyChanges(addI18nProperty()),
115 node("//resource[@type='i18n']/@name", nodeTextEquals("nonstandard-name")));
116 }
117
118 @Test
119 public void pluginParamIsAdded() throws Exception
120 {
121 assertThat(applyChanges(addPluginParam()),
122 nodes("//plugin-info/param", nodeCount(1)));
123 }
124
125 @Test
126 public void pluginParamHasName() throws Exception
127 {
128 assertThat(applyChanges(addPluginParam()),
129 node("//plugin-info/param/@name", nodeTextEquals("foo")));
130 }
131
132 @Test
133 public void pluginParamHasValue() throws Exception
134 {
135 assertThat(applyChanges(addPluginParam()),
136 node("//plugin-info/param", nodeTextEquals("bar")));
137 }
138
139 @Test
140 public void secondPluginParamIsAdded() throws Exception
141 {
142 applyChanges(addPluginParam());
143
144 assertThat(applyChanges(changeset().with(pluginParameter("second", "thing"))),
145 nodes("//plugin-info/param", nodeCount(2)));
146 }
147
148 @Test
149 public void secondPluginParamHasValue() throws Exception
150 {
151 applyChanges(addPluginParam());
152
153 assertThat(applyChanges(changeset().with(pluginParameter("second", "thing"))),
154 node("//plugin-info/param[@name='second']", nodeTextEquals("thing")));
155 }
156
157 @Test
158 public void duplicatePluginParamIsNotAdded() throws Exception
159 {
160 applyChanges(addPluginParam());
161
162 assertThat(applyChanges(changeset().with(pluginParameter("foo", "baz"))),
163 nodes("//plugin-info/param", nodeCount(1)));
164 }
165
166 @Test
167 public void pluginParamCannotBeOverwritten() throws Exception
168 {
169 applyChanges(addPluginParam());
170
171 assertThat(applyChanges(changeset().with(pluginParameter("second", "thing"))),
172 node("//plugin-info/param", nodeTextEquals("bar")));
173 }
174
175 @Test
176 public void componentImportIsAdded() throws Exception
177 {
178 assertThat(applyChanges(changeset().with(IMPORT)),
179 node("//component-import", notNullValue()));
180 }
181
182 @Test
183 public void componentImportHasInterface() throws Exception
184 {
185 assertThat(applyChanges(changeset().with(IMPORT)),
186 node("//component-import/@interface", nodeTextEquals(INTERFACE)));
187 }
188
189 @Test
190 public void componentImportHasDefaultKey() throws Exception
191 {
192 assertThat(applyChanges(changeset().with(IMPORT)),
193 node("//component-import/@key", nodeTextEquals("myInterface")));
194 }
195
196 @Test
197 public void componentImportHasSpecifiedKey() throws Exception
198 {
199 assertThat(applyChanges(changeset().with(IMPORT.key(some("new-key")))),
200 node("//component-import/@key", nodeTextEquals("new-key")));
201 }
202
203 @Test
204 public void componentImportHasNoFilterByDefault() throws Exception
205 {
206 assertThat(applyChanges(changeset().with(IMPORT)),
207 node("//component-import/@filter", nullValue()));
208 }
209
210 @Test
211 public void componentImportHasSpecifiedFilter() throws Exception
212 {
213 assertThat(applyChanges(changeset().with(IMPORT.filter(some("my-filter")))),
214 node("//component-import/@filter", nodeTextEquals("my-filter")));
215 }
216
217 @Test
218 public void duplicateComponentImportKeyCannotBeAdded() throws Exception
219 {
220 applyChanges(changeset().with(IMPORT.key(some("my-key"))));
221
222 assertThat(applyChanges(changeset().with(IMPORT2.key(some("my-key")))),
223 nodes("//component-import", nodeCount(1)));
224 }
225
226 @Test
227 public void componentImportWithSameKeyIsNotOverwritten() throws Exception
228 {
229 applyChanges(changeset().with(IMPORT.key(some("my-key"))));
230
231 assertThat(applyChanges(changeset().with(IMPORT2.key(some("my-key")))),
232 node("//component-import/@interface", nodeTextEquals(INTERFACE)));
233 }
234
235 @Test
236 public void componentWithSameInterfaceCannotBeAdded() throws Exception
237 {
238 applyChanges(changeset().with(IMPORT.key(some("key1"))));
239
240 assertThat(applyChanges(changeset().with(IMPORT.key(some("key2")))),
241 nodes("//component-import", nodeCount(1)));
242 }
243
244 @Test
245 public void componentWithSameInterfaceInSubElementCannotBeAdded() throws Exception
246 {
247 usePluginXml("plugin-with-import-interface-element.xml");
248
249 assertThat(applyChanges(changeset().with(IMPORT.key(some("key2")))),
250 nodes("//component-import", nodeCount(1)));
251 }
252
253 @Test
254 public void componentCannotBeAddedIfAlternateInterfaceIsAlreadyUsed() throws Exception
255 {
256 applyChanges(changeset().with(IMPORT.key(some("key1"))));
257
258 assertThat(applyChanges(changeset().with(IMPORT2.alternateInterfaces(fullyQualified(INTERFACE)).key(some("key2")))),
259 nodes("//component-import", nodeCount(1)));
260 }
261
262 @Test
263 public void componentIsAdded() throws Exception
264 {
265 assertThat(applyChanges(changeset().with(componentBuilder.build())),
266 node("//component", notNullValue()));
267 }
268
269 @Test
270 public void componentHasKey() throws Exception
271 {
272 assertThat(applyChanges(changeset().with(componentBuilder.build())),
273 node("//component/@key", nodeTextEquals("my-key")));
274 }
275
276 @Test
277 public void componentHasClass() throws Exception
278 {
279 assertThat(applyChanges(changeset().with(componentBuilder.build())),
280 node("//component/@class", nodeTextEquals(CLASS)));
281 }
282
283 @Test
284 public void componentHasNoNameByDefault() throws Exception
285 {
286 assertThat(applyChanges(changeset().with(componentBuilder.build())),
287 node("//component/@name", nullValue()));
288 }
289
290 @Test
291 public void componentHasSpecifiedName() throws Exception
292 {
293 componentBuilder.name(some("my-name"));
294
295 assertThat(applyChanges(changeset().with(componentBuilder.build())),
296 node("//component/@name", nodeTextEquals("my-name")));
297 }
298
299 @Test
300 public void componentHasNoNameI18nKeyByDefault() throws Exception
301 {
302 assertThat(applyChanges(changeset().with(componentBuilder.build())),
303 node("//component/@i18n-name-key", nullValue()));
304 }
305
306 @Test
307 public void componentHasSpecifiedNameI18nKey() throws Exception
308 {
309 componentBuilder.nameI18nKey(some("name-key"));
310
311 assertThat(applyChanges(changeset().with(componentBuilder.build())),
312 node("//component/@i18n-name-key", nodeTextEquals("name-key")));
313 }
314
315 @Test
316 public void componentIsPrivateByDefault() throws Exception
317 {
318 assertThat(applyChanges(changeset().with(componentBuilder.build())),
319 node("//component/@public", nullValue()));
320 }
321
322 @Test
323 public void componentIsPublicIfSpecified() throws Exception
324 {
325 componentBuilder.visibility(Visibility.PUBLIC);
326
327 assertThat(applyChanges(changeset().with(componentBuilder.build())),
328 node("//component/@public", nodeTextEquals("true")));
329 }
330
331 @Test
332 public void componentHasNoAliasByDefault() throws Exception
333 {
334 assertThat(applyChanges(changeset().with(componentBuilder.build())),
335 node("//component/@alias", nullValue()));
336 }
337
338 @Test
339 public void componentHasSpecifiedAlias() throws Exception
340 {
341 componentBuilder.alias(some("my-alias"));
342
343 assertThat(applyChanges(changeset().with(componentBuilder.build())),
344 node("//component/@alias", nodeTextEquals("my-alias")));
345 }
346
347 @Test
348 public void componentHasNoDescriptionByDefault() throws Exception
349 {
350 assertThat(applyChanges(changeset().with(componentBuilder.build())),
351 node("//component/description", nullValue()));
352 }
353
354 @Test
355 public void componentHasSpecifiedDescription() throws Exception
356 {
357 componentBuilder.description(some("desc"));
358
359 assertThat(applyChanges(changeset().with(componentBuilder.build())),
360 node("//component/description", nodeTextEquals("desc")));
361 }
362
363 @Test
364 public void componentHasNoDescriptionI18nKeyByDefault() throws Exception
365 {
366 componentBuilder.description(some("desc"));
367
368 assertThat(applyChanges(changeset().with(componentBuilder.build())),
369 node("//component/description/@key", nullValue()));
370 }
371
372 @Test
373 public void componentHasSpecifiedDescriptionI18nKey() throws Exception
374 {
375 componentBuilder.description(some("desc")).descriptionI18nKey(some("desc-key"));
376
377 assertThat(applyChanges(changeset().with(componentBuilder.build())),
378 node("//component/description/@key", nodeTextEquals("desc-key")));
379 }
380
381 @Test
382 public void componentHasNoInterfaceByDefault() throws Exception
383 {
384 assertThat(applyChanges(changeset().with(componentBuilder.build())),
385 node("//component/interface", nullValue()));
386 }
387
388 @Test
389 public void componentHasSpecifiedInterface() throws Exception
390 {
391 componentBuilder.interfaceId(some(fullyQualified(INTERFACE)));
392
393 assertThat(applyChanges(changeset().with(componentBuilder.build())),
394 node("//component/interface", nodeTextEquals(INTERFACE)));
395 }
396
397 @Test
398 public void componentHasNoServicePropertiesByDefault() throws Exception
399 {
400 assertThat(applyChanges(changeset().with(componentBuilder.build())),
401 node("//component/service-properties", nullValue()));
402 }
403
404 @Test
405 public void componentHasSpecifiedServiceProperties() throws Exception
406 {
407 componentBuilder.serviceProperties(ImmutableMap.of("foo", "bar"));
408
409 assertThat(applyChanges(changeset().with(componentBuilder.build())),
410 node("//component/service-properties/entry[@key='foo']/@value", nodeTextEquals("bar")));
411 }
412
413 @Test
414 public void duplicateComponentKeyCannotBeAdded() throws Exception
415 {
416 ComponentDeclaration firstComponent = componentBuilder.name(some("first")).build();
417 ComponentDeclaration secondComponentWithSameKey = componentBuilder.name(some("different")).build();
418 applyChanges(changeset().with(firstComponent));
419
420 assertThat(applyChanges(changeset().with(secondComponentWithSameKey)),
421 nodes("//component", nodeCount(1)));
422 }
423
424 @Test
425 public void componentWithSameKeyIsNotOverwritten() throws Exception
426 {
427 ComponentDeclaration firstComponent = componentBuilder.name(some("first")).build();
428 ComponentDeclaration secondComponentWithSameKey = componentBuilder.name(some("different")).build();
429 applyChanges(changeset().with(firstComponent));
430
431 assertThat(applyChanges(changeset().with(secondComponentWithSameKey)),
432 node("//component/@name", nodeTextEquals("first")));
433 }
434
435 @Test
436 public void moduleDescriptorIsAdded() throws Exception
437 {
438 String module = "<my-module>has some content</my-module>";
439 assertThat(applyChanges(changeset().with(moduleDescriptor(module))),
440 node("//my-module", nodeTextEquals("has some content")));
441 }
442
443 @Test
444 public void moduleDescriptorIsPlacedAfterOtherModuleDescriptorsOfSameElementName() throws Exception
445 {
446 String module1 = "<foo-module type=\"test\">has some content</foo-module>";
447 String module2 = "<bar-module type=\"test\">has some content</bar-module>";
448 applyChanges(changeset().with(moduleDescriptor(module1), moduleDescriptor(module2)));
449
450 String module3 = "<foo-module type=\"test\">another one</foo-module>";
451 assertThat(applyChanges(changeset().with(moduleDescriptor(module3))),
452 node("//*[@type='test'][2]", nodeName(equalTo("bar-module"))));
453 }
454
455 @Test
456 public void moduleDescriptorWithSameTypeAndKeyCannotBeAdded() throws Exception
457 {
458 String module1 = "<my-module key=\"my-key\">good</my-module>";
459 String module2 = "<my-module key=\"my-key\">worse</my-module>";
460 applyChanges(changeset().with(moduleDescriptor(module1)));
461
462 assertThat(applyChanges(changeset().with(moduleDescriptor(module2))),
463 nodes("//my-module", nodeCount(1)));
464 }
465
466 @Test
467 public void moduleDescriptorWithSameTypeAndKeyIsNotOverwritten() throws Exception
468 {
469 String module1 = "<my-module key=\"my-key\">good</my-module>";
470 String module2 = "<my-module key=\"my-key\">worse</my-module>";
471 applyChanges(changeset().with(moduleDescriptor(module1)));
472
473 assertThat(applyChanges(changeset().with(moduleDescriptor(module2))),
474 node("//my-module", nodeTextEquals("good")));
475 }
476
477 protected PluginProjectChangeset addPluginParam()
478 {
479 return new PluginProjectChangeset().with(pluginParameter("foo", "bar"));
480 }
481
482 protected PluginProjectChangeset addI18nProperty()
483 {
484 return new PluginProjectChangeset().with(i18nString("foo", "bar"));
485 }
486
487 protected XmlWrapper applyChanges(PluginProjectChangeset changes) throws Exception
488 {
489 rewriter.applyChanges(changes);
490 return XmlMatchers.xml(FileUtils.readFileToString(helper.pluginXml));
491 }
492 }