Repository navigation
Test Plan
Stephan Zehrer edited this page Jun 28, 2026
·
12 revisions
This page traces every numbered requirement on the Requirements page to a verification method. A requirement is considered verified only when its method is implemented and passing.
| Method | Meaning |
|---|---|
| UT | Automated unit test (#[cfg(test)], run by cargo test). |
| Gate | Enforced by a tooling gate (cargo clippy, cargo build, review). |
| Design | Verified by design review only; no code yet. |
| Inspection | Verified by reading the source / on-disk artifact. |
The String Store ships with 7 unit tests in
src/string_store.rs.
| Test | What it covers | Requirements |
|---|---|---|
intern_dedups_and_assigns_sequential_ids |
Dedup; identical content stored once; sequential StrIds; distinct hashes. |
REQ-10, REQ-11, REQ-12 |
resolve_by_id_and_hash |
resolve_id, resolve_hash, id_of, hash_of agree for one string. |
REQ-11, REQ-12, REQ-19 |
missing_lookups_return_none |
Unknown id/hash lookups return None (no panics, no false hits). |
REQ-19 |
empty_and_unicode_strings |
Empty string and multi-byte Unicode round-trip exactly. | REQ-14, REQ-17 |
roundtrip_save_open |
Save then re-open a single segment; dedup and hash identity survive. | REQ-13, REQ-14, REQ-16, REQ-17 |
multi_block_roundtrip |
500 strings across many ~64-byte blocks round-trip in order. | REQ-15, REQ-16 |
open_rejects_corrupt_magic |
A corrupted header magic is rejected with an error. | REQ-18 |
roundtrip_lz4 |
Save with LZ4 compression, re-open, all strings resolve correctly. | REQ-20 |
roundtrip_zstd |
Save with Zstd compression, re-open, all strings resolve correctly. | REQ-20 |
Additional String Store coverage:
| Requirement | Method | Notes |
|---|---|---|
| REQ-13 (append-only) | Inspection | In-RAM model never mutates stored entries; save rewrites a fresh segment via temp + rename. |
| REQ-17 (CRC + UTF-8 on open) | UT (roundtrip_*) + Inspection |
open re-checks every entry's CRC32 and UTF-8 validity. |
| REQ-20 (block compression) | UT (roundtrip_lz4, roundtrip_zstd) + Bench |
LZ4 and Zstd algorithms implemented; compression ratio measured in benches/string_store.rs. |
| REQ-21 (Bloom filter) | Design | Footer flags reserve the signalling bit; not yet built. |
| REQ-22 (long-value routing) | UT (long_string_routes_to_string_store) |
Graph::set_str routes strings > 14 bytes into the String Store. |
| REQ-23 (incremental append) | Design | v1 rewrites the whole segment. |
| REQ-24 (lazy decompression) | Design (Planned) | Blocks currently fully decompressed on open; on-demand per-entry decompression is a future architectural change. |
| REQ-25 (FSST) | Design (Planned) | Depends on REQ-24 and a production-ready Arrow-free Rust crate. |
The Node Store ships with 10 unit tests in src/node_store.rs.
| Test | What it covers | Requirements |
|---|---|---|
create_assigns_sequential_ids |
IDs are sequential from 0; len and live_count track correctly. |
REQ-30, REQ-31 |
create_typed |
create_typed sets type_id; first_out defaults to NO_ID. |
REQ-33 |
get_out_of_range_returns_none |
No panic or wrong data for unknown IDs. | REQ-30 |
update_record |
update overwrites in place; out-of-range returns false. |
REQ-30 |
tombstone_sets_dead_flag |
tombstone sets DEAD; live_count decrements; len unchanged. |
REQ-33 |
flags_set_clear_subtype |
set, clear, with_subtype work independently. |
REQ-33 |
roundtrip_save_open |
Full serialize + deserialize; flags, type_id, first_out all survive. | REQ-30, REQ-32 |
open_rejects_corrupt_header_magic |
Bad header magic → error. | REQ-18 (same principle) |
open_rejects_corrupt_record_crc |
Flipped byte in record region → CRC error on open. | REQ-17 (same principle) |
no_id_sentinel_never_allocated |
NO_ID = NodeId::MAX; normal create() never returns it. |
REQ-31 |
| Requirement | Method | Notes |
|---|---|---|
| REQ-01 | Design | Node/Edge/Property model — see General Concepts. |
| REQ-02 | Design | "Everything is a node." |
| REQ-03 | Design | Compact integer ID addressing. |
| REQ-04 | Design | Optional type reference to a class node. |
The Property Store ships with 15 unit tests in src/prop_store.rs.
| Test | What it covers | Requirements |
|---|---|---|
encode_decode_edge |
Edge record encodes end_node and round-trips. |
REQ-34, REQ-35 |
encode_decode_none |
Null/absent value round-trips. | REQ-36 |
encode_decode_bool |
Bool true/false round-trips. | REQ-41 |
encode_decode_i64 |
i64 edge cases (0, ±1, MIN, MAX) round-trip. | REQ-41 |
encode_decode_f64 |
f64 values including PI and extremes round-trip. | REQ-41 |
encode_decode_temporal |
Date, Time, DateTime, Duration round-trip. | REQ-42 |
encode_decode_ref_types |
All StrId-referenced types (I128Ref, F128Ref, Uuid, Hash, Geo, StringRef, UrlRef) round-trip. | REQ-37, REQ-43, REQ-44 |
key_round_trips_and_is_independent_of_value |
The record key survives encode/decode and doesn't disturb the value; unkeyed defaults to NO_KEY. |
REQ-66 |
keyed_edge_carries_predicate_and_end_node |
An edge record carries both predicate (key) and end node. | REQ-66 |
encode_decode_inline_str |
Short strings (including Unicode) stored inline round-trip. | REQ-40 |
inline_str_too_long_returns_error |
InlineStr > 10 bytes returns an error, not a panic. | REQ-40 |
create_and_get |
Sequential PropIds; out-of-range returns None. | REQ-34 |
update_record |
In-place overwrite; out-of-range returns false. | REQ-34 |
roundtrip_save_open |
Full serialize + deserialize; all value types survive. | REQ-34, REQ-36 |
open_rejects_corrupt_header_magic |
Bad header magic → error. | REQ-18 (same principle) |
open_rejects_corrupt_record_crc |
Flipped byte in record region → CRC error. | REQ-17 (same principle) |
The Graph API ships with 21 unit tests in src/graph.rs.
| Test | What it covers | Requirements |
|---|---|---|
build_a_small_graph |
Nodes, typed nodes, keyed properties, labelled edges; degree, out_edges, get_property/get_str/edges_of_type. | REQ-01, REQ-02, REQ-60, REQ-61, REQ-62, REQ-66 |
edges_of_type_filters_by_predicate |
edges_of_type returns only edges with the given predicate; out_edges is unfiltered. |
REQ-66 |
find_by_property_and_key |
find_by_property matches exact values; find_by_key lists nodes having the key; ascending order, deduped. |
REQ-67 |
find_by_str_matches_across_storage |
find_by_str matches whether the string is inline or in the String Store. |
REQ-67 |
find_skips_deleted_nodes_and_keys |
A different key doesn't match; deleted nodes drop out of results. | REQ-67 |
from_edge_list_parses_and_remaps |
Sparse ids + comments/blank lines parse; ids remap to contiguous nodes in first-seen order. | REQ-68 |
from_edge_list_undirected_is_symmetric |
Both-direction edge lists load as a symmetric directed graph. | REQ-68 |
from_edge_list_rejects_malformed |
Non-numeric / single-column data lines are rejected with an error. | REQ-68 |
long_string_routes_to_string_store |
set_str keeps ≤14 bytes inline, routes longer strings to a StringRef; both resolve back. |
REQ-22, REQ-37, REQ-62 |
edge_sets_in_out_flags |
add_edge sets HAS_OUT on the start and HAS_IN on the end. |
REQ-61 |
operations_on_unknown_node_error |
Out-of-range nodes are rejected with an error, not a panic. | REQ-60 |
build_index_matches_adjacency |
Exported CSR index matches the live adjacency. | REQ-38, REQ-60 |
save_open_roundtrip |
Persist all four segments and reload; degree, edges, strings survive. | REQ-63 |
incoming_edges_track_sources |
in_edges/in_neighbors/in_degree return sources in add order; out_degree counts edges. |
REQ-64 |
in_edges_of_unknown_node_is_empty |
Out-of-range nodes yield empty incoming results, no panic. | REQ-64 |
out_degree_counts_edges_not_properties |
out_degree counts only edges; degree counts all records. |
REQ-62, REQ-64 |
incoming_survives_save_open |
Reverse adjacency is rebuilt on load, sources in insertion order. | REQ-63, REQ-64 |
delete_node_detaches_both_directions |
Deleting a node removes its in/out edges from peers; degrees update. | REQ-65 |
delete_node_is_idempotent_and_guards_writes |
Re-delete / unknown → false; writes to a deleted node error. | REQ-65 |
delete_node_handles_self_loop |
A self-loop edge is cleaned without leaving a stale entry. | REQ-65 |
deletion_survives_save_open |
Tombstone + detachment persist; reloaded peers show no dangling edges. | REQ-63, REQ-65 |
The Index ships with 7 unit tests in src/index_store.rs.
| Test | What it covers | Requirements |
|---|---|---|
build_groups_records_by_owner |
CSR groups records per owner; add order preserved; gaps (nodes with no records) handled. | REQ-38 |
unknown_node_returns_empty |
Out-of-range / record-less nodes return an empty slice; degree is 0. |
REQ-38 |
empty_graph |
A zero-node build yields a valid empty index. | REQ-38 |
owner_out_of_range_is_error |
An association with owner >= node_count is rejected. |
REQ-38 |
roundtrip_save_open |
Full serialize + deserialize; all neighbour slices survive. | REQ-38 |
open_rejects_corrupt_header_magic |
Bad header magic → error. | REQ-18 (same principle) |
open_rejects_corrupt_body_crc |
Flipped byte in offsets/neighbors region → CRC error. | REQ-17 (same principle) |
| Requirement | Method | Notes |
|---|---|---|
| REQ-30 | UT (Node Store + Prop Store roundtrip tests) | Fixed-length records; direct access by ID verified. |
| REQ-31 | UT + Inspection |
NodeId = u32, PropId = u32; NO_ID/NO_PROP sentinels never allocated by normal create(). |
| REQ-32 | UT (roundtrip_save_open in node_store) |
Option 2 (dedicated node file) implemented and tested. |
| REQ-33 | UT (tombstone_sets_dead_flag, flags_set_clear_subtype) |
Node flags verified. |
| REQ-34 | UT (prop_store roundtrip tests) | 16-byte shared record verified. |
| REQ-35 | UT (encode_decode_edge) |
Edge record carries end_node; start node is the owning node. |
| REQ-36 | UT (encode/decode tests covering all 17 PropTypes) | 16-byte buffer covers all implemented value types. |
| REQ-37 | UT (encode_decode_ref_types) |
Values > 14 bytes stored in String Store; StrId round-trips. |
| REQ-38 | UT (index_store tests) | CSR adjacency; neighbors/degree/save/open verified. |
| Requirement | Method | Notes |
|---|---|---|
| REQ-40 | UT (encode_decode_inline_str, inline_str_too_long_returns_error) |
Inline ≤14 bytes; overflow error (not panic). |
| REQ-41 | UT (encode_decode_bool, encode_decode_i64, encode_decode_f64) |
Bool, i64, f64 all verified. i128 via StrId ref (I128Ref/F128Ref). |
| REQ-42 | UT (encode_decode_temporal) |
Date, Time, DateTime, Duration verified. |
| REQ-43 | UT (encode_decode_ref_types) |
UUID, Hash, Geo all round-trip via StrId. |
| REQ-44 | UT (encode_decode_ref_types) |
UrlRef round-trips via StrId. |
| REQ-45 | Design (Planned) | VECTOR via optional vector store. |
| REQ-46 | UT (all encode/decode tests) | PropType discriminant in byte 0 of every record. |
| Requirement | Method | Notes |
|---|---|---|
| REQ-50 | Design | Minimal, embeddable footprint. |
REQ-51 (no unsafe) |
Gate (review) | No unsafe in our own crates. |
| REQ-52 (zero warnings) | Gate |
cargo clippy --all-targets -- -D warnings and cargo build clean. |
| REQ-53 (little-endian) | Inspection + UT | All on-disk integers written little-endian; round-trip tests confirm. |
| REQ-54 (MIT) | Inspection |
LICENSE file. |
| REQ-55 (ACID) | N/A | Explicitly out of scope for now. |
cargo test # unit + doc tests (63 tests)
cargo clippy --all-targets -- -D warnings # lint gate (zero warnings)
cargo build # zero compiler warnings
cargo bench --bench string_store # intern / resolve / save / open / compression
cargo bench --bench graph # build / traverse / find / index / persist
cargo bench --bench graph -- graph_realworld # real ca-HepTh graph (needs benches/data/ca-HepTh.txt)
cargo bench -- compression_ratio # compression ratio table (LZ4 vs Zstd vs none)
The graph_realworld group needs a dataset that is not committed; see
benches/data/README.md for the one-line download (it is skipped if absent).
(c) Stephan Zehrer (2025)
Planning & process
Design & architecture
Scratch