1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc
.squirreljme
.plugin
.multivm
;
12 import cc
.squirreljme
.plugin
.SquirrelJMEPluginConfiguration
;
13 import cc
.squirreljme
.plugin
.general
.cmake
.CMakeBuildTask
;
14 import cc
.squirreljme
.plugin
.multivm
.ident
.SourceTargetClassifier
;
15 import cc
.squirreljme
.plugin
.multivm
.ident
.TargetClassifier
;
16 import cc
.squirreljme
.plugin
.swm
.JavaMEMidlet
;
17 import cc
.squirreljme
.plugin
.util
.FileLocation
;
18 import cc
.squirreljme
.plugin
.util
.TestDetection
;
19 import cc
.squirreljme
.plugin
.util
.UnassistedLaunchEntry
;
20 import java
.io
.BufferedReader
;
21 import java
.io
.ByteArrayInputStream
;
22 import java
.io
.ByteArrayOutputStream
;
24 import java
.io
.IOException
;
25 import java
.io
.InputStream
;
26 import java
.io
.InputStreamReader
;
27 import java
.io
.OutputStream
;
28 import java
.nio
.file
.Files
;
29 import java
.nio
.file
.Path
;
30 import java
.nio
.file
.Paths
;
31 import java
.nio
.file
.StandardOpenOption
;
32 import java
.util
.ArrayList
;
33 import java
.util
.Arrays
;
34 import java
.util
.Collection
;
35 import java
.util
.Collections
;
36 import java
.util
.HashMap
;
37 import java
.util
.HashSet
;
38 import java
.util
.LinkedHashMap
;
39 import java
.util
.LinkedHashSet
;
40 import java
.util
.LinkedList
;
41 import java
.util
.List
;
42 import java
.util
.Locale
;
44 import java
.util
.Objects
;
46 import java
.util
.TreeMap
;
47 import java
.util
.TreeSet
;
48 import java
.util
.concurrent
.Callable
;
49 import java
.util
.function
.Supplier
;
50 import java
.util
.jar
.Attributes
;
51 import java
.util
.jar
.Manifest
;
52 import java
.util
.regex
.Matcher
;
53 import java
.util
.regex
.Pattern
;
54 import java
.util
.stream
.Stream
;
55 import java
.util
.zip
.ZipEntry
;
56 import java
.util
.zip
.ZipInputStream
;
57 import java
.util
.zip
.ZipOutputStream
;
58 import org
.gradle
.api
.Project
;
59 import org
.gradle
.api
.Task
;
60 import org
.gradle
.api
.artifacts
.Configuration
;
61 import org
.gradle
.api
.artifacts
.Dependency
;
62 import org
.gradle
.api
.artifacts
.ProjectDependency
;
63 import org
.gradle
.api
.capabilities
.Capability
;
64 import org
.gradle
.api
.file
.FileCollection
;
65 import org
.gradle
.api
.provider
.Provider
;
66 import org
.gradle
.api
.tasks
.SourceSet
;
67 import org
.gradle
.jvm
.tasks
.Jar
;
70 * Helpers for the multi-VM handlers.
74 @SuppressWarnings("OverlyComplexClass")
75 public final class VMHelpers
77 /** The class used for single test runs. */
78 public static final String SINGLE_TEST_RUNNER
=
79 "net.multiphasicapps.tac.MainSingleRunner";
81 /** Source set name for test fixtures. */
82 public static final String TEST_FIXTURES_SOURCE_SET_NAME
=
85 /** Main configurations. */
86 private static final String
[] _MAIN_CONFIGS
=
87 new String
[]{"api", "implementation"};
89 /** Test configurations. */
90 private static final String
[] _TEST_CONFIGS
=
91 new String
[]{"testImplementation", "testImplementation"};
93 /** Declaration of hyper-test parameters. */
94 private static final String _HYPER_PARAMETERS_KEY
=
97 /** Declaration of multi-test parameters. */
98 private static final String _MULTI_PARAMETERS_KEY
=
101 /* Copy buffer size. */
102 public static final int COPY_BUFFER
=
115 * Returns a collection of the tests that are available.
117 * @param __project The project to check.
118 * @param __sourceSet The source set for the project.
119 * @return The list of available tests.
120 * @throws NullPointerException On null arguments.
123 public static Map
<String
, CandidateTestFiles
> availableTests(
124 Project __project
, String __sourceSet
)
125 throws NullPointerException
127 if (__project
== null || __sourceSet
== null)
128 throw new NullPointerException("NARG");
130 // Mappings of both source and expected files
131 Set
<String
> names
= new TreeSet
<>();
132 Map
<String
, FileLocation
> sources
= new HashMap
<>();
133 Map
<String
, FileLocation
> secondarySources
= new HashMap
<>();
134 Map
<String
, FileLocation
> expects
= new HashMap
<>();
136 // Setup initial set of sources and files for lookup
137 Set
<CandidateTestFileSource
> everything
= new LinkedHashSet
<>();
138 everything
.add(new CandidateTestFileSource(true,
139 TestDetection
.sourceSetFiles(__project
, __sourceSet
)));
141 // Go through dependencies since we need to know about those test
143 for (ProjectAndTaskName projectTask
: VMHelpers
.runClassTasks(
144 __project
, new SourceTargetClassifier(__sourceSet
, VMType
.HOSTED
,
145 BangletVariant
.NONE
, ClutterLevel
.DEBUG
)))
147 // Only consider actual projects
148 Project subProject
= __project
.project(projectTask
.project
);
149 Task subTask
= subProject
.getTasks().getByName(projectTask
.task
);
150 if (!(subTask
instanceof VMExecutableTask
))
153 // Add to be evaluated by everything
154 everything
.add(new CandidateTestFileSource(false,
155 TestDetection
.sourceSetFiles(subProject
,
156 ((VMExecutableTask
)subTask
).getSourceSet())));
159 // Go through all the potential candidate sources
160 for (CandidateTestFileSource candidateSource
: everything
)
162 // Scan through every file and match sources and expected tests
163 for (FileLocation file
: candidateSource
.collection
)
165 // If this is a MIME encoded file, normalize the name, so it
166 // does not include the mime extension as that is removed at
169 if ("__mime".equals(VMHelpers
.getExtension(
170 file
.getRelative())))
171 normalized
= VMHelpers
.stripExtension(file
.getRelative());
173 normalized
= file
.getRelative();
175 // Determine the name of the class, used to filter if this is
176 // a valid test or not at a later stage
177 String testName
= VMHelpers
.pathToString('.',
178 VMHelpers
.stripExtension(normalized
));
180 // Always add the test now, since this could be a super class
181 // of a test but not something that should be called
184 // Determine how this file is to be handled
185 switch (VMHelpers
.getExtension(normalized
))
187 // Executable Classes
191 if (candidateSource
.primary
)
192 sources
.put(testName
, file
);
194 secondarySources
.put(testName
, file
);
199 expects
.put(testName
, file
);
205 // Setup full set of possible candidates
206 Map
<String
, CandidateTestFiles
> fullSet
= new TreeMap
<>();
207 for (String testName
: names
)
209 // Maybe an abstract test?
210 FileLocation source
= sources
.get(testName
);
211 FileLocation secondarySource
= secondarySources
.get(testName
);
212 if (source
== null && secondarySource
== null)
216 fullSet
.put(testName
, new CandidateTestFiles((source
!= null),
217 (source
!= null ? source
: secondarySource
),
218 expects
.get(testName
)));
221 // Map tests and candidate sets to normal candidates
222 Map
<String
, CandidateTestFiles
> result
= new TreeMap
<>();
223 for (Map
.Entry
<String
, CandidateTestFiles
> entry
: fullSet
.entrySet())
225 String testName
= entry
.getKey();
226 CandidateTestFiles candidate
= entry
.getValue();
228 // Ignore if this does not match the expected name form
229 if (!TestDetection
.isTest(testName
))
232 // If this is not a primary test, then it does not get to be added
233 // to the test list nor do we need to do any processing for it
234 if (!candidate
.primary
)
237 // Load in the manifest for the candidate
238 Manifest manifest
= VMHelpers
.__loadExpectedResults(testName
,
241 // Replace candidate entry with what is fully available here
242 Map
<String
, String
> expectedValues
= new LinkedHashMap
<>();
243 for (Map
.Entry
<Object
, Object
> value
: manifest
.getMainAttributes()
245 expectedValues
.put(Objects
.toString(value
.getKey()),
246 Objects
.toString(value
.getValue()));
247 candidate
= new CandidateTestFiles(candidate
.primary
,
248 candidate
.sourceCode
, candidate
.expectedResult
,
249 Collections
.unmodifiableMap(expectedValues
));
251 // Load the expected results and see if there multi-parameters
252 Collection
<String
> multiParams
= VMHelpers
.__parseMultiParams(
255 // Single test, has no parameters
256 if (multiParams
== null || multiParams
.isEmpty())
257 result
.put(testName
, candidate
);
259 // Otherwise, signify all the parameters within
262 for (String multiParam
: multiParams
)
263 result
.put(testName
+ "@" + multiParam
, candidate
);
267 return Collections
.unmodifiableMap(result
);
271 * Returns the cache directory of the project.
273 * @param __project The project to get the cache directory of.
274 * @param __classifier The classifier for the VM.
275 * @return The path provider to the project cache directory.
276 * @throws NullPointerException On null arguments.
279 public static Provider
<Path
> cacheDir(Project __project
,
280 SourceTargetClassifier __classifier
)
281 throws NullPointerException
283 if (__project
== null || __classifier
== null)
284 throw new NullPointerException("NARG");
286 return __project
.provider(() -> __project
.getBuildDir().toPath()
287 .resolve("squirreljme").resolve(
288 String
.format("vm-%s-%s-%s", __classifier
.getSourceSet(),
289 __classifier
.getVmType().vmName(VMNameFormat
.LOWERCASE
),
290 __classifier
.getTargetClassifier().getClutterLevel()))
291 .resolve(__classifier
.getBangletVariant().properNoun
));
295 * Returns the class path as a string.
297 * @param __paths Class paths.
298 * @return The class path as a string.
299 * @throws NullPointerException On null arguments.
302 public static String
classpathAsString(Path
... __paths
)
303 throws NullPointerException
305 return VMHelpers
.classpathAsString(false, __paths
);
309 * Returns the class path as a string.
311 * @param __paths Class paths.
312 * @return The class path as a string.
313 * @throws NullPointerException On null arguments.
316 public static String
classpathAsString(Iterable
<Path
> __paths
)
317 throws NullPointerException
319 return VMHelpers
.classpathAsString(false, __paths
);
323 * Returns the class path as a string.
325 * @param __unix Use UNIX separator and not the system one.
326 * @param __paths Class paths.
327 * @return The class path as a string.
328 * @throws NullPointerException On null arguments.
331 public static String
classpathAsString(boolean __unix
, Path
... __paths
)
332 throws NullPointerException
335 throw new NullPointerException("NARG");
337 return VMHelpers
.classpathAsString(Arrays
.asList(__paths
));
341 * Returns the class path as a string.
343 * @param __unix Use UNIX separator and not the system one.
344 * @param __paths Class paths.
345 * @return The class path as a string.
346 * @throws NullPointerException On null arguments.
349 public static String
classpathAsString(boolean __unix
,
350 Iterable
<Path
> __paths
)
351 throws NullPointerException
354 throw new NullPointerException("NARG");
356 StringBuilder sb
= new StringBuilder();
358 char separator
= (__unix ?
':' : File
.pathSeparatorChar
);
359 for (Path path
: __paths
)
362 sb
.append(separator
);
366 return sb
.toString();
370 * Decodes the classpath string.
372 * @param __string The string to decode.
373 * @return The decoded path.
374 * @throws NullPointerException On null arguments.
377 public static Path
[] classpathDecode(String __string
)
378 throws NullPointerException
380 if (__string
== null)
381 throw new NullPointerException("NARG");
383 Collection
<Path
> result
= new LinkedList
<>();
384 for (String split
: __string
.split(Pattern
.quote(File
.pathSeparator
)))
385 result
.add(Paths
.get(split
));
387 return result
.<Path
>toArray(new Path
[result
.size()]);
391 * Returns all the compact library tasks that the specified project
394 * @param __project The project to get the dependencies from.
395 * @param __sourceSet The source set to base off.
396 * @return The tasks which are part of the compaction dependencies.
397 * @throws NullPointerException On null arguments.
400 public static Collection
<VMCompactLibraryTask
> compactLibTaskDepends(
401 Project __project
, String __sourceSet
)
402 throws NullPointerException
404 if (__project
== null || __sourceSet
== null)
405 throw new NullPointerException("NARG");
407 // Where does this go?
408 Collection
<VMCompactLibraryTask
> result
= new LinkedHashSet
<>();
411 boolean isTest
= SourceSet
.TEST_SOURCE_SET_NAME
.equals(__sourceSet
);
412 boolean isTestFixtures
=
413 VMHelpers
.TEST_FIXTURES_SOURCE_SET_NAME
.equals(__sourceSet
);
415 // This is a bit messy but it works for now
416 Collection
<ProjectAndTaskName
> runTasks
=
417 VMHelpers
.runClassTasks(__project
,
418 SourceTargetClassifier
.builder()
419 .sourceSet(__sourceSet
)
420 .targetClassifier(TargetClassifier
.builder()
421 .bangletVariant(BangletVariant
.NONE
)
422 .vmType(VMType
.SPRINGCOAT
)
423 .clutterLevel(ClutterLevel
.RELEASE
)
426 for (ProjectAndTaskName projectAndTask
: runTasks
)
428 // Find the referenced project
429 Project subProject
= __project
.project(projectAndTask
.project
);
431 // Ignore our own project, if not testing
432 if (__project
.equals(subProject
) && !isTest
&& !isTestFixtures
)
435 // Check the main source set
436 String checkName
= TaskInitialization
.task("compactLib",
437 SourceSet
.MAIN_SOURCE_SET_NAME
);
438 Task maybe
= subProject
.getTasks().findByName(checkName
);
439 if (maybe
instanceof VMCompactLibraryTask
)
441 VMCompactLibraryTask task
= (VMCompactLibraryTask
)maybe
;
445 // If we are testing, see if we can pull in any test fixtures
448 String check
= TaskInitialization
.task("compactLib",
449 VMHelpers
.TEST_FIXTURES_SOURCE_SET_NAME
);
450 Task fixture
= subProject
.getTasks().findByName(check
);
451 if (fixture
instanceof VMCompactLibraryTask
)
453 VMCompactLibraryTask task
= (VMCompactLibraryTask
)fixture
;
463 * Copies from the input into the output.
465 * @param __in The input.
466 * @param __out The output.
467 * @throws IOException On read/write errors.
468 * @throws NullPointerException On null arguments.
471 public static void copy(InputStream __in
, OutputStream __out
)
472 throws IOException
, NullPointerException
474 if (__in
== null || __out
== null)
475 throw new NullPointerException("NARG");
477 byte[] buf
= new byte[VMHelpers
.COPY_BUFFER
];
480 int rc
= __in
.read(buf
);
485 __out
.write(buf
, 0, rc
);
490 * Copies from the input into the output while recompressing the Zip file.
492 * @param __in The input.
493 * @param __out The output.
494 * @throws IOException On read/write errors.
495 * @throws NullPointerException On null arguments.
498 public static void copyRecompressZip(InputStream __in
, OutputStream __out
)
499 throws IOException
, NullPointerException
501 if (__in
== null || __out
== null)
502 throw new NullPointerException("NARG");
504 try (ZipInputStream inZip
= new ZipInputStream(__in
);
505 ZipOutputStream outZip
= new ZipOutputStream(__out
))
507 // Maximum compression
508 outZip
.setMethod(ZipOutputStream
.DEFLATED
);
511 // Recompress each entry
514 // Get next entry, if null there are none left
515 ZipEntry entry
= inZip
.getNextEntry();
520 outZip
.putNextEntry(new ZipEntry(entry
.getName()));
523 VMHelpers
.copy(inZip
, outZip
);
534 // Make sure output is flushed
539 * Deletes the given directory tree.
541 * @param __task The task deleting for.
542 * @param __path The path to delete.
543 * @throws NullPointerException On null arguments.
546 public static void deleteDirTree(Task __task
, Path __path
)
547 throws NullPointerException
549 if (__task
== null || __path
== null)
550 throw new NullPointerException("NARG");
552 // Ignore if not a directory
553 Path base
= __path
.toAbsolutePath().normalize();
554 if (!Files
.isDirectory(__path
))
557 // Collect files to delete
558 Set
<Path
> deleteFiles
= new LinkedHashSet
<>();
559 Set
<Path
> deleteDirs
= new LinkedHashSet
<>();
561 // Perform the walk to collect files
562 try (Stream
<Path
> walk
= Files
.walk(__path
))
564 walk
.forEach((__it
) -> {
565 Path normal
= __it
.toAbsolutePath().normalize();
567 if (Files
.isDirectory(normal
))
568 deleteDirs
.add(normal
);
570 deleteFiles
.add(normal
);
573 catch (IOException __e
)
575 __e
.printStackTrace();
578 // Run through and delete files then directories
579 for (Set
<Path
> rawByes
: Arrays
.asList(deleteFiles
, deleteDirs
))
581 List
<Path
> byes
= new ArrayList
<>(rawByes
);
582 Collections
.reverse(byes
);
584 for (Path bye
: byes
)
587 __task
.getLogger().lifecycle(
588 String
.format("Cleaning %s...", bye
));
590 // Skip out of tree files
591 if (!bye
.startsWith(base
))
593 __task
.getLogger().lifecycle(
594 String
.format("%s is out of tree, skipping...", bye
));
601 Files
.deleteIfExists(bye
);
603 catch (IOException e
)
612 * Attempts to find the emulator library so that can be loaded directly
613 * instead of being extracted by each test process, if possible.
615 * @param __anyProject Any project.
616 * @return The path to the emulator library.
619 @SuppressWarnings("ConstantConditions")
620 public static Path
findEmulatorLib(Project __anyProject
)
621 throws NullPointerException
623 if (__anyProject
== null)
624 throw new NullPointerException("NARG");
626 // We need to look through the emulator base tasks to determine
627 // the library to select
628 Project emuBase
= __anyProject
.getRootProject()
629 .findProject(":emulators:emulator-base");
631 // Get the CMake Task for this
632 CMakeBuildTask cmake
= (CMakeBuildTask
)emuBase
.getTasks()
633 .getByName("libNativeEmulatorBase");
635 // Use the resultant library
636 return cmake
.cmakeOutFile
;
640 * Returns the full suite libraries for a given task.
642 * @param __task The task to get.
643 * @return The path for the full suite libraries.
646 public static Collection
<Path
> fullSuiteLibraries(Task __task
)
647 throws NullPointerException
649 Collection
<Path
> libPath
= new LinkedHashSet
<>();
650 for (VMLibraryTask dep
: VMHelpers
.fullSuiteLibrariesTasks(__task
))
651 for (File file
: dep
.getOutputs().getFiles())
652 libPath
.add(file
.toPath());
658 * Returns the full suite library tasks for a given task.
660 * @param __task The task to get.
661 * @return The path for the full suite libraries.
664 public static Collection
<VMLibraryTask
> fullSuiteLibrariesTasks(
666 throws NullPointerException
668 // Load executable library tasks from our own VM
669 Collection
<VMLibraryTask
> result
= new LinkedHashSet
<>();
670 for (Task dep
: __task
.getTaskDependencies().getDependencies(__task
))
671 if (dep
instanceof VMLibraryTask
)
672 result
.add((VMLibraryTask
)dep
);
678 * Gets the base name of the file without the extension, if there is one.
680 * @param __path The path to get from.
681 * @return The file base name.
682 * @throws NullPointerException On null arguments.
685 public static String
getBaseName(Path __path
)
686 throws NullPointerException
689 throw new NullPointerException("NARG");
691 // Does this file even have an extension to it?
692 String fileName
= __path
.getFileName().toString();
693 int ld
= fileName
.lastIndexOf('.');
697 // Otherwise extract it
698 return fileName
.substring(0, ld
);
702 * Gets the extension from the given path.
704 * @param __path The path to get from.
705 * @return The file extension.
706 * @throws NullPointerException On null arguments.
709 public static String
getExtension(Path __path
)
710 throws NullPointerException
713 throw new NullPointerException("NARG");
715 // Does this file even have an extension to it?
716 String fileName
= __path
.getFileName().toString();
717 int ld
= fileName
.lastIndexOf('.');
721 // Otherwise extract it
722 return fileName
.substring(ld
+ 1);
726 * Returns the current Fossil commit hash.
728 * @param __project The project.
729 * @return The hash or {@code null} if not in a Fossil checkout.
730 * @throws NullPointerException On null arguments.
733 public static String
hashFossil(Project __project
)
734 throws NullPointerException
736 if (__project
== null)
737 throw new NullPointerException("NARG");
739 Path possible
= __project
.getRootProject()
740 .getProjectDir().toPath().resolve("manifest.uuid");
741 if (Files
.exists(possible
))
744 List
<String
> lines
= Files
.readAllLines(possible
);
745 if (!lines
.isEmpty() && lines
.get(0) != null)
746 return lines
.get(0).trim().toLowerCase(Locale
.ROOT
);
748 catch (IOException __ignored
)
752 // Not in a Fossil checkout
757 * Returns the current Git commit hash.
759 * @param __project The project.
760 * @return The hash or {@code null} if not in a Git checkout.
761 * @throws NullPointerException On null arguments.
764 public static String
hashGit(Project __project
)
765 throws NullPointerException
767 if (__project
== null)
768 throw new NullPointerException("NARG");
773 ProcessBuilder builder
= new ProcessBuilder("git",
774 "rev-parse", "HEAD");
776 builder
.redirectOutput(ProcessBuilder
.Redirect
.PIPE
);
777 builder
.directory(__project
.getRootProject().getProjectDir());
779 // Start and wait for it to complete
780 Process process
= builder
.start();
784 try (InputStream in
= process
.getInputStream();
785 InputStreamReader isr
= new InputStreamReader(in
);
786 BufferedReader br
= new BufferedReader(isr
))
788 String maybe
= br
.readLine();
790 return maybe
.trim().toLowerCase(Locale
.ROOT
);
793 catch (IOException
|InterruptedException __ignored
)
801 * Returns the task that creates the JAR.
803 * @param __project The project to get from.
804 * @param __sourceSet The source set.
805 * @return The jar task used, or {@code null} if not found.
806 * @throws NullPointerException On null arguments.
809 public static Jar
jarTask(Project __project
, String __sourceSet
)
810 throws NullPointerException
812 if (__project
== null || __sourceSet
== null)
813 throw new NullPointerException("NARG");
817 case SourceSet
.MAIN_SOURCE_SET_NAME
:
818 return (Jar
)__project
.getTasks().getByName("jar");
820 case SourceSet
.TEST_SOURCE_SET_NAME
:
821 return (Jar
)__project
.getTasks().getByName("testJar");
823 case VMHelpers
.TEST_FIXTURES_SOURCE_SET_NAME
:
824 return (Jar
)__project
.getTasks()
825 .getByName("testFixturesJar");
828 throw new IllegalStateException("Unknown sourceSet: " +
834 * Returns the main class to execute.
836 * @param __cfg The configuration.
837 * @param __midlet The MIDlet to be run.
838 * @return The main class.
839 * @throws NullPointerException If {@code __cfg} is {@code null}.
842 public static String
mainClass(SquirrelJMEPluginConfiguration __cfg
,
843 JavaMEMidlet __midlet
)
844 throws NullPointerException
847 throw new NullPointerException("NARG");
849 // We either run the MIDlet or we do not
850 return VMHelpers
.mainClass(__midlet
, __cfg
.mainClass
);
854 * Determines the main class to use.
856 * @param __midlet The MIDlet to execute.
857 * @param __mainClass The main class to run.
858 * @return The class for execution.
859 * @throws NullPointerException On null arguments.
862 public static String
mainClass(JavaMEMidlet __midlet
, String __mainClass
)
863 throws NullPointerException
865 if (__midlet
== null && __mainClass
== null)
866 throw new NullPointerException("No main class specified.");
868 // We either run the MIDlet or we do not
869 if (__midlet
!= null)
870 return UnassistedLaunchEntry
.MIDLET_MAIN_CLASS
;
875 * Returns the only file with the given extension in the given collection.
877 * @param __collection The collection to get.
878 * @param __ext The extension to get from.
879 * @return The only file in the collection with the extension.
880 * @throws IllegalStateException If there are multiple or no files
882 * @throws NullPointerException On null arguments.
885 public static Path
onlyFile(FileCollection __collection
, String __ext
)
886 throws IllegalStateException
, NullPointerException
888 if (__collection
== null || __ext
== null)
889 throw new NullPointerException("NARG");
891 // Scan through everything and look for it
893 for (File file
: __collection
.getFiles())
895 Path path
= file
.toPath();
897 if (__ext
.equals(VMHelpers
.getExtension(path
)))
900 throw new IllegalStateException(
901 String
.format("Multiple .%s in %s",
902 __ext
, __collection
));
910 throw new IllegalStateException(
911 String
.format("No .%s in %s", __ext
, __collection
));
916 * Returns the optional dependencies for a given project.
918 * @param __project The project to get for.
919 * @param __sourceSet The source set to look within.
920 * @return The optional project dependencies or an empty list if unknown.
921 * @throws NullPointerException On null arguments.
924 public static List
<Project
> optionalDepends(Project __project
,
926 throws NullPointerException
928 SquirrelJMEPluginConfiguration config
=
929 SquirrelJMEPluginConfiguration
.configurationOrNull(__project
);
931 return Collections
.emptyList();
933 if (__sourceSet
.equals(SourceSet
.MAIN_SOURCE_SET_NAME
))
934 return config
.optionalDependencies
;
935 else if (__sourceSet
.equals(SourceSet
.TEST_SOURCE_SET_NAME
))
936 return config
.optionalDependenciesTest
;
937 else if (__sourceSet
.equals(VMHelpers
.TEST_FIXTURES_SOURCE_SET_NAME
))
938 return config
.optionalDependenciesTestFixtures
;
940 return Collections
.emptyList();
944 * Converts the given path to a String using the delimiter.
946 * @param __delim The delimiter.
947 * @param __path The path to convert.
948 * @return The path as a string.
949 * @throws NullPointerException On null arguments.
952 public static String
pathToString(char __delim
, Path __path
)
953 throws NullPointerException
956 throw new NullPointerException("NARG");
958 // If the path is of only a single element (or none) then it is just
959 // whatever the string form of the path is
960 int n
= __path
.getNameCount();
962 return __path
.toString();
964 // Build together the string
965 StringBuilder sb
= new StringBuilder();
966 for (int i
= 0; i
< n
; i
++)
970 sb
.append(__path
.getName(i
).toString());
973 return sb
.toString();
977 * Returns the directory where profiler snapshots go.
979 * @param __project The project to get the cache directory of.
980 * @param __classifier The classifier used.
981 * @return The path provider to the profiler snapshot directory.
982 * @throws NullPointerException On null arguments.
985 public static Provider
<Path
> profilerDir(Project __project
,
986 SourceTargetClassifier __classifier
)
987 throws NullPointerException
989 if (__project
== null || __classifier
== null)
990 throw new NullPointerException("NARG");
992 return __project
.provider(() -> VMHelpers
.cacheDir(
993 __project
, __classifier
).get().resolve("nps"));
997 * Returns the internal name via the source set.
999 * @param __project The project.
1000 * @param __sourceSet The source set.
1001 * @return The internal name that is used by SquirrelJME.
1002 * @throws NullPointerException On null arguments.
1005 public static String
projectInternalNameViaSourceSet(Project __project
,
1007 throws NullPointerException
1009 if (__project
== null || __sourceSet
== null)
1010 throw new NullPointerException("NARG");
1012 // If main project, just use the normal base name
1013 if (__sourceSet
.equals(SourceSet
.MAIN_SOURCE_SET_NAME
))
1014 return __project
.getName();
1016 // Otherwise, append the source set
1017 return String
.format("%s-%s", __project
.getName(),
1018 __sourceSet
.toLowerCase(Locale
.ROOT
));
1022 * Returns the project classpath.
1024 * @param __project The project.
1025 * @return The class path.
1026 * @throws NullPointerException On null arguments.
1029 public static Iterable
<File
> projectRuntimeClasspath(Project __project
)
1030 throws NullPointerException
1032 if (__project
== null)
1033 throw new NullPointerException("No project specified.");
1035 return __project
.getConfigurations().
1036 getByName("runtimeClasspath").getFiles();
1040 * Returns the name of the suite that should be used for the dependency.
1042 * @param __project The project to get for.
1043 * @param __sourceSet The source set used.
1044 * @return The suite name that should be used.
1045 * @throws NullPointerException On null arguments.
1048 public static String
projectSwmNameViaSourceSet(Project __project
,
1050 throws NullPointerException
1052 if (__project
== null || __sourceSet
== null)
1053 throw new NullPointerException("NARG");
1055 // Need this to get the key
1056 SquirrelJMEPluginConfiguration config
=
1057 SquirrelJMEPluginConfiguration
.configuration(__project
);
1059 // Just uses the set name
1060 if (__sourceSet
.equals(SourceSet
.MAIN_SOURCE_SET_NAME
))
1061 return config
.swmName
;
1063 // Otherwise, gets prefixed
1064 return TaskInitialization
.uppercaseFirst(__sourceSet
) + " for " +
1069 * Reads all the bytes from the stream.
1071 * @param __in The stream to read from.
1072 * @return All the read bytes.
1073 * @throws IOException On read errors.
1074 * @throws NullPointerException On null arguments.
1077 public static byte[] readAll(InputStream __in
)
1078 throws IOException
, NullPointerException
1081 throw new NullPointerException("NARG");
1083 try (ByteArrayOutputStream out
= new ByteArrayOutputStream(4096))
1085 byte[] buf
= new byte[4096];
1088 int rc
= __in
.read(buf
);
1091 return out
.toByteArray();
1093 out
.write(buf
, 0, rc
);
1099 * Recompresses the given Zip file.
1101 * @param __zip The ZIP to recompress.
1102 * @throws IOException On read/write errors.
1103 * @throws NullPointerException On null arguments.
1106 public static void recompressZip(Path __zip
)
1107 throws IOException
, NullPointerException
1110 throw new NullPointerException("NARG");
1112 // Load in everything for copy
1114 byte[] inZip
= Files
.readAllBytes(__zip
);
1115 try (InputStream in
= new ByteArrayInputStream(inZip
);
1116 ByteArrayOutputStream out
= new ByteArrayOutputStream(
1119 // Perform recompression
1120 VMHelpers
.copyRecompressZip(in
, out
);
1122 // Get resultant output
1123 result
= out
.toByteArray();
1126 // Replace everything
1127 Files
.write(__zip
, result
,
1128 StandardOpenOption
.TRUNCATE_EXISTING
,
1129 StandardOpenOption
.WRITE
,
1130 StandardOpenOption
.CREATE
);
1134 * Resolves path elements as needed to determine where a file is.
1136 * @param __in The input to resolve.
1137 * @return The path of the given object.
1138 * @throws NullPointerException On null arguments.
1141 public static Iterable
<Path
> resolvePath(Object __in
)
1142 throws NullPointerException
1145 throw new NullPointerException("NARG");
1147 // Direct file paths
1148 if (__in
instanceof Path
)
1149 return Collections
.singleton((Path
)__in
);
1150 else if (__in
instanceof File
)
1151 return Collections
.singleton(((File
)__in
).toPath());
1154 else if (__in
instanceof Callable
)
1157 return VMHelpers
.resolvePath(
1158 ((Callable
<?
>)__in
).call());
1162 if (e
instanceof RuntimeException
)
1163 throw (RuntimeException
)e
;
1165 throw new RuntimeException("Could not run Callable.", e
);
1169 else if (__in
instanceof Supplier
)
1170 return VMHelpers
.resolvePath(
1171 ((Supplier
<?
>)__in
).get());
1173 // An iterable sequence
1174 else if (__in
instanceof Iterable
)
1176 List
<Path
> result
= new ArrayList
<>();
1179 for (Object obj
: (Iterable
<?
>)__in
)
1180 for (Path sub
: VMHelpers
.resolvePath(obj
))
1188 throw new RuntimeException(String
.format(
1189 "Unknown input path type %s", __in
.getClass()));
1193 * Resolves tasks from the projects and tasks.
1195 * @param <T> The class to resolve as.
1196 * @param __class The class to resolve as.
1197 * @param __project The project to latch onto for lookup.
1198 * @param __in The input project and task names.
1199 * @return An iterable which has the projects resolved.
1200 * @throws NullPointerException On null arguments.
1202 public static <T
extends Task
> Iterable
<T
> resolveProjectTasks(
1203 Class
<T
> __class
, Project __project
, Iterable
<ProjectAndTaskName
> __in
)
1204 throws NullPointerException
1206 if (__project
== null || __in
== null)
1207 throw new NullPointerException("NARG");
1209 Collection
<T
> result
= new LinkedList
<>();
1211 // Map projects and tasks back into tasks
1212 for (ProjectAndTaskName depend
: __in
)
1214 T task
= __class
.cast(__project
.project(depend
.project
)
1215 .getTasks().findByName(depend
.task
));
1221 return Collections
.unmodifiableCollection(result
);
1225 * Returns the path of the all the JARs which make up the classpath for
1226 * running an executable.
1228 * @param __task The task to get for.
1229 * @param __classifier The classifier used.
1230 * @return An array of paths containing the class path of execution.
1231 * @throws NullPointerException On null arguments.
1234 public static Path
[] runClassPath(Task __task
,
1235 SourceTargetClassifier __classifier
)
1237 return VMHelpers
.runClassPath(__task
, __classifier
, false);
1241 * Returns the path of the all the JARs which make up the classpath for
1242 * running an executable.
1244 * @param __task The task to get for.
1245 * @param __classifier The classifier used.
1246 * @param __optional use optional dependencies?
1247 * @return An array of paths containing the class path of execution.
1248 * @throws NullPointerException On null arguments.
1251 public static Path
[] runClassPath(Task __task
,
1252 SourceTargetClassifier __classifier
, boolean __optional
)
1253 throws NullPointerException
1255 return VMHelpers
.runClassPath(__task
.getProject(),
1256 __classifier
, __optional
);
1260 * Returns the path of the all the JARs which make up the classpath for
1261 * running an executable.
1263 * @param __project The project to get for.
1264 * @param __classifier The classifier used.
1265 * @return An array of paths containing the class path of execution.
1266 * @throws NullPointerException On null arguments.
1269 public static Path
[] runClassPath(Project __project
,
1270 SourceTargetClassifier __classifier
)
1271 throws NullPointerException
1273 return VMHelpers
.runClassPath(__project
, __classifier
, false);
1277 * Returns the path of the all the JARs which make up the classpath for
1278 * running an executable.
1280 * @param __project The project to get for.
1281 * @param __classifier The classifier used.
1282 * @param __optional use optional dependencies?
1283 * @return An array of paths containing the class path of execution.
1284 * @throws NullPointerException On null arguments.
1287 public static Path
[] runClassPath(Project __project
,
1288 SourceTargetClassifier __classifier
, boolean __optional
)
1289 throws NullPointerException
1291 if (__project
== null || __classifier
== null)
1292 throw new NullPointerException("NARG");
1294 // Get tasks that are used for dependency running
1295 Iterable
<VMLibraryTask
> tasks
=
1296 VMHelpers
.<VMLibraryTask
>resolveProjectTasks(
1297 VMLibraryTask
.class, __project
, VMHelpers
1298 .runClassTasks(__project
, __classifier
, __optional
));
1300 // Get the outputs of these, as they will be used. Ensure the order is
1301 // kept otherwise execution may be non-deterministic and could break.
1302 Set
<Path
> classPath
= new LinkedHashSet
<>();
1303 for (VMLibraryTask vmLib
: tasks
)
1304 for (File file
: vmLib
.getOutputs().getFiles().getFiles())
1305 classPath
.add(file
.toPath());
1307 return classPath
.toArray(new Path
[classPath
.size()]);
1311 * Returns the internal class path specifier to run the given tasks.
1313 * @param __project The project.
1314 * @param __classifier The classifier used.
1315 * @param __optional Include optional JARs?
1316 * @return The class path string.
1317 * @throws NullPointerException On null arguments.
1320 public static String
runClassPathAsInternalClassPath(
1321 Project __project
, SourceTargetClassifier __classifier
,
1323 throws NullPointerException
1325 // Get tasks that are used for dependency running
1326 Iterable
<VMLibraryTask
> tasks
=
1327 VMHelpers
.<VMLibraryTask
>resolveProjectTasks(
1328 VMLibraryTask
.class, __project
, VMHelpers
1329 .runClassTasks(__project
, __classifier
, __optional
));
1331 // Build paths from it
1332 StringBuilder result
= new StringBuilder();
1333 for (VMLibraryTask task
: tasks
)
1335 // Path separator before
1336 if (result
.length() > 0)
1339 // Use Jar name here
1340 result
.append(VMHelpers
.projectInternalNameViaSourceSet(
1341 task
.getProject(), task
.getSourceSet()) + ".jar");
1344 return result
.toString();
1348 * Returns the task dependencies to get outputs from that would be
1349 * considered a part of the project's class path used at execution time.
1351 * @param __project The task to get from.
1352 * @param __classifier The classifier used.
1353 * @return The direct run dependencies for the task.
1354 * @throws NullPointerException On null arguments.
1357 public static Collection
<ProjectAndTaskName
> runClassTasks(
1358 Project __project
, SourceTargetClassifier __classifier
)
1359 throws NullPointerException
1361 return VMHelpers
.runClassTasks(__project
, __classifier
,
1366 * Returns the task dependencies to get outputs from that would be
1367 * considered a part of the project's class path used at execution time.
1369 * @param __project The task to get from.
1370 * @param __classifier The classifier used.
1371 * @param __optional Include optional dependencies?
1372 * @return The direct run dependencies for the task.
1373 * @throws NullPointerException On null arguments.
1376 public static Collection
<ProjectAndTaskName
> runClassTasks(
1377 Project __project
, SourceTargetClassifier __classifier
,
1379 throws NullPointerException
1381 return VMHelpers
.runClassTasks(__project
, __classifier
, __optional
,
1386 * Returns the task dependencies to get outputs from that would be
1387 * considered a part of the project's class path used at execution time.
1389 * @param __project The task to get from.
1390 * @param __classifier The classifier used.
1391 * @param __optional Include optional dependencies?
1392 * @param __did Projects that have been processed.
1393 * @return The direct run dependencies for the task.
1394 * @throws NullPointerException On null arguments.
1397 public static Collection
<ProjectAndTaskName
> runClassTasks(
1398 Project __project
, SourceTargetClassifier __classifier
,
1399 boolean __optional
, Set
<ProjectAndTaskName
> __did
)
1400 throws NullPointerException
1402 if (__project
== null || __classifier
== null)
1403 throw new NullPointerException("NARG");
1405 // Make sure this is always set
1407 __did
= new HashSet
<>();
1409 // If this was already processed, ignore it
1410 ProjectAndTaskName selfProjectTask
= ProjectAndTaskName
.of(__project
,
1411 TaskInitialization
.task("lib",
1412 __classifier
.withVmByEmulatedJit()));
1413 if (__did
.contains(selfProjectTask
))
1414 return Collections
.emptySet();
1416 Set
<ProjectAndTaskName
> result
= new LinkedHashSet
<>();
1418 // If we are testing then we depend on the main TAC library, otherwise
1419 // we will not be able to do any actual testing
1420 boolean isTesting
= __classifier
.isTestSourceSet();
1424 result
.addAll(VMHelpers
.runClassTasks(
1425 __project
.findProject(":modules:tac"),
1426 __classifier
.withSourceSet(SourceSet
.MAIN_SOURCE_SET_NAME
)
1427 .withVmByEmulatedJit(),
1428 __optional
, __did
));
1430 // Depend on our main project as we will be testing it
1431 result
.addAll(VMHelpers
.runClassTasks(__project
,
1432 __classifier
.withSourceSet(SourceSet
.MAIN_SOURCE_SET_NAME
)
1433 .withVmByEmulatedJit(),
1434 __optional
, __did
));
1437 // Go through the configurations to yank in the dependencies as needed
1438 for (String config
: (isTesting ? VMHelpers
._TEST_CONFIGS
:
1439 VMHelpers
._MAIN_CONFIGS
))
1441 // The configuration may be optional
1442 Configuration foundConfig
= __project
.getConfigurations()
1443 .findByName(config
);
1444 if (foundConfig
== null)
1447 // Handle dependencies
1448 for (Dependency depend
: foundConfig
.getDependencies())
1450 // Only consider projects
1451 if (!(depend
instanceof ProjectDependency
))
1454 ProjectDependency projectDepend
= (ProjectDependency
)depend
;
1455 Project sub
= projectDepend
.getDependencyProject();
1457 // Only consider SquirrelJME projects
1458 SquirrelJMEPluginConfiguration squirreljmeConf
=
1459 SquirrelJMEPluginConfiguration
.configurationOrNull(sub
);
1460 if (squirreljmeConf
== null)
1463 // Does this depend on test fixtures?
1464 boolean isTestFixture
= false;
1465 for (Capability capability
:
1466 projectDepend
.getRequestedCapabilities())
1467 if (capability
.getName()
1468 .equals(sub
.getName() + "-test-fixtures"))
1469 isTestFixture
= true;
1471 // Otherwise, handle the dependencies
1472 String targetSourceSet
= (isTestFixture ?
1473 VMHelpers
.TEST_FIXTURES_SOURCE_SET_NAME
:
1474 SourceSet
.MAIN_SOURCE_SET_NAME
);
1475 Collection
<ProjectAndTaskName
> selected
=
1476 VMHelpers
.runClassTasks(sub
,
1477 __classifier
.withSourceSet(targetSourceSet
)
1478 .withVmByEmulatedJit(),
1481 result
.addAll(selected
);
1485 // Finally, add our own library for usages
1486 result
.add(selfProjectTask
);
1488 // Ignore our own project
1489 __did
.add(selfProjectTask
);
1491 // Include optional dependencies as well, so that they are actually
1492 // used accordingly...
1494 for (Project optional
: VMHelpers
.optionalDepends(__project
,
1495 __classifier
.getSourceSet()))
1496 result
.addAll(VMHelpers
.runClassTasks(optional
,
1497 __classifier
.withSourceSet(SourceSet
.MAIN_SOURCE_SET_NAME
)
1498 .withVmByEmulatedJit(),
1502 __project
.getLogger().debug("Run Depends: {}", result
);
1504 return Collections
.unmodifiableCollection(result
);
1508 * Returns all the tests to run.
1510 * @param __project The project to check.
1511 * @param __sourceSet The source set to check.
1512 * @return All the tests that should be run.
1513 * @throws NullPointerException On null arguments.
1516 public static AvailableTests
runningTests(
1517 Project __project
, String __sourceSet
)
1518 throws NullPointerException
1520 Map
<String
, CandidateTestFiles
> available
=
1521 VMHelpers
.availableTests(__project
, __sourceSet
);
1523 // If specifying a single test to run only specify that
1524 String singleTest
= System
.getProperty(
1525 VMLegacyTestTask
.SINGLE_TEST_PROPERTY
,
1526 System
.getProperty(VMLegacyTestTask
.SINGLE_TEST_PROPERTY_B
));
1527 if (singleTest
!= null)
1529 // We need to check every test, since we may have multi-parameters
1531 Map
<String
, CandidateTestFiles
> singles
= new LinkedHashMap
<>();
1532 for (Map
.Entry
<String
, CandidateTestFiles
> e
: available
1534 if (VMHelpers
.__isSingleTest(e
.getKey(), singleTest
))
1535 singles
.put(e
.getKey(), e
.getValue());
1537 // If we found at least one test then we can test those, there may
1538 // be multiple ones due to multi-parameters
1539 if (!singles
.isEmpty())
1540 return new AvailableTests(
1541 Collections
.unmodifiableMap(singles
), true);
1543 // If the test has no matching file, then just ignore it
1544 throw new IllegalArgumentException(String
.format(
1545 "Could not find test %s, failing.", singleTest
));
1548 // Is only valid if there is at least one test
1549 return new AvailableTests(available
, false);
1553 * Translates a path to a string.
1555 * @param __name The input string file name.
1556 * @return The resultant path.
1557 * @throws NullPointerException On null arguments.
1560 public static Path
stringToPath(String __name
)
1561 throws NullPointerException
1564 throw new NullPointerException("NARG");
1566 return Paths
.get("", __name
.split(Pattern
.quote("/")));
1570 * Strips the extension from the path.
1572 * @param __path The path to strip the extension from.
1573 * @return The input path with the extension stripped.
1574 * @throws NullPointerException On null arguments.
1577 public static Path
stripExtension(Path __path
)
1578 throws NullPointerException
1581 throw new NullPointerException("NARG");
1583 // If there is no extension part then nothing has to be done
1584 String fileName
= __path
.getFileName().toString();
1585 int lastDot
= fileName
.lastIndexOf('.');
1589 // The "renamed" file is in the same parent directory
1590 return __path
.resolveSibling(fileName
.substring(0, lastDot
));
1594 * Returns the directory where test results go.
1596 * @param __project The project to get the cache directory of.
1597 * @param __classifier The classifier used.
1598 * @return The path provider to the test result directory.
1599 * @throws NullPointerException On null arguments.
1602 public static Provider
<Path
> testResultXmlDir(Project __project
,
1603 SourceTargetClassifier __classifier
)
1604 throws NullPointerException
1606 if (__project
== null || __classifier
== null)
1607 throw new NullPointerException("NARG");
1609 return __project
.provider(() -> VMHelpers
.cacheDir(__project
,
1610 __classifier
).get().resolve("junit"));
1614 * Returns the test result XML file name.
1616 * @param __testName The test name.
1617 * @return The name of the XML to use.
1618 * @throws NullPointerException On null arguments.
1621 public static String
testResultXmlName(String __testName
)
1622 throws NullPointerException
1624 if (__testName
== null)
1625 throw new NullPointerException("NARG");
1627 // When Gradle normally makes a test, it encodes @ to #40.
1628 return "TEST-" + __testName
.replaceAll(Pattern
.quote("@"),
1629 Matcher
.quoteReplacement("#40")) + ".xml";
1633 * Returns the directory where test results go.
1635 * @param __project The project to get the cache directory of.
1636 * @param __classifier The classifier used.
1637 * @return The path provider to the test result directory.
1638 * @throws NullPointerException On null arguments.
1641 public static Provider
<Path
> testResultsCsvDir(Project __project
,
1642 SourceTargetClassifier __classifier
)
1643 throws NullPointerException
1645 if (__project
== null || __classifier
== null)
1646 throw new NullPointerException("NARG");
1648 return __project
.provider(() -> VMHelpers
.cacheDir(
1649 __project
, __classifier
).get().resolve("csv"));
1653 * Returns the name for the CSV file.
1655 * @param __project The project this falls under.
1656 * @return The path of the CSV results file.
1657 * @throws NullPointerException On null arguments.
1660 public static Path
testResultsCsvName(Project __project
)
1661 throws NullPointerException
1663 if (__project
== null)
1664 throw new NullPointerException("NARG");
1666 return Paths
.get("RESULTS-" + __project
.getName() + ".csv");
1670 * Returns the unassisted launch entry.
1672 * @param __cfg The configuration to get from.
1673 * @param __midlet The MIDlet to load.
1674 * @return The unassisted launch entry for the given MIDlet.
1675 * @throws NullPointerException If no configuration was specified.
1678 public static UnassistedLaunchEntry
unassistedLaunch(
1679 SquirrelJMEPluginConfiguration __cfg
, JavaMEMidlet __midlet
)
1680 throws NullPointerException
1683 throw new NullPointerException("NARG");
1685 // Starting arguments?
1687 if (__midlet
!= null)
1688 args
= new String
[]{__midlet
.mainClass
};
1690 args
= new String
[0];
1692 return new UnassistedLaunchEntry(
1693 VMHelpers
.mainClass(__cfg
, __midlet
),
1698 * Checks if this is the single test to run, depending if multi-parameters
1701 * @param __key The key to check.
1702 * @param __singleTest The single test that was requested.
1703 * @return If this is the matching single test.
1704 * @throws NullPointerException On null arguments.
1707 private static boolean __isSingleTest(String __key
, String __singleTest
)
1708 throws NullPointerException
1710 if (__key
== null || __singleTest
== null)
1711 throw new NullPointerException("NARG");
1713 // If the test does not have a multi-parameter match it exactly.
1714 // However if we requested a specific multi-parameter then match that
1716 // Convert slashes to dots as well for binary name usage
1717 int la
= __key
.indexOf('@');
1718 if (la
< 0 || __singleTest
.indexOf('@') >= 0)
1719 return __key
.equals(__singleTest
) ||
1720 __key
.equals(__singleTest
.replace('/', '.'));
1722 // Only match by the basename, if multi-parameter assume all of them
1723 // But also convert all slashes to dots in the event binary names
1725 return __key
.substring(0, la
).equals(__singleTest
) ||
1726 __key
.substring(0, la
).equals(
1727 __singleTest
.replace('/', '.'));
1731 * Loads the expected results for a test.
1733 * @param __testName The test being parsed.
1734 * @param __candidates The candidates available, used for super classes.
1735 * @return The expected results.
1736 * @throws NullPointerException On null arguments.
1739 private static Manifest
__loadExpectedResults(String __testName
,
1740 Map
<String
, CandidateTestFiles
> __candidates
)
1741 throws NullPointerException
1743 if (__testName
== null || __candidates
== null)
1744 throw new NullPointerException("NARG");
1746 // If there is no candidate for this test, always just return a
1747 // blank manifest to be parsed
1748 CandidateTestFiles candidate
= __candidates
.get(__testName
);
1749 if (candidate
== null)
1750 return new Manifest();
1752 // Load information gleaned from the source code
1753 __SourceInfo__ info
;
1754 try (InputStream in
= Files
.newInputStream(
1755 candidate
.sourceCode
.getAbsolute(), StandardOpenOption
.READ
))
1757 String extension
= VMHelpers
.getExtension(
1758 candidate
.sourceCode
.getAbsolute());
1759 if ("class".equals(extension
))
1760 info
= __SourceInfo__
.loadClass(in
);
1761 else if ("j".equals(extension
))
1762 info
= __SourceInfo__
.loadJasmin(in
);
1764 info
= __SourceInfo__
.loadJava(in
);
1766 catch (IOException e
)
1768 throw new RuntimeException("Could not parse source: " +
1772 // Read the current manifest
1774 if (candidate
.expectedResult
== null)
1775 over
= new Manifest();
1777 try (InputStream in
= Files
.newInputStream(
1778 candidate
.expectedResult
.getAbsolute(), StandardOpenOption
.READ
))
1780 over
= new Manifest(in
);
1782 catch (IOException e
)
1784 throw new RuntimeException("Could not parse manifest: " +
1788 // If there is no super class there is no need to even try reading or
1789 // merging any of them
1790 if (info
.superClass
== null)
1793 Attributes overAttr
= over
.getMainAttributes();
1795 // Load super class information
1796 VMHelpers
.__loadExpectedResultsSub(overAttr
, info
.superClass
,
1799 // And interfaces...
1800 for (String implementsClass
: info
.implementsClasses
)
1801 VMHelpers
.__loadExpectedResultsSub(overAttr
, implementsClass
,
1808 * Loads the expected classes from the result.
1810 * @param __overAttr The attributes to potentially write over.
1811 * @param __class The class to check.
1812 * @param __candidates The candidates for finding the class.
1815 private static void __loadExpectedResultsSub(Attributes __overAttr
,
1816 String __class
, Map
<String
, CandidateTestFiles
> __candidates
)
1818 // Load the manifest that belongs to this class if it is possible
1819 Manifest under
= VMHelpers
.__loadExpectedResults(__class
,
1822 // Add the underlying manifest, provided it does not replace anything
1823 // on the higher level
1824 for (Map
.Entry
<Object
, Object
> e
: under
.getMainAttributes()
1826 __overAttr
.putIfAbsent(e
.getKey(), e
.getValue());
1830 * Parses multi-parameters from test results.
1832 * @param __expected The expected results to parse.
1833 * @return The multi-parameters, if any.
1834 * @throws NullPointerException On null arguments.
1837 private static Collection
<String
> __parseMultiParams(
1838 Manifest __expected
)
1839 throws NullPointerException
1841 if (__expected
== null)
1842 throw new NullPointerException("NARG");
1844 // Are there hyperparameters?
1845 String hyperIn
= __expected
.getMainAttributes()
1846 .getValue(VMHelpers
._HYPER_PARAMETERS_KEY
);
1848 // Get the possible parameter values
1849 String multiIn
= __expected
.getMainAttributes()
1850 .getValue(VMHelpers
._MULTI_PARAMETERS_KEY
);
1852 // Do nothing if there is neither
1853 if (hyperIn
== null && multiIn
== null)
1857 String
[] hyperSplit
= (hyperIn
== null ?
new String
[0] :
1858 hyperIn
.trim().split("[ \t]"));
1859 String
[] multiSplit
= (multiIn
== null ?
new String
[0] :
1860 multiIn
.trim().split("[ \t]"));
1862 // Has both parameters
1863 if (hyperSplit
.length
> 0 && multiSplit
.length
> 0)
1865 List
<String
> result
= new ArrayList
<>(
1866 hyperSplit
.length
* multiSplit
.length
);
1868 // Combine every possible variant of this
1869 for (String hyper
: hyperSplit
)
1870 for (String multi
: multiSplit
)
1871 result
.add(hyper
+ "@" + multi
);
1877 else if (hyperSplit
.length
> 0)
1878 return Arrays
.asList(hyperSplit
);
1879 else if (multiSplit
.length
> 0)
1880 return Arrays
.asList(multiSplit
);