#include "unittest/TestSuite.h" #include "utilities/printfFormats.h" #include "utilities/IOUtilities.h" #include #include #include #include #include #include #include #define assertBytesMatch(expectedBytes, actualBytes, length) { \ char * _failString; \ unsigned int _index; \ \ _failString = malloc(strlen("Expected but got") + 3 * (length) * 2 + 1); \ _failString[0] = 0; \ strcat(_failString, "Expected"); \ for (_index = 0; _index < (length); _index++) { \ sprintf(_failString + strlen(_failString), " %02X", ((unsigned char *) (expectedBytes))[_index]); \ } \ strcat(_failString, " but got"); \ for (_index = 0; _index < (length); _index++) { \ sprintf(_failString + strlen(_failString), " %02X", ((unsigned char *) (actualBytes))[_index]); \ } \ \ TestCase_assert(!memcmp((expectedBytes), (actualBytes), (length)), "%s", _failString); \ \ free(_failString); \ } #ifdef WIN32 #include static int mkstemp(char * template) { int result = -1; mktemp(template); result = open(template, O_RDWR | O_BINARY | O_CREAT | O_EXCL | _O_SHORT_LIVED, _S_IREAD | _S_IWRITE); return result; } #endif static void testMemreadContextInit() { struct memreadContext context; char * data1 = "abcd", * data2 = "efg"; context = memreadContextInit(data1, 4); TestCase_assert(context.data == data1, "Expected %p but got %p", data1, context.data); TestCase_assert(context.length == 4, "Expected 4 but got %d", (int) context.length); TestCase_assert(context.position == 0, "Expected 0 but got %d", (int) context.position); context = memreadContextInit(data2, 3); TestCase_assert(context.data == data2, "Expected %p but got %p", data2, context.data); TestCase_assert(context.length == 3, "Expected 3 but got %d", (int) context.length); TestCase_assert(context.position == 0, "Expected 0 but got %d", (int) context.position); } static void testMemread() { char target[4]; char expectedTarget1[4] = {'a', 'b', 'c', 'd'}, expectedTarget2[4] = {'1', '2', '3', '\x00'}; struct memreadContext context; bool result; context = memreadContextInit("abcd1234", 8); memset(target, 0, 4); result = memread(&context, 4, target); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.position == 4, "Expected 4 but got %d", (int) context.position); assertBytesMatch(expectedTarget1, target, 4); memset(target, 0, 4); result = memread(&context, 3, target); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.position == 7, "Expected 7 but got %d", (int) context.position); assertBytesMatch(expectedTarget2, target, 4); result = memread(&context, 2, NULL); TestCase_assert(!result, "Expected false but got true"); TestCase_assert(context.position == 7, "Expected 7 but got %d", (int) context.position); result = memread(&context, 1, NULL); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.position == 8, "Expected 8 but got %d", (int) context.position); } static void testMemwriteContextInit() { struct memwriteContext context; char * data1 = "abcd", * data2 = "efg"; context = memwriteContextInit(data1, 4, 5, false); TestCase_assert(context.data == data1, "Expected %p but got %p", data1, context.data); TestCase_assert(context.length == 4, "Expected 4 but got %d", (int) context.length); TestCase_assert(context.allocatedSize == 5, "Expected 5 but got %d", (int) context.allocatedSize); TestCase_assert(context.position == 0, "Expected 0 but got %d", (int) context.position); TestCase_assert(!context.realloc, "Expected false but got true"); context = memwriteContextInit(data2, 3, 4, true); TestCase_assert(context.data == data2, "Expected %p but got %p", data2, context.data); TestCase_assert(context.length == 3, "Expected 3 but got %d", (int) context.length); TestCase_assert(context.allocatedSize == 4, "Expected 4 but got %d", (int) context.allocatedSize); TestCase_assert(context.position == 0, "Expected 0 but got %d", (int) context.position); TestCase_assert(context.realloc, "Expected true but got false"); } static void testMemwrite() { struct memwriteContext context; char target[4]; bool result; memset(target, 0, 4); context = memwriteContextInit(target, 3, 4, false); result = memwrite(&context, 2, "fg"); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.length == 3, "Expected 3 but got %d", (int) context.length); TestCase_assert(context.position == 2, "Expected 2 but got %d", (int) context.position); assertBytesMatch("fg\x00\x00", target, 4); result = memwrite(&context, 3, "sfd"); TestCase_assert(!result, "Expected false but got true"); TestCase_assert(context.length == 3, "Expected 3 but got %d", (int) context.length); TestCase_assert(context.position == 2, "Expected 2 but got %d", (int) context.position); assertBytesMatch("fg\x00\x00", target, 4); result = memwrite(&context, 1, "s"); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.length == 3, "Expected 3 but got %d", (int) context.length); TestCase_assert(context.position == 3, "Expected 3 but got %d", (int) context.position); assertBytesMatch("fgs\x00", target, 4); target[3] = 0xFF; result = memwrite(&context, 1, NULL); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.length == 4, "Expected 4 but got %d", (int) context.length); TestCase_assert(context.position == 4, "Expected 4 but got %d", (int) context.position); assertBytesMatch("fgs\x00", target, 4); context = memwriteContextInit(malloc(1), 0, 1, true); result = memwrite(&context, 2, "aa"); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.length == 2, "Expected 2 but got %d", (int) context.length); TestCase_assert(context.allocatedSize >= 2, "Expected >= 2 but got %d", (int) context.allocatedSize); TestCase_assert(context.position == 2, "Expected 2 but got %d", (int) context.position); assertBytesMatch("aa", context.data, 2); result = memwrite(&context, 5, NULL); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.length == 7, "Expected 7 but got %d", (int) context.length); TestCase_assert(context.allocatedSize >= 7, "Expected >= 7 but got %d", (int) context.allocatedSize); TestCase_assert(context.position == 7, "Expected 7 but got %d", (int) context.position); assertBytesMatch("aa\x00\x00\x00\x00\x00", context.data, 7); context.position = 6; result = memwrite(&context, 3, "baz"); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.length == 9, "Expected 9 but got %d", (int) context.length); TestCase_assert(context.allocatedSize >= 9, "Expected >= 9 but got %d", (int) context.allocatedSize); TestCase_assert(context.position == 9, "Expected 9 but got %d", (int) context.position); assertBytesMatch("aa\x00\x00\x00\x00""baz", context.data, 9); free(context.data); context = memwriteContextInit(NULL, 0, 0, true); result = memwrite(&context, 2, "bb"); TestCase_assert(result, "Expected true but got false"); TestCase_assert(context.length == 2, "Expected 2 but got %d", (int) context.length); TestCase_assert(context.allocatedSize == 2, "Expected 2 but got %d", (int) context.allocatedSize); TestCase_assert(context.position == 2, "Expected 2 but got %d", (int) context.position); assertBytesMatch("bb", context.data, 2); free(context.data); } static void testReadFileSimple() { char fileName[10]; int fileHandle; size_t length; void * result; FILE * file; strcpy(fileName, "tmpXXXXXX"); fileHandle = mkstemp(fileName); close(fileHandle); unlink(fileName); result = readFileSimple(fileName, NULL); TestCase_assert(result == NULL, "Expected NULL but got %p", result); strcpy(fileName, "tmpXXXXXX"); fileHandle = mkstemp(fileName); file = fdopen(fileHandle, "wb"); fprintf(file, "foo bar\nbaz"); fclose(file); result = readFileSimple(fileName, &length); unlink(fileName); TestCase_assert(result != NULL, "Expected non-NULL but got NULL"); TestCase_assert(length == 11, "Expected 11 but got %d", (int) length); assertBytesMatch("foo bar\nbaz", result, 11); strcpy(fileName, "tmpXXXXXX"); fileHandle = mkstemp(fileName); file = fdopen(fileHandle, "wb"); fprintf(file, "Hello, world!"); fclose(file); result = readFileSimple(fileName, &length); unlink(fileName); TestCase_assert(result != NULL, "Expected non-NULL but got NULL"); TestCase_assert(length == 13, "Expected 13 but got %d", (int) length); assertBytesMatch("Hello, world!", result, 13); } static void testWriteFileSimple() { char fileName[10]; int fileHandle; bool result; FILE * file; size_t fileLength; char * fileContents; strcpy(fileName, "tmpXXXXXX"); fileHandle = mkstemp(fileName); result = writeFileSimple(fileName, "foo bar\nbaz", 11); file = fdopen(fileHandle, "rb"); TestCase_assert(file != NULL, "writeFileSimple failed to create target file"); fseek(file, 0, SEEK_END); fileLength = ftell(file); fseek(file, 0, SEEK_SET); fileContents = malloc(fileLength); fread(fileContents, 1, fileLength, file); fclose(file); unlink(fileName); TestCase_assert(result, "Expected true but got false"); TestCase_assert(fileLength == 11, "Expected 11 but got %d", (int) fileLength); assertBytesMatch("foo bar\nbaz", fileContents, 11); free(fileContents); strcpy(fileName, "tmpXXXXXX"); fileHandle = mkstemp(fileName); result = writeFileSimple(fileName, "Hello, world!", 13); file = fdopen(fileHandle, "rb"); TestCase_assert(file != NULL, "writeFileSimple failed to create target file"); fseek(file, 0, SEEK_END); fileLength = ftell(file); fseek(file, 0, SEEK_SET); fileContents = malloc(fileLength); fread(fileContents, 1, fileLength, file); fclose(file); unlink(fileName); TestCase_assert(result, "Expected true but got false"); TestCase_assert(fileLength == 13, "Expected 13 but got %d", (int) fileLength); assertBytesMatch("Hello, world!", fileContents, 13); free(fileContents); } static void testWriteFileAtomic() { char fileName[10]; int fileHandle; bool result; FILE * file; size_t fileLength; char * fileContents; strcpy(fileName, "tmpXXXXXX"); fileHandle = mkstemp(fileName); close(fileHandle); result = writeFileAtomic(fileName, "foo bar\nbaz", 11); file = fopen(fileName, "rb"); TestCase_assert(file != NULL, "writeFileAtomic failed to create target file"); fseek(file, 0, SEEK_END); fileLength = ftell(file); fseek(file, 0, SEEK_SET); fileContents = malloc(fileLength); fread(fileContents, 1, fileLength, file); fclose(file); unlink(fileName); TestCase_assert(result, "Expected true but got false"); TestCase_assert(fileLength == 11, "Expected 11 but got %d", (int) fileLength); assertBytesMatch("foo bar\nbaz", fileContents, 11); free(fileContents); strcpy(fileName, "tmpXXXXXX"); fileHandle = mkstemp(fileName); close(fileHandle); result = writeFileAtomic(fileName, "Hello, world!", 13); file = fopen(fileName, "rb"); TestCase_assert(file != NULL, "writeFileAtomic failed to create target file"); fseek(file, 0, SEEK_END); fileLength = ftell(file); fseek(file, 0, SEEK_SET); fileContents = malloc(fileLength); fread(fileContents, 1, fileLength, file); fclose(file); unlink(fileName); TestCase_assert(result, "Expected true but got false"); TestCase_assert(fileLength == 13, "Expected 13 but got %d", (int) fileLength); assertBytesMatch("Hello, world!", fileContents, 13); free(fileContents); } static void testTemporaryFilePath() { int fd; const char * template, * path; const char * uniqueString; bool success; FILE * file; size_t fileLength; char * fileContents; template = "tmpXXXXXX"; uniqueString = "Unique string 1"; fd = -1; path = temporaryFilePath(template, &fd); TestCase_assert(path != NULL, "temporaryFilePath unexpectedly returned NULL"); TestCase_assert(strlen(path) >= strlen(template), "temporaryFilePath returned a shorter path (\"%s\") than the provided template", path); TestCase_assert(!strncmp(path + strlen(path) - strlen(template), template, 3), "Template prefix not preserved in path (\"%s\")", path); TestCase_assert(fd != -1, "temporaryFilePath didn't return a file descriptor"); success = writeFileSimple(path, uniqueString, strlen(uniqueString)); TestCase_assert(success, "Failed to write to returned path \"%s\"", path); file = fdopen(fd, "rb"); TestCase_assert(file != NULL, "temporaryFilePath didn't return a file descriptor that could be opened with fdopen"); fseek(file, 0, SEEK_END); fileLength = ftell(file); TestCase_assert(fileLength == strlen(uniqueString), "File length (%d) didn't match length of string written to path (%d)", (int) fileLength, (int) strlen(uniqueString)); fseek(file, 0, SEEK_SET); fileContents = malloc(fileLength); fread(fileContents, 1, fileLength, file); TestCase_assert(!memcmp(fileContents, uniqueString, fileLength), "File contents \"%.*s\" didn't match expected string \"%s\"", (int) fileLength, fileContents, uniqueString); fclose(file); unlink(path); template = "helloXXXXXX"; uniqueString = "Unique string 2"; fd = -1; path = temporaryFilePath(template, &fd); TestCase_assert(path != NULL, "temporaryFilePath unexpectedly returned NULL"); TestCase_assert(strlen(path) >= strlen(template), "temporaryFilePath returned a shorter path (\"%s\") than the provided template", path); TestCase_assert(!strncmp(path + strlen(path) - strlen(template), template, 5), "Template prefix not preserved in path (\"%s\")", path); TestCase_assert(fd != -1, "temporaryFilePath didn't return a file descriptor"); success = writeFileSimple(path, uniqueString, strlen(uniqueString)); TestCase_assert(success, "Failed to write to returned path \"%s\"", path); file = fdopen(fd, "rb"); TestCase_assert(file != NULL, "temporaryFilePath didn't return a file descriptor that could be opened with fdopen"); fseek(file, 0, SEEK_END); fileLength = ftell(file); TestCase_assert(fileLength == strlen(uniqueString), "File length (%d) didn't match length of string written to path (%d)", (int) fileLength, (int) strlen(uniqueString)); fseek(file, 0, SEEK_SET); fileContents = malloc(fileLength); fread(fileContents, 1, fileLength, file); TestCase_assert(!memcmp(fileContents, uniqueString, fileLength), "File contents \"%.*s\" didn't match expected string \"%s\"", (int) fileLength, fileContents, uniqueString); fclose(file); unlink(path); } static void testFilePathFunctions() { const char * path, * result; path = "abcd"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 4); path = "Hello.txt"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 6); path = "/path/to/Hello.txt"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 15); path = "/test.dir/"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 10); path = ".ext"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 1); path = "/hello/test.dir/name"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 20); path = "test.a"; result = getBaseName(path); TestCase_assertStringEqual(result, "test"); path = "test2.txt"; result = getBaseName(path); TestCase_assertStringEqual(result, "test2"); path = "test"; result = getBaseName(path); TestCase_assertStringEqual(result, "test"); path = "/hello/test.dir/name.ext"; result = getBaseName(path); TestCase_assertStringEqual(result, "/hello/test.dir/name"); path = "/hello/test.dir/name"; result = getBaseName(path); TestCase_assertStringEqual(result, "/hello/test.dir/name"); path = ""; result = getBaseName(path); TestCase_assertStringEqual(result, ""); path = "abcd"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path); path = "/path/to/Hello.txt"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path + 9); path = "local/path/to/a directory/"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path + 14); path = "/"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path); path = "abcd"; result = getDirectory(path); TestCase_assertStringEqual(result, ""); path = "abcd/efgh"; result = getDirectory(path); TestCase_assertStringEqual(result, "abcd/"); path = "/path/to/something"; result = getDirectory(path); TestCase_assertStringEqual(result, "/path/to/"); path = "/path"; result = getDirectory(path); TestCase_assertStringEqual(result, "/"); path = "/"; result = getDirectory(path); TestCase_assertStringEqual(result, "/"); #if defined(STEM_PLATFORM_windows) path = "C:\\path\\to\\Hello.txt"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 17); path = "\\test.dir\\"; result = getFileExtension(path); TestCase_assertStringPointerEqual(result, path + 10); path = "D:\\path\\to\\Hello.txt"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path + 11); path = "local\\path\\to\\a directory\\"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path + 14); path = "F:\\"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path); path = "G:"; result = getLastPathComponent(path); TestCase_assertStringPointerEqual(result, path); path = "abcd\\efgh"; result = getDirectory(path); TestCase_assertStringEqual(result, "abcd\\"); path = "\\path\\to\\something"; result = getDirectory(path); TestCase_assertStringEqual(result, "\\path\\to\\"); path = "C:\\path\\to\\something"; result = getDirectory(path); TestCase_assertStringEqual(result, "C:\\path\\to\\"); path = "\\path"; result = getDirectory(path); TestCase_assertStringEqual(result, "\\"); path = "D:\\path"; result = getDirectory(path); TestCase_assertStringEqual(result, "D:\\"); path = "\\"; result = getDirectory(path); TestCase_assertStringEqual(result, "\\"); path = "A:\\"; result = getDirectory(path); TestCase_assertStringEqual(result, "A:\\"); path = "a:\\"; result = getDirectory(path); TestCase_assertStringEqual(result, "a:\\"); path = "Z:"; result = getDirectory(path); TestCase_assertStringEqual(result, "Z:"); path = "z:"; result = getDirectory(path); TestCase_assertStringEqual(result, "z:"); path = "D:/"; result = getDirectory(path); TestCase_assertStringEqual(result, "D:/"); #endif } static void testEndianSwapping() { uint16_t value16; uint32_t value32; uint64_t value64; value16 = swapEndian16(0x0100); TestCase_assert(value16 == 0x1, "Expected 0x1 but got 0x%X", value16); value16 = swapEndian16(0x0203); TestCase_assert(value16 == 0x302, "Expected 0x302 but got 0x%X", value16); value16 = swapEndian16(0x0001); TestCase_assert(value16 == 0x100, "Expected 0x100 but got 0x%X", value16); value16 = swapEndian16(0x0302); TestCase_assert(value16 == 0x203, "Expected 0x203 but got 0x%X", value16); value32 = swapEndian32(0x01000000); TestCase_assert(value32 == 0x1, "Expected 0x1 but got 0x%X", value32); value32 = swapEndian32(0x02030405); TestCase_assert(value32 == 0x5040302, "Expected 0x5040302 but got 0x%X", value32); value32 = swapEndian32(0x00000001); TestCase_assert(value32 == 0x1000000, "Expected 0x1000000 but got 0x%X", value32); value32 = swapEndian32(0x05040302); TestCase_assert(value32 == 0x2030405, "Expected 0x2030405 but got 0x%X", value32); value64 = swapEndian64(0x0100000000000000ull); TestCase_assert(value64 == 0x1, "Expected 0x1 but got 0x" XINT64_FORMAT, value64); value64 = swapEndian64(0x0203040506070809ull); TestCase_assert(value64 == 0x908070605040302ull, "Expected 0x908070605040302 but got 0x" XINT64_FORMAT, value64); value64 = swapEndian64(0x0000000000000001ull); TestCase_assert(value64 == 0x100000000000000ull, "Expected 0x100000000000000 but got 0x" XINT64_FORMAT, value64); value64 = swapEndian64(0x0908070605040302ull); TestCase_assert(value64 == 0x203040506070809ull, "Expected 0x203040506070809 but got 0x" XINT64_FORMAT, value64); } static void vsnprintfTest(char * string, size_t size, const char * format, ...) { va_list args; va_start(args, format); vsnprintf_safe(string, size, format, args); va_end(args); } static void testSafeStringFunctions() { char string[16]; string[15] = 0; memset(string, '*', 15); snprintf_safe(string, 14, "Hello, %s!", "world"); TestCase_assertStringEqual(string, "Hello, world!"); memset(string, '*', 15); snprintf_safe(string, 6, "Hello, %s!", "world"); TestCase_assertStringEqual(string, "Hello"); memset(string, '*', 15); vsnprintfTest(string, 14, "Hello, %s!", "world"); TestCase_assertStringEqual(string, "Hello, world!"); memset(string, '*', 15); vsnprintfTest(string, 6, "Hello, %s!", "world"); TestCase_assertStringEqual(string, "Hello"); memset(string, '*', 15); string[2] = 0; snprintf_append(string, 15, "%d", 1); TestCase_assertStringEqual(string, "**1"); memset(string, '*', 15); string[3] = 0; snprintf_append(string, 15, "%d", 20); TestCase_assertStringEqual(string, "***20"); memset(string, '*', 15); string[3] = 0; snprintf_append(string, 5, "%d", 20); TestCase_assertStringEqual(string, "***2"); memset(string, '*', 15); strncpy_safe(string, "Hello, world!", 14); TestCase_assertStringEqual(string, "Hello, world!"); memset(string, '*', 15); strncpy_safe(string, "Hello, world!", 6); TestCase_assertStringEqual(string, "Hello"); char * duplicatedString; duplicatedString = strdup_nullSafe(NULL); TestCase_assertPointerNULL(duplicatedString); duplicatedString = strdup_nullSafe(string); TestCase_assertPointerNonNULL(duplicatedString); TestCase_assertPointerUnequal(duplicatedString, (char *) string); TestCase_assertStringEqual(duplicatedString, "Hello"); free(duplicatedString); int cmpResult = strcmp_nullSafe(NULL, NULL); TestCase_assertIntEqual(cmpResult, 0); cmpResult = strcmp_nullSafe(NULL, "a"); TestCase_assertIntEqual(cmpResult, -1); cmpResult = strcmp_nullSafe("a", NULL); TestCase_assertIntEqual(cmpResult, 1); cmpResult = strcmp_nullSafe("a", "a"); TestCase_assertIntEqual(cmpResult, 0); cmpResult = strcmp_nullSafe("a", "b"); TestCase_assertIntEqual(cmpResult, -1); cmpResult = strcmp_nullSafe("b", "a"); TestCase_assertIntEqual(cmpResult, 1); char unterminated[6] = {'a', 'b', 'c', 'd', 'e', 'f'}; duplicatedString = strdup_length(unterminated, 3); TestCase_assertStringEqual(duplicatedString, "abc"); free(duplicatedString); duplicatedString = strdup_length(unterminated, 6); TestCase_assertStringEqual(duplicatedString, "abcdef"); free(duplicatedString); } static void testMemdup(void) { char bytes[4] = {1, 3, 5, 2}; char * result; result = memdup(bytes, 0); TestCase_assertPointerNULL(result); result = memdup(bytes, 2); TestCase_assertPointerNonNULL(result); TestCase_assertPointerUnequal(result, (char *) bytes); TestCase_assert(!memcmp(result, bytes, 2), "Expected {1, 3} but got {%d, %d}", bytes[0], bytes[1]); free(result); result = memdup(bytes, 4); TestCase_assertPointerNonNULL(result); TestCase_assertPointerUnequal(result, (char *) bytes); TestCase_assert(!memcmp(result, bytes, 4), "Expected {1, 3, 5, 2} but got {%d, %d, %d, %d}", bytes[0], bytes[1], bytes[2], bytes[3]); free(result); } static void testLexstrcmp(void) { TestCase_assertIntEqual(lexstrcmp("a", "b"), -1); TestCase_assertIntEqual(lexstrcmp("b", "b"), 0); TestCase_assertIntEqual(lexstrcmp("b", "a"), 1); TestCase_assertIntEqual(lexstrcmp("Test 5", "Test 6"), -1); TestCase_assertIntEqual(lexstrcmp("Test 5", "Test 10"), -1); TestCase_assertIntEqual(lexstrcmp("a200b4", "a39b9000"), 1); TestCase_assertIntEqual(lexstrcmp("a200b4", "a200b4"), 0); TestCase_assertIntEqual(lexstrcmp("a200b4", "a200b"), 1); TestCase_assertIntEqual(lexstrcmp("a200b", "a200b4"), -1); TestCase_assertIntEqual(lexstrcmp("a1", "ab"), -1); TestCase_assertIntEqual(lexstrcmp("ab", "a1"), 1); TestCase_assertIntEqual(lexstrcmp("a001", "a000"), 1); TestCase_assertIntEqual(lexstrcmp("a000", "a001"), -1); TestCase_assertIntEqual(lexstrcmp("a002", "a2"), 1); TestCase_assertIntEqual(lexstrcmp("a2", "a002"), -1); TestCase_assertIntEqual(lexstrcmp("a002", "a1"), 1); TestCase_assertIntEqual(lexstrcmp("a1", "a002"), -1); TestCase_assertIntEqual(lexstrcmp("a002", "a3"), -1); TestCase_assertIntEqual(lexstrcmp("a3", "a002"), 1); TestCase_assertIntEqual(lexstrcmp("a00b", "a00b"), 0); TestCase_assertIntEqual(lexstrcmp("a000b", "a00b"), 1); TestCase_assertIntEqual(lexstrcmp("a00b", "a000b"), -1); TestCase_assertIntEqual(lexstrcmp("Ab", "aB"), 0); } static void testPrintHexString() { char buffer[32]; char hex1[] = {0x00, 0x01, 0x02, 0x03}, hex2[] = "Hello"; char * result; buffer[31] = 0; result = printHexString(hex1, sizeof(hex1), buffer, 32); TestCase_assert(result == buffer, "Expected %p but got %p", buffer, result); TestCase_assert(!strcmp(buffer, "00 01 02 03"), "Expected \"00 01 02 03\" but got \"%s\"", buffer); result = printHexString(hex2, sizeof(hex2), buffer, 32); TestCase_assert(result == buffer, "Expected %p but got %p", buffer, result); TestCase_assert(!strcmp(buffer, "48 65 6C 6C 6F 00"), "Expected \"48 65 6C 6C 6F 00\" but got \"%s\"", buffer); result = printHexString(hex2, sizeof(hex2), buffer, 5); TestCase_assert(result == buffer, "Expected %p but got %p", buffer, result); TestCase_assert(!strcmp(buffer, "48 6"), "Expected \"48 6\" but got \"%s\"", buffer); result = printHexString(hex1, 0, buffer, 32); TestCase_assert(result == buffer, "Expected %p but got %p", buffer, result); TestCase_assert(!strcmp(buffer, ""), "Expected \"\" but got \"%s\"", buffer); } static void testFormatDecimalString(void) { char result[DECIMAL_STRING_MAX]; unsigned int length; length = formatDecimalString(1, result, sizeof(result), 0, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "1"); TestCase_assertUIntEqual(length, 1); length = formatDecimalString(-243.25, result, sizeof(result), 0, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "-243.25"); TestCase_assertUIntEqual(length, 7); length = formatDecimalString(0.0000152587890625, result, sizeof(result), 0, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "0.0000152587890625"); TestCase_assertUIntEqual(length, 18); length = formatDecimalString(0.0000152587890625, result, 8, 0, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "0.00001"); TestCase_assertUIntEqual(length, 7); length = formatDecimalString(INFINITY, result, sizeof(result), 0, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "inf"); TestCase_assertUIntEqual(length, 3); length = formatDecimalString(-INFINITY, result, sizeof(result), 0, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "-inf"); TestCase_assertUIntEqual(length, 4); length = formatDecimalString(NAN, result, sizeof(result), 0, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "nan"); TestCase_assertUIntEqual(length, 3); length = formatDecimalString(2, result, sizeof(result), 4, DECIMAL_PRECISION_MAX); TestCase_assertStringEqual(result, "2.0000"); TestCase_assertUIntEqual(length, 6); length = formatDecimalString(2.0625, result, sizeof(result), 0, 2); TestCase_assertStringEqual(result, "2.06"); TestCase_assertUIntEqual(length, 4); } static void testParseDecimalString(void) { unsigned int lengthRead = 0; double result = 1.0; bool success = parseDecimalString(&result, "0", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, 0.0); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 1); success = parseDecimalString(&result, "aaaa", UINT_MAX, &lengthRead); TestCase_assertBoolFalse(success); TestCase_assertUIntEqual(lengthRead, 0); success = parseDecimalString(&result, "1.5", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, 1.5); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 3); success = parseDecimalString(&result, "-5.0jjj", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, -5.0); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 4); success = parseDecimalString(&result, "123.45678", 3, &lengthRead); TestCase_assertDoubleEqual(result, 123.0); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 3); success = parseDecimalString(&result, "0.0000152587890625", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, 0.0000152587890625); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 18); success = parseDecimalString(&result, "inf", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, INFINITY); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 3); success = parseDecimalString(&result, "-inf", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, -INFINITY); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 4); success = parseDecimalString(&result, "nan", UINT_MAX, &lengthRead); TestCase_assertBoolTrue(isnan(result)); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 3); success = parseDecimalString(&result, "1e+2", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, 100.0); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 4); success = parseDecimalString(&result, "5e-3", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, 0.005); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 4); success = parseDecimalString(&result, "2e1", UINT_MAX, &lengthRead); TestCase_assertDoubleEqual(result, 20.0); TestCase_assertBoolTrue(success); TestCase_assertUIntEqual(lengthRead, 3); } static void testCreateIdentifierFromDisplayString(void) { char * result; result = createIdentifierFromDisplayString("", 40); TestCase_assertStringEqual(result, ""); free(result); result = createIdentifierFromDisplayString("hello", 40); TestCase_assertStringEqual(result, "hello"); free(result); result = createIdentifierFromDisplayString("HeLlO", 40); TestCase_assertStringEqual(result, "hello"); free(result); result = createIdentifierFromDisplayString("I'm going to be an identifier", 40); TestCase_assertStringEqual(result, "i_m_going_to_be_an_identifier"); free(result); result = createIdentifierFromDisplayString("i_m_already_an_identifier_123", 40); TestCase_assertStringEqual(result, "i_m_already_an_identifier_123"); free(result); result = createIdentifierFromDisplayString(" space space space ", 40); TestCase_assertStringEqual(result, "space_space_space"); free(result); result = createIdentifierFromDisplayString("`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?", 40); TestCase_assertStringEqual(result, ""); free(result); result = createIdentifierFromDisplayString("too long", 5); TestCase_assertStringEqual(result, "too_l"); free(result); } static void testGetFileExtension(void) { const char * result = getFileExtension("/a/b/c.d"); TestCase_assertStringEqual(result, "d"); result = getFileExtension("a/b/ccc.ddd.ee"); TestCase_assertStringEqual(result, "ee"); result = getFileExtension("/abc/def/ghi"); TestCase_assertStringEqual(result, ""); result = getFileExtension("hello.txt"); TestCase_assertStringEqual(result, "txt"); result = getFileExtension(""); TestCase_assertStringEqual(result, ""); } static void testGetLastPathComponent(void) { const char * result = getLastPathComponent("/a/b/c.d"); TestCase_assertStringEqual(result, "c.d"); result = getLastPathComponent("/abc/def/"); TestCase_assertStringEqual(result, "def/"); result = getLastPathComponent("hello"); TestCase_assertStringEqual(result, "hello"); result = getLastPathComponent("/"); TestCase_assertStringEqual(result, "/"); result = getLastPathComponent(""); TestCase_assertStringEqual(result, ""); } static void testGetDirectory(void) { const char * result = getDirectory("/a/b/c.d"); TestCase_assertStringEqual(result, "/a/b/"); result = getDirectory("abc/def"); TestCase_assertStringEqual(result, "abc/"); result = getDirectory("hello"); TestCase_assertStringEqual(result, ""); result = getDirectory("/"); TestCase_assertStringEqual(result, "/"); result = getDirectory(""); TestCase_assertStringEqual(result, ""); } static void testGetBaseName(void) { const char * result = getBaseName("abc.def"); TestCase_assertStringEqual(result, "abc"); result = getBaseName("aa.bb.cc"); TestCase_assertStringEqual(result, "aa.bb"); result = getBaseName("/a/b"); TestCase_assertStringEqual(result, "/a/b"); result = getBaseName(""); TestCase_assertStringEqual(result, ""); } static void testGetSiblingFilePath(void) { const char * result = getSiblingFilePath("/a/b/c", "d"); TestCase_assertStringEqual(result, "/a/b/d"); result = getSiblingFilePath("aa/bb", "hello"); TestCase_assertStringEqual(result, "aa/hello"); result = getSiblingFilePath("aa/bb", ""); TestCase_assertStringEqual(result, "aa/"); result = getSiblingFilePath("", "a"); TestCase_assertStringEqual(result, "a"); result = getSiblingFilePath("", ""); TestCase_assertStringEqual(result, ""); } static void testGetPathRelativeTo(void) { const char * result = getPathRelativeTo("/a/", "/a/c"); TestCase_assertStringEqual(result, "c"); result = getPathRelativeTo("/a/b/", "/a/c"); TestCase_assertStringEqual(result, "../c"); result = getPathRelativeTo("a/b/", "a/c"); TestCase_assertStringEqual(result, "../c"); result = getPathRelativeTo("a/b/c/", "a/d/e"); TestCase_assertStringEqual(result, "../../d/e"); result = getPathRelativeTo("/base/subdir/subdir2", "/base/subdir/subdir2/file"); TestCase_assertStringEqual(result, "subdir2/file"); result = getPathRelativeTo("/base/subdir/subdir2/", "/base/subdir/subdir2/file"); TestCase_assertStringEqual(result, "file"); } static void testGetAbsolutePath(void) { const char * result = getAbsolutePath("/a/", "b"); TestCase_assertStringEqual(result, "/a/b"); result = getAbsolutePath("/a/b", "c"); TestCase_assertStringEqual(result, "/a/c"); result = getAbsolutePath("/a/b", "/d/c"); TestCase_assertStringEqual(result, "/d/c"); result = getAbsolutePath("/a/b/", "../e/f"); TestCase_assertStringEqual(result, "/a/e/f"); result = getAbsolutePath("/a/b/", "../../e/f"); TestCase_assertStringEqual(result, "/e/f"); result = getAbsolutePath("/a/b/", "../../../e/f"); TestCase_assertStringEqual(result, "/e/f"); result = getAbsolutePath("/i/", "./g"); TestCase_assertStringEqual(result, "/i/g"); result = getAbsolutePath("/base/subdir/subdir/", "../r/../g"); TestCase_assertStringEqual(result, "/base/subdir/g"); result = getAbsolutePath("/base/subdir/subdir2/", ".."); TestCase_assertStringEqual(result, "/base/subdir/"); result = getAbsolutePath("/a/b/", "/q/../r/"); TestCase_assertStringEqual(result, "/r/"); } struct enumerateFilesContext { unsigned int fileCount; unsigned int fileCountMax; char ** fileNames; const char * expectedDirectoryPath; }; static bool enumerateDirectoryCallback(const char * directoryPath, const char * fileName, void * context) { struct enumerateFilesContext * contextStruct = context; TestCase_assertStringEqual(directoryPath, contextStruct->expectedDirectoryPath); contextStruct->fileNames[contextStruct->fileCount++] = strdup(fileName); return contextStruct->fileCount < contextStruct->fileCountMax; } static void testEnumerateFilesInDirectory(void) { mkdir("testdir1" #ifndef WIN32 , 0777 #endif ); fclose(fopen("testdir1/testfile1", "w")); mkdir("testdir2" #ifndef WIN32 , 0777 #endif ); fclose(fopen("testdir2/a", "w")); fclose(fopen("testdir2/b", "w")); char * fileNames[3] = {NULL, NULL, NULL}; struct enumerateFilesContext contextStruct = {0, 3, fileNames, "testdir1"}; enumerateFilesInDirectory("testdir1", false, enumerateDirectoryCallback, &contextStruct); TestCase_assertUIntEqual(contextStruct.fileCount, 1); TestCase_assertStringEqual(contextStruct.fileNames[0], "testfile1"); free(contextStruct.fileNames[0]); contextStruct.fileNames[0] = NULL; contextStruct.fileCount = 0; contextStruct.expectedDirectoryPath = "testdir2"; enumerateFilesInDirectory("testdir2", false, enumerateDirectoryCallback, &contextStruct); TestCase_assertUIntEqual(contextStruct.fileCount, 2); if (!strcmp(contextStruct.fileNames[0], "a")) { TestCase_assertStringEqual(contextStruct.fileNames[0], "a"); TestCase_assertStringEqual(contextStruct.fileNames[1], "b"); } else { TestCase_assertStringEqual(contextStruct.fileNames[0], "b"); TestCase_assertStringEqual(contextStruct.fileNames[1], "a"); } free(contextStruct.fileNames[0]); free(contextStruct.fileNames[1]); contextStruct.fileNames[0] = NULL; contextStruct.fileNames[1] = NULL; contextStruct.fileCount = 0; contextStruct.fileCountMax = 1; enumerateFilesInDirectory("testdir2", false, enumerateDirectoryCallback, &contextStruct); TestCase_assertUIntEqual(contextStruct.fileCount, 1); free(contextStruct.fileNames[0]); } TEST_SUITE(IOUtilitiesTest, testMemreadContextInit, testMemread, testMemwriteContextInit, testMemwrite, testReadFileSimple, testWriteFileSimple, testWriteFileAtomic, testTemporaryFilePath, testFilePathFunctions, testEndianSwapping, testSafeStringFunctions, testMemdup, testLexstrcmp, testPrintHexString, testFormatDecimalString, testParseDecimalString, testCreateIdentifierFromDisplayString, testGetFileExtension, testGetLastPathComponent, testGetDirectory, testGetBaseName, testGetSiblingFilePath, testGetPathRelativeTo, testGetAbsolutePath, testEnumerateFilesInDirectory)