diff -b tree9/.gitignore treeA/.gitignore 3a4 > unittest diff -b tree9/Makefile treeA/Makefile 2,3c2 < # (added targets for 'make test' and 'make stocks') < # (added readlinep.o and readlinep.h) --- > # (unit testing) 5c4,5 < # David Kotz - April 2016, 2017 --- > # David Kotz - May 2016, April 2017 > # updated by Xia Zhou, July 2016 8c8 < CFLAGS = -Wall -pedantic -std=c11 -ggdb -DTESTING --- > CFLAGS = -Wall -pedantic -std=c11 -ggdb # -DTESTING 21c21 < .PHONY: test clean --- > .PHONY: test unittest unit clean 25a26,31 > unittest: tree.h tree.c > $(CC) $(CFLAGS) -DUNIT_TEST tree.c -o unittest > > unit: unittest > ./unittest > 32c38 < rm -rf $(PROG).dSYM --- > rm -rf *.dSYM 34a41 > rm -f unittest Only in tree9: diff89 Only in treeA: diff9A diff -b tree9/tree.c treeA/tree.c 3c3 < * (version 8: add malloc/free tracking) --- > * (version A: unit testing) 5c5 < * David Kotz - April 2016, 2017 --- > * David Kotz, April-May 2016, April 2017 229a230,397 > > /******************************************************** > **************** unit testing ************************** > ********************************************************/ > > #ifdef UNIT_TEST > > // Useful MACROS for controlling the unit tests. > > // each test should start by setting the result count to zero > #define START_TEST_CASE(name) int _failures=0; char *_testname = (name); > > // Check a condition; if false, print warning message. > // e.g., EXPECT(dict->start == NULL). > // note: the preprocessor > // converts __LINE__ into line number where this macro was used, and > // converts "#x" into a string constant for arg x. > #define EXPECT(x) \ > if (!(x)) { \ > _failures++; \ > printf("Fail %s Line %d: [%s]\n", _testname, __LINE__, #x); \ > } > > // return the result count at the end of a test > #define END_TEST_CASE \ > if (_failures == 0) { \ > printf("PASS test %s\n\n", _testname); \ > } else { \ > printf("FAIL test %s with %d errors\n\n", _testname, _failures); \ > } > > #define TEST_RESULT (_failures) > > ///////////////////////////////////// > // create and validate an empty tree > int test_newtree0() > { > START_TEST_CASE("newtree0"); > tree_t *tree = tree_new(NULL, NULL); > EXPECT(tree != NULL); > EXPECT(tree->root == NULL); > EXPECT(tree->itemprint == NULL); > EXPECT(tree->itemdelete == NULL); > > EXPECT(tree_find(tree, "hello") == NULL); > > tree_delete(tree); > EXPECT(nmalloc-nfree == 0); > > END_TEST_CASE; > return TEST_RESULT; > } > > ///////////////////////////////////// > // create and validate a tree with one item > int test_newtree1() > { > START_TEST_CASE("newtree1"); > tree_t *tree = tree_new(NULL, NULL); > EXPECT(tree != NULL); > int data = 5; > tree_insert(tree, "abcd", &data); > EXPECT(tree->root != NULL); > EXPECT(strcmp(tree->root->key, "abcd") == 0); > EXPECT(tree->root->data == &data); > EXPECT(tree->root->left == NULL); > EXPECT(tree->root->right == NULL); > > EXPECT(tree_find(tree, "abcd") == &data); > EXPECT(tree_find(tree, "hello") == NULL); > > tree_delete(tree); > EXPECT(nmalloc-nfree == 0); > END_TEST_CASE; > return TEST_RESULT; > } > > ///////////////////////////////////// > // create and validate a tree with long left branch > int test_treeleft() > { > START_TEST_CASE("treeleft"); > tree_t *tree = tree_new(NULL, NULL); > EXPECT(tree != NULL); > int a,b,c,d; > tree_insert(tree, "d", &d); > tree_insert(tree, "c", &c); > tree_insert(tree, "b", &b); > tree_insert(tree, "a", &a); > EXPECT(tree->root != NULL); > EXPECT(tree->root->left != NULL); > EXPECT(tree->root->left->left != NULL); > EXPECT(tree->root->left->left->left != NULL); > EXPECT(strcmp(tree->root->key, "d") == 0); > EXPECT(strcmp(tree->root->left->key, "c") == 0); > EXPECT(strcmp(tree->root->left->left->key, "b") == 0); > EXPECT(strcmp(tree->root->left->left->left->key, "a") == 0); > EXPECT(tree->root->right == NULL); > EXPECT(tree->root->left->right == NULL); > EXPECT(tree->root->left->left->right == NULL); > EXPECT(tree->root->left->left->left->right == NULL); > > EXPECT(tree_find(tree, "a") == &a); > EXPECT(tree_find(tree, "b") == &b); > EXPECT(tree_find(tree, "c") == &c); > EXPECT(tree_find(tree, "d") == &d); > EXPECT(tree_find(tree, "e") == NULL); > > tree_delete(tree); > EXPECT(nmalloc-nfree == 0); > END_TEST_CASE; > return TEST_RESULT; > } > > void test_dataprint(FILE *fp, const char *key, void *data) > { > fprintf(fp, "%s(%d)", key, *(int *)data); > } > > ///////////////////////////////////// > // create a few nodes and test tree_find and tree_print > int test_treefind() > { > START_TEST_CASE("treefind"); > tree_t *tree = tree_new(test_dataprint, NULL); > EXPECT(tree != NULL); > > int dave = 4; tree_insert(tree, "dave", &dave); > EXPECT(tree_find(tree, "dave") == &dave); > > int ann = 1; tree_insert(tree, "ann", &ann); > int bob = 2; tree_insert(tree, "bob", &bob); > int cheri = 3; tree_insert(tree, "cheri", &cheri); > EXPECT(tree_find(tree, "ann") == &ann); > EXPECT(tree_find(tree, "bob") == &bob); > EXPECT(tree_find(tree, "cheri") == &cheri); > EXPECT(tree_find(tree, "dave") == &dave); > EXPECT(tree_find(tree, "fred") == NULL); > > tree_print(stdout, tree); > > tree_delete(tree); > EXPECT(nmalloc-nfree == 0); > END_TEST_CASE; > return TEST_RESULT; > } > > //////////////////////////////////////////// > int > main(const int argc, const char *argv[]) > { > int failed = 0; > > failed += test_newtree0(); > failed += test_newtree1(); > failed += test_treeleft(); > failed += test_treefind(); > > if (failed) { > printf("FAIL %d test cases\n", failed); > return failed; > } else { > printf("PASS all test cases\n"); > return 0; > } > } > > #endif // UNIT_TEST diff -b tree9/tree.h treeA/tree.h 3c3 < * (version 7) --- > * (unit tests)