#include "test.h"
using Test = TestSv<Object>;
TEST_CASE("Object", "[Object]") {
perlvars vars;
Object my(vars.ov);
Sv oth_valid(vars.oavr), oth_invalid(vars.av);
SECTION("ctor") {
SECTION("empty") {
Object r;
REQUIRE(!r);
}
SECTION("SV") {
SECTION("undef") { Test::ctor(vars.undef, behaviour_t::EMPTY); }
SECTION("number") { Test::ctor(vars.iv, behaviour_t::THROWS); }
SECTION("string") { Test::ctor(vars.pv, behaviour_t::THROWS); }
SECTION("RV") { Test::ctor(vars.rv, behaviour_t::THROWS); }
SECTION("RV-OSV") { Test::ctor(vars.ovr, behaviour_t::VALID, vars.ov); }
SECTION("RV-OAV") { Test::ctor(vars.oavr, behaviour_t::VALID, (SV*)vars.oav); }
SECTION("RV-OHV") { Test::ctor(vars.ohvr, behaviour_t::VALID, (SV*)vars.ohv); }
SECTION("RV-OIO") { Test::ctor(vars.ior, behaviour_t::VALID, (SV*)vars.io); }
SECTION("AV") { Test::ctor((SV*)vars.av, behaviour_t::THROWS); }
SECTION("OAV") { Test::ctor((SV*)vars.oav, behaviour_t::VALID); }
SECTION("HV") { Test::ctor((SV*)vars.hv, behaviour_t::THROWS); }
SECTION("OHV") { Test::ctor((SV*)vars.ohv, behaviour_t::VALID); }
SECTION("CV") { Test::ctor((SV*)vars.cv, behaviour_t::THROWS); }
SECTION("GV") { Test::ctor((SV*)vars.gv, behaviour_t::THROWS); }
SECTION("OIO") { Test::ctor((SV*)vars.io, behaviour_t::VALID); }
}
SECTION("AV") {
SECTION("AV") { Test::ctor(vars.av, behaviour_t::THROWS); }
SECTION("OAV") { Test::ctor(vars.oav, behaviour_t::VALID); }
}
SECTION("HV") {
SECTION("HV") { Test::ctor(vars.hv, behaviour_t::THROWS); }
SECTION("OHV") { Test::ctor(vars.ohv, behaviour_t::VALID); }
}
SECTION("CV") { Test::ctor(vars.cv, behaviour_t::THROWS); }
SECTION("GV") { Test::ctor(vars.gv, behaviour_t::THROWS); }
SECTION("OIO") { Test::ctor(vars.io, behaviour_t::VALID); }
SECTION("Object") { Test::ctor(my, behaviour_t::VALID); }
SECTION("valid Sv") { Test::ctor(oth_valid, behaviour_t::VALID); }
SECTION("invalid Sv") { Test::ctor(oth_invalid, behaviour_t::THROWS); }
SECTION("check refcnt") {
auto ocnt = SvREFCNT(vars.ov);
auto rcnt = SvREFCNT(vars.ovr);
{
Object o(vars.ovr);
REQUIRE(SvREFCNT(vars.ov) == ocnt+1);
REQUIRE(SvREFCNT(vars.ovr) == rcnt+1);
}
REQUIRE(SvREFCNT(vars.ov) == ocnt);
REQUIRE(SvREFCNT(vars.ovr) == rcnt);
}
}
SECTION("operator=") {
Object o = Stash("MyTest").bless(Simple(100));
SECTION("SV") {
SECTION("undef") { Test::assign(o, vars.undef, behaviour_t::EMPTY); }
SECTION("number") { Test::assign(o, vars.iv, behaviour_t::THROWS); }
SECTION("string") { Test::assign(o, vars.pv, behaviour_t::THROWS); }
SECTION("RV") { Test::assign(o, vars.rv, behaviour_t::THROWS); }
SECTION("RV-OSV") { Test::assign(o, vars.ovr, behaviour_t::VALID, vars.ov); }
SECTION("RV-OAV") { Test::assign(o, vars.oavr, behaviour_t::VALID, (SV*)vars.oav); }
SECTION("RV-OHV") { Test::assign(o, vars.ohvr, behaviour_t::VALID, (SV*)vars.ohv); }
SECTION("RV-OIO") { Test::assign(o, vars.ior, behaviour_t::VALID, (SV*)vars.io); }
SECTION("AV") { Test::assign(o, (SV*)vars.av, behaviour_t::THROWS); }
SECTION("OAV") { Test::assign(o, (SV*)vars.oav, behaviour_t::VALID); }
SECTION("HV") { Test::assign(o, (SV*)vars.hv, behaviour_t::THROWS); }
SECTION("OHV") { Test::assign(o, (SV*)vars.ohv, behaviour_t::VALID); }
SECTION("CV") { Test::assign(o, (SV*)vars.cv, behaviour_t::THROWS); }
SECTION("GV") { Test::assign(o, (SV*)vars.gv, behaviour_t::THROWS); }
SECTION("OIO") { Test::assign(o, (SV*)vars.io, behaviour_t::VALID); }
}
SECTION("AV") {
SECTION("AV") { Test::assign(o, vars.av, behaviour_t::THROWS); }
SECTION("OAV") { Test::assign(o, vars.oav, behaviour_t::VALID); }
}
SECTION("HV") {
SECTION("HV") { Test::assign(o, vars.hv, behaviour_t::THROWS); }
SECTION("OHV") { Test::assign(o, vars.ohv, behaviour_t::VALID); }
}
SECTION("CV") { Test::assign(o, vars.cv, behaviour_t::THROWS); }
SECTION("GV") { Test::assign(o, vars.gv, behaviour_t::THROWS); }
SECTION("OIO") { Test::assign(o, vars.io, behaviour_t::VALID); }
SECTION("Object") { Test::assign(o, my, behaviour_t::VALID); }
SECTION("valid Sv") { Test::assign(o, oth_valid, behaviour_t::VALID); }
SECTION("invalid Sv") { Test::assign(o, oth_invalid, behaviour_t::THROWS); }
SECTION("check refcnt") {
auto obase = Simple(100);
auto r = Ref::create(obase);
Object o = Stash("MyTest").bless(r);
auto ocnt = SvREFCNT(obase);
auto rcnt = SvREFCNT(r);
auto ocnt2 = SvREFCNT(vars.ov);
auto rcnt2 = SvREFCNT(vars.ovr);
o = vars.ovr;
REQUIRE(SvREFCNT(r) == rcnt-1);
REQUIRE(SvREFCNT(obase) == ocnt-1);
REQUIRE(SvREFCNT(vars.ovr) == rcnt2+1);
REQUIRE(SvREFCNT(vars.ov) == ocnt2+1);
}
}
SECTION("set") {
Object o;
o.set(vars.iv); // no checks
REQUIRE(o);
REQUIRE(SvREFCNT(vars.iv) == 2);
REQUIRE(o.get() == vars.iv);
}
SECTION("stash") {
Object o(vars.ov);
REQUIRE(o.stash());
REQUIRE(o.stash() == vars.stash);
Stash st("MyTest");
o.stash(st);
REQUIRE(o.stash() == gv_stashpvs("MyTest", 0));
o.stash(vars.stash);
REQUIRE(o.stash() == vars.stash);
}
SECTION("rebless") {
Stash st("M1");
auto o = st.bless(Simple(100));
REQUIRE(o.stash() == st);
Stash st2("M2");
o.rebless(st2);
REQUIRE(o.stash() == st2);
}
SECTION("ref") {
Ref r;
{
auto o = Stash("M1").bless(Simple(100));
r = o.ref();
REQUIRE(r);
}
REQUIRE(r.use_count() == 1);
Object o = r;
REQUIRE(o.ref() == r);
REQUIRE(r.use_count() == 2);
o.reset();
REQUIRE(r.use_count() == 1);
o = r;
o = vars.ov;
REQUIRE(r.use_count() == 1);
REQUIRE(o.ref() != r);
}
SECTION("method/method_strict") {
auto o = Stash("M2").bless(Simple(333));
o.stash().sub("child_method", vars.cv);
REQUIRE(o.method("child_method"));
REQUIRE(o.method("child_method") == get_cv("M2::child_method", 0));
REQUIRE(o.method("child_method") == o.method_strict("child_method"));
REQUIRE(o.method("method"));
REQUIRE(o.method("method") == get_cv("M1::method", 0));
REQUIRE(o.method("method") == o.method_strict("method"));
REQUIRE(!o.method("nomethod"));
REQUIRE_THROWS(o.method_strict("nomethod"));
}
SECTION("isa") {
auto o = Stash("M2").bless(Simple(333));
REQUIRE(o.isa("M1"));
REQUIRE(o.isa(Stash("M1")));
REQUIRE(!o.isa("M111"));
REQUIRE(!o.isa(Stash("M222", GV_ADD)));
}
SECTION("call") {
auto o = Stash("M2").bless(Simple(333));
Simple ret = o.call("method");
REQUIRE(ret == 343);
o = vars.ov;
ret = Simple(o.call("method", Simple(100)));
REQUIRE(ret == 233);
}
SECTION("call_next/super/SUPER") {
auto o = Stash("M4").bless(Simple(333));
Sub sub = o.method("meth");
Simple res;
SECTION("SUPER") {
res = o.call_SUPER(sub);
REQUIRE(res == "M4(OBJ)-2");
sub = sub.SUPER_strict();
REQUIRE(sub == get_cv("M2::meth", 0));
res = o.call_SUPER(sub);
REQUIRE(res == "M4(OBJ)-1");
sub = sub.SUPER_strict();
REQUIRE(sub == get_cv("M1::meth", 0));
REQUIRE(!sub.SUPER());
REQUIRE_THROWS(sub.SUPER_strict());
REQUIRE_THROWS(o.call_SUPER<void>(sub));
}
SECTION("next") {
res = o.call_next(sub);
REQUIRE(res == "M4(OBJ)-2");
sub = o.next_method_strict(sub);
REQUIRE(sub == get_cv("M2::meth", 0));
res = o.call_next(sub);
REQUIRE(res == "M4(OBJ)-3");
sub = o.next_method_strict(sub);
REQUIRE(sub == get_cv("M3::meth", 0));
res = o.call_next(sub);
REQUIRE(res == "M4(OBJ)-1");
sub = o.next_method_strict(sub);
REQUIRE(sub == get_cv("M1::meth", 0));
REQUIRE(!o.next_method(sub));
REQUIRE_THROWS(o.next_method_strict(sub));
REQUIRE_THROWS(o.call_next<void>(sub));
}
SECTION("next_maybe") {
res = o.call_next_maybe(sub);
REQUIRE(res == "M4(OBJ)-2");
sub = o.next_method(sub);
res = o.call_next_maybe(sub);
REQUIRE(res == "M4(OBJ)-3");
sub = o.next_method(sub);
res = o.call_next_maybe(sub);
REQUIRE(res == "M4(OBJ)-1");
sub = o.next_method(sub);
res = o.call_next_maybe(sub);
REQUIRE(!res);
}
SECTION("super/dfs") {
res = o.call_super(sub);
REQUIRE(res == "M4(OBJ)-2");
sub = o.super_method_strict(sub);
REQUIRE(sub == get_cv("M2::meth", 0));
res = o.call_super(sub);
REQUIRE(res == "M4(OBJ)-1");
sub = o.super_method_strict(sub);
REQUIRE(sub == get_cv("M1::meth", 0));
REQUIRE(!o.super_method(sub));
REQUIRE_THROWS(o.super_method_strict(sub));
REQUIRE_THROWS(o.call_super<void>(sub));
}
SECTION("super/c3") {
o.call<void>("enable_c3");
res = o.call_super(sub);
REQUIRE(res == "M4(OBJ)-2");
sub = o.super_method_strict(sub);
REQUIRE(sub == get_cv("M2::meth", 0));
res = o.call_super(sub);
REQUIRE(res == "M4(OBJ)-3");
sub = o.super_method_strict(sub);
REQUIRE(sub == get_cv("M3::meth", 0));
res = o.call_super(sub);
REQUIRE(res == "M4(OBJ)-1");
sub = o.super_method_strict(sub);
REQUIRE(sub == get_cv("M1::meth", 0));
REQUIRE(!o.super_method(sub));
REQUIRE_THROWS(o.super_method_strict(sub));
REQUIRE_THROWS(o.call_super<void>(sub));
o.call<void>("disable_c3");
}
SECTION("super_maybe") {
res = o.call_super_maybe(sub);
REQUIRE(res == "M4(OBJ)-2");
sub = o.super_method(sub);
res = o.call_super_maybe(sub);
REQUIRE(res == "M4(OBJ)-1");
sub = o.super_method(sub);
res = o.call_super_maybe(sub);
REQUIRE(!res);
}
}
SECTION("detach") {
auto obase = Simple(100);
auto r = Ref::create(obase);
Object o = Stash("MyTest").bless(r);
REQUIRE(obase.use_count() == 3);
REQUIRE(r.use_count() == 2);
SV* osv = o.detach();
REQUIRE(r.use_count() == 1);
REQUIRE(obase.use_count() == 3);
SvREFCNT_dec(osv);
}
}