1   package com.atlassian.maven.plugins.amps;
2   
3   import java.io.File;
4   import java.io.FileReader;
5   import java.io.InputStream;
6   import java.io.Reader;
7   import java.util.ArrayList;
8   import java.util.List;
9   import java.util.UUID;
10  
11  import com.atlassian.maven.plugins.amps.XmlMatchers.XmlWrapper;
12  import com.atlassian.plugins.codegen.ArtifactDependency;
13  import com.atlassian.plugins.codegen.ArtifactDependency.Scope;
14  import com.atlassian.plugins.codegen.ArtifactId;
15  import com.atlassian.plugins.codegen.BundleInstruction;
16  import com.atlassian.plugins.codegen.MavenPlugin;
17  import com.atlassian.plugins.codegen.PluginProjectChangeset;
18  
19  import org.apache.commons.io.FileUtils;
20  import org.apache.maven.model.Model;
21  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
22  import org.hamcrest.Description;
23  import org.hamcrest.Matcher;
24  import org.hamcrest.Matchers;
25  import org.hamcrest.TypeSafeDiagnosingMatcher;
26  import org.junit.After;
27  import org.junit.Before;
28  import org.junit.Test;
29  
30  import static org.hamcrest.Matchers.hasItem;
31  
32  import static org.hamcrest.Matchers.allOf;
33  
34  import static com.atlassian.maven.plugins.amps.XmlMatchers.node;
35  import static com.atlassian.maven.plugins.amps.XmlMatchers.nodeCount;
36  import static com.atlassian.maven.plugins.amps.XmlMatchers.nodeText;
37  import static com.atlassian.maven.plugins.amps.XmlMatchers.nodeTextEquals;
38  import static com.atlassian.maven.plugins.amps.XmlMatchers.nodes;
39  import static com.atlassian.plugins.codegen.AmpsSystemPropertyVariable.ampsSystemPropertyVariable;
40  import static com.atlassian.plugins.codegen.ArtifactDependency.dependency;
41  import static com.atlassian.plugins.codegen.ArtifactId.artifactId;
42  import static com.atlassian.plugins.codegen.BundleInstruction.importPackage;
43  import static com.atlassian.plugins.codegen.BundleInstruction.privatePackage;
44  import static com.atlassian.plugins.codegen.MavenPlugin.mavenPlugin;
45  import static com.atlassian.plugins.codegen.PluginArtifact.pluginArtifact;
46  import static com.atlassian.plugins.codegen.PluginArtifact.ArtifactType.BUNDLED_ARTIFACT;
47  import static com.atlassian.plugins.codegen.PluginArtifact.ArtifactType.PLUGIN_ARTIFACT;
48  import static com.atlassian.plugins.codegen.VersionId.noVersion;
49  import static com.atlassian.plugins.codegen.VersionId.version;
50  import static com.atlassian.plugins.codegen.VersionId.versionProperty;
51  import static org.apache.commons.io.IOUtils.closeQuietly;
52  import static org.hamcrest.MatcherAssert.assertThat;
53  import static org.hamcrest.Matchers.any;
54  import static org.hamcrest.Matchers.equalTo;
55  import static org.hamcrest.Matchers.notNullValue;
56  import static org.hamcrest.Matchers.nullValue;
57  
58  public class MavenProjectRewriterTest
59  {
60      private static final ArtifactId CUSTOM_ARTIFACT = artifactId("com.atlassian.dogs", "cooper");
61      private static final ArtifactId CUSTOM_ARTIFACT2 = artifactId("com.atlassian.dogs", "sailor");
62      private static final ArtifactId MAVEN_ARTIFACT = artifactId("maven-dependency-plugin");
63      
64      private static final String TEST_POM = "test-pom.xml";
65      private static final String TEST_POM_WITH_CONFIG = "test-pom-with-config.xml";
66      private static final String TEST_POM_WITH_INSTRUCTIONS = "test-pom-with-instructions.xml";
67      private static final String TEST_POM_WITH_MAVEN_PLUGIN = "test-pom-with-maven-plugin.xml";
68  
69      private static final ArtifactDependency NEW_DEPENDENCY =
70          dependency(CUSTOM_ARTIFACT, "1.0", Scope.PROVIDED);
71  
72      private static final int INITIAL_MAVEN_PLUGIN_COUNT = 1;  // see test-pom.xml
73      private static final String NEW_MAVEN_PLUGIN_CONFIG =
74          "<executions><execution>" +
75              "<id>EXECUTION_ID</id>" +
76              "<phase>PHASE</phase>" +
77              "<goals><goal>GOAL1</goal><goal>GOAL2</goal></goals>" +
78              "<configuration>" +
79                  "<param1>value1</param1>" +
80              "</configuration>" +
81          "</execution></executions>";
82      private static final String MAVEN_PLUGIN_CONFIG_WITH_CONFLICTING_EXECUTION =
83          "<executions><execution>" +
84              "<id>copy-storage-plugin</id>" +
85              "<phase>WRONG</phase>" +
86              "<goals><goal>NO</goal></goals>" +
87          "</execution></executions>";
88  
89      private static final MavenPlugin NEW_MAVEN_PLUGIN_NO_VERSION =
90          mavenPlugin(MAVEN_ARTIFACT, noVersion(), NEW_MAVEN_PLUGIN_CONFIG);
91      private static final MavenPlugin NEW_MAVEN_PLUGIN_WITH_VERSION =
92          mavenPlugin(MAVEN_ARTIFACT, version("1.0"), NEW_MAVEN_PLUGIN_CONFIG);
93      private static final MavenPlugin NEW_MAVEN_PLUGIN_WITH_GROUP_ID =
94          mavenPlugin(CUSTOM_ARTIFACT, version("1.0"), NEW_MAVEN_PLUGIN_CONFIG);
95  
96      private static final com.atlassian.plugins.codegen.PluginArtifact NEW_BUNDLED_ARTIFACT =
97          pluginArtifact(BUNDLED_ARTIFACT, CUSTOM_ARTIFACT, noVersion());
98      private static final com.atlassian.plugins.codegen.PluginArtifact NEW_BUNDLED_ARTIFACT_WITH_VERSION =
99          pluginArtifact(BUNDLED_ARTIFACT, CUSTOM_ARTIFACT, version("1.0"));
100     private static final com.atlassian.plugins.codegen.PluginArtifact NEW_BUNDLED_ARTIFACT_WITH_VERSION_PROPERTY =
101         pluginArtifact(BUNDLED_ARTIFACT, CUSTOM_ARTIFACT, versionProperty("dog.version", "1.0"));
102     private static final com.atlassian.plugins.codegen.PluginArtifact NEW_PLUGIN_ARTIFACT =
103         pluginArtifact(PLUGIN_ARTIFACT, CUSTOM_ARTIFACT, noVersion());
104     
105     private static final BundleInstruction NEW_IMPORT_PACKAGE =
106         importPackage("com.atlassian.random", "2.0.1");
107     private static final BundleInstruction DUPLICATE_IMPORT_PACKAGE =
108         importPackage("com.atlassian.plugins.rest.common*", "1.0.5");
109     private static final BundleInstruction NEW_PRIVATE_PACKAGE =
110         privatePackage("com.atlassian.random");
111     
112     private static final PluginProjectChangeset changeset = new PluginProjectChangeset();
113     
114     private File tempDir;
115     private File pom;
116     private MavenProjectRewriter rewriter;
117     
118     @Before
119     public void setup() throws Exception
120     {
121         final File sysTempDir = new File("target");
122         String dirName = UUID.randomUUID().toString();
123         tempDir = new File(sysTempDir, dirName);
124         tempDir.mkdirs();
125         
126         pom = new File(tempDir, "pom.xml");
127     }
128     
129     @After
130     public void deleteTempDir() throws Exception
131     {
132         FileUtils.deleteDirectory(tempDir);
133     }
134 
135     @Test
136     public void dependencyIsAdded() throws Exception
137     {
138         assertThat(applyChanges(TEST_POM, changeset.with(NEW_DEPENDENCY)),
139                    nodes("//dependencies/dependency", nodeCount(3)));
140     }
141 
142     @Test
143     public void dependencyHasGroupId() throws Exception
144     {
145         assertThat(applyChanges(TEST_POM, changeset.with(NEW_DEPENDENCY)),
146                    node("//dependencies/dependency[3]/groupId", nodeTextEquals(CUSTOM_ARTIFACT.getGroupId().get())));
147     }
148 
149     @Test
150     public void dependencyHasArtifactId() throws Exception
151     {
152         assertThat(applyChanges(TEST_POM, changeset.with(NEW_DEPENDENCY)),
153                    node("//dependencies/dependency[3]/artifactId", nodeTextEquals(CUSTOM_ARTIFACT.getArtifactId())));
154     }
155 
156     @Test
157     public void dependencyHasVersion() throws Exception
158     {
159         assertThat(applyChanges(TEST_POM, changeset.with(NEW_DEPENDENCY)),
160                    node("//dependencies/dependency[3]/version", nodeTextEquals(NEW_DEPENDENCY.getVersionId().toString())));
161     }
162 
163     @Test
164     public void dependencyHasScope() throws Exception
165     {
166         assertThat(applyChanges(TEST_POM, changeset.with(NEW_DEPENDENCY)),
167                    node("//dependencies/dependency[3]/scope", nodeTextEquals("provided")));
168     }
169     
170     @Test
171     public void duplicateDependencyIsNotAdded() throws Exception
172     {
173         ArtifactDependency existing = dependency("com.atlassian.plugins", "test-artifact-1", "1.0", Scope.PROVIDED);
174         
175         assertThat(applyChanges(TEST_POM, changeset.with(existing)),
176                    nodes("//dependencies/dependency", nodeCount(2)));
177     }
178     
179     @Test
180     public void dependencyWithVersionPropertyUsesPropertyNameForVersion() throws Exception
181     {
182         ArtifactDependency dependency = dependency(CUSTOM_ARTIFACT, versionProperty("dog.version", "1.0"), Scope.PROVIDED);
183         
184         assertThat(applyChanges(TEST_POM, changeset.with(dependency)),
185                    node("//dependencies/dependency[3]/version", nodeTextEquals("${dog.version}")));
186     }
187 
188     @Test
189     public void dependencyWithVersionPropertyAddsPropertyNameAndValueToProperties() throws Exception
190     {
191         ArtifactDependency dependency = dependency(CUSTOM_ARTIFACT, versionProperty("dog.version", "1.0"), Scope.PROVIDED);
192         
193         assertThat(applyChanges(TEST_POM, changeset.with(dependency)),
194                    node("//properties/dog.version", nodeTextEquals("1.0")));
195     }
196 
197     @Test
198     public void dependencyWithVersionPropertyDoesNotOverwriteExistingProperty() throws Exception
199     {
200         ArtifactDependency dependency = dependency(CUSTOM_ARTIFACT, versionProperty("dog.version", "1.0"), Scope.PROVIDED);
201         ArtifactDependency dependency2 = dependency(CUSTOM_ARTIFACT2, versionProperty("dog.version", "3.5"), Scope.PROVIDED);
202         
203         assertThat(applyChanges(TEST_POM, changeset.with(dependency, dependency2)),
204                    node("//properties/dog.version", nodeTextEquals("1.0")));
205     }
206     
207     @Test
208     public void mavenPluginIsAdded() throws Exception
209     {
210         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
211                    nodes("//build/plugins/plugin", nodeCount(INITIAL_MAVEN_PLUGIN_COUNT + 1)));
212     }
213     
214     @Test
215     public void mavenPluginHasArtifactId() throws Exception
216     {
217         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
218                    node("//build/plugins/plugin[2]/artifactId", nodeTextEquals(MAVEN_ARTIFACT.getArtifactId())));
219     }
220     
221     @Test
222     public void mavenPluginHasExecutionId() throws Exception
223     {
224         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
225                    node("//build/plugins/plugin[2]/executions/execution/id", nodeTextEquals("EXECUTION_ID")));
226     }
227 
228     @Test
229     public void mavenPluginHasExecutionPhase() throws Exception
230     {
231         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
232                    node("//build/plugins/plugin[2]/executions/execution/phase", nodeTextEquals("PHASE")));
233     }
234 
235     @Test
236     public void mavenPluginHasExecutionGoal1() throws Exception
237     {
238         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
239                    node("//build/plugins/plugin[2]/executions/execution/goals/goal[1]", nodeTextEquals("GOAL1")));
240     }
241 
242     @Test
243     public void mavenPluginHasExecutionGoal2() throws Exception
244     {
245         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
246                    node("//build/plugins/plugin[2]/executions/execution/goals/goal[1]", nodeTextEquals("GOAL1")));
247     }
248 
249     @Test
250     public void mavenPluginHasExecutionConfig() throws Exception
251     {
252         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
253                    node("//build/plugins/plugin[2]/executions/execution/configuration/param1", nodeTextEquals("value1")));
254     }
255 
256     @Test
257     public void mavenPluginWithNoGroupIdHasNoGroupId() throws Exception
258     {
259         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
260                    node("//build/plugins/plugin[2]/groupId", nullValue()));
261     }
262 
263     @Test
264     public void mavenPluginWithGroupIdHasGroupId() throws Exception
265     {
266         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_WITH_GROUP_ID)),
267                    node("//build/plugins/plugin[2]/groupId", nodeTextEquals(CUSTOM_ARTIFACT.getGroupId().get())));
268     }
269 
270     @Test
271     public void mavenPluginWithNoVersionHasNoVersion() throws Exception
272     {
273         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
274                    node("//build/plugins/plugin[2]/version", nullValue()));
275     }
276 
277     @Test
278     public void mavenPluginWithVersionHasVersion() throws Exception
279     {
280         assertThat(applyChanges(TEST_POM, changeset.with(NEW_MAVEN_PLUGIN_WITH_VERSION)),
281                    node("//build/plugins/plugin[2]/version", nodeTextEquals(NEW_MAVEN_PLUGIN_WITH_VERSION.getVersionId().toString())));
282     }
283 
284     @Test
285     public void mavenPluginExecutionIsAddedToExistingPlugin() throws Exception
286     {
287         assertThat(applyChanges(TEST_POM_WITH_MAVEN_PLUGIN, changeset.with(NEW_MAVEN_PLUGIN_NO_VERSION)),
288                    node("//build/plugins/plugin[2]/executions/execution[2]/id", nodeTextEquals("EXECUTION_ID")));
289     }
290 
291     @Test
292     public void mavenPluginExecutionWithDuplicateIdIsNotAdded() throws Exception
293     {
294         MavenPlugin pluginWithConflictingExecutionConfig =
295             mavenPlugin(MAVEN_ARTIFACT, noVersion(), MAVEN_PLUGIN_CONFIG_WITH_CONFLICTING_EXECUTION);
296 
297         assertThat(applyChanges(TEST_POM_WITH_MAVEN_PLUGIN, changeset.with(pluginWithConflictingExecutionConfig)),
298                    nodes("//build/plugins/plugin[2]/executions/execution", nodeCount(1)));
299     }
300 
301     @Test
302     public void mavenPluginExecutionWithDuplicateIdDoesNotOverwriteExistingConfig() throws Exception
303     {
304         MavenPlugin pluginWithConflictingExecutionConfig =
305             mavenPlugin(MAVEN_ARTIFACT, noVersion(), MAVEN_PLUGIN_CONFIG_WITH_CONFLICTING_EXECUTION);
306 
307         assertThat(applyChanges(TEST_POM_WITH_MAVEN_PLUGIN, changeset.with(pluginWithConflictingExecutionConfig)),
308                    node("//build/plugins/plugin[2]/executions/execution/phase", nodeTextEquals("process-resources")));
309     }
310 
311     @Test
312     public void configElementIsCreatedForBundleInstruction() throws Exception
313     {
314         assertThat(applyChanges(TEST_POM, changeset.with(NEW_IMPORT_PACKAGE)),
315                    node("//build/plugins/plugin[1]/configuration", notNullValue()));
316     }
317 
318     @Test
319     public void instructionsElementIsCreatedWithinNewlyCreatedConfigElement() throws Exception
320     {
321         assertThat(applyChanges(TEST_POM, changeset.with(NEW_IMPORT_PACKAGE)),
322                    node("//build/plugins/plugin[1]/configuration/instructions", notNullValue()));
323     }
324 
325     @Test
326     public void bundleInstructionIsAddedToNewInstructionsInNewConfig() throws Exception
327     {
328         assertThat(applyChanges(TEST_POM, changeset.with(NEW_IMPORT_PACKAGE)),
329                    node("//build/plugins/plugin[1]/configuration/instructions/Import-Package",
330                         nodeTextEquals("com.atlassian.random;version=\"2.0.1\"")));
331     }
332 
333     @Test
334     public void instructionsElementIsCreatedWithinExistingConfigElement() throws Exception
335     {
336         assertThat(applyChanges(TEST_POM_WITH_CONFIG, changeset.with(NEW_IMPORT_PACKAGE)),
337                    node("//build/plugins/plugin[1]/configuration/instructions", notNullValue()));
338     }
339 
340     @Test
341     public void bundleInstructionIsAddedToNewInstructionsInExistingConfig() throws Exception
342     {
343         assertThat(applyChanges(TEST_POM_WITH_CONFIG, changeset.with(NEW_IMPORT_PACKAGE)),
344                    node("//build/plugins/plugin[1]/configuration/instructions/Import-Package",
345                         nodeTextEquals("com.atlassian.random;version=\"2.0.1\"")));
346     }
347 
348     @Test
349     public void bundleInstructionIsAddedToExistingCategory() throws Exception
350     {
351         assertThat(applyChanges(TEST_POM_WITH_INSTRUCTIONS, changeset.with(NEW_IMPORT_PACKAGE)),
352                    node("//build/plugins/plugin[1]/configuration/instructions/Import-Package",
353                         nodeText(delimitedList(",", Matchers.<String>iterableWithSize(4)))));
354     }
355 
356     @SuppressWarnings("unchecked")
357     @Test
358     public void bundleInstructionIsInsertedInPackageOrderWithinExistingCategory() throws Exception
359     {
360         assertThat(applyChanges(TEST_POM_WITH_INSTRUCTIONS, changeset.with(NEW_IMPORT_PACKAGE)),
361                    node("//build/plugins/plugin[1]/configuration/instructions/Import-Package",
362                         nodeText(delimitedList(",",
363                                                Matchers.<String>hasItems(any(String.class), 
364                                                    equalTo("com.atlassian.random;version=\"2.0.1\""),
365                                                    any(String.class), any(String.class))))));
366     }
367 
368     @SuppressWarnings("unchecked")
369     @Test
370     public void existingInstructionsArePreservedWhenAddingNewInstructionInCategory() throws Exception
371     {
372         assertThat(applyChanges(TEST_POM_WITH_INSTRUCTIONS, changeset.with(NEW_IMPORT_PACKAGE)),
373                    node("//build/plugins/plugin[1]/configuration/instructions/Import-Package",
374                         nodeText(delimitedList(",",
375                                                Matchers.<String>hasItems(equalTo("com.atlassian.plugin.*;version=\"${atlassian.plugins.version}\""),
376                                                    any(String.class), any(String.class), any(String.class))))));
377     }
378 
379     @Test
380     public void bundleInstructionIsNotInsertedIfPackageIsAlreadyPresentInCategory() throws Exception
381     {
382         assertThat(applyChanges(TEST_POM_WITH_INSTRUCTIONS, changeset.with(DUPLICATE_IMPORT_PACKAGE)),
383                    node("//build/plugins/plugin[1]/configuration/instructions/Import-Package",
384                         nodeText(delimitedList(",",
385                                                Matchers.<String>iterableWithSize(3)))));
386     }
387 
388     @SuppressWarnings("unchecked")
389     @Test
390     public void bundleInstructionDoesNotOverwriteInstructionForSamePackage() throws Exception
391     {
392         assertThat(applyChanges(TEST_POM_WITH_INSTRUCTIONS, changeset.with(DUPLICATE_IMPORT_PACKAGE)),
393                    node("//build/plugins/plugin[1]/configuration/instructions/Import-Package",
394                         nodeText(delimitedList(",",
395                                                Matchers.<String>hasItems(equalTo("com.atlassian.plugins.rest.common*;version=\"1.0.5\""))))));
396     }
397 
398     @Test
399     public void bundleInstructionIsAddedToNewCategoryInExistingInstructions() throws Exception
400     {
401         assertThat(applyChanges(TEST_POM_WITH_INSTRUCTIONS, changeset.with(NEW_PRIVATE_PACKAGE)),
402                    node("//build/plugins/plugin[1]/configuration/instructions/Private-Package", nodeTextEquals("com.atlassian.random")));
403     }
404 
405     @Test
406     public void configElementIsCreatedForBundledArtifact() throws Exception
407     {
408         assertThat(applyChanges(TEST_POM, changeset.with(NEW_BUNDLED_ARTIFACT)),
409                    node("//build/plugins/plugin[1]/configuration", notNullValue()));
410     }
411 
412     @Test
413     public void bundledArtifactHasGroupId() throws Exception
414     {
415         assertThat(applyChanges(TEST_POM, changeset.with(NEW_BUNDLED_ARTIFACT)),
416                    node("//build/plugins/plugin[1]/configuration/bundledArtifacts/bundledArtifact/groupId",
417                         nodeTextEquals(CUSTOM_ARTIFACT.getGroupId().get())));
418     }
419 
420     @Test
421     public void bundledArtifactHasArtifactId() throws Exception
422     {
423         assertThat(applyChanges(TEST_POM, changeset.with(NEW_BUNDLED_ARTIFACT)),
424                    node("//build/plugins/plugin[1]/configuration/bundledArtifacts/bundledArtifact/artifactId",
425                         nodeTextEquals(CUSTOM_ARTIFACT.getArtifactId())));
426     }
427 
428     @Test
429     public void pluginArtifactHasArtifactId() throws Exception
430     {
431         assertThat(applyChanges(TEST_POM, changeset.with(NEW_PLUGIN_ARTIFACT)),
432                    node("//build/plugins/plugin[1]/configuration/pluginArtifacts/pluginArtifact/artifactId",
433                         nodeTextEquals(CUSTOM_ARTIFACT.getArtifactId())));
434     }
435 
436     @Test
437     public void bundledArtifactWithNoVersionHasNoVersion() throws Exception
438     {
439         assertThat(applyChanges(TEST_POM, changeset.with(NEW_BUNDLED_ARTIFACT)),
440                    node("//build/plugins/plugin[1]/configuration/bundledArtifacts/bundledArtifact/version",
441                         nullValue()));
442     }
443     
444     @Test
445     public void bundledArtifactWithVersionHasVersion() throws Exception
446     {
447         assertThat(applyChanges(TEST_POM, changeset.with(NEW_BUNDLED_ARTIFACT_WITH_VERSION)),
448                    node("//build/plugins/plugin[1]/configuration/bundledArtifacts/bundledArtifact/version",
449                         nodeTextEquals("1.0")));
450     }
451 
452     @Test
453     public void bundledArtifactWithVersionPropertyUsesPropertyName() throws Exception
454     {
455         assertThat(applyChanges(TEST_POM, changeset.with(NEW_BUNDLED_ARTIFACT_WITH_VERSION_PROPERTY)),
456                    node("//build/plugins/plugin[1]/configuration/bundledArtifacts/bundledArtifact/version",
457                         nodeTextEquals("${dog.version}")));
458     }
459 
460     @Test
461     public void bundledArtifactWithVersionPropertyAddsPropertyNameAndValueToProperties() throws Exception
462     {
463         assertThat(applyChanges(TEST_POM, changeset.with(NEW_BUNDLED_ARTIFACT_WITH_VERSION_PROPERTY)),
464                    node("//properties/dog.version", nodeTextEquals("1.0")));
465     }
466 
467     @Test
468     public void existingBundledArtifactIsNotAddedAgain() throws Exception
469     {
470         assertThat(applyChanges(TEST_POM_WITH_CONFIG, changeset.with(NEW_BUNDLED_ARTIFACT)),
471                    nodes("//build/plugins/plugin[1]/configuration/bundledArtifacts/bundledArtifact", nodeCount(1)));
472     }
473 
474     @Test
475     public void configElementIsCreatedForAmpsSystemProperty() throws Exception
476     {
477         assertThat(applyChanges(TEST_POM, changeset.with(ampsSystemPropertyVariable("newVariable", "bar"))),
478                    node("//build/plugins/plugin[1]/configuration", notNullValue()));
479     }
480     
481     @Test
482     public void variablesElementIsCreatedForAmpsSystemProperty() throws Exception
483     {
484         assertThat(applyChanges(TEST_POM, changeset.with(ampsSystemPropertyVariable("newVariable", "bar"))),
485                    node("//build/plugins/plugin[1]/configuration/systemPropertyVariables", notNullValue()));
486     }
487     
488     @Test
489     public void ampsSystemPropertyHasNameAndValue() throws Exception
490     {
491         assertThat(applyChanges(TEST_POM, changeset.with(ampsSystemPropertyVariable("newVariable", "bar"))),
492                    node("//build/plugins/plugin[1]/configuration/systemPropertyVariables/newVariable", nodeTextEquals("bar")));
493     }
494 
495     @Test
496     public void ampsSystemPropertyIsAddedToList() throws Exception
497     {
498         assertThat(applyChanges(TEST_POM_WITH_CONFIG, changeset.with(ampsSystemPropertyVariable("newVariable", "bar"))),
499                    node("//build/plugins/plugin[1]/configuration/systemPropertyVariables/newVariable", nodeTextEquals("bar")));
500     }
501     
502     @Test
503     public void ampsSystemPropertyDoesNotOverwriteVariableWithDifferentName() throws Exception
504     {
505         assertThat(applyChanges(TEST_POM_WITH_CONFIG, changeset.with(ampsSystemPropertyVariable("newVariable", "bar"))),
506                    node("//build/plugins/plugin[1]/configuration/systemPropertyVariables/existingVariable", nodeTextEquals("foo")));
507     }
508     
509     @Test
510     public void ampsSystemPropertyDoesNotOverwriteVariableWithSameName() throws Exception
511     {
512         assertThat(applyChanges(TEST_POM_WITH_CONFIG, changeset.with(ampsSystemPropertyVariable("existingVariable", "bar"))),
513                    node("//build/plugins/plugin[1]/configuration/systemPropertyVariables/existingVariable", nodeTextEquals("foo")));
514     }
515     
516     protected XmlWrapper applyChanges(String pomTemplateName, PluginProjectChangeset changes) throws Exception
517     {
518         InputStream is = getClass().getClassLoader().getResourceAsStream(pomTemplateName);
519         FileUtils.copyInputStreamToFile(is, pom);
520         closeQuietly(is);
521         
522         Reader reader = new FileReader(pom);
523         try
524         {
525             MavenXpp3Reader xpp3Reader = new MavenXpp3Reader();
526             Model model = xpp3Reader.read(reader);
527             rewriter = new MavenProjectRewriter(model, pom);
528         }
529         finally
530         {
531             closeQuietly(reader);
532         }
533 
534         rewriter.applyChanges(changes);
535         
536         return XmlMatchers.xml(FileUtils.readFileToString(pom), "project");
537     }
538     
539 
540     public static Matcher<String> delimitedList(final String delimiter, final Matcher<Iterable<String>> listMatcher)
541     {
542         return new TypeSafeDiagnosingMatcher<String>()
543         {
544             protected boolean matchesSafely(String s, Description mismatchDescription)
545             {
546                 String[] parts = s.split(delimiter);
547                 List<String> trimmed = new ArrayList<String>(parts.length);
548                 for (String p : parts)
549                 {
550                     trimmed.add(p.trim());
551                 }
552                 if (!listMatcher.matches(trimmed))
553                 {
554                     listMatcher.describeMismatch(trimmed, mismatchDescription);
555                     return false;
556                 }
557                 return true;
558             }
559 
560             public void describeTo(Description description)
561             {
562                 description.appendText("list delimited by '" + delimiter + "' ");
563                 listMatcher.describeTo(description);
564             }
565         };
566     }
567 }