29 #include "cx/test.h" |
29 #include "cx/test.h" |
30 #include "util_allocator.h" |
30 #include "util_allocator.h" |
31 |
31 |
32 #include "cx/buffer.h" |
32 #include "cx/buffer.h" |
33 |
33 |
34 static CX_TEST_SUBROUTINE(expect_default_flush_config, CxBuffer *buf) { |
|
35 CX_TEST_ASSERT(buf->flush_blkmax == 0); |
|
36 CX_TEST_ASSERT(buf->flush_blksize == 4096); |
|
37 CX_TEST_ASSERT(buf->flush_threshold == SIZE_MAX); |
|
38 CX_TEST_ASSERT(buf->flush_func == NULL); |
|
39 CX_TEST_ASSERT(buf->flush_target == NULL); |
|
40 } |
|
41 |
|
42 CX_TEST(test_buffer_init_wrap_space) { |
34 CX_TEST(test_buffer_init_wrap_space) { |
43 CxTestingAllocator talloc; |
35 CxTestingAllocator talloc; |
44 cx_testing_allocator_init(&talloc); |
36 cx_testing_allocator_init(&talloc); |
45 CxAllocator *alloc = &talloc.base; |
37 CxAllocator *alloc = &talloc.base; |
46 CX_TEST_DO { |
38 CX_TEST_DO { |
47 CxBuffer buf; |
39 CxBuffer buf; |
48 void *space = cxMalloc(alloc, 16); |
40 void *space = cxMalloc(alloc, 16); |
49 cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_DEFAULT); |
41 cxBufferInit(&buf, space, 16, alloc, CX_BUFFER_DEFAULT); |
50 CX_TEST_CALL_SUBROUTINE(expect_default_flush_config, &buf); |
42 CX_TEST_ASSERT(buf.flush == NULL); |
51 CX_TEST_ASSERT(buf.space == space); |
43 CX_TEST_ASSERT(buf.space == space); |
52 CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0); |
44 CX_TEST_ASSERT((buf.flags & CX_BUFFER_AUTO_EXTEND) == 0); |
53 CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == 0); |
45 CX_TEST_ASSERT((buf.flags & CX_BUFFER_FREE_CONTENTS) == 0); |
54 CX_TEST_ASSERT(buf.pos == 0); |
46 CX_TEST_ASSERT(buf.pos == 0); |
55 CX_TEST_ASSERT(buf.size == 0); |
47 CX_TEST_ASSERT(buf.size == 0); |
1088 cxBufferDestroy(&buf); |
1072 cxBufferDestroy(&buf); |
1089 } |
1073 } |
1090 |
1074 |
1091 CX_TEST(test_buffer_write_flush_at_capacity) { |
1075 CX_TEST(test_buffer_write_flush_at_capacity) { |
1092 CxBuffer buf, target; |
1076 CxBuffer buf, target; |
1093 cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
1077 cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
1094 cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); |
1078 cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); |
1095 memcpy(buf.space, "prep\0\0\0\0\0\0\0\0\0\0\0\0", 16); |
1079 memset(buf.space, 0, 8); |
1096 buf.capacity = 8; |
1080 cxBufferPutString(&buf, "prep"); |
1097 buf.size = buf.pos = 4; |
1081 CX_TEST_DO { |
1098 buf.flush_target = ⌖ |
1082 CxBufferFlushConfig flush; |
1099 buf.flush_func = (cx_write_func)cxBufferWrite; |
1083 flush.threshold = 0; |
1100 buf.flush_blkmax = 1; |
1084 flush.blksize = 32; |
1101 CX_TEST_DO { |
1085 flush.blkmax = 1; |
|
1086 flush.target = ⌖ |
|
1087 flush.wfunc = (cx_write_func)cxBufferWrite; |
|
1088 CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); |
1102 size_t written = cxBufferWrite("foo", 1, 3, &buf); |
1089 size_t written = cxBufferWrite("foo", 1, 3, &buf); |
1103 CX_TEST_ASSERT(written == 3); |
1090 CX_TEST_ASSERT(written == 3); |
1104 CX_TEST_ASSERT(buf.pos == 7); |
1091 CX_TEST_ASSERT(buf.pos == 7); |
1105 CX_TEST_ASSERT(buf.size == 7); |
1092 CX_TEST_ASSERT(buf.size == 7); |
1106 CX_TEST_ASSERT(target.pos == 0); |
1093 CX_TEST_ASSERT(target.pos == 0); |
1107 CX_TEST_ASSERT(target.size == 0); |
1094 CX_TEST_ASSERT(target.size == 0); |
1108 written = cxBufferWrite("hello", 1, 5, &buf); |
1095 written = cxBufferWrite("hello", 1, 5, &buf); |
1109 CX_TEST_ASSERT(written == 5); |
1096 CX_TEST_ASSERT(written == 5); |
1110 CX_TEST_ASSERT(buf.pos == 0); |
1097 CX_TEST_ASSERT(buf.pos == 5); |
1111 CX_TEST_ASSERT(buf.size == 0); |
1098 CX_TEST_ASSERT(buf.size == 5); |
1112 CX_TEST_ASSERT(buf.capacity == 8); |
1099 CX_TEST_ASSERT(buf.capacity == 8); |
1113 CX_TEST_ASSERT(target.pos == 12); |
1100 CX_TEST_ASSERT(target.pos == 7); |
1114 CX_TEST_ASSERT(target.size == 12); |
1101 CX_TEST_ASSERT(target.size == 7); |
1115 CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoohello", 12)); |
1102 CX_TEST_ASSERT(0 == memcmp(buf.space, "hello", 5)); |
|
1103 CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoo", 7)); |
1116 } |
1104 } |
1117 cxBufferDestroy(&buf); |
1105 cxBufferDestroy(&buf); |
1118 cxBufferDestroy(&target); |
1106 cxBufferDestroy(&target); |
1119 } |
1107 } |
1120 |
1108 |
1121 CX_TEST(test_buffer_write_flush_at_threshold) { |
1109 CX_TEST(test_buffer_write_flush_at_threshold) { |
1122 CxBuffer buf, target; |
1110 CxBuffer buf, target; |
1123 cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
1111 cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
1124 cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); |
1112 cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
1125 memcpy(buf.space, "prep\0\0\0\0\0\0\0\0\0\0\0\0", 16); |
1113 cxBufferPutString(&buf, "prep"); |
1126 buf.capacity = 8; |
1114 CX_TEST_DO { |
1127 buf.size = buf.pos = 4; |
1115 CxBufferFlushConfig flush; |
1128 buf.flush_target = ⌖ |
1116 flush.threshold = 12; |
1129 buf.flush_func = (cx_write_func)cxBufferWrite; |
1117 flush.blksize = 32; |
1130 buf.flush_blkmax = 1; |
1118 flush.blkmax = 1; |
1131 buf.flush_threshold = 12; |
1119 flush.target = ⌖ |
1132 buf.flags |= CX_BUFFER_AUTO_EXTEND; |
1120 flush.wfunc = (cx_write_func)cxBufferWrite; |
1133 CX_TEST_DO { |
1121 CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); |
1134 size_t written = cxBufferWrite("foobar", 1, 6, &buf); |
1122 size_t written = cxBufferWrite("foobar", 1, 6, &buf); |
1135 CX_TEST_ASSERT(written == 6); |
1123 CX_TEST_ASSERT(written == 6); |
1136 CX_TEST_ASSERT(buf.pos == 10); |
1124 CX_TEST_ASSERT(buf.pos == 10); |
1137 CX_TEST_ASSERT(buf.size == 10); |
1125 CX_TEST_ASSERT(buf.size == 10); |
1138 CX_TEST_ASSERT(buf.capacity >= 10); |
1126 CX_TEST_ASSERT(buf.capacity >= 10); |
1139 CX_TEST_ASSERT(buf.capacity <= 12); |
1127 CX_TEST_ASSERT(buf.capacity <= 12); |
1140 CX_TEST_ASSERT(target.pos == 0); |
1128 CX_TEST_ASSERT(target.pos == 0); |
1141 CX_TEST_ASSERT(target.size == 0); |
1129 CX_TEST_ASSERT(target.size == 0); |
1142 written = cxBufferWrite("hello", 1, 5, &buf); |
1130 written = cxBufferWrite("hello", 1, 5, &buf); |
1143 CX_TEST_ASSERT(written == 5); |
1131 CX_TEST_ASSERT(written == 5); |
1144 CX_TEST_ASSERT(buf.pos == 0); |
1132 CX_TEST_ASSERT(buf.pos == 5); |
1145 CX_TEST_ASSERT(buf.size == 0); |
1133 CX_TEST_ASSERT(buf.size == 5); |
1146 CX_TEST_ASSERT(buf.capacity <= 12); |
1134 CX_TEST_ASSERT(buf.capacity <= 12); |
1147 CX_TEST_ASSERT(target.pos == 15); |
1135 CX_TEST_ASSERT(target.pos == 10); |
1148 CX_TEST_ASSERT(target.size == 15); |
1136 CX_TEST_ASSERT(target.size == 10); |
1149 CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoobarhello", 15)); |
1137 CX_TEST_ASSERT(0 == memcmp(buf.space, "hello", 5)); |
|
1138 CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoobar", 10)); |
1150 } |
1139 } |
1151 cxBufferDestroy(&buf); |
1140 cxBufferDestroy(&buf); |
1152 cxBufferDestroy(&target); |
1141 cxBufferDestroy(&target); |
1153 } |
1142 } |
1154 |
1143 |
1155 CX_TEST(test_buffer_write_flush_rate_limited) { |
1144 CX_TEST(test_buffer_write_flush_rate_limited_and_buffer_too_small) { |
|
1145 // the idea is that the target only accepts two bytes and |
|
1146 // then gives up... accepts another two bytes, gives up, etc. |
|
1147 // and at the same time, the written string is too large for |
|
1148 // the buffer (buffer can take 8, we want to write 13) |
1156 CxBuffer buf, target; |
1149 CxBuffer buf, target; |
1157 cxBufferInit(&target, NULL, 16, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
1150 cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
1158 cxBufferInit(&buf, NULL, 16, cxDefaultAllocator, CX_BUFFER_DEFAULT); |
1151 cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); |
1159 memcpy(buf.space, "prep\0\0\0\0\0\0\0\0\0\0\0\0", 16); |
1152 cxBufferPutString(&buf, "prep"); |
1160 buf.capacity = 8; |
1153 CX_TEST_DO { |
1161 buf.size = buf.pos = 4; |
1154 CxBufferFlushConfig flush; |
1162 buf.flush_target = ⌖ |
1155 flush.threshold = 0; |
1163 buf.flush_blkmax = 1; |
1156 flush.blksize = 32; |
1164 // limit the rate of the flush function and the capacity of the target |
1157 flush.blkmax = 1; |
1165 buf.flush_func = (cx_write_func) mock_write_limited_rate; |
1158 flush.target = ⌖ |
1166 target.capacity = 16; |
1159 flush.wfunc = (cx_write_func)mock_write_limited_rate; |
1167 target.flags &= ~CX_BUFFER_AUTO_EXTEND; |
1160 CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); |
1168 CX_TEST_DO { |
|
1169 size_t written = cxBufferWrite("foo", 1, 3, &buf); |
1161 size_t written = cxBufferWrite("foo", 1, 3, &buf); |
1170 CX_TEST_ASSERT(written == 3); |
1162 CX_TEST_ASSERT(written == 3); |
1171 CX_TEST_ASSERT(buf.pos == 7); |
1163 CX_TEST_ASSERT(buf.pos == 7); |
1172 CX_TEST_ASSERT(buf.size == 7); |
1164 CX_TEST_ASSERT(buf.size == 7); |
1173 CX_TEST_ASSERT(target.pos == 0); |
1165 CX_TEST_ASSERT(target.pos == 0); |
1179 CX_TEST_ASSERT(buf.size == 7); |
1171 CX_TEST_ASSERT(buf.size == 7); |
1180 CX_TEST_ASSERT(buf.capacity == 8); |
1172 CX_TEST_ASSERT(buf.capacity == 8); |
1181 CX_TEST_ASSERT(0 == memcmp(buf.space, " world!", 7)); |
1173 CX_TEST_ASSERT(0 == memcmp(buf.space, " world!", 7)); |
1182 CX_TEST_ASSERT(target.pos == 13); |
1174 CX_TEST_ASSERT(target.pos == 13); |
1183 CX_TEST_ASSERT(target.size == 13); |
1175 CX_TEST_ASSERT(target.size == 13); |
1184 CX_TEST_ASSERT(target.capacity == 16); |
1176 CX_TEST_ASSERT(target.capacity >= 13); |
1185 CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoohello,", 13)); |
1177 CX_TEST_ASSERT(0 == memcmp(target.space, "prepfoohello,", 13)); |
|
1178 } |
|
1179 cxBufferDestroy(&buf); |
|
1180 cxBufferDestroy(&target); |
|
1181 } |
|
1182 |
|
1183 CX_TEST(test_buffer_flush) { |
|
1184 CxBuffer buf, target; |
|
1185 cxBufferInit(&target, NULL, 8, cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); |
|
1186 cxBufferInit(&buf, NULL, 8, cxDefaultAllocator, CX_BUFFER_DEFAULT); |
|
1187 cxBufferPutString(&buf, "prepare"); |
|
1188 CX_TEST_DO { |
|
1189 CxBufferFlushConfig flush; |
|
1190 flush.threshold = 0; |
|
1191 flush.blksize = 2; |
|
1192 flush.blkmax = 2; |
|
1193 flush.target = ⌖ |
|
1194 flush.wfunc = (cx_write_func)cxBufferWrite; |
|
1195 CX_TEST_ASSERT(0 == cxBufferEnableFlushing(&buf, flush)); |
|
1196 CX_TEST_ASSERT(buf.size == 7); |
|
1197 buf.pos = 5; |
|
1198 size_t flushed = cxBufferFlush(&buf); |
|
1199 CX_TEST_ASSERT(flushed == flush.blkmax * flush.blksize); |
|
1200 CX_TEST_ASSERT(buf.pos == 1); |
|
1201 CX_TEST_ASSERT(buf.size == 3); |
|
1202 CX_TEST_ASSERT(target.pos == 4); |
|
1203 CX_TEST_ASSERT(target.size == 4); |
|
1204 CX_TEST_ASSERT(0 == memcmp(buf.space, "are", 3)); |
|
1205 CX_TEST_ASSERT(0 == memcmp(target.space, "prep", 4)); |
|
1206 flushed = cxBufferFlush(&buf); |
|
1207 CX_TEST_ASSERT(flushed == 1); |
|
1208 CX_TEST_ASSERT(buf.pos == 0); |
|
1209 CX_TEST_ASSERT(buf.size == 2); |
|
1210 CX_TEST_ASSERT(target.pos == 5); |
|
1211 CX_TEST_ASSERT(target.size == 5); |
|
1212 CX_TEST_ASSERT(0 == memcmp(buf.space, "re", 2)); |
|
1213 CX_TEST_ASSERT(0 == memcmp(target.space, "prepa", 5)); |
1186 } |
1214 } |
1187 cxBufferDestroy(&buf); |
1215 cxBufferDestroy(&buf); |
1188 cxBufferDestroy(&target); |
1216 cxBufferDestroy(&target); |
1189 } |
1217 } |
1190 |
1218 |