#include #include #include #include #include #include #include #include #include #include #include //#include "../examples/libc99/libc99.h" #include "../src/prototype.hh" void test_getters(int* c_int_p, pEp::POD& pint, int expected) { // pEpLog("to_string(): " + pint.to_string()); // compare addresses pEpLog("addresses == c_int_p"); assert(pint.c_data() == c_int_p); assert(pint.data() == c_int_p); // compare values if (c_int_p != nullptr) { pEpLog("operator int(): " + std::to_string(pint)); assert(pint == *c_int_p); assert(pint == expected); // will segfault with nullptr, and this is correct pEpLog("data(): " + std::to_string(*pint.data())); assert(*pint.data() == *c_int_p); assert(*pint.data() == expected); pEpLog("c_data(): " + std::to_string(*pint.c_data())); assert(*pint.c_data() == *c_int_p); assert(*pint.c_data() == expected); } } void test_assign(int* c_int_p, pEp::POD& pint) { { pEpLogH2("assign operator"); int new_val = 23; pint = new_val; test_getters(c_int_p, pint, new_val); } { pEpLogH2("raw c_str assign"); int new_val = 23; *c_int_p = new_val; test_getters(c_int_p, pint, new_val); } } void test_getters(char** c_str_p, pEp::String& pstr, const std::string& expected) { pEpLog("to_string(): " + pstr.to_string()); // compare addresses pEpLog("addresses == c_str_p"); assert(pstr.c_data() == *c_str_p); assert(pstr.obj() == c_str_p); // compare values if (*c_str_p != nullptr) { pEpLog("operator std::string(): " + std::string(pstr)); assert(std::string(pstr) == std::string(*c_str_p)); assert(std::string(pstr) == expected); // will segfault with nullptr, and this is correct pEpLog("data(): " + std::string(*pstr.obj())); assert(std::string(*pstr.obj()) == std::string(*c_str_p)); assert(std::string(*pstr.obj()) == expected); pEpLog("c_data(): " + std::string(pstr.c_data())); assert(std::string(pstr.c_data()) == std::string(*c_str_p)); assert(std::string(pstr.c_data()) == expected); } else { std::string tmp{ pstr }; pEpLog("operator std::string(): " + tmp); assert(tmp.empty()); } } void test_assign(char** c_str_p, pEp::String& pstr) { { pEpLogH2("assign operator"); std::string new_val{ "assign operator" }; pstr = new_val; test_getters(c_str_p, pstr, new_val); } { pEpLogH2("raw c_str assign"); std::string new_val{ "raw c_str assign" }; free(*c_str_p); *c_str_p = strdup(new_val.c_str()); test_getters(c_str_p, pstr, new_val); } } //void test_func1(char** out) { // *out = strdup("fds"); //} int main() { // c-types are always POD // we need to handle pointer types and value types differently // pointer types need to be memory-managed (heap) // value types are being copied around (stack) static_assert(std::is_pod::value && !std::is_pointer::value, "not an integral"); static_assert( std::is_pod<::C99_Enum>::value && !std::is_pointer<::C99_Enum>::value, "not an integral"); static_assert(std::is_pod<::C99_B>::value && !std::is_pointer<::C99_B>::value, "not an integral"); // pEp::Utils::readKey(); pEp::Adapter::pEpLog::set_enabled(true); // char* tmp = strdup("fd"); // std::cout << pEp::CXX::Inspect::all(tmp) << std::endl; // change_ptr(tmp); // std::cout << pEp::CXX::Inspect::all(tmp) << std::endl; // char *ht; // pEp::String tmp1{true,&ht}; // // test_func1(tmp1); // std::cout << tmp1; // POD if (0) { // VALID USAGE int init_val = 0; // new pEp::POD on int { pEpLogH1("new pEp::POD on int"); int c_int = init_val; pEp::POD pint(&c_int); test_getters(&c_int, pint, init_val); test_assign(&c_int, pint); } // equality operator { pEpLogH1("equality operator"); int c_int1 = init_val; int c_int2 = init_val; pEp::POD pint1(&c_int1); pEp::POD pint2(&c_int2); assert(pint1 == pint2); c_int2 = 23; assert(pint1 != pint2); } } // String // pEp::String::log_enabled = false; if (0) { //TODO: Test non-owning mode // // INVALID USAGE // char* c_str_u; // uninitialized == INVALID // undefined behaviour, most likely "pointer being freed was not allocated" // { // char* c_str; // pEp::String pstr(c_str); // } // char* c_str_s = "fdsfs"; // statically initialized == INVALID // { // char ca[4] = { 'p', 'E', 'p'}; // char* c_str = ca; // pEp::String pstr(c_str); // } // VALID USAGE { pEpLogH1("new pEp::String on char* pointing to NULL"); char* c_str = NULL; // nullptr pEp::String pstr(&c_str); test_getters(&c_str, pstr, ""); test_assign(&c_str, pstr); } std::string init_val{ "initialized c string" }; { pEpLogH1("new pEp::String on already initalized char*"); char* c_str = strdup(init_val.c_str()); pEp::String pstr(&c_str); test_getters(&c_str, pstr, init_val); test_assign(&c_str, pstr); } // equality operator { pEpLogH1("equality operator"); char* c_str1 = strdup(init_val.c_str()); char* c_str2 = strdup(init_val.c_str()); pEp::String pstr1{ &c_str1 }; pEp::String pstr2{ &c_str2 }; assert(pstr1 == pstr2); pstr2 = "huhu"; assert(pstr1 != pstr2); } } if (1) { pEpLogH2("Create a sleeve and an instance"); int i = 23; pEp::Sleeve ot_i{ i }; pEpLog(pEp::CXX::Inspect::all(i)); pEpLog(ot_i.to_string()); assert(ot_i == i); assert(!ot_i.is(i)); pEpLogH3("change from C++ / POTS"); pEp::Sleeve i_pots{42}; ot_i = i_pots; assert(ot_i == i_pots); assert(!ot_i.is(i_pots)); pEpLogH3("change from C++ / native"); int i_native = 23; ot_i = i_native; assert(ot_i == i_native); assert(!ot_i.is(i_native)); pEpLogH3("change from C99"); i = 42; int* pi = ot_i.obj_ptr(); *pi = i; assert(ot_i == i); assert(!ot_i.is(i)); } if (1) { pEpLogH2("create a sleeve on an instance, static"); int i{ 23 }; pEp::Sleeve ot_i{ &i }; pEpLog(pEp::CXX::Inspect::all(i)); pEpLog(ot_i.to_string()); assert(ot_i == i); assert(ot_i.is(i)); pEpLogH3("change from C++ / POTS"); pEp::Sleeve i_pots{42}; ot_i = i_pots; assert(ot_i == i_pots); assert(!ot_i.is(i_pots)); pEpLogH3("change from C++ / native"); int i_native = 23; ot_i = i_native; assert(ot_i == i_native); assert(!ot_i.is(i_native)); pEpLogH3("change from C99"); i = 42; int* pi = ot_i.obj_ptr(); *pi = i; assert(ot_i == i); assert(ot_i.is(i)); } if (1) { pEpLogH2("create a sleeve on an instance, dynamic"); int i{ 23 }; pEp::Sleeve ot_i{ [&i](){ return &i;} }; pEpLog(pEp::CXX::Inspect::all(i)); pEpLog(ot_i.to_string()); assert(ot_i == i); assert(ot_i.is(i)); pEpLogH3("change from C++ / POTS"); pEp::Sleeve i_pots{42}; ot_i = i_pots; assert(ot_i == i_pots); assert(!ot_i.is(i_pots)); pEpLogH3("change from C++ / native"); int i_native = 23; ot_i = i_native; assert(ot_i == i_native); assert(!ot_i.is(i_native)); pEpLogH3("change from C99"); i = 42; int* pi = ot_i.obj_ptr(); *pi = i; assert(ot_i == i); assert(ot_i.is(i)); } // Struct /* if (0) { // sleeve empty { pEp::Sleeve<::B> pstruct1{ nullptr }; const B* cc_struct = pstruct1; B* c_struct = pstruct1; assert(pstruct1.data() == nullptr); assert(pstruct1.c_data() == nullptr); assert(c_struct == nullptr); assert(cc_struct == nullptr); pEpLog("DONE"); // return_struct(pstruct1); } // Creates a sleeve managing and holding a newly created object { pEp::Sleeve<::B> pstruct1{}; B* c_struct = pstruct1; c_struct->c_int = 3; c_struct->c_str = std::string("huhu").data(); c_struct->c_enum = TWO; pEpLog("DONE"); } // Create a sleeve managing and holding an already existing object { // create an object ::B* c_struct1 = ::new_B(0, ONE, "pEp"); pEpLog(c_struct1->c_int); pEpLog(c_struct1->c_enum); pEpLog(c_struct1->c_str); pEpLog("DONE"); // reference the object pEp::Sleeve<::B> pstruct1{ c_struct1 }; pEpLog("DONE"); } // Create a sleeve managing a C-sleeve { B* c_struct = nullptr; pEp::Sleeve<::B> pstruct1{ &c_struct }; // c_struct->c_str = strdup("pEp"); // c_struct->c_int = 5; // c_struct->c_enum = TWO; } } */ // Calling conventions // pEp::Utils::readKey(); // { // pEpLogH1("use_struct()"); // { // pEp::A a{}; // use_struct(a); // } // pEpLogH1("c99_supply_struct()"); // { // int val = 23; // // C99 // { // // prepare data structure // ::C99_A* c_a = ::c99_A_new(); // c_a->b = c99_B_new(); // c_a->b->c = c99_C_new(); // c_a->b->c->pi = (int*)calloc(1, sizeof(int)); // *c_a->b->c->pi = val; // // // call supply // ::C99_Status status = c99_supply_struct(c_a); // // // test // assert(!status); // assert(*c_a->b->c->pi == val * 2); // } // C++ { // a = b; // b = 5 // a.b = pEp::B{}; // a.b.c = pEp::C{}; // a.b.c.pi = (int*)calloc(1, sizeof(int)); // a.b.c.pi = 23; // ::Status status = supply_struct(a); // test // assert(!status); // assert(*a.b.c.pi == val * 2); } // pstruct1.c_int // } // pEpLogH1("provide_struct()"); // { // pEp::A a{}; // //release ownership // provide_struct(a); // } // pEpLogH1("return_struct()"); // { // A* a = NULL; // return_struct(&a); // pEp::A pa{ a }; // pEpLog(*(pa.b.c.pi.data())); // } // } return 0; }