/** * StorageTest - Unit tests for high-level Storage interface */ using Implexus.Core; using Implexus.Storage; public static int main(string[] args) { int passed = 0; int failed = 0; // Test 1: Store and get entity metadata if (test_store_entity_metadata()) { passed++; stdout.puts("PASS: test_store_entity_metadata\n"); } else { failed++; stdout.puts("FAIL: test_store_entity_metadata\n"); } // Test 2: Entity exists if (test_entity_exists()) { passed++; stdout.puts("PASS: test_entity_exists\n"); } else { failed++; stdout.puts("FAIL: test_entity_exists\n"); } // Test 3: Delete entity if (test_delete_entity()) { passed++; stdout.puts("PASS: test_delete_entity\n"); } else { failed++; stdout.puts("FAIL: test_delete_entity\n"); } // Test 4: Store and load properties if (test_store_load_properties()) { passed++; stdout.puts("PASS: test_store_load_properties\n"); } else { failed++; stdout.puts("FAIL: test_store_load_properties\n"); } // Test 5: Add and get children if (test_add_get_children()) { passed++; stdout.puts("PASS: test_add_get_children\n"); } else { failed++; stdout.puts("FAIL: test_add_get_children\n"); } // Test 6: Remove child if (test_remove_child()) { passed++; stdout.puts("PASS: test_remove_child\n"); } else { failed++; stdout.puts("FAIL: test_remove_child\n"); } // Test 7: Has child if (test_has_child()) { passed++; stdout.puts("PASS: test_has_child\n"); } else { failed++; stdout.puts("FAIL: test_has_child\n"); } // Test 8: Store and get category config if (test_category_config()) { passed++; stdout.puts("PASS: test_category_config\n"); } else { failed++; stdout.puts("FAIL: test_category_config\n"); } // Test 9: Type label storage if (test_type_label()) { passed++; stdout.puts("PASS: test_type_label\n"); } else { failed++; stdout.puts("FAIL: test_type_label\n"); } // Test 10: Multiple entity types if (test_multiple_entity_types()) { passed++; stdout.puts("PASS: test_multiple_entity_types\n"); } else { failed++; stdout.puts("FAIL: test_multiple_entity_types\n"); } // Test 11: Root entity if (test_root_entity()) { passed++; stdout.puts("PASS: test_root_entity\n"); } else { failed++; stdout.puts("FAIL: test_root_entity\n"); } // Test 12: Nested paths if (test_nested_paths()) { passed++; stdout.puts("PASS: test_nested_paths\n"); } else { failed++; stdout.puts("FAIL: test_nested_paths\n"); } // Test 13: Complex properties if (test_complex_properties()) { passed++; stdout.puts("PASS: test_complex_properties\n"); } else { failed++; stdout.puts("FAIL: test_complex_properties\n"); } // Test 14: Empty children if (test_empty_children()) { passed++; stdout.puts("PASS: test_empty_children\n"); } else { failed++; stdout.puts("FAIL: test_empty_children\n"); } // Test 15: Persistence if (test_storage_persistence()) { passed++; stdout.puts("PASS: test_storage_persistence\n"); } else { failed++; stdout.puts("FAIL: test_storage_persistence\n"); } stdout.printf("\nResults: %d passed, %d failed\n", passed, failed); return failed > 0 ? 1 : 0; } // Helper to create temporary directory string create_temp_dir() { string temp_dir = DirUtils.mkdtemp("implexus_storage_test_XXXXXX"); return temp_dir; } // Test 1: Store and get entity metadata bool test_store_entity_metadata() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/users"); storage.store_entity_metadata(path, EntityType.CONTAINER, null); var type = storage.get_entity_type(path); if (type == null) return false; if ((!) type != EntityType.CONTAINER) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 2: Entity exists bool test_entity_exists() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/users"); if (storage.entity_exists(path)) return false; // Should not exist yet storage.store_entity_metadata(path, EntityType.CONTAINER, null); if (!storage.entity_exists(path)) return false; // Should exist now cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 3: Delete entity bool test_delete_entity() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/users"); storage.store_entity_metadata(path, EntityType.CONTAINER, null); if (!storage.entity_exists(path)) return false; storage.delete_entity(path); if (storage.entity_exists(path)) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 4: Store and load properties bool test_store_load_properties() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/users/john"); storage.store_entity_metadata(path, EntityType.DOCUMENT, "User"); var props = new Invercargill.DataStructures.PropertyDictionary(); props.set("name", new Invercargill.NativeElement("John Doe")); props.set("age", new Invercargill.NativeElement(30)); props.set("active", new Invercargill.NativeElement(true)); storage.store_properties(path, props); var loaded = storage.load_properties(path); if (loaded == null) return false; // Check name var name_elem = ((!) loaded).get("name"); if (name_elem == null || ((!) name_elem).is_null()) return false; string name = ((!) name_elem).as(); if (name != "John Doe") return false; // Check age var age_elem = ((!) loaded).get("age"); if (age_elem == null || ((!) age_elem).is_null()) return false; int64? age = ((!) age_elem).as(); if (age == null || (!) age != 30) return false; // Check active var active_elem = ((!) loaded).get("active"); if (active_elem == null || ((!) active_elem).is_null()) return false; bool active = ((!) active_elem).as(); if (active != true) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 5: Add and get children bool test_add_get_children() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var parent = new EntityPath("/users"); storage.store_entity_metadata(parent, EntityType.CONTAINER, null); storage.add_child(parent, "john"); storage.add_child(parent, "jane"); storage.add_child(parent, "bob"); var children = storage.get_children(parent); if (children.count() != 3) return false; // Check all children are present var child_set = new Invercargill.DataStructures.HashSet(); foreach (var child in children) { child_set.add(child); } if (!child_set.has("john")) return false; if (!child_set.has("jane")) return false; if (!child_set.has("bob")) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 6: Remove child bool test_remove_child() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var parent = new EntityPath("/users"); storage.store_entity_metadata(parent, EntityType.CONTAINER, null); storage.add_child(parent, "john"); storage.add_child(parent, "jane"); if (storage.get_children(parent).count() != 2) return false; storage.remove_child(parent, "john"); var children = storage.get_children(parent); if (children.count() != 1) return false; foreach (var child in children) { if (child != "jane") return false; } cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 7: Has child bool test_has_child() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var parent = new EntityPath("/users"); storage.store_entity_metadata(parent, EntityType.CONTAINER, null); if (storage.has_child(parent, "john")) return false; storage.add_child(parent, "john"); if (!storage.has_child(parent, "john")) return false; if (storage.has_child(parent, "jane")) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 8: Store and get category config bool test_category_config() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/users/by_name"); storage.store_entity_metadata(path, EntityType.CATEGORY, null); storage.store_category_config(path, "User", "name"); var config = storage.get_category_config(path); if (config == null) return false; if (((!) config).type_label != "User") return false; if (((!) config).expression != "name") return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 9: Type label storage bool test_type_label() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/users/john"); storage.store_entity_metadata(path, EntityType.DOCUMENT, "User"); var label = storage.get_entity_type_label(path); if (label == null || (!) label != "User") return false; // Test without type label var path2 = new EntityPath("/categories"); storage.store_entity_metadata(path2, EntityType.CONTAINER, null); var label2 = storage.get_entity_type_label(path2); // Should be null for containers without type label if (label2 != null) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 10: Multiple entity types bool test_multiple_entity_types() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); // Container var cat_path = new EntityPath("/categories"); storage.store_entity_metadata(cat_path, EntityType.CONTAINER, null); // Document var doc_path = new EntityPath("/documents/doc1"); storage.store_entity_metadata(doc_path, EntityType.DOCUMENT, "Doc"); // Category var category_path = new EntityPath("/categories/cat1"); storage.store_entity_metadata(category_path, EntityType.CATEGORY, null); // Index var index_path = new EntityPath("/indices/idx1"); storage.store_entity_metadata(index_path, EntityType.INDEX, null); // Verify types var cat_type = storage.get_entity_type(cat_path); if (cat_type == null || (!) cat_type != EntityType.CONTAINER) return false; var doc_type = storage.get_entity_type(doc_path); if (doc_type == null || (!) doc_type != EntityType.DOCUMENT) return false; var category_type = storage.get_entity_type(category_path); if (category_type == null || (!) category_type != EntityType.CATEGORY) return false; var index_type = storage.get_entity_type(index_path); if (index_type == null || (!) index_type != EntityType.INDEX) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 11: Root entity bool test_root_entity() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var root = new EntityPath.root(); storage.store_entity_metadata(root, EntityType.CONTAINER, null); var type = storage.get_entity_type(root); if (type == null || (!) type != EntityType.CONTAINER) return false; if (!storage.entity_exists(root)) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 12: Nested paths bool test_nested_paths() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); // Create nested structure var level1 = new EntityPath("/level1"); var level2 = new EntityPath("/level1/level2"); var level3 = new EntityPath("/level1/level2/level3"); storage.store_entity_metadata(level1, EntityType.CONTAINER, null); storage.store_entity_metadata(level2, EntityType.CONTAINER, null); storage.store_entity_metadata(level3, EntityType.DOCUMENT, "Deep"); // Verify all exist if (!storage.entity_exists(level1)) return false; if (!storage.entity_exists(level2)) return false; if (!storage.entity_exists(level3)) return false; // Verify types var type1 = storage.get_entity_type(level1); var type2 = storage.get_entity_type(level2); var type3 = storage.get_entity_type(level3); if (type1 == null || (!) type1 != EntityType.CONTAINER) return false; if (type2 == null || (!) type2 != EntityType.CONTAINER) return false; if (type3 == null || (!) type3 != EntityType.DOCUMENT) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 13: Complex properties bool test_complex_properties() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/complex"); storage.store_entity_metadata(path, EntityType.DOCUMENT, "Complex"); var props = new Invercargill.DataStructures.PropertyDictionary(); // Nested array var array = new Invercargill.DataStructures.Vector(); array.add(new Invercargill.NativeElement("item1")); array.add(new Invercargill.NativeElement("item2")); array.add(new Invercargill.NativeElement("item3")); props.set("items", new Invercargill.NativeElement>(array)); // Nested dictionary var dict = new Invercargill.DataStructures.PropertyDictionary(); dict.set("key1", new Invercargill.NativeElement("value1")); dict.set("key2", new Invercargill.NativeElement("value2")); props.set("nested", new Invercargill.NativeElement(dict)); storage.store_properties(path, props); var loaded = storage.load_properties(path); if (loaded == null) return false; // Check array var items_elem = ((!) loaded).get("items"); if (items_elem == null || ((!) items_elem).is_null()) return false; var items = ((!) items_elem).as>(); if (items.count() != 3) return false; // Check dictionary var nested_elem = ((!) loaded).get("nested"); if (nested_elem == null || ((!) nested_elem).is_null()) return false; var nested = ((!) nested_elem).as(); if (nested.count() != 2) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 14: Empty children bool test_empty_children() { string temp_dir = create_temp_dir(); try { var storage = new BasicStorage.with_directory(temp_dir); var parent = new EntityPath("/empty"); storage.store_entity_metadata(parent, EntityType.CONTAINER, null); var children = storage.get_children(parent); if (children.count() != 0) return false; if (storage.has_child(parent, "any")) return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Test 15: Persistence bool test_storage_persistence() { string temp_dir = create_temp_dir(); try { // Create and write var storage1 = new BasicStorage.with_directory(temp_dir); var path = new EntityPath("/persistent"); storage1.store_entity_metadata(path, EntityType.DOCUMENT, "Persistent"); var props = new Invercargill.DataStructures.PropertyDictionary(); props.set("key", new Invercargill.NativeElement("value")); storage1.store_properties(path, props); // Create new instance var storage2 = new BasicStorage.with_directory(temp_dir); // Verify data persists if (!storage2.entity_exists(path)) return false; var type = storage2.get_entity_type(path); if (type == null || (!) type != EntityType.DOCUMENT) return false; var loaded = storage2.load_properties(path); if (loaded == null) return false; var key_elem = ((!) loaded).get("key"); if (key_elem == null || ((!) key_elem).is_null()) return false; string key = ((!) key_elem).as(); if (key != "value") return false; cleanup_dir(temp_dir); return true; } catch (Error e) { cleanup_dir(temp_dir); return false; } } // Cleanup helper void cleanup_dir(string path) { try { Dir dir = Dir.open(path, 0); string? name; while ((name = dir.read_name()) != null) { FileUtils.unlink(Path.build_filename(path, name)); } } catch (FileError e) { // Ignore errors } DirUtils.remove(path); }