#include "test.h"
using
Test = TestSv<Simple>;
using
panda::string_view;
template
<
typename
T>
typename
std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, T>::type getnum (
const
SV* sv) {
return
SvIVX(sv); }
template
<
typename
T>
typename
std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type getnum (
const
SV* sv) {
return
SvUVX(sv); }
template
<
typename
T>
typename
std::enable_if<std::is_floating_point<T>::value, T>::type getnum (
const
SV* sv) {
return
SvNVX(sv); }
template
<
typename
T>
typename
std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value, T>::type oknumtype (
const
SV* sv) {
return
(
bool
)SvIOK(sv); }
template
<
typename
T>
typename
std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value, T>::type oknumtype (
const
SV* sv) {
return
SvUOK(sv) || SvIOK(sv); }
template
<
typename
T>
typename
std::enable_if<std::is_floating_point<T>::value, T>::type oknumtype (
const
SV* sv) {
return
(
bool
)SvNOK(sv); }
template
<
class
T>
static
void
test_ctor (T val) {
Simple obj(val);
REQUIRE(getnum<T>(obj) == val);
}
template
<
class
T>
static
void
test_assign (T val) {
Simple obj;
obj = val;
REQUIRE(obj);
REQUIRE(oknumtype<T>(obj));
REQUIRE(getnum<T>(obj) == val);
SV* _sv = obj;
obj = (T)0;
REQUIRE(oknumtype<T>(_sv));
REQUIRE(getnum<T>(obj) == 0);
REQUIRE((SV*)obj == _sv);
SV* _tmp = sv_2mortal(newSVpvs(
"hello"
));
obj = _tmp;
REQUIRE(SvPOK(_tmp));
obj = val;
REQUIRE(oknumtype<T>(_tmp));
REQUIRE(!SvPOK(_tmp));
REQUIRE(getnum<T>(obj) == val);
REQUIRE((SV*)obj == _tmp);
}
template
<
class
T>
static
void
test_set (T val) {
Simple obj((T)0);
obj.set(val);
REQUIRE(obj);
REQUIRE(oknumtype<T>(obj));
REQUIRE(getnum<T>(obj) == val);
}
template
<
class
T>
static
void
test_cast (T val) {
Simple obj;
T r = obj;
REQUIRE(r == (T)0);
obj = val;
r = obj;
REQUIRE(r == val);
}
template
<
class
T>
static
void
test_get (T val) {
Simple obj(val);
REQUIRE(obj.get<T>() == val);
}
template
<
class
T>
static
void
test_as_string () {
Simple o;
REQUIRE(o.as_string<T>() == T());
o = Sv::create();
REQUIRE(o.as_string<T>() == T());
T src(
"epta"
);
o = string_view(src.data(), src.length());
REQUIRE(o.as_string<T>() == src);
}
TEST_CASE(
"Simple"
,
"[Simple]"
) {
perlvars vars;
Simple my(vars.iv);
Sv oth_valid(vars.ov), oth_invalid(vars.av);
int
ivsize = Simple(eval(
"use Config; $Config{ivsize}"
));
SECTION(
"ctor"
) {
SECTION(
"empty"
) {
Simple obj;
REQUIRE(!obj);
}
SECTION(
"SV"
) {
SECTION(
"undef"
) { Test::ctor(vars.undef, behaviour_t::VALID); }
SECTION(
"number"
) { Test::ctor(vars.iv, behaviour_t::VALID); }
SECTION(
"string"
) { Test::ctor(vars.pv, behaviour_t::VALID); }
SECTION(
"OSV"
) { Test::ctor(vars.ov, behaviour_t::VALID); }
SECTION(
"RV"
) { Test::ctor(vars.rv, behaviour_t::THROWS); }
SECTION(
"AV"
) { Test::ctor((SV*)vars.av, behaviour_t::THROWS); }
SECTION(
"HV"
) { Test::ctor((SV*)vars.hv, behaviour_t::THROWS); }
SECTION(
"CV"
) { Test::ctor((SV*)vars.cv, behaviour_t::THROWS); }
SECTION(
"GV"
) { Test::ctor((SV*)vars.gv, behaviour_t::THROWS); }
SECTION(
"IO"
) { Test::ctor((SV*)vars.io, behaviour_t::THROWS); }
}
SECTION(
"Simple"
) { 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(
"from number"
) {
test_ctor((int8_t)-5);
test_ctor((int16_t)-30000);
test_ctor((int32_t)1000000000);
if
(ivsize == 8) test_ctor(9223372036854775807L);
test_ctor((uint8_t)255);
test_ctor((uint16_t)65535);
test_ctor((uint32_t)4000000000);
if
(ivsize == 8) test_ctor(18446744073709551615LU);
test_ctor(5.5f);
test_ctor(222222222.222222);
}
SECTION(
"from string_view"
) {
Simple obj(string_view(
"suka"
));
REQUIRE(string_view(SvPVX(obj), 4) ==
"suka"
);
REQUIRE(SvCUR(obj) == 4);
REQUIRE(obj.is_string());
}
}
SECTION(
"noinc"
) {
SECTION(
"undef"
) { Test::noinc(vars.undef, behaviour_t::VALID); }
SECTION(
"number"
) { Test::noinc(vars.iv, behaviour_t::VALID); }
SECTION(
"string"
) { Test::noinc(vars.pv, behaviour_t::VALID); }
SECTION(
"OSV"
) { Test::noinc(vars.ov, behaviour_t::VALID); }
SECTION(
"RV"
) { Test::noinc(vars.rv, behaviour_t::THROWS); }
SECTION(
"AV"
) { Test::noinc((SV*)vars.av, behaviour_t::THROWS); }
SECTION(
"HV"
) { Test::noinc((SV*)vars.hv, behaviour_t::THROWS); }
SECTION(
"CV"
) { Test::noinc((SV*)vars.cv, behaviour_t::THROWS); }
SECTION(
"GV"
) { Test::noinc((SV*)vars.gv, behaviour_t::THROWS); }
SECTION(
"IO"
) { Test::noinc((SV*)vars.io, behaviour_t::THROWS); }
}
SECTION(
"format"
) {
Simple obj = Simple::format(
"pi = %0.2f"
, 3.14157);
REQUIRE(obj.as_string() ==
"pi = 3.14"
);
}
SECTION(
"operator="
) {
Simple o(10);
SECTION(
"SV"
) {
SECTION(
"undef"
) { Test::assign(o, vars.undef, behaviour_t::VALID); }
SECTION(
"number"
) { Test::assign(o, vars.iv, behaviour_t::VALID); }
SECTION(
"string"
) { Test::assign(o, vars.pv, behaviour_t::VALID); }
SECTION(
"OSV"
) { Test::assign(o, vars.ov, behaviour_t::VALID); }
SECTION(
"RV"
) { Test::assign(o, vars.rv, behaviour_t::THROWS); }
SECTION(
"AV"
) { Test::assign(o, (SV*)vars.av, behaviour_t::THROWS); }
SECTION(
"HV"
) { Test::assign(o, (SV*)vars.hv, behaviour_t::THROWS); }
SECTION(
"CV"
) { Test::assign(o, (SV*)vars.cv, behaviour_t::THROWS); }
SECTION(
"GV"
) { Test::assign(o, (SV*)vars.gv, behaviour_t::THROWS); }
SECTION(
"IO"
) { Test::assign(o, (SV*)vars.io, behaviour_t::THROWS); }
}
SECTION(
"Simple"
) { 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(
"number"
) {
test_assign((int8_t)-5);
test_assign((int16_t)-30000);
test_assign((int32_t)1000000000);
if
(ivsize == 8) test_assign(9223372036854775807L);
test_assign((uint8_t)255);
test_assign((uint16_t)65535);
test_assign((uint32_t)4000000000);
if
(ivsize == 8) test_assign(18446744073709551615LU);
test_assign(5.5f);
test_assign(222222222.222222);
}
SECTION(
"char*"
) {
Simple obj(vars.iv);
obj =
"abcd"
;
REQUIRE(string_view(SvPVX(obj), 4) ==
"abcd"
);
REQUIRE(string_view(SvPVX(vars.iv), 4) ==
"abcd"
);
REQUIRE(SvCUR(obj) == 4);
REQUIRE(obj.is_string());
}
SECTION(
"string_view"
) {
Simple obj(vars.iv);
obj = string_view(
"abcd"
);
REQUIRE(string_view(SvPVX(obj), 4) ==
"abcd"
);
REQUIRE(string_view(SvPVX(vars.iv), 4) ==
"abcd"
);
REQUIRE(SvCUR(obj) == 4);
REQUIRE(obj.is_string());
}
}
SECTION(
"set"
) {
SECTION(
"number"
) {
test_set((int8_t)-5);
test_set((int16_t)-30000);
test_set((int32_t)1000000000);
if
(ivsize == 8) test_set(9223372036854775807L);
test_set((uint8_t)255);
test_set((uint16_t)65535);
test_set((uint32_t)4000000000);
if
(ivsize == 8) test_set(18446744073709551615LU);
test_set(5.5f);
test_set(222222222.222222);
}
SECTION(
"string"
) {
Simple o(
"xxxx"
);
o.set(
"abcd"
);
REQUIRE(o.is_string());
REQUIRE(string_view(SvPVX(o), 4) ==
"abcd"
);
REQUIRE(SvCUR(o) == 4);
o.set(string_view(
"suka blya"
));
REQUIRE(o.is_string());
REQUIRE(string_view(SvPVX(o), 9) ==
"suka blya"
);
REQUIRE(SvCUR(o) == 9);
}
}
SECTION(
"cast"
) {
SECTION(
"to number"
) {
test_cast((int8_t)-5);
test_cast((int16_t)-30000);
test_cast((int32_t)1000000000);
if
(ivsize == 8) test_cast(9223372036854775807L);
test_cast((uint8_t)255);
test_cast((uint16_t)65535);
test_cast((uint32_t)4000000000);
if
(ivsize == 8) test_cast(18446744073709551615LU);
test_cast(5.5f);
test_cast(222222222.222222);
}
SECTION(
"to string_view"
) {
Simple o;
REQUIRE(o.c_str() ==
nullptr
);
REQUIRE((string_view)o == string_view());
o = Sv::create();
REQUIRE(
strlen
(o.c_str()) == 0);
REQUIRE((string_view)o == string_view());
const
char
* src =
"epta"
;
o = src;
REQUIRE(
strlen
(o.c_str()) == 4);
REQUIRE(!
strcmp
(o.c_str(), src));
REQUIRE(o.c_str() != src);
REQUIRE(
strlen
(o.get<
char
*>()) == 4);
REQUIRE(!
strcmp
(o.get<
char
*>(), src));
REQUIRE(o.get<
char
*>() != src);
REQUIRE((string_view)o == string_view(src));
REQUIRE(((string_view)o).data() != src);
}
SECTION(
"to SV"
) {
Simple o(vars.iv);
auto
cnt = SvREFCNT(vars.iv);
SV* r = o;
REQUIRE(r == vars.iv);
REQUIRE(SvREFCNT(vars.iv) == cnt);
}
}
SECTION(
"as_string"
) {
SECTION(
"string_view"
) { test_as_string<string_view>(); }
SECTION(
"std::string"
) { test_as_string<std::string>(); }
SECTION(
"panda::string"
) { test_as_string<panda::string>(); }
}
SECTION(
"get"
) {
SECTION(
"number"
) {
test_get((int8_t)-5);
test_get((int16_t)-30000);
test_get((int32_t)1000000000);
if
(ivsize == 8) test_get(9223372036854775807L);
test_get((uint8_t)255);
test_get((uint16_t)65535);
test_get((uint32_t)4000000000);
if
(ivsize == 8) test_get(18446744073709551615LU);
test_get(5.5f);
test_get(222222222.222222);
}
SECTION(
"string"
) {
Simple o(vars.pv);
REQUIRE(o.get<
char
*>() == SvPVX(vars.pv));
REQUIRE(o.get<string_view>() == string_view(
"hello"
));
REQUIRE(o.get<string_view>().data() == SvPVX(vars.pv));
}
SECTION(
"SV"
) {
Simple o(vars.iv);
auto
cnt = SvREFCNT(vars.iv);
REQUIRE(o.get<SV>() == vars.iv);
REQUIRE(SvREFCNT(vars.iv) == cnt);
}
}
SECTION(
"length"
) {
Simple o = vars.pv;
REQUIRE(o.length() == 5);
o.length(3);
REQUIRE(o.length() == 3);
REQUIRE((string_view)o ==
"hel"
);
}
SECTION(
"upgrade"
) {
Simple o = vars.iv;
o.upgrade(SVt_PVMG);
REQUIRE(o.type() == SVt_PVMG);
}
SECTION(
"capacity / create with capacity"
) {
Simple o = vars.pv;
REQUIRE(o.capacity() >= 6);
o = Simple::create(100);
REQUIRE(o.capacity() >= 100);
REQUIRE(o.length() == 0);
char
* buf = o.get<
char
*>();
*buf++ =
'j'
;
*buf++ =
'o'
;
*buf++ =
'p'
;
*buf++ =
'a'
;
*buf++ = 0;
o.length(4);
REQUIRE((string_view)o == string_view(
"jopa"
));
}
SECTION(
"shared"
) {
Simple o(
"str"
);
Simple o2(
"str"
);
REQUIRE(o.get<
char
*>() != o2.get<
char
*>());
o = Simple::shared(
"str"
);
o2 = Simple::shared(
"str"
);
REQUIRE(o.get<
char
*>() == o2.get<
char
*>());
}
SECTION(
"is_shared"
) {
Simple o;
REQUIRE(!o.is_shared());
o = Simple(
"hello"
);
REQUIRE(!o.is_shared());
o = Simple::shared(
"hello"
);
REQUIRE(o.is_shared());
}
SECTION(
"hek"
) {
auto
o = Simple::shared(
"world"
);
auto
hek = o.hek();
REQUIRE(string_view(HEK_KEY(hek), HEK_LEN(hek)) ==
"world"
);
}
SECTION(
"hash"
) {
Simple o;
REQUIRE(o.hash() == 0);
o =
"mystring"
;
U32 h;
PERL_HASH(h,
"mystring"
, 8);
REQUIRE(o.hash() == h);
}
SECTION(
"const operator[]"
) {
const
Simple o(
"hello world"
);
REQUIRE(o[0] ==
'h'
);
REQUIRE(o[10] ==
'd'
);
}
SECTION(
"operator[]"
) {
Simple o(
"hello world"
);
REQUIRE(o[0] ==
'h'
);
REQUIRE(o[10] ==
'd'
);
o[10] =
's'
;
REQUIRE(o[10] ==
's'
);
REQUIRE(o.get<string_view>() == string_view(
"hello worls"
));
}
SECTION(
"at"
) {
SECTION(
"string"
) {
Simple o(
"hello world"
);
REQUIRE(o.at(0) ==
'h'
);
REQUIRE(o.at(10) ==
'd'
);
REQUIRE_THROWS(o.at(11));
}
SECTION(
"empty obj"
) {
Simple o;
REQUIRE_THROWS(o.at(0));
}
SECTION(
"empty string"
) {
Simple o(
""
);
REQUIRE_THROWS(o.at(0));
}
SECTION(
"number"
) {
Simple o(100);
REQUIRE(o.at(0) ==
'1'
);
}
}
SECTION(
"LV"
) {
auto
lv = SvREFCNT_inc(SvRV(eval_pv(
"\\substr('suka', 1, 2)"
, 1)));
SECTION(
"detached to a value"
) {
auto
val = Simple(lv);
CHECK(SvTYPE(val.get()) != SVt_PVLV);
CHECK(val.as_string() ==
"uk"
);
}
SECTION(
"refcnt"
) {
auto
rcnt = SvREFCNT(lv);
auto
val = Simple(lv);
CHECK(SvREFCNT(lv) == rcnt);
SvREFCNT_inc(lv);
rcnt = SvREFCNT(lv);
auto
val2 = Simple::noinc(lv);
CHECK(SvREFCNT(lv) == rcnt - 1);
}
SvREFCNT_dec(lv);
}
}