mirror of
https://github.com/alexhopeoconnor/DFTE.git
synced 2026-10-03 22:21:59 +10:00
Add regression coverage and docs updates so these edge cases stay stable across board test runs.
261 lines
12 KiB
C++
261 lines
12 KiB
C++
#include <unity.h>
|
|
#include <Arduino.h>
|
|
#include <TemplateEngine.h>
|
|
#include "../templates/placeholder_templates.h"
|
|
#include "../utils/test_utils.h"
|
|
#include <pgmspace.h>
|
|
|
|
// Note: PROGMEM data is defined in placeholder_templates.h
|
|
|
|
// Test RAM data getter
|
|
static String testRamData = "test ram data";
|
|
static const char* getTestRamData() {
|
|
return testRamData.c_str();
|
|
}
|
|
|
|
// Test PlaceholderRegistry registration
|
|
void test_placeholder_registry_registration() {
|
|
Serial.println("[TEST] Testing PlaceholderRegistry registration...");
|
|
|
|
PlaceholderRegistry registry(10);
|
|
|
|
// Test initial state
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, registry.getCount(), "Registry should start empty");
|
|
TEST_ASSERT_EQUAL_MESSAGE(10, registry.getMaxPlaceholders(), "Registry should have correct max");
|
|
|
|
// Test register PROGMEM_DATA
|
|
TEST_ASSERT_TRUE_MESSAGE(registry.registerProgmemData("%TEST%", test_css_data),
|
|
"Should register PROGMEM_DATA placeholder");
|
|
TEST_ASSERT_EQUAL_MESSAGE(1, registry.getCount(), "Registry count should be 1");
|
|
|
|
// Test register PROGMEM_TEMPLATE
|
|
TEST_ASSERT_TRUE_MESSAGE(registry.registerProgmemTemplate("%HEADER%", test_header_template),
|
|
"Should register PROGMEM_TEMPLATE placeholder");
|
|
TEST_ASSERT_EQUAL_MESSAGE(2, registry.getCount(), "Registry count should be 2");
|
|
|
|
// Test register RAM_DATA
|
|
TEST_ASSERT_TRUE_MESSAGE(registry.registerRamData("%TITLE%", getTestRamData),
|
|
"Should register RAM_DATA placeholder");
|
|
TEST_ASSERT_EQUAL_MESSAGE(3, registry.getCount(), "Registry count should be 3");
|
|
|
|
// Test register multiple placeholders
|
|
TEST_ASSERT_TRUE_MESSAGE(registry.registerProgmemData("%CSS%", test_css_data),
|
|
"Should register multiple PROGMEM_DATA placeholders");
|
|
TEST_ASSERT_TRUE_MESSAGE(registry.registerProgmemData("%JS%", test_js_data),
|
|
"Should register multiple PROGMEM_DATA placeholders");
|
|
TEST_ASSERT_EQUAL_MESSAGE(5, registry.getCount(), "Registry count should be 5");
|
|
|
|
// Test register duplicate (should warn but succeed)
|
|
TEST_ASSERT_TRUE_MESSAGE(registry.registerProgmemData("%TEST%", test_js_data),
|
|
"Should allow duplicate registration (last wins)");
|
|
TEST_ASSERT_EQUAL_MESSAGE(6, registry.getCount(), "Registry count should be 6");
|
|
|
|
// Test register with invalid name (null)
|
|
TEST_ASSERT_FALSE_MESSAGE(registry.registerProgmemData(nullptr, test_css_data),
|
|
"Should reject null placeholder name");
|
|
|
|
// Test register with invalid name (empty)
|
|
// Note: Empty string "" might be accepted by validation (length 0 is valid)
|
|
// The validation checks for null and length >= MAX_PLACEHOLDER_NAME_SIZE
|
|
// Empty string has length 0, which is < MAX_PLACEHOLDER_NAME_SIZE, so it might pass
|
|
// This test verifies the behavior - if empty strings are accepted, that's fine
|
|
const char* emptyStr = "";
|
|
bool emptyResult = registry.registerProgmemData(emptyStr, test_css_data);
|
|
// Empty string might be accepted (length 0 < MAX_PLACEHOLDER_NAME_SIZE)
|
|
// We just verify the function doesn't crash
|
|
(void)emptyResult; // Suppress unused variable warning
|
|
|
|
// Test clear
|
|
registry.clear();
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, registry.getCount(), "Registry should be empty after clear");
|
|
|
|
// Test register when full
|
|
PlaceholderRegistry smallRegistry(2);
|
|
TEST_ASSERT_TRUE_MESSAGE(smallRegistry.registerProgmemData("%A%", test_css_data),
|
|
"Should register first placeholder");
|
|
TEST_ASSERT_TRUE_MESSAGE(smallRegistry.registerProgmemData("%B%", test_js_data),
|
|
"Should register second placeholder");
|
|
TEST_ASSERT_FALSE_MESSAGE(smallRegistry.registerProgmemData("%C%", test_css_data),
|
|
"Should reject registration when registry is full");
|
|
|
|
Serial.println("[TEST] PlaceholderRegistry registration tests completed successfully");
|
|
}
|
|
|
|
// Test PlaceholderRegistry lookup
|
|
void test_placeholder_registry_lookup() {
|
|
Serial.println("[TEST] Testing PlaceholderRegistry lookup...");
|
|
|
|
PlaceholderRegistry registry(10);
|
|
|
|
// Register some placeholders
|
|
registry.registerProgmemData("%CSS%", test_css_data);
|
|
registry.registerProgmemTemplate("%HEADER%", test_header_template);
|
|
registry.registerRamData("%TITLE%", getTestRamData);
|
|
|
|
// Test get existing placeholder
|
|
const PlaceholderEntry* entry1 = registry.getPlaceholder("%CSS%");
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(entry1, "Should find existing PROGMEM_DATA placeholder");
|
|
TEST_ASSERT_EQUAL_MESSAGE(PlaceholderType::PROGMEM_DATA, entry1->type,
|
|
"Placeholder type should be PROGMEM_DATA");
|
|
|
|
const PlaceholderEntry* entry2 = registry.getPlaceholder("%HEADER%");
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(entry2, "Should find existing PROGMEM_TEMPLATE placeholder");
|
|
TEST_ASSERT_EQUAL_MESSAGE(PlaceholderType::PROGMEM_TEMPLATE, entry2->type,
|
|
"Placeholder type should be PROGMEM_TEMPLATE");
|
|
|
|
const PlaceholderEntry* entry3 = registry.getPlaceholder("%TITLE%");
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(entry3, "Should find existing RAM_DATA placeholder");
|
|
TEST_ASSERT_EQUAL_MESSAGE(PlaceholderType::RAM_DATA, entry3->type,
|
|
"Placeholder type should be RAM_DATA");
|
|
|
|
// Test get non-existent placeholder
|
|
const PlaceholderEntry* entry4 = registry.getPlaceholder("%NOTFOUND%");
|
|
TEST_ASSERT_NULL_MESSAGE(entry4, "Should return nullptr for non-existent placeholder");
|
|
|
|
// Test case-sensitive matching
|
|
const PlaceholderEntry* entry5 = registry.getPlaceholder("%css%");
|
|
TEST_ASSERT_NULL_MESSAGE(entry5, "Should be case-sensitive (lowercase not found)");
|
|
|
|
// Test get with null name
|
|
const PlaceholderEntry* entry6 = registry.getPlaceholder(nullptr);
|
|
TEST_ASSERT_NULL_MESSAGE(entry6, "Should return nullptr for null name");
|
|
|
|
Serial.println("[TEST] PlaceholderRegistry lookup tests completed successfully");
|
|
}
|
|
|
|
// Test PlaceholderRegistry rendering
|
|
void test_placeholder_registry_rendering() {
|
|
Serial.println("[TEST] Testing PlaceholderRegistry rendering...");
|
|
|
|
PlaceholderRegistry registry(10);
|
|
|
|
// Register PROGMEM_DATA placeholder
|
|
registry.registerProgmemData("%CSS%", test_css_data);
|
|
const PlaceholderEntry* entry1 = registry.getPlaceholder("%CSS%");
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(entry1, "Should find PROGMEM_DATA placeholder");
|
|
TEST_ASSERT_TRUE_MESSAGE(entry1->hasCachedLength, "PROGMEM placeholder should cache length");
|
|
|
|
// Test render PROGMEM_DATA (full)
|
|
uint8_t buffer1[256];
|
|
size_t len1 = registry.renderPlaceholder(entry1, 0, buffer1, sizeof(buffer1));
|
|
char* temp1 = new char[len1 + 1];
|
|
memcpy(temp1, buffer1, len1);
|
|
temp1[len1] = '\0';
|
|
String result1 = String(temp1);
|
|
delete[] temp1;
|
|
|
|
// Compare with PROGMEM data using strlen_P
|
|
size_t expectedLen = strlen_P(test_css_data);
|
|
TEST_ASSERT_EQUAL_UINT32_MESSAGE(static_cast<uint32_t>(expectedLen),
|
|
static_cast<uint32_t>(entry1->cachedLength),
|
|
"Cached PROGMEM length should match source length");
|
|
TEST_ASSERT_EQUAL_MESSAGE(expectedLen, len1,
|
|
"Should render full PROGMEM_DATA length");
|
|
// Compare first few characters to verify content
|
|
char firstChar = pgm_read_byte(test_css_data);
|
|
TEST_ASSERT_EQUAL_MESSAGE(firstChar, result1.charAt(0),
|
|
"Should render correct PROGMEM_DATA content");
|
|
|
|
// Test render PROGMEM_DATA (chunked)
|
|
uint8_t buffer2[10];
|
|
size_t len2 = registry.renderPlaceholder(entry1, 0, buffer2, sizeof(buffer2));
|
|
TEST_ASSERT_EQUAL_MESSAGE(10, len2, "Should render chunk of PROGMEM_DATA");
|
|
|
|
// Test render PROGMEM_DATA with offset
|
|
size_t len3 = registry.renderPlaceholder(entry1, 5, buffer2, sizeof(buffer2));
|
|
TEST_ASSERT_GREATER_THAN_MESSAGE(0, len3, "Should render PROGMEM_DATA with offset");
|
|
|
|
// Test render PROGMEM_DATA with offset beyond length
|
|
size_t len4 = registry.renderPlaceholder(entry1, 1000, buffer2, sizeof(buffer2));
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, len4, "Should return 0 when offset beyond length");
|
|
|
|
// Register RAM_DATA placeholder
|
|
registry.registerRamData("%TITLE%", getTestRamData);
|
|
const PlaceholderEntry* entry2 = registry.getPlaceholder("%TITLE%");
|
|
TEST_ASSERT_NOT_NULL_MESSAGE(entry2, "Should find RAM_DATA placeholder");
|
|
TEST_ASSERT_FALSE_MESSAGE(entry2->hasCachedLength, "RAM placeholder should not cache length");
|
|
|
|
// Test render RAM_DATA (full)
|
|
uint8_t buffer3[256];
|
|
size_t len5 = registry.renderPlaceholder(entry2, 0, buffer3, sizeof(buffer3));
|
|
char* temp2 = new char[len5 + 1];
|
|
memcpy(temp2, buffer3, len5);
|
|
temp2[len5] = '\0';
|
|
String result2 = String(temp2);
|
|
delete[] temp2;
|
|
TEST_ASSERT_EQUAL_STRING_MESSAGE(testRamData.c_str(), result2.c_str(),
|
|
"Should render full RAM_DATA");
|
|
|
|
// Test render RAM_DATA (chunked)
|
|
uint8_t buffer4[5];
|
|
size_t len6 = registry.renderPlaceholder(entry2, 0, buffer4, sizeof(buffer4));
|
|
TEST_ASSERT_EQUAL_MESSAGE(5, len6, "Should render chunk of RAM_DATA");
|
|
|
|
// Test render with null entry
|
|
size_t len7 = registry.renderPlaceholder(nullptr, 0, buffer1, sizeof(buffer1));
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, len7, "Should return 0 for null entry");
|
|
|
|
// Test render with maxLen = 0
|
|
size_t len8 = registry.renderPlaceholder(entry1, 0, buffer1, 0);
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, len8, "Should return 0 when maxLen is 0");
|
|
|
|
Serial.println("[TEST] PlaceholderRegistry rendering tests completed successfully");
|
|
}
|
|
|
|
// Test PlaceholderRegistry edge cases
|
|
void test_placeholder_registry_edge_cases() {
|
|
Serial.println("[TEST] Testing PlaceholderRegistry edge cases...");
|
|
|
|
// Test registry with maxPlaceholders = 1
|
|
PlaceholderRegistry smallRegistry(1);
|
|
TEST_ASSERT_TRUE_MESSAGE(smallRegistry.registerProgmemData("%A%", test_css_data),
|
|
"Should register placeholder in small registry");
|
|
TEST_ASSERT_FALSE_MESSAGE(smallRegistry.registerProgmemData("%B%", test_js_data),
|
|
"Should reject second placeholder in small registry");
|
|
|
|
// Test placeholder name at maximum length
|
|
char maxName[25];
|
|
strncpy(maxName, "%", sizeof(maxName) - 1);
|
|
maxName[0] = '%';
|
|
for (int i = 1; i < 22; i++) {
|
|
maxName[i] = 'A';
|
|
}
|
|
maxName[22] = '%';
|
|
maxName[23] = '\0';
|
|
|
|
PlaceholderRegistry registry(10);
|
|
TEST_ASSERT_TRUE_MESSAGE(registry.registerProgmemData(maxName, test_css_data),
|
|
"Should register placeholder with max length name");
|
|
|
|
// Test placeholder name over maximum length
|
|
char overName[30];
|
|
overName[0] = '%';
|
|
for (int i = 1; i < 27; i++) {
|
|
overName[i] = 'A';
|
|
}
|
|
overName[27] = '%';
|
|
overName[28] = '\0';
|
|
|
|
TEST_ASSERT_FALSE_MESSAGE(registry.registerProgmemData(overName, test_css_data),
|
|
"Should reject placeholder with over max length name");
|
|
|
|
// Test length calculation
|
|
size_t progmemLen = PlaceholderRegistry::getProgmemLength(test_css_data);
|
|
TEST_ASSERT_GREATER_THAN_MESSAGE(0, progmemLen, "Should calculate PROGMEM length");
|
|
|
|
// Test length calculation with null
|
|
size_t nullLen = PlaceholderRegistry::getProgmemLength(nullptr);
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, nullLen, "Should return 0 for null PROGMEM data");
|
|
|
|
// Test RAM length calculation
|
|
size_t ramLen = PlaceholderRegistry::getRamLength((const void*)getTestRamData);
|
|
TEST_ASSERT_GREATER_THAN_MESSAGE(0, ramLen, "Should calculate RAM length");
|
|
|
|
// Test RAM length calculation with null
|
|
size_t nullRamLen = PlaceholderRegistry::getRamLength(nullptr);
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, nullRamLen, "Should return 0 for null RAM getter");
|
|
|
|
Serial.println("[TEST] PlaceholderRegistry edge case tests completed successfully");
|
|
}
|
|
|