results: fix Debug rendering assertion #18

Merged
mcp merged 2 commits from codex/issue-7-results-assert into main 2026-07-30 16:47:26 +01:00
4 changed files with 44 additions and 5 deletions
+1
View File
@@ -13,5 +13,6 @@ if(BUILD_TESTING)
tests/tests.cc) tests/tests.cc)
add_test(NAME validator COMMAND partridge_tests validator) add_test(NAME validator COMMAND partridge_tests validator)
add_test(NAME construction COMMAND partridge_tests construction) add_test(NAME construction COMMAND partridge_tests construction)
add_test(NAME rendering COMMAND partridge_tests rendering)
add_test(NAME solver-small COMMAND partridge_tests solver-small) add_test(NAME solver-small COMMAND partridge_tests solver-small)
endif() endif()
+5 -4
View File
@@ -12,7 +12,8 @@ ctest --test-dir build --output-on-failure
The tests independently check board dimensions, square multiplicities, bounds, The tests independently check board dimensions, square multiplicities, bounds,
overlap, and complete coverage. They cover small unsatisfiable solver inputs, a overlap, and complete coverage. They cover small unsatisfiable solver inputs, a
known order-8 solution, invalid placement diagnostics, and construction of an known order-8 solution, invalid placement diagnostics, and construction of an
order-9 solution from the order-8 fixture. order-9 solution from the order-8 fixture. The rendering test also formats the
known order-8 solution and checks the resulting grid dimensions and coverage.
## Debug and sanitizers ## Debug and sanitizers
@@ -37,6 +38,6 @@ ctest --test-dir build-ubsan --output-on-failure
``` ```
The sanitizer flags shown are supported by Clang and GCC. Other compilers may The sanitizer flags shown are supported by Clang and GCC. Other compilers may
require different flags. Debug compilation and a feasible solver run currently require different flags. A feasible solver run currently exposes the
expose the pre-existing defects tracked by issues #7 and #14 respectively; the pre-existing defect tracked by issue #14; the test additions deliberately do
test additions deliberately do not include fixes for those separate issues. not include its separate fix.
+2 -1
View File
@@ -85,7 +85,8 @@ namespace {
auto set(std::string &s, size_t x, size_t y, char c) const noexcept -> void { auto set(std::string &s, size_t x, size_t y, char c) const noexcept -> void {
assert(x < length_); assert(x < length_);
assert(y < length_); assert(y < length_);
assert(grid_[x + y * length_] != c); // Size labels may replace interior spaces, but must not duplicate a write.
assert(s[x + y * length_] != c);
s[x + y * length_] = c; s[x + y * length_] = c;
} }
+36
View File
@@ -138,6 +138,16 @@ namespace {
}; };
} }
auto renderable_result(std::uint64_t side,
std::vector<Placement> const &placements) -> Results {
std::vector<Square> squares;
squares.reserve(placements.size());
for (auto const &placement: placements) {
squares.emplace_back(placement.x + placement.y * side, placement.side);
}
return Results(side, std::move(squares));
}
auto construct_next_odd(std::uint64_t even_order, auto construct_next_odd(std::uint64_t even_order,
std::vector<Placement> placements) std::vector<Placement> placements)
-> std::vector<Placement> { -> std::vector<Placement> {
@@ -221,6 +231,29 @@ namespace {
"even-to-odd construction was rejected:\n" + validation.text()); "even-to-odd construction was rejected:\n" + validation.text());
} }
auto test_rendering() -> int {
auto const result = renderable_result(36, known_order_8());
std::ostringstream rendered;
auto *const original_buffer = std::cout.rdbuf(rendered.rdbuf());
result.output();
std::cout.rdbuf(original_buffer);
int failures = 0;
std::istringstream lines(rendered.str());
std::string line;
std::uint64_t line_count = 0;
while (std::getline(lines, line)) {
++line_count;
failures += expect(line.size() == result.length(),
"rendered row has incorrect width");
failures += expect(line.find('.') == std::string::npos,
"valid solution left an unrendered cell");
}
failures += expect(line_count == result.length(),
"rendered output has incorrect height");
return failures;
}
auto test_small_solver() -> int { auto test_small_solver() -> int {
int failures = 0; int failures = 0;
for (auto const order: std::array<std::uint64_t, 2>{2, 3}) { for (auto const order: std::array<std::uint64_t, 2>{2, 3}) {
@@ -262,6 +295,9 @@ int main(int argc, char **argv) {
if (test == "construction") { if (test == "construction") {
return test_construction(); return test_construction();
} }
if (test == "rendering") {
return test_rendering();
}
if (test == "solver-small") { if (test == "solver-small") {
return test_small_solver(); return test_small_solver();
} }