Target environment:
- RAD Studio / Delphi 23.0
- Win64
- DUnitX from RAD Studio or a separate DUnitX checkout
- CRLF Delphi source files
Standard Release test run:
scripts\run-pattern-tests.bat
Debug test run with range and overflow checks:
scripts\run-pattern-tests.bat Debug
Full Release stress run:
scripts\run-pattern-stress-full.bat Release
Reproduce a full stress run with a fixed seed:
scripts\run-pattern-stress-full.bat Release --seed=D1B54A32D192ED03
Full test and benchmark run:
scripts\run-pattern-all.bat Release full
CI-style Debug plus full Release plus full benchmark:
scripts\run-pattern-ci.bat
Every runner exits non-zero on the first failed build or test.
scripts\build-pattern-suite.bat invokes dcc64 directly. It deletes the selected configuration's DCU directory before each suite build and uses -B, so stale units cannot satisfy a test build.
Debug uses:
-$O- -$D+ -$L+ -$R+ -$Q+
Release uses:
-$O+ -$D- -$L- -$R- -$Q-
Outputs are separated by configuration:
bin\Win64\Debug
bin\Win64\Release
dcu\Win64\Debug
dcu\Win64\Release
If dcc64.exe is not on PATH, run from a RAD Studio command prompt or let the script load the default Delphi 23.0 rsvars.bat.
Project:
tests\dunitx\PatternSearchDUnitX.dpr
The suite contains 100 fixed contract tests. They assert concrete offsets, match lengths, edit distances, pattern indexes, units, exception behavior and dispatcher types.
Coverage includes:
TPatternMatch.NotFound- signature parsing and malformed input
- public dynamic-array immutability
- input-array copy semantics
- exact expected offsets and overlapping matches
StartOffset- 1, 64 and 65 byte bit-algorithm boundaries
- long periodic Two-Way patterns
- UTF-16 code-unit offsets, surrogate pairs and embedded
#0 - byte, nibble, full and arbitrary bit masks
- Levenshtein substitution, insertion and deletion
- Myers substitution, insertion and deletion
- one-best-match-per-start fuzzy semantics
- zero-distance fuzzy/exact equivalence
- Aho-Corasick and Commentz-Walter expected pattern indexes
- duplicate, prefix and suffix multi-patterns
- copied multi-pattern input ownership for both engines
- exact, masked, fuzzy and multi-pattern chunk-boundary searches
- fuzzy candidate improvement across a 64 KiB boundary
- sorted fuzzy
FindAllresults when an earlier start becomes valid only after the next stream chunk - stream current-position and
PreservePositioncontracts - no duplicate boundary matches
- nil and empty streams
- automatic exact thresholds at 64, 65, 256 and 257 bytes
- automatic fuzzy and multi-pattern selection
- explicit algorithm selection
- invalid
MaxDistancecombinations - AVX2/scalar equivalence when AVX2 is available
NUnit-compatible XML is written on every DUnitX run to:
test-results\PatternSearchDUnitX-<Config>.xml
Override the path with NATIVEPE_DUNITX_XML.
If DUnitX is not on the Delphi library path:
set DUNITX_PATH=C:\path\to\DUnitX\Source
The build also creates:
TestPatternSearch.exe
TestPatternSearchRandom.exe
TestPatternSearchStress.exe
TestPatternSearch.exe holds compact deterministic regressions.
TestPatternSearchRandom.exe performs reproducible differential tests against simple reference search implementations.
TestPatternSearchStress.exe is the large differential suite. It uses a deterministic xorshift sequence and reports the initial seed and current state on failure.
Reproduce a sequence with:
TestPatternSearchStress.exe --full --seed=D1B54A32D192ED03
Standard run:
Exact byte: 10000
Masked byte: 6000
Fuzzy byte: 1500
Multi-pattern: 3000
Exact string: 3000
Fuzzy string: 500
Exact stream: 500
Masked stream: 250
Multi-pattern stream: 200
Full run:
Exact byte: 50000
Masked byte: 30000
Fuzzy byte: 8000
Multi-pattern: 15000
Exact string: 15000
Fuzzy string: 2500
Exact stream: 2500
Masked stream: 1200
Multi-pattern stream: 1000
A fixed fuzzy-stream regression runs in addition to those counts.
Exact byte stress deliberately includes pattern lengths:
1 2 3 7 8 15 16 31 32 63 64 65 127 255 256 257
Random exact cases also extend to 320 bytes and use both low-entropy and full-byte alphabets.
Masked cases use masks including:
FF F0 0F 00 3C C3
String stress includes ASCII, #0 and non-ASCII UTF-16 code units.
Exact implementations are checked against naive byte/string scanning:
Boyer-Moore-Horspool
Bitap
SBNDM
Rabin-Karp
Two-Way
AVX2 when available
Auto dispatcher
Masked implementations are checked against per-byte mask comparison:
Bitap
SBNDM
Fuzzy implementations are checked against independent full dynamic-programming edit distance over every admissible substring:
Levenshtein
Myers Bit-Vector
Multi-pattern implementations are checked against naive search of every pattern:
Aho-Corasick
Commentz-Walter
The optimized algorithm is never used as its own differential oracle.
Quick benchmark:
scripts\run-pattern-benchmark.bat Release
Full benchmark:
scripts\run-pattern-benchmark.bat Release full
CSV output is separated by configuration and mode:
test-results\pattern-benchmark-Release-quick.csv
test-results\pattern-benchmark-Release-full.csv
Columns:
category;algorithm;data_bytes;pattern_length;pattern_count;iterations;elapsed_ms;ns_per_op;mb_per_s;checksum
Scan scenarios include:
- exact patterns at 4, 8, 16, 32, 64, 128, 300 and 1024 bytes
- guaranteed no-match cases
- sparse
FindAllthroughput - masked patterns at 16, 32 and 64 bytes
- fuzzy patterns at 8, 16, 32 and 64 positions
- multi-pattern
FindFirstsets with 4, 16, 64 and 256 patterns - multi-pattern
FindAllthroughput with 16 and 64 patterns - stream scanning at 16, 64 and 300 bytes
- automatic dispatcher paths
- AVX2 when available
Preprocessing is measured separately in the Compile category for exact searchers and CompileMulti for Aho-Corasick, Commentz-Walter and the automatic multi-pattern dispatcher. Scan throughput constructs the searcher before timing, matching the compile-once/search-many design.
Before timed loops, the benchmark validates results. Exact and masked searches use naive reference results. Fuzzy engines are cross-checked against the Levenshtein contract already covered independently by the stress suite. Multi-pattern engines are required to agree before measurement. Stream benchmarks validate the exact expected offset.
Every timed loop contributes to a checksum so result paths cannot be optimized away accidentally and CSV runs can be compared for consistency.