package ai.nomyo; import org.junit.jupiter.api.*; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class SecureMemoryTest { @BeforeEach void resetSecureMemoryState() { SecureMemory.setSecureMemoryEnabled(true); } @Test @DisplayName("getMemoryProtectionInfo should return enabled=true by default") void getMemoryProtectionInfo_default_shouldBeEnabled() { Map info = SecureMemory.getMemoryProtectionInfo(); assertEquals(true, info.get("enabled"), "Memory protection should be enabled by default"); } @Test @DisplayName("getMemoryProtectionInfo should report has_secure_zeroing=true") void getMemoryProtectionInfo_shouldReportZeroing() { Map info = SecureMemory.getMemoryProtectionInfo(); assertEquals(true, info.get("has_secure_zeroing"), "Should report secure zeroing available"); } @Test @DisplayName("getMemoryProtectionInfo should report has_memory_locking=false") void getMemoryProtectionInfo_shouldReportNoLocking() { Map info = SecureMemory.getMemoryProtectionInfo(); assertEquals(false, info.get("has_memory_locking"), "Should report memory locking unavailable"); } @Test @DisplayName("getMemoryProtectionInfo should report protection_level=zeroing_only") void getMemoryProtectionInfo_protectionLevel_shouldBeZeroingOnly() { Map info = SecureMemory.getMemoryProtectionInfo(); assertEquals("zeroing_only", info.get("protection_level"), "Protection level should be zeroing_only (no memory locking)"); } @Test @DisplayName("getMemoryProtectionInfo should return page_size from Constants") void getMemoryProtectionInfo_pageSize_shouldMatchConstants() { Map info = SecureMemory.getMemoryProtectionInfo(); assertEquals(Constants.PAGE_SIZE, info.get("page_size"), "Page size should match Constants.PAGE_SIZE"); } @Test @DisplayName("getMemoryProtectionInfo should report supports_full_protection=false without locking") void getMemoryProtectionInfo_fullProtection_shouldBeFalse() { Map info = SecureMemory.getMemoryProtectionInfo(); assertEquals(false, info.get("supports_full_protection"), "Full protection should be false without memory locking"); } @Test @DisplayName("getMemoryProtectionInfo should report supports_full_protection=false when disabled") void getMemoryProtectionInfo_disabled_shouldNotSupportFull() { SecureMemory.setSecureMemoryEnabled(false); try { Map info = SecureMemory.getMemoryProtectionInfo(); assertEquals(false, info.get("supports_full_protection"), "Full protection should be false when disabled"); assertEquals(false, info.get("enabled"), "Enabled should be false"); } finally { SecureMemory.setSecureMemoryEnabled(true); } } @Test @DisplayName("secureByteArray should create a SecureBuffer with data") void secureByteArray_shouldCreateBuffer() { byte[] data = new byte[]{1, 2, 3, 4, 5}; try (SecureMemory.SecureBuffer buffer = SecureMemory.secureByteArray(data)) { assertNotNull(buffer.getData(), "Data segment should not be null"); assertEquals(5, buffer.getSize(), "Size should match input"); assertNotEquals(0, buffer.getAddress(), "Address should not be zero"); } } @Test @DisplayName("secureByteArray should handle null data gracefully") void secureByteArray_nullData_shouldHandleGracefully() { try (SecureMemory.SecureBuffer buffer = SecureMemory.secureByteArray(null)) { assertNotNull(buffer, "Buffer should not be null even with null data"); assertEquals(0, buffer.getSize(), "Size should be 0 for null data"); } } @Test @DisplayName("SecureBuffer zero should clear all bytes") void secureBuffer_zero_shouldClearBytes() { byte[] data = new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF}; SecureMemory.SecureBuffer buffer = SecureMemory.secureByteArray(data); buffer.zero(); assertDoesNotThrow(() -> buffer.zero(), "Zeroing should not throw"); } @Test @DisplayName("SecureBuffer close should zero and unlock") void secureBuffer_close_shouldZeroAndUnlock() { byte[] data = new byte[]{1, 2, 3}; assertDoesNotThrow(() -> { try (SecureMemory.SecureBuffer buffer = SecureMemory.secureByteArray(data)) { assertNotNull(buffer.getData()); } }, "Close via try-with-resources should not throw"); } @Test @DisplayName("SecureBuffer close should be idempotent") void secureBuffer_close_idempotent() { byte[] data = new byte[]{1, 2, 3}; SecureMemory.SecureBuffer buffer = SecureMemory.secureByteArray(data); assertDoesNotThrow(() -> buffer.close(), "First close should not throw"); assertDoesNotThrow(() -> buffer.close(), "Second close should not throw"); } @Test @DisplayName("SecureBuffer lock should return false (not supported)") void secureBuffer_lock_shouldReturnFalse() { byte[] data = new byte[]{1, 2, 3}; SecureMemory.SecureBuffer buffer = SecureMemory.secureByteArray(data, true); assertFalse(buffer.lock(), "Lock should return false (not supported)"); } @Test @DisplayName("SecureBuffer unlock should return false") void secureBuffer_unlock_shouldReturnFalse() { byte[] data = new byte[]{1, 2, 3}; SecureMemory.SecureBuffer buffer = SecureMemory.secureByteArray(data, true); assertFalse(buffer.unlock(), "Unlock should return false"); } @Test @DisplayName("HAS_MEMORY_LOCKING should be false") void hasMemoryLocking_shouldBeFalse() { assertFalse(SecureMemory.isHAS_MEMORY_LOCKING(), "HAS_MEMORY_LOCKING should be false"); } @Test @DisplayName("HAS_SECURE_ZEROING should be true") void hasSecureZeroing_shouldBeTrue() { assertTrue(SecureMemory.isHAS_SECURE_ZEROING(), "HAS_SECURE_ZEROING should be true"); } }