#include "test.h"
#include <panda/function.h>
#include <panda/function_utils.h>
#include <panda/refcnt.h>
#include <panda/string.h>
using
function_details::make_method;
using
function_details::tmp_abstract_function;
#define TEST(name) TEST_CASE("function: " name, "[function]")
namespace
test {
void
void_func(){}
void
void_func2(){}
void
func_int(
int
){}
void
func_int16(int16_t){}
void
func_double(
int
){}
int
foo2() {
return
1;}
int
plus_one(
int
a) {
return
a + 1;}
class
Test :
public
panda::Refcnt {
public
:
int
value = 0;
Test(
int
value) : value(value) {}
Test() : value(0) {}
void
foo(
int
) {}
void
foo2(
int
) {}
int
bar() {
return
value + 40;}
int
operator()(
int
v) {
return
v;}
bool
operator == (
const
Test& oth)
const
{
return
value == oth.value;}
};
}
using
namespace
test;
TEST(
"simplest function"
) {
function<
void
(
void
)> f = &void_func;
REQUIRE(
true
);
}
TEST(
"simplest function call"
) {
function<
int
(
int
)> f;
f = &plus_one;
REQUIRE(f(1) == 2);
}
TEST(
"function by reference call"
) {
function<
int
(
int
)> f;
f = plus_one;
REQUIRE(f(1) == 2);
}
TEST(
"simplest lambda call"
) {
int
a = 13;
function<
int
(
void
)> f = [&](){
return
a;};
REQUIRE(f() == 13);
}
TEST(
"simplest method call"
) {
iptr<Test> t =
new
Test();
t->value = 14;
auto
m = make_function(&Test::bar, t);
REQUIRE(m() == 54);
}
TEST(
"mixedcall"
) {
iptr<Test> t =
new
Test();
t->value = 14;
auto
f = make_function(&Test::bar, t);
REQUIRE(f() == 54);
f = &foo2;
REQUIRE(f() == 1);
int
a = 13;
f = [&](){
return
a;};
REQUIRE(f() == 13);
}
TEST(
"function ptr comparations"
) {
function<
void
(
void
)> f1_void = &void_func;
function<
void
(
void
)> f2_void = &void_func;
function<
void
(
void
)> f3_void = &void_func2;
REQUIRE(f1_void == f2_void);
REQUIRE(f1_void != f3_void);
REQUIRE(f1_void == tmp_abstract_function(&void_func));
REQUIRE(f1_void != tmp_abstract_function(&void_func2));
}
TEST(
"function ptr comparations covariant"
) {
struct
Int {
void
operator()(
int
) {}
bool
operator==(
const
Int&)
const
{
return
true
;
}
};
function<
void
(
int
)> f1(&func_int);
function<
void
(
double
)> f2(&func_int);
function<
void
(
double
)> f3(&func_double);
function<
void
(
double
)> f4(&func_int);
CHECK(f1 == f2);
CHECK(f1 != f3);
CHECK(f2 != f3);
CHECK(f2 == f4);
Int i;
function<
void
(
int
)> ff1(i);
function<
void
(
double
)> ff2(i);
CHECK(ff1 == ff2);
}
TEST(
"function covariant copy comparations"
) {
bool
called =
false
;
auto
lambda = [&](
int
a) {
called =
true
;
return
a;
};
function<
int
(int16_t)> f1 = lambda;
function<
int
(
int
)> f2(f1);
CHECK(f1 == f2);
CHECK(f2 == f1);
}
TEST(
"methods comparations"
) {
iptr<Test> t =
new
Test();
auto
m1 = make_function(&Test::foo, t);
auto
m2 = make_method(&Test::foo);
REQUIRE(m1 != *m2);
m2->bind(t);
REQUIRE(m1 == function<
void
(
int
)>(m2));
iptr<Test> t2 =
new
Test();
m2->bind(t2);
REQUIRE(m1 != *m2);
auto
m3 = make_method(&Test::foo2);
REQUIRE(m1 != *m3);
}
TEST(
"lambdas comparations"
) {
int
a = 10;
function<
int
(
void
)> l1 = [&](){
return
a;};
auto
l2 = l1;
function<
int
(
void
)> l3 = [&](){
return
a;};
REQUIRE(l1 == l2);
REQUIRE(l1 != l3);
}
TEST(
"mixed function comparations"
) {
int
a = 10;
function<
int
(
void
)> l = [&](){
return
a;};
function<
int
(
void
)> f = &foo2;
iptr<Test> t =
new
Test();
auto
m = make_function(&Test::bar, t);
REQUIRE(l != f);
REQUIRE(m != l);
REQUIRE(m != f);
}
TEST(
"null function comparations"
) {
int
a = 10;
function<
int
(
void
)> n;
function<
int
(
void
)> l = [&](){
return
a;};
function<
int
(
void
)> f = &foo2;
iptr<Test> t =
new
Test();
auto
m = make_function(&Test::bar, t);
REQUIRE_FALSE(l == n);
REQUIRE_FALSE(f == n);
REQUIRE_FALSE(m == n);
REQUIRE_FALSE(n == l);
REQUIRE_FALSE(n == f);
REQUIRE_FALSE(n == m);
}
TEST(
"functors comparations"
) {
function<
int
(
int
)> f1 = Test(1);
function<
int
(
int
)> f2 = Test(2);
function<
int
(
int
)> f11 = Test(1);
REQUIRE(f1 != f2);
REQUIRE(f1 == f11);
auto
tmp1 = tmp_abstract_function<
int
,
int
>(Test(1));
REQUIRE(f1 == tmp1);
}
TEST(
"function copy ellision"
) {
Tracer::refresh();
{
function<
int
(
int
)> f = Tracer(10);
auto
f2 = f;
f(11);
f2(12);
}
REQUIRE(Tracer::ctor_calls == 1);
REQUIRE(Tracer::copy_calls == 0);
REQUIRE(Tracer::move_calls == 1);
REQUIRE(Tracer::dtor_calls == 2);
}
TEST(
"covariant return type optional"
) {
function<panda::optional<
int
> (
int
)> cb = [](
int
a) ->
int
{
return
a;
};
REQUIRE(cb(3).value_or(42) == 3);
}
TEST(
"covariant return type double"
) {
function<
double
(
int
)> cb = [](
int
a) ->
int
{
return
a;
};
REQUIRE(cb(3) == 3.0);
}
TEST(
"contravariance of arguments"
) {
function<
double
(
int
)> cb = [](
double
) ->
int
{
return
10;
};
REQUIRE(cb(3) == 10);
}
struct
Base {
virtual
~Base(){}
virtual
panda::string name() {
return
"base"
;}
};
struct
Derrived : Base {
virtual
panda::string name() override {
return
"override"
;}
};
TEST(
"contravariance of arguments classes"
) {
using
panda::string;
function<Base& (Derrived&)> cb = [](Base& b) -> Base& {
return
b;
};
Derrived b;
REQUIRE(cb(b).name() == b.name());
}
function<
int
(
int
)> lamda() {
Tracer t(1);
auto
wrapper = [t](
int
a) ->
int
{
Tracer o = t;
return
a + 1;
};
return
wrapper;
}
TEST(
"function memory"
) {
Tracer::refresh();
{
auto
wrapper = lamda();
REQUIRE(wrapper(10) == 11);
}
REQUIRE(Tracer::ctor_total() == Tracer::dtor_calls);
}
TEST(
"lambda self reference"
) {
int
a = 1;
int
b;
function<
void
(
void
)> outer;
{
auto
inner = [=, &b](panda::Ifunction<
void
>& self)
mutable
{
if
(a == 1) {
a++;
self();;
}
else
{
b = 43;
}
};
outer = inner;
}
outer();
REQUIRE(b == 43);
}
TEST(
"no capture self reference"
) {
static
int
a = 0;
function<
void
(
int
)> outer;
{
auto
inner = [](panda::Ifunction<
void
,
int
>& self,
int
val) {
while
(
false
) {self(a);}
a = val;
};
outer = inner;
}
outer(1);
REQUIRE(a == 1);
}
TEST(
"function from null"
) {
void
(*fptr)();
fptr =
nullptr
;
function<
void
()> f = fptr;
REQUIRE(!f);
}
TEST(
"function from null method"
) {
auto
meth = &Test::bar;
meth =
nullptr
;
auto
m = make_function(meth);
REQUIRE(!m);
}
TEST(
"function from nullable object"
) {
struct
S {
void
operator()()
const
{}
explicit
operator
bool
()
const
{
return
val;
}
bool
val;
};
S s{
false
};
function<
void
()> f = s;
REQUIRE(!f);
s.val =
true
;
f = s;
REQUIRE(f);
}
TEST(
"lambda self reference gcc bug"
) {
struct
SomeStruct {
void
method(
int
val) {
function<
void
(
int
)> ff = [
this
](panda::Ifunction<
void
,
int
>&,
auto
... args)
mutable
{
this
->bar(args...);
};
ff(val);
}
void
bar(
int
val) {
a = val;
}
int
a = 10;
};
SomeStruct s;
s.method(20);
REQUIRE(s.a == 20);
}
TEST(
"lambda self reference auto..."
) {
int
a = 10;
function<
int
(
int
)> f = [&](
auto
...args) ->
int
{
static_assert
(
sizeof
...(args) == 1,
"auto... resolved as without SELF"
);
return
(a = 20) + 1;
};
int
b = f(42);
REQUIRE(a == 20);
REQUIRE(b == 21);
function<
int
(
int
)> f2 = [&](
auto
&&...args) ->
int
{
static_assert
(
sizeof
...(args) == 1,
"auto... resolved as without SELF"
);
return
111;
};
CHECK(f2(123) == 111);
function<
int
(
int
)> f3 = [&](
auto
&&...args) {
REQUIRE(
sizeof
...(args) == 1);
return
111;
};
CHECK(f3(123) == 111);
}