Files
DFTE/test/test_template_engine/tests/test_placeholder_registry.cpp
T
2025-11-09 10:17:57 +10:00

256 lines
11 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 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_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 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");
}