| Crates.io | hedl-test |
| lib.rs | hedl-test |
| version | 1.2.0 |
| created_at | 2026-01-08 11:13:24.13309+00 |
| updated_at | 2026-01-21 02:59:23.834813+00 |
| description | Shared test fixtures and utilities for HEDL format converters |
| homepage | https://dweve.com |
| repository | https://github.com/dweve/hedl |
| max_upload_size | |
| id | 2030002 |
| size | 235,941 |
Shared test fixtures and utilities for HEDL—comprehensive test data, builders, and error cases for consistent testing across all crates.
Testing format converters requires representative documents. Building test cases by hand is tedious and error-prone. Common test scenarios should be reusable across crates. Edge cases need systematic coverage. Error conditions must be validated consistently.
hedl-test provides 15 pre-built fixtures covering all HEDL features, 4 builder types for programmatic document construction, comprehensive error fixtures (15 invalid HEDL, 15 invalid expressions, 8 semantic violations), and edge case generators (deep nesting, wide documents, long strings, many references).
Comprehensive test infrastructure:
[dev-dependencies]
hedl-test = { workspace = true }
Or specify version directly:
[dev-dependencies]
hedl-test = "1.2"
use hedl_test::fixtures;
// Scalar types (all primitives)
let doc = fixtures::scalars();
// Contains: int, float, bool, null, string examples
// Special strings (escapes, Unicode, etc.)
let doc = fixtures::special_strings();
// Contains: quotes, escapes, newlines, Unicode
// References (qualified and local)
let doc = fixtures::references();
// Contains: local references (@id) and typed references (@Type:id)
// Tensors (matrix literals)
let doc = fixtures::tensors();
// Contains: 1D, 2D, 3D tensors and empty tensor
use hedl_test::fixtures;
// User list (simple matrix)
let doc = fixtures::user_list();
// 3 users: alice, bob, charlie with id, name, email
// Mixed type list
let doc = fixtures::mixed_type_list();
// Items with int, float, bool, null, and string fields
// With references
let doc = fixtures::with_references();
// Users and Posts with author references
// With NEST hierarchy
let doc = fixtures::with_nest();
// Users with nested posts (parent-child via NEST)
// Deep NEST hierarchy
let doc = fixtures::deep_nest();
// Organization → Department → Employee (3 levels)
// Blog (nested structure)
let doc = fixtures::blog();
// Complex blog platform: users, categories, tags, posts, comments, reactions, post_tags, followers
All HEDL features in one document:
use hedl_test::fixtures;
let doc = fixtures::comprehensive();
// Contains:
// - Scalar values (bool, string, int, float)
// - Expressions (function calls, identifiers, literals)
// - Tensors
// - Users list with nested posts (via NEST)
// - Comments and Tags lists
// - References between entities
// - Multiple STRUCT definitions
// - NEST directive
Programmatically construct documents:
use hedl_test::fixtures::builders::DocumentBuilder;
use hedl_core::Value;
let doc = DocumentBuilder::new()
.version(1, 0)
.struct_def("User", vec!["id".to_string(), "name".to_string(), "email".to_string()])
.alias("api_url", "https://api.example.com")
.nest("User", "Post")
.scalar("app_name", Value::String("MyApp".to_string().into()))
.scalar("debug", Value::Bool(true))
.build();
Methods:
version(major, minor) - Set document versionstruct_def(name, fields) - Add struct definitionalias(alias, target) - Add aliasnest(parent, child) - Add NEST relationshipscalar(name, value) - Add scalar value to rootlist(name, list) - Add MatrixList to rootitem(name, item) - Add Item to rootbuild() - Build the DocumentBuild typed entity lists:
use hedl_test::fixtures::builders::MatrixListBuilder;
use hedl_core::{Node, Value};
let list = MatrixListBuilder::new("User")
.schema(vec!["id".to_string(), "name".to_string(), "age".to_string()])
.row(Node::new("User", "alice", vec![
Value::String("alice".to_string().into()),
Value::String("Alice Smith".to_string().into()),
Value::Int(30),
]))
.row(Node::new("User", "bob", vec![
Value::String("bob".to_string().into()),
Value::String("Bob Jones".to_string().into()),
Value::Int(25),
]))
.build();
Methods:
schema(fields) - Set schema (all field names)field(field) - Add single field to schemarow(node) - Add a row (node)rows(nodes) - Add multiple rowscount_hint(count) - Set count hintbuild() - Build the MatrixListBuild individual entities:
use hedl_test::fixtures::builders::NodeBuilder;
use hedl_core::Value;
let node = NodeBuilder::new("User", "alice")
.field(Value::String("alice".to_string().into()))
.field(Value::String("Alice Smith".to_string().into()))
.field(Value::Int(30))
.build();
Methods:
field(value) - Add a field valuefields(values) - Add multiple field valueschildren(rel_name, nodes) - Add child nodes under a relationshipchild(rel_name, node) - Add single child nodechild_count(count) - Set child count hintbuild() - Build the NodeStatic helper methods for creating values:
use hedl_test::fixtures::builders::ValueBuilder;
// Scalar values
let v = ValueBuilder::null();
let v = ValueBuilder::bool_val(true);
let v = ValueBuilder::int(42);
let v = ValueBuilder::float(3.14);
let v = ValueBuilder::string("Hello");
// References
let v = ValueBuilder::reference("User", "alice"); // Qualified reference
let v = ValueBuilder::local_ref("some_id"); // Local reference
// Tensors
let v = ValueBuilder::tensor_1d(vec![1.0, 2.0, 3.0]);
let v = ValueBuilder::tensor_2d(vec![vec![1.0, 2.0], vec![3.0, 4.0]]);
Methods:
null() - Create null valuebool_val(value) - Create boolean valueint(value) - Create integer valuefloat(value) - Create float valuestring(value) - Create string valuereference(type_name, id) - Create qualified referencelocal_ref(id) - Create local referencetensor_1d(values) - Create 1D tensortensor_2d(rows) - Create 2D tensoruse hedl_test::fixtures::errors;
// Get all invalid HEDL samples as (name, hedl_text) pairs
let samples = errors::invalid_hedl_samples();
for (name, hedl_text) in samples {
// Test parser with invalid input
// Each should fail to parse
}
Available samples (15 total):
empty - Empty documentwhitespace_only - Only whitespaceinvalid_directive - Invalid directive namemissing_separator - Missing --- separatorinvalid_version - Invalid version numbermalformed_struct - Malformed STRUCT directiveunclosed_string - Unclosed string literalinvalid_escape - Invalid escape sequencemalformed_reference - Malformed referenceinvalid_tensor - Malformed tensor syntaxmismatched_brackets - Mismatched bracketsinvalid_number - Invalid number formatmalformed_expression - Malformed expressioninvalid_identifier - Invalid identifierduplicate_directive - Duplicate directiveuse hedl_test::fixtures::errors;
// Get all invalid expression samples as (description, expr_string) pairs
let samples = errors::invalid_expression_samples();
for (desc, expr_str) in samples {
// Test expression parser with invalid input
// Each should fail to parse
}
Available samples (15 total):
empty - Empty expressionwhitespace_only - Only whitespaceunclosed_paren - Unclosed parenthesisunclosed_string - Unclosed string literalinvalid_chars - Invalid charactersdouble_dot - Double dot in pathtrailing_dot - Trailing dotleading_dot - Leading dotmismatched_parens - Mismatched parenthesesempty_call - Empty function callinvalid_identifier - Invalid identifierspecial_chars_only - Only special charactersnested_unclosed - Nested unclosed parenthesescomma_without_args - Comma without argumentstrailing_comma - Trailing commaValid syntax but semantic violations:
use hedl_test::fixtures::errors;
// Get all semantically invalid documents as (name, document) pairs
let docs = errors::semantically_invalid_docs();
for (name, doc) in docs {
// Test validation logic with semantically invalid documents
// Each should fail validation but parse correctly
}
Available documents (8 total):
undefined_struct - MatrixList references undefined structundefined_nest - NEST directive references non-existent child typecircular_nest - Circular NEST references (TypeA → TypeB → TypeA)dangling_reference - Reference points to non-existent nodemismatched_schema - MatrixList schema doesn't match struct definitionempty_type_name - MatrixList has empty type nameduplicate_ids - Multiple nodes with same ID in a listinvalid_alias - Alias references non-existent itemTest parser depth limits:
use hedl_test::fixtures::errors;
let doc = errors::deeply_nested_document(1000);
// Creates 1000 levels of nested children via NEST
Use Case: Verify recursion depth limits and stack safety
Test handling of many entities:
use hedl_test::fixtures::errors;
let doc = errors::wide_document(1000);
// Creates a MatrixList with 1000 rows
Use Case: Verify large list handling and memory efficiency
Test string length limits:
use hedl_test::fixtures::errors;
let doc = errors::long_string_document(1024 * 1024);
// Creates a document with a 1 MB string value
Use Case: Verify string buffer limits and allocation safety
Test reference resolution performance:
use hedl_test::fixtures::errors;
let doc = errors::many_references_document(10_000);
// Creates 10K target nodes and 10K references
Use Case: Verify reference resolution performance and correctness
use hedl_test::{count_nodes, count_references};
// Count total nodes (entities) in document
let count = count_nodes(&doc);
// Count total references in document
let ref_count = count_references(&doc);
Available functions:
count_nodes(&doc) - Count all nodes in the document (including nested children)count_references(&doc) - Count all reference values in the documentuse hedl_test::{expr, try_expr, expr_value, try_expr_value, ExprError};
// Create Expression from string (panics on error)
let e = expr("42");
let e = expr("now()");
let e = expr("user.name");
// Create Expression safely (returns Result)
let result = try_expr("invalid!!!");
match result {
Ok(e) => println!("Parsed: {:?}", e),
Err(ExprError::ParseFailed { source, input }) => {
println!("Failed to parse '{}': {}", input, source);
}
Err(ExprError::EmptyInput) => println!("Empty input"),
Err(ExprError::Missing) => println!("Missing expression"),
}
// Create Value::Expression from string
let v = expr_value("42"); // Panics on error
let v = try_expr_value("42")?; // Returns Result
Available functions:
expr(s) - Parse expression string, panic on errortry_expr(s) - Parse expression string, return Resultexpr_value(s) - Create Value::Expression, panic on errortry_expr_value(s) - Create Value::Expression, return ResultError type:
ExprError::EmptyInput - Expression string is emptyExprError::ParseFailed { source, input } - Parse failed with lexical errorExprError::Missing - Expression is missing or nullThe fixtures::builders::quick module provides convenient helper functions for common patterns:
use hedl_test::fixtures::builders::quick;
// Create document with simple scalar fields
let doc = quick::simple_scalars(vec![
("name", "Alice"),
("city", "NYC"),
]);
// Create document with simple user list
let doc = quick::simple_user_list(vec![
("alice", "Alice Smith", "alice@example.com"),
("bob", "Bob Jones", "bob@example.com"),
]);
// Create document with references
let doc = quick::with_references(
vec![("alice", "Alice"), ("bob", "Bob")], // users
vec![("post1", "Title", "alice")], // posts with author refs
);
use hedl_test::fixtures;
#[test]
fn test_parse_user_list() {
let doc = fixtures::user_list();
assert_eq!(doc.version, (1, 0));
if let Some(hedl_core::Item::List(list)) = doc.root.get("users") {
assert_eq!(list.rows.len(), 3);
assert_eq!(list.type_name, "User");
}
}
use hedl_test::fixtures;
#[test]
fn test_all_fixtures() {
for (name, fixture_fn) in fixtures::all() {
let doc = fixture_fn();
// Test your converter with each fixture
let json = to_json(&doc).unwrap();
let back = from_json(&json).unwrap();
// Verify roundtrip
assert_eq!(doc, back, "Fixture {} failed roundtrip", name);
}
}
use hedl_test::fixtures::errors;
#[test]
fn test_invalid_hedl_samples() {
for (name, hedl_text) in errors::invalid_hedl_samples() {
let result = parse(hedl_text);
assert!(result.is_err(), "Sample {} should fail to parse", name);
}
}
#[test]
fn test_semantic_errors() {
for (name, doc) in errors::semantically_invalid_docs() {
let result = validate(&doc);
assert!(result.is_err(), "Document {} should fail validation", name);
}
}
use hedl_test::fixtures::errors;
use hedl_test::count_nodes;
#[test]
fn test_deeply_nested() {
let doc = errors::deeply_nested_document(100);
let count = count_nodes(&doc);
// Verify deep nesting is handled correctly
assert!(count > 0);
}
#[test]
fn test_many_references() {
let doc = errors::many_references_document(1000);
// Test reference resolution performance
let result = resolve_references(&doc);
assert!(result.is_ok());
}
Property-Based Testing: Fixtures are hand-crafted examples. For property-based testing, use proptest or quickcheck with custom generators.
Performance Testing: Fixtures designed for correctness testing. For performance, use hedl-bench with realistic workloads.
Fuzz Testing: No fuzzing infrastructure. For fuzz testing, use cargo-fuzz with custom fuzz targets.
Test Data Generation: Fixtures are static. For dynamic test data, write custom generators using builders.
hedl-core - Core HEDL types and parsinghedl-c14n - Canonicalization for HEDL documentssmallvec - Optimized small vector implementationApache-2.0