Skip to main content
Glama
DataReferenceTest.java12.3 kB
package com.ghidramcp.services; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; /** * Unit tests for data reference functionality in DecompilationService. * * These tests verify output formatting, error message handling, and validation * for the get_function_data functionality. * * Note: Full integration tests with Ghidra Program objects would require * the Ghidra test framework and are beyond the scope of unit tests. */ class DataReferenceTest { /** * Test that error messages for missing parameters are correct */ @Test @DisplayName("Should return error when neither address nor name is provided") void testMissingParameterError() { String expectedError = "Error: Either 'address' or 'name' parameter is required"; assertTrue(expectedError.startsWith("Error: "), "Should be formatted as error message"); assertTrue(expectedError.contains("required"), "Should indicate parameter is required"); assertTrue(expectedError.contains("address") && expectedError.contains("name"), "Should mention both possible parameters"); } /** * Test error message when no program is loaded */ @Test @DisplayName("Should return error when no program is loaded") void testNoProgramLoadedError() { String expectedError = "No program loaded"; assertNotNull(expectedError); assertTrue(expectedError.contains("No program"), "Should indicate no program is loaded"); } /** * Test error message when function is not found by name */ @Test @DisplayName("Should return error when function not found by name") void testFunctionNotFoundByName() { String functionName = "nonexistent_function"; String expectedError = "Function not found: " + functionName; assertTrue(expectedError.startsWith("Function not found:"), "Should indicate function was not found"); assertTrue(expectedError.contains(functionName), "Should include the function name in error message"); } /** * Test error message when function is not found at address */ @Test @DisplayName("Should return error when function not found at address") void testFunctionNotFoundByAddress() { String address = "0x401000"; String expectedError = "No function found at or containing address " + address; assertTrue(expectedError.contains("No function found"), "Should indicate function was not found"); assertTrue(expectedError.contains(address), "Should include the address in error message"); } /** * Test error message when address is required but not provided */ @Test @DisplayName("Should return error when address is empty or null") void testAddressRequiredError() { String expectedError = "Address is required"; assertNotNull(expectedError); assertTrue(expectedError.contains("required"), "Should indicate address is required"); } /** * Test that output header format is correct */ @Test @DisplayName("Should format output header with correct columns") void testOutputHeaderFormat() { String[] expectedColumns = { "Symbol", "Address", "Type", "RefFrom", "Value" }; // Validate all expected columns are defined assertEquals(5, expectedColumns.length, "Should have 5 columns"); assertEquals("Symbol", expectedColumns[0], "First column should be Symbol"); assertEquals("Address", expectedColumns[1], "Second column should be Address"); assertEquals("Type", expectedColumns[2], "Third column should be Type"); assertEquals("RefFrom", expectedColumns[3], "Fourth column should be RefFrom"); assertEquals("Value", expectedColumns[4], "Fifth column should be Value"); } /** * Test that function header line is formatted correctly */ @Test @DisplayName("Should format function header line correctly") void testFunctionHeaderFormat() { String functionName = "test_function"; String address = "0x401000"; String expectedHeader = "Data references from " + functionName + " (" + address + "):"; assertTrue(expectedHeader.startsWith("Data references from"), "Header should start with 'Data references from'"); assertTrue(expectedHeader.contains(functionName), "Header should contain function name"); assertTrue(expectedHeader.contains(address), "Header should contain function address"); assertTrue(expectedHeader.endsWith(":"), "Header should end with colon"); } /** * Test that empty result message is formatted correctly */ @Test @DisplayName("Should format empty result message correctly") void testEmptyResultMessage() { String expectedMessage = " No data references found."; assertTrue(expectedMessage.contains("No data references"), "Should indicate no data references were found"); assertTrue(expectedMessage.endsWith("."), "Message should end with period"); } /** * Test that total count line is formatted correctly */ @ParameterizedTest @DisplayName("Should format total count line correctly") @ValueSource(ints = {0, 1, 5, 10, 100}) void testTotalCountFormat(int count) { String expectedTotal = " Total: " + count + " data references"; assertTrue(expectedTotal.startsWith(" Total:"), "Should start with 'Total:'"); assertTrue(expectedTotal.contains(String.valueOf(count)), "Should contain the count"); assertTrue(expectedTotal.endsWith("data references"), "Should end with 'data references'"); } /** * Test that string values are quoted */ @Test @DisplayName("Should quote string values in output") void testStringValueQuoting() { String stringValue = "test string"; String quotedValue = "\"" + stringValue + "\""; assertTrue(quotedValue.startsWith("\""), "String value should start with quote"); assertTrue(quotedValue.endsWith("\""), "String value should end with quote"); assertEquals("\"test string\"", quotedValue, "Should properly quote the string"); } /** * Test that long values are truncated */ @Test @DisplayName("Should truncate long values with ellipsis") void testValueTruncation() { String longValue = "a".repeat(50); // 50 characters String truncatedValue = longValue.substring(0, 37) + "..."; assertEquals(40, truncatedValue.length(), "Truncated value should be 40 characters (37 + '...')"); assertTrue(truncatedValue.endsWith("..."), "Truncated value should end with '...'"); } /** * Test valid address formats for function lookup */ @ParameterizedTest @DisplayName("Should accept valid address formats") @ValueSource(strings = { "0x401000", "0x1400010a0", "5356:3cd8", "4592:000e" }) void testValidAddressFormats(String address) { assertNotNull(address, "Address should not be null"); assertFalse(address.isEmpty(), "Address should not be empty"); // Validate format patterns boolean isValid = address.matches("^(0x)?[0-9a-fA-F]+$") || address.matches("^[0-9a-fA-F]+:[0-9a-fA-F]+$"); assertTrue(isValid, "Address should match valid format: " + address); } /** * Test that data reference output includes all required fields */ @Test @DisplayName("Should include all required fields in data reference output") void testDataReferenceFields() { String[] requiredFields = { "Symbol", // Data symbol/label "Address", // Data address "Type", // Data type "RefFrom", // Reference source address "Value" // Data value }; for (String field : requiredFields) { assertNotNull(field, "Field should be defined: " + field); assertFalse(field.isEmpty(), "Field should not be empty: " + field); } assertEquals(5, requiredFields.length, "Should have exactly 5 required fields"); } /** * Test exception error message format */ @Test @DisplayName("Should format exception errors correctly") void testExceptionErrorFormat() { String address = "0x401000"; String exceptionMessage = "Invalid address format"; String expectedError = "Error getting data references: " + exceptionMessage; assertTrue(expectedError.startsWith("Error getting data references:"), "Exception error should describe the operation"); assertTrue(expectedError.contains(exceptionMessage), "Should include the exception message"); } /** * Test that separator line has appropriate length */ @Test @DisplayName("Should format separator line correctly") void testSeparatorLineFormat() { int maxLabelLen = 20; int expectedLength = maxLabelLen + 70; String separator = " " + "-".repeat(expectedLength); assertTrue(separator.startsWith(" "), "Separator should start with spacing"); assertTrue(separator.contains("-"), "Separator should contain dashes"); assertEquals(expectedLength + 2, separator.length(), "Separator should have correct total length"); } /** * Test column alignment spacing */ @Test @DisplayName("Should use consistent column spacing") void testColumnSpacing() { // Expected column widths based on implementation int symbolWidth = 20; // Minimum, dynamic based on content int addressWidth = 12; int typeWidth = 20; int refFromWidth = 12; // Value column is variable width assertTrue(symbolWidth >= 20, "Symbol column should be at least 20 chars"); assertEquals(12, addressWidth, "Address column should be 12 chars"); assertEquals(20, typeWidth, "Type column should be 20 chars"); assertEquals(12, refFromWidth, "RefFrom column should be 12 chars"); } /** * Test that data type names are formatted correctly */ @ParameterizedTest @DisplayName("Should format common data type names") @ValueSource(strings = { "dword", "char[20]", "pointer", "byte", "qword", "undefined" }) void testDataTypeFormatting(String dataType) { assertNotNull(dataType, "Data type should not be null"); assertFalse(dataType.isEmpty(), "Data type should not be empty"); // Data types should not contain control characters assertFalse(dataType.matches(".*[\\p{Cntrl}].*"), "Data type should not contain control characters: " + dataType); } /** * Test output consistency */ @Test @DisplayName("Should maintain consistent output structure") void testOutputStructure() { // Expected output structure: // 1. Header line with function name and address // 2. Blank line // 3. Column headers OR "No data references found" // 4. Separator line (if data exists) // 5. Data rows (if data exists) // 6. Blank line // 7. Total count line String[] outputSections = { "Data references from", // Header "Symbol", // Column header "Total:" // Summary }; for (String section : outputSections) { assertNotNull(section, "Output section should be defined"); assertFalse(section.isEmpty(), "Output section should not be empty"); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HK47196/GhidraMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server