xo-umbrella2/xo-indentlog2/utest/LineState.test.cpp

154 lines
6 KiB
C++

/** @file LineState.test.cpp
*
* @author Roland Conybeare, Jul 2026
**/
#include "LineState.hpp"
#include <xo/testutil/try_test_array.hpp>
#include <xo/randomgen/random_seed.hpp>
#include <xo/randomgen/xoshiro256.hpp>
// #include <xo/testutil/UtestRehearser.hpp>
#include <catch2/catch.hpp>
#include <vector>
namespace ut {
using xo::LineState;
using xo::rng::Seed;
using xo::rng::xoshiro256ss;
using xo::UtestRehearser;
using std::vector;
using std::uint32_t;
/** Unit test setup.
* Test sequence:
* call LineState::_check_update_localstate()
* with progressive prefixes comprising the first break_v_[i].first
* characters in text_; expect resulting state to match break_v_[i].second
**/
struct TestCase_LineState {
TestCase_LineState(const char * text,
std::vector<std::pair<uint32_t, LineState>> break_v)
: text_{text},
break_v_{std::move(break_v)}
{}
const char * text_ = nullptr;
std::vector<std::pair<uint32_t, LineState>> break_v_ = {};
};
vector<TestCase_LineState>
s_linestate_testcase_v = {
/* reminder:
* LineState(local_ppos, solpos, color_escape_chars, color_escape_start)
*/
/* test case: trivial: 0 chars written from empty string */
TestCase_LineState("",
{{0, LineState(0, 0, 0, -1)}
}),
/* test case: 1 non-special character */
TestCase_LineState("a",
{{0, LineState(0, 0, 0, -1)},
{1, LineState(1, 0, 0, -1)}}),
/* test case: 1 special character (newline) */
TestCase_LineState("\n",
{{0, LineState(0, 0, 0, -1)},
{1, LineState(1, 1, 0, -1)}}),
/* test case: 1 special character (carriage return) */
TestCase_LineState("\r",
{{0, LineState(0, 0, 0, -1)},
{1, LineState(1, 1, 0, -1)}}),
/* test case: 1 special character (escape)
* (defer counting color-escape chars until the end of the escape)
*/
TestCase_LineState("\033",
{{0, LineState(0, 0, 0, -1)},
{1, LineState(1, 0, 0, 0)}}),
/* test case: color-escape \033..m
* (defer counting color-escape chars until the end of the escape)
*/
TestCase_LineState("\033[31;9m",
{{0, LineState(0, 0, 0, -1)},
{6, LineState(6, 0, 0, 0)},
{7, LineState(7, 0, 7, -1)}}),
/* test case: incomplete color-escape (interrupted by non-escape-eligible char) */
TestCase_LineState("\033[31;hello",
{{ 0, LineState( 0, 0, 0, -1)},
{ 5, LineState( 5, 0, 0, 0)},
{ 6, LineState( 6, 0, 0, -1)},
{10, LineState(10, 0, 0, -1)}}),
/* test case: multiple lines, no color escapes */
TestCase_LineState("we hold\nall these truths\nself-evident",
{{ 0, LineState( 0, 0, 0, -1)},
{ 7, LineState( 7, 0, 0, -1)},
{ 8, LineState( 8, 8, 0, -1)},
{24, LineState(24, 8, 0, -1)},
{25, LineState(25, 25, 0, -1)},
{37, LineState(37, 25, 0, -1)},
}),
/* test case: multiple line, color escapes */
TestCase_LineState("we \033[31;9mhold\n\033[0mall \033[31;13mthese\033[0m truths\nself-evident",
{{ 0, LineState( 0, 0, 0, -1)},
/* color-escape \033..m on 1st line uses 7 chars */
{14, LineState(14, 0, 7, -1)},
/* \n at char 15 resets color_escape */
{15, LineState(15, 15, 0, -1)},
/* color escape \033..m on 2nd line uses 4 chars */
{20, LineState(20, 15, 4, -1)},
/* 2nd color escape on 2nd line uses 8 chars */
{32, LineState(32, 15, 12, -1)},
/* incomplete 3rd color escape at this point: */
{39, LineState(39, 15, 12, 36)},
/* 3rd color escape on 2nd line uses 4 chars */
{40, LineState(40, 15, 16, -1)},
/* \n at 47 resets color escape */
{48, LineState(48, 48, 0, -1)},
{60, LineState(60, 48, 0, -1)},
}),
};
void
linestate_test_fn(const TestCase_LineState & tc,
UtestRehearser * p_rh)
{
Seed<xoshiro256ss> seed;
auto rgen = xoshiro256ss(seed);
LineState act_lstate;
for (uint32_t j_prefix = 0; j_prefix < tc.break_v_.size(); ++j_prefix) {
act_lstate._check_update_local_state
(tc.text_,
tc.text_ + tc.break_v_[j_prefix].first,
p_rh->enable_debug());
const LineState & exp_lstate = tc.break_v_[j_prefix].second;
REHEARSE(*p_rh,
act_lstate.local_ppos() == exp_lstate.local_ppos());
REHEARSE(*p_rh,
act_lstate.solpos() == exp_lstate.solpos());
REHEARSE(*p_rh,
act_lstate.color_escape_chars()
== exp_lstate.color_escape_chars());
REHEARSE(*p_rh,
act_lstate.color_escape_start()
== exp_lstate.color_escape_start());
}
}
TEST_CASE("LineState", "[LineState]")
{
//constexpr bool c_debug_flag = false;
try_test_array(s_linestate_testcase_v,
&linestate_test_fn);
}
}
/* end LineState.test.cpp */