diff --git a/build.gradle.kts b/build.gradle.kts index 0f4d4fca8..77ff0325e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -64,6 +64,7 @@ dependencies { implementation(libs.jsoup) implementation(libs.commons.text) implementation(libs.jtokkit) + testImplementation(kotlin("test")) } tasks.register("updateSubmodules") { diff --git a/codegpt-telemetry/build.gradle.kts b/codegpt-telemetry/build.gradle.kts index 60546d9ec..a808a377b 100644 --- a/codegpt-telemetry/build.gradle.kts +++ b/codegpt-telemetry/build.gradle.kts @@ -4,4 +4,5 @@ plugins { dependencies { implementation(libs.analytics) + implementation(libs.gson) } diff --git a/codegpt-telemetry/src/main/java/ee/carlrobert/codegpt/telemetry/core/service/segment/IdentifyTraitsPersistence.java b/codegpt-telemetry/src/main/java/ee/carlrobert/codegpt/telemetry/core/service/segment/IdentifyTraitsPersistence.java index ab20ce074..bca14b317 100644 --- a/codegpt-telemetry/src/main/java/ee/carlrobert/codegpt/telemetry/core/service/segment/IdentifyTraitsPersistence.java +++ b/codegpt-telemetry/src/main/java/ee/carlrobert/codegpt/telemetry/core/service/segment/IdentifyTraitsPersistence.java @@ -28,9 +28,10 @@ public class IdentifyTraitsPersistence { public static final IdentifyTraitsPersistence INSTANCE = new IdentifyTraitsPersistence(); private static final Logger LOGGER = Logger.getInstance(IdentifyTraitsPersistence.class); - private static final Path FILE = Directories.PATH.resolve("segment-identify-traits.json"); + static Path FILE = Directories.PATH.resolve("segment-identify-traits.json"); - private IdentifyTraits identifyTraits = null; + IdentifyTraits identifyTraits = null; + private Gson gson = new Gson(); protected IdentifyTraitsPersistence() {} @@ -41,36 +42,25 @@ public synchronized IdentifyTraits get() { return identifyTraits; } - public synchronized void set(IdentifyTraits identifyTraits) { + public synchronized boolean set(IdentifyTraits identifyTraits) { if (Objects.equals(identifyTraits, this.identifyTraits)) { - return; + return true; } this.identifyTraits = identifyTraits; - String string = null; - if (identifyTraits != null) { - string = serialize(identifyTraits); - } - save(string, FILE); + return save(serialize(identifyTraits), FILE); } - private String serialize(IdentifyTraits identifyTraits) { - if (identifyTraits == null) { - return null; - } - return new Gson().toJson(identifyTraits); + String serialize(IdentifyTraits identifyTraits) { + return identifyTraits == null ? null : gson.toJson(identifyTraits); } - private IdentifyTraits deserialize(String identity) { - if (identity == null) { - return null; - } - return new Gson().fromJson(identity, IdentifyTraits.class); + IdentifyTraits deserialize(String identity) { + return identity == null ? null : gson.fromJson(identity, IdentifyTraits.class); } - private String load(Path file) { - String event = null; + String load(Path file) { try(Stream lines = getLines(file)) { - event = lines + return lines .filter(l -> !l.isBlank()) .findAny() .map(String::trim) @@ -78,7 +68,7 @@ private String load(Path file) { } catch (IOException e) { LOGGER.warn("Could not read identity file at " + file.toAbsolutePath(), e); } - return event; + return null; } /* for testing purposes */ @@ -86,13 +76,15 @@ protected Stream getLines(Path file) throws IOException { return Files.lines(file); } - private void save(String event, Path file) { + boolean save(String event, Path file) { try { createFileAndParent(file); writeFile(event, file); + return true; } catch (IOException e) { LOGGER.warn("Could not write identity to file at " + FILE.toAbsolutePath(), e); } + return false; } /* for testing purposes */ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 165d019fe..49c0c4c74 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,6 +6,7 @@ checkstyle = "10.15.0" commons-text = "1.11.0" flexmark = "0.64.8" gradle-intellij-plugin-version = "1.17.3" +gson = "2.10.1" jackson = "2.17.0" jsoup = "1.17.2" jtokkit = "1.0.0" @@ -21,6 +22,7 @@ assertj-core = { module = "org.assertj:assertj-core", version.ref = "assertj" } commons-text = { module = "org.apache.commons:commons-text", version.ref = "commons-text" } flexmark-all = { module = "com.vladsch.flexmark:flexmark-all", version.ref = "flexmark" } gradle-intellij-plugin = { module = "org.jetbrains.intellij.plugins:gradle-intellij-plugin", version.ref = "gradle-intellij-plugin-version" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } jackson-bom = { module = "com.fasterxml.jackson:jackson-bom", version.ref = "jackson" } jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } jtokkit = { module = "com.knuddels:jtokkit", version.ref = "jtokkit" } diff --git a/src/main/java/ee/carlrobert/codegpt/actions/IncludeFilesInContextAction.java b/src/main/java/ee/carlrobert/codegpt/actions/IncludeFilesInContextAction.java index 63cdc1e9e..924d24ec3 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/IncludeFilesInContextAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/IncludeFilesInContextAction.java @@ -49,7 +49,7 @@ public class IncludeFilesInContextAction extends AnAction { private static final Logger LOG = Logger.getInstance(IncludeFilesInContextAction.class); public IncludeFilesInContextAction() { - super(CodeGPTBundle.get("action.includeFilesInContext.title")); + this("action.includeFilesInContext.title"); } public IncludeFilesInContextAction(String customTitleKey) { diff --git a/src/test/kotlin/ee/carlrobert/codegpt/telemetry/core/service/segment/IdentifyTraitsPersistenceTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/telemetry/core/service/segment/IdentifyTraitsPersistenceTest.kt new file mode 100644 index 000000000..689f784a2 --- /dev/null +++ b/src/test/kotlin/ee/carlrobert/codegpt/telemetry/core/service/segment/IdentifyTraitsPersistenceTest.kt @@ -0,0 +1,67 @@ +package ee.carlrobert.codegpt.telemetry.core.service.segment + +import com.google.gson.Gson +import com.google.gson.JsonSyntaxException +import com.intellij.util.io.write +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import kotlin.io.path.Path +import kotlin.io.path.createTempFile +import kotlin.io.path.readText +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertNull + +private const val NOT_JSON = "}NOT]:JSON{" + +class IdentifyTraitsPersistenceTest { + private val gson = Gson() + private val persistence = IdentifyTraitsPersistence.INSTANCE + private val identifyTraits = IdentifyTraits("locale", "timezone", "os", "version", "distribution") + + @BeforeEach + fun setUp() { + persistence.identifyTraits = null + IdentifyTraitsPersistence.FILE = createTempFile() + } + + @Test + fun `get returns null when file does not exist`() { + IdentifyTraitsPersistence.FILE = Path(" ") + assertNull(persistence.get()) + } + + @Test + fun `get throws JsonSyntaxException when file contains malformed JSON`() { + IdentifyTraitsPersistence.FILE.write(NOT_JSON) + assertFailsWith { + persistence.get() + } + } + + @Test + fun `set saves the event to the file overwriting it`() { + IdentifyTraitsPersistence.FILE.write(NOT_JSON) + persistence.set(identifyTraits) + assertEquals(IdentifyTraitsPersistence.FILE.readText(), gson.toJson(identifyTraits)) + } + + @Test + fun `set saves the event to the file when file does not exist`() { + persistence.set(identifyTraits) + assertEquals(IdentifyTraitsPersistence.FILE.readText(), gson.toJson(identifyTraits)) + } + + @Test + fun `get returns the deserialized event`() { + IdentifyTraitsPersistence.FILE.write(gson.toJson(identifyTraits)) + assertEquals(identifyTraits, persistence.get()) + } + + @Test + fun `set throws IOException when file cannot be written and returns false`() { + IdentifyTraitsPersistence.FILE = IdentifyTraitsPersistence.FILE.resolve(" xyz ") + assertEquals(persistence.set(identifyTraits), false) + } + +}