1//
2//	ListTMethodsTest.m
3//	Tests
4//
5//	Copyright (c) 2020 Apple Inc. All rights reserved.
6//
7
8#import <XCTest/XCTest.h>
9#include "list.h"
10#include "mDNSEmbeddedAPI.h"
11#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
12
13typedef struct test_struct_t {
14	mDNSu8	field_one;
15	mDNSu32 field_two;
16} test_struct_t;
17
18@interface ListTMethodsTest : XCTestCase
19
20@end
21
22@implementation ListTMethodsTest
23
24- (void)testListInitAndUninit{
25	list_t list;
26
27	list_init(&list, sizeof(test_struct_t));
28	XCTAssertEqual(list.head_ptr,		&list.head,				@"list.head_ptr should point to list.head");
29	XCTAssertEqual(list.tail_ptr,		&list.tail,				@"list.tail_ptr should point to list.tail");
30	XCTAssertEqual(list.head_ptr->next, list.tail_ptr,			@"The next node of head should be tail");
31	XCTAssertEqual(list.tail_ptr->prev, list.head_ptr,			@"The previous node of tail should be head");
32	XCTAssertEqual(list.data_size,		sizeof(test_struct_t),	@"The data size should be sizeof(test_struct_t)");
33
34	list_uninit(&list);
35	XCTAssertEqual(list.data_size, 0,			@"The data size should be 0");
36	XCTAssertNil((__bridge id)list.head.next,	@"The next node of head should be NULL");
37	XCTAssertNil((__bridge id)list.tail.prev,	@"The previous node of tail should be NULL");
38	XCTAssertNil((__bridge id)list.head_ptr,	@"The head pointer should point to NULL");
39	XCTAssertNil((__bridge id)list.tail_ptr,	@"The tail pointer should point to NULL");
40}
41
42- (void)testListGeneralOperation{
43	mStatus error;
44	list_t	list;
45	mDNSBool empty;
46	mDNSu8 count;
47	test_struct_t *append_node_data_1, *append_node_data_2, *prepend_node_data_1, *prepend_node_data_2;
48	list_node_t *first_node, *second_node, *third_node, *fourth_node;
49
50	// Initialize
51	list_init(&list, sizeof(test_struct_t));
52
53	// Get first and last for empty list
54	XCTAssertNil((__bridge id)list_get_first(&list));
55	XCTAssertNil((__bridge id)list_get_last(&list));
56
57	// Append succeeds
58	error = list_append_uinitialized(&list, sizeof(test_struct_t), (void **)&append_node_data_1);
59	XCTAssertEqual(error, mStatus_NoError, @"list_append_uinitialized failed; error_description='%s'", mStatusDescription(error));
60	first_node = list.head_ptr->next;
61	XCTAssertEqual(first_node->prev, list.head_ptr,			@"The first node should point to head");
62	XCTAssertEqual(first_node->next, list.tail_ptr,			@"The next of first node should point to tail");
63	XCTAssertEqual(list.tail_ptr->prev, first_node,			@"The previous of tail should point to first node");
64	XCTAssertEqual((void *)first_node->data, (void *)append_node_data_1, @"The data field should be equal to the returned data pointer");
65
66	// Get first and last
67	XCTAssertEqual(list_get_first(&list),	first_node);
68	XCTAssertEqual(list_get_last(&list),	first_node);
69
70	// Append fails
71	error = list_append_uinitialized(&list, sizeof(test_struct_t) - 1, (void **)&append_node_data_2);
72	XCTAssertEqual(error, mStatus_BadParamErr, @"List should not add new node since the type of embedded data does not match");
73
74	// Empty test
75	empty = list_empty(&list);
76	XCTAssertFalse(empty, @"List should not be empty");
77
78	// Count test
79	count = list_count_node(&list);
80	XCTAssertEqual(count, 1, @"There should be only 1 node");
81
82	// Append 2nd succeeds
83	error = list_append_uinitialized(&list, sizeof(test_struct_t), (void **)&append_node_data_2);
84	XCTAssertEqual(error, mStatus_NoError, @"list_append_uinitialized failed; error_description='%s'", mStatusDescription(error));
85	second_node = list.tail_ptr->prev;
86	XCTAssertEqual(first_node->next,			second_node);
87	XCTAssertEqual(first_node->prev,			list.head_ptr);
88	XCTAssertEqual(first_node->next,			second_node);
89	XCTAssertEqual(second_node->next,			list.tail_ptr);
90	XCTAssertEqual(second_node->prev,			first_node);
91	XCTAssertEqual((void *)second_node->data,	(void *)append_node_data_2);
92
93	// Count test
94	count = list_count_node(&list);
95	XCTAssertEqual(count, 2);
96
97	// Get first and last
98	XCTAssertEqual(list_get_first(&list),	first_node);
99	XCTAssertEqual(list_get_last(&list),	second_node);
100
101	// Prepend 3rd succeeds
102	error = list_prepend_uinitialized(&list, sizeof(test_struct_t), (void **)&prepend_node_data_1);
103	XCTAssertEqual(error, mStatus_NoError);
104	third_node = list.head_ptr->next;
105	XCTAssertEqual(third_node->next,			first_node);
106	XCTAssertEqual(third_node->prev,			list.head_ptr);
107	XCTAssertEqual(first_node->prev,			third_node);
108	XCTAssertEqual((void *)third_node->data,	(void *)prepend_node_data_1);
109
110	// Count test
111	count = list_count_node(&list);
112	XCTAssertEqual(count, 3);
113
114	// Get first and last
115	XCTAssertEqual(list_get_first(&list),	third_node);
116	XCTAssertEqual(list_get_last(&list),	second_node);
117
118	// Prepend fails
119	error = list_prepend_uinitialized(&list, sizeof(test_struct_t) - 1, (void **)&prepend_node_data_2);
120	XCTAssertEqual(error, mStatus_BadParamErr);
121
122	// Preopend 4th succeeds
123	error = list_prepend_uinitialized(&list, sizeof(test_struct_t), (void **)&prepend_node_data_2);
124	XCTAssertEqual(error, mStatus_NoError);
125	fourth_node = list.head_ptr->next;
126	XCTAssertEqual(fourth_node->next,			third_node);
127	XCTAssertEqual(fourth_node->prev,			list.head_ptr);
128	XCTAssertEqual(third_node->prev,			fourth_node);
129	XCTAssertEqual((void *)fourth_node->data,	(void *)prepend_node_data_2);
130
131	// Count test
132	count = list_count_node(&list);
133	XCTAssertEqual(count, 4);
134
135	// Get first and last
136	XCTAssertEqual(list_get_first(&list),	fourth_node);
137	XCTAssertEqual(list_get_last(&list),	second_node);
138
139	// Iteration test
140	for (list_node_t *node = list_get_first(&list); !list_has_ended(&list, node); node = list_next(node)) {
141		if (node == first_node) {
142			XCTAssertEqual((void *)node->data, (void *)append_node_data_1);
143		} else if (node == second_node) {
144			XCTAssertEqual((void *)node->data, (void *)append_node_data_2);
145		} else if (node == third_node) {
146			XCTAssertEqual((void *)node->data, (void *)prepend_node_data_1);
147		} else if (node == fourth_node) {
148			XCTAssertEqual((void *)node->data, (void *)prepend_node_data_2);
149		} else {
150			XCTAssertTrue(mDNSfalse, @"Unknown node added into the list");
151		}
152	}
153
154	// Delete one node with node pointer
155	list_node_delete(first_node);
156	XCTAssertEqual(third_node->next,		second_node);
157	XCTAssertEqual(third_node->prev,		fourth_node);
158	XCTAssertEqual(second_node->prev,		third_node);
159	XCTAssertEqual(list_count_node(&list),	3);
160	XCTAssertFalse(list_empty(&list));
161
162	// Delete one node with data pointer that exists
163	error = list_delete_node_with_data_ptr(&list, prepend_node_data_2);
164	XCTAssertEqual(error, mStatus_NoError);
165	XCTAssertEqual(list_get_first(&list),	third_node);
166	XCTAssertEqual(list_get_last(&list),	second_node);
167	XCTAssertEqual(third_node->next,		second_node);
168	XCTAssertEqual(third_node->prev,		list.head_ptr);
169	XCTAssertEqual(second_node->next,		list.tail_ptr);
170	XCTAssertEqual(list_count_node(&list),	2);
171	XCTAssertFalse(list_empty(&list));
172
173	// Delete one node with data pointer that does not exist
174	error = list_delete_node_with_data_ptr(&list, prepend_node_data_2 + 1);
175	XCTAssertEqual(error,					mStatus_NoSuchKey);
176	XCTAssertEqual(list_get_first(&list),	third_node);
177	XCTAssertEqual(list_get_last(&list),	second_node);
178	XCTAssertEqual(third_node->next,		second_node);
179	XCTAssertEqual(third_node->prev,		list.head_ptr);
180	XCTAssertEqual(second_node->next,		list.tail_ptr);
181	XCTAssertEqual(list_count_node(&list),	2);
182	XCTAssertFalse(list_empty(&list));
183
184	// Delete all the nodes
185	list_node_delete_all(&list);
186
187	// Count test
188	count = list_count_node(&list);
189	XCTAssertEqual(count, 0);
190
191	// Empty test
192	empty = list_empty(&list);
193	XCTAssertTrue(empty);
194
195	// Iterate through the empty list
196	for (list_node_t *node = list_get_first(&list); !list_has_ended(&list, node); node = list_next(node)) {
197		XCTAssertFalse(mDNStrue, @"Should never excute this line if the line is empty");
198	}
199
200	// uninitialize the list
201	list_uninit(&list);
202	XCTAssertEqual(list.data_size, 0);
203	XCTAssertNil((__bridge id)list.head.next);
204	XCTAssertNil((__bridge id)list.tail.prev);
205	XCTAssertNil((__bridge id)list.head_ptr);
206	XCTAssertNil((__bridge id)list.tail_ptr);
207}
208@end
209
210#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
211