From db9195b540b009908abc547705e2048a82c6ac92 Mon Sep 17 00:00:00 2001 From: Florian McKee <84742327+fmck3516@users.noreply.github.com> Date: Sun, 17 Mar 2024 19:53:31 -0500 Subject: [PATCH] catch up with latest in 0.0.18-SNAPSHOT --- .../io/skippy/build/SkippyBuildApiTest.java | 18 ++-- .../io/skippy/common/model/AnalyzedTest.java | 67 ++++++++++++--- .../io/skippy/common/model/ClassFile.java | 86 +++++++++++++------ .../common/model/ClassFileContainer.java | 22 ++--- .../common/model/SkippyConfiguration.java | 15 +++- .../common/model/TestImpactAnalysis.java | 8 +- .../common/repository/SkippyRepository.java | 51 +++++++++-- .../skippy/common/model/AnalyzedTestTest.java | 8 +- .../common/model/ClassFileContainerTest.java | 4 +- .../io/skippy/common/model/ClassFileTest.java | 10 +-- .../common/model/TestImpactAnalysisTest.java | 10 +-- .../gradle/GradleClassFileCollector.java | 2 +- .../skippy/maven/MavenClassFileCollector.java | 2 +- 13 files changed, 210 insertions(+), 93 deletions(-) diff --git a/skippy-build-common/src/test/java/io/skippy/build/SkippyBuildApiTest.java b/skippy-build-common/src/test/java/io/skippy/build/SkippyBuildApiTest.java index 6c324b7..bc8f323 100644 --- a/skippy-build-common/src/test/java/io/skippy/build/SkippyBuildApiTest.java +++ b/skippy-build-common/src/test/java/io/skippy/build/SkippyBuildApiTest.java @@ -77,7 +77,7 @@ void testEmptySkippyFolderWithoutExecFiles() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -128,7 +128,7 @@ void testEmptySkippyFolderWithTwoExecFilesExecutionDataPersistenceEnabled() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -188,7 +188,7 @@ void testEmptySkippyFolderWithTwoExecFiles() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -246,7 +246,7 @@ void testEmptySkippyFolderWithTwoExecFilesAndTwoExecFiles() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -306,7 +306,7 @@ void testEmptySkippyFolderWithTwoExecFilesOneFailedTests() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -363,7 +363,7 @@ void testExistingJsonFileNoExecFile() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -425,7 +425,7 @@ void testExistingJsonFileUpdatedExecFile() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -495,7 +495,7 @@ void testExistingJsonFileUpdatedExecFileExecutionDataEnabled() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { @@ -588,7 +588,7 @@ void testExistingJsonFileNewTestFailure() { verify(skippyRepository).saveTestImpactAnalysis(tiaCaptor.capture()); var tia = tiaCaptor.getValue(); - assertThat(tia.toJson(classProperties(NAME), allTestProperties())).isEqualToIgnoringWhitespace(""" + assertThat(tia.toJson(classProperties(ClassFile.JsonProperty.CF_CLASS), allTestProperties())).isEqualToIgnoringWhitespace(""" { "classes": { "0": { diff --git a/skippy-common/src/main/java/io/skippy/common/model/AnalyzedTest.java b/skippy-common/src/main/java/io/skippy/common/model/AnalyzedTest.java index 4d2037f..10fecd4 100644 --- a/skippy-common/src/main/java/io/skippy/common/model/AnalyzedTest.java +++ b/skippy-common/src/main/java/io/skippy/common/model/AnalyzedTest.java @@ -26,31 +26,70 @@ import static java.util.stream.Collectors.joining; /** - * Programmatic representation of a test in `test-impact-analysis.json`: - * + * Represents a test that has been analyzed by Skippy. + *

+ * A list of {@link AnalyzedTest}s together with a {@link ClassFileContainer} make up a {@link TestImpactAnalysis}. + *

+ * JSON example: *
  * {
  *      "class": "0",
  *      "result": "PASSED",
  *      "coveredClasses": ["0", "1"],
- *      "execution": "C57F877F6F9BF164"
+ *      "executionId": "C57F877F6F9BF164"
  * }
  * 
* + * @param testClassId the reference to the test class in the {@link ClassFileContainer} + * @param result the {@link TestResult} + * @param coveredClassesIds references to the covered classes in the {@link ClassFileContainer} + * @param executionId a unique identifier for JaCoCo execution data if capture of execution data is enabled + * (see {@link SkippyConfiguration#saveExecutionData()}), an empty {@link Optional} otherwise * @author Florian McKee */ public record AnalyzedTest(String testClassId, TestResult result, List coveredClassesIds, Optional executionId) implements Comparable { + /** + * Allows test to specify which properties to include in the JSON representation. This allows tests to focus on a + * sub-set of all properties instead of asserting against the value of all properties. + */ public enum JsonProperty { - CLASS, - RESULT, - COVERED_CLASSES, - EXECUTION_ID; + /** + * The reference to the test class in the {@link ClassFileContainer}. + */ + AT_CLASS, + + /** + * The {@link TestResult}. + */ + AT_RESULT, + + /** + * References to the covered classes in the {@link ClassFileContainer}. + */ + AT_COVERED_CLASSES, + + /** + * A unique identifier for JaCoCo execution data if capture of execution data is enabled. + */ + AT_EXECUTION_ID; + + /** + * Convenience method for tests that assert against a sub-set of the JSON representation. + * + * @param properties the input + * @return the input + */ public static AnalyzedTest.JsonProperty[] testProperties(AnalyzedTest.JsonProperty... properties) { - return Arrays.asList(properties).toArray(new AnalyzedTest.JsonProperty[0]); + return properties; } + /** + * Convenience method for tests that assert against the entire JSON representation. + * + * @return all properties + */ public static AnalyzedTest.JsonProperty[] allTestProperties() { return JsonProperty.values(); } @@ -121,7 +160,7 @@ private static List parseCoveredClasses(Tokenizer tokenizer) { } /** - * Renders this instance as JSON string. + * Returns this instance as JSON string. * * @return the instance as JSON string */ @@ -141,17 +180,17 @@ String toJson(JsonProperty... propertiesToRender) { var renderedProperties = new ArrayList(); for (var propertyToRender : propertiesToRender) { - if (propertyToRender == JsonProperty.EXECUTION_ID && executionId().isEmpty()) { + if (propertyToRender == JsonProperty.AT_EXECUTION_ID && executionId().isEmpty()) { continue; } renderedProperties.add(switch (propertyToRender) { - case CLASS -> "\t\t\t\"class\": \"%s\"".formatted(testClassId()); - case RESULT -> "\t\t\t\"result\": \"%s\"".formatted(result()); - case COVERED_CLASSES -> "\t\t\t\"coveredClasses\": [%s]".formatted(coveredClassesIds().stream() + case AT_CLASS -> "\t\t\t\"class\": \"%s\"".formatted(testClassId()); + case AT_RESULT -> "\t\t\t\"result\": \"%s\"".formatted(result()); + case AT_COVERED_CLASSES -> "\t\t\t\"coveredClasses\": [%s]".formatted(coveredClassesIds().stream() .map(Integer::valueOf) .sorted() .map(id -> "\"%s\"".formatted(id)).collect(joining(","))); - case EXECUTION_ID -> "\t\t\t\"executionId\": \"%s\"".formatted(executionId.get()); + case AT_EXECUTION_ID -> "\t\t\t\"executionId\": \"%s\"".formatted(executionId.get()); }); } result.append(renderedProperties.stream().collect(joining("," + lineSeparator()))); diff --git a/skippy-common/src/main/java/io/skippy/common/model/ClassFile.java b/skippy-common/src/main/java/io/skippy/common/model/ClassFile.java index 640189b..e544268 100644 --- a/skippy-common/src/main/java/io/skippy/common/model/ClassFile.java +++ b/skippy-common/src/main/java/io/skippy/common/model/ClassFile.java @@ -30,8 +30,9 @@ import static java.util.stream.Collectors.joining; /** - * Programmatic representation of a class file in `test-impact-analysis.json`: - * + * Represents a class file that has been analyzed by Skippy. + *

+ * JSON example: *
  *  {
  *      "class": "com.example.Foo",
@@ -45,21 +46,52 @@
  */
 public final class ClassFile implements Comparable {
 
-    private final String className;
+    private final String clazz;
     private final Path outputFolder;
-    private final Path classFile;
+    private final Path path;
     private final String hash;
 
+    /**
+     * Allows test to specify which properties to include in the JSON representation. This allows tests to focus on a
+     * sub-set of all properties instead of asserting against the value of all properties.
+     */
     public enum JsonProperty {
-        NAME,
-        FILE,
-        OUTPUT_FOLDER,
-        HASH;
 
+        /**
+         * The fully qualified class name.
+         */
+        CF_CLASS,
+
+        /**
+         * The path of the class file relative to the output folder (e.g., com/example/Foo.class).
+         */
+        CF_PATH,
+
+        /**
+         * The path of the output folder relative to the project root (e.g., build/classes/java/main).
+         */
+        CF_OUTPUT_FOLDER,
+
+        /**
+         * The hash of the class file.
+         */
+        CF_HASH;
+
+        /**
+         * Convenience method for tests that assert against a sub-set of the JSON representation.
+         *
+         * @param properties the input
+         * @return the input
+         */
         public static JsonProperty[] classProperties(ClassFile.JsonProperty... properties) {
-            return Arrays.asList(properties).toArray(new ClassFile.JsonProperty[0]);
+            return properties;
         }
 
+        /**
+         * Convenience method for tests that assert against the entire JSON representation.
+         *
+         * @return all properties
+         */
         public static JsonProperty[] allClassProperties() {
             return values();
         }
@@ -68,15 +100,15 @@ public static JsonProperty[] allClassProperties() {
     /**
      * C'tor.
      *
-     * @param className the fully qualified class name
+     * @param clazz the fully qualified class name
      * @param outputFolder the path of the output folder relative to the project root (e.g., build/classes/java/main)
-     * @param classFile the path of the class file relative to the output folder (e.g., com/example/Foo.class)
+     * @param path the path of the class file relative to the output folder (e.g., com/example/Foo.class)
      * @param hash a hash of the class file
      */
-    private ClassFile(String className, Path outputFolder, Path classFile, String hash) {
-        this.className = className;
+    private ClassFile(String clazz, Path outputFolder, Path path, String hash) {
+        this.clazz = clazz;
         this.outputFolder = outputFolder;
-        this.classFile = classFile;
+        this.path = path;
         this.hash = hash;
     }
 
@@ -151,10 +183,10 @@ String toJson(JsonProperty... propertiesToRender) {
         var renderedProperties = new ArrayList();
         for (var propertyToRender : propertiesToRender) {
             renderedProperties.add(switch (propertyToRender) {
-                case NAME -> "\t\t\t\"name\": \"%s\"".formatted(className);
-                case FILE -> "\t\t\t\"path\": \"%s\"".formatted(classFile);
-                case OUTPUT_FOLDER -> "\t\t\t\"outputFolder\": \"%s\"".formatted(outputFolder);
-                case HASH -> "\t\t\t\"hash\": \"%s\"".formatted(hash);
+                case CF_CLASS -> "\t\t\t\"name\": \"%s\"".formatted(clazz);
+                case CF_PATH -> "\t\t\t\"path\": \"%s\"".formatted(path);
+                case CF_OUTPUT_FOLDER -> "\t\t\t\"outputFolder\": \"%s\"".formatted(outputFolder);
+                case CF_HASH -> "\t\t\t\"hash\": \"%s\"".formatted(hash);
             });
         }
         result.append(renderedProperties.stream().collect(joining("," +  lineSeparator())));
@@ -168,13 +200,13 @@ String toJson(JsonProperty... propertiesToRender) {
      *
      * @return the fully qualified class name (e.g., com.example.Foo)
      */
-    public String getClassName() {
-        return className;
+    public String getClazz() {
+        return clazz;
     }
 
     @Override
     public int compareTo(ClassFile other) {
-        return comparing(ClassFile::getClassName)
+        return comparing(ClassFile::getClazz)
                 .thenComparing(ClassFile::getOutputFolder)
                 .compare(this, other);
     }
@@ -182,14 +214,14 @@ public int compareTo(ClassFile other) {
     @Override
     public boolean equals(Object other) {
         if (other instanceof ClassFile c) {
-            return Objects.equals(getClassName() + getOutputFolder(), c.getClassName()  + c.getOutputFolder());
+            return Objects.equals(getClazz() + getOutputFolder(), c.getClazz()  + c.getOutputFolder());
         }
         return false;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(getClassName(), getOutputFolder());
+        return Objects.hash(getClazz(), getOutputFolder());
     }
 
     /**
@@ -206,8 +238,8 @@ Path getOutputFolder() {
      *
      * @return the path of the class file relative to the output folder (e.g., com/example/Foo.class)
      */
-    Path getClassFile() {
-        return classFile;
+    Path getPath() {
+        return path;
     }
 
     /**
@@ -220,10 +252,10 @@ String getHash() {
     }
 
     boolean hasChanged() {
-        return ! hash.equals(debugAgnosticHash(outputFolder.resolve(classFile)));
+        return ! hash.equals(debugAgnosticHash(outputFolder.resolve(path)));
     }
 
     boolean classFileNotFound() {
-        return false == exists(outputFolder.resolve(classFile));
+        return false == exists(outputFolder.resolve(path));
     }
 }
diff --git a/skippy-common/src/main/java/io/skippy/common/model/ClassFileContainer.java b/skippy-common/src/main/java/io/skippy/common/model/ClassFileContainer.java
index ed299f4..d4152f4 100644
--- a/skippy-common/src/main/java/io/skippy/common/model/ClassFileContainer.java
+++ b/skippy-common/src/main/java/io/skippy/common/model/ClassFileContainer.java
@@ -28,13 +28,16 @@
 
 /**
  * Container for {@link ClassFile}s that stores static information about classes in a project.
- * It supports a variety of queries:
+ * 

+ * A list of {@link AnalyzedTest}s together with a {@link ClassFileContainer} make up a {@link TestImpactAnalysis}. + *

+ * A {@link ClassFileContainer} supports a variety of queries: *
    *
  • get {@link ClassFile} by id
  • *
  • get ids by class name
  • *
  • get {@link ClassFile} by id
  • *
- * The JSON representation: + * JSON example: *
  * {
  *      "0": {
@@ -54,8 +57,7 @@
  * 
* * A {@link ClassFileContainer} assigns a numerical id to each analyzed class file. Those ids are used for referencing - * purposes in the JSON representation of a {@link TestImpactAnalysis}. - *

+ * purposes in the JSON representation of the {@link TestImpactAnalysis}. * * @author Florian McKee */ @@ -74,14 +76,14 @@ private ClassFileContainer(Map classFilesById) { classFiles.add(classFile); idsByClassFile.put(classFile, id); this.classFilesById.put(entry.getKey(), entry.getValue()); - if (false == idsByClassName.containsKey(classFile.getClassName())) { - idsByClassName.put(classFile.getClassName(), new ArrayList<>()); + if (false == idsByClassName.containsKey(classFile.getClazz())) { + idsByClassName.put(classFile.getClazz(), new ArrayList<>()); } - idsByClassName.get(classFile.getClassName()).add(id); - if (false == classFilesByClassName.containsKey(classFile.getClassName())) { - classFilesByClassName.put(classFile.getClassName(), new ArrayList<>()); + idsByClassName.get(classFile.getClazz()).add(id); + if (false == classFilesByClassName.containsKey(classFile.getClazz())) { + classFilesByClassName.put(classFile.getClazz(), new ArrayList<>()); } - classFilesByClassName.get(classFile.getClassName()).add(classFile); + classFilesByClassName.get(classFile.getClazz()).add(classFile); } } diff --git a/skippy-common/src/main/java/io/skippy/common/model/SkippyConfiguration.java b/skippy-common/src/main/java/io/skippy/common/model/SkippyConfiguration.java index ff43f47..3f4092f 100644 --- a/skippy-common/src/main/java/io/skippy/common/model/SkippyConfiguration.java +++ b/skippy-common/src/main/java/io/skippy/common/model/SkippyConfiguration.java @@ -27,8 +27,14 @@ public record SkippyConfiguration(boolean saveExecutionData) { public static final SkippyConfiguration DEFAULT = new SkippyConfiguration(false); - public static SkippyConfiguration parse(String string) { - var tokenizer = new Tokenizer(string); + /** + * Creates a new instance from JSON. + * + * @param json the JSON representation of a {@link SkippyConfiguration} + * @return a new instance from JSON + */ + public static SkippyConfiguration parse(String json) { + var tokenizer = new Tokenizer(json); tokenizer.skip('{'); boolean executionData = false; while (true) { @@ -48,6 +54,11 @@ public static SkippyConfiguration parse(String string) { return new SkippyConfiguration(executionData); } + /** + * Returns this instance as JSON string. + * + * @return the instance as JSON string + */ public String toJson() { return """ { diff --git a/skippy-common/src/main/java/io/skippy/common/model/TestImpactAnalysis.java b/skippy-common/src/main/java/io/skippy/common/model/TestImpactAnalysis.java index fb4009c..f77b49d 100644 --- a/skippy-common/src/main/java/io/skippy/common/model/TestImpactAnalysis.java +++ b/skippy-common/src/main/java/io/skippy/common/model/TestImpactAnalysis.java @@ -87,7 +87,7 @@ public String getId() { public PredictionWithReason predict(String testClassName) { return Profiler.profile("TestImpactAnalysis#predict", () -> { var maybeAnalyzedTest = analyzedTests.stream() - .filter(test -> classFileContainer.getById(test.testClassId()).getClassName().equals(testClassName)) + .filter(test -> classFileContainer.getById(test.testClassId()).getClazz().equals(testClassName)) .findFirst(); if (maybeAnalyzedTest.isEmpty()) { return PredictionWithReason.execute(new Reason(NO_DATA_FOUND_FOR_TEST, Optional.empty())); @@ -100,7 +100,7 @@ public PredictionWithReason predict(String testClassName) { } if (testClass.classFileNotFound()) { - return PredictionWithReason.execute(new Reason(TEST_CLASS_CLASS_FILE_NOT_FOUND, Optional.of(testClass.getClassFile().toString()))); + return PredictionWithReason.execute(new Reason(TEST_CLASS_CLASS_FILE_NOT_FOUND, Optional.of(testClass.getPath().toString()))); } if (testClass.hasChanged()) { @@ -109,10 +109,10 @@ public PredictionWithReason predict(String testClassName) { for (var coveredClassId : analyzedTest.coveredClassesIds()) { var coveredClass = classFileContainer.getById(coveredClassId); if (coveredClass.classFileNotFound()) { - return PredictionWithReason.execute(new Reason(COVERED_CLASS_CLASS_FILE_NOT_FOUND, Optional.of(coveredClass.getClassFile().toString()))); + return PredictionWithReason.execute(new Reason(COVERED_CLASS_CLASS_FILE_NOT_FOUND, Optional.of(coveredClass.getPath().toString()))); } if (coveredClass.hasChanged()) { - return PredictionWithReason.execute(new Reason(BYTECODE_CHANGE_IN_COVERED_CLASS, Optional.of(coveredClass.getClassName()))); + return PredictionWithReason.execute(new Reason(BYTECODE_CHANGE_IN_COVERED_CLASS, Optional.of(coveredClass.getClazz()))); } } return PredictionWithReason.skip(new Reason(NO_CHANGE, Optional.empty())); diff --git a/skippy-common/src/main/java/io/skippy/common/repository/SkippyRepository.java b/skippy-common/src/main/java/io/skippy/common/repository/SkippyRepository.java index 35ac9b3..2af4377 100644 --- a/skippy-common/src/main/java/io/skippy/common/repository/SkippyRepository.java +++ b/skippy-common/src/main/java/io/skippy/common/repository/SkippyRepository.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Optional; import java.util.zip.Deflater; +import java.util.zip.Inflater; import static java.nio.file.Files.*; import static java.nio.file.StandardOpenOption.CREATE; @@ -268,7 +269,15 @@ public Optional readTestImpactAnalysis() { @Override public Optional readJacocoExecutionData(String executionId) { - return Optional.empty(); + try { + var execFile = SkippyFolder.get(this.projectDir).resolve("%s.exec".formatted(executionId)); + if (exists(execFile)) { + return Optional.of(unzip(readAllBytes(execFile))); + } + return Optional.empty(); + } catch (IOException e) { + throw new UncheckedIOException("Unable to read JaCoCo execution data %s: %s.".formatted(executionId, e.getMessage()), e); + } } @Override @@ -301,30 +310,54 @@ public String saveJacocoExecutionData(byte[] jacocoExecutionData) { } try { var executionId = JacocoExecutionDataUtil.getExecutionId(jacocoExecutionData); - Files.write(SkippyFolder.get(projectDir).resolve("%s.exec".formatted(executionId)), compress(jacocoExecutionData), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + Files.write(SkippyFolder.get(projectDir).resolve("%s.exec".formatted(executionId)), zip(jacocoExecutionData), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); return executionId; } catch (IOException e) { throw new UncheckedIOException("Unable to save JaCoCo execution data: %s.".formatted(e.getMessage()), e); } } - private static byte[] compress(byte[] data) { + private static byte[] zip(byte[] data) { Deflater deflater = new Deflater(); deflater.setInput(data); deflater.finish(); byte[] buffer = new byte[1024]; - byte[] outputStream = new byte[0]; + byte[] result = new byte[0]; while (!deflater.finished()) { int count = deflater.deflate(buffer); - byte[] newOutputStream = new byte[outputStream.length + count]; - System.arraycopy(outputStream, 0, newOutputStream, 0, outputStream.length); - System.arraycopy(buffer, 0, newOutputStream, outputStream.length, count); - outputStream = newOutputStream; + byte[] tmp = new byte[result.length + count]; + System.arraycopy(result, 0, tmp, 0, result.length); + System.arraycopy(buffer, 0, tmp, result.length, count); + result = tmp; } deflater.end(); - return outputStream; + return result; + } + + public static byte[] unzip(byte[] data) { + Inflater inflater = new Inflater(); + inflater.setInput(data); + + byte[] buffer = new byte[1024]; + byte[] result = new byte[0]; + + try { + while (!inflater.finished()) { + int count = inflater.inflate(buffer); + byte[] tmp = new byte[result.length + count]; + System.arraycopy(result, 0, tmp, 0, result.length); + System.arraycopy(buffer, 0, tmp, result.length, count); + result = tmp; + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + inflater.end(); + } + + return result; } private void deleteObsoleteExecutionDataFiles(TestImpactAnalysis testImpactAnalysis) { diff --git a/skippy-common/src/test/java/io/skippy/common/model/AnalyzedTestTest.java b/skippy-common/src/test/java/io/skippy/common/model/AnalyzedTestTest.java index 7761aa8..9f8599d 100644 --- a/skippy-common/src/test/java/io/skippy/common/model/AnalyzedTestTest.java +++ b/skippy-common/src/test/java/io/skippy/common/model/AnalyzedTestTest.java @@ -158,7 +158,7 @@ void testParseWithExecutionId() { void testToJsonClassProperty() { var analyzedTest = new AnalyzedTest("0", TestResult.PASSED, asList("0", "1")); - assertThat(analyzedTest.toJson(CLASS)).isEqualToIgnoringWhitespace(""" + assertThat(analyzedTest.toJson(AT_CLASS)).isEqualToIgnoringWhitespace(""" { "class": "0" } @@ -169,7 +169,7 @@ void testToJsonClassProperty() { void testToJsonResultProperty() { var analyzedTest = new AnalyzedTest("0", TestResult.PASSED, asList("0", "1")); - assertThat(analyzedTest.toJson(RESULT)).isEqualToIgnoringWhitespace(""" + assertThat(analyzedTest.toJson(AT_RESULT)).isEqualToIgnoringWhitespace(""" { "result": "PASSED" } @@ -180,7 +180,7 @@ void testToJsonResultProperty() { void testToJsonCoveredClassesProperty() { var analyzedTest = new AnalyzedTest("0", TestResult.PASSED, asList("0", "1")); - assertThat(analyzedTest.toJson(COVERED_CLASSES)).isEqualToIgnoringWhitespace(""" + assertThat(analyzedTest.toJson(AT_COVERED_CLASSES)).isEqualToIgnoringWhitespace(""" { "coveredClasses": ["0", "1"] } @@ -190,7 +190,7 @@ void testToJsonCoveredClassesProperty() { void testToJsonExecutionProperty() { var analyzedTest = new AnalyzedTest("0", TestResult.PASSED, asList("0", "1"), "0".repeat(32)); - assertThat(analyzedTest.toJson(EXECUTION_ID)).isEqualToIgnoringWhitespace(""" + assertThat(analyzedTest.toJson(AT_EXECUTION_ID)).isEqualToIgnoringWhitespace(""" { "executionId": "00000000000000000000000000000000" } diff --git a/skippy-common/src/test/java/io/skippy/common/model/ClassFileContainerTest.java b/skippy-common/src/test/java/io/skippy/common/model/ClassFileContainerTest.java index fedda13..49296fa 100644 --- a/skippy-common/src/test/java/io/skippy/common/model/ClassFileContainerTest.java +++ b/skippy-common/src/test/java/io/skippy/common/model/ClassFileContainerTest.java @@ -89,8 +89,8 @@ void testParse() { } """)); assertEquals(2, classFileContainer.getClassFiles().size()); - assertEquals("com.example.LeftPadder", classFileContainer.getById("0").getClassName()); - assertEquals("com.example.LeftPadderTest", classFileContainer.getById("1").getClassName()); + assertEquals("com.example.LeftPadder", classFileContainer.getById("0").getClazz()); + assertEquals("com.example.LeftPadderTest", classFileContainer.getById("1").getClazz()); assertEquals(asList("0"), classFileContainer.getIdsByClassName("com.example.LeftPadder")); assertEquals(asList("1"), classFileContainer.getIdsByClassName("com.example.LeftPadderTest")); } diff --git a/skippy-common/src/test/java/io/skippy/common/model/ClassFileTest.java b/skippy-common/src/test/java/io/skippy/common/model/ClassFileTest.java index f697cde..f32b917 100644 --- a/skippy-common/src/test/java/io/skippy/common/model/ClassFileTest.java +++ b/skippy-common/src/test/java/io/skippy/common/model/ClassFileTest.java @@ -56,7 +56,7 @@ void testToJsonSingleProperty() { "ZT0GoiWG8Az5TevH9/JwBg==" ); - assertThat(classFile.toJson(ClassFile.JsonProperty.NAME)).isEqualToIgnoringWhitespace( + assertThat(classFile.toJson(ClassFile.JsonProperty.CF_CLASS)).isEqualToIgnoringWhitespace( """ { "name": "com.example.RightPadder" @@ -76,8 +76,8 @@ void testParse() { } """ )); - assertEquals("com.example.RightPadder", classFile.getClassName()); - assertEquals(Path.of("com/example/RightPadder.class"), classFile.getClassFile()); + assertEquals("com.example.RightPadder", classFile.getClazz()); + assertEquals(Path.of("com/example/RightPadder.class"), classFile.getPath()); assertEquals(Path.of("build/classes/java/main"), classFile.getOutputFolder()); assertEquals("ZT0GoiWG8Az5TevH9/JwBg==", classFile.getHash()); } @@ -92,7 +92,7 @@ void testGetClassName(String fileName, String expectedValue) throws URISyntaxExc var classFile = Paths.get(getClass().getResource(fileName).toURI()); var outputFolder = classFile.getParent(); var projectDir = outputFolder.getParent(); - assertEquals(expectedValue, ClassFile.fromFileSystem(projectDir, outputFolder, classFile).getClassName()); + assertEquals(expectedValue, ClassFile.fromFileSystem(projectDir, outputFolder, classFile).getClazz()); } @ParameterizedTest @@ -104,7 +104,7 @@ void testGetClassFile(String fileName, String expectedValue) throws URISyntaxExc var classFile = Paths.get(getClass().getResource(fileName).toURI()); var outputFolder = classFile.getParent(); var projectDir = outputFolder.getParent(); - assertEquals(Path.of(expectedValue), ClassFile.fromFileSystem(projectDir, outputFolder, classFile).getClassFile()); + assertEquals(Path.of(expectedValue), ClassFile.fromFileSystem(projectDir, outputFolder, classFile).getPath()); } @ParameterizedTest diff --git a/skippy-common/src/test/java/io/skippy/common/model/TestImpactAnalysisTest.java b/skippy-common/src/test/java/io/skippy/common/model/TestImpactAnalysisTest.java index f8b3d83..1dff1fa 100644 --- a/skippy-common/src/test/java/io/skippy/common/model/TestImpactAnalysisTest.java +++ b/skippy-common/src/test/java/io/skippy/common/model/TestImpactAnalysisTest.java @@ -191,7 +191,7 @@ void testParseOneTestOneClass() { var classFiles = new ArrayList<>(testImpactAnalysis.getClassFileContainer().getClassFiles()); assertEquals(1, classFiles.size()); - assertEquals("com.example.FooTest", classFiles.get(0).getClassName()); + assertEquals("com.example.FooTest", classFiles.get(0).getClazz()); var tests = testImpactAnalysis.getAnalyzedTests(); assertEquals(1, tests.size()); @@ -247,10 +247,10 @@ void testParseTwoTestsFourClasses() { var classFiles = new ArrayList<>(testImpactAnalysis.getClassFileContainer().getClassFiles()); assertEquals(4, classFiles.size()); - assertEquals("com.example.Class1", classFiles.get(0).getClassName()); - assertEquals("com.example.Class1Test", classFiles.get(1).getClassName()); - assertEquals("com.example.Class2", classFiles.get(2).getClassName()); - assertEquals("com.example.Class2Test", classFiles.get(3).getClassName()); + assertEquals("com.example.Class1", classFiles.get(0).getClazz()); + assertEquals("com.example.Class1Test", classFiles.get(1).getClazz()); + assertEquals("com.example.Class2", classFiles.get(2).getClazz()); + assertEquals("com.example.Class2Test", classFiles.get(3).getClazz()); var tests = testImpactAnalysis.getAnalyzedTests(); assertEquals(2, tests.size()); diff --git a/skippy-gradle/src/main/java/io/skippy/gradle/GradleClassFileCollector.java b/skippy-gradle/src/main/java/io/skippy/gradle/GradleClassFileCollector.java index 6f5bb28..24fe07d 100644 --- a/skippy-gradle/src/main/java/io/skippy/gradle/GradleClassFileCollector.java +++ b/skippy-gradle/src/main/java/io/skippy/gradle/GradleClassFileCollector.java @@ -90,7 +90,7 @@ private List collect(File outputFolder, File directory) { private List sort(List input) { return input.stream() - .sorted(comparing(ClassFile::getClassName)) + .sorted(comparing(ClassFile::getClazz)) .toList(); } diff --git a/skippy-maven/src/main/java/io/skippy/maven/MavenClassFileCollector.java b/skippy-maven/src/main/java/io/skippy/maven/MavenClassFileCollector.java index ef4c7a9..f9afe2c 100644 --- a/skippy-maven/src/main/java/io/skippy/maven/MavenClassFileCollector.java +++ b/skippy-maven/src/main/java/io/skippy/maven/MavenClassFileCollector.java @@ -72,7 +72,7 @@ private List collect(File outputFolder, File searchDirectory) { private List sort(List input) { return input.stream() - .sorted(comparing(ClassFile::getClassName)) + .sorted(comparing(ClassFile::getClazz)) .toList(); }