View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.model.validation;
20  
21  import java.io.InputStream;
22  import java.util.List;
23  import java.util.Properties;
24  import java.util.function.UnaryOperator;
25  
26  import org.apache.maven.model.Model;
27  import org.apache.maven.model.building.DefaultModelBuildingRequest;
28  import org.apache.maven.model.building.ModelBuildingRequest;
29  import org.apache.maven.model.building.SimpleProblemCollector;
30  import org.apache.maven.model.interpolation.DefaultModelVersionProcessor;
31  import org.apache.maven.model.v4.MavenStaxReader;
32  import org.junit.jupiter.api.AfterEach;
33  import org.junit.jupiter.api.BeforeEach;
34  import org.junit.jupiter.api.Test;
35  
36  import static org.junit.jupiter.api.Assertions.assertEquals;
37  import static org.junit.jupiter.api.Assertions.assertNotNull;
38  import static org.junit.jupiter.api.Assertions.assertTrue;
39  
40  /**
41   */
42  class DefaultModelValidatorTest {
43  
44      private ModelValidator validator;
45  
46      private Model read(String pom) throws Exception {
47          String resource = "/poms/validation/" + pom;
48          try (InputStream is = getClass().getResourceAsStream(resource)) {
49              assertNotNull(is, "missing resource: " + resource);
50              return new Model(new MavenStaxReader().read(is));
51          }
52      }
53  
54      private SimpleProblemCollector validate(String pom) throws Exception {
55          return validateEffective(pom, UnaryOperator.identity());
56      }
57  
58      private SimpleProblemCollector validateRaw(String pom) throws Exception {
59          return validateRaw(pom, UnaryOperator.identity());
60      }
61  
62      private SimpleProblemCollector validateEffective(String pom, int level) throws Exception {
63          return validateEffective(pom, mbr -> mbr.setValidationLevel(level));
64      }
65  
66      private SimpleProblemCollector validateEffective(String pom, UnaryOperator<ModelBuildingRequest> requestConfigurer)
67              throws Exception {
68          Model model = read(pom);
69  
70          SimpleProblemCollector problems = new SimpleProblemCollector(model);
71  
72          validator.validateEffectiveModel(model, requestConfigurer.apply(new DefaultModelBuildingRequest()), problems);
73  
74          return problems;
75      }
76  
77      private SimpleProblemCollector validateRaw(String pom, int level) throws Exception {
78          return validateRaw(pom, mbr -> mbr.setValidationLevel(level));
79      }
80  
81      private SimpleProblemCollector validateRaw(String pom, UnaryOperator<ModelBuildingRequest> requestConfigurer)
82              throws Exception {
83          Model model = read(pom);
84  
85          SimpleProblemCollector problems = new SimpleProblemCollector(model);
86  
87          ModelBuildingRequest request = requestConfigurer.apply(new DefaultModelBuildingRequest());
88  
89          validator.validateFileModel(model, request, problems);
90  
91          validator.validateRawModel(model, request, problems);
92  
93          return problems;
94      }
95  
96      private void assertContains(String msg, String substring) {
97          assertTrue(msg.contains(substring), "\"" + substring + "\" was not found in: " + msg);
98      }
99  
100     @BeforeEach
101     void setUp() throws Exception {
102         validator = new DefaultModelValidator(new DefaultModelVersionProcessor());
103     }
104 
105     @AfterEach
106     void tearDown() throws Exception {
107         this.validator = null;
108     }
109 
110     private void assertViolations(SimpleProblemCollector result, int fatals, int errors, int warnings) {
111         assertEquals(fatals, result.getFatals().size(), String.valueOf(result.getFatals()));
112         assertEquals(errors, result.getErrors().size(), String.valueOf(result.getErrors()));
113         assertEquals(warnings, result.getWarnings().size(), String.valueOf(result.getWarnings()));
114     }
115 
116     @Test
117     void testMissingModelVersion() throws Exception {
118         SimpleProblemCollector result = validate("missing-modelVersion-pom.xml");
119 
120         assertViolations(result, 0, 1, 0);
121 
122         assertEquals("'modelVersion' is missing.", result.getErrors().get(0));
123     }
124 
125     @Test
126     void testBadModelVersion() throws Exception {
127         SimpleProblemCollector result =
128                 validateRaw("bad-modelVersion.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
129 
130         assertViolations(result, 1, 0, 0);
131 
132         assertTrue(result.getFatals().get(0).contains("modelVersion"));
133     }
134 
135     @Test
136     void testModelVersionMessage() throws Exception {
137         SimpleProblemCollector result =
138                 validateRaw("modelVersion-4_0.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
139 
140         assertViolations(result, 0, 1, 0);
141 
142         assertTrue(result.getErrors().get(0).contains("'modelVersion' must be one of"));
143     }
144 
145     @Test
146     void testMissingArtifactId() throws Exception {
147         SimpleProblemCollector result = validate("missing-artifactId-pom.xml");
148 
149         assertViolations(result, 0, 1, 0);
150 
151         assertEquals("'artifactId' is missing.", result.getErrors().get(0));
152     }
153 
154     @Test
155     void testMissingGroupId() throws Exception {
156         SimpleProblemCollector result = validate("missing-groupId-pom.xml");
157 
158         assertViolations(result, 0, 1, 0);
159 
160         assertEquals("'groupId' is missing.", result.getErrors().get(0));
161     }
162 
163     @Test
164     void testInvalidCoordinateIds() throws Exception {
165         SimpleProblemCollector result = validate("invalid-coordinate-ids-pom.xml");
166 
167         assertViolations(result, 0, 2, 0);
168 
169         assertEquals(
170                 "'groupId' with value 'o/a/m' does not match a valid coordinate id pattern.",
171                 result.getErrors().get(0));
172 
173         assertEquals(
174                 "'artifactId' with value 'm$-do$' does not match a valid coordinate id pattern.",
175                 result.getErrors().get(1));
176     }
177 
178     @Test
179     void testMissingType() throws Exception {
180         SimpleProblemCollector result = validate("missing-type-pom.xml");
181 
182         assertViolations(result, 0, 1, 0);
183 
184         assertEquals("'packaging' is missing.", result.getErrors().get(0));
185     }
186 
187     @Test
188     void testMissingVersion() throws Exception {
189         SimpleProblemCollector result = validate("missing-version-pom.xml");
190 
191         assertViolations(result, 0, 1, 0);
192 
193         assertEquals("'version' is missing.", result.getErrors().get(0));
194     }
195 
196     @Test
197     void testInvalidAggregatorPackaging() throws Exception {
198         SimpleProblemCollector result = validate("invalid-aggregator-packaging-pom.xml");
199 
200         assertViolations(result, 0, 1, 0);
201 
202         assertTrue(result.getErrors().get(0).contains("Aggregator projects require 'pom' as packaging."));
203     }
204 
205     @Test
206     void testMissingDependencyArtifactId() throws Exception {
207         SimpleProblemCollector result = validate("missing-dependency-artifactId-pom.xml");
208 
209         assertViolations(result, 0, 1, 0);
210 
211         assertTrue(result.getErrors()
212                 .get(0)
213                 .contains("'dependencies.dependency.artifactId' for groupId:null:jar is missing"));
214     }
215 
216     @Test
217     void testMissingDependencyGroupId() throws Exception {
218         SimpleProblemCollector result = validate("missing-dependency-groupId-pom.xml");
219 
220         assertViolations(result, 0, 1, 0);
221 
222         assertTrue(result.getErrors()
223                 .get(0)
224                 .contains("'dependencies.dependency.groupId' for null:artifactId:jar is missing"));
225     }
226 
227     @Test
228     void testMissingDependencyVersion() throws Exception {
229         SimpleProblemCollector result = validate("missing-dependency-version-pom.xml");
230 
231         assertViolations(result, 0, 1, 0);
232 
233         assertTrue(result.getErrors()
234                 .get(0)
235                 .contains("'dependencies.dependency.version' for groupId:artifactId:jar is missing"));
236     }
237 
238     @Test
239     void testMissingDependencyManagementArtifactId() throws Exception {
240         SimpleProblemCollector result = validate("missing-dependency-mgmt-artifactId-pom.xml");
241 
242         assertViolations(result, 0, 1, 0);
243 
244         assertTrue(result.getErrors()
245                 .get(0)
246                 .contains("'dependencyManagement.dependencies.dependency.artifactId' for groupId:null:jar is missing"));
247     }
248 
249     @Test
250     void testMissingDependencyManagementGroupId() throws Exception {
251         SimpleProblemCollector result = validate("missing-dependency-mgmt-groupId-pom.xml");
252 
253         assertViolations(result, 0, 1, 0);
254 
255         assertTrue(result.getErrors()
256                 .get(0)
257                 .contains("'dependencyManagement.dependencies.dependency.groupId' for null:artifactId:jar is missing"));
258     }
259 
260     @Test
261     void testMissingAll() throws Exception {
262         SimpleProblemCollector result = validate("missing-1-pom.xml");
263 
264         assertViolations(result, 0, 4, 0);
265 
266         List<String> messages = result.getErrors();
267 
268         assertTrue(messages.contains("'modelVersion' is missing."));
269         assertTrue(messages.contains("'groupId' is missing."));
270         assertTrue(messages.contains("'artifactId' is missing."));
271         assertTrue(messages.contains("'version' is missing."));
272         // type is inherited from the super pom
273     }
274 
275     @Test
276     void testMissingPluginArtifactId() throws Exception {
277         SimpleProblemCollector result = validate("missing-plugin-artifactId-pom.xml");
278 
279         assertViolations(result, 0, 1, 0);
280 
281         assertEquals(
282                 "'build.plugins.plugin.artifactId' is missing.",
283                 result.getErrors().get(0));
284     }
285 
286     @Test
287     void testEmptyPluginVersion() throws Exception {
288         SimpleProblemCollector result = validate("empty-plugin-version.xml");
289 
290         assertViolations(result, 0, 1, 0);
291 
292         assertEquals(
293                 "'build.plugins.plugin.version' for org.apache.maven.plugins:maven-it-plugin"
294                         + " must be a valid version but is ''.",
295                 result.getErrors().get(0));
296     }
297 
298     @Test
299     void testMissingRepositoryId() throws Exception {
300         SimpleProblemCollector result =
301                 validateRaw("missing-repository-id-pom.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
302 
303         assertViolations(result, 0, 4, 0);
304 
305         assertEquals(
306                 "'repositories.repository.id' is missing.", result.getErrors().get(0));
307 
308         assertEquals(
309                 "'repositories.repository.[null].url' is missing.",
310                 result.getErrors().get(1));
311 
312         assertEquals(
313                 "'pluginRepositories.pluginRepository.id' is missing.",
314                 result.getErrors().get(2));
315 
316         assertEquals(
317                 "'pluginRepositories.pluginRepository.[null].url' is missing.",
318                 result.getErrors().get(3));
319     }
320 
321     @Test
322     void testMissingResourceDirectory() throws Exception {
323         SimpleProblemCollector result = validate("missing-resource-directory-pom.xml");
324 
325         assertViolations(result, 0, 2, 0);
326 
327         assertEquals(
328                 "'build.resources.resource.directory' is missing.",
329                 result.getErrors().get(0));
330 
331         assertEquals(
332                 "'build.testResources.testResource.directory' is missing.",
333                 result.getErrors().get(1));
334     }
335 
336     @Test
337     void testBadPluginDependencyScope() throws Exception {
338         SimpleProblemCollector result = validate("bad-plugin-dependency-scope.xml");
339 
340         assertViolations(result, 0, 3, 0);
341 
342         assertTrue(result.getErrors().get(0).contains("test:d"));
343 
344         assertTrue(result.getErrors().get(1).contains("test:e"));
345 
346         assertTrue(result.getErrors().get(2).contains("test:f"));
347     }
348 
349     @Test
350     void testBadDependencyScope() throws Exception {
351         SimpleProblemCollector result = validate("bad-dependency-scope.xml");
352 
353         assertViolations(result, 0, 0, 2);
354 
355         assertTrue(result.getWarnings().get(0).contains("test:f"));
356 
357         assertTrue(result.getWarnings().get(1).contains("test:g"));
358     }
359 
360     @Test
361     void testBadDependencyManagementScope() throws Exception {
362         SimpleProblemCollector result = validate("bad-dependency-management-scope.xml");
363 
364         assertViolations(result, 0, 0, 1);
365 
366         assertContains(result.getWarnings().get(0), "test:g");
367     }
368 
369     @Test
370     void testBadDependencyVersion() throws Exception {
371         SimpleProblemCollector result = validate("bad-dependency-version.xml");
372 
373         assertViolations(result, 0, 2, 0);
374 
375         assertContains(
376                 result.getErrors().get(0), "'dependencies.dependency.version' for test:b:jar must be a valid version");
377         assertContains(
378                 result.getErrors().get(1),
379                 "'dependencies.dependency.version' for test:c:jar must not contain any of these characters");
380     }
381 
382     @Test
383     void testDuplicateModule() throws Exception {
384         SimpleProblemCollector result = validateRaw("duplicate-module.xml");
385 
386         assertViolations(result, 0, 1, 0);
387 
388         assertTrue(result.getErrors().get(0).contains("child"));
389     }
390 
391     @Test
392     void testInvalidProfileId() throws Exception {
393         SimpleProblemCollector result = validateRaw("invalid-profile-ids.xml");
394 
395         assertViolations(result, 0, 4, 0);
396 
397         assertTrue(result.getErrors().get(0).contains("+invalid-id"));
398         assertTrue(result.getErrors().get(1).contains("-invalid-id"));
399         assertTrue(result.getErrors().get(2).contains("!invalid-id"));
400         assertTrue(result.getErrors().get(3).contains("?invalid-id"));
401     }
402 
403     public void testDuplicateProfileId() throws Exception {
404         SimpleProblemCollector result = validateRaw("duplicate-profile-id.xml");
405 
406         assertViolations(result, 0, 1, 0);
407 
408         assertTrue(result.getErrors().get(0).contains("non-unique-id"));
409     }
410 
411     @Test
412     void testBadPluginVersion() throws Exception {
413         SimpleProblemCollector result = validate("bad-plugin-version.xml");
414 
415         assertViolations(result, 0, 4, 0);
416 
417         assertContains(
418                 result.getErrors().get(0), "'build.plugins.plugin.version' for test:mip must be a valid version");
419         assertContains(
420                 result.getErrors().get(1), "'build.plugins.plugin.version' for test:rmv must be a valid version");
421         assertContains(
422                 result.getErrors().get(2), "'build.plugins.plugin.version' for test:lmv must be a valid version");
423         assertContains(
424                 result.getErrors().get(3),
425                 "'build.plugins.plugin.version' for test:ifsc must not contain any of these characters");
426     }
427 
428     @Test
429     void testDistributionManagementStatus() throws Exception {
430         SimpleProblemCollector result = validate("distribution-management-status.xml");
431 
432         assertViolations(result, 0, 1, 0);
433 
434         assertTrue(result.getErrors().get(0).contains("distributionManagement.status"));
435     }
436 
437     @Test
438     void testIncompleteParent() throws Exception {
439         SimpleProblemCollector result = validateRaw("incomplete-parent.xml");
440 
441         assertViolations(result, 3, 0, 0);
442         assertTrue(result.getFatals().get(0).contains("parent.groupId"));
443         assertTrue(result.getFatals().get(1).contains("parent.artifactId"));
444         assertTrue(result.getFatals().get(2).contains("parent.version"));
445     }
446 
447     @Test
448     void testHardCodedSystemPath() throws Exception {
449         SimpleProblemCollector result = validateRaw("hard-coded-system-path.xml");
450 
451         assertViolations(result, 0, 0, 3);
452 
453         assertContains(
454                 result.getWarnings().get(0),
455                 "'dependencies.dependency.scope' for test:a:jar declares usage of deprecated 'system' scope");
456         assertContains(
457                 result.getWarnings().get(1),
458                 "'dependencies.dependency.systemPath' for test:a:jar should use a variable instead of a hard-coded path");
459         assertContains(
460                 result.getWarnings().get(2),
461                 "'dependencies.dependency.scope' for test:b:jar declares usage of deprecated 'system' scope");
462     }
463 
464     @Test
465     void testEmptyModule() throws Exception {
466         SimpleProblemCollector result = validate("empty-module.xml");
467 
468         assertViolations(result, 0, 1, 0);
469 
470         assertTrue(result.getErrors().get(0).contains("'modules.module[0]' has been specified without a path"));
471     }
472 
473     @Test
474     void testDuplicatePlugin() throws Exception {
475         SimpleProblemCollector result = validateRaw("duplicate-plugin.xml");
476 
477         assertViolations(result, 0, 4, 0);
478 
479         assertTrue(result.getErrors().get(0).contains("duplicate declaration of plugin test:duplicate"));
480         assertTrue(result.getErrors().get(1).contains("duplicate declaration of plugin test:managed-duplicate"));
481         assertTrue(result.getErrors().get(2).contains("duplicate declaration of plugin profile:duplicate"));
482         assertTrue(result.getErrors().get(3).contains("duplicate declaration of plugin profile:managed-duplicate"));
483     }
484 
485     @Test
486     void testDuplicatePluginExecution() throws Exception {
487         SimpleProblemCollector result = validateRaw("duplicate-plugin-execution.xml");
488 
489         assertViolations(result, 0, 4, 0);
490 
491         assertContains(result.getErrors().get(0), "duplicate execution with id a");
492         assertContains(result.getErrors().get(1), "duplicate execution with id default");
493         assertContains(result.getErrors().get(2), "duplicate execution with id c");
494         assertContains(result.getErrors().get(3), "duplicate execution with id b");
495     }
496 
497     @Test
498     void testReservedRepositoryId() throws Exception {
499         SimpleProblemCollector result = validate("reserved-repository-id.xml");
500 
501         assertViolations(result, 0, 4, 0);
502 
503         assertContains(result.getErrors().get(0), "'repositories.repository.id'" + " must not be 'local'");
504         assertContains(result.getErrors().get(1), "'pluginRepositories.pluginRepository.id' must not be 'local'");
505         assertContains(result.getErrors().get(2), "'distributionManagement.repository.id' must not be 'local'");
506         assertContains(result.getErrors().get(3), "'distributionManagement.snapshotRepository.id' must not be 'local'");
507     }
508 
509     @Test
510     void testMissingPluginDependencyGroupId() throws Exception {
511         SimpleProblemCollector result = validate("missing-plugin-dependency-groupId.xml");
512 
513         assertViolations(result, 0, 1, 0);
514 
515         assertTrue(result.getErrors().get(0).contains(":a:"));
516     }
517 
518     @Test
519     void testMissingPluginDependencyArtifactId() throws Exception {
520         SimpleProblemCollector result = validate("missing-plugin-dependency-artifactId.xml");
521 
522         assertViolations(result, 0, 1, 0);
523 
524         assertTrue(result.getErrors().get(0).contains("test:"));
525     }
526 
527     @Test
528     void testMissingPluginDependencyVersion() throws Exception {
529         SimpleProblemCollector result = validate("missing-plugin-dependency-version.xml");
530 
531         assertViolations(result, 0, 1, 0);
532 
533         assertTrue(result.getErrors().get(0).contains("test:a"));
534     }
535 
536     @Test
537     void testBadPluginDependencyVersion() throws Exception {
538         SimpleProblemCollector result = validate("bad-plugin-dependency-version.xml");
539 
540         assertViolations(result, 0, 1, 0);
541 
542         assertTrue(result.getErrors().get(0).contains("test:b"));
543     }
544 
545     @Test
546     void testBadVersion() throws Exception {
547         SimpleProblemCollector result = validate("bad-version.xml");
548 
549         assertViolations(result, 0, 1, 0);
550 
551         assertContains(result.getErrors().get(0), "'version' must not contain any of these characters");
552     }
553 
554     @Test
555     void testBadSnapshotVersion() throws Exception {
556         SimpleProblemCollector result = validate("bad-snapshot-version.xml");
557 
558         assertViolations(result, 0, 1, 0);
559 
560         assertContains(result.getErrors().get(0), "'version' uses an unsupported snapshot version format");
561     }
562 
563     @Test
564     void testBadRepositoryId() throws Exception {
565         SimpleProblemCollector result = validate("bad-repository-id.xml");
566 
567         assertViolations(result, 0, 4, 0);
568 
569         assertContains(
570                 result.getErrors().get(0), "'repositories.repository.id' must not contain any of these characters");
571         assertContains(
572                 result.getErrors().get(1),
573                 "'pluginRepositories.pluginRepository.id' must not contain any of these characters");
574         assertContains(
575                 result.getErrors().get(2),
576                 "'distributionManagement.repository.id' must not contain any of these characters");
577         assertContains(
578                 result.getErrors().get(3),
579                 "'distributionManagement.snapshotRepository.id' must not contain any of these characters");
580     }
581 
582     @Test
583     void testBadDependencyExclusionId() throws Exception {
584         SimpleProblemCollector result =
585                 validateEffective("bad-dependency-exclusion-id.xml", ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0);
586 
587         assertViolations(result, 0, 0, 2);
588 
589         assertContains(
590                 result.getWarnings().get(0), "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar");
591         assertContains(
592                 result.getWarnings().get(1),
593                 "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar");
594 
595         // MNG-3832: Aether (part of M3+) supports wildcard expressions for exclusions
596 
597         SimpleProblemCollector result_30 = validate("bad-dependency-exclusion-id.xml");
598 
599         assertViolations(result_30, 0, 0, 0);
600     }
601 
602     @Test
603     void testMissingDependencyExclusionId() throws Exception {
604         SimpleProblemCollector result = validate("missing-dependency-exclusion-id.xml");
605 
606         assertViolations(result, 0, 0, 2);
607 
608         assertContains(
609                 result.getWarnings().get(0),
610                 "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar is missing");
611         assertContains(
612                 result.getWarnings().get(1),
613                 "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar is missing");
614     }
615 
616     @Test
617     void testBadImportScopeType() throws Exception {
618         SimpleProblemCollector result = validateRaw("bad-import-scope-type.xml");
619 
620         assertViolations(result, 0, 0, 1);
621 
622         assertContains(
623                 result.getWarnings().get(0),
624                 "'dependencyManagement.dependencies.dependency.type' for test:a:jar must be 'pom'");
625     }
626 
627     @Test
628     void testBadImportScopeClassifier() throws Exception {
629         SimpleProblemCollector result = validateRaw("bad-import-scope-classifier.xml");
630 
631         assertViolations(result, 0, 1, 0);
632 
633         assertContains(
634                 result.getErrors().get(0),
635                 "'dependencyManagement.dependencies.dependency.classifier' for test:a:pom:cls must be empty");
636     }
637 
638     @Test
639     void testSystemPathRefersToProjectBasedir() throws Exception {
640         SimpleProblemCollector result = validateRaw("basedir-system-path.xml");
641 
642         assertViolations(result, 0, 0, 4);
643 
644         assertContains(
645                 result.getWarnings().get(0),
646                 "'dependencies.dependency.scope' for test:a:jar declares usage of deprecated 'system' scope");
647         assertContains(
648                 result.getWarnings().get(1),
649                 "'dependencies.dependency.systemPath' for test:a:jar should not point at files within the project directory");
650         assertContains(
651                 result.getWarnings().get(2),
652                 "'dependencies.dependency.scope' for test:b:jar declares usage of deprecated 'system' scope");
653         assertContains(
654                 result.getWarnings().get(3),
655                 "'dependencies.dependency.systemPath' for test:b:jar should not point at files within the project directory");
656     }
657 
658     @Test
659     void testInvalidVersionInPluginManagement() throws Exception {
660         SimpleProblemCollector result = validateRaw("raw-model/missing-plugin-version-pluginManagement.xml");
661 
662         assertViolations(result, 1, 0, 0);
663 
664         assertEquals(
665                 "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' version of a plugin must be defined. ",
666                 result.getFatals().get(0));
667     }
668 
669     @Test
670     void testInvalidGroupIdInPluginManagement() throws Exception {
671         SimpleProblemCollector result = validateRaw("raw-model/missing-groupId-pluginManagement.xml");
672 
673         assertViolations(result, 1, 0, 0);
674 
675         assertEquals(
676                 "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' groupId of a plugin must be defined. ",
677                 result.getFatals().get(0));
678     }
679 
680     @Test
681     void testInvalidArtifactIdInPluginManagement() throws Exception {
682         SimpleProblemCollector result = validateRaw("raw-model/missing-artifactId-pluginManagement.xml");
683 
684         assertViolations(result, 1, 0, 0);
685 
686         assertEquals(
687                 "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' artifactId of a plugin must be defined. ",
688                 result.getFatals().get(0));
689     }
690 
691     @Test
692     void testInvalidGroupAndArtifactIdInPluginManagement() throws Exception {
693         SimpleProblemCollector result = validateRaw("raw-model/missing-ga-pluginManagement.xml");
694 
695         assertViolations(result, 2, 0, 0);
696 
697         assertEquals(
698                 "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' groupId of a plugin must be defined. ",
699                 result.getFatals().get(0));
700 
701         assertEquals(
702                 "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' artifactId of a plugin must be defined. ",
703                 result.getFatals().get(1));
704     }
705 
706     @Test
707     void testMissingReportPluginVersion() throws Exception {
708         SimpleProblemCollector result = validate("missing-report-version-pom.xml");
709 
710         assertViolations(result, 0, 0, 0);
711     }
712 
713     @Test
714     void testDeprecatedDependencyMetaversionsLatestAndRelease() throws Exception {
715         SimpleProblemCollector result = validateRaw("deprecated-dependency-metaversions-latest-and-release.xml");
716 
717         assertViolations(result, 0, 0, 2);
718 
719         assertContains(
720                 result.getWarnings().get(0),
721                 "'dependencies.dependency.version' for test:a:jar is either LATEST or RELEASE (both of them are being deprecated)");
722         assertContains(
723                 result.getWarnings().get(1),
724                 "'dependencies.dependency.version' for test:b:jar is either LATEST or RELEASE (both of them are being deprecated)");
725     }
726 
727     @Test
728     void testSelfReferencingDependencyInRawModel() throws Exception {
729         SimpleProblemCollector result = validateRaw("raw-model/self-referencing.xml");
730 
731         assertViolations(result, 1, 0, 0);
732 
733         assertEquals(
734                 "'dependencies.dependency[com.example.group:testinvalidpom:0.0.1-SNAPSHOT]' for com.example.group:testinvalidpom:0.0.1-SNAPSHOT is referencing itself.",
735                 result.getFatals().get(0));
736     }
737 
738     @Test
739     void testSelfReferencingDependencyWithClassifierInRawModel() throws Exception {
740         SimpleProblemCollector result = validateRaw("raw-model/self-referencing-classifier.xml");
741 
742         assertViolations(result, 0, 0, 0);
743     }
744 
745     @Test
746     void testCiFriendlySha1() throws Exception {
747         SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-sha1.xml");
748         assertViolations(result, 0, 0, 0);
749     }
750 
751     @Test
752     void testCiFriendlyRevision() throws Exception {
753         SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-revision.xml");
754         assertViolations(result, 0, 0, 0);
755     }
756 
757     @Test
758     void testCiFriendlyChangeList() throws Exception {
759         SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-changelist.xml");
760         assertViolations(result, 0, 0, 0);
761     }
762 
763     @Test
764     void testCiFriendlyAllExpressions() throws Exception {
765         SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-all-expressions.xml");
766         assertViolations(result, 0, 0, 0);
767     }
768 
769     @Test
770     void testCiFriendlyBad() throws Exception {
771         SimpleProblemCollector result = validateRaw("raw-model/bad-ci-friendly.xml");
772         assertViolations(result, 0, 0, 1);
773         assertEquals(
774                 "'version' contains an expression but should be a constant.",
775                 result.getWarnings().get(0));
776     }
777 
778     @Test
779     void testCiFriendlyBadSha1Plus() throws Exception {
780         SimpleProblemCollector result = validateRaw("raw-model/bad-ci-friendly-sha1plus.xml");
781         assertViolations(result, 0, 0, 1);
782         assertEquals(
783                 "'version' contains an expression but should be a constant.",
784                 result.getWarnings().get(0));
785     }
786 
787     @Test
788     void testCiFriendlyBadSha1Plus2() throws Exception {
789         SimpleProblemCollector result = validateRaw("raw-model/bad-ci-friendly-sha1plus2.xml");
790         assertViolations(result, 0, 0, 1);
791         assertEquals(
792                 "'version' contains an expression but should be a constant.",
793                 result.getWarnings().get(0));
794     }
795 
796     @Test
797     void testParentVersionLATEST() throws Exception {
798         SimpleProblemCollector result = validateRaw("raw-model/bad-parent-version-latest.xml");
799         assertViolations(result, 0, 0, 1);
800         assertEquals(
801                 "'parent.version' is either LATEST or RELEASE (both of them are being deprecated)",
802                 result.getWarnings().get(0));
803     }
804 
805     @Test
806     void testParentVersionRELEASE() throws Exception {
807         SimpleProblemCollector result = validateRaw("raw-model/bad-parent-version-release.xml");
808         assertViolations(result, 0, 0, 1);
809         assertEquals(
810                 "'parent.version' is either LATEST or RELEASE (both of them are being deprecated)",
811                 result.getWarnings().get(0));
812     }
813 
814     @Test
815     void repositoryWithExpression() throws Exception {
816         SimpleProblemCollector result = validateRaw("raw-model/repository-with-expression.xml");
817         assertViolations(result, 0, 1, 0);
818         assertEquals(
819                 "'repositories.repository.[repo].url' contains an expression but should be a constant.",
820                 result.getErrors().get(0));
821     }
822 
823     @Test
824     void repositoryWithBasedirExpression() throws Exception {
825         SimpleProblemCollector result = validateRaw("raw-model/repository-with-basedir-expression.xml");
826         assertViolations(result, 0, 0, 0);
827     }
828 
829     @Test
830     void profileActivationWithAllowedExpression() throws Exception {
831         SimpleProblemCollector result = validateRaw(
832                 "raw-model/profile-activation-file-with-allowed-expressions.xml",
833                 mbr -> mbr.setUserProperties(new Properties() {
834                     private static final long serialVersionUID = 1L;
835 
836                     {
837                         setProperty("foo", "foo");
838                         setProperty("bar", "foo");
839                     }
840                 }));
841         assertViolations(result, 0, 0, 0);
842     }
843 
844     @Test
845     void profileActivationFileWithProjectExpression() throws Exception {
846         SimpleProblemCollector result = validateRaw("raw-model/profile-activation-file-with-project-expressions.xml");
847         assertViolations(result, 0, 0, 2);
848 
849         assertEquals(
850                 "'profiles.profile[exists-project-version].activation.file.exists' "
851                         + "Failed to interpolate profile activation property ${project.version}/test.txt: "
852                         + "${project.version} expressions are not supported during profile activation.",
853                 result.getWarnings().get(0));
854 
855         assertEquals(
856                 "'profiles.profile[missing-project-version].activation.file.missing' "
857                         + "Failed to interpolate profile activation property ${project.version}/test.txt: "
858                         + "${project.version} expressions are not supported during profile activation.",
859                 result.getWarnings().get(1));
860     }
861 
862     @Test
863     void profileActivationPropertyWithProjectExpression() throws Exception {
864         SimpleProblemCollector result =
865                 validateRaw("raw-model/profile-activation-property-with-project-expressions.xml");
866         assertViolations(result, 0, 0, 2);
867 
868         assertEquals(
869                 "'profiles.profile[property-name-project-version].activation.property.name' "
870                         + "Failed to interpolate profile activation property ${project.version}: "
871                         + "${project.version} expressions are not supported during profile activation.",
872                 result.getWarnings().get(0));
873 
874         assertEquals(
875                 "'profiles.profile[property-value-project-version].activation.property.value' "
876                         + "Failed to interpolate profile activation property ${project.version}: "
877                         + "${project.version} expressions are not supported during profile activation.",
878                 result.getWarnings().get(1));
879     }
880 }