1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.plugin.surefire;
20  
21  import javax.annotation.Nonnull;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.math.BigDecimal;
26  import java.nio.file.Files;
27  import java.text.ChoiceFormat;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.Enumeration;
33  import java.util.HashMap;
34  import java.util.HashSet;
35  import java.util.LinkedHashSet;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Map.Entry;
39  import java.util.Optional;
40  import java.util.Properties;
41  import java.util.Set;
42  import java.util.SortedSet;
43  import java.util.TreeSet;
44  import java.util.concurrent.ConcurrentHashMap;
45  import java.util.function.Function;
46  import java.util.stream.Collectors;
47  import java.util.zip.ZipFile;
48  
49  import org.apache.maven.artifact.Artifact;
50  import org.apache.maven.artifact.DefaultArtifact;
51  import org.apache.maven.artifact.handler.ArtifactHandler;
52  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
53  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
54  import org.apache.maven.artifact.versioning.ArtifactVersion;
55  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
56  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
57  import org.apache.maven.artifact.versioning.VersionRange;
58  import org.apache.maven.execution.MavenSession;
59  import org.apache.maven.model.Dependency;
60  import org.apache.maven.model.Plugin;
61  import org.apache.maven.plugin.AbstractMojo;
62  import org.apache.maven.plugin.MojoExecutionException;
63  import org.apache.maven.plugin.MojoFailureException;
64  import org.apache.maven.plugin.descriptor.PluginDescriptor;
65  import org.apache.maven.plugin.surefire.booterclient.ChecksumCalculator;
66  import org.apache.maven.plugin.surefire.booterclient.ClasspathForkConfiguration;
67  import org.apache.maven.plugin.surefire.booterclient.ForkConfiguration;
68  import org.apache.maven.plugin.surefire.booterclient.ForkStarter;
69  import org.apache.maven.plugin.surefire.booterclient.JarManifestForkConfiguration;
70  import org.apache.maven.plugin.surefire.booterclient.ModularClasspathForkConfiguration;
71  import org.apache.maven.plugin.surefire.booterclient.Platform;
72  import org.apache.maven.plugin.surefire.extensions.LegacyForkNodeFactory;
73  import org.apache.maven.plugin.surefire.extensions.SurefireConsoleOutputReporter;
74  import org.apache.maven.plugin.surefire.extensions.SurefireStatelessReporter;
75  import org.apache.maven.plugin.surefire.extensions.SurefireStatelessTestsetInfoReporter;
76  import org.apache.maven.plugin.surefire.log.PluginConsoleLogger;
77  import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
78  import org.apache.maven.plugin.surefire.util.DependencyScanner;
79  import org.apache.maven.plugin.surefire.util.DirectoryScanner;
80  import org.apache.maven.plugins.annotations.Component;
81  import org.apache.maven.plugins.annotations.Parameter;
82  import org.apache.maven.project.MavenProject;
83  import org.apache.maven.shared.artifact.filter.PatternIncludesArtifactFilter;
84  import org.apache.maven.surefire.api.booter.ProviderParameterNames;
85  import org.apache.maven.surefire.api.booter.Shutdown;
86  import org.apache.maven.surefire.api.cli.CommandLineOption;
87  import org.apache.maven.surefire.api.report.ReporterConfiguration;
88  import org.apache.maven.surefire.api.report.ReporterFactoryOptions;
89  import org.apache.maven.surefire.api.suite.RunResult;
90  import org.apache.maven.surefire.api.testset.DirectoryScannerParameters;
91  import org.apache.maven.surefire.api.testset.RunOrderParameters;
92  import org.apache.maven.surefire.api.testset.TestArtifactInfo;
93  import org.apache.maven.surefire.api.testset.TestListResolver;
94  import org.apache.maven.surefire.api.testset.TestRequest;
95  import org.apache.maven.surefire.api.testset.TestSetFailedException;
96  import org.apache.maven.surefire.api.util.DefaultScanResult;
97  import org.apache.maven.surefire.api.util.RunOrder;
98  import org.apache.maven.surefire.booter.ClassLoaderConfiguration;
99  import org.apache.maven.surefire.booter.Classpath;
100 import org.apache.maven.surefire.booter.ClasspathConfiguration;
101 import org.apache.maven.surefire.booter.KeyValueSource;
102 import org.apache.maven.surefire.booter.ModularClasspath;
103 import org.apache.maven.surefire.booter.ModularClasspathConfiguration;
104 import org.apache.maven.surefire.booter.ProcessCheckerType;
105 import org.apache.maven.surefire.booter.ProviderConfiguration;
106 import org.apache.maven.surefire.booter.StartupConfiguration;
107 import org.apache.maven.surefire.booter.SurefireBooterForkException;
108 import org.apache.maven.surefire.booter.SurefireExecutionException;
109 import org.apache.maven.surefire.extensions.ForkNodeFactory;
110 import org.apache.maven.surefire.providerapi.ConfigurableProviderInfo;
111 import org.apache.maven.surefire.providerapi.ProviderDetector;
112 import org.apache.maven.surefire.providerapi.ProviderInfo;
113 import org.apache.maven.surefire.providerapi.ProviderRequirements;
114 import org.apache.maven.surefire.shared.utils.io.FileUtils;
115 import org.apache.maven.toolchain.DefaultToolchain;
116 import org.apache.maven.toolchain.Toolchain;
117 import org.apache.maven.toolchain.ToolchainManager;
118 import org.apache.maven.toolchain.java.DefaultJavaToolChain;
119 import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
120 import org.codehaus.plexus.languages.java.jpms.LocationManager;
121 import org.codehaus.plexus.languages.java.jpms.ResolvePathRequest;
122 import org.codehaus.plexus.languages.java.jpms.ResolvePathResult;
123 import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
124 import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
125 import org.slf4j.Logger;
126 import org.slf4j.LoggerFactory;
127 
128 import static java.lang.Integer.parseInt;
129 import static java.util.Arrays.asList;
130 import static java.util.Collections.addAll;
131 import static java.util.Collections.emptyList;
132 import static java.util.Collections.singletonList;
133 import static java.util.Collections.singletonMap;
134 import static org.apache.maven.plugin.surefire.AbstractSurefireMojo.PluginFailureReason.COULD_NOT_RUN_DEFAULT_TESTS;
135 import static org.apache.maven.plugin.surefire.AbstractSurefireMojo.PluginFailureReason.COULD_NOT_RUN_SPECIFIED_TESTS;
136 import static org.apache.maven.plugin.surefire.AbstractSurefireMojo.PluginFailureReason.NONE;
137 import static org.apache.maven.plugin.surefire.SurefireDependencyResolver.isWithinVersionSpec;
138 import static org.apache.maven.plugin.surefire.SurefireHelper.replaceThreadNumberPlaceholders;
139 import static org.apache.maven.plugin.surefire.util.DependencyScanner.filter;
140 import static org.apache.maven.surefire.api.booter.ProviderParameterNames.EXCLUDE_JUNIT5_ENGINES_PROP;
141 import static org.apache.maven.surefire.api.booter.ProviderParameterNames.INCLUDE_JUNIT5_ENGINES_PROP;
142 import static org.apache.maven.surefire.api.suite.RunResult.failure;
143 import static org.apache.maven.surefire.api.suite.RunResult.noTestsRun;
144 import static org.apache.maven.surefire.booter.Classpath.emptyClasspath;
145 import static org.apache.maven.surefire.booter.SystemUtils.endsWithJavaPath;
146 import static org.apache.maven.surefire.booter.SystemUtils.isBuiltInJava9AtLeast;
147 import static org.apache.maven.surefire.booter.SystemUtils.isJava9AtLeast;
148 import static org.apache.maven.surefire.booter.SystemUtils.toJdkHomeFromJvmExec;
149 import static org.apache.maven.surefire.booter.SystemUtils.toJdkVersionFromReleaseFile;
150 import static org.apache.maven.surefire.shared.lang3.JavaVersion.JAVA_RECENT;
151 import static org.apache.maven.surefire.shared.lang3.StringUtils.substringBeforeLast;
152 import static org.apache.maven.surefire.shared.lang3.SystemUtils.IS_OS_WINDOWS;
153 import static org.apache.maven.surefire.shared.utils.StringUtils.capitalizeFirstLetter;
154 import static org.apache.maven.surefire.shared.utils.StringUtils.isEmpty;
155 import static org.apache.maven.surefire.shared.utils.StringUtils.isNotBlank;
156 import static org.apache.maven.surefire.shared.utils.StringUtils.isNotEmpty;
157 import static org.apache.maven.surefire.shared.utils.StringUtils.split;
158 import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.addShutDownHook;
159 import static org.apache.maven.surefire.shared.utils.cli.ShutdownHookUtils.removeShutdownHook;
160 
161 
162 
163 
164 
165 
166 public abstract class AbstractSurefireMojo extends AbstractMojo implements SurefireExecutionParameters {
167     private static final Map<String, String> JAVA_9_MATCHER_OLD_NOTATION = singletonMap("version", "[1.9,)");
168     private static final Map<String, String> JAVA_9_MATCHER = singletonMap("version", "[9,)");
169     private static final Platform PLATFORM = new Platform();
170 
171     private final ClasspathCache classpathCache = new ClasspathCache();
172 
173     @Parameter
174     private SurefireStatelessReporter statelessTestsetReporter;
175 
176     @Parameter
177     private SurefireConsoleOutputReporter consoleOutputReporter;
178 
179     @Parameter
180     private SurefireStatelessTestsetInfoReporter statelessTestsetInfoReporter;
181 
182     
183 
184 
185 
186 
187 
188     @Parameter(defaultValue = "${plugin}", readonly = true, required = true)
189     private PluginDescriptor pluginDescriptor;
190 
191     
192 
193 
194 
195 
196 
197 
198 
199     @Parameter(property = "skipTests", defaultValue = "false")
200     protected boolean skipTests;
201 
202     
203 
204 
205 
206 
207 
208     @Deprecated
209     @Parameter(property = "maven.test.skip.exec")
210     protected boolean skipExec;
211 
212     
213 
214 
215 
216 
217     @Parameter(property = "maven.test.skip", defaultValue = "false")
218     protected boolean skip;
219 
220     
221 
222 
223     @Parameter(defaultValue = "${project}", required = true, readonly = true)
224     private MavenProject project;
225 
226     
227 
228 
229 
230     @Parameter(defaultValue = "${basedir}", readonly = true, required = true)
231     protected File basedir;
232 
233     
234 
235 
236 
237     @Parameter(defaultValue = "${project.build.testOutputDirectory}")
238     protected File testClassesDirectory;
239 
240     
241 
242 
243 
244 
245 
246 
247 
248 
249 
250 
251 
252 
253 
254     @Parameter(property = "maven.test.dependency.excludes")
255     private String[] classpathDependencyExcludes;
256 
257     
258 
259 
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 
270 
271     @Parameter(defaultValue = "")
272     private String classpathDependencyScopeExclude;
273 
274     
275 
276 
277 
278 
279 
280 
281     @Parameter(property = "maven.test.additionalClasspath")
282     private String[] additionalClasspathElements;
283 
284     
285 
286 
287 
288 
289 
290 
291 
292 
293 
294 
295 
296 
297 
298 
299 
300 
301     @Parameter(property = "maven.test.additionalClasspathDependencies")
302     private List<Dependency> additionalClasspathDependencies;
303 
304     
305 
306 
307 
308 
309 
310     @Parameter(defaultValue = "${project.build.testSourceDirectory}")
311     private File testSourceDirectory;
312 
313     
314 
315 
316 
317 
318 
319     @Deprecated
320     @Parameter
321     Properties systemProperties;
322 
323     
324 
325 
326 
327 
328 
329 
330 
331 
332 
333 
334 
335 
336 
337 
338 
339 
340 
341 
342 
343 
344 
345 
346 
347 
348     @Parameter
349     Map<String, String> systemPropertyVariables;
350 
351     
352 
353 
354 
355 
356 
357 
358     @Parameter(defaultValue = "true")
359     boolean promoteUserPropertiesToSystemProperties;
360 
361     
362 
363 
364 
365 
366 
367 
368 
369 
370 
371 
372 
373 
374 
375 
376 
377 
378 
379 
380 
381     @Parameter
382     private Properties properties;
383 
384     
385 
386 
387     @Parameter(property = "plugin.artifactMap", required = true, readonly = true)
388     private Map<String, Artifact> pluginArtifactMap;
389 
390     
391 
392 
393     @Parameter(property = "project.artifactMap", readonly = true, required = true)
394     private Map<String, Artifact> projectArtifactMap;
395 
396     
397 
398 
399 
400 
401 
402     @Parameter(property = "surefire.reportNameSuffix", defaultValue = "")
403     private String reportNameSuffix;
404 
405     
406 
407 
408 
409 
410 
411     @Parameter(property = "maven.test.redirectTestOutputToFile", defaultValue = "false")
412     private boolean redirectTestOutputToFile;
413 
414     
415 
416 
417 
418 
419     @Parameter(property = "failIfNoTests", defaultValue = "false")
420     private boolean failIfNoTests;
421 
422     
423 
424 
425 
426 
427 
428 
429 
430 
431 
432 
433     @Parameter(property = "tempDir", defaultValue = "surefire")
434     private String tempDir;
435 
436     
437 
438 
439 
440 
441 
442 
443     @Parameter(property = "jvm")
444     private String jvm;
445 
446     
447 
448 
449 
450 
451 
452 
453 
454 
455 
456 
457 
458 
459 
460 
461 
462 
463     @Parameter(property = "argLine")
464     private String argLine;
465 
466     
467 
468 
469 
470 
471     @Parameter
472     private Map<String, String> environmentVariables = new HashMap<>();
473 
474     
475 
476 
477 
478 
479     @Parameter(property = "basedir")
480     private File workingDirectory;
481 
482     
483 
484 
485 
486 
487 
488 
489 
490     @Parameter(property = "childDelegation", defaultValue = "false")
491     private boolean childDelegation;
492 
493     
494 
495 
496 
497 
498 
499 
500 
501 
502 
503 
504 
505 
506     @Parameter(property = "groups")
507     private String groups;
508 
509     
510 
511 
512 
513 
514 
515 
516 
517 
518 
519 
520 
521 
522     @Parameter(property = "excludedGroups")
523     private String excludedGroups;
524 
525     
526 
527 
528 
529 
530     @Parameter(property = "junitArtifactName", defaultValue = "junit:junit")
531     private String junitArtifactName;
532 
533     
534 
535 
536 
537 
538     @Parameter(property = "testNGArtifactName", defaultValue = "org.testng:testng")
539     private String testNGArtifactName;
540 
541     
542 
543 
544 
545 
546 
547     @Parameter(property = "threadCount")
548     private int threadCount;
549 
550     
551 
552 
553 
554 
555 
556 
557 
558 
559 
560 
561 
562 
563 
564 
565     @Parameter(property = "forkCount", defaultValue = "1")
566     String forkCount;
567 
568     
569 
570 
571 
572 
573 
574     @Parameter(property = "reuseForks", defaultValue = "true")
575     private boolean reuseForks;
576 
577     
578 
579 
580 
581 
582 
583     @Parameter(property = "perCoreThreadCount", defaultValue = "true")
584     private boolean perCoreThreadCount;
585 
586     
587 
588 
589 
590 
591 
592 
593     @Parameter(property = "useUnlimitedThreads", defaultValue = "false")
594     private boolean useUnlimitedThreads;
595 
596     
597 
598 
599 
600 
601 
602 
603 
604 
605 
606 
607 
608 
609 
610 
611 
612 
613 
614 
615 
616 
617 
618 
619     @Parameter(property = "parallel")
620     private String parallel;
621 
622     
623 
624 
625 
626 
627 
628 
629 
630     @Parameter(property = "parallelOptimized", defaultValue = "true")
631     private boolean parallelOptimized;
632 
633     
634 
635 
636 
637 
638 
639 
640 
641 
642 
643 
644 
645 
646 
647 
648 
649     @Parameter(property = "threadCountSuites", defaultValue = "0")
650     private int threadCountSuites;
651 
652     
653 
654 
655 
656 
657 
658 
659 
660 
661 
662 
663 
664 
665 
666 
667 
668 
669 
670 
671 
672     @Parameter(property = "threadCountClasses", defaultValue = "0")
673     private int threadCountClasses;
674 
675     
676 
677 
678 
679 
680 
681 
682 
683 
684 
685 
686 
687 
688 
689 
690 
691 
692 
693 
694     @Parameter(property = "threadCountMethods", defaultValue = "0")
695     private int threadCountMethods;
696 
697     
698 
699 
700 
701 
702     @Parameter(property = "trimStackTrace", defaultValue = "false")
703     private boolean trimStackTrace;
704 
705     
706 
707 
708 
709 
710 
711     @Deprecated 
712     @Parameter(property = "disableXmlReport")
713     private Boolean disableXmlReport;
714 
715     
716 
717 
718 
719 
720 
721     @Parameter(property = "enableAssertions", defaultValue = "true")
722     private boolean enableAssertions;
723 
724     
725 
726 
727 
728 
729 
730 
731     @Parameter(property = "enableOutErrElements", defaultValue = "true")
732     private boolean enableOutErrElements;
733 
734     
735 
736 
737 
738 
739     @Parameter(property = "enablePropertiesElement", defaultValue = "true")
740     private boolean enablePropertiesElement;
741 
742     
743 
744 
745     @Parameter(defaultValue = "${session}", required = true, readonly = true)
746     private MavenSession session;
747 
748     private Logger logger = LoggerFactory.getLogger(getClass());
749 
750     
751 
752 
753 
754 
755     @Parameter(property = "objectFactory")
756     private String objectFactory;
757 
758     
759 
760 
761     @Parameter(defaultValue = "${session.parallel}", readonly = true)
762     private Boolean parallelMavenExecution;
763 
764     
765 
766 
767 
768     @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true)
769     private File projectBuildDirectory;
770 
771     
772 
773 
774 
775 
776 
777 
778 
779 
780 
781 
782 
783 
784 
785 
786 
787 
788 
789 
790 
791 
792 
793 
794 
795 
796 
797 
798 
799     @Parameter(property = "dependenciesToScan")
800     private String[] dependenciesToScan;
801 
802     
803 
804 
805 
806 
807 
808 
809 
810 
811 
812 
813 
814 
815 
816 
817 
818 
819 
820 
821 
822 
823 
824 
825 
826 
827 
828 
829 
830 
831 
832 
833 
834 
835     @Parameter
836     private Map<String, String> jdkToolchain;
837 
838     
839 
840 
841     @Component
842     private ToolchainManager toolchainManager;
843 
844     @Component
845     private LocationManager locationManager;
846 
847     @Component
848     private ProviderDetector providerDetector;
849 
850     private Toolchain toolchain;
851 
852     private int effectiveForkCount = -1;
853 
854     protected abstract String getPluginName();
855 
856     protected abstract int getRerunFailingTestsCount();
857 
858     @Override
859     public abstract List<String> getIncludes();
860 
861     public abstract File getIncludesFile();
862 
863     @Override
864     public abstract void setIncludes(List<String> includes);
865 
866     public abstract File getExcludesFile();
867 
868     
869 
870 
871 
872 
873 
874     protected abstract List<File> suiteXmlFiles();
875 
876     
877 
878 
879     protected abstract boolean hasSuiteXmlFiles();
880 
881     protected abstract String[] getExcludedEnvironmentVariables();
882 
883     public abstract File[] getSuiteXmlFiles();
884 
885     public abstract void setSuiteXmlFiles(File[] suiteXmlFiles);
886 
887     public abstract String getRunOrder();
888 
889     public abstract void setRunOrder(String runOrder);
890 
891     public abstract Long getRunOrderRandomSeed();
892 
893     public abstract void setRunOrderRandomSeed(Long runOrderRandomSeed);
894 
895     protected abstract void handleSummary(RunResult summary, Exception firstForkException)
896             throws MojoExecutionException, MojoFailureException;
897 
898     protected abstract boolean isSkipExecution();
899 
900     protected abstract String[] getDefaultIncludes();
901 
902     protected abstract String getReportSchemaLocation();
903 
904     protected abstract boolean useModulePath();
905 
906     protected abstract void setUseModulePath(boolean useModulePath);
907 
908     protected abstract String getEnableProcessChecker();
909 
910     protected abstract ForkNodeFactory getForkNode();
911 
912     
913 
914 
915 
916 
917     protected Artifact getMojoArtifact() {
918         return getPluginDescriptor().getPluginArtifact();
919     }
920 
921     private String getDefaultExcludes() {
922         return "**/*$*";
923     }
924 
925     @Component(role = SurefireDependencyResolver.class)
926     private SurefireDependencyResolver surefireDependencyResolver;
927 
928     private TestListResolver specificTests;
929 
930     private TestListResolver includedExcludedTests;
931 
932     private List<CommandLineOption> cli;
933 
934     private volatile PluginConsoleLogger consoleLogger;
935 
936     @Override
937     public void execute() throws MojoExecutionException, MojoFailureException {
938         if (isSkipExecution()) {
939             getConsoleLogger().info("Tests are skipped.");
940             return;
941         }
942 
943         cli = commandLineOptions();
944         
945         setupStuff();
946         Platform platform = PLATFORM.withJdkExecAttributesForTests(getEffectiveJvm());
947         Thread shutdownThread = new Thread(platform::setShutdownState, "Surefire Shutdown Hook");
948         addShutDownHook(shutdownThread);
949         try {
950             if (verifyParameters() && !hasExecutedBefore()) {
951                 DefaultScanResult scan = scanForTestClasses();
952                 if (!hasSuiteXmlFiles() && scan.isEmpty()) {
953                     switch (getEffectiveFailIfNoTests()) {
954                         case COULD_NOT_RUN_DEFAULT_TESTS:
955                             throw new MojoFailureException(
956                                     "No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)");
957                         case COULD_NOT_RUN_SPECIFIED_TESTS:
958                             throw new MojoFailureException("No tests matching pattern \""
959                                     + getSpecificTests().toString()
960                                     + "\" were executed! (Set "
961                                     + "-D" + getPluginName()
962                                     + ".failIfNoSpecifiedTests=false to ignore this error.)");
963                         default:
964                             handleSummary(noTestsRun(), null);
965                             return;
966                     }
967                 }
968                 logReportsDirectory();
969                 executeAfterPreconditionsChecked(scan, platform);
970             }
971         } finally {
972             platform.clearShutdownState();
973             removeShutdownHook(shutdownThread);
974         }
975     }
976 
977     void setLogger(Logger logger) {
978         this.logger = logger;
979     }
980 
981     void setSurefireDependencyResolver(SurefireDependencyResolver surefireDependencyResolver) {
982         this.surefireDependencyResolver = surefireDependencyResolver;
983     }
984 
985     @Nonnull
986     protected final PluginConsoleLogger getConsoleLogger() {
987         if (consoleLogger == null) {
988             synchronized (this) {
989                 if (consoleLogger == null) {
990                     consoleLogger = new PluginConsoleLogger(logger);
991                 }
992             }
993         }
994         return consoleLogger;
995     }
996 
997     private Toolchain getToolchain() throws MojoFailureException {
998         Toolchain tc = null;
999 
1000         if (getJdkToolchain() != null) {
1001             List<Toolchain> tcs = getToolchainManager().getToolchains(getSession(), "jdk", getJdkToolchain());
1002             if (tcs.isEmpty()) {
1003                 throw new MojoFailureException(
1004                         "Requested toolchain specification did not match any configured toolchain: "
1005                                 + getJdkToolchain());
1006             }
1007             tc = tcs.get(0);
1008         }
1009 
1010         if (tc == null) {
1011             tc = getToolchainManager().getToolchainFromBuildContext("jdk", getSession());
1012         }
1013 
1014         return tc;
1015     }
1016 
1017     private void setupStuff() throws MojoFailureException {
1018 
1019         if (getBooterArtifact() == null) {
1020             throw new RuntimeException("Unable to locate surefire-booter in the list of plugin artifacts");
1021         }
1022 
1023         if (getToolchainManager() != null) {
1024             toolchain = getToolchain();
1025         }
1026     }
1027 
1028     @Nonnull
1029     private DefaultScanResult scanForTestClasses() throws MojoFailureException {
1030         DefaultScanResult scan = scanDirectories();
1031         DefaultScanResult scanDeps = scanDependencies();
1032         return scan.append(scanDeps);
1033     }
1034 
1035     private DefaultScanResult scanDirectories() throws MojoFailureException {
1036         DirectoryScanner scanner = new DirectoryScanner(getTestClassesDirectory(), getIncludedAndExcludedTests());
1037         return scanner.scan();
1038     }
1039 
1040     List<Artifact> getProjectTestArtifacts() {
1041         return project.getTestArtifacts();
1042     }
1043 
1044     DefaultScanResult scanDependencies() throws MojoFailureException {
1045         if (getDependenciesToScan() == null) {
1046             return null;
1047         } else {
1048             try {
1049                 DefaultScanResult result = null;
1050 
1051                 List<Artifact> dependenciesToScan = filter(getProjectTestArtifacts(), asList(getDependenciesToScan()));
1052 
1053                 for (Artifact artifact : dependenciesToScan) {
1054                     String type = artifact.getType();
1055                     File out = artifact.getFile();
1056                     if (out == null
1057                             || !out.exists()
1058                             || !("jar".equals(type)
1059                                     || out.isDirectory()
1060                                     || out.getName().endsWith(".jar"))) {
1061                         continue;
1062                     }
1063 
1064                     if (out.isFile()) {
1065                         DependencyScanner scanner =
1066                                 new DependencyScanner(singletonList(out), getIncludedAndExcludedTests());
1067                         result = result == null ? scanner.scan() : result.append(scanner.scan());
1068                     } else if (out.isDirectory()) {
1069                         DirectoryScanner scanner = new DirectoryScanner(out, getIncludedAndExcludedTests());
1070                         result = result == null ? scanner.scan() : result.append(scanner.scan());
1071                     }
1072                 }
1073 
1074                 return result;
1075             } catch (Exception e) {
1076                 throw new MojoFailureException(e.getLocalizedMessage(), e);
1077             }
1078         }
1079     }
1080 
1081     boolean verifyParameters() throws MojoFailureException, MojoExecutionException {
1082         setProperties(new SurefireProperties(getProperties()));
1083 
1084         String jvmToUse = getJvm();
1085         if (toolchain != null) {
1086             getConsoleLogger().info("Toolchain in maven-" + getPluginName() + "-plugin: " + toolchain);
1087             if (jvmToUse != null) {
1088                 getConsoleLogger().warning("Toolchains are ignored, 'jvm' parameter is set to " + jvmToUse);
1089             }
1090         }
1091 
1092         if (!getTestClassesDirectory().exists()
1093                 && (getDependenciesToScan() == null || getDependenciesToScan().length == 0)) {
1094             if (getFailIfNoTests()) {
1095                 throw new MojoFailureException("No tests to run!");
1096             }
1097             getConsoleLogger().info("No tests to run.");
1098         } else {
1099             ensureEnableProcessChecker();
1100             ensureWorkingDirectoryExists();
1101             ensureParallelRunningCompatibility();
1102             warnIfUselessUseSystemClassLoaderParameter();
1103             warnIfDefunctGroupsCombinations();
1104             warnIfRerunClashes();
1105             warnIfWrongShutdownValue();
1106             warnIfNotApplicableSkipAfterFailureCount();
1107             warnIfIllegalTempDir();
1108             warnIfForkCountIsZero();
1109             warnIfIllegalFailOnFlakeCount();
1110             printDefaultSeedIfNecessary();
1111         }
1112         return true;
1113     }
1114 
1115     private void warnIfForkCountIsZero() {
1116         if ("0".equals(getForkCount())) {
1117             getConsoleLogger()
1118                     .warning("The parameter forkCount should likely not be 0. Forking a JVM for tests "
1119                             + "improves test accuracy. Ensure to have a <forkCount> >= 1.");
1120         }
1121     }
1122 
1123     private void executeAfterPreconditionsChecked(@Nonnull DefaultScanResult scanResult, @Nonnull Platform platform)
1124             throws MojoExecutionException, MojoFailureException {
1125         TestClassPath testClasspath = generateTestClasspath();
1126         List<ProviderInfo> providers = createProviders(testClasspath);
1127         ResolvePathResultWrapper wrapper =
1128                 findModuleDescriptor(platform.getJdkExecAttributesForTests().getJdkHome());
1129 
1130         RunResult current = noTestsRun();
1131 
1132         Exception firstForkException = null;
1133         for (ProviderInfo provider : providers) {
1134             try {
1135                 current = current.aggregate(executeProvider(provider, scanResult, testClasspath, platform, wrapper));
1136             } catch (SurefireBooterForkException | SurefireExecutionException | TestSetFailedException e) {
1137                 if (firstForkException == null) {
1138                     firstForkException = e;
1139                 }
1140             }
1141         }
1142 
1143         if (firstForkException != null) {
1144             current = failure(current, firstForkException);
1145         }
1146 
1147         handleSummary(current, firstForkException);
1148     }
1149 
1150     protected List<ProviderInfo> createProviders(TestClassPath testClasspath) throws MojoExecutionException {
1151         Artifact junitDepArtifact = getJunitDepArtifact();
1152         return providerDetector.resolve(
1153                 new DynamicProviderInfo(null),
1154                 new JUnitPlatformProviderInfo(getJUnitPlatformRunnerArtifact(), getJUnit5Artifact(), testClasspath),
1155                 new TestNgProviderInfo(getTestNgArtifact()),
1156                 new JUnitCoreProviderInfo(getJunitArtifact(), junitDepArtifact),
1157                 new JUnit4ProviderInfo(getJunitArtifact(), junitDepArtifact),
1158                 new JUnit3ProviderInfo(),
1159                 new JUnitPlatformProviderShadefireInfo(
1160                         getJUnitPlatformRunnerArtifact(), getJUnit5Artifact(), testClasspath));
1161     }
1162 
1163     SurefireProperties setupProperties() {
1164         SurefireProperties sysPropsFromFile = null;
1165         try {
1166             sysPropsFromFile = SurefireProperties.loadProperties(getSystemPropertiesFile());
1167         } catch (IOException e) {
1168             String msg = "The file '" + getSystemPropertiesFile().getAbsolutePath() + "' can't be read.";
1169             if (getConsoleLogger().isDebugEnabled()) {
1170                 getConsoleLogger().debug(msg, e);
1171             } else {
1172                 getConsoleLogger().warning(msg);
1173             }
1174         }
1175 
1176         SurefireProperties result = calculateEffectiveProperties(
1177                 getSystemProperties(),
1178                 getSystemPropertyVariables(),
1179                 promoteUserPropertiesToSystemProperties ? getUserProperties() : new Properties(),
1180                 sysPropsFromFile);
1181 
1182         result.setProperty("basedir", getBasedir().getAbsolutePath());
1183         result.setProperty("localRepository", getLocalRepositoryPath());
1184         if (isForking()) {
1185             for (Object o : result.propertiesThatCannotBeSetASystemProperties()) {
1186                 if (getArgLine() == null || !getArgLine().contains("-D" + o + "=")) {
1187                     getConsoleLogger()
1188                             .warning(o + " cannot be set as system property, use <argLine>-D" + o
1189                                     + "=...</argLine> instead");
1190                 }
1191             }
1192             for (Object systemPropertyMatchingArgLine : systemPropertiesMatchingArgLine(result)) {
1193                 getConsoleLogger()
1194                         .warning("The system property "
1195                                 + systemPropertyMatchingArgLine
1196                                 + " is configured twice! "
1197                                 + "The property appears in <argLine/> and any of <systemPropertyVariables/>, "
1198                                 + "<systemProperties/> or user property.");
1199             }
1200         } else {
1201             result.setProperty("user.dir", getWorkingDirectory().getAbsolutePath());
1202         }
1203 
1204         if (getConsoleLogger().isDebugEnabled()) {
1205             showToLog(result, getConsoleLogger());
1206         }
1207 
1208         return result;
1209     }
1210 
1211     private SurefireProperties calculateEffectiveProperties(
1212             Properties systemProperties,
1213             Map<String, String> systemPropertyVariables,
1214             Properties userProperties,
1215             SurefireProperties sysPropsFromFile) {
1216         SurefireProperties result = new SurefireProperties();
1217         result.copyPropertiesFrom(systemProperties);
1218 
1219         Collection<String> overwrittenProperties = result.copyPropertiesFrom(sysPropsFromFile);
1220         if (!overwrittenProperties.isEmpty() && getConsoleLogger().isDebugEnabled()) {
1221             getConsoleLogger().debug(getOverwrittenPropertiesLogMessage(overwrittenProperties, "systemPropertiesFile"));
1222         }
1223         overwrittenProperties = result.copyPropertiesFrom(systemPropertyVariables);
1224         if (!overwrittenProperties.isEmpty() && getConsoleLogger().isDebugEnabled()) {
1225             getConsoleLogger()
1226                     .debug(getOverwrittenPropertiesLogMessage(overwrittenProperties, "systemPropertyVariables"));
1227         }
1228         
1229         
1230         
1231         
1232         if (!userProperties.isEmpty()) {
1233             overwrittenProperties = result.copyPropertiesFrom(userProperties);
1234             if (!overwrittenProperties.isEmpty()) {
1235                 getConsoleLogger()
1236                         .warning(getOverwrittenPropertiesLogMessage(
1237                                 overwrittenProperties, "user properties from Maven session"));
1238             }
1239         }
1240         return result;
1241     }
1242 
1243     private Set<Object> systemPropertiesMatchingArgLine(SurefireProperties result) {
1244         Set<Object> intersection = new HashSet<>();
1245         if (isNotBlank(getArgLine())) {
1246             for (Object systemProperty : result.getStringKeySet()) {
1247                 if (getArgLine().contains("-D" + systemProperty + "=")) {
1248                     intersection.add(systemProperty);
1249                 }
1250             }
1251 
1252             Set<Object> ignored = result.propertiesThatCannotBeSetASystemProperties();
1253             intersection.removeAll(ignored);
1254         }
1255         return intersection;
1256     }
1257 
1258     private String getOverwrittenPropertiesLogMessage(
1259             Collection<String> overwrittenProperties, String overwrittenBySource) {
1260         if (overwrittenProperties.isEmpty()) {
1261             throw new IllegalArgumentException("overwrittenProperties must not be empty");
1262         }
1263         
1264         ChoiceFormat propertyChoice = new ChoiceFormat("1#property|1>properties");
1265         StringBuilder message = new StringBuilder("System ");
1266         message.append(propertyChoice.format(overwrittenProperties.size())).append(" ");
1267         message.append(overwrittenProperties.stream().collect(Collectors.joining("], [", "[", "]")));
1268         message.append(" overwritten by ").append(overwrittenBySource);
1269         return message.toString();
1270     }
1271 
1272     private void showToLog(SurefireProperties props, ConsoleLogger log) {
1273         for (Object key : props.getStringKeySet()) {
1274             String value = props.getProperty((String) key);
1275             log.debug("Setting system property [" + key + "]=[" + value + "]");
1276         }
1277     }
1278 
1279     @Nonnull
1280     private RunResult executeProvider(
1281             @Nonnull ProviderInfo provider,
1282             @Nonnull DefaultScanResult scanResult,
1283             @Nonnull TestClassPath testClasspathWrapper,
1284             @Nonnull Platform platform,
1285             @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult)
1286             throws MojoExecutionException, MojoFailureException, SurefireExecutionException,
1287                     SurefireBooterForkException, TestSetFailedException {
1288         getConsoleLogger().debug("Using the provider " + provider.getProviderName());
1289         SurefireProperties effectiveProperties = setupProperties();
1290         ClassLoaderConfiguration classLoaderConfiguration = getClassLoaderConfiguration();
1291         provider.addProviderProperties();
1292         RunOrderParameters runOrderParameters =
1293                 new RunOrderParameters(getRunOrder(), getStatisticsFile(getConfigChecksum()), getRunOrderRandomSeed());
1294 
1295         if (isNotForking()) {
1296             Properties originalSystemProperties =
1297                     (Properties) System.getProperties().clone();
1298             try {
1299                 createCopyAndReplaceForkNumPlaceholder(effectiveProperties, 1).copyToSystemProperties();
1300                 getConsoleLogger().debug("Using in-process starter");
1301                 InPluginVMSurefireStarter surefireStarter = createInprocessStarter(
1302                         provider,
1303                         classLoaderConfiguration,
1304                         runOrderParameters,
1305                         scanResult,
1306                         platform,
1307                         testClasspathWrapper);
1308                 return surefireStarter.runSuitesInProcess(scanResult);
1309             } finally {
1310                 System.setProperties(originalSystemProperties);
1311             }
1312         } else {
1313             ForkConfiguration forkConfiguration = createForkConfiguration(platform, resolvedJavaModularityResult);
1314             if (getConsoleLogger().isDebugEnabled()) {
1315                 getConsoleLogger()
1316                         .debug("Using fork starter with configuration implementation "
1317                                 + forkConfiguration.getClass().getName());
1318                 showMap(getEnvironmentVariables(), "environment variable");
1319                 showArray(getExcludedEnvironmentVariables(), "excluded environment variable");
1320             }
1321 
1322             Properties originalSystemProperties =
1323                     (Properties) System.getProperties().clone();
1324             ForkStarter forkStarter = null;
1325             try {
1326                 forkStarter = createForkStarter(
1327                         provider,
1328                         forkConfiguration,
1329                         classLoaderConfiguration,
1330                         runOrderParameters,
1331                         getConsoleLogger(),
1332                         scanResult,
1333                         testClasspathWrapper,
1334                         platform,
1335                         resolvedJavaModularityResult);
1336 
1337                 return forkStarter.run(effectiveProperties, scanResult);
1338             } catch (SurefireBooterForkException e) {
1339                 forkStarter.killOrphanForks();
1340                 throw e;
1341             } finally {
1342                 System.setProperties(originalSystemProperties);
1343                 cleanupForkConfiguration(forkConfiguration);
1344             }
1345         }
1346     }
1347 
1348     public static SurefireProperties createCopyAndReplaceForkNumPlaceholder(
1349             SurefireProperties effectiveSystemProperties, int threadNumber) {
1350         SurefireProperties filteredProperties = new SurefireProperties((KeyValueSource) effectiveSystemProperties);
1351         for (Entry<Object, Object> entry : effectiveSystemProperties.entrySet()) {
1352             if (entry.getValue() instanceof String) {
1353                 String value = (String) entry.getValue();
1354                 filteredProperties.put(entry.getKey(), replaceThreadNumberPlaceholders(value, threadNumber));
1355             }
1356         }
1357         return filteredProperties;
1358     }
1359 
1360     protected void cleanupForkConfiguration(ForkConfiguration forkConfiguration) {
1361         if (!getConsoleLogger().isDebugEnabled() && forkConfiguration != null) {
1362             File tempDirectory = forkConfiguration.getTempDirectory();
1363             try {
1364                 FileUtils.deleteDirectory(tempDirectory);
1365             } catch (IOException e) {
1366                 getConsoleLogger()
1367                         .warning("Could not delete temp directory " + tempDirectory + " because " + e.getMessage());
1368             }
1369         }
1370     }
1371 
1372     protected void logReportsDirectory() {
1373         logDebugOrCliShowErrors(capitalizeFirstLetter(getPluginName()) + " report directory: " + getReportsDirectory());
1374     }
1375 
1376     private boolean existsModuleDescriptor(ResolvePathResultWrapper resolvedJavaModularityResult) {
1377         return resolvedJavaModularityResult.getResolvePathResult() != null;
1378     }
1379 
1380     private ResolvePathResultWrapper findModuleDescriptor(File jdkHome) {
1381         ResolvePathResultWrapper test = findModuleDescriptor(jdkHome, getTestClassesDirectory(), false);
1382         return test.getResolvePathResult() == null ? findModuleDescriptor(jdkHome, getMainBuildPath(), true) : test;
1383     }
1384 
1385     private ResolvePathResultWrapper findModuleDescriptor(File jdkHome, File buildPath, boolean isMainDescriptor) {
1386         boolean isJpmsModule =
1387                 buildPath.isDirectory() ? new File(buildPath, "module-info.class").exists() : isModule(buildPath);
1388 
1389         if (!isJpmsModule) {
1390             return new ResolvePathResultWrapper(null, isMainDescriptor);
1391         }
1392 
1393         try {
1394             ResolvePathRequest<?> request = ResolvePathRequest.ofFile(buildPath).setJdkHome(jdkHome);
1395             ResolvePathResult result = getLocationManager().resolvePath(request);
1396             boolean isEmpty = result.getModuleNameSource() == null;
1397             return new ResolvePathResultWrapper(isEmpty ? null : result, isMainDescriptor);
1398         } catch (Exception e) {
1399             return new ResolvePathResultWrapper(null, isMainDescriptor);
1400         }
1401     }
1402 
1403     private static boolean isModule(File jar) {
1404         try (ZipFile zip = new ZipFile(jar)) {
1405             return zip.getEntry("module-info.class") != null;
1406         } catch (IOException e) {
1407             return false;
1408         }
1409     }
1410 
1411     private boolean canExecuteProviderWithModularPath(
1412             @Nonnull Platform platform, @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult) {
1413         return useModulePath()
1414                 && platform.getJdkExecAttributesForTests().isJava9AtLeast()
1415                 && existsModuleDescriptor(resolvedJavaModularityResult);
1416     }
1417 
1418     
1419 
1420 
1421 
1422     private void convertTestNGParameters() throws MojoExecutionException {
1423         if (this.getParallel() != null) {
1424             getProperties().setProperty(ProviderParameterNames.PARALLEL_PROP, this.getParallel());
1425         }
1426         convertGroupParameters();
1427 
1428         if (this.getThreadCount() > 0) {
1429             getProperties()
1430                     .setProperty(ProviderParameterNames.THREADCOUNT_PROP, Integer.toString(this.getThreadCount()));
1431         }
1432         if (this.getObjectFactory() != null) {
1433             getProperties().setProperty("objectfactory", this.getObjectFactory());
1434         }
1435         if (this.getTestClassesDirectory() != null) {
1436             getProperties()
1437                     .setProperty(
1438                             "testng.test.classpath", getTestClassesDirectory().getAbsolutePath());
1439         }
1440 
1441         Artifact testNgArtifact = getTestNgArtifact();
1442         if (testNgArtifact != null) {
1443             DefaultArtifactVersion defaultArtifactVersion = new DefaultArtifactVersion(testNgArtifact.getVersion());
1444             getProperties()
1445                     .setProperty(
1446                             "testng.configurator", getConfiguratorName(defaultArtifactVersion, getConsoleLogger()));
1447         }
1448     }
1449 
1450     private static String getConfiguratorName(ArtifactVersion version, PluginConsoleLogger log)
1451             throws MojoExecutionException {
1452         try {
1453             VersionRange range = VersionRange.createFromVersionSpec("[4.7,5.2)");
1454             if (range.containsVersion(version)) {
1455                 return "org.apache.maven.surefire.testng.conf.TestNG4751Configurator";
1456             }
1457             range = VersionRange.createFromVersionSpec("[5.2,5.3)");
1458             if (range.containsVersion(version)) {
1459                 return "org.apache.maven.surefire.testng.conf.TestNG52Configurator";
1460             }
1461             range = VersionRange.createFromVersionSpec("[5.3,5.10)");
1462             if (range.containsVersion(version)) {
1463                 return "org.apache.maven.surefire.testng.conf.TestNGMapConfigurator";
1464             }
1465             range = VersionRange.createFromVersionSpec("[5.10,5.13)");
1466             if (range.containsVersion(version)) {
1467                 return "org.apache.maven.surefire.testng.conf.TestNG510Configurator";
1468             }
1469             range = VersionRange.createFromVersionSpec("[5.13,5.14.1)");
1470             if (range.containsVersion(version)) {
1471                 return "org.apache.maven.surefire.testng.conf.TestNG513Configurator";
1472             }
1473             range = VersionRange.createFromVersionSpec("[5.14.1,5.14.3)");
1474             if (range.containsVersion(version)) {
1475                 log.warning("The 'reporter' or 'listener' may not work properly in TestNG 5.14.1 and 5.14.2.");
1476                 return "org.apache.maven.surefire.testng.conf.TestNG5141Configurator";
1477             }
1478             range = VersionRange.createFromVersionSpec("[5.14.3,6.0)");
1479             if (range.containsVersion(version)) {
1480                 if (version.equals(new DefaultArtifactVersion("[5.14.3,5.14.5]"))) {
1481                     throw new MojoExecutionException("TestNG 5.14.3-5.14.5 is not supported. "
1482                             + "System dependency org.testng:guice missed path.");
1483                 }
1484                 return "org.apache.maven.surefire.testng.conf.TestNG5143Configurator";
1485             }
1486             range = VersionRange.createFromVersionSpec("[6.0,7.4.0)");
1487             if (range.containsVersion(version)) {
1488                 return "org.apache.maven.surefire.testng.conf.TestNG60Configurator";
1489             }
1490             range = VersionRange.createFromVersionSpec("[7.4.0,)");
1491             if (range.containsVersion(version)) {
1492                 return "org.apache.maven.surefire.testng.conf.TestNG740Configurator";
1493             }
1494 
1495             throw new MojoExecutionException("Unknown TestNG version " + version);
1496         } catch (InvalidVersionSpecificationException invsex) {
1497             throw new MojoExecutionException("Bug in plugin. Please report it with the attached stacktrace", invsex);
1498         }
1499     }
1500 
1501     private void convertGroupParameters() {
1502         if (this.getExcludedGroups() != null) {
1503             getProperties().setProperty(ProviderParameterNames.TESTNG_EXCLUDEDGROUPS_PROP, this.getExcludedGroups());
1504         }
1505         if (this.getGroups() != null) {
1506             getProperties().setProperty(ProviderParameterNames.TESTNG_GROUPS_PROP, this.getGroups());
1507         }
1508     }
1509 
1510     private void convertJunitEngineParameters() {
1511         if (getIncludeJUnit5Engines() != null && getIncludeJUnit5Engines().length != 0) {
1512             getProperties().setProperty(INCLUDE_JUNIT5_ENGINES_PROP, join(getIncludeJUnit5Engines()));
1513         }
1514 
1515         if (getExcludeJUnit5Engines() != null && getExcludeJUnit5Engines().length != 0) {
1516             getProperties().setProperty(EXCLUDE_JUNIT5_ENGINES_PROP, join(getExcludeJUnit5Engines()));
1517         }
1518     }
1519 
1520     private static String join(String[] array) {
1521         StringBuilder stringBuilder = new StringBuilder();
1522         for (int i = 0, length = array.length; i < length; i++) {
1523             stringBuilder.append(array[i]);
1524             if (i < length - 1) {
1525                 stringBuilder.append(',');
1526             }
1527         }
1528         return stringBuilder.toString();
1529     }
1530 
1531     protected boolean isAnyConcurrencySelected() {
1532         return getParallel() != null && !getParallel().trim().isEmpty();
1533     }
1534 
1535     protected boolean isAnyGroupsSelected() {
1536         return this.getGroups() != null || this.getExcludedGroups() != null;
1537     }
1538 
1539     
1540 
1541 
1542 
1543     private void convertJunitCoreParameters() throws MojoExecutionException {
1544         checkThreadCountEntity(getThreadCountSuites(), "suites");
1545         checkThreadCountEntity(getThreadCountClasses(), "classes");
1546         checkThreadCountEntity(getThreadCountMethods(), "methods");
1547 
1548         String usedParallel = (getParallel() != null) ? getParallel() : "none";
1549 
1550         if (!"none".equals(usedParallel)) {
1551             checkNonForkedThreads(parallel);
1552         }
1553 
1554         getProperties().setProperty(ProviderParameterNames.PARALLEL_PROP, usedParallel);
1555         if (this.getThreadCount() > 0) {
1556             getProperties().setProperty(ProviderParameterNames.THREADCOUNT_PROP, Integer.toString(getThreadCount()));
1557         }
1558         getProperties().setProperty("perCoreThreadCount", Boolean.toString(getPerCoreThreadCount()));
1559         getProperties().setProperty("useUnlimitedThreads", Boolean.toString(getUseUnlimitedThreads()));
1560         getProperties()
1561                 .setProperty(ProviderParameterNames.THREADCOUNTSUITES_PROP, Integer.toString(getThreadCountSuites()));
1562         getProperties()
1563                 .setProperty(ProviderParameterNames.THREADCOUNTCLASSES_PROP, Integer.toString(getThreadCountClasses()));
1564         getProperties()
1565                 .setProperty(ProviderParameterNames.THREADCOUNTMETHODS_PROP, Integer.toString(getThreadCountMethods()));
1566         getProperties()
1567                 .setProperty(
1568                         ProviderParameterNames.PARALLEL_TIMEOUT_PROP,
1569                         Double.toString(getParallelTestsTimeoutInSeconds()));
1570         getProperties()
1571                 .setProperty(
1572                         ProviderParameterNames.PARALLEL_TIMEOUTFORCED_PROP,
1573                         Double.toString(getParallelTestsTimeoutForcedInSeconds()));
1574         getProperties()
1575                 .setProperty(ProviderParameterNames.PARALLEL_OPTIMIZE_PROP, Boolean.toString(isParallelOptimized()));
1576         getProperties()
1577                 .setProperty(
1578                         ProviderParameterNames.ENABLE_OUT_ERR_ELEMENTS_PROP,
1579                         Boolean.toString(isEnableOutErrElements()));
1580         getProperties()
1581                 .setProperty(
1582                         ProviderParameterNames.ENABLE_PROPERTIES_ELEMENT_PROP,
1583                         Boolean.toString(isEnablePropertiesElement()));
1584 
1585         String message = "parallel='" + usedParallel + '\''
1586                 + ", perCoreThreadCount=" + getPerCoreThreadCount()
1587                 + ", threadCount=" + getThreadCount()
1588                 + ", useUnlimitedThreads=" + getUseUnlimitedThreads()
1589                 + ", threadCountSuites=" + getThreadCountSuites()
1590                 + ", threadCountClasses=" + getThreadCountClasses()
1591                 + ", threadCountMethods=" + getThreadCountMethods()
1592                 + ", parallelOptimized=" + isParallelOptimized()
1593                 + ", enableOutErrElements=" + isEnableOutErrElements()
1594                 + ", enablePropertiesElement=" + isEnablePropertiesElement();
1595 
1596         logDebugOrCliShowErrors(message);
1597     }
1598 
1599     private void checkNonForkedThreads(String parallel) throws MojoExecutionException {
1600         if ("suites".equals(parallel)) {
1601             if (!(getUseUnlimitedThreads() || getThreadCount() > 0 ^ getThreadCountSuites() > 0)) {
1602                 throw new MojoExecutionException(
1603                         "Use threadCount or threadCountSuites > 0 or useUnlimitedThreads=true for parallel='suites'");
1604             }
1605             setThreadCountClasses(0);
1606             setThreadCountMethods(0);
1607         } else if ("classes".equals(parallel)) {
1608             if (!(getUseUnlimitedThreads() || getThreadCount() > 0 ^ getThreadCountClasses() > 0)) {
1609                 throw new MojoExecutionException(
1610                         "Use threadCount or threadCountClasses > 0 or useUnlimitedThreads=true for parallel='classes'");
1611             }
1612             setThreadCountSuites(0);
1613             setThreadCountMethods(0);
1614         } else if ("methods".equals(parallel)) {
1615             if (!(getUseUnlimitedThreads() || getThreadCount() > 0 ^ getThreadCountMethods() > 0)) {
1616                 throw new MojoExecutionException(
1617                         "Use threadCount or threadCountMethods > 0 or useUnlimitedThreads=true for parallel='methods'");
1618             }
1619             setThreadCountSuites(0);
1620             setThreadCountClasses(0);
1621         } else if ("suitesAndClasses".equals(parallel)) {
1622             if (!(getUseUnlimitedThreads()
1623                     || onlyThreadCount()
1624                     || getThreadCountSuites() > 0
1625                             && getThreadCountClasses() > 0
1626                             && getThreadCount() == 0
1627                             && getThreadCountMethods() == 0
1628                     || getThreadCount() > 0
1629                             && getThreadCountSuites() > 0
1630                             && getThreadCountClasses() > 0
1631                             && getThreadCountMethods() == 0
1632                     || getThreadCount() > 0
1633                             && getThreadCountSuites() > 0
1634                             && getThreadCount() > getThreadCountSuites()
1635                             && getThreadCountClasses() == 0
1636                             && getThreadCountMethods() == 0)) {
1637                 throw new MojoExecutionException("Use useUnlimitedThreads=true, "
1638                         + "or only threadCount > 0, "
1639                         + "or (threadCountSuites > 0 and threadCountClasses > 0), "
1640                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCountClasses > 0) "
1641                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCount > threadCountSuites) "
1642                         + "for parallel='suitesAndClasses' or 'both'");
1643             }
1644             setThreadCountMethods(0);
1645         } else if ("suitesAndMethods".equals(parallel)) {
1646             if (!(getUseUnlimitedThreads()
1647                     || onlyThreadCount()
1648                     || getThreadCountSuites() > 0
1649                             && getThreadCountMethods() > 0
1650                             && getThreadCount() == 0
1651                             && getThreadCountClasses() == 0
1652                     || getThreadCount() > 0
1653                             && getThreadCountSuites() > 0
1654                             && getThreadCountMethods() > 0
1655                             && getThreadCountClasses() == 0
1656                     || getThreadCount() > 0
1657                             && getThreadCountSuites() > 0
1658                             && getThreadCount() > getThreadCountSuites()
1659                             && getThreadCountClasses() == 0
1660                             && getThreadCountMethods() == 0)) {
1661                 throw new MojoExecutionException("Use useUnlimitedThreads=true, "
1662                         + "or only threadCount > 0, "
1663                         + "or (threadCountSuites > 0 and threadCountMethods > 0), "
1664                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCountMethods > 0), "
1665                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCount > threadCountSuites) "
1666                         + "for parallel='suitesAndMethods'");
1667             }
1668             setThreadCountClasses(0);
1669         } else if ("both".equals(parallel) || "classesAndMethods".equals(parallel)) {
1670             if (!(getUseUnlimitedThreads()
1671                     || onlyThreadCount()
1672                     || getThreadCountClasses() > 0
1673                             && getThreadCountMethods() > 0
1674                             && getThreadCount() == 0
1675                             && getThreadCountSuites() == 0
1676                     || getThreadCount() > 0
1677                             && getThreadCountClasses() > 0
1678                             && getThreadCountMethods() > 0
1679                             && getThreadCountSuites() == 0
1680                     || getThreadCount() > 0
1681                             && getThreadCountClasses() > 0
1682                             && getThreadCount() > getThreadCountClasses()
1683                             && getThreadCountSuites() == 0
1684                             && getThreadCountMethods() == 0)) {
1685                 throw new MojoExecutionException("Use useUnlimitedThreads=true, "
1686                         + "or only threadCount > 0, "
1687                         + "or (threadCountClasses > 0 and threadCountMethods > 0), "
1688                         + "or (threadCount > 0 and threadCountClasses > 0 and threadCountMethods > 0), "
1689                         + "or (threadCount > 0 and threadCountClasses > 0 and threadCount > threadCountClasses) "
1690                         + "for parallel='both' or parallel='classesAndMethods'");
1691             }
1692             setThreadCountSuites(0);
1693         } else if ("all".equals(parallel)) {
1694             if (!(getUseUnlimitedThreads()
1695                     || onlyThreadCount()
1696                     || getThreadCountSuites() > 0 && getThreadCountClasses() > 0 && getThreadCountMethods() > 0
1697                     || getThreadCount() > 0
1698                             && getThreadCountSuites() > 0
1699                             && getThreadCountClasses() > 0
1700                             && getThreadCountMethods() == 0
1701                             && getThreadCount() > (getThreadCountSuites() + getThreadCountClasses()))) {
1702                 throw new MojoExecutionException("Use useUnlimitedThreads=true, "
1703                         + "or only threadCount > 0, "
1704                         + "or (threadCountSuites > 0 and threadCountClasses > 0 and threadCountMethods > 0), "
1705                         + "or every thread-count is specified, "
1706                         + "or (threadCount > 0 and threadCountSuites > 0 and threadCountClasses > 0 "
1707                         + "and threadCount > threadCountSuites + threadCountClasses) "
1708                         + "for parallel='all'");
1709             }
1710         } else {
1711             throw new MojoExecutionException("Illegal parallel='" + parallel + "'");
1712         }
1713     }
1714 
1715     private boolean onlyThreadCount() {
1716         return getThreadCount() > 0
1717                 && getThreadCountSuites() == 0
1718                 && getThreadCountClasses() == 0
1719                 && getThreadCountMethods() == 0;
1720     }
1721 
1722     private static void checkThreadCountEntity(int count, String entity) throws MojoExecutionException {
1723         if (count < 0) {
1724             throw new MojoExecutionException("parallel maven execution does not allow negative thread-count" + entity);
1725         }
1726     }
1727 
1728     private boolean isJunit47Compatible(Artifact artifact) {
1729         return isWithinVersionSpec(artifact, "[4.7,)");
1730     }
1731 
1732     private boolean isAnyJunit4(Artifact artifact) {
1733         return isWithinVersionSpec(artifact, "[4.0,)");
1734     }
1735 
1736     protected boolean isForking() {
1737         return 0 < getEffectiveForkCount();
1738     }
1739 
1740     private List<RunOrder> getRunOrders() {
1741         String runOrderString = getRunOrder();
1742         RunOrder[] runOrder = runOrderString == null ? RunOrder.DEFAULT : RunOrder.valueOfMulti(runOrderString);
1743         return asList(runOrder);
1744     }
1745 
1746     private boolean requiresRunHistory() {
1747         final List<RunOrder> runOrders = getRunOrders();
1748         return runOrders.contains(RunOrder.BALANCED) || runOrders.contains(RunOrder.FAILEDFIRST);
1749     }
1750 
1751     private PluginFailureReason getEffectiveFailIfNoTests() {
1752         if (isSpecificTestSpecified()) {
1753             return getFailIfNoSpecifiedTests() ? COULD_NOT_RUN_SPECIFIED_TESTS : NONE;
1754         } else {
1755             return getFailIfNoTests() ? COULD_NOT_RUN_DEFAULT_TESTS : NONE;
1756         }
1757     }
1758 
1759     private ProviderConfiguration createProviderConfiguration(RunOrderParameters runOrderParameters)
1760             throws MojoExecutionException, MojoFailureException {
1761         final ReporterConfiguration reporterConfiguration =
1762                 new ReporterConfiguration(getReportsDirectory(), isTrimStackTrace());
1763 
1764         final Artifact testNgArtifact = getTestNgArtifact();
1765         final boolean isTestNg = testNgArtifact != null;
1766         final TestArtifactInfo testNg =
1767                 isTestNg ? new TestArtifactInfo(testNgArtifact.getVersion(), testNgArtifact.getClassifier()) : null;
1768         final TestRequest testSuiteDefinition = new TestRequest(
1769                 suiteXmlFiles(), getTestSourceDirectory(), getSpecificTests(), getRerunFailingTestsCount());
1770 
1771         final boolean actualFailIfNoTests;
1772         DirectoryScannerParameters directoryScannerParameters = null;
1773         if (hasSuiteXmlFiles() && !isSpecificTestSpecified()) {
1774             actualFailIfNoTests = getFailIfNoTests();
1775             if (!isTestNg) {
1776                 throw new MojoExecutionException("suiteXmlFiles is configured, but there is no TestNG dependency");
1777             }
1778         } else {
1779             
1780             
1781             
1782 
1783             List<String> actualIncludes = getIncludeList(); 
1784             List<String> actualExcludes = getExcludeList(); 
1785             
1786             List<String> specificTests = Collections.emptyList();
1787 
1788             directoryScannerParameters = new DirectoryScannerParameters(
1789                     getTestClassesDirectory(), actualIncludes, actualExcludes, specificTests, getRunOrder());
1790         }
1791 
1792         Map<String, String> providerProperties = toStringProperties(getProperties());
1793 
1794         return new ProviderConfiguration(
1795                 directoryScannerParameters,
1796                 runOrderParameters,
1797                 reporterConfiguration,
1798                 testNg, 
1799                 testSuiteDefinition,
1800                 providerProperties,
1801                 null,
1802                 false,
1803                 cli,
1804                 getSkipAfterFailureCount(),
1805                 Shutdown.parameterOf(getShutdown()),
1806                 getForkedProcessExitTimeoutInSeconds());
1807     }
1808 
1809     private static Map<String, String> toStringProperties(Properties properties) {
1810         Map<String, String> h = new ConcurrentHashMap<>(properties.size());
1811         for (Enumeration<?> e = properties.keys(); e.hasMoreElements(); ) {
1812             Object k = e.nextElement();
1813             Object v = properties.get(k);
1814             if (k.getClass() == String.class && v.getClass() == String.class) {
1815                 h.put((String) k, (String) v);
1816             }
1817         }
1818         return h;
1819     }
1820 
1821     private File getStatisticsFile(String configurationHash) {
1822         return new File(getBasedir(), ".surefire-" + configurationHash);
1823     }
1824 
1825     private StartupConfiguration createStartupConfiguration(
1826             @Nonnull ProviderInfo provider,
1827             boolean isForking,
1828             @Nonnull ClassLoaderConfiguration classLoaderConfiguration,
1829             @Nonnull DefaultScanResult scanResult,
1830             @Nonnull TestClassPath testClasspathWrapper,
1831             @Nonnull Platform platform,
1832             @Nonnull ResolvePathResultWrapper resolvedJavaModularity)
1833             throws MojoExecutionException {
1834         try {
1835             if (isForking && canExecuteProviderWithModularPath(platform, resolvedJavaModularity)) {
1836                 File jdkHome = platform.getJdkExecAttributesForTests().getJdkHome();
1837                 return newStartupConfigWithModularPath(
1838                         classLoaderConfiguration,
1839                         provider,
1840                         resolvedJavaModularity,
1841                         scanResult,
1842                         jdkHome.getAbsolutePath(),
1843                         testClasspathWrapper);
1844             } else {
1845                 return newStartupConfigWithClasspath(classLoaderConfiguration, provider, testClasspathWrapper);
1846             }
1847         } catch (IOException e) {
1848             throw new MojoExecutionException(e.getMessage(), e);
1849         }
1850     }
1851 
1852     private StartupConfiguration newStartupConfigWithClasspath(
1853             @Nonnull ClassLoaderConfiguration classLoaderConfiguration,
1854             @Nonnull ProviderInfo providerInfo,
1855             @Nonnull TestClassPath testClasspathWrapper)
1856             throws MojoExecutionException {
1857         Classpath testClasspath = testClasspathWrapper.toClasspath();
1858         Set<Artifact> providerArtifacts = providerInfo.getProviderClasspath();
1859         String providerName = providerInfo.getProviderName();
1860         Classpath providerClasspath = classpathCache.getCachedClassPath(providerName);
1861         if (providerClasspath == null) {
1862             providerClasspath = classpathCache.setCachedClasspath(providerName, providerArtifacts);
1863         }
1864 
1865         getConsoleLogger().debug(testClasspath.getLogMessage("test classpath:"));
1866         getConsoleLogger().debug(providerClasspath.getLogMessage("provider classpath:"));
1867         getConsoleLogger().debug(testClasspath.getCompactLogMessage("test(compact) classpath:"));
1868         getConsoleLogger().debug(providerClasspath.getCompactLogMessage("provider(compact) classpath:"));
1869 
1870         Artifact[] additionalInProcArtifacts = {
1871             getCommonArtifact(),
1872             getBooterArtifact(),
1873             getExtensionsArtifact(),
1874             getApiArtifact(),
1875             getSpiArtifact(),
1876             getLoggerApiArtifact(),
1877             getSurefireSharedUtilsArtifact()
1878         };
1879         Set<Artifact> inProcArtifacts = retainInProcArtifactsUnique(providerArtifacts, additionalInProcArtifacts);
1880         Classpath inProcClasspath = createInProcClasspath(providerClasspath, inProcArtifacts);
1881         getConsoleLogger().debug(inProcClasspath.getLogMessage("in-process classpath:"));
1882         getConsoleLogger().debug(inProcClasspath.getCompactLogMessage("in-process(compact) classpath:"));
1883 
1884         ClasspathConfiguration classpathConfiguration = new ClasspathConfiguration(
1885                 testClasspath, providerClasspath, inProcClasspath, effectiveIsEnableAssertions(), isChildDelegation());
1886         ProviderRequirements forkRequirements = new ProviderRequirements(false, false, false);
1887         return new StartupConfiguration(
1888                 providerName,
1889                 classpathConfiguration,
1890                 classLoaderConfiguration,
1891                 ProcessCheckerType.toEnum(getEnableProcessChecker()),
1892                 providerInfo.getJpmsArguments(forkRequirements));
1893     }
1894 
1895     private static Set<Artifact> retainInProcArtifactsUnique(
1896             Set<Artifact> providerArtifacts, Artifact... inPluginArtifacts) {
1897         Set<Artifact> result = new LinkedHashSet<>();
1898         for (Artifact inPluginArtifact : inPluginArtifacts) {
1899             boolean contains = false;
1900             for (Artifact providerArtifact : providerArtifacts) {
1901                 if (hasGroupArtifactId(
1902                         providerArtifact.getGroupId(), providerArtifact.getArtifactId(), inPluginArtifact)) {
1903                     contains = true;
1904                     break;
1905                 }
1906             }
1907             if (!contains) {
1908                 result.add(inPluginArtifact);
1909             }
1910         }
1911         return result;
1912     }
1913 
1914     private static boolean hasGroupArtifactId(String groupId, String artifactId, Artifact artifact) {
1915         return groupId.equals(artifact.getGroupId()) && artifactId.equals(artifact.getArtifactId());
1916     }
1917 
1918     private static Classpath createInProcClasspath(Classpath providerClasspath, Set<Artifact> newArtifacts) {
1919         Classpath inprocClasspath = providerClasspath.clone();
1920         for (Artifact newArtifact : newArtifacts) {
1921             inprocClasspath =
1922                     inprocClasspath.addClassPathElementUrl(newArtifact.getFile().getAbsolutePath());
1923         }
1924         return inprocClasspath;
1925     }
1926 
1927     
1928 
1929 
1930 
1931     private LocationManager getLocationManager() {
1932         return locationManager;
1933     }
1934 
1935     private StartupConfiguration newStartupConfigWithModularPath(
1936             @Nonnull ClassLoaderConfiguration classLoaderConfiguration,
1937             @Nonnull ProviderInfo providerInfo,
1938             @Nonnull ResolvePathResultWrapper moduleDescriptor,
1939             @Nonnull DefaultScanResult scanResult,
1940             @Nonnull String javaHome,
1941             @Nonnull TestClassPath testClasspathWrapper)
1942             throws MojoExecutionException, IOException {
1943         boolean isMainDescriptor = moduleDescriptor.isMainModuleDescriptor();
1944         JavaModuleDescriptor javaModuleDescriptor =
1945                 moduleDescriptor.getResolvePathResult().getModuleDescriptor();
1946         SortedSet<String> packages = new TreeSet<>();
1947 
1948         Classpath testClasspath = testClasspathWrapper.toClasspath();
1949         Set<Artifact> providerArtifacts = providerInfo.getProviderClasspath();
1950         String providerName = providerInfo.getProviderName();
1951         Classpath providerClasspath = classpathCache.getCachedClassPath(providerName);
1952         if (providerClasspath == null) {
1953             providerClasspath = classpathCache.setCachedClasspath(providerName, providerArtifacts);
1954         }
1955 
1956         final ProviderRequirements providerRequirements;
1957         final Classpath testModulepath;
1958         if (isMainDescriptor) {
1959             providerRequirements = new ProviderRequirements(true, true, false);
1960             ResolvePathsRequest<String> req = ResolvePathsRequest.ofStrings(testClasspath.getClassPath())
1961                     .setIncludeAllProviders(true)
1962                     .setJdkHome(javaHome)
1963                     .setIncludeStatic(true)
1964                     .setModuleDescriptor(javaModuleDescriptor);
1965 
1966             ResolvePathsResult<String> result = getLocationManager().resolvePaths(req);
1967             for (Entry<String, Exception> entry : result.getPathExceptions().entrySet()) {
1968                 
1969                 getConsoleLogger().warning("Exception for '" + entry.getKey() + "'.", entry.getValue());
1970             }
1971 
1972             testClasspath = new Classpath(result.getClasspathElements());
1973             testModulepath = new Classpath(result.getModulepathElements().keySet());
1974 
1975             for (String className : scanResult.getClasses()) {
1976                 packages.add(substringBeforeLast(className, "."));
1977             }
1978         } else {
1979             providerRequirements = new ProviderRequirements(true, false, true);
1980             testModulepath = testClasspath;
1981             testClasspath = emptyClasspath();
1982         }
1983 
1984         getConsoleLogger().debug("main module descriptor name: " + javaModuleDescriptor.name());
1985 
1986         ModularClasspath modularClasspath = new ModularClasspath(
1987                 javaModuleDescriptor.name(),
1988                 testModulepath.getClassPath(),
1989                 packages,
1990                 isMainDescriptor ? getTestClassesDirectory() : null,
1991                 isMainDescriptor);
1992 
1993         Artifact[] additionalInProcArtifacts = {
1994             getCommonArtifact(),
1995             getBooterArtifact(),
1996             getExtensionsArtifact(),
1997             getApiArtifact(),
1998             getSpiArtifact(),
1999             getLoggerApiArtifact(),
2000             getSurefireSharedUtilsArtifact()
2001         };
2002         Set<Artifact> inProcArtifacts = retainInProcArtifactsUnique(providerArtifacts, additionalInProcArtifacts);
2003         Classpath inProcClasspath = createInProcClasspath(providerClasspath, inProcArtifacts);
2004 
2005         ModularClasspathConfiguration classpathConfiguration = new ModularClasspathConfiguration(
2006                 modularClasspath,
2007                 testClasspath,
2008                 providerClasspath,
2009                 inProcClasspath,
2010                 effectiveIsEnableAssertions(),
2011                 isChildDelegation());
2012 
2013         getConsoleLogger().debug(testClasspath.getLogMessage("test classpath:"));
2014         getConsoleLogger().debug(testModulepath.getLogMessage("test modulepath:"));
2015         getConsoleLogger().debug(providerClasspath.getLogMessage("provider classpath:"));
2016         getConsoleLogger().debug(testClasspath.getCompactLogMessage("test(compact) classpath:"));
2017         getConsoleLogger().debug(testModulepath.getCompactLogMessage("test(compact) modulepath:"));
2018         getConsoleLogger().debug(providerClasspath.getCompactLogMessage("provider(compact) classpath:"));
2019         getConsoleLogger().debug(inProcClasspath.getLogMessage("in-process classpath:"));
2020         getConsoleLogger().debug(inProcClasspath.getCompactLogMessage("in-process(compact) classpath:"));
2021 
2022         ProcessCheckerType processCheckerType = ProcessCheckerType.toEnum(getEnableProcessChecker());
2023         List<String[]> jpmsArgs = providerInfo.getJpmsArguments(providerRequirements);
2024         return new StartupConfiguration(
2025                 providerName, classpathConfiguration, classLoaderConfiguration, processCheckerType, jpmsArgs);
2026     }
2027 
2028     private Artifact getCommonArtifact() {
2029         return getPluginArtifactMap().get("org.apache.maven.surefire:maven-surefire-common");
2030     }
2031 
2032     private Artifact getExtensionsArtifact() {
2033         return getPluginArtifactMap().get("org.apache.maven.surefire:surefire-extensions-api");
2034     }
2035 
2036     private Artifact getSpiArtifact() {
2037         return getPluginArtifactMap().get("org.apache.maven.surefire:surefire-extensions-spi");
2038     }
2039 
2040     private Artifact getApiArtifact() {
2041         return getPluginArtifactMap().get("org.apache.maven.surefire:surefire-api");
2042     }
2043 
2044     private Artifact getSurefireSharedUtilsArtifact() {
2045         return getPluginArtifactMap().get("org.apache.maven.surefire:surefire-shared-utils");
2046     }
2047 
2048     private Artifact getLoggerApiArtifact() {
2049         return getPluginArtifactMap().get("org.apache.maven.surefire:surefire-logger-api");
2050     }
2051 
2052     private Artifact getBooterArtifact() {
2053         return getPluginArtifactMap().get("org.apache.maven.surefire:surefire-booter");
2054     }
2055 
2056     private Artifact getShadefireArtifact() {
2057         return getPluginArtifactMap().get("org.apache.maven.surefire:surefire-shadefire");
2058     }
2059 
2060     private StartupReportConfiguration getStartupReportConfiguration(
2061             String configChecksum, boolean isForking, ProviderInfo providerInfo) {
2062         SurefireStatelessReporter xmlReporter =
2063                 statelessTestsetReporter == null ? new SurefireStatelessReporter() : statelessTestsetReporter;
2064 
2065         if (disableXmlReport != null) {
2066             xmlReporter.setDisable(disableXmlReport);
2067         }
2068 
2069         SurefireConsoleOutputReporter outReporter =
2070                 consoleOutputReporter == null ? new SurefireConsoleOutputReporter() : consoleOutputReporter;
2071 
2072         SurefireStatelessTestsetInfoReporter testsetReporter = statelessTestsetInfoReporter == null
2073                 ? new SurefireStatelessTestsetInfoReporter()
2074                 : statelessTestsetInfoReporter;
2075 
2076         
2077         ReporterFactoryOptions reporterFactoryOptions = new ReporterFactoryOptions();
2078         if ("org.apache.maven.surefire.junitplatform.JUnitPlatformProvider".equals(providerInfo.getProviderName())) {
2079             reporterFactoryOptions.setStatPerSourceName(true);
2080         }
2081         return new StartupReportConfiguration(
2082                 isUseFile(),
2083                 isPrintSummary(),
2084                 getReportFormat(),
2085                 isRedirectTestOutputToFile(),
2086                 getReportsDirectory(),
2087                 isTrimStackTrace(),
2088                 getReportNameSuffix(),
2089                 getStatisticsFile(configChecksum),
2090                 requiresRunHistory(),
2091                 getRerunFailingTestsCount(),
2092                 getReportSchemaLocation(),
2093                 getEncoding(),
2094                 isForking,
2095                 isEnableOutErrElements(),
2096                 isEnablePropertiesElement(),
2097                 xmlReporter,
2098                 outReporter,
2099                 testsetReporter,
2100                 reporterFactoryOptions);
2101     }
2102 
2103     private boolean isSpecificTestSpecified() {
2104         return isNotBlank(getTest());
2105     }
2106 
2107     @Nonnull
2108     private List<String> readListFromFile(@Nonnull final File file) {
2109         getConsoleLogger().debug("Reading list from: " + file);
2110 
2111         if (!file.exists()) {
2112             throw new RuntimeException("Failed to load list from file: " + file);
2113         }
2114 
2115         try {
2116             List<String> list = FileUtils.loadFile(file);
2117 
2118             if (getConsoleLogger().isDebugEnabled()) {
2119                 getConsoleLogger().debug("List contents:");
2120                 for (String entry : list) {
2121                     getConsoleLogger().debug("  " + entry);
2122                 }
2123             }
2124             return list;
2125         } catch (IOException e) {
2126             throw new RuntimeException("Failed to load list from file: " + file, e);
2127         }
2128     }
2129 
2130     @Nonnull
2131     private List<String> getExcludedScanList() throws MojoFailureException {
2132         return getExcludeList(true);
2133     }
2134 
2135     @Nonnull
2136     private List<String> getExcludeList() throws MojoFailureException {
2137         return getExcludeList(false);
2138     }
2139 
2140     
2141 
2142 
2143 
2144 
2145 
2146 
2147     @Nonnull
2148     private List<String> getExcludeList(boolean asScanList) throws MojoFailureException {
2149         List<String> excludes;
2150         if (isSpecificTestSpecified()) {
2151             excludes = Collections.emptyList();
2152         } else {
2153             excludes = new ArrayList<>();
2154             if (asScanList) {
2155                 if (getExcludes() != null) {
2156                     excludes.addAll(getExcludes());
2157                 }
2158                 checkMethodFilterInIncludesExcludes(excludes);
2159             }
2160 
2161             if (getExcludesFile() != null) {
2162                 excludes.addAll(readListFromFile(getExcludesFile()));
2163             }
2164 
2165             if (asScanList && excludes.isEmpty()) {
2166                 excludes = Collections.singletonList(getDefaultExcludes());
2167             }
2168         }
2169         return filterNulls(excludes);
2170     }
2171 
2172     @Nonnull
2173     private List<String> getIncludedScanList() throws MojoFailureException {
2174         return getIncludeList(true);
2175     }
2176 
2177     @Nonnull
2178     private List<String> getIncludeList() throws MojoFailureException {
2179         return getIncludeList(false);
2180     }
2181 
2182     
2183 
2184 
2185 
2186 
2187 
2188 
2189     @Nonnull
2190     private List<String> getIncludeList(boolean asScanList) throws MojoFailureException {
2191         final List<String> includes = new ArrayList<>();
2192         if (isSpecificTestSpecified()) {
2193             addAll(includes, split(getTest(), ","));
2194         } else {
2195             if (asScanList) {
2196                 if (getIncludes() != null) {
2197                     includes.addAll(getIncludes());
2198                 }
2199                 checkMethodFilterInIncludesExcludes(includes);
2200             }
2201 
2202             if (getIncludesFile() != null) {
2203                 includes.addAll(readListFromFile(getIncludesFile()));
2204             }
2205 
2206             if (asScanList && includes.isEmpty()) {
2207                 addAll(includes, getDefaultIncludes());
2208             }
2209         }
2210 
2211         return filterNulls(includes);
2212     }
2213 
2214     private void checkMethodFilterInIncludesExcludes(Iterable<String> patterns) throws MojoFailureException {
2215         for (String pattern : patterns) {
2216             if (pattern != null && pattern.contains("#")) {
2217                 throw new MojoFailureException("Method filter prohibited in includes|excludes parameter: " + pattern);
2218             }
2219         }
2220     }
2221 
2222     private TestListResolver getIncludedAndExcludedTests() throws MojoFailureException {
2223         if (includedExcludedTests == null) {
2224             includedExcludedTests = new TestListResolver(getIncludedScanList(), getExcludedScanList());
2225             getConsoleLogger().debug("Resolved included and excluded patterns: " + includedExcludedTests);
2226         }
2227         return includedExcludedTests;
2228     }
2229 
2230     public TestListResolver getSpecificTests() throws MojoFailureException {
2231         if (specificTests == null) {
2232             specificTests = new TestListResolver(getIncludeList(), getExcludeList());
2233         }
2234         return specificTests;
2235     }
2236 
2237     @Nonnull
2238     private List<String> filterNulls(@Nonnull List<String> toFilter) {
2239         List<String> result = new ArrayList<>(toFilter.size());
2240         for (String item : toFilter) {
2241             if (item != null) {
2242                 item = item.trim();
2243                 if (!item.isEmpty()) {
2244                     result.add(item);
2245                 }
2246             }
2247         }
2248 
2249         return result;
2250     }
2251 
2252     private Artifact getTestNgArtifact() throws MojoExecutionException {
2253         Artifact artifact = getProjectArtifactMap().get(getTestNGArtifactName());
2254         Artifact projectArtifact = project.getArtifact();
2255         String projectArtifactName = projectArtifact.getGroupId() + ":" + projectArtifact.getArtifactId();
2256 
2257         if (artifact != null) {
2258             VersionRange range = createVersionRange();
2259             if (!range.containsVersion(new DefaultArtifactVersion(artifact.getVersion()))) {
2260                 throw new MojoExecutionException(
2261                         "TestNG support requires version 4.7 or above. You have declared version "
2262                                 + artifact.getVersion());
2263             }
2264         } else if (projectArtifactName.equals(getTestNGArtifactName())) {
2265             artifact = projectArtifact;
2266         }
2267 
2268         return artifact;
2269     }
2270 
2271     private VersionRange createVersionRange() {
2272         try {
2273             return VersionRange.createFromVersionSpec("[4.7,)");
2274         } catch (InvalidVersionSpecificationException e) {
2275             throw new RuntimeException(e);
2276         }
2277     }
2278 
2279     private Artifact getJunitArtifact() {
2280         Artifact artifact = getProjectArtifactMap().get(getJunitArtifactName());
2281         Artifact projectArtifact = project.getArtifact();
2282         String projectArtifactName = projectArtifact.getGroupId() + ":" + projectArtifact.getArtifactId();
2283 
2284         if (artifact == null && projectArtifactName.equals(getJunitArtifactName())) {
2285             artifact = projectArtifact;
2286         }
2287 
2288         return artifact;
2289     }
2290 
2291     private Artifact getJunitDepArtifact() {
2292         return getProjectArtifactMap().get("junit:junit-dep");
2293     }
2294 
2295     private Artifact getJUnitPlatformRunnerArtifact() {
2296         return getProjectArtifactMap().get("org.junit.platform:junit-platform-runner");
2297     }
2298 
2299     private Artifact getJUnit5Artifact() {
2300         Artifact artifact = getPluginArtifactMap().get("org.junit.platform:junit-platform-engine");
2301         if (artifact == null) {
2302             return getProjectArtifactMap().get("org.junit.platform:junit-platform-commons");
2303         }
2304 
2305         return artifact;
2306     }
2307 
2308     private ForkStarter createForkStarter(
2309             @Nonnull ProviderInfo provider,
2310             @Nonnull ForkConfiguration forkConfiguration,
2311             @Nonnull ClassLoaderConfiguration classLoaderConfiguration,
2312             @Nonnull RunOrderParameters runOrderParameters,
2313             @Nonnull ConsoleLogger log,
2314             @Nonnull DefaultScanResult scanResult,
2315             @Nonnull TestClassPath testClasspathWrapper,
2316             @Nonnull Platform platform,
2317             @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult)
2318             throws MojoExecutionException, MojoFailureException {
2319         StartupConfiguration startupConfiguration = createStartupConfiguration(
2320                 provider,
2321                 true,
2322                 classLoaderConfiguration,
2323                 scanResult,
2324                 testClasspathWrapper,
2325                 platform,
2326                 resolvedJavaModularityResult);
2327         String configChecksum = getConfigChecksum();
2328         StartupReportConfiguration startupReportConfiguration =
2329                 getStartupReportConfiguration(configChecksum, true, provider);
2330 
2331         ProviderConfiguration providerConfiguration = createProviderConfiguration(runOrderParameters);
2332         return new ForkStarter(
2333                 providerConfiguration,
2334                 startupConfiguration,
2335                 forkConfiguration,
2336                 getForkedProcessTimeoutInSeconds(),
2337                 startupReportConfiguration,
2338                 log);
2339     }
2340 
2341     private InPluginVMSurefireStarter createInprocessStarter(
2342             @Nonnull ProviderInfo provider,
2343             @Nonnull ClassLoaderConfiguration classLoaderConfig,
2344             @Nonnull RunOrderParameters runOrderParameters,
2345             @Nonnull DefaultScanResult scanResult,
2346             @Nonnull Platform platform,
2347             @Nonnull TestClassPath testClasspathWrapper)
2348             throws MojoExecutionException, MojoFailureException {
2349         StartupConfiguration startupConfiguration = createStartupConfiguration(
2350                 provider,
2351                 false,
2352                 classLoaderConfig,
2353                 scanResult,
2354                 testClasspathWrapper,
2355                 platform,
2356                 new ResolvePathResultWrapper(null, true));
2357         String configChecksum = getConfigChecksum();
2358         StartupReportConfiguration startupReportConfiguration =
2359                 getStartupReportConfiguration(configChecksum, false, provider);
2360         ProviderConfiguration providerConfiguration = createProviderConfiguration(runOrderParameters);
2361         return new InPluginVMSurefireStarter(
2362                 startupConfiguration, providerConfiguration, startupReportConfiguration, getConsoleLogger(), platform);
2363     }
2364 
2365     
2366     @Nonnull
2367     private ForkNodeFactory getForkNodeFactory() {
2368         ForkNodeFactory forkNode = getForkNode();
2369         return forkNode == null ? new LegacyForkNodeFactory() : forkNode;
2370     }
2371 
2372     @Nonnull
2373     private ForkConfiguration createForkConfiguration(
2374             @Nonnull Platform platform, @Nonnull ResolvePathResultWrapper resolvedJavaModularityResult)
2375             throws MojoExecutionException {
2376         File tmpDir = getSurefireTempDir();
2377 
2378         Artifact shadeFire = getShadefireArtifact();
2379 
2380         Classpath bootClasspath = getArtifactClasspath(shadeFire != null ? shadeFire : getBooterArtifact());
2381 
2382         ForkNodeFactory forkNode = getForkNodeFactory();
2383 
2384         getConsoleLogger()
2385                 .debug("Found implementation of fork node factory: "
2386                         + forkNode.getClass().getName());
2387 
2388         if (canExecuteProviderWithModularPath(platform, resolvedJavaModularityResult)) {
2389             return new ModularClasspathForkConfiguration(
2390                     bootClasspath,
2391                     tmpDir,
2392                     getEffectiveDebugForkedProcess(),
2393                     getWorkingDirectory() != null ? getWorkingDirectory() : getBasedir(),
2394                     getProject().getModel().getProperties(),
2395                     getArgLine(),
2396                     getEnvironmentVariables(),
2397                     getExcludedEnvironmentVariables(),
2398                     getConsoleLogger().isDebugEnabled(),
2399                     getEffectiveForkCount(),
2400                     reuseForks,
2401                     platform,
2402                     getConsoleLogger(),
2403                     forkNode);
2404         } else if (getClassLoaderConfiguration().isManifestOnlyJarRequestedAndUsable()) {
2405             return new JarManifestForkConfiguration(
2406                     bootClasspath,
2407                     tmpDir,
2408                     getEffectiveDebugForkedProcess(),
2409                     getWorkingDirectory() != null ? getWorkingDirectory() : getBasedir(),
2410                     getProject().getModel().getProperties(),
2411                     getArgLine(),
2412                     getEnvironmentVariables(),
2413                     getExcludedEnvironmentVariables(),
2414                     getConsoleLogger().isDebugEnabled(),
2415                     getEffectiveForkCount(),
2416                     reuseForks,
2417                     platform,
2418                     getConsoleLogger(),
2419                     forkNode);
2420         } else {
2421             return new ClasspathForkConfiguration(
2422                     bootClasspath,
2423                     tmpDir,
2424                     getEffectiveDebugForkedProcess(),
2425                     getWorkingDirectory() != null ? getWorkingDirectory() : getBasedir(),
2426                     getProject().getModel().getProperties(),
2427                     getArgLine(),
2428                     getEnvironmentVariables(),
2429                     getExcludedEnvironmentVariables(),
2430                     getConsoleLogger().isDebugEnabled(),
2431                     getEffectiveForkCount(),
2432                     reuseForks,
2433                     platform,
2434                     getConsoleLogger(),
2435                     forkNode);
2436         }
2437     }
2438 
2439     private void ensureEnableProcessChecker() throws MojoFailureException {
2440         if (!ProcessCheckerType.isValid(getEnableProcessChecker())) {
2441             throw new MojoFailureException("Unexpected value '"
2442                     + getEnableProcessChecker()
2443                     + "' in the configuration parameter 'enableProcessChecker'.");
2444         }
2445     }
2446 
2447     @SuppressWarnings("checkstyle:emptyblock")
2448     protected int getEffectiveForkCount() {
2449         if (effectiveForkCount < 0) {
2450             try {
2451                 effectiveForkCount = convertWithCoreCount(forkCount);
2452             } catch (NumberFormatException ignored) {
2453             }
2454 
2455             if (effectiveForkCount < 0) {
2456                 throw new IllegalArgumentException("Fork count " + forkCount.trim() + " is not a legal value.");
2457             }
2458         }
2459 
2460         return effectiveForkCount;
2461     }
2462 
2463     protected int convertWithCoreCount(String count) {
2464         String trimmed = count.trim();
2465         if (trimmed.endsWith("C")) {
2466             double multiplier = Double.parseDouble(trimmed.substring(0, trimmed.length() - 1));
2467             double calculated = multiplier * ((double) Runtime.getRuntime().availableProcessors());
2468             return calculated > 0d ? Math.max((int) calculated, 1) : 0;
2469         } else {
2470             return parseInt(trimmed);
2471         }
2472     }
2473 
2474     private String getEffectiveDebugForkedProcess() {
2475         String debugForkedProcess = getDebugForkedProcess();
2476         if ("true".equals(debugForkedProcess)) {
2477             return "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:5005";
2478         }
2479         return debugForkedProcess;
2480     }
2481 
2482     private JdkAttributes getEffectiveJvm() throws MojoFailureException {
2483         if (isNotEmpty(getJvm())) {
2484             File pathToJava = new File(getJvm()).getAbsoluteFile();
2485             if (!endsWithJavaPath(pathToJava.getPath())) {
2486                 throw new MojoFailureException(
2487                         "Given path does not end with java executor \"" + pathToJava.getPath() + "\".");
2488             }
2489 
2490             if (!(pathToJava.isFile()
2491                     || "java".equals(pathToJava.getName())
2492                             && pathToJava.getParentFile().isDirectory())) {
2493                 throw new MojoFailureException(
2494                         "Given path to java executor does not exist \"" + pathToJava.getPath() + "\".");
2495             }
2496 
2497             File jdkHome = toJdkHomeFromJvmExec(pathToJava.getPath());
2498             if (jdkHome == null) {
2499                 getConsoleLogger().warning("Cannot determine JAVA_HOME of jvm exec path " + pathToJava);
2500             } else if (!getEnvironmentVariables().containsKey("JAVA_HOME")) {
2501                 getEnvironmentVariables().put("JAVA_HOME", jdkHome.getAbsolutePath());
2502             }
2503             BigDecimal version = jdkHome == null ? null : toJdkVersionFromReleaseFile(jdkHome);
2504             boolean javaVersion9 = version == null ? isJava9AtLeast(pathToJava.getPath()) : isJava9AtLeast(version);
2505             return new JdkAttributes(pathToJava, jdkHome, javaVersion9);
2506         }
2507 
2508         if (toolchain != null) {
2509             String jvmToUse = toolchain.findTool("java");
2510             if (isNotEmpty(jvmToUse)) {
2511                 boolean javaVersion9 = false;
2512                 String jdkHome = null;
2513 
2514                 if (toolchain instanceof DefaultToolchain) {
2515                     DefaultToolchain defaultToolchain = (DefaultToolchain) toolchain;
2516                     javaVersion9 = defaultToolchain.matchesRequirements(JAVA_9_MATCHER)
2517                             || defaultToolchain.matchesRequirements(JAVA_9_MATCHER_OLD_NOTATION);
2518                 }
2519 
2520                 if (toolchain instanceof DefaultJavaToolChain) {
2521                     DefaultJavaToolChain defaultJavaToolChain = (DefaultJavaToolChain) toolchain;
2522                     if (!getEnvironmentVariables().containsKey("JAVA_HOME")) {
2523                         jdkHome = defaultJavaToolChain.getJavaHome();
2524                         getEnvironmentVariables().put("JAVA_HOME", jdkHome);
2525                     }
2526                 }
2527 
2528                 if (!javaVersion9) {
2529                     javaVersion9 = isJava9AtLeast(jvmToUse);
2530                 }
2531 
2532                 return new JdkAttributes(
2533                         new File(jvmToUse),
2534                         jdkHome == null ? toJdkHomeFromJvmExec(jvmToUse) : new File(jdkHome),
2535                         javaVersion9);
2536             }
2537         }
2538 
2539         
2540         String jvmToUse = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
2541         getConsoleLogger().debug("Using JVM: " + jvmToUse + " with Java version " + JAVA_RECENT);
2542 
2543         return new JdkAttributes(jvmToUse, isBuiltInJava9AtLeast());
2544     }
2545 
2546     
2547 
2548 
2549 
2550 
2551     File getSurefireTempDir() {
2552         File result = IS_OS_WINDOWS ? createSurefireBootDirectoryInTemp() : createSurefireBootDirectoryInBuild();
2553         try {
2554             File canonical = result.getCanonicalFile();
2555             if (!result.equals(canonical)) {
2556                 getConsoleLogger().debug("Canonicalized tempDir path '" + result + "' to '" + canonical + "'");
2557             }
2558             return canonical;
2559         } catch (IOException e) {
2560             getConsoleLogger().error("Could not canonicalize tempDir path '" + result + "'", e);
2561         }
2562         return result;
2563     }
2564 
2565     
2566 
2567 
2568 
2569 
2570     private String getConfigChecksum() {
2571         ChecksumCalculator checksum = new ChecksumCalculator();
2572         checksum.add(getPluginName());
2573         checksum.add(isSkipTests());
2574         checksum.add(isSkipExec());
2575         checksum.add(isSkip());
2576         checksum.add(getTestClassesDirectory());
2577         checksum.add(getMainBuildPath());
2578         checksum.add(getClasspathDependencyExcludes());
2579         checksum.add(getClasspathDependencyScopeExclude());
2580         checksum.add(getAdditionalClasspathElements());
2581         checksum.add(getReportsDirectory());
2582         checksum.add(getProjectBuildDirectory());
2583         checksum.add(getTestSourceDirectory());
2584         checksum.add(getTest());
2585         checksum.add(getIncludes());
2586         checksum.add(getSkipAfterFailureCount());
2587         checksum.add(getShutdown());
2588         checksum.add(getExcludes());
2589         checksum.add(getLocalRepositoryPath());
2590         checksum.add(getSystemProperties());
2591         checksum.add(getSystemPropertyVariables());
2592         checksum.add(getSystemPropertiesFile());
2593         checksum.add(getProperties());
2594         checksum.add(isPrintSummary());
2595         checksum.add(getReportFormat());
2596         checksum.add(getReportNameSuffix());
2597         checksum.add(isUseFile());
2598         checksum.add(isRedirectTestOutputToFile());
2599         checksum.add(getForkCount());
2600         checksum.add(isReuseForks());
2601         checksum.add(getJvm());
2602         checksum.add(getArgLine());
2603         checksum.add(getDebugForkedProcess());
2604         checksum.add(getForkedProcessTimeoutInSeconds());
2605         checksum.add(getParallelTestsTimeoutInSeconds());
2606         checksum.add(getParallelTestsTimeoutForcedInSeconds());
2607         checksum.add(getEnvironmentVariables());
2608         checksum.add(getExcludedEnvironmentVariables());
2609         checksum.add(getWorkingDirectory());
2610         checksum.add(isChildDelegation());
2611         checksum.add(getGroups());
2612         checksum.add(getExcludedGroups());
2613         checksum.add(getIncludeJUnit5Engines());
2614         checksum.add(getExcludeJUnit5Engines());
2615         checksum.add(getSuiteXmlFiles());
2616         checksum.add(getJunitArtifact());
2617         checksum.add(getTestNGArtifactName());
2618         checksum.add(getThreadCount());
2619         checksum.add(getThreadCountSuites());
2620         checksum.add(getThreadCountClasses());
2621         checksum.add(getThreadCountMethods());
2622         checksum.add(getPerCoreThreadCount());
2623         checksum.add(getUseUnlimitedThreads());
2624         checksum.add(getParallel());
2625         checksum.add(isParallelOptimized());
2626         checksum.add(isTrimStackTrace());
2627         checksum.add(disableXmlReport);
2628         checksum.add(isUseSystemClassLoader());
2629         checksum.add(isUseManifestOnlyJar());
2630         checksum.add(getEncoding());
2631         checksum.add(isEnableAssertions());
2632         checksum.add(getObjectFactory());
2633         checksum.add(getFailIfNoTests());
2634         checksum.add(getRunOrder());
2635         checksum.add(getDependenciesToScan());
2636         checksum.add(getForkedProcessExitTimeoutInSeconds());
2637         checksum.add(getRerunFailingTestsCount());
2638         checksum.add(getTempDir());
2639         checksum.add(useModulePath());
2640         checksum.add(getEnableProcessChecker());
2641         checksum.add(isEnableOutErrElements());
2642         checksum.add(isEnablePropertiesElement());
2643         addPluginSpecificChecksumItems(checksum);
2644         return checksum.getSha1();
2645     }
2646 
2647     protected void addPluginSpecificChecksumItems(ChecksumCalculator checksum) {}
2648 
2649     protected boolean hasExecutedBefore() {
2650         
2651         String configChecksum = getConfigChecksum();
2652         @SuppressWarnings("unchecked")
2653         Map<String, String> pluginContext = getPluginContext();
2654         if (pluginContext.containsKey(configChecksum)) {
2655             getConsoleLogger()
2656                     .info("Skipping execution of surefire because it has already been run for this configuration");
2657             return true;
2658         }
2659         pluginContext.put(configChecksum, configChecksum);
2660 
2661         return false;
2662     }
2663 
2664     @Nonnull
2665     protected ClassLoaderConfiguration getClassLoaderConfiguration() {
2666         return isForking()
2667                 ? new ClassLoaderConfiguration(isUseSystemClassLoader(), isUseManifestOnlyJar())
2668                 : new ClassLoaderConfiguration(false, false);
2669     }
2670 
2671     
2672 
2673 
2674 
2675 
2676 
2677     private TestClassPath generateTestClasspath() throws MojoFailureException {
2678         Set<Artifact> classpathArtifacts = getProject().getArtifacts();
2679 
2680         if (getClasspathDependencyScopeExclude() != null
2681                 && !getClasspathDependencyScopeExclude().isEmpty()) {
2682             ArtifactFilter dependencyFilter = new ScopeArtifactFilter(getClasspathDependencyScopeExclude());
2683             classpathArtifacts = filterArtifacts(classpathArtifacts, dependencyFilter);
2684         }
2685 
2686         if (getClasspathDependencyExcludes() != null) {
2687             List<String> excludedDependencies = asList(getClasspathDependencyExcludes());
2688             ArtifactFilter dependencyFilter = new PatternIncludesArtifactFilter(excludedDependencies);
2689             classpathArtifacts = filterArtifacts(classpathArtifacts, dependencyFilter);
2690         }
2691 
2692         Map<String, Artifact> dependencyConflictIdsProjectArtifacts = classpathArtifacts.stream()
2693                 .collect(Collectors.toMap(Artifact::getDependencyConflictId, Function.identity()));
2694         Set<String> additionalClasspathElements = new LinkedHashSet<>();
2695         if (getAdditionalClasspathElements() != null) {
2696             Arrays.stream(getAdditionalClasspathElements()).forEach(additionalClasspathElements::add);
2697         }
2698         if (additionalClasspathDependencies != null && !additionalClasspathDependencies.isEmpty()) {
2699             Collection<Artifact> additionalArtifacts = resolveDependencies(additionalClasspathDependencies);
2700             
2701             for (Artifact additionalArtifact : additionalArtifacts) {
2702                 Artifact conflictingArtifact =
2703                         dependencyConflictIdsProjectArtifacts.get(additionalArtifact.getDependencyConflictId());
2704                 if (conflictingArtifact != null
2705                         && !additionalArtifact.getVersion().equals(conflictingArtifact.getVersion())) {
2706                     getConsoleLogger()
2707                             .warning(
2708                                     "Potential classpath conflict between project dependency and resolved additionalClasspathDependency: Found multiple versions of "
2709                                             + additionalArtifact.getDependencyConflictId() + ": "
2710                                             + additionalArtifact.getVersion() + " and "
2711                                             + conflictingArtifact.getVersion());
2712                 }
2713                 additionalClasspathElements.add(additionalArtifact.getFile().getAbsolutePath());
2714             }
2715         }
2716         return new TestClassPath(
2717                 classpathArtifacts, getMainBuildPath(), getTestClassesDirectory(), additionalClasspathElements);
2718     }
2719 
2720     protected Collection<Artifact> resolveDependencies(List<Dependency> dependencies) throws MojoFailureException {
2721         Map<String, Artifact> dependencyConflictIdsAndArtifacts = new HashMap<>();
2722         try {
2723             dependencies.stream()
2724                     .map(dependency -> {
2725                         try {
2726                             return surefireDependencyResolver.resolveDependencies(
2727                                     session.getRepositorySession(), project.getRemoteProjectRepositories(), dependency);
2728                         } catch (MojoExecutionException e) {
2729                             throw new IllegalStateException(e);
2730                         }
2731                     })
2732                     .forEach(artifacts -> {
2733                         for (Artifact a : artifacts) {
2734                             Artifact conflictingArtifact =
2735                                     dependencyConflictIdsAndArtifacts.get(a.getDependencyConflictId());
2736                             if (conflictingArtifact != null
2737                                     && !a.getVersion().equals(conflictingArtifact.getVersion())) {
2738                                 getConsoleLogger()
2739                                         .warning(
2740                                                 "Potential classpath conflict among resolved additionalClasspathDependencies: Found multiple versions of "
2741                                                         + a.getDependencyConflictId() + ": " + a.getVersion() + " and "
2742                                                         + conflictingArtifact.getVersion());
2743                             } else {
2744                                 dependencyConflictIdsAndArtifacts.put(a.getDependencyConflictId(), a);
2745                             }
2746                         }
2747                     });
2748         } catch (IllegalStateException e) {
2749             throw new MojoFailureException(e.getMessage(), e.getCause());
2750         }
2751         return dependencyConflictIdsAndArtifacts.values();
2752     }
2753 
2754     
2755 
2756 
2757 
2758 
2759 
2760 
2761     private static Set<Artifact> filterArtifacts(Set<Artifact> artifacts, ArtifactFilter filter) {
2762         Set<Artifact> filteredArtifacts = new LinkedHashSet<>();
2763 
2764         for (Artifact artifact : artifacts) {
2765             if (!filter.include(artifact)) {
2766                 filteredArtifacts.add(artifact);
2767             }
2768         }
2769 
2770         return filteredArtifacts;
2771     }
2772 
2773     private void showMap(Map<?, ?> map, String setting) {
2774         for (Object o : map.keySet()) {
2775             String key = (String) o;
2776             String value = (String) map.get(key);
2777             getConsoleLogger().debug("Setting " + setting + " [" + key + "]=[" + value + "]");
2778         }
2779     }
2780 
2781     private <T> void showArray(T[] array, String setting) {
2782         for (T e : array) {
2783             getConsoleLogger().debug("Setting " + setting + " [" + e + "]");
2784         }
2785     }
2786 
2787     private Classpath getArtifactClasspath(Artifact surefireArtifact) throws MojoExecutionException {
2788         Classpath existing = classpathCache.getCachedClassPath(surefireArtifact.getArtifactId());
2789         if (existing == null) {
2790             List<String> items = new ArrayList<>();
2791             Set<Artifact> booterArtifacts = surefireDependencyResolver.resolveArtifacts(
2792                     session.getRepositorySession(), project.getRemotePluginRepositories(), surefireArtifact);
2793             for (Artifact artifact : booterArtifacts) {
2794                 items.add(artifact.getFile().getAbsolutePath());
2795             }
2796             existing = new Classpath(items);
2797             classpathCache.setCachedClasspath(surefireArtifact.getArtifactId(), existing);
2798         }
2799         return existing;
2800     }
2801 
2802     Properties getUserProperties() {
2803         return getSession().getUserProperties();
2804     }
2805 
2806     private void ensureWorkingDirectoryExists() throws MojoFailureException {
2807         if (getWorkingDirectory() == null) {
2808             throw new MojoFailureException("workingDirectory cannot be null");
2809         }
2810 
2811         if (isForking()) {
2812             
2813             
2814             return;
2815         }
2816 
2817         if (!getWorkingDirectory().exists()) {
2818             if (!getWorkingDirectory().mkdirs()) {
2819                 throw new MojoFailureException("Cannot create workingDirectory " + getWorkingDirectory());
2820             }
2821         }
2822 
2823         if (!getWorkingDirectory().isDirectory()) {
2824             throw new MojoFailureException(
2825                     "workingDirectory " + getWorkingDirectory() + " exists and is not a directory");
2826         }
2827     }
2828 
2829     private void ensureParallelRunningCompatibility() throws MojoFailureException {
2830         if (isMavenParallel() && isNotForking()) {
2831             throw new MojoFailureException("parallel maven execution is not compatible with surefire forkCount 0");
2832         }
2833     }
2834 
2835     private void warnIfUselessUseSystemClassLoaderParameter() {
2836         if (isUseSystemClassLoader() && isNotForking()) {
2837             getConsoleLogger().warning("useSystemClassLoader setting has no effect when not forking");
2838         }
2839     }
2840 
2841     private boolean isNotForking() {
2842         return !isForking();
2843     }
2844 
2845     private List<CommandLineOption> commandLineOptions() {
2846         return SurefireHelper.commandLineOptions(getSession(), getConsoleLogger());
2847     }
2848 
2849     private void warnIfDefunctGroupsCombinations() throws MojoFailureException, MojoExecutionException {
2850         if (isAnyGroupsSelected()) {
2851             if (getTestNgArtifact() == null) {
2852                 Artifact junitArtifact = getJunitArtifact();
2853                 boolean junit47Compatible = isJunit47Compatible(junitArtifact);
2854                 boolean junit5PlatformCompatible = getJUnit5Artifact() != null;
2855                 if (!junit47Compatible && !junit5PlatformCompatible) {
2856                     if (junitArtifact != null) {
2857                         throw new MojoFailureException("groups/excludedGroups are specified but JUnit version on "
2858                                 + "classpath is too old to support groups. "
2859                                 + "Check your dependency:tree to see if your project "
2860                                 + "is picking up an old junit version");
2861                     }
2862                     throw new MojoFailureException("groups/excludedGroups require TestNG, JUnit48+ or JUnit 5 "
2863                             + "(a specific engine required on classpath) on project test classpath");
2864                 }
2865             }
2866         }
2867     }
2868 
2869     private void warnIfRerunClashes() throws MojoFailureException {
2870         if (getRerunFailingTestsCount() < 0) {
2871             throw new MojoFailureException("Parameter \"rerunFailingTestsCount\" should not be negative.");
2872         }
2873 
2874         if (getSkipAfterFailureCount() < 0) {
2875             throw new MojoFailureException("Parameter \"skipAfterFailureCount\" should not be negative.");
2876         }
2877     }
2878 
2879     private void warnIfWrongShutdownValue() throws MojoFailureException {
2880         if (!Shutdown.isKnown(getShutdown())) {
2881             throw new MojoFailureException("Parameter \"shutdown\" should have values " + Shutdown.listParameters());
2882         }
2883     }
2884 
2885     private void warnIfNotApplicableSkipAfterFailureCount() throws MojoFailureException {
2886         int skipAfterFailureCount = getSkipAfterFailureCount();
2887 
2888         if (skipAfterFailureCount < 0) {
2889             throw new MojoFailureException("Parameter \"skipAfterFailureCount\" should not be negative.");
2890         } else if (skipAfterFailureCount > 0) {
2891             try {
2892                 Artifact testng = getTestNgArtifact();
2893                 if (testng != null) {
2894                     VersionRange range = VersionRange.createFromVersionSpec("[5.10,)");
2895                     if (!range.containsVersion(new DefaultArtifactVersion(testng.getVersion()))) {
2896                         throw new MojoFailureException(
2897                                 "Parameter \"skipAfterFailureCount\" expects TestNG Version 5.10 or higher. "
2898                                         + "java.lang.NoClassDefFoundError: org/testng/IInvokedMethodListener");
2899                     }
2900                 } else {
2901                     
2902                     Artifact junit = getJunitArtifact();
2903                     if (junit != null) {
2904                         VersionRange range = VersionRange.createFromVersionSpec("[4.0,)");
2905                         if (!range.containsVersion(new DefaultArtifactVersion(junit.getVersion()))) {
2906                             throw new MojoFailureException(
2907                                     "Parameter \"skipAfterFailureCount\" expects JUnit Version 4.0 or higher. "
2908                                             + "java.lang.NoSuchMethodError: "
2909                                             + "org.junit.runner.notification.RunNotifier.pleaseStop()V");
2910                         }
2911                     }
2912                 }
2913             } catch (MojoExecutionException e) {
2914                 throw new MojoFailureException(e.getLocalizedMessage());
2915             } catch (InvalidVersionSpecificationException e) {
2916                 throw new RuntimeException(e);
2917             }
2918         }
2919     }
2920 
2921     private void warnIfIllegalTempDir() throws MojoFailureException {
2922         if (isEmpty(getTempDir())) {
2923             throw new MojoFailureException("Parameter 'tempDir' should not be blank string.");
2924         }
2925     }
2926 
2927     protected void warnIfIllegalFailOnFlakeCount() throws MojoFailureException {}
2928 
2929     private void printDefaultSeedIfNecessary() {
2930         if (getRunOrder().equals(RunOrder.RANDOM.name())) {
2931             if (getRunOrderRandomSeed() == null) {
2932                 setRunOrderRandomSeed(System.nanoTime());
2933             }
2934             getConsoleLogger()
2935                     .info("Tests will run in random order. To reproduce ordering use flag -D" + getPluginName()
2936                             + ".runOrder.random.seed=" + getRunOrderRandomSeed());
2937         }
2938     }
2939 
2940     final class TestNgProviderInfo implements ProviderInfo {
2941         private final Artifact testNgArtifact;
2942 
2943         TestNgProviderInfo(Artifact testNgArtifact) {
2944             this.testNgArtifact = testNgArtifact;
2945         }
2946 
2947         @Override
2948         @Nonnull
2949         public String getProviderName() {
2950             return "org.apache.maven.surefire.testng.TestNGProvider";
2951         }
2952 
2953         @Override
2954         public boolean isApplicable() {
2955             return testNgArtifact != null;
2956         }
2957 
2958         @Override
2959         public void addProviderProperties() throws MojoExecutionException {
2960             convertTestNGParameters();
2961         }
2962 
2963         @Nonnull
2964         @Override
2965         public List<String[]> getJpmsArguments(@Nonnull ProviderRequirements forkRequirements) {
2966             return emptyList();
2967         }
2968 
2969         @Override
2970         @Nonnull
2971         public Set<Artifact> getProviderClasspath() throws MojoExecutionException {
2972             Artifact surefireArtifact = getBooterArtifact();
2973             String version = surefireArtifact.getBaseVersion();
2974             return surefireDependencyResolver.getProviderClasspath(
2975                     session.getRepositorySession(), project.getRemotePluginRepositories(), "surefire-testng", version);
2976         }
2977     }
2978 
2979     final class JUnit3ProviderInfo implements ProviderInfo {
2980         @Override
2981         @Nonnull
2982         public String getProviderName() {
2983             return "org.apache.maven.surefire.junit.JUnit3Provider";
2984         }
2985 
2986         @Override
2987         public boolean isApplicable() {
2988             return true;
2989         }
2990 
2991         @Override
2992         public void addProviderProperties() {}
2993 
2994         @Nonnull
2995         @Override
2996         public List<String[]> getJpmsArguments(@Nonnull ProviderRequirements forkRequirements) {
2997             return emptyList();
2998         }
2999 
3000         @Override
3001         @Nonnull
3002         public Set<Artifact> getProviderClasspath() throws MojoExecutionException {
3003             
3004             
3005             String version = getBooterArtifact().getBaseVersion();
3006             return surefireDependencyResolver.getProviderClasspath(
3007                     session.getRepositorySession(), project.getRemotePluginRepositories(), "surefire-junit3", version);
3008         }
3009     }
3010 
3011     final class JUnit4ProviderInfo implements ProviderInfo {
3012         private final Artifact junitArtifact;
3013 
3014         private final Artifact junitDepArtifact;
3015 
3016         JUnit4ProviderInfo(Artifact junitArtifact, Artifact junitDepArtifact) {
3017             this.junitArtifact = junitArtifact;
3018             this.junitDepArtifact = junitDepArtifact;
3019         }
3020 
3021         @Override
3022         @Nonnull
3023         public String getProviderName() {
3024             return "org.apache.maven.surefire.junit4.JUnit4Provider";
3025         }
3026 
3027         @Override
3028         public boolean isApplicable() {
3029             return junitDepArtifact != null || isAnyJunit4(junitArtifact);
3030         }
3031 
3032         @Override
3033         public void addProviderProperties() {}
3034 
3035         @Nonnull
3036         @Override
3037         public List<String[]> getJpmsArguments(@Nonnull ProviderRequirements forkRequirements) {
3038             return emptyList();
3039         }
3040 
3041         @Override
3042         @Nonnull
3043         public Set<Artifact> getProviderClasspath() throws MojoExecutionException {
3044             String version = getBooterArtifact().getBaseVersion();
3045             return surefireDependencyResolver.getProviderClasspath(
3046                     session.getRepositorySession(), project.getRemotePluginRepositories(), "surefire-junit4", version);
3047         }
3048     }
3049 
3050     class JUnitPlatformProviderInfo implements ProviderInfo {
3051         private static final String PROVIDER_DEP_GID = "org.junit.platform";
3052         private static final String PROVIDER_DEP_AID = "junit-platform-launcher";
3053 
3054         private final Artifact junitPlatformRunnerArtifact;
3055         private final Artifact junitPlatformArtifact;
3056         private final TestClassPath testClasspath;
3057 
3058         JUnitPlatformProviderInfo(
3059                 Artifact junitPlatformRunnerArtifact,
3060                 Artifact junitPlatformArtifact,
3061                 @Nonnull TestClassPath testClasspath) {
3062             this.junitPlatformRunnerArtifact = junitPlatformRunnerArtifact;
3063             this.junitPlatformArtifact = junitPlatformArtifact;
3064             this.testClasspath = testClasspath;
3065         }
3066 
3067         @Override
3068         @Nonnull
3069         public String getProviderName() {
3070             return "org.apache.maven.surefire.junitplatform.JUnitPlatformProvider";
3071         }
3072 
3073         protected String getProviderArtifactName() {
3074             return "surefire-junit-platform";
3075         }
3076 
3077         @Override
3078         public boolean isApplicable() {
3079             return junitPlatformRunnerArtifact == null && junitPlatformArtifact != null;
3080         }
3081 
3082         @Override
3083         public void addProviderProperties() {
3084             convertGroupParameters();
3085             convertJunitEngineParameters();
3086         }
3087 
3088         @Nonnull
3089         @Override
3090         public List<String[]> getJpmsArguments(@Nonnull ProviderRequirements forkRequirements) {
3091             boolean hasTestDescriptor = forkRequirements.isModularPath() && forkRequirements.hasTestModuleDescriptor();
3092             return hasTestDescriptor ? getJpmsArgs() : Collections.<String[]>emptyList();
3093         }
3094 
3095         @Override
3096         @Nonnull
3097         public Set<Artifact> getProviderClasspath() throws MojoExecutionException {
3098             String surefireVersion = getBooterArtifact().getBaseVersion();
3099             Map<String, Artifact> providerArtifacts = surefireDependencyResolver.getProviderClasspathAsMap(
3100                     session.getRepositorySession(),
3101                     project.getRemotePluginRepositories(),
3102                     getProviderArtifactName(),
3103                     surefireVersion);
3104             Map<String, Artifact> testDeps = testClasspath.getTestDependencies();
3105 
3106             Plugin plugin = getPluginDescriptor().getPlugin();
3107             Map<String, Artifact> pluginDeps = surefireDependencyResolver.resolvePluginDependencies(
3108                     session.getRepositorySession(),
3109                     project.getRemotePluginRepositories(),
3110                     plugin,
3111                     getPluginArtifactMap());
3112 
3113             if (hasDependencyPlatformEngine(pluginDeps)) {
3114                 providerArtifacts.putAll(pluginDeps);
3115             } else {
3116                 String engineVersion = null;
3117                 if (hasDependencyJupiterAPI(testDeps)
3118                         && !testDeps.containsKey("org.junit.jupiter:junit-jupiter-engine")) {
3119                     String engineGroupId = "org.junit.jupiter";
3120                     String engineArtifactId = "junit-jupiter-engine";
3121                     String engineCoordinates = engineGroupId + ":" + engineArtifactId;
3122                     String api = "org.junit.jupiter:junit-jupiter-api";
3123                     engineVersion = testDeps.get(api).getBaseVersion();
3124                     getConsoleLogger()
3125                             .debug("Test dependencies contain " + api + ". Resolving " + engineCoordinates + ":"
3126                                     + engineVersion);
3127                     addEngineByApi(engineGroupId, engineArtifactId, engineVersion, providerArtifacts);
3128                 }
3129 
3130                 if ((testDeps.containsKey("junit:junit") || testDeps.containsKey("junit:junit-dep"))
3131                         && !testDeps.containsKey("org.junit.vintage:junit-vintage-engine")) {
3132                     String engineGroupId = "org.junit.vintage";
3133                     String engineArtifactId = "junit-vintage-engine";
3134                     String engineCoordinates = engineGroupId + ":" + engineArtifactId;
3135 
3136                     if (engineVersion != null) {
3137                         getConsoleLogger()
3138                                 .debug("Test dependencies contain JUnit4. Resolving " + engineCoordinates + ":"
3139                                         + engineVersion);
3140                         addEngineByApi(engineGroupId, engineArtifactId, engineVersion, providerArtifacts);
3141                     }
3142                 }
3143             }
3144 
3145             narrowDependencies(providerArtifacts, testDeps);
3146             alignProviderVersions(providerArtifacts);
3147 
3148             return new LinkedHashSet<>(providerArtifacts.values());
3149         }
3150 
3151         private List<String[]> getJpmsArgs() {
3152             List<String[]> args = new ArrayList<>();
3153 
3154             args.add(new String[] {
3155                 "--add-opens", "org.junit.platform.commons/org.junit.platform.commons.util=ALL-UNNAMED"
3156             });
3157 
3158             args.add(new String[] {
3159                 "--add-opens", "org.junit.platform.commons/org.junit.platform.commons.logging=ALL-UNNAMED"
3160             });
3161 
3162             return args;
3163         }
3164 
3165         private void addEngineByApi(
3166                 String engineGroupId,
3167                 String engineArtifactId,
3168                 String engineVersion,
3169                 Map<String, Artifact> providerArtifacts)
3170                 throws MojoExecutionException {
3171             for (Artifact dep : resolve(engineGroupId, engineArtifactId, engineVersion, null, "jar")) {
3172                 String key = dep.getGroupId() + ":" + dep.getArtifactId();
3173                 providerArtifacts.put(key, dep);
3174             }
3175         }
3176 
3177         private void narrowDependencies(
3178                 Map<String, Artifact> providerArtifacts, Map<String, Artifact> testDependencies) {
3179             providerArtifacts.keySet().removeAll(testDependencies.keySet());
3180         }
3181 
3182         protected void alignProviderVersions(Map<String, Artifact> providerArtifacts) throws MojoExecutionException {
3183             String version = junitPlatformArtifact.getBaseVersion();
3184             for (Artifact launcherArtifact : resolve(PROVIDER_DEP_GID, PROVIDER_DEP_AID, version, null, "jar")) {
3185                 String key = launcherArtifact.getGroupId() + ":" + launcherArtifact.getArtifactId();
3186                 if (providerArtifacts.containsKey(key)) {
3187                     providerArtifacts.put(key, launcherArtifact);
3188                 }
3189             }
3190         }
3191 
3192         private Set<Artifact> resolve(String g, String a, String v, String c, String t) throws MojoExecutionException {
3193             ArtifactHandler handler = junitPlatformArtifact.getArtifactHandler();
3194             Artifact artifact = new DefaultArtifact(g, a, v, null, t, c, handler);
3195             getConsoleLogger().debug("Resolving artifact " + g + ":" + a + ":" + v);
3196             Set<Artifact> r = surefireDependencyResolver.resolveArtifacts(
3197                     session.getRepositorySession(), project.getRemoteProjectRepositories(), artifact);
3198             getConsoleLogger().debug("Resolved artifact " + g + ":" + a + ":" + v + " to " + r);
3199             return r;
3200         }
3201 
3202         private boolean hasDependencyJupiterAPI(Map<String, Artifact> dependencies) {
3203             return dependencies.containsKey("org.junit.jupiter:junit-jupiter-api");
3204         }
3205 
3206         private boolean hasDependencyPlatformEngine(Map<String, Artifact> dependencies) {
3207             for (Entry<String, Artifact> dependency : dependencies.entrySet()) {
3208                 if (dependency.getKey().equals("org.junit.platform:junit-platform-engine")) {
3209                     return true;
3210                 }
3211             }
3212 
3213             return false;
3214         }
3215     }
3216 
3217     final class JUnitPlatformProviderShadefireInfo extends JUnitPlatformProviderInfo {
3218 
3219         JUnitPlatformProviderShadefireInfo(
3220                 Artifact junitPlatformRunnerArtifact,
3221                 Artifact junitPlatformArtifact,
3222                 @Nonnull TestClassPath testClasspath) {
3223             super(junitPlatformRunnerArtifact, junitPlatformArtifact, testClasspath);
3224         }
3225 
3226         @Override
3227         public boolean isApplicable() {
3228             
3229             return false;
3230         }
3231 
3232         @Override
3233         @Nonnull
3234         public String getProviderName() {
3235             return "org.apache.maven.shadefire.surefire.junitplatform.JUnitPlatformProvider";
3236         }
3237 
3238         @Override
3239         protected String getProviderArtifactName() {
3240             return "surefire-shadefire";
3241         }
3242 
3243         @Override
3244         protected void alignProviderVersions(Map<String, Artifact> providerArtifacts) throws MojoExecutionException {
3245             
3246             
3247             providerArtifacts.put("org.junit.platform:junit-platform-launcher", null);
3248             super.alignProviderVersions(providerArtifacts);
3249         }
3250     }
3251 
3252     final class JUnitCoreProviderInfo implements ProviderInfo {
3253         private final Artifact junitArtifact;
3254 
3255         private final Artifact junitDepArtifact;
3256 
3257         JUnitCoreProviderInfo(Artifact junitArtifact, Artifact junitDepArtifact) {
3258             this.junitArtifact = junitArtifact;
3259             this.junitDepArtifact = junitDepArtifact;
3260         }
3261 
3262         @Override
3263         @Nonnull
3264         public String getProviderName() {
3265             return "org.apache.maven.surefire.junitcore.JUnitCoreProvider";
3266         }
3267 
3268         private boolean is47CompatibleJunitDep() {
3269             return isJunit47Compatible(junitDepArtifact);
3270         }
3271 
3272         @Override
3273         public boolean isApplicable() {
3274             final boolean isJunitArtifact47 = isAnyJunit4(junitArtifact) && isJunit47Compatible(junitArtifact);
3275             final boolean isAny47ProvidersForces = isAnyConcurrencySelected() || isAnyGroupsSelected();
3276             return isAny47ProvidersForces && (isJunitArtifact47 || is47CompatibleJunitDep());
3277         }
3278 
3279         @Override
3280         public void addProviderProperties() throws MojoExecutionException {
3281             convertJunitCoreParameters();
3282             convertGroupParameters();
3283             convertJunitEngineParameters();
3284         }
3285 
3286         @Nonnull
3287         @Override
3288         public List<String[]> getJpmsArguments(@Nonnull ProviderRequirements forkRequirements) {
3289             return emptyList();
3290         }
3291 
3292         @Override
3293         @Nonnull
3294         public Set<Artifact> getProviderClasspath() throws MojoExecutionException {
3295             String version = getBooterArtifact().getBaseVersion();
3296             return surefireDependencyResolver.getProviderClasspath(
3297                     session.getRepositorySession(), project.getRemotePluginRepositories(), "surefire-junit47", version);
3298         }
3299     }
3300 
3301     
3302 
3303 
3304     final class DynamicProviderInfo implements ConfigurableProviderInfo {
3305         final String providerName;
3306 
3307         DynamicProviderInfo(String providerName) {
3308             this.providerName = providerName;
3309         }
3310 
3311         @Override
3312         public ProviderInfo instantiate(String providerName) {
3313             return new DynamicProviderInfo(providerName);
3314         }
3315 
3316         @Override
3317         @Nonnull
3318         public String getProviderName() {
3319             return providerName;
3320         }
3321 
3322         @Override
3323         public boolean isApplicable() {
3324             return true;
3325         }
3326 
3327         @Override
3328         public void addProviderProperties() throws MojoExecutionException {
3329             
3330             convertJunitCoreParameters();
3331             convertTestNGParameters();
3332         }
3333 
3334         @Nonnull
3335         @Override
3336         public List<String[]> getJpmsArguments(@Nonnull ProviderRequirements forkRequirements) {
3337             return emptyList();
3338         }
3339 
3340         @Override
3341         @Nonnull
3342         public Set<Artifact> getProviderClasspath() throws MojoExecutionException {
3343             Plugin plugin = getPluginDescriptor().getPlugin();
3344             Map<String, Artifact> providerArtifacts = surefireDependencyResolver.resolvePluginDependencies(
3345                     session.getRepositorySession(),
3346                     project.getRemotePluginRepositories(),
3347                     plugin,
3348                     getPluginArtifactMap());
3349             return new LinkedHashSet<>(providerArtifacts.values());
3350         }
3351     }
3352 
3353     File createSurefireBootDirectoryInBuild() {
3354         File tmp = new File(getProjectBuildDirectory(), getTempDir());
3355         
3356         tmp.mkdirs();
3357         return tmp;
3358     }
3359 
3360     File createSurefireBootDirectoryInTemp() {
3361         try {
3362             return Files.createTempDirectory(getTempDir()).toFile();
3363         } catch (IOException e) {
3364             return createSurefireBootDirectoryInBuild();
3365         }
3366     }
3367 
3368     @Override
3369     public String getLocalRepositoryPath() {
3370         return Optional.ofNullable(
3371                         session.getRepositorySession().getLocalRepository().getBasedir())
3372                 .map(File::getAbsolutePath)
3373                 .orElse(".");
3374     }
3375 
3376     public Properties getSystemProperties() {
3377         return systemProperties;
3378     }
3379 
3380     @SuppressWarnings("UnusedDeclaration")
3381     public void setSystemProperties(Properties systemProperties) {
3382         this.systemProperties = systemProperties;
3383     }
3384 
3385     public Map<String, String> getSystemPropertyVariables() {
3386         return systemPropertyVariables;
3387     }
3388 
3389     @SuppressWarnings("UnusedDeclaration")
3390     public void setSystemPropertyVariables(Map<String, String> systemPropertyVariables) {
3391         this.systemPropertyVariables = systemPropertyVariables;
3392     }
3393 
3394     
3395 
3396 
3397 
3398 
3399     public abstract File getSystemPropertiesFile();
3400 
3401     @SuppressWarnings("UnusedDeclaration")
3402     public abstract void setSystemPropertiesFile(File systemPropertiesFile);
3403 
3404     private Properties getProperties() {
3405         return properties;
3406     }
3407 
3408     public void setProperties(Properties properties) {
3409         this.properties = properties;
3410     }
3411 
3412     public Map<String, Artifact> getPluginArtifactMap() {
3413         return pluginArtifactMap;
3414     }
3415 
3416     @SuppressWarnings("UnusedDeclaration")
3417     public void setPluginArtifactMap(Map<String, Artifact> pluginArtifactMap) {
3418         this.pluginArtifactMap = pluginArtifactMap;
3419     }
3420 
3421     public Map<String, Artifact> getProjectArtifactMap() {
3422         return projectArtifactMap;
3423     }
3424 
3425     @SuppressWarnings("UnusedDeclaration")
3426     public void setProjectArtifactMap(Map<String, Artifact> projectArtifactMap) {
3427         this.projectArtifactMap = projectArtifactMap;
3428     }
3429 
3430     public String getReportNameSuffix() {
3431         return reportNameSuffix;
3432     }
3433 
3434     @SuppressWarnings("UnusedDeclaration")
3435     public void setReportNameSuffix(String reportNameSuffix) {
3436         this.reportNameSuffix = reportNameSuffix;
3437     }
3438 
3439     public boolean isRedirectTestOutputToFile() {
3440         return redirectTestOutputToFile;
3441     }
3442 
3443     @SuppressWarnings("UnusedDeclaration")
3444     public void setRedirectTestOutputToFile(boolean redirectTestOutputToFile) {
3445         this.redirectTestOutputToFile = redirectTestOutputToFile;
3446     }
3447 
3448     public boolean getFailIfNoTests() {
3449         return failIfNoTests;
3450     }
3451 
3452     public void setFailIfNoTests(boolean failIfNoTests) {
3453         this.failIfNoTests = failIfNoTests;
3454     }
3455 
3456     public String getJvm() {
3457         return jvm;
3458     }
3459 
3460     public String getArgLine() {
3461         return argLine;
3462     }
3463 
3464     @SuppressWarnings("UnusedDeclaration")
3465     public void setArgLine(String argLine) {
3466         this.argLine = argLine;
3467     }
3468 
3469     public Map<String, String> getEnvironmentVariables() {
3470         return environmentVariables;
3471     }
3472 
3473     @SuppressWarnings("UnusedDeclaration")
3474     public void setEnvironmentVariables(Map<String, String> environmentVariables) {
3475         this.environmentVariables = environmentVariables;
3476     }
3477 
3478     public File getWorkingDirectory() {
3479         return workingDirectory;
3480     }
3481 
3482     @SuppressWarnings("UnusedDeclaration")
3483     public void setWorkingDirectory(File workingDirectory) {
3484         this.workingDirectory = workingDirectory;
3485     }
3486 
3487     public boolean isChildDelegation() {
3488         return childDelegation;
3489     }
3490 
3491     @SuppressWarnings("UnusedDeclaration")
3492     public void setChildDelegation(boolean childDelegation) {
3493         this.childDelegation = childDelegation;
3494     }
3495 
3496     public String getGroups() {
3497         return groups;
3498     }
3499 
3500     @SuppressWarnings("UnusedDeclaration")
3501     public void setGroups(String groups) {
3502         this.groups = groups;
3503     }
3504 
3505     public String getExcludedGroups() {
3506         return excludedGroups;
3507     }
3508 
3509     @SuppressWarnings("UnusedDeclaration")
3510     public void setExcludedGroups(String excludedGroups) {
3511         this.excludedGroups = excludedGroups;
3512     }
3513 
3514     public String getJunitArtifactName() {
3515         return junitArtifactName;
3516     }
3517 
3518     @SuppressWarnings("UnusedDeclaration")
3519     public void setJunitArtifactName(String junitArtifactName) {
3520         this.junitArtifactName = junitArtifactName;
3521     }
3522 
3523     public String getTestNGArtifactName() {
3524         return testNGArtifactName;
3525     }
3526 
3527     @SuppressWarnings("UnusedDeclaration")
3528     public void setTestNGArtifactName(String testNGArtifactName) {
3529         this.testNGArtifactName = testNGArtifactName;
3530     }
3531 
3532     public int getThreadCount() {
3533         return threadCount;
3534     }
3535 
3536     @SuppressWarnings("UnusedDeclaration")
3537     public void setThreadCount(int threadCount) {
3538         this.threadCount = threadCount;
3539     }
3540 
3541     public boolean getPerCoreThreadCount() {
3542         return perCoreThreadCount;
3543     }
3544 
3545     @SuppressWarnings("UnusedDeclaration")
3546     public void setPerCoreThreadCount(boolean perCoreThreadCount) {
3547         this.perCoreThreadCount = perCoreThreadCount;
3548     }
3549 
3550     public boolean getUseUnlimitedThreads() {
3551         return useUnlimitedThreads;
3552     }
3553 
3554     @SuppressWarnings("UnusedDeclaration")
3555     public void setUseUnlimitedThreads(boolean useUnlimitedThreads) {
3556         this.useUnlimitedThreads = useUnlimitedThreads;
3557     }
3558 
3559     public String getParallel() {
3560         return parallel;
3561     }
3562 
3563     @SuppressWarnings("UnusedDeclaration")
3564     public void setParallel(String parallel) {
3565         this.parallel = parallel;
3566     }
3567 
3568     public boolean isParallelOptimized() {
3569         return parallelOptimized;
3570     }
3571 
3572     @SuppressWarnings("UnusedDeclaration")
3573     public void setParallelOptimized(boolean parallelOptimized) {
3574         this.parallelOptimized = parallelOptimized;
3575     }
3576 
3577     public int getThreadCountSuites() {
3578         return threadCountSuites;
3579     }
3580 
3581     public void setThreadCountSuites(int threadCountSuites) {
3582         this.threadCountSuites = threadCountSuites;
3583     }
3584 
3585     public int getThreadCountClasses() {
3586         return threadCountClasses;
3587     }
3588 
3589     public void setThreadCountClasses(int threadCountClasses) {
3590         this.threadCountClasses = threadCountClasses;
3591     }
3592 
3593     public int getThreadCountMethods() {
3594         return threadCountMethods;
3595     }
3596 
3597     public void setThreadCountMethods(int threadCountMethods) {
3598         this.threadCountMethods = threadCountMethods;
3599     }
3600 
3601     public boolean isTrimStackTrace() {
3602         return trimStackTrace;
3603     }
3604 
3605     @SuppressWarnings("UnusedDeclaration")
3606     public void setTrimStackTrace(boolean trimStackTrace) {
3607         this.trimStackTrace = trimStackTrace;
3608     }
3609 
3610     public boolean isEnableAssertions() {
3611         return enableAssertions;
3612     }
3613 
3614     public boolean effectiveIsEnableAssertions() {
3615         if (getArgLine() != null) {
3616             List<String> args = asList(getArgLine().split(" "));
3617             if (args.contains("-da") || args.contains("-disableassertions")) {
3618                 return false;
3619             }
3620         }
3621         return isEnableAssertions();
3622     }
3623 
3624     @SuppressWarnings("UnusedDeclaration")
3625     public void setEnableAssertions(boolean enableAssertions) {
3626         this.enableAssertions = enableAssertions;
3627     }
3628 
3629     public boolean isEnableOutErrElements() {
3630         return enableOutErrElements;
3631     }
3632 
3633     @SuppressWarnings("UnusedDeclaration")
3634     public void setEnableOutErrElements(boolean enableOutErrElements) {
3635         this.enableOutErrElements = enableOutErrElements;
3636     }
3637 
3638     public boolean isEnablePropertiesElement() {
3639         return enablePropertiesElement;
3640     }
3641 
3642     @SuppressWarnings("UnusedDeclaration")
3643     public void setEnablePropertiesElement(boolean enablePropertiesElement) {
3644         this.enablePropertiesElement = enablePropertiesElement;
3645     }
3646 
3647     public MavenSession getSession() {
3648         return session;
3649     }
3650 
3651     @SuppressWarnings("UnusedDeclaration")
3652     public void setSession(MavenSession session) {
3653         this.session = session;
3654     }
3655 
3656     public String getObjectFactory() {
3657         return objectFactory;
3658     }
3659 
3660     @SuppressWarnings("UnusedDeclaration")
3661     public void setObjectFactory(String objectFactory) {
3662         this.objectFactory = objectFactory;
3663     }
3664 
3665     public ToolchainManager getToolchainManager() {
3666         return toolchainManager;
3667     }
3668 
3669     @SuppressWarnings("UnusedDeclaration")
3670     public void setToolchainManager(ToolchainManager toolchainManager) {
3671         this.toolchainManager = toolchainManager;
3672     }
3673 
3674     public boolean isMavenParallel() {
3675         return parallelMavenExecution != null && parallelMavenExecution;
3676     }
3677 
3678     public String[] getDependenciesToScan() {
3679         return dependenciesToScan;
3680     }
3681 
3682     public void setDependenciesToScan(String[] dependenciesToScan) {
3683         this.dependenciesToScan = dependenciesToScan;
3684     }
3685 
3686     @SuppressWarnings("UnusedDeclaration")
3687     void setPluginDescriptor(PluginDescriptor pluginDescriptor) {
3688         this.pluginDescriptor = pluginDescriptor;
3689     }
3690 
3691     public PluginDescriptor getPluginDescriptor() {
3692         return pluginDescriptor;
3693     }
3694 
3695     public MavenProject getProject() {
3696         return project;
3697     }
3698 
3699     @SuppressWarnings("UnusedDeclaration")
3700     public void setProject(MavenProject project) {
3701         this.project = project;
3702     }
3703 
3704     @Override
3705     public File getTestSourceDirectory() {
3706         return testSourceDirectory;
3707     }
3708 
3709     @Override
3710     public void setTestSourceDirectory(File testSourceDirectory) {
3711         this.testSourceDirectory = testSourceDirectory;
3712     }
3713 
3714     public String getForkCount() {
3715         return forkCount;
3716     }
3717 
3718     public boolean isReuseForks() {
3719         return reuseForks;
3720     }
3721 
3722     public String[] getAdditionalClasspathElements() {
3723         return additionalClasspathElements;
3724     }
3725 
3726     public void setAdditionalClasspathElements(String[] additionalClasspathElements) {
3727         this.additionalClasspathElements = additionalClasspathElements;
3728     }
3729 
3730     public String[] getClasspathDependencyExcludes() {
3731         return classpathDependencyExcludes;
3732     }
3733 
3734     public void setClasspathDependencyExcludes(String[] classpathDependencyExcludes) {
3735         this.classpathDependencyExcludes = classpathDependencyExcludes;
3736     }
3737 
3738     public String getClasspathDependencyScopeExclude() {
3739         return classpathDependencyScopeExclude;
3740     }
3741 
3742     public void setClasspathDependencyScopeExclude(String classpathDependencyScopeExclude) {
3743         this.classpathDependencyScopeExclude = classpathDependencyScopeExclude;
3744     }
3745 
3746     public File getProjectBuildDirectory() {
3747         return projectBuildDirectory;
3748     }
3749 
3750     public void setProjectBuildDirectory(File projectBuildDirectory) {
3751         this.projectBuildDirectory = projectBuildDirectory;
3752     }
3753 
3754     protected void logDebugOrCliShowErrors(String s) {
3755         SurefireHelper.logDebugOrCliShowErrors(s, getConsoleLogger(), cli);
3756     }
3757 
3758     public Map<String, String> getJdkToolchain() {
3759         return jdkToolchain;
3760     }
3761 
3762     public void setJdkToolchain(Map<String, String> jdkToolchain) {
3763         this.jdkToolchain = jdkToolchain;
3764     }
3765 
3766     public String getTempDir() {
3767         return tempDir;
3768     }
3769 
3770     public void setTempDir(String tempDir) {
3771         this.tempDir = tempDir;
3772     }
3773 
3774     private static final class ClasspathCache {
3775         private final Map<String, Classpath> classpaths = new HashMap<>(4);
3776 
3777         private Classpath getCachedClassPath(@Nonnull String artifactId) {
3778             return classpaths.get(artifactId);
3779         }
3780 
3781         private void setCachedClasspath(@Nonnull String key, @Nonnull Classpath classpath) {
3782             classpaths.put(key, classpath);
3783         }
3784 
3785         private Classpath setCachedClasspath(@Nonnull String key, @Nonnull Set<Artifact> artifacts) {
3786             Collection<String> files = new ArrayList<>();
3787             for (Artifact artifact : artifacts) {
3788                 files.add(artifact.getFile().getAbsolutePath());
3789             }
3790             Classpath classpath = new Classpath(files);
3791             setCachedClasspath(key, classpath);
3792             return classpath;
3793         }
3794     }
3795 
3796     
3797 
3798 
3799     enum PluginFailureReason {
3800         NONE,
3801         COULD_NOT_RUN_SPECIFIED_TESTS,
3802         COULD_NOT_RUN_DEFAULT_TESTS,
3803     }
3804 }