Remove the boost test runner#38
Open
rustaceanrob wants to merge 6 commits into
Open
Conversation
896e74d to
742edb9
Compare
3367419 to
c807d70
Compare
-BEGIN VERIFY SCRIPT-
set -eu
MACRO_RE='BOOST_CHECK|BOOST_REQUIRE|BOOST_CHECK_MESSAGE|BOOST_REQUIRE_MESSAGE|BOOST_CHECK_NO_THROW|BOOST_REQUIRE_NO_THROW'
FILES=$(git grep -lE "\b(${MACRO_RE})[[:space:]]*\(" -- \
':(glob)src/test/**/*.cpp' ':(glob)src/test/**/*.h' \
':(glob)src/test/*.cpp' ':(glob)src/test/*.h' \
':(glob)src/ipc/test/**/*.cpp' ':(glob)src/ipc/test/**/*.h' \
':(glob)src/ipc/test/*.cpp' ':(glob)src/ipc/test/*.h' 2>/dev/null || true)
if [ -z "$FILES" ]; then
echo "no matching files"
exit 0
fi
perl -i -0777 -pe '
use strict;
use warnings;
my $names = "BOOST_CHECK|BOOST_REQUIRE|BOOST_CHECK_MESSAGE|BOOST_REQUIRE_MESSAGE|BOOST_CHECK_NO_THROW|BOOST_REQUIRE_NO_THROW";
my $re = qr/\b($names)\s*\(/;
my @DIGIT_SEP_PREV = (0) x 256;
$DIGIT_SEP_PREV[ord($_)] = 1 for split //, "0123456789abcdefABCDEF" . chr(39);
sub is_char_open {
my ($s, $i) = @_;
return 1 if $i == 0;
return $DIGIT_SEP_PREV[ord(substr($$s, $i-1, 1))] ? 0 : 1;
}
sub close_paren {
my ($s, $open) = @_;
my ($depth, $i, $in_str, $in_char) = (0, $open, 0, 0);
my $n = length($$s);
while ($i < $n) {
my $c = substr($$s, $i, 1);
if ($in_str) {
if ($c eq "\\") { $i += 2; next; }
$in_str = 0 if $c eq q{"};
} elsif ($in_char) {
if ($c eq "\\") { $i += 2; next; }
$in_char = 0 if $c eq chr(39);
} elsif ($c eq q{"}) { $in_str = 1; }
elsif ($c eq chr(39) && is_char_open($s, $i)) { $in_char = 1; }
elsif ($c =~ /[(\[{]/) { $depth++; }
elsif ($c =~ /[)\]}]/) { $depth--; return $i if $depth == 0; }
$i++;
}
return -1;
}
sub split_first_comma {
my ($s) = @_;
my ($depth, $i, $in_str, $in_char) = (0, 0, 0, 0);
my $n = length($s);
while ($i < $n) {
my $c = substr($s, $i, 1);
if ($in_str) {
if ($c eq "\\") { $i += 2; next; }
$in_str = 0 if $c eq q{"};
} elsif ($in_char) {
if ($c eq "\\") { $i += 2; next; }
$in_char = 0 if $c eq chr(39);
} elsif ($c eq q{"}) { $in_str = 1; }
elsif ($c eq chr(39) && is_char_open(\$s, $i)) { $in_char = 1; }
elsif ($c =~ /[(\[{]/) { $depth++; }
elsif ($c =~ /[)\]}]/) { $depth--; }
elsif ($c eq "," && $depth == 0) {
return (substr($s, 0, $i), substr($s, $i));
}
$i++;
}
return ($s, "");
}
sub top_level_and_positions {
my ($e) = @_;
my @ops;
my ($depth, $i, $in_str, $in_char) = (0, 0, 0, 0);
my $n = length($e);
while ($i < $n) {
my $c = substr($e, $i, 1);
if ($in_str) {
if ($c eq "\\") { $i += 2; next; }
$in_str = 0 if $c eq q{"};
$i++; next;
} elsif ($in_char) {
if ($c eq "\\") { $i += 2; next; }
$in_char = 0 if $c eq chr(39);
$i++; next;
}
if ($c eq q{"}) { $in_str = 1; $i++; next; }
if ($c eq chr(39) && is_char_open(\$e, $i)) { $in_char = 1; $i++; next; }
if ($c =~ /[(\[{]/) { $depth++; $i++; next; }
if ($c =~ /[)\]}]/) { $depth--; $i++; next; }
if ($depth == 0 && $i + 1 < $n && substr($e, $i, 2) eq "&&") {
push @ops, $i;
$i += 2; next;
}
$i++;
}
return @ops;
}
my $text = $_;
my $out = "";
my $cur = 0;
while ($text =~ /$re/g) {
my $macro = $1;
my $m_start = $-[0];
my $p_open = $+[0] - 1;
my $p_close = close_paren(\$text, $p_open);
next if $p_close < 0;
my $args = substr($text, $p_open + 1, $p_close - $p_open - 1);
my ($expr_raw, $message) = split_first_comma($args);
my $expr = $expr_raw;
$expr =~ s/^\s+//;
$expr =~ s/\s+$//;
my @ats = top_level_and_positions($expr);
next unless @ats;
# Compose the replacement with original indentation.
my $line_start = rindex(substr($text, 0, $m_start), "\n") + 1;
my $indent = substr($text, $line_start, $m_start - $line_start);
$indent =~ s/[^\s].*//s;
my @Parts;
my $last = 0;
for my $p (@ats) {
my $piece = substr($expr, $last, $p - $last);
$piece =~ s/^\s+//; $piece =~ s/\s+$//;
push @Parts, $piece;
$last = $p + 2;
}
my $tail = substr($expr, $last);
$tail =~ s/^\s+//; $tail =~ s/\s+$//;
push @Parts, $tail;
my $sep = ";\n" . $indent;
my $replacement = join($sep, map { "$macro($_$message)" } @Parts);
$out .= substr($text, $cur, $m_start - $cur);
$out .= $replacement;
$cur = $p_close + 1;
# Resume the global match where the new content ends.
pos($text) = $cur;
}
$out .= substr($text, $cur);
$_ = $out;
' -- $FILES
-END VERIFY SCRIPT-
-BEGIN VERIFY SCRIPT-
set -eu
MACRO_RE='BOOST_CHECK|BOOST_REQUIRE|BOOST_CHECK_MESSAGE|BOOST_REQUIRE_MESSAGE|BOOST_CHECK_NO_THROW|BOOST_REQUIRE_NO_THROW'
FILES=$(git grep -lE "\b(${MACRO_RE})[[:space:]]*\(" -- \
':(glob)src/test/**/*.cpp' ':(glob)src/test/**/*.h' \
':(glob)src/test/*.cpp' ':(glob)src/test/*.h' \
':(glob)src/ipc/test/**/*.cpp' ':(glob)src/ipc/test/**/*.h' \
':(glob)src/ipc/test/*.cpp' ':(glob)src/ipc/test/*.h' 2>/dev/null || true)
if [ -z "$FILES" ]; then
echo "no matching files"
exit 0
fi
perl -i -0777 -pe '
use strict;
use warnings;
my $names = "BOOST_CHECK|BOOST_REQUIRE|BOOST_CHECK_MESSAGE|BOOST_REQUIRE_MESSAGE|BOOST_CHECK_NO_THROW|BOOST_REQUIRE_NO_THROW";
my $re = qr/\b($names)\s*\(/;
my @DIGIT_SEP_PREV = (0) x 256;
$DIGIT_SEP_PREV[ord($_)] = 1 for split //, "0123456789abcdefABCDEF" . chr(39);
sub is_char_open {
my ($s, $i) = @_;
return 1 if $i == 0;
return $DIGIT_SEP_PREV[ord(substr($$s, $i-1, 1))] ? 0 : 1;
}
sub close_paren {
my ($s, $open) = @_;
my ($depth, $i, $in_str, $in_char) = (0, $open, 0, 0);
my $n = length($$s);
while ($i < $n) {
my $c = substr($$s, $i, 1);
if ($in_str) {
if ($c eq "\\") { $i += 2; next; }
$in_str = 0 if $c eq q{"};
} elsif ($in_char) {
if ($c eq "\\") { $i += 2; next; }
$in_char = 0 if $c eq chr(39);
} elsif ($c eq q{"}) { $in_str = 1; }
elsif ($c eq chr(39) && is_char_open($s, $i)) { $in_char = 1; }
elsif ($c =~ /[(\[{]/) { $depth++; }
elsif ($c =~ /[)\]}]/) { $depth--; return $i if $depth == 0; }
$i++;
}
return -1;
}
sub split_first_comma {
my ($s) = @_;
my ($depth, $i, $in_str, $in_char) = (0, 0, 0, 0);
my $n = length($s);
while ($i < $n) {
my $c = substr($s, $i, 1);
if ($in_str) {
if ($c eq "\\") { $i += 2; next; }
$in_str = 0 if $c eq q{"};
} elsif ($in_char) {
if ($c eq "\\") { $i += 2; next; }
$in_char = 0 if $c eq chr(39);
} elsif ($c eq q{"}) { $in_str = 1; }
elsif ($c eq chr(39) && is_char_open(\$s, $i)) { $in_char = 1; }
elsif ($c =~ /[(\[{]/) { $depth++; }
elsif ($c =~ /[)\]}]/) { $depth--; }
elsif ($c eq "," && $depth == 0) {
return (substr($s, 0, $i), substr($s, $i));
}
$i++;
}
return ($s, "");
}
sub has_top_level_or {
my ($e) = @_;
my ($depth, $i, $in_str, $in_char) = (0, 0, 0, 0);
my $n = length($e);
while ($i < $n) {
my $c = substr($e, $i, 1);
if ($in_str) {
if ($c eq "\\") { $i += 2; next; }
$in_str = 0 if $c eq q{"};
$i++; next;
} elsif ($in_char) {
if ($c eq "\\") { $i += 2; next; }
$in_char = 0 if $c eq chr(39);
$i++; next;
}
if ($c eq q{"}) { $in_str = 1; $i++; next; }
if ($c eq chr(39) && is_char_open(\$e, $i)) { $in_char = 1; $i++; next; }
if ($c =~ /[(\[{]/) { $depth++; $i++; next; }
if ($c =~ /[)\]}]/) { $depth--; $i++; next; }
if ($depth == 0 && $i + 1 < $n && substr($e, $i, 2) eq "||") {
return 1;
}
$i++;
}
return 0;
}
my $text = $_;
my $out = "";
my $cur = 0;
while ($text =~ /$re/g) {
my $macro = $1;
my $m_start = $-[0];
my $p_open = $+[0] - 1;
my $p_close = close_paren(\$text, $p_open);
next if $p_close < 0;
my $args = substr($text, $p_open + 1, $p_close - $p_open - 1);
my ($expr_raw, $message) = split_first_comma($args);
my $expr = $expr_raw;
$expr =~ s/^\s+//;
$expr =~ s/\s+$//;
next unless has_top_level_or($expr);
$out .= substr($text, $cur, $m_start - $cur);
$out .= "$macro(($expr)$message)";
$cur = $p_close + 1;
pos($text) = $cur;
}
$out .= substr($text, $cur);
$_ = $out;
' -- $FILES
-END VERIFY SCRIPT-
270a034 to
ef29ae0
Compare
e780299 to
ae72cf9
Compare
Member
|
Concept ACK, nice work
|
ae72cf9 to
ff95d8c
Compare
josibake
reviewed
Jun 8, 2026
josibake
left a comment
Member
There was a problem hiding this comment.
Concept ACK
Overall, looking great! Did some testing and uncovered a lil bug, will continue reading through the code tomorrow. There are also some stale document comments , not a priority but something to fix before the final pass.
| std::string_view arg = argv[i]; | ||
| if (arg == "--") { | ||
| for (int j{i + 1}; j < argc; ++j) { | ||
| opts.passthrough.emplace_back(argv[j]); |
Member
There was a problem hiding this comment.
I don't think this is being used. I ran some old justfile commands I had laying around and testdatadir wasn't used, but the tests ran. I suspect this is because test/main.cpp reads framework::user_args() but I don't see opts.passthrough being copied in.
Member
Author
ff95d8c to
ccf607f
Compare
Adds src/test/util/framework.hpp as a lightweight Boost.Test replacement. This commit only introduces the header; build-system integration and call-site migration follow in subsequent commits. Includes: - `CHECK`, valid with any comparison operator, optional message - `REQUIRE`, valid with any comparison operator, optional message - `CHECK_EQUAL_RANGES`, better debugging for vectors - `THROW_*`, macros for checking throwing conditions - Info and warn messages
Integrates src/test/util/framework.hpp into the build (CMake, main.cpp) and replaces the Boost.Test macros across the unit test suite via a scripted diff.
ccf607f to
77bf05d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the
boosttest runner with a simple header-only variant. Simplifies the macros to the following:CHECK, valid with any comparison operator (e.g.==,!=), optional messageREQUIRE, valid with any comparison operator, optional messageCHECK_EQUAL_RANGES, better debugging for vectorsTHROW_*, macros for checking throwing conditionsThis framework has 4 log levels, offers test filtering, and also includes suites and fixtures. The runner executes in approximately the same time as boost, and should compile faster as well.
A list of a few advantages over
boostin addition to macro simplification:ToStringare printed whenCHECKorREQUIREfailsABORTorASSERTmacros that fail-fast)To try it out:
On commit 1 and commit 2, these are given by guidance of
Catch2.&&conditions are unrolled into two separate checks.Replace all boost macros (third commit)