xo-umbrella2/xo-stringtable2/utest/printable_render.test.cpp

161 lines
6.1 KiB
C++

/* @file printable_render.test.cpp
*
* author: Roland Conybeare, Aug 2026
*
* Phase C verification for the APrintable printers in xo-stringtable2.
*
* TEMPLATE for the remaining printers -- see
* .xo-backlog/xo-printable2/issues/01-aprintable-pretty-ppsink.md
*
* Each printer is rendered through
*
* toppstr(PpConfig, x) -> Prettifier<obj<APrintable,D>> -> x.pretty(sink)
*
* and the rendering is PINNED, not merely smoke-tested.
*
* Until phase E these tables carried a second expectation per case, observed
* through the deprecated two-pass protocol, so that a conversion could be
* checked against the rendering it replaced. That scaffolding was deleted
* with pretty_deprecated itself; the pinned `pretty` expectations are what
* remain, and they are the coverage. Where the two protocols deliberately
* differed (a reviewed rendering change, as for DList's "(...)" fallback),
* the surviving expectation is the NEW one.
*
* Margin is the case variable: it is what makes the protocols disagree if they
* are going to.
*
* Uses UtestRehearser rather than INFO: renderings can run to many lines, and
* INFO builds and stacks them on every iteration whether or not anything
* fails. REHEARSE records failures on a first pass and re-runs with logging
* enabled only when needed.
*
* Expectations are OBSERVED, never predicted.
*/
#include "String.hpp" /* pulls in IPrintable_DString.hpp */
#include "StringTable.hpp" /* the public path to a DUniqueString */
#include "uniquestring/IPrintable_DUniqueString.hpp"
#include "init_stringtable2.hpp"
#include <xo/printable2/Printable.hpp>
#include <xo/indentlog2/print/toppstr.hpp>
#include <xo/testutil/UtestRehearser.hpp>
#include <xo/alloc2/Allocator.hpp>
#include <xo/alloc2/Arena.hpp>
#include <xo/ppsink/scope.hpp>
#include <xo/ppsink/scope_macros.hpp>
#include <catch2/catch.hpp>
#include <cstdint>
#include <string>
#include <vector>
namespace xo {
using xo::scm::DString;
using xo::scm::DUniqueString;
using xo::print::APrintable;
using xo::mm::AAllocator;
using xo::mm::DArena;
using xo::mm::ArenaConfig;
using xo::facet::with_facet;
namespace ut {
using xo::pp::PpConfig;
using xo::pp::toppstr;
using xo::pp::scope;
using xo::pp::xtag;
namespace {
struct Testcase_Render {
Testcase_Render(std::uint32_t margin,
const char * text,
const char * expect_pretty)
: margin_{margin}, text_{text},
expect_pretty_{expect_pretty} {}
/** right margin, applied to BOTH protocols **/
std::uint32_t margin_;
/** string content to render **/
std::string text_;
/** OBSERVED rendering via pretty. The assertion that outlives
* phase E.
**/
std::string expect_pretty_;
};
std::vector<Testcase_Render>
s_testcase_v = {
/* margin text pretty */
Testcase_Render(200, "hello", "hello"),
Testcase_Render(20, "hello", "hello"),
Testcase_Render(4, "hello", "hello"),
Testcase_Render(200, "", ""),
Testcase_Render(200, "with spaces in it", "with spaces in it"),
Testcase_Render(8, "with spaces in it", "with spaces in it"),
};
/** render @p x through pretty(PpSink&) **/
template <typename T>
std::string
render_pretty(const T & x, std::uint32_t margin) {
return toppstr(PpConfig::scratch_plain(margin), x);
}
} /*namespace*/
TEST_CASE("DString-render", "[printable][DString]")
{
UtestRehearser rh;
for (auto _ : rh) {
scope log(XO_DEBUG2_(rh.enable_debug(), "DString-render"));
for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) {
const Testcase_Render & tc = s_testcase_v[i_tc];
auto tmp = ArenaNameStr::sprintf("testarena.%ld", i_tc);
ArenaConfig cfg { .name_ = tmp,
.size_ = 4*1024 };
DArena arena = DArena::map(cfg);
auto alloc = with_facet<AAllocator>::mkobj(&arena);
DString * s = DString::from_cstr(alloc, tc.text_.c_str());
auto p = with_facet<APrintable>::mkobj(s);
std::string pretty = render_pretty(p, tc.margin_);
log && log(xtag("i_tc", i_tc),
xtag("margin", tc.margin_),
xtag("text", tc.text_),
xtag("pretty", pretty));
REHEARSE(rh, pretty == tc.expect_pretty_);
}
}
}
TEST_CASE("DUniqueString-render", "[printable][DUniqueString]")
{
UtestRehearser rh;
for (auto _ : rh) {
scope log(XO_DEBUG2_(rh.enable_debug(), "DUniqueString-render"));
for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) {
const Testcase_Render & tc = s_testcase_v[i_tc];
xo::scm::StringTable table(1024);
const DUniqueString * u = table.intern(tc.text_);
auto p = with_facet<APrintable>::mkobj(const_cast<DUniqueString *>(u));
std::string pretty = render_pretty(p, tc.margin_);
log && log(xtag("i_tc", i_tc),
xtag("margin", tc.margin_),
xtag("text", tc.text_),
xtag("pretty", pretty));
REHEARSE(rh, pretty == tc.expect_pretty_);
}
}
}
} /*namespace ut*/
} /*namespace xo*/
/* end printable_render.test.cpp */