test: cover pipeTest
This commit is contained in:
1 parent
82089a684a
commit
9dfdd34540
1 file changed
+183
+183
@@ -0,0 +1,183 @@
|
||||
#include "ktest.h"
|
||||
#include "pipe.h"
|
||||
#include "string.h"
|
||||
|
||||
KTEST(pipeWriteThenReadRoundTrips)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
const char* msg = "hello pipe";
|
||||
int64 written = pipeWrite(h, msg, strlen(msg));
|
||||
KT_EQ(t, written, (int64)strlen(msg));
|
||||
|
||||
char buffer[32];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
int64 got = pipeRead(h, buffer, sizeof(buffer));
|
||||
KT_EQ(t, got, (int64)strlen(msg));
|
||||
KT_TRUE(t, memcmp(buffer, msg, strlen(msg)) == 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeReadOnEmptyOpenPipeWouldBlock)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
char buffer[8];
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), -1);
|
||||
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeReadZeroLengthIsNoop)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
char buffer[1];
|
||||
KT_EQ(t, pipeRead(h, buffer, 0), 0);
|
||||
KT_EQ(t, pipeWrite(h, buffer, 0), 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeFullWriteWouldBlockThenDrainsAndAcceptsMore)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
uint8 chunk[pipeBufferSize];
|
||||
memset(chunk, 0xAB, sizeof(chunk));
|
||||
|
||||
/* this exactly fills the ring. */
|
||||
int64 filled = pipeWrite(h, chunk, sizeof(chunk));
|
||||
KT_EQ(t, filled, (int64)sizeof(chunk));
|
||||
|
||||
/* buffer is full: further write must report "would block" */
|
||||
KT_EQ(t, pipeWrite(h, chunk, 1), -1);
|
||||
|
||||
/* drain some bytes, then more space is available */
|
||||
uint8 drained[64];
|
||||
int64 gotDrain = pipeRead(h, drained, sizeof(drained));
|
||||
KT_EQ(t, gotDrain, (int64)sizeof(drained));
|
||||
for (uint64 i = 0; i < sizeof(drained); i++)
|
||||
KT_EQU(t, drained[i], 0xAB);
|
||||
|
||||
int64 moreWritten = pipeWrite(h, chunk, sizeof(drained));
|
||||
KT_EQ(t, moreWritten, (int64)sizeof(drained));
|
||||
|
||||
pipeCloseRead(h);
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeEofAfterWriterClosedAndBufferDrained)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
const char* msg = "last bytes";
|
||||
KT_EQ(t, pipeWrite(h, msg, strlen(msg)), (int64)strlen(msg));
|
||||
|
||||
pipeCloseWrite(h);
|
||||
|
||||
/* data queued before close is still readable */
|
||||
char buffer[32];
|
||||
int64 got = pipeRead(h, buffer, sizeof(buffer));
|
||||
KT_EQ(t, got, (int64)strlen(msg));
|
||||
|
||||
/* now drained and no writer left: true end-of-file, not "would block" */
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), 0);
|
||||
KT_EQ(t, pipeRead(h, buffer, sizeof(buffer)), 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
}
|
||||
|
||||
KTEST(pipeWriteAfterReaderClosedIsBrokenPipe)
|
||||
{
|
||||
int h = pipeCreate();
|
||||
KT_GE(t, h, 0);
|
||||
|
||||
pipeCloseRead(h);
|
||||
|
||||
const char* msg = "nobody listening";
|
||||
KT_EQ(t, pipeWrite(h, msg, strlen(msg)), -1);
|
||||
|
||||
pipeCloseWrite(h);
|
||||
}
|
||||
|
||||
KTEST(pipeInvalidHandleIsRejected)
|
||||
{
|
||||
KT_FALSE(t, pipeValid(-1));
|
||||
KT_FALSE(t, pipeValid(999));
|
||||
|
||||
char buffer[4];
|
||||
KT_EQ(t, pipeRead(-1, buffer, sizeof(buffer)), -1);
|
||||
KT_EQ(t, pipeWrite(-1, buffer, sizeof(buffer)), -1);
|
||||
|
||||
/* closing an invalid handle must not crash */
|
||||
pipeCloseRead(-1);
|
||||
pipeCloseWrite(999);
|
||||
}
|
||||
|
||||
KTEST(pipeIndependentPipesDoNotInterfere)
|
||||
{
|
||||
int a = pipeCreate();
|
||||
int b = pipeCreate();
|
||||
KT_GE(t, a, 0);
|
||||
KT_GE(t, b, 0);
|
||||
KT_NE(t, a, b);
|
||||
|
||||
KT_EQ(t, pipeWrite(a, "AAAA", 4), 4);
|
||||
KT_EQ(t, pipeWrite(b, "BB", 2), 2);
|
||||
|
||||
char bufA[8];
|
||||
char bufB[8];
|
||||
memset(bufA, 0, sizeof(bufA));
|
||||
memset(bufB, 0, sizeof(bufB));
|
||||
|
||||
KT_EQ(t, pipeRead(b, bufB, sizeof(bufB)), 2);
|
||||
KT_TRUE(t, memcmp(bufB, "BB", 2) == 0);
|
||||
|
||||
KT_EQ(t, pipeRead(a, bufA, sizeof(bufA)), 4);
|
||||
KT_TRUE(t, memcmp(bufA, "AAAA", 4) == 0);
|
||||
|
||||
pipeCloseRead(a);
|
||||
pipeCloseWrite(a);
|
||||
pipeCloseRead(b);
|
||||
pipeCloseWrite(b);
|
||||
}
|
||||
|
||||
KTEST(pipeTableExhaustionAndReuse)
|
||||
{
|
||||
int handles[maxPipes + 1];
|
||||
int created = 0;
|
||||
|
||||
while (created < maxPipes + 1) {
|
||||
int h = pipeCreate();
|
||||
if (h < 0)
|
||||
break;
|
||||
handles[created++] = h;
|
||||
}
|
||||
|
||||
/* the table must run out before maxPipes+1 succeed */
|
||||
KT_LT(t, created, maxPipes + 1);
|
||||
KT_EQ(t, pipeCreate(), -1);
|
||||
|
||||
/* fully closing one pipe frees its slot for reuse */
|
||||
pipeCloseRead(handles[0]);
|
||||
pipeCloseWrite(handles[0]);
|
||||
int reused = pipeCreate();
|
||||
KT_GE(t, reused, 0);
|
||||
|
||||
pipeCloseRead(reused);
|
||||
pipeCloseWrite(reused);
|
||||
for (int i = 1; i < created; i++) {
|
||||
pipeCloseRead(handles[i]);
|
||||
pipeCloseWrite(handles[i]);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user