This guide covers all testing approaches in the Dist Agent Language ecosystem.
# Layer 1: Run Rust unit tests (syntax validation)
cd dist_agent_lang
cargo test
# Layer 2: Semantic validation (used within tests)
# See examples in tests/example_tests.rs
# Layer 3: Run DAL test files (runtime behavior)
./scripts/run_dal_tests.shDAL uses a three-layer testing strategy that provides comprehensive validation at different levels:
For complete details, see THREE_LAYER_TESTING.md.
Validate that all DAL code parses correctly and has valid syntax.
/dist_agent_lang/tests/example_tests.rs
# Run all tests
cargo test
# Run only example tests
cargo test --test example_tests
# Run specific test
cargo test test_hello_world_demo_parses
# Run with verbose output
cargo test -- --nocapture
# Run tests for a category
cargo test test_blockchain_examples_parse✅ All .dal files in examples/ directory ✅
Syntax correctness ✅ Parse-time validation ✅ Attribute syntax ✅
Statement structure
Tests automatically include any .dal file in the
examples/ directory. To add a new test:
.dal file to examples/cargo testrunning 25 tests
test test_hello_world_demo_parses ... ok
test test_cross_chain_patterns_parses ... ok
test test_token_contract_parses ... ok
test test_all_examples_parse ... ok
test result: ok. 25 passed; 0 failed; 0 ignored
Validate semantic meaning beyond syntax (attribute values, types, rules).
/dist_agent_lang/src/stdlib/test.rs
// Validate trust models
test::expect_valid_trust_model("hybrid") // ✓
test::expect_valid_trust_model("centralized") // ✓
test::expect_valid_trust_model("decentralized") // ✓
test::expect_valid_trust_model("invalid") // ✗ Error
// Validate blockchains
test::expect_valid_chain("ethereum") // ✓
test::expect_valid_chain("polygon") // ✓
test::expect_valid_chain("solana") // ✓
test::expect_valid_chain("fake") // ✗ Error
// Validate attribute compatibility
test::expect_compatible_attributes(["trust"]) // ✓
test::expect_compatible_attributes(["trust", "chain"]) // ✓
test::expect_compatible_attributes(["secure", "public"]) // ✗ Exclusive// Validate types
let value = Value::Number(42.0);
test::expect_type(&value, "number") // ✓
test::expect_type(&value, "string") // ✗ Error
// Validate ranges
test::expect_in_range(Value::Number(50.0), 0.0, 100.0) // ✓
test::expect_in_range(Value::Number(150.0), 0.0, 100.0) // ✗ Out of range// Validate length
test::expect_length(Value::String("hello"), 5) // ✓
// Validate not empty
test::expect_not_empty(Value::Vector(vec![...])) // ✓
// Validate map keys
test::expect_has_key(map, "key") // ✓test::expect_contains("hello world", "world") // ✓
test::expect_starts_with("0x123", "0x") // ✓#[test]
fn test_semantic_validation() {
let source = r#"
@trust("hybrid")
@chain("ethereum")
service MyService {}
"#;
let ast = parse_source(source).unwrap();
if let Statement::Service(service) = &ast.statements[0] {
// Validate trust model
let trust_attr = service.attributes.iter()
.find(|a| a.name == "trust")
.unwrap();
if let Expression::Literal(Literal::String(model)) = &trust_attr.parameters[0] {
expect_valid_trust_model(model).unwrap();
}
}
}describe("Semantic Validation", fn() {
it("should validate trust model", fn() {
test::expect_valid_trust_model("hybrid");
test::expect_valid_chain("ethereum");
});
});
Test runtime behavior and integration, written in DAL itself.
*.test.dalexamples/./scripts/run_dal_tests.shdescribe("Test Suite Name", fn() {
// Setup
let contract;
beforeEach(fn() {
// Runs before each test
contract = deploy_service("MyService", {});
});
afterEach(fn() {
// Runs after each test
reset_context();
});
it("should do something", fn() {
// Test implementation
let result = contract.some_method();
expect(result).to_equal(expected);
});
});
// Equality
expect(value).to_equal(expected);
expect(value).not_to_equal(other);
// Booleans
expect(value).to_be_true();
expect(value).to_be_false();
// Null checks
expect(value).to_be_nil();
expect(value).not_to_be_nil();
// Exceptions
expect_throws(fn() {
some_error_producing_code();
}, "error message");
// Layer 2 semantic validation
test::expect_type(&value, "number");
test::expect_in_range(value, 0.0, 100.0);
test::expect_valid_trust_model("hybrid");
beforeAll(fn() {
// Runs once before all tests in suite
});
beforeEach(fn() {
// Runs before each test
});
afterEach(fn() {
// Runs after each test
});
afterAll(fn() {
// Runs once after all tests in suite
});
See token_contract.test.dal
for a complete example.
# Run all test files
./scripts/run_dal_tests.sh
# Run specific test file
cargo run --release -- run examples/token_contract.test.dal
# Run with verbose output
cargo run --release -- run examples/token_contract.test.dal --verbose# Watch mode for Rust tests
cargo watch -x test
# Quick syntax check
cargo test --test example_tests# Full test suite
cargo test
# Run DAL tests
./scripts/run_dal_tests.sh# .github/workflows/test.yml
- name: Run Rust tests
run: cargo test
- name: Run DAL tests
run: ./scripts/run_dal_tests.sh ╱╲
╱ ╲ Few: Integration tests (Layer 3)
╱────╲
╱ ╲ Medium: Semantic tests (Layer 2)
╱────────╲
╱ ╲ Many: Unit tests (Layer 1)
╱────────────╲
// Rust tests
#[test]
fn test_<feature>_<scenario>() { }
// Example:
fn test_token_transfer_succeeds_with_valid_amount() { }// DAL tests
describe("Feature", fn() {
it("should do something specific", fn() { });
});
// Example:
describe("TokenContract", fn() {
it("should transfer tokens with valid amount", fn() { });
});
it("should update balance after transfer", fn() {
// Arrange
let initial_balance = contract.balance_of("alice");
let amount = 100.0;
// Act
contract.transfer("bob", amount);
// Assert
let final_balance = contract.balance_of("alice");
expect(final_balance).to_equal(initial_balance - amount);
});
describe("Tests", fn() {
beforeEach(fn() {
// Fresh state for each test
contract = deploy_service("MyService", {});
});
it("test 1", fn() { /* ... */ });
it("test 2", fn() { /* ... */ }); // Independent of test 1
});
describe("Edge Cases", fn() {
it("should handle zero values", fn() { /* ... */ });
it("should handle maximum values", fn() { /* ... */ });
it("should handle empty inputs", fn() { /* ... */ });
it("should reject invalid inputs", fn() { /* ... */ });
});
#[test]
fn test_service_attributes() {
let source = "@trust(\"hybrid\") @chain(\"ethereum\") service S {}";
let ast = parse_source(source).unwrap();
// Extract attributes
if let Statement::Service(s) = &ast.statements[0] {
let attrs: Vec<&str> = s.attributes.iter()
.map(|a| a.name.as_str())
.collect();
// Validate
expect_compatible_attributes(attrs).unwrap();
}
}it("should update state correctly", fn() {
let before = contract.get_state();
contract.modify_state();
let after = contract.get_state();
expect(after).not_to_equal(before);
});
it("should reject invalid input", fn() {
expect_throws(fn() {
contract.risky_operation(-1);
}, "must be positive");
});
describe("Multi-service integration", fn() {
let token;
let escrow;
beforeEach(fn() {
token = deploy_service("Token", {});
escrow = deploy_service("Escrow", { "token": token });
});
it("should integrate services", fn() {
token.approve(escrow, 100.0);
escrow.deposit(100.0);
expect(token.balance_of(escrow)).to_equal(100.0);
});
});
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_name -- --nocapture
# Show full backtraces
RUST_BACKTRACE=1 cargo test# Run with verbose mode
cargo run --release -- run test.dal --verbose
# Add print statements
print("Debug: value =", value);
# Check parsed AST
cargo run --release -- parse test.dalIssue: Test fails with "Parse error" Solution: Run Layer 1 tests first to check syntax
Issue: Semantic validation fails Solution: Check attribute values match allowed options
Issue: Runtime behavior unexpected Solution: Add debug prints, check service state
describe("Performance", fn() {
it("should complete in reasonable time", fn() {
let start = time::now();
// Operation to test
for i in 0..1000 {
contract.operation();
}
let duration = time::now() - start;
test::expect_in_range(duration, 0.0, 1000.0); // < 1 second
});
});
# Install tarpaulin
cargo install cargo-tarpaulin
# Generate coverage report
cargo tarpaulin --out Html
# View report
open tarpaulin-report.html# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Run Layer 1 tests
run: cargo test
- name: Run Layer 3 tests
run: ./scripts/run_dal_tests.sh| Layer | Tool | Speed | Purpose |
|---|---|---|---|
| Layer 1 | cargo test |
⚡ Fast | Syntax validation |
| Layer 2 | test::expect_*() |
🚀 Medium | Semantic validation |
| Layer 3 | ./scripts/run_dal_tests.sh |
🐌 Slower | Runtime behavior |
Best Practice: Start with Layer 1, add Layer 2 for semantic rules, and Layer 3 for critical paths.
For more details, see:
THREE_LAYER_TESTING.md
- Complete strategy overviewTESTING_ATTRIBUTES.md -
Attribute testing deep diveWHY_RUST_UNIT_TESTS.md
- Rationale for Rust tests