123 lines
4.6 KiB
C++
123 lines
4.6 KiB
C++
/* @file json_render.test.cpp
|
|
*
|
|
* author: Roland Conybeare, Sep 2026
|
|
*
|
|
* JSON rendering for object2's D-types, via xo-printjson.
|
|
*
|
|
* The pairing to keep in view: DFloat::reflect_self() describes the BOX
|
|
* faithfully -- a struct with a `value` member -- while
|
|
* SetupObject2::provide_json_printers installs a printer that renders it as a
|
|
* bare number. Both are asserted here, because the whole point of separating
|
|
* them is that they say different things.
|
|
*
|
|
* Expectations are OBSERVED, never predicted.
|
|
*/
|
|
|
|
#include <xo/object2/DFloat.hpp>
|
|
#include <xo/object2/SetupObject2.hpp>
|
|
#include <xo/object2/number/IReflectable_DFloat.hpp>
|
|
#include <xo/object2/number/IGCObject_DFloat.hpp>
|
|
#include <xo/alloc2/arena/IAllocator_DArena.hpp>
|
|
#include <xo/printjson/PrintJson.hpp>
|
|
#include <xo/reflectable2/FopTdx.hpp>
|
|
#include <xo/reflect/Reflect.hpp>
|
|
#include <catch2/catch.hpp>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace xo {
|
|
using xo::scm::DFloat;
|
|
using xo::scm::SetupObject2;
|
|
using xo::json::PrintJson;
|
|
using xo::reflect::AReflectable;
|
|
using xo::reflect::Metatype;
|
|
using xo::reflect::Reflect;
|
|
using xo::mm::AAllocator;
|
|
using xo::mm::AGCObject;
|
|
using xo::mm::DArena;
|
|
using xo::mm::ArenaConfig;
|
|
using xo::mm::ArenaNameStr;
|
|
using xo::facet::with_facet;
|
|
using xo::facet::vt;
|
|
|
|
namespace ut {
|
|
namespace {
|
|
/** object2's registrations, once. **/
|
|
void require_object2_setup(PrintJson * pjson) {
|
|
REQUIRE(SetupObject2::register_facets());
|
|
|
|
SetupObject2::reflect_types();
|
|
SetupObject2::provide_json_printers(pjson);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("DFloat-reflects-its-layout", "[printjson][DFloat]")
|
|
{
|
|
PrintJson print_json;
|
|
require_object2_setup(&print_json);
|
|
|
|
auto td = Reflect::require<DFloat>();
|
|
|
|
/* reflection describes the BOX -- a struct with one member. If
|
|
* this ever reads mt_atomic, reflect_self() did not run, and the
|
|
* json below would still pass, since the printer short-circuits
|
|
* the metatype switch.
|
|
*/
|
|
REQUIRE(td->metatype() == Metatype::mt_struct);
|
|
REQUIRE(td->n_child_fixed() == 1);
|
|
REQUIRE(td->struct_member_name(0) == std::string("value"));
|
|
} /*TEST_CASE(DFloat-reflects-its-layout)*/
|
|
|
|
TEST_CASE("DFloat-renders-as-a-bare-number", "[printjson][DFloat]")
|
|
{
|
|
PrintJson print_json;
|
|
require_object2_setup(&print_json);
|
|
|
|
ArenaConfig cfg { .name_ = ArenaNameStr::sprintf("utest.json.float"),
|
|
.size_ = 4*1024 };
|
|
DArena arena = DArena::map(cfg);
|
|
auto alloc = with_facet<AAllocator>::mkobj(&arena);
|
|
|
|
auto x = with_facet<AReflectable>::mkobj(DFloat::_box(alloc, 1.5));
|
|
|
|
std::stringstream ss;
|
|
print_json.print_obj(x, &ss);
|
|
|
|
/* NOT {"_name_": "DFloat", "value": 1.5}: the printer decides how a
|
|
* boxed float reads, and reflection is left honest about layout
|
|
*/
|
|
REQUIRE(ss.str() == std::string("1.5"));
|
|
} /*TEST_CASE(DFloat-renders-as-a-bare-number)*/
|
|
|
|
TEST_CASE("erased-DFloat-renders-the-same", "[printjson][DFloat]")
|
|
{
|
|
/* the routine shape: a D-type's member is obj<AGCObject>, not a
|
|
* typed fop. Reaching the printer from there needs the rotation
|
|
* through AReflectable that xo-reflectable2 provides.
|
|
*/
|
|
PrintJson print_json;
|
|
require_object2_setup(&print_json);
|
|
|
|
ArenaConfig cfg { .name_ = ArenaNameStr::sprintf("utest.json.erased"),
|
|
.size_ = 4*1024 };
|
|
DArena arena = DArena::map(cfg);
|
|
auto alloc = with_facet<AAllocator>::mkobj(&arena);
|
|
|
|
/* vt<>, NOT with_facet<>::mkobj -- mkobj hands back a TYPED
|
|
* obj<AGCObject,DFloat> (obj.hpp:165), which FopTdx resolves at
|
|
* compile time and which therefore never reaches the rotation.
|
|
* The conversion below is what erases it. Corrected 2026-09-13:
|
|
* this case passed with register_impl<AReflectable,DFloat>()
|
|
* commented out, i.e. it was green without testing its subject.
|
|
*/
|
|
vt<AGCObject> gco = with_facet<AGCObject>::mkobj(DFloat::_box(alloc, 1.5));
|
|
|
|
std::stringstream ss;
|
|
print_json.print_obj(gco, &ss);
|
|
|
|
REQUIRE(ss.str() == std::string("1.5"));
|
|
} /*TEST_CASE(erased-DFloat-renders-the-same)*/
|
|
} /*namespace ut*/
|
|
} /*namespace xo*/
|
|
|
|
/* end json_render.test.cpp */
|