1 package com.atlassian.plugins.codegen;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.util.UUID;
7
8 import com.atlassian.plugins.codegen.ComponentDeclaration.Visibility;
9 import com.atlassian.plugins.codegen.modules.PluginModuleLocation;
10
11 import com.google.common.collect.ImmutableMap;
12
13 import org.apache.commons.io.FileUtils;
14 import org.apache.commons.io.IOUtils;
15 import org.dom4j.Document;
16 import org.dom4j.DocumentHelper;
17 import org.dom4j.Node;
18 import org.junit.Before;
19 import org.junit.Test;
20
21 import static com.atlassian.fugue.Option.some;
22 import static com.atlassian.plugins.codegen.ClassId.fullyQualified;
23 import static junit.framework.Assert.assertEquals;
24 import static junit.framework.Assert.assertNotNull;
25 import static junit.framework.Assert.assertNull;
26 import static junit.framework.Assert.assertTrue;
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 File tempDir;
35 protected File resourcesDir;
36 protected File pluginXml;
37 protected ComponentDeclaration.Builder componentBuilder = ComponentDeclaration.builder(fullyQualified(CLASS), "my-key");
38
39 protected PluginXmlRewriter rewriter;
40
41 @Before
42 public void setup() throws Exception
43 {
44 final File sysTempDir = new File("target");
45 String dirName = UUID.randomUUID().toString();
46 tempDir = new File(sysTempDir, dirName);
47 resourcesDir = new File(tempDir, "resources");
48 pluginXml = new File(resourcesDir, "atlassian-plugin.xml");
49
50 tempDir.mkdirs();
51 resourcesDir.mkdirs();
52
53 InputStream is = this.getClass().getResourceAsStream("/empty-plugin.xml");
54 IOUtils.copy(is, FileUtils.openOutputStream(pluginXml));
55
56 rewriter = new PluginXmlRewriter(pluginXml);
57 }
58
59 @Test
60 public void canConstructXmlRewriterFromLocation() throws Exception
61 {
62 PluginModuleLocation location = new PluginModuleLocation.Builder(new File(tempDir, "src"))
63 .resourcesDirectory(resourcesDir)
64 .testDirectory(new File(tempDir, "test-src"))
65 .build();
66 rewriter = new PluginXmlRewriter(location);
67
68
69 long oldFileSize = FileUtils.sizeOf(pluginXml);
70 rewriter.applyChanges(addPluginParam());
71
72
73 assertTrue(FileUtils.sizeOf(pluginXml) != oldFileSize);
74 }
75
76 @Test
77 public void i18nResourceIsNotAddedByDefault() throws Exception
78 {
79 Document xml = applyChanges(addPluginParam());
80
81 assertEquals(0, xml.selectNodes("//resource").size());
82 }
83
84 @Test
85 public void i18nResourceIsAddedIfI18nPropertiesArePresent() throws Exception
86 {
87 Document xml = applyChanges(addI18nProperty());
88
89 assertNotNull(xml.selectSingleNode("//resource"));
90 }
91
92 @Test
93 public void i18nResourceHasType() throws Exception
94 {
95 Document xml = applyChanges(addI18nProperty());
96
97 assertEquals("i18n", xml.selectSingleNode("//resource/@type").getText());
98 }
99
100 @Test
101 public void i18nResourceHasName() throws Exception
102 {
103 Document xml = applyChanges(addI18nProperty());
104
105 assertEquals("i18n", xml.selectSingleNode("//resource/@name").getText());
106 }
107
108 @Test
109 public void i18nResourceHasLocation() throws Exception
110 {
111 Document xml = applyChanges(addI18nProperty());
112
113 assertEquals(ProjectRewriter.DEFAULT_I18N_NAME, xml.selectSingleNode("//resource/@location").getText());
114 }
115
116 @Test
117 public void pluginParamIsAdded() throws Exception
118 {
119 Document xml = applyChanges(addPluginParam());
120
121 assertNotNull(xml.selectSingleNode("//plugin-info/param"));
122 }
123
124 @Test
125 public void pluginParamHasName() throws Exception
126 {
127 Document xml = applyChanges(addPluginParam());
128
129 assertEquals("foo", xml.selectSingleNode("//plugin-info/param/@name").getText());
130 }
131
132 @Test
133 public void pluginParamHasValue() throws Exception
134 {
135 Document xml = applyChanges(addPluginParam());
136
137 assertEquals("bar", xml.selectSingleNode("//plugin-info/param").getText());
138 }
139
140 @Test
141 public void secondPluginParamIsAdded() throws Exception
142 {
143 applyChanges(addPluginParam());
144 Document xml = applyChanges(new PluginProjectChangeset().withPluginParameters(ImmutableMap.of("second", "thing")));
145
146 assertEquals(2, xml.selectNodes("//plugin-info/param").size());
147 }
148
149 @Test
150 public void secondPluginParamHasValue() throws Exception
151 {
152 applyChanges(addPluginParam());
153 Document xml = applyChanges(new PluginProjectChangeset().withPluginParameters(ImmutableMap.of("second", "thing")));
154
155 assertEquals("thing", xml.selectSingleNode("//plugin-info/param[@name='second']").getText());
156 }
157
158 @Test
159 public void pluginParamCannotBeOverwritten() throws Exception
160 {
161 applyChanges(addPluginParam());
162 Document xml = applyChanges(new PluginProjectChangeset().withPluginParameters(ImmutableMap.of("foo", "baz")));
163
164 assertEquals("bar", xml.selectSingleNode("//plugin-info/param").getText());
165 }
166
167 @Test
168 public void componentImportIsAdded() throws Exception
169 {
170 Document xml = applyChanges(componentImport(IMPORT));
171
172 assertNotNull(xml.selectSingleNode("//component-import"));
173 }
174
175 @Test
176 public void componentImportHasInterface() throws Exception
177 {
178 Document xml = applyChanges(componentImport(IMPORT));
179
180 assertEquals(INTERFACE, xml.selectSingleNode("//component-import/@interface").getText());
181 }
182
183 @Test
184 public void componentImportHasDefaultKey() throws Exception
185 {
186 Document xml = applyChanges(componentImport(IMPORT));
187
188 assertEquals("myInterface", xml.selectSingleNode("//component-import/@key").getText());
189 }
190
191 @Test
192 public void componentImportHasSpecifiedKey() throws Exception
193 {
194 Document xml = applyChanges(componentImport(IMPORT.key(some("new-key"))));
195
196 assertEquals("new-key", xml.selectSingleNode("//component-import/@key").getText());
197 }
198
199 @Test
200 public void componentImportHasNoFilterByDefault() throws Exception
201 {
202 Document xml = applyChanges(componentImport(IMPORT));
203
204 assertNull(xml.selectSingleNode("//component-import/@filter"));
205 }
206
207 @Test
208 public void componentImportHasSpecifiedFilter() throws Exception
209 {
210 Document xml = applyChanges(componentImport(IMPORT.filter(some("my-filter"))));
211
212 assertEquals("my-filter", xml.selectSingleNode("//component-import/@filter").getText());
213 }
214
215 @Test
216 public void componentIsAdded() throws Exception
217 {
218 Document xml = applyChanges(component());
219
220 assertNotNull(xml.selectSingleNode("//component"));
221 }
222
223 @Test
224 public void componentHasKey() throws Exception
225 {
226 Document xml = applyChanges(component());
227
228 assertEquals("my-key", xml.selectSingleNode("//component/@key").getText());
229 }
230
231 @Test
232 public void componentHasClass() throws Exception
233 {
234 Document xml = applyChanges(component());
235
236 assertEquals(CLASS, xml.selectSingleNode("//component/@class").getText());
237 }
238
239 @Test
240 public void componentHasNoNameByDefault() throws Exception
241 {
242 Document xml = applyChanges(component());
243
244 assertNull(xml.selectSingleNode("//component/@name"));
245 }
246
247 @Test
248 public void componentHasSpecifiedName() throws Exception
249 {
250 componentBuilder.name(some("my-name"));
251 Document xml = applyChanges(component());
252
253 assertEquals("my-name", xml.selectSingleNode("//component/@name").getText());
254 }
255
256 @Test
257 public void componentHasNoNameI18nKeyByDefault() throws Exception
258 {
259 Document xml = applyChanges(component());
260
261 assertNull(xml.selectSingleNode("//component/@i18n-name-key"));
262 }
263
264 @Test
265 public void componentHasSpecifiedNameI18nKey() throws Exception
266 {
267 componentBuilder.nameI18nKey(some("name-key"));
268 Document xml = applyChanges(component());
269
270 assertEquals("name-key", xml.selectSingleNode("//component/@i18n-name-key").getText());
271 }
272
273 @Test
274 public void componentIsPublicByDefault() throws Exception
275 {
276 Document xml = applyChanges(component());
277
278 assertEquals("true", xml.selectSingleNode("//component/@public").getText());
279 }
280
281 @Test
282 public void componentIsPrivateIfSpecified() throws Exception
283 {
284 componentBuilder.visibility(Visibility.PRIVATE);
285 Document xml = applyChanges(component());
286
287 assertNull(xml.selectSingleNode("//component/@public"));
288 }
289
290 @Test
291 public void componentHasNoAliasByDefault() throws Exception
292 {
293 Document xml = applyChanges(component());
294
295 assertNull(xml.selectSingleNode("//component/@alias"));
296 }
297
298 @Test
299 public void componentHasSpecifiedAlias() throws Exception
300 {
301 componentBuilder.alias(some("my-alias"));
302 Document xml = applyChanges(component());
303
304 assertEquals("my-alias", xml.selectSingleNode("//component/@alias").getText());
305 }
306
307 @Test
308 public void componentHasNoDescriptionByDefault() throws Exception
309 {
310 Document xml = applyChanges(component());
311
312 assertNull(xml.selectSingleNode("//component/description"));
313 }
314
315 @Test
316 public void componentHasSpecifiedDescription() throws Exception
317 {
318 componentBuilder.description(some("desc"));
319 Document xml = applyChanges(component());
320
321 assertEquals("desc", xml.selectSingleNode("//component/description").getText());
322 }
323
324 @Test
325 public void componentHasNoDescriptionI18nKeyByDefault() throws Exception
326 {
327 componentBuilder.description(some("desc"));
328 Document xml = applyChanges(component());
329
330 assertNull(xml.selectSingleNode("//component/description/@key"));
331 }
332
333 @Test
334 public void componentHasSpecifiedDescriptionI18nKey() throws Exception
335 {
336 componentBuilder.description(some("desc")).descriptionI18nKey(some("desc-key"));
337 Document xml = applyChanges(component());
338
339 assertEquals("desc-key", xml.selectSingleNode("//component/description/@key").getText());
340 }
341
342 @Test
343 public void componentHasNoInterfaceByDefault() throws Exception
344 {
345 Document xml = applyChanges(component());
346
347 assertNull(xml.selectSingleNode("//component/interface"));
348 }
349
350 @Test
351 public void componentHasSpecifiedInterface() throws Exception
352 {
353 componentBuilder.interfaceId(some(fullyQualified(INTERFACE)));
354 Document xml = applyChanges(component());
355
356 assertEquals(INTERFACE, xml.selectSingleNode("//component/interface").getText());
357 }
358
359 @Test
360 public void componentHasNoServicePropertiesByDefault() throws Exception
361 {
362 Document xml = applyChanges(component());
363
364 assertNull(xml.selectSingleNode("//component/service-properties"));
365 }
366
367 @Test
368 public void componentHasSpecifiedServiceProperties() throws Exception
369 {
370 componentBuilder.serviceProperties(ImmutableMap.of("foo", "bar"));
371 Document xml = applyChanges(component());
372
373 assertEquals("bar", xml.selectSingleNode("//component/service-properties/entry[@key='foo']/@value").getText());
374 }
375
376 @Test
377 public void moduleDescriptorIsAdded() throws Exception
378 {
379 String module = "<my-module>has some content</my-module>";
380 Document xml = applyChanges(moduleDescriptor(module));
381
382 assertEquals("has some content", xml.selectSingleNode("//my-module").getText());
383 }
384
385 @Test(expected=IOException.class)
386 public void cannotAddMalformedModuleDescriptor() throws Exception
387 {
388 String module = "<my-module>has some content</boo>";
389 rewriter.applyChanges(moduleDescriptor(module));
390 }
391
392 @Test
393 public void moduleDescriptorIsPlacedAfterOtherModuleDescriptorsOfSameElementName() throws Exception
394 {
395 String module1 = "<foo-module type=\"test\">has some content</foo-module>";
396 String module2 = "<bar-module type=\"test\">has some content</bar-module>";
397 applyChanges(moduleDescriptor(module1).with(moduleDescriptor(module2)));
398
399 String module3 = "<foo-module type=\"test\">another one</foo-module>";
400 Document xml = applyChanges(moduleDescriptor(module3));
401
402 assertEquals("bar-module", ((Node) xml.selectNodes("//*[@type='test']").get(1)).getName());
403 }
404
405 protected PluginProjectChangeset addPluginParam()
406 {
407 return new PluginProjectChangeset().withPluginParameters(ImmutableMap.of("foo", "bar"));
408 }
409
410 protected PluginProjectChangeset addI18nProperty()
411 {
412 return new PluginProjectChangeset().withI18nProperties(ImmutableMap.of("foo", "bar"));
413 }
414
415 protected PluginProjectChangeset componentImport(ComponentImport componentImport)
416 {
417 return new PluginProjectChangeset().withComponentImports(componentImport);
418 }
419
420 protected PluginProjectChangeset component()
421 {
422 return new PluginProjectChangeset().withComponentDeclarations(componentBuilder.build());
423 }
424
425 protected PluginProjectChangeset moduleDescriptor(String content)
426 {
427 return new PluginProjectChangeset().withModuleDescriptor(ModuleDescriptor.moduleDescriptor(content));
428 }
429
430 protected Document applyChanges(PluginProjectChangeset changes) throws Exception
431 {
432 rewriter.applyChanges(changes);
433 return DocumentHelper.parseText(FileUtils.readFileToString(pluginXml));
434 }
435 }