From 539a8ab4e8cf8cf72dfdd93814913e34ceb00c23 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Wed, 11 Dec 2024 20:22:09 -0800 Subject: [PATCH 1/3] Add JSON file persistence for event files Add functionality to persist and read the list of files to/from a JSON file in `EventImplWriter`. * Add methods to serialize and deserialize the list of files to/from a JSON file. * Call the serialization method at the end of each scan and the deserialization method at the start of each scan. * Validate if the existing files are still present and restart the file collection if files have been removed. * Add unit tests in `EventImplWriterTest` to verify the output of the JSON file, including serialization, deserialization, and validation of the file list. * Add tests in `TestEventFactoryTest` to assert the existence and contents of the output JSON file. --- .../processor/EventImplWriter.java | 49 ++++++++ .../processor/EventImplWriterTest.java | 109 ++++++++++++++++++ .../java/test/event/TestEventFactoryTest.java | 13 +++ 3 files changed, 171 insertions(+) create mode 100644 src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java diff --git a/src/main/java/org/spongepowered/eventimplgen/processor/EventImplWriter.java b/src/main/java/org/spongepowered/eventimplgen/processor/EventImplWriter.java index 7c867b6..0cbd040 100644 --- a/src/main/java/org/spongepowered/eventimplgen/processor/EventImplWriter.java +++ b/src/main/java/org/spongepowered/eventimplgen/processor/EventImplWriter.java @@ -44,13 +44,18 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.util.Elements; +import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; /** * A consumer of computed event information, that will generate individual @@ -96,6 +101,7 @@ public class EventImplWriter implements PropertyConsumer { this.outputFactory = options.generatedEventFactory(); this.factoryGenerator = factoryGenerator; this.generator = generator; + this.readFileList(); } @Override @@ -148,6 +154,7 @@ public void dumpRound(final Set rootElements) throws IOExcept this.allFoundProperties.putAll(this.roundFoundProperties); this.roundFoundProperties.clear(); + this.serializeFileList(); } public void dumpFinal() throws IOException { @@ -165,4 +172,46 @@ public void dumpFinal() throws IOException { } return (DeclaredType) this.elements.getTypeElement("java.lang.Object").asType(); } + + private void serializeFileList() throws IOException { + Gson gson = new Gson(); + try (FileWriter writer = new FileWriter("fileList.json")) { + gson.toJson(this.allFoundProperties.keySet().stream() + .map(e -> this.elements.getBinaryName(e).toString()) + .toList(), writer); + } + } + + private List deserializeFileList() throws IOException { + Gson gson = new Gson(); + try (var reader = Files.newBufferedReader(Paths.get("fileList.json"))) { + return gson.fromJson(reader, new TypeToken>() {}.getType()); + } + } + + public void validateFileList() throws IOException { + List fileList = deserializeFileList(); + for (String fileName : fileList) { + if (this.elements.getTypeElement(fileName) == null) { + this.allFoundProperties.clear(); + this.roundFoundProperties.clear(); + this.classesWritten = false; + break; + } + } + } + + private void readFileList() { + try { + List fileList = deserializeFileList(); + for (String fileName : fileList) { + TypeElement element = this.elements.getTypeElement(fileName); + if (element != null) { + this.allFoundProperties.put(element, new EventData(new ArrayList<>(), Set.of())); + } + } + } catch (IOException e) { + // Handle exception + } + } } diff --git a/src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java b/src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java new file mode 100644 index 0000000..97ecbb8 --- /dev/null +++ b/src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java @@ -0,0 +1,109 @@ +package org.spongepowered.eventimplgen.processor; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +public class EventImplWriterTest { + + private EventImplWriter writer; + private Elements elements; + private FileWriter fileWriter; + + @BeforeEach + public void setUp() throws IOException { + elements = mock(Elements.class); + fileWriter = mock(FileWriter.class); + writer = new EventImplWriter( + mock(Filer.class), + elements, + mock(PropertySorter.class), + Set.of(), + mock(EventGenOptions.class), + mock(FactoryInterfaceGenerator.class), + mock(ClassGenerator.class) + ); + } + + @Test + public void testSerializeFileList() throws IOException { + TypeElement element1 = mock(TypeElement.class); + TypeElement element2 = mock(TypeElement.class); + when(elements.getBinaryName(element1)).thenReturn(() -> "test.Element1"); + when(elements.getBinaryName(element2)).thenReturn(() -> "test.Element2"); + + writer.allFoundProperties.put(element1, new EventData(List.of(), Set.of())); + writer.allFoundProperties.put(element2, new EventData(List.of(), Set.of())); + + writer.serializeFileList(); + + Gson gson = new Gson(); + List expectedList = List.of("test.Element1", "test.Element2"); + String expectedJson = gson.toJson(expectedList); + + String actualJson = Files.readString(Paths.get("fileList.json")); + assertEquals(expectedJson, actualJson); + } + + @Test + public void testDeserializeFileList() throws IOException { + Gson gson = new Gson(); + List expectedList = List.of("test.Element1", "test.Element2"); + String json = gson.toJson(expectedList); + Files.writeString(Paths.get("fileList.json"), json); + + List actualList = writer.deserializeFileList(); + assertEquals(expectedList, actualList); + } + + @Test + public void testValidateFileList() throws IOException { + TypeElement element1 = mock(TypeElement.class); + TypeElement element2 = mock(TypeElement.class); + when(elements.getTypeElement("test.Element1")).thenReturn(element1); + when(elements.getTypeElement("test.Element2")).thenReturn(null); + + Gson gson = new Gson(); + List fileList = List.of("test.Element1", "test.Element2"); + String json = gson.toJson(fileList); + Files.writeString(Paths.get("fileList.json"), json); + + writer.validateFileList(); + + assertEquals(0, writer.allFoundProperties.size()); + assertEquals(0, writer.roundFoundProperties.size()); + assertEquals(false, writer.classesWritten); + } + + @Test + public void testReadFileList() throws IOException { + TypeElement element1 = mock(TypeElement.class); + when(elements.getTypeElement("test.Element1")).thenReturn(element1); + + Gson gson = new Gson(); + List fileList = List.of("test.Element1"); + String json = gson.toJson(fileList); + Files.writeString(Paths.get("fileList.json"), json); + + writer.readFileList(); + + assertEquals(1, writer.allFoundProperties.size()); + assertEquals(element1, writer.allFoundProperties.keySet().iterator().next()); + } +} diff --git a/test-data/src/test/java/test/event/TestEventFactoryTest.java b/test-data/src/test/java/test/event/TestEventFactoryTest.java index af2ca50..945850c 100644 --- a/test-data/src/test/java/test/event/TestEventFactoryTest.java +++ b/test-data/src/test/java/test/event/TestEventFactoryTest.java @@ -28,6 +28,9 @@ import org.junit.jupiter.api.Test; import test.event.lifecycle.NestedTest; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.List; class TestEventFactoryTest { @@ -72,4 +75,14 @@ void testImplicitlyAllowedByAnnotation() { Assertions.assertNotNull(TestEventFactory.createInclusiveEvent(List.of(), false)); } + @Test + void testJsonFileExists() throws IOException { + Assertions.assertTrue(Files.exists(Paths.get("fileList.json"))); + } + + @Test + void testJsonFileContents() throws IOException { + String jsonContent = Files.readString(Paths.get("fileList.json")); + Assertions.assertTrue(jsonContent.contains("test.event.lifecycle.NestedTest")); + } } From 119fe9c50d6dd8996472d0433fd190212a92527e Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Wed, 11 Dec 2024 20:25:28 -0800 Subject: [PATCH 2/3] Add license header to `EventImplWriterTest.java` * Attach the license header to the new test file --- .../processor/EventImplWriterTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java b/src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java index 97ecbb8..56a04b6 100644 --- a/src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java +++ b/src/test/java/org/spongepowered/eventimplgen/processor/EventImplWriterTest.java @@ -1,3 +1,27 @@ +/* + * This file is part of Event Implementation Generator, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package org.spongepowered.eventimplgen.processor; import com.google.gson.Gson; From ef4266c2df053e396e8cf2b5228e453ca97d3f87 Mon Sep 17 00:00:00 2001 From: Gabriel Harris-Rouquette Date: Wed, 11 Dec 2024 20:30:58 -0800 Subject: [PATCH 3/3] Add Gson dependency and module requirement * Add `requires com.google.gson` to `module-info.java` * Add Gson library entry to `libs.versions.toml` * Add Gson dependency to `dependencies` section in `build.gradle` --- annotations/src/main/java/module-info.java | 4 +++- build.gradle | 4 +++- gradle/libs.versions.toml | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/annotations/src/main/java/module-info.java b/annotations/src/main/java/module-info.java index d36dc82..a4f2a46 100644 --- a/annotations/src/main/java/module-info.java +++ b/annotations/src/main/java/module-info.java @@ -4,4 +4,6 @@ // This way we can still use the internal package, but not // to external developers. exports org.spongepowered.eventgen.annotations.internal to org.spongepowered.eventimplgen; -} \ No newline at end of file + + requires com.google.gson; +} diff --git a/build.gradle b/build.gradle index 0702147..e532cb2 100644 --- a/build.gradle +++ b/build.gradle @@ -109,6 +109,8 @@ dependencies { compileOnlyApi libs.jetbrainsAnnotations + api(libs.gson) + // Tests testImplementation libs.assertj testImplementation libs.joor @@ -119,4 +121,4 @@ dependencies { testImplementation libs.junit.params testRuntimeOnly libs.junit.engine testRuntimeOnly libs.junit.launcher -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f73f752..4847174 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ checkerQual = "3.26.0" dagger = "2.52" errorprone = "2.28.0" junit = "5.10.2" +gson = "2.8.8" [libraries] autoService-annotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoService" } @@ -19,6 +20,7 @@ javapoet = { module = "io.soabase.java-composer:java-composer", version = "1.0" jetbrainsAnnotations = { module = "org.jetbrains:annotations", version = "24.1.0"} jakartaInject = { module = "jakarta.inject:jakarta.inject-api", version = "2.0.1" } javaxInject = { module = "javax.inject:javax.inject", version = "1" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } # Tests assertj = { module = "org.assertj:assertj-core", version = "3.26.0" }