diff --git a/libc/string/main.c b/libc/string/main.c index fa2843fa3..f13d554ae 100644 --- a/libc/string/main.c +++ b/libc/string/main.c @@ -34,6 +34,10 @@ void runner(void) RUN_TEST_GROUP(signal_psignal); RUN_TEST_GROUP(string_cat); RUN_TEST_GROUP(string_dup); + RUN_TEST_GROUP(string_memcmp); + RUN_TEST_GROUP(string_strncmp); + RUN_TEST_GROUP(string_strcmp); + RUN_TEST_GROUP(string_strcoll); } diff --git a/libc/string/string_cmp.c b/libc/string/string_cmp.c new file mode 100644 index 000000000..e8012ba22 --- /dev/null +++ b/libc/string/string_cmp.c @@ -0,0 +1,439 @@ +/* + * Phoenix-RTOS + * + * POSIX.1-2017 standard library functions tests + * HEADER: + * - string.h + * TESTED: + * - memcmp() + * - strcmp() + * - strncmp() + * - strcoll() + * + * Copyright 2023 Phoenix Systems + * Author: Damian Modzelewski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include +#include +#include +#include +#include + +#include "testdata.h" + + +#define BUFF_SIZE 128 + +static char empty[BUFF_SIZE] = { 0 }, + support[BUFF_SIZE] = { 0 }, + hugeZeroString[INT16_MAX] = { 0 }, + separated[24] = { 0, 0, 0, 0, 0, 0, 'T', 'E', 'S', 'T', 0, 0, 0 }, + charEdgeValue[1] = { 0 }, + *asciiSet, + *hugeString, + *nonZeroAsciiSet, + basicStr[6] = "Basic"; + +TEST_GROUP(string_memcmp); +TEST_GROUP(string_strncmp); +TEST_GROUP(string_strcmp); +TEST_GROUP(string_strcoll); + +/* +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + + +TEST_SETUP(string_memcmp) +{ + /* Creating all needed data sets to run test cases */ + + nonZeroAsciiSet = testdata_createCharStr(BUFF_SIZE); + asciiSet = testdata_createCharStr(BUFF_SIZE); + hugeString = testdata_createCharStr(INT16_MAX); + asciiSet[0] = 0; + sprintf(support, "%s", "Tests"); +} + + +TEST_TEAR_DOWN(string_memcmp) +{ + + free(nonZeroAsciiSet); + free(asciiSet); + free(hugeString); + memset(support, 0, sizeof(support)); +} + + +TEST(string_memcmp, basic) +{ + TEST_ASSERT_EQUAL_INT(0, memcmp(basicStr, basicStr, sizeof(basicStr))); + TEST_ASSERT_LESS_THAN_INT(0, memcmp(basicStr, support, sizeof(basicStr))); + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(support, basicStr, sizeof(basicStr))); +} + + +TEST(string_memcmp, unsigned_char_cast) +{ + /* + * Checking do memcmp convert elements of input to unsigned char + * If we get a value less than 0 that means memcmp treats the value of s1 as + * signed char and return diff between SCHAR_MIN and 0 + * otherwise it will calculate the difference between 254 and 0 and memcmp will return + * negative value + */ + charEdgeValue[0] = SCHAR_MIN; + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(charEdgeValue, "\0", 1)); + TEST_ASSERT_LESS_THAN_INT(0, memcmp("\0", charEdgeValue, 1)); +} + + +TEST(string_memcmp, emptyInput) +{ + TEST_ASSERT_LESS_THAN_INT(0, memcmp(empty, asciiSet, BUFF_SIZE)); + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(asciiSet, empty, BUFF_SIZE)); + TEST_ASSERT_LESS_THAN_INT(0, memcmp(empty, nonZeroAsciiSet, BUFF_SIZE)); + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(nonZeroAsciiSet, empty, BUFF_SIZE)); + TEST_ASSERT_EQUAL_INT(0, memcmp(empty, empty, BUFF_SIZE)); + + /* Memory cmp is not sensitive for NUL characters */ + TEST_ASSERT_NOT_EQUAL_INT(0, memcmp(empty, separated, sizeof(separated))); +} + + +TEST(string_memcmp, big) +{ + TEST_ASSERT_EQUAL_INT(0, memcmp(hugeString, hugeString, INT16_MAX)); + TEST_ASSERT_LESS_THAN_INT(0, memcmp(hugeZeroString, hugeString, INT16_MAX)); + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(hugeString, hugeZeroString, INT16_MAX)); + TEST_ASSERT_EQUAL_INT(0, memcmp(hugeZeroString, hugeZeroString, INT16_MAX)); +} + + +TEST(string_memcmp, various_sizes) +{ + int i; + + for (i = 1; i < BUFF_SIZE; i++) { + /* Checking various sizes of compare passed to memcmp */ + TEST_ASSERT_LESS_THAN_INT(0, memcmp(asciiSet, nonZeroAsciiSet, i)); + + /* + * The testing compares elements that value are every time on a different spot + * and will check if the placement of the dataset on s1 and s2 will not impact on this + */ + support[i] = 1; + TEST_ASSERT_LESS_THAN_INT(0, memcmp(empty, support, BUFF_SIZE)); + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(support, empty, BUFF_SIZE)); + support[i] = 0; + } +} + + +TEST(string_memcmp, offsets) +{ + + char dataSet[4000] = { 0 }, + supportSet[4000] = { 0 }; + int s1Offs, s2Offs, szOffset, sz = sizeof(dataSet); + + for (s1Offs = 0; s1Offs < sz; s1Offs++) { + dataSet[s1Offs] = s1Offs; + supportSet[s1Offs] = s1Offs; + } + + /*Testing different offset of data blocks with same space or different*/ + for (s1Offs = 0; s1Offs < 8; s1Offs++) { + for (s2Offs = 0; s2Offs < 8; s2Offs++) { + for (szOffset = 0; szOffset < 8; szOffset++) { + + if (s2Offs < s1Offs) { + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(&dataSet[s1Offs], &dataSet[s2Offs], sz - (s1Offs + szOffset))); + TEST_ASSERT_GREATER_THAN_INT(0, memcmp(&dataSet[s1Offs], &supportSet[s2Offs], sz - (s1Offs + szOffset))); + } + else if (s2Offs == s1Offs) { + TEST_ASSERT_EQUAL_INT(0, memcmp(&dataSet[s1Offs], &dataSet[s2Offs], sz - (s1Offs + s2Offs + szOffset))); + TEST_ASSERT_EQUAL_INT(0, memcmp(&dataSet[s1Offs], &supportSet[s2Offs], sz - (s1Offs + s2Offs + szOffset))); + } + else { + TEST_ASSERT_LESS_THAN_INT(0, memcmp(&dataSet[s1Offs], &dataSet[s2Offs], sz - (s2Offs + szOffset))); + TEST_ASSERT_LESS_THAN_INT(0, memcmp(&dataSet[s1Offs], &supportSet[s2Offs], sz - (s2Offs + szOffset))); + } + } + } + } +} + + +/* +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + + +TEST_SETUP(string_strncmp) +{ + /* Creating all needed data sets to run test cases */ + + nonZeroAsciiSet = testdata_createCharStr(BUFF_SIZE); + asciiSet = testdata_createCharStr(BUFF_SIZE); + hugeString = testdata_createCharStr(INT16_MAX); + asciiSet[0] = 0; + sprintf(support, "%s", "Tests"); +} + + +TEST_TEAR_DOWN(string_strncmp) +{ + + free(nonZeroAsciiSet); + free(asciiSet); + free(hugeString); + memset(support, 0, sizeof(support)); +} + + +TEST(string_strncmp, basic) +{ + TEST_ASSERT_EQUAL_INT(0, strncmp(basicStr, basicStr, sizeof(basicStr))); + TEST_ASSERT_LESS_THAN_INT(0, strncmp(basicStr, support, sizeof(basicStr))); + TEST_ASSERT_GREATER_THAN_INT(0, strncmp(support, basicStr, sizeof(basicStr))); +} + + +TEST(string_strncmp, unsigned_char_cast) +{ + /* + * Checking do strncmp convert elements of input to unsigned char + * If we get a value less than 0 that means strncmp treats the value of s1 as + * signed char and return diff between SCHAR_MIN and 0 + * otherwise it will calculate the difference between 254 and 0 and strncmp will return + * negative value + */ + charEdgeValue[0] = SCHAR_MIN; + TEST_ASSERT_GREATER_THAN_INT(0, strncmp(charEdgeValue, "\0", 1)); + TEST_ASSERT_LESS_THAN_INT(0, strncmp("\0", charEdgeValue, 1)); +} + + +TEST(string_strncmp, emptyInput) +{ + TEST_ASSERT_EQUAL_INT(0, strncmp(empty, asciiSet, BUFF_SIZE)); + TEST_ASSERT_EQUAL_INT(0, strncmp(asciiSet, empty, BUFF_SIZE)); + TEST_ASSERT_LESS_THAN_INT(0, strncmp(empty, nonZeroAsciiSet, BUFF_SIZE)); + TEST_ASSERT_GREATER_THAN_INT(0, strncmp(nonZeroAsciiSet, empty, BUFF_SIZE)); + TEST_ASSERT_EQUAL_INT(0, strncmp(empty, empty, BUFF_SIZE)); + + /* Otherwise than in memcmp, strncmp is NUL character sensitive and treats 0 as the end of array */ + TEST_ASSERT_EQUAL_INT(0, strncmp(empty, separated, BUFF_SIZE)); +} + +TEST(string_strncmp, big) +{ + TEST_ASSERT_EQUAL_INT(0, strncmp(hugeString, hugeString, INT16_MAX)); + TEST_ASSERT_LESS_THAN_INT(0, strncmp(hugeZeroString, hugeString, INT16_MAX)); + TEST_ASSERT_EQUAL_INT(0, strncmp(hugeZeroString, hugeZeroString, INT16_MAX)); +} + + +TEST(string_strncmp, various_sizes) +{ + int i; + + TEST_ASSERT_EQUAL_INT(0, strncmp(&asciiSet[BUFF_SIZE / 2], &nonZeroAsciiSet[BUFF_SIZE / 2], BUFF_SIZE / 2)); + TEST_ASSERT_EQUAL_INT(0, strncmp(&asciiSet[BUFF_SIZE - 1], &nonZeroAsciiSet[BUFF_SIZE - 1], 1)); + TEST_ASSERT_EQUAL_INT(0, strncmp(&nonZeroAsciiSet[BUFF_SIZE - 1], &asciiSet[BUFF_SIZE - 1], 1)); + TEST_ASSERT_EQUAL_INT(0, strncmp(&nonZeroAsciiSet[BUFF_SIZE - 1], &nonZeroAsciiSet[BUFF_SIZE - 1], BUFF_SIZE - 1)); + TEST_ASSERT_EQUAL_INT(0, strncmp(asciiSet, nonZeroAsciiSet, 0)); + + /* Loop which changes the size of compared space to place where asciSet ends */ + for (i = 1; i < BUFF_SIZE - 1; i++) { + TEST_ASSERT_LESS_THAN_INT(0, strncmp(asciiSet, nonZeroAsciiSet, i)); + } + + /* Testing size bigger than string having in mind the compare will end with null terminator */ + TEST_ASSERT_EQUAL_INT(0, strncmp(asciiSet, asciiSet, SIZE_MAX)); +} + + +/* +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + + +TEST_SETUP(string_strcmp) +{ + /* Creating all needed data sets to run test cases */ + + nonZeroAsciiSet = testdata_createCharStr(BUFF_SIZE); + asciiSet = testdata_createCharStr(BUFF_SIZE); + hugeString = testdata_createCharStr(INT16_MAX); + asciiSet[0] = 0; + sprintf(support, "%s", "Tests"); +} + + +TEST_TEAR_DOWN(string_strcmp) +{ + + free(nonZeroAsciiSet); + free(asciiSet); + free(hugeString); + memset(support, 0, sizeof(support)); +} + + +TEST(string_strcmp, basic) +{ + TEST_ASSERT_EQUAL_INT(0, strcmp(basicStr, basicStr)); + TEST_ASSERT_LESS_THAN_INT(0, strcmp(basicStr, support)); + TEST_ASSERT_GREATER_THAN_INT(0, strcmp(support, basicStr)); +} + + +TEST(string_strcmp, unsigned_char_cast) +{ + /* + * Checking do strcmp convert elements of input to unsigned char + * If we get a value less than 0 that means strcmp treats the value of s1 as + * signed char and return diff between SCHAR_MIN and 0 + * otherwise it will calculate the difference between 254 and 0 and strcmp will return + * negative value + */ + charEdgeValue[0] = SCHAR_MIN; + TEST_ASSERT_GREATER_THAN_INT(0, strcmp(charEdgeValue, "\0")); + TEST_ASSERT_LESS_THAN_INT(0, strcmp("\0", charEdgeValue)); +} + + +TEST(string_strcmp, emptyInput) +{ + TEST_ASSERT_EQUAL_INT(0, strcmp(empty, asciiSet)); + TEST_ASSERT_EQUAL_INT(0, strcmp(asciiSet, empty)); + TEST_ASSERT_LESS_THAN_INT(0, strcmp(empty, nonZeroAsciiSet)); + TEST_ASSERT_GREATER_THAN_INT(0, strcmp(nonZeroAsciiSet, empty)); + TEST_ASSERT_EQUAL_INT(0, strcmp(empty, empty)); +} + + +TEST(string_strcmp, big) +{ + TEST_ASSERT_EQUAL_INT(0, strcmp(hugeString, hugeString)); + TEST_ASSERT_LESS_THAN_INT(0, strcmp(hugeZeroString, hugeString)); + TEST_ASSERT_EQUAL_INT(0, strcmp(hugeZeroString, hugeZeroString)); +} + + +TEST(string_strcmp, various_sizes) +{ + TEST_ASSERT_EQUAL_INT(0, strcmp(&asciiSet[BUFF_SIZE / 2], &nonZeroAsciiSet[BUFF_SIZE / 2])); + TEST_ASSERT_EQUAL_INT(0, strcmp(&asciiSet[BUFF_SIZE - 1], &nonZeroAsciiSet[BUFF_SIZE - 1])); +} + + +/* +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + + +TEST_SETUP(string_strcoll) +{ + /* Creating all needed data sets to run test cases */ + + nonZeroAsciiSet = testdata_createCharStr(BUFF_SIZE); + asciiSet = testdata_createCharStr(BUFF_SIZE); + hugeString = testdata_createCharStr(INT16_MAX); + asciiSet[0] = 0; + sprintf(support, "%s", "Tests"); +} + + +TEST_TEAR_DOWN(string_strcoll) +{ + + free(nonZeroAsciiSet); + free(asciiSet); + free(hugeString); + memset(support, 0, sizeof(support)); +} + + +TEST(string_strcoll, basic) +{ + TEST_ASSERT_EQUAL_INT(0, strcoll(basicStr, basicStr)); + TEST_ASSERT_LESS_THAN_INT(0, strcoll(basicStr, support)); + TEST_ASSERT_GREATER_THAN_INT(0, strcoll(support, basicStr)); +} + + +TEST(string_strcoll, emptyInput) +{ + TEST_ASSERT_EQUAL_INT(0, strcoll(empty, asciiSet)); + TEST_ASSERT_LESS_THAN_INT(0, strcoll(empty, nonZeroAsciiSet)); + TEST_ASSERT_EQUAL_INT(0, strcoll(asciiSet, empty)); + TEST_ASSERT_EQUAL_INT(0, strcoll(empty, empty)); +} + + +TEST(string_strcoll, big) +{ + TEST_ASSERT_EQUAL_INT(0, strcoll(hugeString, hugeString)); + TEST_ASSERT_LESS_THAN_INT(0, strcoll(hugeZeroString, hugeString)); + TEST_ASSERT_EQUAL_INT(0, strcoll(hugeZeroString, hugeZeroString)); +} + + +TEST(string_strcoll, sizes) +{ + TEST_ASSERT_EQUAL_INT(0, strcoll(&asciiSet[BUFF_SIZE / 2], &nonZeroAsciiSet[BUFF_SIZE / 2])); + TEST_ASSERT_EQUAL_INT(0, strcoll(&asciiSet[BUFF_SIZE - 1], &nonZeroAsciiSet[BUFF_SIZE - 1])); +} + + +/* +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + + +TEST_GROUP_RUNNER(string_memcmp) +{ + RUN_TEST_CASE(string_memcmp, basic); + RUN_TEST_CASE(string_memcmp, unsigned_char_cast); + RUN_TEST_CASE(string_memcmp, emptyInput); + RUN_TEST_CASE(string_memcmp, big); + RUN_TEST_CASE(string_memcmp, various_sizes); + RUN_TEST_CASE(string_memcmp, offsets); +} + +TEST_GROUP_RUNNER(string_strncmp) +{ + RUN_TEST_CASE(string_strncmp, basic); + RUN_TEST_CASE(string_strncmp, unsigned_char_cast); + RUN_TEST_CASE(string_strncmp, emptyInput); + RUN_TEST_CASE(string_strncmp, big); + RUN_TEST_CASE(string_strncmp, various_sizes); +} + +TEST_GROUP_RUNNER(string_strcmp) +{ + RUN_TEST_CASE(string_strcmp, basic); + RUN_TEST_CASE(string_strcmp, unsigned_char_cast); + RUN_TEST_CASE(string_strcmp, emptyInput); + RUN_TEST_CASE(string_strcmp, big); + RUN_TEST_CASE(string_strcmp, various_sizes); +} + +TEST_GROUP_RUNNER(string_strcoll) +{ + RUN_TEST_CASE(string_strcoll, basic); + RUN_TEST_CASE(string_strcoll, emptyInput); + RUN_TEST_CASE(string_strcoll, big); + RUN_TEST_CASE(string_strcoll, sizes); +}