diff --git a/java/gradle/libs.versions.toml b/java/gradle/libs.versions.toml index b1eca0b..b6c3187 100644 --- a/java/gradle/libs.versions.toml +++ b/java/gradle/libs.versions.toml @@ -1,9 +1,12 @@ [versions] gradle = "8.7.3" rustAndroid = "0.9.4" +junitJupiterApi = "5.11.3" axionReleasePlugin = "1.17.0" [libraries] gradle = { module = "com.android.tools.build:gradle", version.ref = "gradle" } rust-android = { module = "org.mozilla.rust-android-gradle:plugin", version.ref = "rustAndroid" } +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junitJupiterApi" } +junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junitJupiterApi" } axion-release-plugin = { module = "pl.allegro.tech.build:axion-release-plugin", version.ref = "axionReleasePlugin" } diff --git a/java/lib/build.gradle b/java/lib/build.gradle index 8a4896b..80a0645 100644 --- a/java/lib/build.gradle +++ b/java/lib/build.gradle @@ -4,8 +4,8 @@ apply plugin: 'pl.allegro.tech.build.axion-release' apply plugin: 'org.mozilla.rust-android-gradle.rust-android' android { - ndkVersion "28.0.12433566" - namespace "dev.arkbuilders.core" + ndkVersion '28.0.12433566' + namespace 'dev.arkbuilders.core' defaultConfig { compileSdk 35 minSdkVersion 26 @@ -22,18 +22,42 @@ android { } cargo { - libname = "fs_storage" - module = "../../fs-storage" + libname = 'fs_storage' + module = '../../fs-storage' prebuiltToolchains = true - targetDirectory = "../../target" - targets = ["arm64", "x86", "x86_64", "arm"] - profile = gradle.startParameter.taskNames.any { it.toLowerCase().contains("debug") } ? "debug" : "release" + targetDirectory = '../../target' + targets = ['arm64', 'x86', 'x86_64', 'arm'] + profile = gradle.startParameter.taskNames.any { it.containsIgnoreCase('debug') } ? 'debug' : 'release' } -dependencies {} +dependencies { + testImplementation(libs.junit.jupiter.api) + testImplementation(libs.junit.jupiter.engine) +} + +tasks.register('buildRustDebug', Exec) { + workingDir '../../fs-storage' + commandLine 'cargo', 'build' +} + +tasks.register('buildRustRelease', Exec) { + workingDir '../../fs-storage' + commandLine 'cargo', 'build', '--release' +} + +tasks.withType(Test).configureEach { it -> + useJUnitPlatform() + if (it.name.containsIgnoreCase('debug')) { + it.dependsOn 'buildRustDebug' + systemProperty('java.library.path', projectDir.toPath().resolve('../../target/debug').toString()) + } else if (it.name.containsIgnoreCase('release')) { + it.dependsOn 'buildRustRelease' + systemProperty('java.library.path', projectDir.toPath().resolve('../../target/release').toString()) + } +} tasks.configureEach { task -> - if ((task.name == 'mergeDebugJniLibFolders' || task.name == 'mergeReleaseJniLibFolders')) { + if (task.name == 'mergeDebugJniLibFolders' || task.name == 'mergeReleaseJniLibFolders') { task.dependsOn 'cargoBuild' } } @@ -42,16 +66,16 @@ def libVersion = scmVersion.version publishing { publications { release(MavenPublication) { - groupId = "dev.arkbuilders" - artifactId = "core" + groupId = 'dev.arkbuilders' + artifactId = 'core' version = libVersion afterEvaluate { from components.release } } debug(MavenPublication) { - groupId = "dev.arkbuilders" - artifactId = "core-debug" + groupId = 'dev.arkbuilders' + artifactId = 'core-debug' version = libVersion afterEvaluate { from components.debug @@ -60,11 +84,11 @@ publishing { } repositories { maven { - name = "GithubPackages" - url = "https://maven.pkg.github.com/ARK-Builders/ark-core" + name = 'GithubPackages' + url = 'https://maven.pkg.github.com/ARK-Builders/ark-core' credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") + username = System.getenv('GITHUB_ACTOR') + password = System.getenv('GITHUB_TOKEN') } } } diff --git a/java/lib/src/test/java/dev/arkbuilders/core/FileStorageTest.java b/java/lib/src/test/java/dev/arkbuilders/core/FileStorageTest.java new file mode 100644 index 0000000..bf386d1 --- /dev/null +++ b/java/lib/src/test/java/dev/arkbuilders/core/FileStorageTest.java @@ -0,0 +1,193 @@ +package dev.arkbuilders.core; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +public class FileStorageTest { + @TempDir + Path tempDir; + + @Test + public void testFileStorageWriteRead() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + + fileStorage.set("key1", "value1"); + fileStorage.set("key2", "value2"); + + fileStorage.remove("key1"); + fileStorage.writeFS(); + + @SuppressWarnings("unchecked") + LinkedHashMap data = (LinkedHashMap) fileStorage.readFS(); + assertEquals(1, data.size()); + assertEquals("value2", data.get("key2")); + } + + @Test + public void testFileStorageAutoDelete() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + + fileStorage.set("key1", "value1"); + fileStorage.set("key1", "value2"); + fileStorage.writeFS(); + + File file = storagePath.toFile(); + assertTrue(file.exists()); + + fileStorage.erase(); + assertFalse(file.exists()); + } + + @Test + public void testFileStorageNeedsSyncing() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + fileStorage.writeFS(); + assertEquals(FileStorage.SyncStatus.InSync, fileStorage.syncStatus()); + fileStorage.set("key1", "value1"); + assertEquals(FileStorage.SyncStatus.StorageStale, fileStorage.syncStatus()); + fileStorage.writeFS(); + assertEquals(FileStorage.SyncStatus.InSync, fileStorage.syncStatus()); + } + + @Test + public void testFileStorageMonoidCombine() { + Path storagePath1 = tempDir.resolve("test1.txt"); + Path storagePath2 = tempDir.resolve("test2.txt"); + FileStorage fileStorage1 = new FileStorage("test1", storagePath1.toString()); + FileStorage fileStorage2 = new FileStorage("test2", storagePath2.toString()); + + fileStorage1.set("key1", "2"); + fileStorage1.set("key2", "6"); + + fileStorage2.set("key1", "3"); + fileStorage2.set("key3", "9"); + + fileStorage1.merge(fileStorage2); + fileStorage1.writeFS(); + + @SuppressWarnings("unchecked") + LinkedHashMap data = (LinkedHashMap) fileStorage1.readFS(); + assertEquals(3, data.size()); + assertEquals("23", data.get("key1")); + assertEquals("6", data.get("key2")); + assertEquals("9", data.get("key3")); + } + + @Test + public void testFileStorageMainScenario() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + + fileStorage.set("key", "value"); + fileStorage.set("key", "value1"); + fileStorage.set("key1", "value"); + + fileStorage.remove("key"); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + fileStorage.writeFS(); + + @SuppressWarnings("unchecked") + LinkedHashMap data = (LinkedHashMap) fileStorage.readFS(); + assertEquals(1, data.size()); + assertEquals("value", data.get("key1")); + + fileStorage.erase(); + File file = storagePath.toFile(); + assertFalse(file.exists()); + } + + @Test + public void testFileStorageGet() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + + fileStorage.set("key", "value"); + fileStorage.set("key", "value1"); + fileStorage.set("key1", "value"); + + assertEquals("value1", fileStorage.get("key")); + assertEquals("value", fileStorage.get("key1")); + } + + @Test + public void testBTreeMapIterator() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + + fileStorage.set("key", "value"); + fileStorage.set("key", "value1"); + fileStorage.set("key1", "value"); + + fileStorage.writeFS(); + + @SuppressWarnings("unchecked") + LinkedHashMap data = (LinkedHashMap) fileStorage.readFS(); + + BTreeMapIterator bTreeMapIterator = fileStorage.iterator(); + Map iteratorData = new LinkedHashMap<>(); + while (bTreeMapIterator.hasNext()) { + Map.Entry entry = bTreeMapIterator.next(); + iteratorData.put(entry.getKey(), entry.getValue()); + } + assertEquals(data, iteratorData); + } + + @Test + public void testRemoveException() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + Exception exception = assertThrows(RuntimeException.class, () -> fileStorage.remove("invalid_id")); + assertTrue(Objects.requireNonNull(exception.getMessage()).matches("Storage error.*")); + } + + @Test + public void testSyncException() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + Exception exception = assertThrows(RuntimeException.class, fileStorage::sync); + assertTrue(Objects.requireNonNull(exception.getMessage()).matches("IO error.*")); + } + + @Test + public void testCreateException() { + Path storagePath = tempDir.resolve(""); + Exception exception = assertThrows(RuntimeException.class, () -> new FileStorage("", storagePath.toString())); + assertTrue(Objects.requireNonNull(exception.getMessage()).matches("IO error.*")); + } + + @Test + public void testEraseException() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + Exception exception = assertThrows(RuntimeException.class, fileStorage::erase); + assertTrue(Objects.requireNonNull(exception.getMessage()).matches("Storage error.*")); + } + + @Test + public void testReadException() { + Path storagePath = tempDir.resolve("test.txt"); + FileStorage fileStorage = new FileStorage("test", storagePath.toString()); + Exception exception = assertThrows(RuntimeException.class, fileStorage::readFS); + assertTrue(Objects.requireNonNull(exception.getMessage()).matches("Storage error.*")); + } +} \ No newline at end of file