diff --git a/sefht.geany b/sefht.geany index 3f386228b09a9216fb91fc73f8808d29ac22b3a7..6469562934d4c5f2b996bcbca4ece4ff396c4b5a 100644 --- a/sefht.geany +++ b/sefht.geany @@ -41,22 +41,22 @@ FILE_NAME_8=1550;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fpr FILE_NAME_9=1562;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment.h;0;8 FILE_NAME_10=2022;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_data.c;0;8 FILE_NAME_11=2558;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ffragment_class.c;0;8 -FILE_NAME_12=6660;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8 -FILE_NAME_13=2360;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.h;0;8 +FILE_NAME_12=15959;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.c;0;8 +FILE_NAME_13=3151;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fnode_fragment.h;0;8 FILE_NAME_14=25820;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.c;0;8 FILE_NAME_15=904;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Ftext.h;0;8 FILE_NAME_16=1779;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.c;0;8 FILE_NAME_17=919;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator.h;0;8 FILE_NAME_18=14237;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.c;0;8 FILE_NAME_19=859;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fvalidator_tag.h;0;8 -FILE_NAME_20=4608;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8 +FILE_NAME_20=4735;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fstatus.h;0;8 FILE_NAME_21=901;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Flog.h;0;4 FILE_NAME_22=907;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fmacro.h;0;8 FILE_NAME_23=1078;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Fsrc%2Flib%2Fsefht%2Fsefht.h;0;8 FILE_NAME_24=290;Make;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2FMakefile.am;0;8 FILE_NAME_25=1085;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_cms.c;0;8 FILE_NAME_26=3283;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_data.c;0;8 -FILE_NAME_27=4338;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8 +FILE_NAME_27=32229;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_node_fragment.c;0;8 FILE_NAME_28=11068;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_text.c;0;8 FILE_NAME_29=5744;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftests%2Ftest_validator.c;0;8 FILE_NAME_30=165;None;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fprgm%2Finternet%2Fweb%2FSeFHT%2Ftodo.txt;0;8 diff --git a/src/lib/sefht/node_fragment.c b/src/lib/sefht/node_fragment.c index d3dcf041bc38ea4ad752fa4a73d767d454d8aecc..434b32686339f24523e849bc0a65fa8783205c69 100644 --- a/src/lib/sefht/node_fragment.c +++ b/src/lib/sefht/node_fragment.c @@ -42,13 +42,17 @@ #include "fragment_class.c" + +#define CHILD_CHUNK 5 + struct SH_NodeFragment { struct SH_Fragment base; /*@only@*/ char * tag; - size_t child_n; + size_t child_s; /* allocated size */ + size_t child_n; /* real size */ /*@only@*/ struct SH_Fragment ** childs; }; @@ -77,6 +81,30 @@ static const struct fragment_methods methods = { }; +static inline +size_t +get_alloc_size (size_t size) + /*@*/ +{ + /* underflow */ + if (size == 0) + { + return 0; + } + /* overflow */ + else if (((SIZE_MAX / CHILD_CHUNK) - 1) + < ((size - 1) / CHILD_CHUNK)) + { + return SIZE_MAX; + } + /* calculate the number of needed chunks */ + else + { + return CHILD_CHUNK * (((size - 1) / CHILD_CHUNK) + 1); + } +} + + /*@null@*/ /*@only@*/ struct SH_Fragment /*@alt struct SH_NodeFragment@*/ * @@ -115,6 +143,7 @@ SH_NodeFragment_new (const char * tag, } + fragment->child_s = 0; fragment->child_n = 0; fragment->childs = malloc (0); @@ -150,6 +179,7 @@ SH_NodeFragment_raw_new (/*@only@*/ char * tag, fragment->tag = tag; + fragment->child_s = 0; fragment->child_n = 0; fragment->childs = malloc (0); @@ -216,6 +246,7 @@ SH_NodeFragment_copy (const struct SH_NodeFragment * fragment, } + copy->child_s = 0; copy->child_n = 0; copy->childs = malloc (0); @@ -264,10 +295,10 @@ SH_NodeFragment_deepcopy (const struct SH_NodeFragment * fragment, copy->child_n = fragment->child_n; - copy->childs = malloc (sizeof (struct SH_NodeFragment *) - * fragment->child_n); + copy->child_s = get_alloc_size (fragment->child_n); + copy->childs = malloc (copy->child_s * sizeof (*copy->childs)); - if (copy->child_n != 0 && copy->childs == NULL) + if (copy->child_s != 0 && copy->childs == NULL) { set_status (status, E_ALLOC, 5, "Memory allocation for " @@ -364,6 +395,13 @@ SH_Fragment_get_parent (const struct SH_Fragment * fragment) return get_parent (fragment); } +size_t +SH_NodeFragment_count_childs (const struct SH_NodeFragment * fragment) + /*@*/ +{ + return fragment->child_n; +} + /*@null@*/ /*@observer@*/ struct SH_Fragment * @@ -428,45 +466,244 @@ SH_NodeFragment_is_descendant (const struct SH_NodeFragment * fragment, } bool -SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, - /*@only@*/ struct SH_Fragment * child, - /*@out@*/ /*@null@*/ - struct SH_Status * status) +SH_NodeFragment_is_parent (const struct SH_Fragment * fragment, + const struct SH_NodeFragment * parent) + /*@*/ +{ + if (parent == get_parent (fragment)) + { + return TRUE; + } + + return FALSE; +} + +bool +SH_NodeFragment_is_ancestor (const struct SH_Fragment * fragment, + const struct SH_NodeFragment * ancestor) + /*@*/ +{ + if ((NULL != get_parent (fragment)) + && ((ancestor == get_parent (fragment)) + || (SH_NodeFragment_is_ancestor ((const struct SH_Fragment *) + get_parent (fragment), + ancestor)))) + { + return TRUE; + } + + return FALSE; +} + +static inline +bool +insert_child (struct SH_NodeFragment * fragment, + /*@only@*/ struct SH_Fragment * child, + size_t position, + /*@out@*/ /*@null@*/ struct SH_Status * status) /*@modifies fragment->childs@*/ + /*@modifies fragment->child_s@*/ /*@modifies fragment->child_n@*/ /*@globals fileSystem@*/ /*@modifies fileSystem@*/ /*@modifies status@*/ { + size_t new_size; + size_t index; struct SH_Fragment ** new_childs; - new_childs = realloc (fragment->childs, - sizeof (struct SH_Fragment *) - * (fragment->child_n + 1)); + if (!SH_Fragment_is_orphan (child)) + { + set_status (status, E_STATE, 2, + "child is already linked; " + "please unlink first or link a copy.\n"); + return FALSE; + } - if (new_childs == NULL) + if (SH_Fragment_is_NodeFragment (child) + && SH_NodeFragment_is_ancestor ((struct SH_Fragment *)fragment, + (struct SH_NodeFragment *)child)) { - set_status (status, E_ALLOC, 6, - "Memory allocation for " - "fragment child failed.\n"); + set_status (status, E_STATE, 2, + "refusing to make a tree cyclic.\n"); + return FALSE; + } + + new_size = get_alloc_size (fragment->child_n + 1); + if (new_size > fragment->child_s) + { + if ((SIZE_MAX / sizeof (*new_childs)) < new_size) + { + set_status (status, E_DOMAIN, -6, + "maximum number of " + "childs reached.\n"); + return FALSE; + } + + new_childs = realloc (fragment->childs, new_size + * sizeof (*new_childs)); + + if (new_childs == NULL) + { + set_status (status, E_ALLOC, 5, + "Memory allocation for " + "fragment child failed.\n"); /* bad code to silence splint, should never be executed. */ #ifdef S_SPLINT_S - fragment->childs = (void *) 0x12345; + fragment->childs = (void *) 0x12345; #endif - return FALSE; - } + return FALSE; + } - new_childs[fragment->child_n] = child; + fragment->childs = new_childs; + fragment->child_s = new_size; + } - fragment->childs = new_childs; + for (index = fragment->child_n; index > position; index--) + { + fragment->childs[index] = fragment->childs[index-1]; + } + fragment->childs[position] = child; fragment->child_n++; + child->parent = fragment; set_success (status); return TRUE; } +bool +SH_NodeFragment_insert_child (struct SH_NodeFragment * fragment, + /*@only@*/ struct SH_Fragment * child, + size_t position, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment->childs@*/ + /*@modifies fragment->child_s@*/ + /*@modifies fragment->child_n@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + if (position > fragment->child_n) + { + set_status (status, E_VALUE, 2, + "index out of range.\n"); + return FALSE; + } + + return insert_child (fragment, child, position, status); +} + +bool +SH_NodeFragment_prepend_child (struct SH_NodeFragment * fragment, + /*@only@*/ struct SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment->childs@*/ + /*@modifies fragment->child_s@*/ + /*@modifies fragment->child_n@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + return insert_child (fragment, child, 0, status); +} + +bool +SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, + /*@only@*/ struct SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment->childs@*/ + /*@modifies fragment->child_s@*/ + /*@modifies fragment->child_n@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + return insert_child (fragment, child, fragment->child_n, status); +} + +bool +SH_NodeFragment_insert_child_before (struct SH_Fragment * fragment, + /*@only@*/ + struct SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment->childs@*/ + /*@modifies fragment->child_s@*/ + /*@modifies fragment->child_n@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + size_t index; + + #define parent get_parent (fragment) + if (NULL == parent) + { + set_status (status, E_STATE, 2, + "child is not linked, " + "can't insert before.\n"); + return FALSE; + } + + for (index = 0; index < parent->child_n; index++) + { + if (parent->childs[index] == fragment) + { + return insert_child (parent, child, + index, status); + } + } + #undef parent + + set_status (status, E_BUG, 10, + "fragment is both child and not child.\n"); + return FALSE; +} + +bool +SH_NodeFragment_insert_child_after (struct SH_Fragment * fragment, + /*@only@*/ + struct SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment->childs@*/ + /*@modifies fragment->child_s@*/ + /*@modifies fragment->child_n@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/ +{ + size_t index; + + #define parent get_parent (fragment) + if (NULL == parent) + { + set_status (status, E_STATE, 2, + "child is not linked, " + "can't insert before.\n"); + return FALSE; + } + + for (index = 0; index < parent->child_n; index++) + { + if (parent->childs[index] == fragment) + { + return insert_child (parent, child, + index+1, status); + } + } + #undef parent + + set_status (status, E_BUG, 10, + "fragment is both child and not child.\n"); + return FALSE; +} + /*@null@*/ /*@only@*/ struct SH_Text * diff --git a/src/lib/sefht/node_fragment.h b/src/lib/sefht/node_fragment.h index f325428ddc6998a83638c3599e28180f519a9bcc..3a50360bc669038659528da705200693d1c010e4 100644 --- a/src/lib/sefht/node_fragment.h +++ b/src/lib/sefht/node_fragment.h @@ -112,13 +112,34 @@ SH_NodeFragment_is_child (const SH_NodeFragment * fragment, /*@*/; bool -SH_NodeFragment_is_descendant (const struct SH_NodeFragment * fragment, - const struct SH_Fragment * child) +SH_NodeFragment_is_descendant (const SH_NodeFragment * fragment, + const SH_Fragment * child) /*@*/; bool -SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, - /*@only@*/ struct SH_Fragment * child, +SH_NodeFragment_is_parent (const SH_Fragment * fragment, + const SH_NodeFragment * parent) + /*@*/; + +bool +SH_NodeFragment_is_ancestor (const SH_Fragment * fragment, + const SH_NodeFragment * ancestor) + /*@*/; + +bool +SH_NodeFragment_insert_child (SH_NodeFragment * fragment, + /*@only@*/ SH_Fragment * child, + size_t position, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_NodeFragment_prepend_child (SH_NodeFragment * fragment, + /*@only@*/ SH_Fragment * child, /*@out@*/ /*@null@*/ struct SH_Status * status) /*@modifies fragment@*/ @@ -126,6 +147,36 @@ SH_NodeFragment_append_child (struct SH_NodeFragment * fragment, /*@modifies fileSystem@*/ /*@modifies status@*/; +bool +SH_NodeFragment_append_child (SH_NodeFragment * fragment, + /*@only@*/ SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_NodeFragment_insert_child_before (SH_Fragment * fragment, + /*@only@*/ SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + +bool +SH_NodeFragment_insert_child_after (SH_Fragment * fragment, + /*@only@*/ SH_Fragment * child, + /*@out@*/ /*@null@*/ + struct SH_Status * status) + /*@modifies fragment@*/ + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ + /*@modifies status@*/; + /*@null@*/ /*@only@*/ SH_Text * diff --git a/src/lib/sefht/status.h b/src/lib/sefht/status.h index 4b4b479ee2b7fb623f650127ab686e3b939f49ae..8ee1a364449c950c09bde844073b6ddbd8d69d90 100644 --- a/src/lib/sefht/status.h +++ b/src/lib/sefht/status.h @@ -112,7 +112,9 @@ struct SH_Status SUCCESS, E_ALLOC, E_DOMAIN, - E_VALUE + E_VALUE, + E_STATE, + E_BUG } status; int errno_; diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c index 89275bd776d67f18b5c877a4caafde188bcc503e..824b519ae788c44060fc3be98016a5da0e67a61b 100644 --- a/tests/test_node_fragment.c +++ b/tests/test_node_fragment.c @@ -290,6 +290,20 @@ START_TEST(test_node_fragment_tag) } END_TEST +START_TEST(test_node_fragment_child_alloc) +{ + ck_assert_int_eq (0, get_alloc_size (0)); + ck_assert_int_eq (CHILD_CHUNK, get_alloc_size (1)); + ck_assert_int_eq (CHILD_CHUNK, get_alloc_size (CHILD_CHUNK)); + ck_assert_int_eq (2*CHILD_CHUNK, get_alloc_size (CHILD_CHUNK+1)); + ck_assert_int_eq (SIZE_MAX, get_alloc_size (SIZE_MAX)); + for (size_t i = 0; i < CHILD_CHUNK; i++) + { + ck_assert_int_le (SIZE_MAX-i, get_alloc_size (SIZE_MAX-i)); + } +} +END_TEST + START_TEST(test_node_fragment_child) { struct SH_Status status; @@ -316,8 +330,7 @@ START_TEST(test_node_fragment_child) ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[0], child1); - /* TODO: not implemented yet. */ - //~ ck_assert_ptr_eq (parent, get_parent (child1)); + ck_assert_ptr_eq (parent, get_parent (child1)); /* with error */ ck_assert_int_eq (((struct SH_NodeFragment *) parent)->child_n, 1); @@ -332,8 +345,7 @@ START_TEST(test_node_fragment_child) ck_assert_ptr_eq (((struct SH_NodeFragment *) parent)->childs[1], child2); - /* TODO: not implemented yet. */ - //~ ck_assert_ptr_eq (parent, get_parent (child2)); + ck_assert_ptr_eq (parent, get_parent (child2)); SH_Fragment_free (parent); @@ -475,6 +487,537 @@ START_TEST(test_node_fragment_is_descendant) } END_TEST +START_TEST(test_node_fragment_is_parent) +{ + struct SH_Fragment * parent; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Data * data; + bool boolean; + + data = SH_Data_new (NULL); + + parent = SH_NodeFragment_new ("html", data, NULL); + child1 = SH_NodeFragment_new ("head", data, NULL); + child2 = SH_NodeFragment_new ("title", data, NULL); + + SH_NodeFragment_append_child (((struct SH_NodeFragment *) parent), + child1, NULL); + SH_NodeFragment_append_child (((struct SH_NodeFragment *) child1), + child2, NULL); + + boolean = SH_NodeFragment_is_parent (child1, + (struct SH_NodeFragment *) + parent); + ck_assert_int_eq (boolean, TRUE); + + boolean = SH_NodeFragment_is_parent (child2, + (struct SH_NodeFragment *) + parent); + ck_assert_int_eq (boolean, FALSE); + + boolean = SH_NodeFragment_is_parent (child2, + (struct SH_NodeFragment *) + child1); + ck_assert_int_eq (boolean, TRUE); + + SH_Fragment_free (parent); + + SH_Data_free (data); +} +END_TEST + +START_TEST(test_node_fragment_is_ancestor) +{ + struct SH_Fragment * parent; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Fragment * child3; + struct SH_Data * data; + bool boolean; + + data = SH_Data_new (NULL); + + parent = SH_NodeFragment_new ("html", data, NULL); + child1 = SH_NodeFragment_new ("head", data, NULL); + child2 = SH_NodeFragment_new ("body", data, NULL); + child3 = SH_NodeFragment_new ("title", data, NULL); + + SH_NodeFragment_append_child (((struct SH_NodeFragment *)parent), + child1, NULL); + SH_NodeFragment_append_child (((struct SH_NodeFragment *)parent), + child2, NULL); + SH_NodeFragment_append_child (((struct SH_NodeFragment *)child1), + child3, NULL); + + boolean = SH_NodeFragment_is_ancestor (child1, + ((struct SH_NodeFragment *) + parent)); + ck_assert_int_eq (boolean, TRUE); + + boolean = SH_NodeFragment_is_ancestor (child2, + ((struct SH_NodeFragment *) + parent)); + ck_assert_int_eq (boolean, TRUE); + + boolean = SH_NodeFragment_is_ancestor (child3, + ((struct SH_NodeFragment *) + parent)); + ck_assert_int_eq (boolean, TRUE); + + boolean = SH_NodeFragment_is_ancestor (child2, + ((struct SH_NodeFragment *) + child1)); + ck_assert_int_eq (boolean, FALSE); + + boolean = SH_NodeFragment_is_ancestor (child3, + ((struct SH_NodeFragment *) + child1)); + ck_assert_int_eq (boolean, TRUE); + + boolean = SH_NodeFragment_is_ancestor (child3, + ((struct SH_NodeFragment *) + child2)); + ck_assert_int_eq (boolean, FALSE); + + SH_Fragment_free (parent); + + SH_Data_free (data); +} +END_TEST + +START_TEST(test_node_fragment_child_insert_no_error) +{ + SH_Data * data; + struct SH_NodeFragment * parent; + struct SH_Fragment * child; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Fragment * child3; + bool result; + + data = SH_Data_new (NULL); + + parent = (struct SH_NodeFragment *) + SH_NodeFragment_new ("body", data, NULL); + child1 = SH_NodeFragment_new ("header", data, NULL); + child2 = SH_NodeFragment_new ("main", data, NULL); + child3 = SH_NodeFragment_new ("footer", data, NULL); + + /* insert - success */ + result = insert_child (parent, child1, 0, NULL); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (1, parent->child_n); + ck_assert_int_le (1, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child1, parent->childs[0]); + ck_assert_ptr_eq (parent, child1->parent); + + /* reinsert - failing */ + result = insert_child (parent, child1, 0, NULL); + ck_assert_int_eq (FALSE, result); + + /* insert copy - success */ + child = SH_Fragment_copy (child1, NULL); + result = insert_child (parent, child, 0, NULL); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (2, parent->child_n); + ck_assert_int_le (2, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child, parent->childs[0]); + ck_assert_ptr_eq (child1, parent->childs[1]); + ck_assert_ptr_eq (parent, child->parent); + ck_assert_ptr_eq (parent, child1->parent); + + /* insert parent into child - failing */ + result = insert_child ((struct SH_NodeFragment *)child1, + (struct SH_Fragment *)parent, + 0, NULL); + ck_assert_int_eq (FALSE, result); + + /* insert inbetween */ + result = insert_child (parent, child2, 1, NULL); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (3, parent->child_n); + ck_assert_int_le (3, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child, parent->childs[0]); + ck_assert_ptr_eq (child1, parent->childs[2]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (parent, child->parent); + ck_assert_ptr_eq (parent, child1->parent); + ck_assert_ptr_eq (parent, child2->parent); + + /* insert after */ + result = insert_child (parent, child3, 3, NULL); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (4, parent->child_n); + ck_assert_int_le (4, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child, parent->childs[0]); + ck_assert_ptr_eq (child1, parent->childs[2]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (child3, parent->childs[3]); + ck_assert_ptr_eq (parent, child->parent); + ck_assert_ptr_eq (parent, child1->parent); + ck_assert_ptr_eq (parent, child2->parent); + ck_assert_ptr_eq (parent, child3->parent); + + SH_NodeFragment_free (parent); + + SH_Data_free (data); +} +END_TEST + +START_TEST(test_node_fragment_child_insert_with_error) +{ + struct SH_Status status; + SH_Data * data; + struct SH_NodeFragment * parent; + struct SH_Fragment * child; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Fragment * child3; + bool result; + + data = SH_Data_new (NULL); + + parent = (struct SH_NodeFragment *) + SH_NodeFragment_new ("body", data, NULL); + child1 = SH_NodeFragment_new ("header", data, NULL); + child2 = SH_NodeFragment_new ("main", data, NULL); + child3 = SH_NodeFragment_new ("footer", data, NULL); + + /* insert - success */ + _status_preinit (status); + result = insert_child (parent, child1, 0, &status); + ck_assert (succeed (&status)); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (1, parent->child_n); + ck_assert_int_le (1, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child1, parent->childs[0]); + ck_assert_ptr_eq (parent, child1->parent); + + /* reinsert - failing */ + _status_preinit (status); + result = insert_child (parent, child1, 0, &status); + ck_assert (failed (&status)); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_STATE, status.status); + + /* insert copy - success */ + child = SH_Fragment_copy (child1, NULL); + _status_preinit (status); + result = insert_child (parent, child, 0, &status); + ck_assert (succeed (&status)); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (2, parent->child_n); + ck_assert_int_le (2, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child, parent->childs[0]); + ck_assert_ptr_eq (child1, parent->childs[1]); + ck_assert_ptr_eq (parent, child->parent); + ck_assert_ptr_eq (parent, child1->parent); + + /* insert parent into child - failing */ + _status_preinit (status); + result = insert_child ((struct SH_NodeFragment *)child1, + (struct SH_Fragment *)parent, + 0, &status); + ck_assert (failed (&status)); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_STATE, status.status); + + /* insert inbetween */ + _status_preinit (status); + result = insert_child (parent, child2, 1, &status); + ck_assert (succeed (&status)); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (3, parent->child_n); + ck_assert_int_le (3, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child, parent->childs[0]); + ck_assert_ptr_eq (child1, parent->childs[2]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (parent, child->parent); + ck_assert_ptr_eq (parent, child1->parent); + ck_assert_ptr_eq (parent, child2->parent); + + /* insert after */ + _status_preinit (status); + result = insert_child (parent, child3, 3, &status); + ck_assert (succeed (&status)); + ck_assert_int_eq (TRUE, result); + ck_assert_int_eq (4, parent->child_n); + ck_assert_int_le (4, parent->child_s); + ck_assert_int_eq (CHILD_CHUNK, parent->child_s); + ck_assert_ptr_eq (child, parent->childs[0]); + ck_assert_ptr_eq (child1, parent->childs[2]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (child3, parent->childs[3]); + ck_assert_ptr_eq (parent, child->parent); + ck_assert_ptr_eq (parent, child1->parent); + ck_assert_ptr_eq (parent, child2->parent); + ck_assert_ptr_eq (parent, child3->parent); + + SH_NodeFragment_free (parent); + + SH_Data_free (data); +} +END_TEST + +START_TEST(test_node_fragment_child_insert_insert_no_error) +{ + struct SH_NodeFragment * parent; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Fragment * child3; + SH_Data * data; + bool result; + + data = SH_Data_new (NULL); + + parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body", + data, + NULL); + child1 = SH_NodeFragment_new ("header", data, NULL); + child2 = SH_NodeFragment_new ("main", data, NULL); + child3 = SH_NodeFragment_new ("footer", data, NULL); + + /* out of range - fail */ + result = SH_NodeFragment_insert_child (parent, child1, 1, NULL); + ck_assert_int_eq (FALSE, result); + + /* insert - success */ + result = SH_NodeFragment_insert_child (parent, child2, 0, NULL); + ck_assert_int_eq (TRUE, result); + + /* insert before - success */ + result = SH_NodeFragment_insert_child (parent, child1, 0, NULL); + ck_assert_int_eq (TRUE, result); + + /* insert after - success */ + result = SH_NodeFragment_insert_child (parent, child3, 2, NULL); + ck_assert_int_eq (TRUE, result); + + ck_assert_int_eq (3, parent->child_n); + ck_assert_ptr_eq (child1, parent->childs[0]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (child3, parent->childs[2]); + + SH_NodeFragment_free (parent); + + SH_Data_free (data); +} +END_TEST + +START_TEST(test_node_fragment_child_insert_insert_with_error) +{ + struct SH_Status status; + struct SH_NodeFragment * parent; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Fragment * child3; + SH_Data * data; + bool result; + + data = SH_Data_new (NULL); + + parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body", + data, + NULL); + child1 = SH_NodeFragment_new ("header", data, NULL); + child2 = SH_NodeFragment_new ("main", data, NULL); + child3 = SH_NodeFragment_new ("footer", data, NULL); + + /* out of range - fail */ + _status_preinit (status); + result = SH_NodeFragment_insert_child (parent, child1, 1, + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_VALUE, status.status); + ck_assert (failed (&status)); + + /* insert - success */ + _status_preinit (status); + result = SH_NodeFragment_insert_child (parent, child2, 0, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert (succeed (&status)); + + /* insert before - success */ + _status_preinit (status); + result = SH_NodeFragment_insert_child (parent, child1, 0, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert (succeed (&status)); + + /* insert after - success */ + _status_preinit (status); + result = SH_NodeFragment_insert_child (parent, child3, 2, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert (succeed (&status)); + + ck_assert_int_eq (3, parent->child_n); + ck_assert_ptr_eq (child1, parent->childs[0]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (child3, parent->childs[2]); + + SH_NodeFragment_free (parent); + + SH_Data_free (data); +} +END_TEST + +START_TEST(test_node_fragment_child_insert_relative_no_error) +{ + struct SH_NodeFragment * parent; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Fragment * child3; + SH_Data * data; + bool result; + + data = SH_Data_new (NULL); + + parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body", + data, + NULL); + child1 = SH_NodeFragment_new ("header", data, NULL); + child2 = SH_NodeFragment_new ("main", data, NULL); + child3 = SH_NodeFragment_new ("footer", data, NULL); + + /* test erroneous call */ + result = SH_NodeFragment_insert_child_before (child2, child1, + NULL); + ck_assert_int_eq (FALSE, result); + + result = SH_NodeFragment_insert_child_after (child2, child3, + NULL); + ck_assert_int_eq (FALSE, result); + + /* test bug check */ + child2->parent = parent; + + result = SH_NodeFragment_insert_child_before (child2, child1, + NULL); + ck_assert_int_eq (FALSE, result); + + result = SH_NodeFragment_insert_child_after (child2, child3, + NULL); + ck_assert_int_eq (FALSE, result); + + child2->parent = NULL; + + /* test real */ + result = SH_NodeFragment_insert_child (parent, child2, 0, + NULL); + ck_assert_int_eq (TRUE, result); + + result = SH_NodeFragment_insert_child_before (child2, child1, + NULL); + ck_assert_int_eq (TRUE, result); + + result = SH_NodeFragment_insert_child_after (child2, child3, + NULL); + ck_assert_int_eq (TRUE, result); + + ck_assert_int_eq (3, parent->child_n); + ck_assert_ptr_eq (child1, parent->childs[0]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (child3, parent->childs[2]); + + SH_NodeFragment_free (parent); + + SH_Data_free (data); +} +END_TEST + +START_TEST(test_node_fragment_child_insert_relative_with_error) +{ + struct SH_Status status; + struct SH_NodeFragment * parent; + struct SH_Fragment * child1; + struct SH_Fragment * child2; + struct SH_Fragment * child3; + SH_Data * data; + bool result; + + data = SH_Data_new (NULL); + + parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body", + data, + NULL); + child1 = SH_NodeFragment_new ("header", data, NULL); + child2 = SH_NodeFragment_new ("main", data, NULL); + child3 = SH_NodeFragment_new ("footer", data, NULL); + + /* test erroneous call */ + _status_preinit (status); + result = SH_NodeFragment_insert_child_before (child2, child1, + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_STATE, status.status); + ck_assert (failed (&status)); + + _status_preinit (status); + result = SH_NodeFragment_insert_child_after (child2, child3, + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_STATE, status.status); + ck_assert (failed (&status)); + + /* test bug check */ + child2->parent = parent; + + _status_preinit (status); + result = SH_NodeFragment_insert_child_before (child2, child1, + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_BUG, status.status); + ck_assert (failed (&status)); + + _status_preinit (status); + result = SH_NodeFragment_insert_child_after (child2, child3, + &status); + ck_assert_int_eq (FALSE, result); + ck_assert_int_eq (E_BUG, status.status); + ck_assert (failed (&status)); + + child2->parent = NULL; + + /* test real */ + _status_preinit (status); + result = SH_NodeFragment_insert_child (parent, child2, 0, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert (succeed (&status)); + + _status_preinit (status); + result = SH_NodeFragment_insert_child_before (child2, child1, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert (succeed (&status)); + + _status_preinit (status); + result = SH_NodeFragment_insert_child_after (child2, child3, + &status); + ck_assert_int_eq (TRUE, result); + ck_assert (succeed (&status)); + + ck_assert_int_eq (3, parent->child_n); + ck_assert_ptr_eq (child1, parent->childs[0]); + ck_assert_ptr_eq (child2, parent->childs[1]); + ck_assert_ptr_eq (child3, parent->childs[2]); + + SH_NodeFragment_free (parent); + + SH_Data_free (data); +} +END_TEST + START_TEST(test_node_fragment_html) { struct SH_Status status; @@ -555,10 +1098,19 @@ Suite * fragment_suite (void) tcase_add_test (tc_core, test_node_fragment_copy); tcase_add_test (tc_core, test_node_fragment_deepcopy); tcase_add_test (tc_core, test_node_fragment_tag); + tcase_add_test (tc_core, test_node_fragment_child_alloc); tcase_add_test (tc_core, test_node_fragment_child); tcase_add_test (tc_core, test_node_fragment_get_child); tcase_add_test (tc_core, test_node_fragment_is_child); tcase_add_test (tc_core, test_node_fragment_is_descendant); + tcase_add_test (tc_core, test_node_fragment_is_parent); + tcase_add_test (tc_core, test_node_fragment_is_ancestor); + tcase_add_test (tc_core, test_node_fragment_child_insert_no_error); + tcase_add_test (tc_core, test_node_fragment_child_insert_with_error); + tcase_add_test (tc_core, test_node_fragment_child_insert_insert_no_error); + tcase_add_test (tc_core, test_node_fragment_child_insert_insert_with_error); + tcase_add_test (tc_core, test_node_fragment_child_insert_relative_no_error); + tcase_add_test (tc_core, test_node_fragment_child_insert_relative_with_error); tcase_add_test (tc_core, test_node_fragment_html); suite_add_tcase (s, tc_core);