From d19f9ddb866ac2415cbfe66966897a8efe8ddb63 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Fri, 16 Oct 2026 20:53:55 +0800 Subject: test(compiler): add seeded C++ differential tests across seven groups Generate 10000 random records per group plus boundary inputs using a portable SHA-256 stream. Compare native and runner output independently. Co-Authored-By: Claude Fable 5.1 --- tests/ii/strings/case.json | 1 + tests/ii/strings/generate.pl | 23 +++++++++++++++++++++++ tests/ii/strings/notes.md | 5 +++++ tests/ii/strings/program.cps | 17 +++++++++++++++++ tests/ii/strings/reference.cc | 20 ++++++++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 tests/ii/strings/case.json create mode 100644 tests/ii/strings/generate.pl create mode 100644 tests/ii/strings/notes.md create mode 100644 tests/ii/strings/program.cps create mode 100644 tests/ii/strings/reference.cc (limited to 'tests/ii/strings') diff --git a/tests/ii/strings/case.json b/tests/ii/strings/case.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/ii/strings/case.json @@ -0,0 +1 @@ +{} diff --git a/tests/ii/strings/generate.pl b/tests/ii/strings/generate.pl new file mode 100644 index 0000000..f3ac098 --- /dev/null +++ b/tests/ii/strings/generate.pl @@ -0,0 +1,23 @@ +use strict; +use warnings; +use FindBin; +use lib "$FindBin::Bin/.."; +use Random; +my ($seed, $count) = @ARGV; +my $rng = Random->new($seed, "strings"); +my @edges = ( + '1 placeholder 1 0', + '0 A 1 1', + '0 Ab09 4 1', + '0 Ab09 1 4', + '0 Ab09 2 0', +); +$rng->emit($count, \@edges, sub { +my $size = $rng->integer(0,24); +return '1 placeholder 1 0' if $size == 0; +my @alphabet = split //, 'ABCXYZabcxyz019@_-'; +my $text = join '', map { $alphabet[$rng->integer(0,$#alphabet)] } 1 .. $size; +my $start = $rng->integer(1,$size); +my $width = $rng->integer(0,$size-$start+1); +return "0 $text $start $width"; +}); diff --git a/tests/ii/strings/notes.md b/tests/ii/strings/notes.md new file mode 100644 index 0000000..01ea90a --- /dev/null +++ b/tests/ii/strings/notes.md @@ -0,0 +1,5 @@ +# strings + +CIE pp. 16-17 for LENGTH/MID/RIGHT/concatenation; full-STRING LCASE/UCASE is a project extension. Inputs are ASCII under the default C locale. Empty input is encoded with a flag because project INPUT reads tokens. Substrings remain in range; zero width is a documented project boundary. + +Each record produces exactly one output line. Random records are preceded by fixed boundary records; every arithmetic intermediate is bounded. diff --git a/tests/ii/strings/program.cps b/tests/ii/strings/program.cps new file mode 100644 index 0000000..55e7541 --- /dev/null +++ b/tests/ii/strings/program.cps @@ -0,0 +1,17 @@ +DECLARE Count : INTEGER +DECLARE Index : INTEGER +DECLARE Empty : INTEGER +DECLARE Text : STRING +DECLARE Start : INTEGER +DECLARE Width : INTEGER +INPUT Count +FOR Index <- 1 TO Count + INPUT Empty + INPUT Text + INPUT Start + INPUT Width + IF Empty = 1 THEN + Text <- "" + ENDIF + OUTPUT LENGTH(Text), ":", MID(Text, Start, Width), ":", RIGHT(Text, Width), ":", Text = ("" & Text), ":", LCASE(Text), ":", UCASE(Text) +NEXT Index diff --git a/tests/ii/strings/reference.cc b/tests/ii/strings/reference.cc new file mode 100644 index 0000000..54d6efc --- /dev/null +++ b/tests/ii/strings/reference.cc @@ -0,0 +1,20 @@ +#include +#include +#include +#include +int main() { + int count; + if (!(std::cin >> count)) return 1; + for (int i = 0; i < count; ++i) { + int empty, start, width; + std::string text; + if (!(std::cin >> empty >> text >> start >> width)) return 1; + if (empty) text.clear(); + auto lower = text, upper = text; + for (auto &c : lower) c = static_cast(std::tolower(static_cast(c))); + for (auto &c : upper) c = static_cast(std::toupper(static_cast(c))); + auto mid = text.substr(static_cast(start - 1), static_cast(width)); + auto right = text.substr(text.size() - static_cast(width)); + std::cout << text.size() << ':' << mid << ':' << right << ":TRUE:" << lower << ':' << upper << '\n'; + } +} -- cgit v1.3.1-4-g156e