Improve test_qdsocket
[fwd.git] / test / test_qdsocket.c
1 /*
2  * Test for qdsocket.c
3  *
4  * Copyright (C) 2015 Chris Jaekl
5  */
6
7 #include <string.h>
8
9 #include "qdtestcase.h"
10
11 #include "mock_io.h"
12 #include "qdsocket.h"
13 #include "qdtypes.h"
14
15 static const char * DATA = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ345678961234567897123456789812345678991234567890";
16
17 void setUp(void)
18 {
19   //This is run before EACH TEST
20 }
21
22 void tearDown(void)
23 {
24 }
25
26 void test_qdSockInit(void)
27 {
28     struct qdSocket sock;
29
30     qdSockInit(&sock);
31
32     TEST_ASSERT_EQUAL(0, sock.sd);
33     TEST_ASSERT_EQUAL(0, sock.toWrite);
34     TEST_ASSERT_EQUAL(FALSE, sock.closeRequested);
35 }
36
37 void test_qdSockWrite_socketBusy(void)
38 {
39     ssize_t ret;
40     struct qdSocket sock;
41     char buf[32];
42
43     memset(buf, 'A', 32);
44
45     qdSockInit(&sock);
46
47     qdMock_resetWriteBuf(0);
48     
49     ret = qdSockWrite(&sock, buf, 32);
50
51     TEST_ASSERT_EQUAL(0, ret);
52     TEST_ASSERT_EQUAL(32, sock.toWrite);
53     TEST_ASSERT_EQUAL(FALSE, sock.closeRequested);
54     TEST_ASSERT_EQUAL(0, memcmp(buf, sock.buf, 32));
55
56     TEST_ASSERT_EQUAL(0, qdMock_getNumBytesWritten());
57 }
58
59 void test_qdSockWrite_partWritten(void)
60 {
61     ssize_t ret;
62     struct qdSocket sock;
63     char buf[32];
64
65     memcpy(buf, DATA, 32);
66
67     qdSockInit(&sock);
68
69     qdMock_resetWriteBuf(17);
70
71     ret = qdSockWrite(&sock, buf, 32);
72
73     TEST_ASSERT_EQUAL(17, ret);
74     TEST_ASSERT_EQUAL(15, sock.toWrite);
75     TEST_ASSERT_EQUAL(FALSE, sock.closeRequested);
76     TEST_ASSERT_EQUAL(0, memcmp(buf + 17, sock.buf, 15));
77
78     TEST_ASSERT_EQUAL(17, qdMock_getNumBytesWritten());
79     TEST_ASSERT_EQUAL(0, memcmp(buf, qdMock_getBytesWritten(), 17));
80
81     qdMock_resetWriteBuf(17);
82
83     ret = qdSockFlush(&sock);
84
85     TEST_ASSERT_EQUAL(15, ret);
86     TEST_ASSERT_EQUAL(0, sock.toWrite);
87     TEST_ASSERT_EQUAL(FALSE, sock.closeRequested);
88
89     TEST_ASSERT_EQUAL(15, qdMock_getNumBytesWritten());
90     TEST_ASSERT_EQUAL(0, memcmp(buf + 17, qdMock_getBytesWritten(), 15));
91 }
92
93 #define WWVB_SIZE 33
94 void test_qdSockWrite_writeWithVariedBuffering(void)
95 {
96     ssize_t ret;
97     struct qdSocket sock;
98     char buf[WWVB_SIZE];
99     const char * expected;
100     const char * actual;
101     int chunkSize;
102
103     memcpy(buf, DATA, WWVB_SIZE);
104
105     // Constrain socket writes to chunkSize bytes at a time.
106     // Try various different chunk sizes, and confirm that the
107     // whole write eventually succeeds, after enough calls to 
108     // qdSockFlush().
109     // 
110     for (chunkSize = 1; chunkSize <= (WWVB_SIZE + 1); ++chunkSize) {
111         qdSockInit(&sock);
112         qdMock_resetWriteBuf(chunkSize);
113
114         expected = &(buf[0]);
115         ret = qdSockWrite(&sock, buf, WWVB_SIZE);
116
117         while (ret > 0) {
118             actual = qdMock_getBytesWritten();
119             while (ret > 0) {
120                 TEST_ASSERT_EQUAL(*expected, *actual);
121                 ++expected;
122                 ++actual;
123                 --ret;
124             }
125
126             qdMock_resetWriteBuf(chunkSize);
127             ret = qdSockFlush(&sock);
128         }
129     }
130 }
131
132 #define BUBTF_SIZE      80
133
134 void test_qdSockWrite_buildUpBufferThenFlush(void)
135 {
136     struct qdSocket sock;
137     char buf[BUBTF_SIZE];
138     int chunkSize, chunk, numChunks;
139     ssize_t ret;
140
141     memcpy(buf, DATA, BUBTF_SIZE);
142
143     for (chunkSize = 1; chunkSize < BUBTF_SIZE; ++chunkSize) {
144         qdSockInit(&sock);
145         qdMock_resetWriteBuf(0);        // block all writes for the time being
146
147         numChunks = (BUBTF_SIZE / chunkSize) + ((BUBTF_SIZE % chunkSize) ? 1 : 0);
148
149         for (chunk = 0; chunk < numChunks; ++chunk) {
150             int offset = chunk * chunkSize;
151             int count = chunkSize;
152             if (offset + count > BUBTF_SIZE) {
153                 count = BUBTF_SIZE - offset;
154             }
155             ret = qdSockWrite(&sock, &(buf[offset]), count);
156             TEST_ASSERT_EQUAL(0, ret);  // nothing written, but should have been queued 
157         }
158
159         // Now that we've queued up the writes, unblock the socket and let them flow out
160         qdMock_resetWriteBuf(BUBTF_SIZE);
161
162         ret = qdSockFlush(&sock);
163         TEST_ASSERT_EQUAL(BUBTF_SIZE, ret);
164
165         TEST_ASSERT_EQUAL(0, memcmp(buf, qdMock_getBytesWritten(), BUBTF_SIZE));
166     }
167 }
168
169 void test_qdSockWrite_bufferAfterPartialFlush(void)
170 {
171     struct qdSocket sock;
172     char buf[BUBTF_SIZE];
173     int chunkSize, countWritten;
174     ssize_t ret;
175
176     chunkSize = BUBTF_SIZE / 4;
177
178     memcpy(buf, DATA, BUBTF_SIZE);
179
180     qdSockInit(&sock);
181     qdMock_resetWriteBuf(chunkSize);
182
183     // Write chunkSize bytes, and buffer another chunkSize bytes as pending
184     ret = qdSockWrite(&sock, buf, chunkSize * 2);
185     countWritten = chunkSize * 2;
186     TEST_ASSERT_EQUAL(chunkSize, ret);  
187
188     // Should have already written the first chunkSize bytes of buf
189     TEST_ASSERT_EQUAL(0, memcmp(buf, qdMock_getBytesWritten(), chunkSize));
190
191     // Queue a further chunkSize bytes
192     ret = qdSockWrite(&sock, (buf + countWritten), chunkSize);
193     countWritten += chunkSize;
194     TEST_ASSERT_EQUAL(0, ret);  // nothing flushed, because socket is "blocked"
195
196     // Flush chunkSize bytes
197     qdMock_resetWriteBuf(chunkSize);
198     ret = qdSockFlush(&sock);
199     TEST_ASSERT_EQUAL(chunkSize, ret);
200     TEST_ASSERT_EQUAL(0, memcmp((buf + chunkSize), qdMock_getBytesWritten(), chunkSize));
201
202     // The story so far:
203     //    Wrote (chunkSize * 3) bytes
204     //    Flushed (chunkSize * 2) bytes
205     //    Not yet written:  BUBTF_SIZE - (chunkSize * 3) bytes
206
207     // Queue the rest of the data
208     ret = qdSockWrite(&sock, (buf + countWritten), (BUBTF_SIZE - countWritten));
209     countWritten = BUBTF_SIZE;
210     TEST_ASSERT_EQUAL(0, ret);  // socket is blocked, so nothing made it through
211
212     // Flush the rest
213     qdMock_resetWriteBuf(BUBTF_SIZE);
214     ret = qdSockFlush(&sock);
215     TEST_ASSERT_EQUAL(BUBTF_SIZE - (chunkSize * 2), ret);
216     TEST_ASSERT_EQUAL(0, memcmp((buf + (chunkSize * 2)), qdMock_getBytesWritten(), (BUBTF_SIZE - (chunkSize * 2))));
217 }
218
219 // TODO:  Should have more tests here:
220 // - write buffer overflow (not yet implemented anyway...)
221
222 int main(void)
223 {
224   UnityBegin("test_qdsocket.c");
225
226   // RUN_TEST calls runTest
227   RUN_TEST(test_qdSockInit);
228   RUN_TEST(test_qdSockWrite_socketBusy);
229   RUN_TEST(test_qdSockWrite_partWritten);
230   RUN_TEST(test_qdSockWrite_writeWithVariedBuffering);
231   RUN_TEST(test_qdSockWrite_buildUpBufferThenFlush);
232   RUN_TEST(test_qdSockWrite_bufferAfterPartialFlush);
233
234   UnityEnd();
235   return 0;
236 }