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