Location: /Users/akollegger/.cabal/bin/gramref (or in PATH)
Source: ../gram-hs/ Haskell project
Purpose: Generate test patterns and validate outputs for testing gram-rs
Created: 2026-01-08
gramref (formerly gram-hs) is a CLI tool for generating test patterns and validating outputs. It serves as the reference implementation for testing and equivalence checking.
| Aspect | ../gram-hs/ Library |
gramref CLI Tool |
|---|---|---|
| What | Haskell source code | Executable program |
| Location | ../gram-hs/libs/ |
/Users/akollegger/.cabal/bin/gramref |
| Purpose | Reference implementation to port | Testing and validation tool |
| Use for | Reading code, understanding algorithms | Generating test data, checking outputs |
| When | During implementation | During testing |
Key point: Read from ../gram-hs/libs/ when implementing features; execute gramref when testing those features.
which gramref
# Output: /Users/akollegger/.cabal/bin/gramref
gramref --helpcd ../gram-hs
cabal build
cabal installgramref <command> [options]| Command | Description |
|---|---|
parse |
Parse gram notation and output pattern structure |
generate |
Generate test patterns with specified criteria |
Parse gram notation and output the pattern structure.
echo '(alice)' | gramref parse --format jsonOutput (includes metadata):
{
"meta": {
"hash": "abc123...",
"timestamp": "2024-01-08T10:30:00Z"
},
"value": {
"symbol": "alice",
"labels": [],
"properties": {}
},
"elements": []
}Get just the pattern value without metadata:
echo '(alice)' | gramref parse --format json --value-onlyOutput:
{
"elements": [],
"value": {
"labels": [],
"properties": {},
"symbol": "alice"
}
}Use case: Equivalence checking without metadata differences.
Sort JSON keys alphabetically for consistent output:
echo '(alice:Person)' | gramref parse --format json --canonicalUse case: Reliable diff comparison, byte-for-byte matching.
Use fixed values for metadata (timestamp and hash):
echo '(alice)' | gramref parse --format json --deterministicMetadata values:
timestamp:"1970-01-01T00:00:00+0000"hash:"0000000000000000000000000000000000000000000000000000000000000000"
Use case: Snapshot testing with reproducible outputs.
Combine flags for optimal testing:
# Value only + canonical + deterministic
echo '(alice)' | gramref parse --format json --value-only --canonical --deterministicUse case: Most reliable equivalence checking.
Generate test patterns with specified complexity and count.
gramref generate --type suite --count 10 --format jsonGenerates 10 test cases in test suite format.
gramref generate --type suite --count 100 --seed 42 --format jsonSame seed = same test cases: Enables reproducible test generation.
Control the complexity of generated patterns:
# Minimal complexity
gramref generate --type suite --count 10 --complexity minimal --format json
# Basic complexity (default)
gramref generate --type suite --count 10 --complexity basic --format json
# Standard complexity
gramref generate --type suite --count 10 --complexity standard --format json
# Complex patterns
gramref generate --type suite --count 10 --complexity complex --format json
# Adversarial/edge cases
gramref generate --type suite --count 10 --complexity adversarial --format jsonComplexity levels:
| Level | Description | Use Case |
|---|---|---|
minimal |
Simple patterns (nodes, basic relationships) | Quick validation, debugging |
basic |
Common patterns | Standard testing |
standard |
Realistic patterns | Integration testing |
complex |
Nested structures, many properties | Stress testing |
adversarial |
Edge cases, boundary conditions | Robustness testing |
Generate test cases without metadata:
gramref generate --type suite --count 100 --seed 42 --format json --value-onlyUse case: Smaller test files, faster comparison.
gramref generate --type suite --count 100 --seed 42 --format json --value-only > test_cases.jsonGenerated test suites follow a standardized format:
{
"version": "1.0",
"test_cases": [
{
"name": "test_case_001",
"description": "...",
"input": {
"type": "gram_notation",
"value": "(alice:Person)"
},
"expected": {
"type": "pattern",
"value": {
"elements": [],
"value": {
"symbol": "alice",
"labels": ["Person"],
"properties": {}
}
}
},
"operations": null
}
]
}Fields:
name: Unique test case identifierdescription: Human-readable descriptioninput: Gram notation to parseexpected: Expected pattern structureoperations: Optional transformations (usuallynull)
| Flag | Description |
|---|---|
--format json |
Output in JSON format (default) |
--value-only |
Output only pattern value (no metadata) |
--canonical |
Sort JSON keys alphabetically |
--deterministic |
Use fixed timestamps and hashes |
| Flag | Description |
|---|---|
--type suite |
Generate test suite format |
--count N |
Number of test cases to generate |
--seed N |
Random seed for reproducible generation |
--complexity LEVEL |
Complexity: minimal, basic, standard, complex, adversarial |
Generate reference output to compare with gram-rs:
# Get reference from gramref
echo '(alice)-[:KNOWS]->(bob)' | gramref parse --format json --value-only --canonical > ref.json
# Get output from gram-rs (when CLI is implemented)
echo '(alice)-[:KNOWS]->(bob)' | cargo run --bin gram-rs parse --format json --value-only > rs.json
# Compare
diff ref.json rs.jsonCreate a large test suite for gram-rs:
# Generate test suite
gramref generate --type suite --count 100 --seed 42 --complexity standard \
--format json --value-only > tests/common/test_cases.json
# Validate format
cargo run --bin test-validator tests/common/test_cases.json
# Run equivalence tests
cargo test --test equivalenceGenerate deterministic snapshots for regression testing:
# Generate snapshot
echo '(alice:Person {name: "Alice"})' | gramref parse --format json --deterministic --canonical > snapshot.json
# Use in test (snapshot will never change)
cargo test --test snapshot_testsGenerate diverse patterns for property-based tests:
# Generate adversarial test cases
gramref generate --type suite --count 50 --complexity adversarial \
--format json --value-only > adversarial_tests.jsonuse std::process::Command;
use serde_json::Value;
pub fn get_gramref_reference(input: &str) -> Result<Value, String> {
let output = Command::new("gramref")
.args(&["parse", "--format", "json", "--value-only", "--canonical"])
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn()
.map_err(|e| format!("Failed to spawn gramref: {}", e))?;
// Write input to stdin
use std::io::Write;
if let Some(mut stdin) = output.stdin {
stdin.write_all(input.as_bytes())
.map_err(|e| format!("Failed to write to gramref: {}", e))?;
}
let result = output.wait_with_output()
.map_err(|e| format!("Failed to get gramref output: {}", e))?;
if !result.status.success() {
return Err(format!("gramref failed: {}", String::from_utf8_lossy(&result.stderr)));
}
serde_json::from_slice(&result.stdout)
.map_err(|e| format!("Failed to parse gramref JSON: {}", e))
}pub fn generate_test_suite(
count: usize,
seed: u64,
complexity: &str
) -> Result<Value, String> {
let output = Command::new("gramref")
.args(&[
"generate",
"--type", "suite",
"--count", &count.to_string(),
"--seed", &seed.to_string(),
"--complexity", complexity,
"--format", "json",
"--value-only",
])
.output()
.map_err(|e| format!("Failed to run gramref: {}", e))?;
if !output.status.success() {
return Err(format!("gramref generate failed: {}",
String::from_utf8_lossy(&output.stderr)));
}
serde_json::from_slice(&output.stdout)
.map_err(|e| format!("Failed to parse test suite JSON: {}", e))
}Goal: Verify gram-rs produces same results as reference implementation.
Approach:
- Parse with
gramref parse --value-only --canonical - Parse with
gram_codec::parse_gram_notation - Compare JSON outputs
Example:
echo '(alice)' | gramref parse --format json --value-only --canonical > ref.json
# Compare with gram-rs outputGoal: Generate comprehensive test suites from reference implementation.
Approach:
- Use
gramref generate --type suite - Specify count, seed, complexity
- Save to
tests/common/test_cases.json
Example:
gramref generate --type suite --count 100 --seed 42 --format json > test_cases.jsonGoal: Detect unintended behavior changes.
Approach:
- Use
--deterministicflag for reproducible outputs - Save as snapshot files
- Compare on each test run
Example:
echo '(alice)' | gramref parse --format json --deterministic > snapshot.jsonGoal: Test with diverse, automatically generated inputs.
Approach:
- Generate patterns at different complexity levels
- Use as inputs to property tests
- Verify invariants hold
Example:
gramref generate --type suite --count 1000 --complexity adversarial --format jsonEliminates metadata differences (timestamps, hashes).
# ✅ Good
gramref parse --format json --value-only
# ❌ Avoid (metadata changes on every run)
gramref parse --format jsonEnsures consistent key ordering.
gramref parse --format json --canonical --value-onlyMakes outputs reproducible.
gramref parse --format json --deterministic --canonicalSame seed = same test cases.
gramref generate --seed 42 --deterministic --format jsonEasier to debug issues.
gramref generate --complexity minimal --count 10 --format json# Check if in PATH
which gramref
# If not found, use full path
/Users/akollegger/.cabal/bin/gramref --help# Use --canonical to ensure consistent formatting
gramref parse --format json --canonical --value-only# Use both --deterministic and --seed together
gramref generate --seed 42 --deterministic --format json| Aspect | gramref | gram-lint |
|---|---|---|
| Purpose | Reference implementation | Syntax validation |
| Output | Pattern structures (JSON) | Parse errors, tree (s-expr) |
| Language | Haskell | Rust |
| Use case | Testing gram-rs | Pre-validation |
| Commands | parse, generate |
Validation only |
Workflow:
- Use
gram-lintfor syntax checks - Use
gramreffor reference outputs - Use
gram-codecfor actual parsing
- Parse speed: Fast for small patterns, moderate for large
- Generate speed: Depends on complexity level
minimal: Very fastadversarial: Slower (complex generation logic)
- JSON output: Can be large for deep nesting
Tip: Use --value-only to reduce output size.
- gramref Quick Reference - Command examples
- gramref CLI Testing Guide - Detailed testing guide
- gram-codec API - Programmatic parsing
- Gram Notation Syntax - Syntax reference
Last Updated: 2026-01-08