From fdfff0c5c5fd1f0c48ea56152e2fc2193e47a7fc Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 9 Oct 2021 16:55:51 +0200 Subject: [PATCH] Add framework to test containers againts C++ library --- tests/Makefile | 14 +- tests/check-array.cpp | 61 ++++++ tests/check-deque.cpp | 68 +++++++ tests/check-dplist.cpp | 71 +++++++ tests/check-generic.hpp | 421 ++++++++++++++++++++++++++++++++++++++++ tests/check-list.cpp | 73 +++++++ 6 files changed, 703 insertions(+), 5 deletions(-) create mode 100644 tests/check-array.cpp create mode 100644 tests/check-deque.cpp create mode 100644 tests/check-dplist.cpp create mode 100644 tests/check-generic.hpp create mode 100644 tests/check-list.cpp diff --git a/tests/Makefile b/tests/Makefile index 2e642a69..5b9cef93 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -21,6 +21,7 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. CC=cc -std=c99 +CXX=c++ -std=c++11 WCFLAGS_GCC=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -Wdate-time -Wconversion -Wformat=2 -Winit-self -Wjump-misses-init -Wstack-protector -Wtrampolines -Wwrite-strings -Wformat-security -Wno-float-conversion -O WCFLAGS_CLANG=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wold-style-definition -Wunused-function -ftrapv -Wsign-conversion -O WCFLAGS_CPP=-Wall -W -pedantic -Wshadow -Wpointer-arith -Wcast-qual -Wswitch-default -Wswitch-enum -Wcast-align -Wpointer-arith -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wshadow -Wunreachable-code -Wstrict-aliasing=2 -Wredundant-decls -Wunused-function -ftrapv -Wsign-conversion @@ -44,12 +45,15 @@ all: .POSIX: .PHONY: scan-build sanitize check clean *.log coverage synthesis .SUFFIXES: -.SUFFIXES: .c .exe .log .depend .gcov .analyzer +.SUFFIXES: .c .exe .log .depend .gcov .analyzer .cpp .SECONDARY: .c.exe: $(CC) $(CFLAGS) $(CPPFLAGS) -g $(LDFLAGS) $< -o $@ +.cpp.exe: + $(CXX) $(WCFLAGS_CPP) $(XCFLAGS) $(CPPFLAGS) -g $(LDFLAGS) $< -o $@ + .c.depend: $(CC) $(CFLAGS) $(CPPFLAGS) -MM -MT `echo $< |$(SED) 's/\.c/\.exe/g'` $< > $@ @@ -82,14 +86,14 @@ depend: # Clean ##################################################################################################### -exe: depend - $(MAKE) `ls test-*.c|$(SED) 's/\.c/\.exe/g'` CC="$(CC)" CFLAGS="$(CFLAGS)" - @echo All executable generated - check: depend $(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'` CC="$(CC)" CFLAGS="$(CFLAGS)" @echo All tests passed +check-stl: depend + $(MAKE) `ls check-*.cpp|$(SED) 's/\.cpp/\.log/g'` CXX="$(CXX)" XCFLAGS="-O2 -fsanitize=address,undefined,leak -Wno-sign-conversion -Wno-inline" + @echo All comparison against C++ STL passed + clean: $(RM) *.exe *.s *~ *.o *.log a*.dat $(RM) *.gcda *.gcno *.gcov all.info test.tar *.synt clang_output_* *.c.c *.end.c *.first.c *.middle.c *.analyzer diff --git a/tests/check-array.cpp b/tests/check-array.cpp new file mode 100644 index 00000000..b3337b82 --- /dev/null +++ b/tests/check-array.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include "m-array.h" + +ARRAY_DEF(array_int, int) + +// Transform an integer 'i' into a M*LIB base item 'a' +#define TYPE_SET_INT(a, i) (a) = (i) + +// Container OPLIST +#define CONT_OPL ARRAY_OPLIST(array_int, M_OPL_int()) + +// C++ Base class of the item in the container +#define BASE_CLASS int + +// Transform an integer 'i' into a C++ base item 'a' +#define CLASS_SET_INT(a, i) (a) = (i) + +// C++ Container class +#define CONT_CLASS std::vector + +// Compare the M*LIB container a to the C++ container b +#define CMP_CONT(a, b) cmp_cont(a, b) + +// Compate the M*LIB base object to the C++ base object +#define CMP_BASE(a, b) assert( (a) == (b) ) + +void cmp_cont(array_int_t a, std::vector b) +{ + size_t s = array_int_size(a); + assert (s == b.size()); + for(size_t i = 0; i < s; i++) { + int *b0 = array_int_get(a, i); + int &b1 = b.at(i); + CMP_BASE(*b0, b1); + } +} + +#define DEFAULT_NUMBER 1000000 +#include "check-generic.hpp" diff --git a/tests/check-deque.cpp b/tests/check-deque.cpp new file mode 100644 index 00000000..57374574 --- /dev/null +++ b/tests/check-deque.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include "m-deque.h" + +DEQUE_DEF(deque_float, float) + +// Transform an integer 'i' into a M*LIB base item 'a' +#define TYPE_SET_INT(a, i) (a) = (i) + +// Container OPLIST +#define CONT_OPL DEQUE_OPLIST(deque_float, M_OPL_float()) + +// C++ Base class of the item in the container +#define BASE_CLASS float + +// Transform an integer 'i' into a C++ base item 'a' +#define CLASS_SET_INT(a, i) (a) = (i) + +// C++ Container class +#define CONT_CLASS std::deque + +// Compare the M*LIB container a to the C++ container b +#define CMP_CONT(a, b) cmp_cont(a, b) + +// Compate the M*LIB base object to the C++ base object +#define CMP_BASE(a, b) assert( (a) == (b) ) + +void cmp_cont(deque_float_t a, std::deque b) +{ + deque_float_it_t ita; + deque_float_it(ita, a); + auto itb = b.begin(); + while (itb != b.end()) { + assert(!deque_float_end_p(ita)); + const float *b0 = deque_float_cref(ita); + float &b1 = *itb; + CMP_BASE(*b0, b1); + itb++; + deque_float_next(ita); + } + assert(deque_float_end_p(ita)); +} + +#define DEFAULT_NUMBER 1000000 +#define HAVE_PUSH_FRONT +#define HAVE_POP_FRONT +#include "check-generic.hpp" diff --git a/tests/check-dplist.cpp b/tests/check-dplist.cpp new file mode 100644 index 00000000..867ff6e4 --- /dev/null +++ b/tests/check-dplist.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include "m-list.h" + +LIST_DUAL_PUSH_DEF(list_int, int) + +// Transform an integer 'i' into a M*LIB base item 'a' +#define TYPE_SET_INT(a, i) (a) = (i) + +// Container OPLIST +#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int()) + +// C++ Base class of the item in the container +#define BASE_CLASS int + +// Transform an integer 'i' into a C++ base item 'a' +#define CLASS_SET_INT(a, i) (a) = (i) + +// C++ Container class +#define CONT_CLASS std::list + +// Compare the M*LIB container a to the C++ container b +#define CMP_CONT(a, b) cmp_cont(a, b) + +// Compate the M*LIB base object to the C++ base object +#define CMP_BASE(a, b) assert( (a) == (b) ) + +void cmp_cont(const list_int_t a, const std::list &b) +{ + list_int_it_t ita; + list_int_it(ita, a); + auto itb = b.rbegin(); + while (itb != b.rend()) { + assert(!list_int_end_p(ita)); + const int *b0 = list_int_cref(ita); + const int &b1 = *itb; + //printf("%d VS %d\n", *b0, b1); + CMP_BASE(*b0, b1); + itb++; + list_int_next(ita); + } + assert(list_int_end_p(ita)); +} + +#define DEFAULT_NUMBER 100000 + +#define HAVE_PUSH_FRONT +#define HAVE_REVERSE_IT + +#include "check-generic.hpp" diff --git a/tests/check-generic.hpp b/tests/check-generic.hpp new file mode 100644 index 00000000..ff279993 --- /dev/null +++ b/tests/check-generic.hpp @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2021, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include + +/* This test will perform random generic operations on the + M*LIB container and compares it to the same operation on the + C++ equivalent container. + If there are some differences, it reports an error. + It is therefore quite generic and based on the properties of the container +*/ + +/* Get the types from the container oplist if needed */ +#ifndef CONT_TYPE +# define CONT_TYPE_(CONT_OPL) M_GET_TYPE CONT_OPL +# define CONT_TYPE CONT_TYPE_(CONT_OPL) +#endif +#ifndef BASE_TYPE +# define BASE_TYPE_(CONT_OPL) M_GET_SUBTYPE CONT_OPL +# define BASE_TYPE BASE_TYPE_(CONT_OPL) +#endif + +#define CONT_NAME_(CONT_OPL) M_GET_NAME CONT_OPL +#define CONT_NAME CONT_NAME_(CONT_OPL) + +#define MAX_TEST 25 + +#ifdef HAVE_REVERSE_IT +// Scan the C++ sequence in reverse +# define begin rbegin +# define end rend +# define IT(x) std::prev(x.base(), 1) +#else +# define IT(x) x +#endif + +volatile int test_case; + +void test(int select_test, int index, + BASE_TYPE &b0, BASE_CLASS &b1, CONT_TYPE &c0, CONT_CLASS &c1) +{ + bool p0 = false, p1 = false; + size_t s0 = 0, s1 = 0; + CONT_TYPE tmp; +#if M_TEST_METHOD_P(IT_TYPE, CONT_OPL) + M_ID(M_GET_IT_TYPE CONT_OPL) it0; + auto it1 = c1.begin(); +#endif + + // Save in a volatile variable the last test for debug purpose + test_case = select_test % MAX_TEST; +#ifdef DEBUG + printf("Case=%d\n", test_case); +#endif + switch (test_case) { +#if M_TEST_METHOD_P(PUSH, CONT_OPL) + case 0: + TYPE_SET_INT(b0, index); + CLASS_SET_INT(b1, index); + M_CALL_PUSH(CONT_OPL, c0, b0); + c1.push_back(b1); + break; + + case 1: + index = index % 1000; + for(int i = 0; i < index; i++) { + TYPE_SET_INT(b0, i); + CLASS_SET_INT(b1, i); + M_CALL_PUSH(CONT_OPL, c0, b0); + c1.push_back(b1); + } + break; +#endif + +#if M_TEST_METHOD_P(POP, CONT_OPL) + case 2: + if (!c1.empty()) { + M_CALL_POP(CONT_OPL, &b0, c0); + b1 = c1.back(); + c1.pop_back(); + } + break; +#endif + +#if M_TEST_METHOD_P(EMPTY_P, CONT_OPL) + case 3: + p0 = M_CALL_EMPTY_P(CONT_OPL, c0); + p1 = c1.empty(); + break; +#endif + +#if M_TEST_METHOD_P(SIZE, CONT_OPL) + case 4: + s0 = M_CALL_SIZE(CONT_OPL, c0); + s1 = c1.size(); + break; +#endif + +#if M_TEST_METHOD_P(CLEAN, CONT_OPL) + case 5: + M_CALL_CLEAN(CONT_OPL, c0); + c1.clear(); + break; +#endif + +#if M_TEST_METHOD_P(GET_KEY, CONT_OPL) + case 6: + if (!c1.empty()) { + // To rework for dict + index = index % c1.size(); + M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_GET_KEY(CONT_OPL, c0, index)); + b1 = c1[index]; + } + break; +#endif + +#if M_TEST_METHOD_P(SET_KEY, CONT_OPL) + case 7: + if (!c1.empty()) { + TYPE_SET_INT(b0, index); + CLASS_SET_INT(b1, index); + index = index % c1.size(); + M_CALL_SET_KEY(CONT_OPL, c0, index, b0); + c1[index] = b1; + } + break; +#endif + +#if M_TEST_METHOD_P(ERASE_KEY, CONT_OPL) + case 8: + if (!c1.empty()) { + index = index % c1.size(); + p0 = M_CALL_ERASE_KEY(CONT_OPL, c0, index); + c1.erase(c1.begin() + index); + p1 = true; + } + break; +#endif + +#if M_TEST_METHOD_P(SET, CONT_OPL) && M_TEST_METHOD_P(INIT_SET, CONT_OPL) + case 9: + M_CALL_INIT_SET(CONT_OPL, tmp, c0); +#if M_TEST_METHOD_P(EQUAL_P, CONT_OPL) + assert( M_CALL_EQUAL_P(CONT_OPL, tmp, c0) ); +#endif + M_CALL_SET(CONT_OPL, c0, tmp); + M_CALL_CLEAR(CONT_OPL, tmp); + break; +#endif + +#if M_TEST_METHOD_P(INIT_MOVE, CONT_OPL) + case 10: + M_CALL_INIT_MOVE(CONT_OPL, tmp, c0); + M_CALL_INIT_MOVE(CONT_OPL, c0, tmp); + break; +#endif + +#if M_TEST_METHOD_P(MOVE, CONT_OPL) && M_TEST_METHOD_P(INIT_MOVE, CONT_OPL) + case 11: + M_CALL_INIT_SET(CONT_OPL, tmp, c0); + M_CALL_MOVE(CONT_OPL, tmp, c0); + M_CALL_INIT_MOVE(CONT_OPL, c0, tmp); + break; +#endif + +#if M_TEST_METHOD_P(SWAP, CONT_OPL) && M_TEST_METHOD_P(GET_SIZE, CONT_OPL) + case 12: + s0 = M_CALL_GET_SIZE(CONT_OPL, c0); + M_CALL_INIT(CONT_OPL, tmp); + M_CALL_SWAP(CONT_OPL, tmp, c0); + s1 = M_CALL_GET_SIZE(CONT_OPL, tmp); + M_CALL_SWAP(CONT_OPL, tmp, c0); + M_CALL_CLEAR(CONT_OPL, tmp); + break; + case 13: + M_CALL_INIT_SET(CONT_OPL, tmp, c0); + M_CALL_SWAP(CONT_OPL, tmp, c0); + M_CALL_CLEAR(CONT_OPL, tmp); + break; +#endif + +#if M_TEST_METHOD_P(GET_SET_KEY, CONT_OPL) + case 14: + // To rework for dict + index = (1 + (c1.size() < 1000000)) * (index % ( c1.size() + 1) ); + M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_GET_SET_KEY(CONT_OPL, c0, index)); + if ((size_t) index >= c1.size() ) { + c1.resize(index+1); + } + b1 = c1[index]; + break; +#endif + +#if M_TEST_METHOD_P(IT_CREF, CONT_OPL) + case 15: + M_CALL_IT_FIRST(CONT_OPL, it0, c0); + it1 = c1.begin(); + while (it1 != c1.end()) { + assert( !M_CALL_IT_END_P(CONT_OPL, it0)); + M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0)); + b1 = *it1; + CMP_BASE(b0, b1); + M_CALL_IT_NEXT(CONT_OPL, it0); + it1++; + } + assert(M_CALL_IT_END_P(CONT_OPL, it0)); + break; +#endif + +#if M_TEST_METHOD_P(IT_REF, CONT_OPL) + case 16: + M_CALL_IT_FIRST(CONT_OPL, it0, c0); + it1 = c1.begin(); + while (it1 != c1.end()) { + assert( !M_CALL_IT_END_P(CONT_OPL, it0)); + TYPE_SET_INT(b0, index); + CLASS_SET_INT(b1, index); + M_CALL_SET(M_GET_OPLIST CONT_OPL, *M_CALL_IT_REF(CONT_OPL, it0), b0); + *it1 = b1; + M_CALL_IT_NEXT(CONT_OPL, it0); + it1++; + index = 1457857U * index + 458741U; + } + assert(M_CALL_IT_END_P(CONT_OPL, it0)); + break; +#endif + +#if M_TEST_METHOD_P(IT_LAST, CONT_OPL) + case 17: + { + M_CALL_IT_LAST(CONT_OPL, it0, c0); + auto it1b = c1.rbegin(); + while (it1b != c1.rend()) { + assert( !M_CALL_IT_END_P(CONT_OPL, it0)); + M_CALL_SET(M_GET_OPLIST CONT_OPL, b0, *M_CALL_IT_CREF(CONT_OPL, it0)); + b1 = *it1b; + CMP_BASE(b0, b1); + M_CALL_IT_PREVIOUS(CONT_OPL, it0); + it1b++; + } + assert(M_CALL_IT_END_P(CONT_OPL, it0)); + } + break; +#endif + +#if M_TEST_METHOD_P(IT_INSERT, CONT_OPL) + case 18: + M_CALL_IT_FIRST(CONT_OPL, it0, c0); + it1 = c1.begin(); + TYPE_SET_INT(b0, index); + CLASS_SET_INT(b1, index); +#ifdef HAVE_INSERT_AFTER + while (it1 != c1.end() ) { + if (rand() > index) + break; + M_CALL_IT_NEXT(CONT_OPL, it0); + it1++; + } + if (it1 != c1.end() ) { + M_CALL_IT_INSERT(CONT_OPL, c0, it0, b0); + c1.insert_after(it1, b1); + } +#else + if (!c1.empty() ){ + index = index % c1.size(); + if (index == 0) { + M_CALL_IT_END(CONT_OPL, it0, c0); + } else { + for(int i = 0; i < index; i++) { + assert( it1 != c1.end()); + assert( !M_CALL_IT_END_P(CONT_OPL, it0)); + M_CALL_IT_NEXT(CONT_OPL, it0); + it1++; + } + it1++; + } + } + M_CALL_IT_INSERT(CONT_OPL, c0, it0, b0); +#ifdef HAVE_REVERSE_IT + // in cases of reverse iterator, fix iterator. + it1 = std::prev(it1, 1); +#endif + c1.insert(IT(it1), b1); +#endif + break; +#endif + +#if M_TEST_METHOD_P(IT_REMOVE, CONT_OPL) + case 19: + M_CALL_IT_FIRST(CONT_OPL, it0, c0); + it1 = c1.begin(); +#ifdef HAVE_ERASE_AFTER + while (it1 != c1.end() ) { + M_CALL_IT_NEXT(CONT_OPL, it0); + if (rand() > index) + break; + it1++; + } + if (it1 != c1.end() && !M_CALL_IT_END_P(CONT_OPL, it0) ) { + M_CALL_IT_REMOVE(CONT_OPL, c0, it0); + c1.erase_after(it1); + } +#else + if (!c1.empty() ){ + index = index % c1.size(); + for(int i = 0; i < index; i++) { + assert( it1 != c1.end()); + assert( !M_CALL_IT_END_P(CONT_OPL, it0)); + M_CALL_IT_NEXT(CONT_OPL, it0); + it1++; + } + M_CALL_IT_REMOVE(CONT_OPL, c0, it0); + c1.erase(IT(it1)); + } +#endif + break; +#endif + +#if M_TEST_METHOD_P(REVERSE, CONT_OPL) + case 20: + M_CALL_REVERSE(CONT_OPL, c0); + c1.reverse(); + break; +#endif + +#if M_TEST_METHOD_P(SPLICE_BACK, CONT_OPL) + case 21: + M_CALL_REVERSE(CONT_OPL, c0); + c1.reverse(); + break; +#endif + +#ifdef HAVE_PUSH_FRONT + case 22: + TYPE_SET_INT(b0, index); + CLASS_SET_INT(b1, index); + M_C(CONT_NAME, _push_front)(c0, b0); + c1.push_front(b1); + break; + + case 23: + index = index % 1000; + for(int i = 0; i < index; i++) { + TYPE_SET_INT(b0, i); + CLASS_SET_INT(b1, i); + M_C(CONT_NAME, _push_front)(c0, b0); + c1.push_front(b1); + } + break; +#endif + +#ifdef HAVE_POP_FRONT + case 24: + if (!c1.empty()) { + M_C(CONT_NAME, _pop_front)(&b0, c0); + b1 = c1.front(); + c1.pop_front(); + } + break; +#endif + + // SPLICE_BACK + // SPLICE_AT + // Needs SPLICE ? + + default: + // Nothing to do + break; + } + CMP_BASE(b0, b1); + CMP_CONT(c0, c1); + assert(p0 == p1); + assert(s0 == s1); +} + + +int main(int argc, const char *argv[]) +{ + int loop = argc >= 2 ? atoi(argv[1]) : DEFAULT_NUMBER; + + BASE_TYPE b0; + BASE_CLASS b1; + CONT_TYPE c0; + CONT_CLASS c1; + + M_CALL_INIT(CONT_OPL, c0); + M_CALL_INIT(M_GET_OPLIST CONT_OPL, b0); + TYPE_SET_INT(b0, 0); + CLASS_SET_INT(b1, 0); + + for(int i = 0; i < loop; i++) { + int t = rand(); + int s = rand(); + test(t, s, b0, b1, c0, c1); + } + + M_CALL_CLEAR(M_GET_OPLIST CONT_OPL, b0); + M_CALL_CLEAR(CONT_OPL, c0); + return 0; +} diff --git a/tests/check-list.cpp b/tests/check-list.cpp new file mode 100644 index 00000000..f853204c --- /dev/null +++ b/tests/check-list.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include "m-list.h" + +LIST_DEF(list_int, int) + +// Transform an integer 'i' into a M*LIB base item 'a' +#define TYPE_SET_INT(a, i) (a) = (i) + +// Container OPLIST +#define CONT_OPL LIST_OPLIST(list_int, M_OPL_int()) + +// C++ Base class of the item in the container +#define BASE_CLASS int + +// Transform an integer 'i' into a C++ base item 'a' +#define CLASS_SET_INT(a, i) (a) = (i) + +// C++ Container class +#define CONT_CLASS std::forward_list + +// Compare the M*LIB container a to the C++ container b +#define CMP_CONT(a, b) cmp_cont(a, b) + +// Compate the M*LIB base object to the C++ base object +#define CMP_BASE(a, b) assert( (a) == (b) ) + +void cmp_cont(list_int_t a, std::forward_list b) +{ + list_int_it_t ita; + list_int_it(ita, a); + auto itb = b.begin(); + while (itb != b.end()) { + assert(!list_int_end_p(ita)); + const int *b0 = list_int_cref(ita); + int &b1 = *itb; + CMP_BASE(*b0, b1); + itb++; + list_int_next(ita); + } + assert(list_int_end_p(ita)); +} + +#define HAVE_INSERT_AFTER +#define HAVE_ERASE_AFTER +#define DEFAULT_NUMBER 100000 + +// C++ forward_list pushs in front instead of in back +#define push_back push_front +#define pop_back pop_front +#define back front +#include "check-generic.hpp"