Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.diamonddagger590.mccore.testing.TestCorePlugin;
import dev.dejvokep.boostedyaml.block.implementation.Section;
import org.bukkit.Material;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ItemType;
import org.junit.jupiter.api.AfterEach;
Expand All @@ -13,12 +14,17 @@
import org.junit.jupiter.api.Test;
import org.mockbukkit.mockbukkit.MockBukkit;

import dev.dejvokep.boostedyaml.route.Route;

import java.util.Collections;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -247,4 +253,100 @@ void copyConstructor_copiesBuilderState_fromSource() {
ItemBuilder copy = ItemBuilder.from(source.asItemStack());
assertNotNull(copy);
}

@Test
@DisplayName("Given a section with a non-empty player field, when from(Section) is called, then skull builder path is invoked")
void fromSection_invokesSkullBuilder_whenPlayerIsNonEmpty() {
Section section = createMinimalSection();
when(section.getString(eq(ItemBuilderConfigurationKeys.MATERIAL), eq("stone"))).thenReturn("player_head");
when(section.getString(eq(ItemBuilderConfigurationKeys.PLAYER), eq(""))).thenReturn("Notch");

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
}

@Test
@DisplayName("Given a section with a mob type, when from(Section) is called, then spawner builder path is invoked")
void fromSection_invokesSpawnerBuilder_whenMobTypeProvided() {
Section section = createMinimalSection();
when(section.getString(eq(ItemBuilderConfigurationKeys.MATERIAL), eq("stone"))).thenReturn("spawner");
when(section.getString(eq(ItemBuilderConfigurationKeys.MOB_TYPE), eq(""))).thenReturn("zombie");

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
}

@Test
@DisplayName("Given a section with potions, when from(Section) is called, then potion builder path is invoked")
void fromSection_invokesPotionBuilder_whenPotionSectionProvided() {
Section section = createMinimalSection();
when(section.getString(eq(ItemBuilderConfigurationKeys.MATERIAL), eq("stone"))).thenReturn("potion");

Section potionSection = mock(Section.class);
when(section.getSection(eq(ItemBuilderConfigurationKeys.POTION_HEADER))).thenReturn(potionSection);
when(potionSection.getRoutesAsStrings(false)).thenReturn(Set.of("speed"));
when(potionSection.getInt(any(Route.class), eq(60))).thenReturn(200);
when(potionSection.getInt(any(Route.class), eq(1))).thenReturn(2);
when(potionSection.getBoolean(any(Route.class), eq(false))).thenReturn(false);

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
}

@Test
@DisplayName("Given a section with banner patterns, when from(Section) is called, then pattern builder path is invoked")
void fromSection_invokesPatternBuilder_whenPatternSectionProvided() {
Section section = createMinimalSection();
when(section.getString(eq(ItemBuilderConfigurationKeys.MATERIAL), eq("stone"))).thenReturn("white_banner");

Section patternSection = mock(Section.class);
when(section.getSection(eq(ItemBuilderConfigurationKeys.PATTERN_HEADER))).thenReturn(patternSection);
when(patternSection.getRoutesAsStrings(false)).thenReturn(Set.of("stripe_top"));
when(patternSection.getString("stripe_top", "white")).thenReturn("red");

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
}

@Test
@DisplayName("Given a section with item flags, when from(Section) is called, then item flags are applied")
void fromSection_appliesItemFlags_whenItemFlagsProvided() {
Section section = createMinimalSection();
when(section.getStringList(eq(ItemBuilderConfigurationKeys.ITEM_FLAGS))).thenReturn(List.of("HIDE_ENCHANTS"));

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
ItemStack stack = result.asItemStack();
assertTrue(stack.getItemFlags().contains(ItemFlag.HIDE_ENCHANTS));
}

@Test
@DisplayName("Given a section with custom model data, when from(Section) is called, then custom model data is set")
void fromSection_setsCustomModelData_whenProvided() {
Section section = createMinimalSection();
when(section.getInt(eq(ItemBuilderConfigurationKeys.CUSTOM_MODEL_DATA), eq(-1))).thenReturn(42);

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
}

@Test
@DisplayName("Given a section with display name, when from(Section) is called, then completes without error")
void fromSection_completesWithoutError_whenNameProvided() {
Section section = createMinimalSection();
when(section.getString(eq(ItemBuilderConfigurationKeys.NAME), eq(""))).thenReturn("Custom Name");

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
}

@Test
@DisplayName("Given a section with lore, when from(Section) is called, then completes without error")
void fromSection_completesWithoutError_whenLoreProvided() {
Section section = createMinimalSection();
when(section.getStringList(eq(ItemBuilderConfigurationKeys.LORE_ROUTE))).thenReturn(List.of("Line 1", "Line 2"));

ItemBuilder result = assertDoesNotThrow(() -> ItemBuilder.from(section));
assertNotNull(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand Down Expand Up @@ -260,6 +262,113 @@ protected boolean blockMainThreadOnStart() {
}
}

@Test
@DisplayName("Given a non-blocking database with custom functions, when initializeDatabase is called, then functions are invoked asynchronously")
void initializeDatabase_invokesCustomFunctions_whenNonBlocking() throws Exception {
setupDriverRegistry();

NonBlockingTestDatabase database = new NonBlockingTestDatabase(plugin);
CompletableFuture<Void> createDone = new CompletableFuture<>();
CompletableFuture<Void> updateDone = new CompletableFuture<>();

database.addCreateTableFunction(db -> {
CompletableFuture<Void> future = new CompletableFuture<>();
db.getDatabaseExecutorService().submit(() -> {
future.complete(null);
createDone.complete(null);
});
return future;
});
database.addUpdateTableFunction(db -> {
CompletableFuture<Void> future = new CompletableFuture<>();
db.getDatabaseExecutorService().submit(() -> {
future.complete(null);
updateDone.complete(null);
});
return future;
});

try {
database.initializeDatabase();
createDone.get(5, TimeUnit.SECONDS);
updateDone.get(5, TimeUnit.SECONDS);
assertTrue(createDone.isDone(), "Create table function should have been called");
assertTrue(updateDone.isDone(), "Update table function should have been called");
} finally {
database.shutdown();
}
}

@Test
@DisplayName("Given a non-blocking database, when initializeDatabase is called, then core tables are created")
void initializeDatabase_createsTables_whenNonBlocking() throws Exception {
setupDriverRegistry();

NonBlockingTestDatabase database = new NonBlockingTestDatabase(plugin);
CompletableFuture<Void> tablesReady = new CompletableFuture<>();
database.addUpdateTableFunction(db -> {
CompletableFuture<Void> future = new CompletableFuture<>();
db.getDatabaseExecutorService().submit(() -> {
future.complete(null);
tablesReady.complete(null);
});
return future;
});
try {
database.initializeDatabase();
tablesReady.get(5, TimeUnit.SECONDS);

Connection conn = database.getConnection();
assertTrue(database.tableExists(conn, "table_history"));
conn.close();
} finally {
database.shutdown();
}
}

@Test
@DisplayName("Given an initialized database, when shutdown is called twice, then no error occurs")
void shutdown_noError_whenCalledTwice() throws Exception {
setupDriverRegistry();

InMemoryTestDatabase database = new InMemoryTestDatabase(plugin);
database.initializeDatabase();
database.shutdown();
assertDoesNotThrow(database::shutdown);
}

@Test
@DisplayName("Given an initialized database, when getDatabaseDriverType is called, then returns the configured type")
void getDatabaseDriverType_returnsConfiguredType() {
InMemoryTestDatabase database = new InMemoryTestDatabase(plugin);
assertEquals(DatabaseDriverType.SQLITE, database.getDatabaseDriverType());
database.getDatabaseExecutorService().shutdownNow();
}

@Test
@DisplayName("Given an initialized database, when getDatabaseExecutorService is called, then returns non-null executor")
void getDatabaseExecutorService_returnsNonNullExecutor() {
InMemoryTestDatabase database = new InMemoryTestDatabase(plugin);
assertNotNull(database.getDatabaseExecutorService());
database.getDatabaseExecutorService().shutdownNow();
}

@Test
@DisplayName("Given an initialized database, when tableExists is called for non-existent table, then returns false")
void tableExists_returnsFalse_whenTableDoesNotExist() throws Exception {
setupDriverRegistry();

InMemoryTestDatabase database = new InMemoryTestDatabase(plugin);
try {
database.initializeDatabase();
Connection conn = database.getConnection();
assertFalse(database.tableExists(conn, "non_existent_table"));
conn.close();
} finally {
database.shutdown();
}
}

static class LeakDetectionTestDatabase extends Database {
private static final Credentials CREDENTIALS = new Credentials("", 0, "", "", "");
private static final ConnectionDetails CONNECTION_DETAILS = new ConnectionDetails(5000, 300000, 600000, 2, 10, 30000);
Expand Down
Loading
Loading