Skip to content

Test Plan

Stephan Zehrer edited this page Jun 28, 2026 · 12 revisions

Test Plan

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.

Verification methods

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.

1. String Store (implemented — v1)

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.

2. Node Store (implemented — v1)

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

3. Graph model

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.

4. Property Store (implemented — v1)

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)

4c. Graph API (implemented — v1)

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

4a. Index (implemented — v1)

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)

5. Persistent Layer — additional coverage

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.

6. Value types

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.

5. Non-functional

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.

Running the suite

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).

Clone this wiki locally