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