View Javadoc

1   package com.atlassian.plugin.parsers;
2   
3   import java.io.ByteArrayInputStream;
4   import java.io.File;
5   import java.io.FileInputStream;
6   import java.io.FileNotFoundException;
7   import java.io.InputStream;
8   import java.net.URL;
9   import java.util.Set;
10  
11  import com.atlassian.fugue.Option;
12  import com.atlassian.fugue.Suppliers;
13  import com.atlassian.plugin.Application;
14  import com.atlassian.plugin.InstallationMode;
15  import com.atlassian.plugin.ModuleDescriptorFactory;
16  import com.atlassian.plugin.Plugin;
17  import com.atlassian.plugin.PluginArtifact;
18  import com.atlassian.plugin.PluginInformation;
19  import com.atlassian.plugin.PluginParseException;
20  import com.atlassian.plugin.PluginPermission;
21  import com.atlassian.plugin.classloader.PluginClassLoader;
22  import com.atlassian.plugin.impl.DefaultDynamicPlugin;
23  import com.atlassian.plugin.mock.MockAnimalModuleDescriptor;
24  import com.atlassian.plugin.util.ClassLoaderUtils;
25  
26  import com.google.common.base.Function;
27  import com.google.common.collect.ImmutableSet;
28  import com.google.common.collect.Iterables;
29  import com.mockobjects.dynamic.C;
30  import com.mockobjects.dynamic.Mock;
31  
32  import junit.framework.TestCase;
33  
34  import static com.atlassian.fugue.Option.option;
35  import static com.atlassian.fugue.Option.some;
36  import static org.hamcrest.Matchers.hasItem;
37  import static org.hamcrest.Matchers.hasItems;
38  import static org.hamcrest.Matchers.is;
39  import static org.hamcrest.Matchers.empty;
40  import static org.junit.Assert.assertThat;
41  
42  @SuppressWarnings({"deprecation"}) //suppress deprecation warnings because we still need to test deprecated methods.
43  public class TestXmlDescriptorParser extends TestCase
44  {
45      private static final String MISSING_INFO_TEST_FILE = "test-missing-plugin-info.xml";
46      private static final String DUMMY_PLUGIN_FILE = "pooh-test-plugin.jar";
47  
48      public TestXmlDescriptorParser(String name)
49      {
50          super(name);
51      }
52  
53      // CONF-12680 Test for missing plugin-info
54      public void testMissingPluginInfo()
55      {
56          // mock up some supporting objects
57          PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
58          Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
59          mockFactory.expect("getModuleDescriptorClass", "unknown-plugin");
60  
61          // create a Plugin for testing
62          Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
63  
64          try
65          {
66              XmlDescriptorParser parser = new XmlDescriptorParser(new FileInputStream(getTestFile(MISSING_INFO_TEST_FILE)), ImmutableSet.<Application>of());
67              parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
68  
69              PluginInformation info = testPlugin.getPluginInformation();
70              assertNotNull("Info should not be null", info);
71          }
72          catch (PluginParseException e)
73          {
74              e.printStackTrace();
75              fail("Plugin information parsing should not fail.");
76          }
77          catch (FileNotFoundException e)
78          {
79              e.printStackTrace();
80              // This shouldn't happen
81              fail("Error setting up test");
82          }
83      }
84  
85      public void testPluginsApplicationVersionMinMax()
86      {
87          XmlDescriptorParser parser = parse(null,
88                  "<atlassian-plugin key='foo'>",
89                  "  <plugin-info>",
90                  "    <application-version min='3' max='4' />",
91                  "  </plugin-info>",
92                  "</atlassian-plugin>");
93          assertEquals(3, (int) parser.getPluginInformation().getMinVersion());
94          assertEquals(4, (int) parser.getPluginInformation().getMaxVersion());
95      }
96  
97      public void testPluginsApplicationVersionMinMaxWithOnlyMin()
98      {
99          XmlDescriptorParser parser = parse(null,
100                 "<atlassian-plugin key='foo'>",
101                 "  <plugin-info>",
102                 "    <application-version min='3' />",
103                 "  </plugin-info>",
104                 "</atlassian-plugin>");
105         assertEquals(3, (int) parser.getPluginInformation().getMinVersion());
106         assertEquals(0, (int) parser.getPluginInformation().getMaxVersion());
107     }
108 
109     public void testPluginsApplicationVersionMinMaxWithOnlyMax()
110     {
111         XmlDescriptorParser parser = parse(null,
112                 "<atlassian-plugin key='foo'>",
113                 "  <plugin-info>",
114                 "    <application-version max='3' />",
115                 "  </plugin-info>",
116                 "</atlassian-plugin>");
117         assertEquals(3, (int) parser.getPluginInformation().getMaxVersion());
118         assertEquals(0, (int) parser.getPluginInformation().getMinVersion());
119     }
120 
121     // Also CONF-12680 test for missing "essential metadata"
122 
123     public void testPluginsVersion()
124     {
125         String xml = "<atlassian-plugin key=\"foo\" pluginsVersion=\"2\" />";
126         XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream(xml.getBytes()), ImmutableSet.<Application>of());
127         assertEquals(2, parser.getPluginsVersion());
128     }
129 
130     public void testPluginsVersionAfterConfigure()
131     {
132         XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream("<atlassian-plugin key=\"foo\" plugins-version=\"2\" />".getBytes()), ImmutableSet.<Application>of());
133         // mock up some supporting objects
134         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
135         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
136         mockFactory.expect("getModuleDescriptorClass", "unknown-plugin");
137 
138         // create a Plugin for testing
139         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
140         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
141         assertEquals(2, testPlugin.getPluginsVersion());
142     }
143 
144     public void testPluginWithModules()
145     {
146         XmlDescriptorParser parser = parse(null,
147                 "<atlassian-plugin key='foo'>",
148                 "  <animal key='bear' />",
149                 "</atlassian-plugin>");
150         // mock up some supporting objects
151         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
152         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
153         mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
154 
155         // create a Plugin for testing
156         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
157         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
158         assertNotNull(testPlugin.getModuleDescriptor("bear"));
159     }
160 
161     public void testPluginWithModulesNoApplicationKey()
162     {
163         XmlDescriptorParser parser = parse(null,
164                 "<atlassian-plugin key='foo'>",
165                 "  <animal key='bear' application='foo'/>",
166                 "</atlassian-plugin>");
167         // mock up some supporting objects
168         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
169         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
170         mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
171 
172         // create a Plugin for testing
173         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
174         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
175         assertNull(testPlugin.getModuleDescriptor("bear"));
176     }
177 
178     public void testPluginWithSomeNonApplicationModules()
179     {
180         XmlDescriptorParser parser = parse(newApplication("myapp"),
181                 "<atlassian-plugin key='foo'>",
182                 "  <animal key='bear' application='myapp'/>",
183                 "  <animal key='bear2' application='otherapp'/>",
184                 "</atlassian-plugin>");
185         // mock up some supporting objects
186         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
187         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
188         mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
189 
190         // create a Plugin for testing
191         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
192         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
193         assertNotNull(testPlugin.getModuleDescriptor("bear"));
194         assertNull(testPlugin.getModuleDescriptor("bear2"));
195     }
196 
197     public void testPluginWithSomeRestrictionOnModulesNoVersion()
198     {
199         XmlDescriptorParser parser = parse(newApplication("myapp"),
200                 "<atlassian-plugin key='foo'>",
201                 "  <animal key='bear'>",
202                 "    <restrict application='myapp'/>",
203                 "  </animal>",
204                 "  <animal key='bear2' application='otherapp'/>",
205                 "</atlassian-plugin>");
206         // mock up some supporting objects
207         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
208         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
209         mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
210 
211         // create a Plugin for testing
212         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
213         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
214         assertNotNull(testPlugin.getModuleDescriptor("bear"));
215         assertNull(testPlugin.getModuleDescriptor("bear2"));
216     }
217 
218     public void testPluginWithSomeRestrictionOnModulesVersionAsAttribute()
219     {
220         XmlDescriptorParser parser = parse(newApplication("myapp", "2.0"),
221                 "<atlassian-plugin key='foo'>",
222                 "  <animal key='bear'>",
223                 "    <restrict application='myapp' version='[2.0]' />",
224                 "  </animal>",
225                 "  <animal key='bear2'>",
226                 "    <restrict application='myapp' version='[1.0]' />",
227                 "  </animal>",
228                 "</atlassian-plugin>");
229         // mock up some supporting objects
230         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
231         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
232         mockFactory.matchAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
233 
234         // create a Plugin for testing
235         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
236         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
237         assertNotNull(testPlugin.getModuleDescriptor("bear"));
238         assertNull(testPlugin.getModuleDescriptor("bear2"));
239     }
240 
241     public void testPluginWithSomeRestrictionOnModulesVersionAsElement()
242     {
243         XmlDescriptorParser parser = parse(newApplication("myapp", "2.0"),
244                 "<atlassian-plugin key='foo'>",
245                 "  <animal key='bear'>",
246                 "    <restrict application='myapp'>",
247                 "      <version>(,3.0)</version>",
248                 "      <version>[5.0,)</version>",
249                 "    </restrict>",
250                 "  </animal>",
251                 "  <animal key='bear2'>",
252                 "    <restrict application='myapp'>",
253                 "      <version>(,2.0)</version>",
254                 "      <version>[5.0,)</version>",
255                 "    </restrict>",
256                 "  </animal>",
257                 "</atlassian-plugin>");
258         // mock up some supporting objects
259         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
260         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
261         mockFactory.matchAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
262 
263         // create a Plugin for testing
264         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
265         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
266         assertNotNull(testPlugin.getModuleDescriptor("bear"));
267         assertNull(testPlugin.getModuleDescriptor("bear2"));
268     }
269 
270     public void testPluginWithSystemAttribute()
271     {
272         XmlDescriptorParser parser = parse(null,
273                 "<atlassian-plugin key='foo' system='true'>",
274                 "</atlassian-plugin>");
275 
276         // mock up some supporting objects
277         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
278         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
279         mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
280 
281         // create a Plugin for testing
282         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
283         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
284         // PLUG-415 Plugins2 plugins now need to be able to be declared as system.
285         assertEquals("This plugin should be a system plugin - bundled plugins2 plugins are system plugins.", true, testPlugin.isSystemPlugin());
286     }
287 
288     public void testPluginWithoutSystemAttribute()
289     {
290         XmlDescriptorParser parser = parse(null,
291                 "<atlassian-plugin key='foo' >",
292                 "</atlassian-plugin>");
293 
294         // mock up some supporting objects
295         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
296         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
297         mockFactory.expectAndReturn("getModuleDescriptorClass", C.args(C.eq("animal")), MockAnimalModuleDescriptor.class);
298 
299         // create a Plugin for testing
300         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
301         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
302         assertEquals("This plugin should not be a system plugin.", false, testPlugin.isSystemPlugin());
303     }
304 
305     public void testPluginsVersionWithDash()
306     {
307         String xml = "<atlassian-plugin key=\"foo\" plugins-version=\"2\" />";
308         XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream(xml.getBytes()), ImmutableSet.<Application>of());
309         assertEquals(2, parser.getPluginsVersion());
310     }
311 
312     public void testPluginsVersionMissing()
313     {
314         String xml = "<atlassian-plugin key=\"foo\" />";
315         XmlDescriptorParser parser = new XmlDescriptorParser(new ByteArrayInputStream(xml.getBytes()), ImmutableSet.<Application>of());
316         assertEquals(1, parser.getPluginsVersion());
317     }
318 
319     public void testPluginsResourcesAvailableToModuleDescriptors()
320     {
321         XmlDescriptorParser parser = parse(null,
322                 "<atlassian-plugin key='foo'>",
323                 "  <resource type='velocity' name='edit'>Show an input box here.</resource>",
324                 "  <animal key='bear' />",
325                 "</atlassian-plugin>");
326         // mock up some supporting objects
327         PluginClassLoader classLoader = new PluginClassLoader(new File(getTestFile("ap-plugins") + "/" + DUMMY_PLUGIN_FILE));
328         Mock mockFactory = new Mock(ModuleDescriptorFactory.class);
329         MockAnimalModuleDescriptor descriptor = new MockAnimalModuleDescriptor("velocity", "edit");
330         mockFactory.expectAndReturn("getModuleDescriptor", C.args(C.eq("animal")), descriptor);
331 
332         // create a Plugin for testing
333         Plugin testPlugin = new DefaultDynamicPlugin((PluginArtifact) new Mock(PluginArtifact.class).proxy(), classLoader);
334         parser.configurePlugin((ModuleDescriptorFactory) mockFactory.proxy(), testPlugin);
335         assertNotNull(testPlugin.getModuleDescriptor("bear"));
336 
337         mockFactory.verify();
338     }
339 
340     public void testPluginPermissionsIsAllPermissionsForPluginsWithNoVersionByDefault()
341     {
342         XmlDescriptorParser parser = parse(null,
343                 "<atlassian-plugin key='foo'>",
344                 "  <plugin-info>",
345                 "  </plugin-info>",
346                 "</atlassian-plugin>");
347 
348         final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
349         assertEquals(1, parsedPermissions.size());
350         assertSame(PluginPermission.ALL, Iterables.get(parsedPermissions, 0));
351     }
352 
353     public void testPluginPermissionsIsAllPermissionsForPlugins1ByDefault()
354     {
355         XmlDescriptorParser parser = parse(null,
356                 "<atlassian-plugin key='foo' plugins-version='1'>",
357                 "  <plugin-info>",
358                 "  </plugin-info>",
359                 "</atlassian-plugin>");
360 
361         final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
362         assertEquals(1, parsedPermissions.size());
363         assertSame(PluginPermission.ALL, Iterables.get(parsedPermissions, 0));
364     }
365 
366     public void testPluginPermissionsIsAllPermissionsForPlugins2ByDefault()
367     {
368         XmlDescriptorParser parser = parse(null,
369                 "<atlassian-plugin key='foo' plugins-version='2'>",
370                 "  <plugin-info>",
371                 "  </plugin-info>",
372                 "</atlassian-plugin>");
373 
374         final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
375         assertEquals(1, parsedPermissions.size());
376         assertSame(PluginPermission.ALL, Iterables.get(parsedPermissions, 0));
377     }
378 
379     public void testPluginPermissionsIsFilteredByApplications()
380     {
381         XmlDescriptorParser parser = parse(newApplication("my-app"),
382                 "<atlassian-plugin key='foo' plugins-version='2'>",
383                 "  <plugin-info>",
384                 "    <permissions>",
385                 "      <permission application='my-other-app'>some_permission</permission>",
386                 "      <permission application='my-app'>some_other_permission</permission>",
387                 "      <permission application='my-other-app' installation-mode='local'>yet_another_permission</permission>",
388                 "    </permissions>",
389                 "  </plugin-info>",
390                 "</atlassian-plugin>");
391 
392         final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
393         assertEquals(1, parsedPermissions.size());
394         assertEquals("some_other_permission", Iterables.get(parsedPermissions, 0).getName());
395     }
396 
397     public void testPluginPermissions()
398     {
399         XmlDescriptorParser parser = parse(newApplication("my-other-app"),
400                 "<atlassian-plugin key='foo' plugins-version='2'>",
401                 "  <plugin-info>",
402                 "    <permissions>",
403                 "      <permission>some_permission</permission>",
404                 "      <permission application='my-app'>some_other_permission</permission>",
405                 "      <permission installation-mode='local'>yet_another_permission</permission>",
406                 "    </permissions>",
407                 "  </plugin-info>",
408                 "</atlassian-plugin>");
409 
410         final Set<PluginPermission> parsedPermissions = parser.getPluginInformation().getPermissions();
411         assertEquals(2, parsedPermissions.size());
412 
413         final PluginPermission firstPermission = Iterables.get(parsedPermissions, 0);
414         assertEquals("some_permission", firstPermission.getName());
415         assertEquals(Option.<InstallationMode>none(), firstPermission.getInstallationMode());
416 
417         final PluginPermission secondPermission = Iterables.get(parsedPermissions, 1);
418         assertEquals("yet_another_permission", secondPermission.getName());
419         assertEquals(some(InstallationMode.LOCAL), secondPermission.getInstallationMode());
420     }
421 
422     public void testPluginPermissionsIsEmptyForRemotablePluginByDefault()
423     {
424         XmlDescriptorParser parser = parse(null,
425                 "<atlassian-plugin key='foo' plugins-version='3'>",
426                 "  <plugin-info>",
427                 "  </plugin-info>",
428                 "</atlassian-plugin>");
429 
430         assertTrue(parser.getPluginInformation().getPermissions().isEmpty());
431     }
432 
433     public void testPluginPermissionsIsEmptyForBlankPermissions()
434     {
435         XmlDescriptorParser parser = parse(null,
436                 "<atlassian-plugin key='foo' plugins-version='3'>",
437                 "  <plugin-info>",
438                 "    <permissions>",
439                 "      <permission> \t </permission>",
440                 "      <permission></permission>",
441                 "    </permissions>",
442                 "  </plugin-info>",
443                 "</atlassian-plugin>");
444 
445         assertTrue(parser.getPluginInformation().getPermissions().isEmpty());
446     }
447 
448     public void testStartupIsParsed()
449     {
450         final XmlDescriptorParser parser = parse(null,
451                 "<atlassian-plugin>",
452                 "  <plugin-info>",
453                 "    <startup>early</startup>",
454                 "  </plugin-info>",
455                 "</atlassian-plugin>");
456 
457         assertEquals(parser.getPluginInformation().getStartup(), "early");
458     }
459 
460     public void testNoScanFolderWhenNoScanModulesElementIsProvided()
461     {
462         final XmlDescriptorParser parser = parse(null,
463                 "<atlassian-plugin>",
464                 "  <plugin-info>",
465                 "  </plugin-info>",
466                 "</atlassian-plugin>");
467 
468         assertThat(parser.getPluginInformation().getModuleScanFolders(), is(empty()));
469     }
470 
471     public void testDefaultScanFolderWhenNoFolderProvided()
472     {
473         final XmlDescriptorParser parser = parse(null,
474                 "<atlassian-plugin>",
475                 "  <plugin-info>",
476                 "    <scan-modules/>",
477                 "  </plugin-info>",
478                 "</atlassian-plugin>");
479 
480         assertThat(parser.getPluginInformation().getModuleScanFolders(), hasItem("META-INF/atlassian"));
481     }
482 
483     public void testDefaultScanFolderWhenFoldersAreProvided()
484     {
485         final XmlDescriptorParser parser = parse(null,
486                 "<atlassian-plugin>",
487                 "  <plugin-info>",
488                 "    <scan-modules>",
489                 "      <folder>folder1</folder>",
490                 "      <folder>folder2</folder>",
491                 "    </scan-modules>",
492                 "  </plugin-info>",
493                 "</atlassian-plugin>");
494 
495         assertThat(parser.getPluginInformation().getModuleScanFolders(), hasItems("folder1","folder2"));
496     }
497 
498 
499     private String getTestFile(String filename)
500     {
501         final URL url = ClassLoaderUtils.getResource(filename, this.getClass());
502         return url.getFile();
503     }
504 
505     private static XmlDescriptorParser parse(Application application, String... lines)
506     {
507         StringBuffer sb = new StringBuffer();
508         for (String line : lines)
509         {
510             sb.append(line.replace('\'', '"')).append('\n');
511         }
512         InputStream in = new ByteArrayInputStream(sb.toString().getBytes());
513         return new XmlDescriptorParser(in, option(application).fold(
514                 Suppliers.ofInstance(ImmutableSet.<Application>of()),
515                 new Function<Application, Set<Application>>()
516                 {
517                     @Override
518                     public Set<Application> apply(Application app)
519                     {
520                         return ImmutableSet.of(app);
521                     }
522                 }));
523     }
524 
525     private Application newApplication(final String appKey)
526     {
527         return newApplication(appKey, null);
528     }
529 
530     private Application newApplication(final String appKey, final String version)
531     {
532         return new Application()
533         {
534             @Override
535             public String getKey()
536             {
537                 return appKey;
538             }
539 
540             @Override
541             public String getVersion()
542             {
543                 return version;
544             }
545 
546             @Override
547             public String getBuildNumber()
548             {
549                 return null;
550             }
551         };
552     }
553 }