/** * test_full_pipeline.c - Integration tests for the full GlaMaC pipeline * * Copyright (C) 2025 https://optics-design.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. */ #include "../test_framework.h" #include "../../include/glass_data.h" #include "../../include/glamac_view.h" #include "../../include/glautils/fgla.h" // Test complete glass data loading and processing pipeline int test_glass_data_pipeline() { TEST_START("Glass Data Pipeline"); // Initialize glass data system initialize_glass_data(); // Try to load JSON data b32 json_loaded = load_glasses_from_json((const byte*)"tests/data/test_glasses.json", NULL); if (json_loaded) { // Verify we have multiple catalogs u32 catalog_count = get_catalog_count(); TEST_ASSERT(catalog_count > 0, "Should have loaded multiple catalogs"); // Test each catalog for (u32 i = 0; i < catalog_count; i++) { set_current_catalog(i); const char* catalog_name = get_catalog_name(i); TEST_ASSERT_NOT_NULL(catalog_name, "Each catalog should have a name"); u32 glass_count = get_glass_count(); TEST_ASSERT(glass_count > 0, "Each catalog should have glasses"); // Test glass properties for (u32 j = 0; j < glass_count; j++) { const Glass* glass = get_glass(j); TEST_ASSERT_NOT_NULL(glass, "Should be able to get each glass"); // Validate glass data TEST_ASSERT(glass->abbeNumber > 10.0f && glass->abbeNumber < 100.0f, "Abbe number should be in reasonable range"); TEST_ASSERT(glass->refractiveIndex > 1.0f && glass->refractiveIndex < 4.0f, "Refractive index should be in reasonable range"); const byte* name = get_glass_name(j); TEST_ASSERT_NOT_NULL(name, "Each glass should have a name"); TEST_ASSERT(strlen((const char*)name) > 0, "Glass name should not be empty"); } } } else { printf(YELLOW " Info: JSON test data not available - testing with default data" RESET "\n"); // Test with default data u32 glass_count = get_glass_count(); TEST_ASSERT(glass_count > 0, "Should have default glasses"); } cleanup_glass_data(); TEST_END(); } // Test view system with real glass data int test_view_with_glass_data() { TEST_START("View System with Glass Data"); // Initialize systems initialize_glass_data(); ViewState view; init_view(&view, 1024, 768); // Load test data if available load_glasses_from_json((const byte*)"tests/data/test_glasses.json", NULL); // Test view fitting with real data fit_view_to_data(&view); // After fitting, we should be able to see all glasses TEST_ASSERT(view.zoom > 0.0f, "Zoom should be positive after fitting"); TEST_ASSERT(view.zoom <= MAX_ZOOM, "Zoom should not exceed maximum"); // Test coordinate transformations with actual glass data u32 glass_count = get_glass_count(); if (glass_count > 0) { const Glass* glass = get_glass(0); i32 screenX, screenY; glass_to_screen_coords(glass->abbeNumber, glass->refractiveIndex, &view, &screenX, &screenY); // Screen coordinates should be reasonable TEST_ASSERT(screenX >= -100 && screenX <= view.windowWidth + 100, "Screen X should be near window bounds"); TEST_ASSERT(screenY >= -100 && screenY <= view.windowHeight + 100, "Screen Y should be near window bounds"); // Test inverse transformation f32 recovered_abbe, recovered_ri; screen_to_glass_coords(screenX, screenY, &view, &recovered_abbe, &recovered_ri); TEST_ASSERT_FLOAT_EQ(glass->abbeNumber, recovered_abbe, 0.1f, "Should recover original Abbe number"); TEST_ASSERT_FLOAT_EQ(glass->refractiveIndex, recovered_ri, 0.001f, "Should recover original refractive index"); } // Test clustering with real data update_clustering(&view); TEST_ASSERT(view.clusterCount >= 0, "Clustering should complete successfully"); cleanup_glass_data(); TEST_END(); } // Test FGLA search functionality with actual data int test_fgla_search_integration() { TEST_START("FGLA Search Integration"); // Test various search functions that would be used in the real application // Test glass code pattern matching with realistic codes TEST_ASSERT(fgla_matches_glass_code_pattern_safe("517642", "517642"), "Should match exact glass code"); TEST_ASSERT(fgla_matches_glass_code_pattern_safe("517642123", "517642"), "Should match first 6 digits of longer code"); TEST_ASSERT(fgla_matches_glass_code_pattern_safe("517642", "51x64x"), "Should match wildcard pattern"); // Test realistic search terms TEST_ASSERT(fgla_validate_search_term("N-BK7"), "N-BK7 should be valid search term"); TEST_ASSERT(fgla_validate_search_term("SF10"), "SF10 should be valid search term"); TEST_ASSERT(fgla_validate_search_term("FCD1"), "FCD1 should be valid search term"); // Test substring matching with realistic glass names TEST_ASSERT(fgla_contains_substring_safe("N-BK7", "BK"), "Should find BK in N-BK7"); TEST_ASSERT(fgla_contains_substring_safe("SF10", "sf"), "Should find sf in SF10 (case insensitive)"); TEST_ASSERT(fgla_contains_substring_safe("FCD1", "fcd"), "Should find fcd in FCD1 (case insensitive)"); // Test catalog matching with real manufacturers const char* real_catalogs[] = {"SCHOTT", "HOYA", "CDGM", "Ohara"}; TEST_ASSERT(fgla_matches_catalog("SCHOTT", real_catalogs, 4), "Should match SCHOTT catalog"); TEST_ASSERT(fgla_matches_catalog("hoya", real_catalogs, 4), "Should match HOYA catalog (case insensitive)"); TEST_ASSERT(!fgla_matches_catalog("UNKNOWN", real_catalogs, 4), "Should not match unknown manufacturer"); TEST_END(); } // Test error handling across systems int test_error_handling_integration() { TEST_START("Error Handling Integration"); // Test glass data error handling b32 result = load_glasses_from_json((const byte*)"nonexistent.json", NULL); TEST_ASSERT(!result, "Should fail gracefully with non-existent file"); result = load_glasses_from_json(NULL, NULL); TEST_ASSERT(!result, "Should fail gracefully with NULL path"); // Test view system with invalid parameters ViewState view; init_view(&view, 0, 0); // Invalid dimensions TEST_ASSERT(view.windowWidth > 0, "Should handle invalid width gracefully"); TEST_ASSERT(view.windowHeight > 0, "Should handle invalid height gracefully"); // Test coordinate transformations with extreme values i32 screenX, screenY; glass_to_screen_coords(1000.0f, 10.0f, &view, &screenX, &screenY); // Extreme values // Should not crash - exact values depend on implementation // Test FGLA with invalid inputs TEST_ASSERT(!fgla_validate_search_term(NULL), "Should reject NULL search term"); TEST_ASSERT(!fgla_validate_search_term(""), "Should reject empty search term"); TEST_ASSERT(!fgla_is_glass_code_pattern(NULL), "Should reject NULL glass code pattern"); TEST_END(); } // Test memory management across systems int test_memory_management() { TEST_START("Memory Management"); // Test multiple initialize/cleanup cycles for (int i = 0; i < 5; i++) { initialize_glass_data(); // Load data load_glasses_from_json((const byte*)"tests/data/test_glasses.json", NULL); // Use the data u32 count = get_glass_count(); if (count > 0) { const Glass* glass = get_glass(0); (void)glass; // Suppress unused variable warning } // Cleanup cleanup_glass_data(); } // After all cycles, we should be back to clean state // Try to initialize again initialize_glass_data(); u32 final_count = get_glass_count(); TEST_ASSERT(final_count >= 0, "Should be able to initialize after cleanup cycles"); cleanup_glass_data(); TEST_END(); } // Test performance with realistic data volumes int test_performance() { TEST_START("Performance Test"); initialize_glass_data(); // Load data b32 loaded = load_glasses_from_json((const byte*)"tests/data/test_glasses.json", NULL); if (loaded) { // Test rapid catalog switching u32 catalog_count = get_catalog_count(); for (int i = 0; i < 100; i++) { set_current_catalog(i % catalog_count); u32 count = get_glass_count(); (void)count; // Use the result } // Test rapid coordinate transformations ViewState view; init_view(&view, 1024, 768); fit_view_to_data(&view); for (int i = 0; i < 1000; i++) { i32 screenX, screenY; f32 abbe = 30.0f + (i % 50); f32 ri = 1.4f + (i % 20) * 0.01f; glass_to_screen_coords(abbe, ri, &view, &screenX, &screenY); } // Test clustering performance for (int i = 0; i < 10; i++) { update_clustering(&view); } } cleanup_glass_data(); TEST_END(); } // Main integration test runner int main() { printf(BLUE "=== GlaMaC Integration Tests ===" RESET "\n\n"); RUN_TEST(test_glass_data_pipeline); RUN_TEST(test_view_with_glass_data); RUN_TEST(test_fgla_search_integration); RUN_TEST(test_error_handling_integration); RUN_TEST(test_memory_management); RUN_TEST(test_performance); TEST_SUMMARY(); }