From 8d84e3c75ccef1b5f8b7f609013c7858aa7f7eea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonathan=20Sch=C3=B6bel?= <jonathan@xn--schbel-yxa.info>
Date: Thu, 16 Mar 2023 13:12:07 +0100
Subject: [PATCH] NodeFragment: added remove methods

Various remove methods were added, which are all implemented by an
static method, analog to the last commit.
---
 sefht.geany                   |   6 +-
 src/lib/sefht/node_fragment.c | 175 ++++++++++
 src/lib/sefht/node_fragment.h |  28 ++
 tests/test_node_fragment.c    | 587 ++++++++++++++++++++++++++++++++++
 4 files changed, 793 insertions(+), 3 deletions(-)

diff --git a/sefht.geany b/sefht.geany
index 6469562..a36946c 100644
--- a/sefht.geany
+++ b/sefht.geany
@@ -41,8 +41,8 @@ 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=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_12=15951;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=5930;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
@@ -56,7 +56,7 @@ FILE_NAME_23=1078;C;0;EUTF-8;1;1;0;%2Fhome%2Fjonathan%2FDokumente%2Fprojekte%2Fp
 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=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_27=51595;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 434b326..6e3e498 100644
--- a/src/lib/sefht/node_fragment.c
+++ b/src/lib/sefht/node_fragment.c
@@ -704,6 +704,181 @@ SH_NodeFragment_insert_child_after (struct SH_Fragment * fragment,
 	return FALSE;
 }
 
+static inline
+/*@null@*/
+/*@only@*/
+struct SH_Fragment *
+remove_child (struct SH_NodeFragment * fragment, size_t position,
+              /*@out@*/ /*@null@*/ struct SH_Status * status)
+{
+	size_t index;
+	size_t new_size;
+	typeof (fragment->childs) new_childs;
+	struct SH_Fragment * child;
+
+	child = fragment->childs[position];
+
+	for (index = position+1; index < fragment->child_n; index++)
+	{
+		fragment->childs[index-1] = fragment->childs[index];
+	}
+
+	new_size = get_alloc_size (fragment->child_n - 1);
+	if (new_size < fragment->child_s)
+	{
+		new_childs = realloc (fragment->childs, new_size
+		                      * sizeof (*new_childs));
+		if ((0 != new_size) && (NULL == new_childs))
+		{
+			for (index = fragment->child_n-1;
+			     index > position;
+			     index--)
+			{
+				fragment->childs[index] =
+				fragment->childs[index-1];
+			}
+
+			set_status (status, E_ALLOC, 4,
+			            "realloc failed.\n");
+			return NULL;
+		}
+
+		fragment->childs = new_childs;
+		fragment->child_s = new_size;
+	}
+
+	fragment->child_n--;
+	child->parent = NULL;
+
+	set_success (status);
+
+	return child;
+}
+
+bool
+SH_Fragment_remove (struct SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status)
+{
+	size_t index;
+
+	#define parent get_parent (fragment)
+	if (NULL == parent)
+	{
+		set_status (status, E_STATE, 2,
+		            "fragment not linked, "
+		            "can't remove it from parent");
+		return FALSE;
+	}
+
+	for (index = 0; index < parent->child_n; index++)
+	{
+		if (fragment == parent->childs[index])
+		{
+			return NULL != remove_child (parent, index,
+			                             status);
+		}
+	}
+	#undef parent
+
+	set_status (status, E_BUG, 10,
+	            "fragment is both child and not child.\n");
+	return FALSE;
+}
+
+bool
+SH_Fragment_delete (/*@only@*/ struct SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status)
+{
+	size_t index;
+
+	#define parent get_parent (fragment)
+	if (NULL == parent)
+	{
+		set_status (status, E_STATE, 2,
+		            "fragment not linked, "
+		            "can't remove it from parent");
+		return FALSE;
+	}
+
+	for (index = 0; index < parent->child_n; index++)
+	{
+		if (fragment == parent->childs[index])
+		{
+			if (NULL == remove_child (parent, index, status))
+			{
+				return FALSE;
+			}
+
+			SH_Fragment_free (fragment);
+			return TRUE;
+		}
+	}
+	#undef parent
+
+	set_status (status, E_BUG, 10,
+	            "fragment is both child and not child.\n");
+	return FALSE;
+}
+
+bool
+SH_NodeFragment_remove_child (struct SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+{
+	if (position >= fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	return NULL != remove_child (fragment, position, status);
+}
+
+bool
+SH_NodeFragment_delete_child (struct SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status)
+{
+	struct SH_Fragment * child;
+
+	if (position >= fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return FALSE;
+	}
+
+	child = remove_child (fragment, position, status);
+	if (NULL == child)
+	{
+		return FALSE;
+	}
+
+	SH_Fragment_free (child);
+	return TRUE;
+}
+
+/*@null@*/
+/*@only@*/
+struct SH_Fragment *
+SH_NodeFragment_pop_child (struct SH_NodeFragment * fragment,
+                           size_t position,
+                           /*@out@*/ /*@null@*/
+                           struct SH_Status * status)
+{
+	if (position >= fragment->child_n)
+	{
+		set_status (status, E_VALUE, 2,
+		            "index out of range.\n");
+		return NULL;
+	}
+
+	return remove_child (fragment, position, status);
+}
+
 /*@null@*/
 /*@only@*/
 struct SH_Text *
diff --git a/src/lib/sefht/node_fragment.h b/src/lib/sefht/node_fragment.h
index 3a50360..44ac67c 100644
--- a/src/lib/sefht/node_fragment.h
+++ b/src/lib/sefht/node_fragment.h
@@ -177,6 +177,34 @@ SH_NodeFragment_insert_child_after (SH_Fragment * fragment,
 	/*@modifies fileSystem@*/
 	/*@modifies status@*/;
 
+bool
+SH_Fragment_remove (SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status);
+
+bool
+SH_Fragment_delete (/*@only@*/ SH_Fragment * fragment,
+                    /*@out@*/ /*@null@*/ struct SH_Status * status);
+
+bool
+SH_NodeFragment_remove_child (SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status);
+
+bool
+SH_NodeFragment_delete_child (SH_NodeFragment * fragment,
+                              size_t position,
+                              /*@out@*/ /*@null@*/
+                              struct SH_Status * status);
+
+/*@null@*/
+/*@only@*/
+SH_Fragment *
+SH_NodeFragment_pop_child (SH_NodeFragment * fragment,
+                           size_t position,
+                           /*@out@*/ /*@null@*/
+                           struct SH_Status * status);
+
 /*@null@*/
 /*@only@*/
 SH_Text *
diff --git a/tests/test_node_fragment.c b/tests/test_node_fragment.c
index 824b519..35f2cdd 100644
--- a/tests/test_node_fragment.c
+++ b/tests/test_node_fragment.c
@@ -1018,6 +1018,581 @@ START_TEST(test_node_fragment_child_insert_relative_with_error)
 }
 END_TEST
 
+START_TEST(test_node_fragment_child_remove_no_error)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	struct SH_Fragment * child4;
+	struct SH_Fragment * child5;
+	struct SH_Fragment * child6;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("p", data, NULL);
+	child2 = SH_NodeFragment_new ("p", data, NULL);
+	child3 = SH_NodeFragment_new ("p", data, NULL);
+	child4 = SH_NodeFragment_new ("p", data, NULL);
+	child5 = SH_NodeFragment_new ("p", data, NULL);
+	child6 = SH_NodeFragment_new ("p", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child2, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child3, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child4, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child5, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child6, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+
+	ck_assert_int_eq (10, parent->child_s);
+	ck_assert_int_eq (6, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child1);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child1);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (5, parent->child_n);
+	ck_assert_ptr_eq (child2, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child2);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child2);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (4, parent->child_n);
+	ck_assert_ptr_eq (child3, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child3);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child3);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child4, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child4);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child4);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (2, parent->child_n);
+	ck_assert_ptr_eq (child5, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child5);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child5);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (1, parent->child_n);
+	ck_assert_ptr_eq (child6, parent->childs[0]);
+
+	child = remove_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child6);
+	ck_assert_ptr_eq (NULL, child->parent);
+	SH_Fragment_free (child6);
+	ck_assert_int_eq (0, parent->child_s);
+	ck_assert_int_eq (0, parent->child_n);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_with_error)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	struct SH_Fragment * child2;
+	struct SH_Fragment * child3;
+	struct SH_Fragment * child4;
+	struct SH_Fragment * child5;
+	struct SH_Fragment * child6;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("body",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("p", data, NULL);
+	child2 = SH_NodeFragment_new ("p", data, NULL);
+	child3 = SH_NodeFragment_new ("p", data, NULL);
+	child4 = SH_NodeFragment_new ("p", data, NULL);
+	child5 = SH_NodeFragment_new ("p", data, NULL);
+	child6 = SH_NodeFragment_new ("p", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child2, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child3, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child4, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child5, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_append_child (parent, child6, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+
+	ck_assert_int_eq (10, parent->child_s);
+	ck_assert_int_eq (6, parent->child_n);
+	ck_assert_ptr_eq (child1, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child1);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child1);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (5, parent->child_n);
+	ck_assert_ptr_eq (child2, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child2);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child2);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (4, parent->child_n);
+	ck_assert_ptr_eq (child3, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child3);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child3);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (3, parent->child_n);
+	ck_assert_ptr_eq (child4, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child4);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child4);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (2, parent->child_n);
+	ck_assert_ptr_eq (child5, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child5);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child5);
+	ck_assert_int_eq (5, parent->child_s);
+	ck_assert_int_eq (1, parent->child_n);
+	ck_assert_ptr_eq (child6, parent->childs[0]);
+
+	_status_preinit (status);
+	child = remove_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child6);
+	ck_assert_ptr_eq (NULL, child->parent);
+	ck_assert (succeed (&status));
+	SH_Fragment_free (child6);
+	ck_assert_int_eq (0, parent->child_s);
+	ck_assert_int_eq (0, parent->child_n);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_remove_self_no_error)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test erroneous call */
+	result = SH_Fragment_remove (parent, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test real */
+	result = SH_Fragment_remove (child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	result = SH_Fragment_remove (child, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	SH_Fragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_remove_self_with_error)
+{
+	struct SH_Status status;
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test erroneous call */
+	_status_preinit (status);
+	result = SH_Fragment_remove (parent, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_STATE, status.status);
+
+	/* test real */
+	_status_preinit (status);
+	result = SH_Fragment_remove (child, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	_status_preinit (status);
+	result = SH_Fragment_remove (child, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_BUG, status.status);
+
+	SH_Fragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_self_no_error)
+{
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	/* test erroneous call */
+	result = SH_Fragment_delete (parent, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	result = SH_Fragment_delete (child, NULL);
+	ck_assert_int_eq (FALSE, result);
+	child->parent = NULL;
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test real */
+	result = SH_Fragment_delete (child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_self_with_error)
+{
+	struct SH_Status status;
+	struct SH_Fragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = SH_NodeFragment_new ("html", data, NULL);
+	child = SH_NodeFragment_new ("head", data, NULL);
+
+	/* test erroneous call */
+	_status_preinit (status);
+	result = SH_Fragment_remove (parent, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_STATE, status.status);
+
+	/* test bug check */
+	child->parent = (struct SH_NodeFragment *)parent;
+	_status_preinit (status);
+	result = SH_Fragment_delete (child, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_BUG, status.status);
+	child->parent = NULL;
+
+	result = SH_NodeFragment_append_child ((struct SH_NodeFragment *)
+	                                       parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	/* test real */
+	_status_preinit (status);
+	result = SH_Fragment_delete (child, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	SH_Fragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_remove_no_error)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_remove_child (parent, 1, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	result = SH_NodeFragment_remove_child (parent, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_remove_with_error)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_remove_child (parent, 1, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_remove_child (parent, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_no_error)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	result = SH_NodeFragment_delete_child (parent, 1, NULL);
+	ck_assert_int_eq (FALSE, result);
+
+	result = SH_NodeFragment_delete_child (parent, 0, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_delete_with_error)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_delete_child (parent, 1, &status);
+	ck_assert_int_eq (FALSE, result);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	_status_preinit (status);
+	result = SH_NodeFragment_delete_child (parent, 0, &status);
+	ck_assert_int_eq (TRUE, result);
+	ck_assert (succeed (&status));
+
+	SH_NodeFragment_free (parent);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_pop_no_error)
+{
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	child = SH_NodeFragment_pop_child (parent, 1, NULL);
+	ck_assert_ptr_eq (NULL, child);
+
+	child = SH_NodeFragment_pop_child (parent, 0, NULL);
+	ck_assert_ptr_eq (child, child1);
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
+START_TEST(test_node_fragment_child_remove_pop_with_error)
+{
+	struct SH_Status status;
+	struct SH_NodeFragment * parent;
+	struct SH_Fragment * child;
+	struct SH_Fragment * child1;
+	SH_Data * data;
+	bool result;
+
+	data = SH_Data_new (NULL);
+
+	parent = (struct SH_NodeFragment *)SH_NodeFragment_new ("html",
+	                                                        data,
+	                                                        NULL);
+	child1 = SH_NodeFragment_new ("body", data, NULL);
+
+	result = SH_NodeFragment_append_child (parent, child1, NULL);
+	ck_assert_int_eq (TRUE, result);
+
+	_status_preinit (status);
+	child = SH_NodeFragment_pop_child (parent, 1, &status);
+	ck_assert_ptr_eq (NULL, child);
+	ck_assert (failed (&status));
+	ck_assert_int_eq (E_VALUE, status.status);
+
+	_status_preinit (status);
+	child = SH_NodeFragment_pop_child (parent, 0, &status);
+	ck_assert_ptr_eq (child, child1);
+	ck_assert (succeed (&status));
+
+	SH_NodeFragment_free (parent);
+	SH_Fragment_free (child);
+
+	SH_Data_free (data);
+}
+END_TEST
+
 START_TEST(test_node_fragment_html)
 {
 	struct SH_Status status;
@@ -1111,6 +1686,18 @@ Suite * fragment_suite (void)
 	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_child_remove_no_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_with_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_self_no_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_self_with_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_self_no_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_self_with_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_no_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_remove_with_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_no_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_delete_with_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_pop_no_error);
+	tcase_add_test (tc_core, test_node_fragment_child_remove_pop_with_error);
 	tcase_add_test (tc_core, test_node_fragment_html);
 	suite_add_tcase (s, tc_core);
 
-- 
GitLab