From 1c4fd9f3cb6d9ed9440c5d31a71f0c39894c8f12 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 4 Jul 2026 21:05:48 -0400 Subject: [PATCH] main.c: add three real iconv() tests --- main.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 157 insertions(+), 8 deletions(-) diff --git a/main.c b/main.c index 38df478..c19c7e0 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include /* The various invalid sequences can be inferred from the table of @@ -28,6 +29,9 @@ * (d) 0xC0, 0xC1, 0xF5-0xFF are never valid */ +#define ASCII_MAX 0x7F +#define MULTIBYTE_MIN 0xC3 + #define SUCCESS 0 #define FAILURE 1 @@ -110,7 +114,6 @@ int test_open_close() { return FAILURE; } - return SUCCESS; } @@ -195,13 +198,13 @@ int test_iconv_open_does_not_support_invalid_from_codeset() { printf("iconv_open() does not support invalid \"from\" codeset..."); iconv_t cd = iconv_open(tocode, fromcode); if (cd == (iconv_t)(-1)) { - switch (errno) { - case EINVAL: - printf("OK (EINVAL, expected)\n"); - return SUCCESS; - default: - printf("FAIL (errno=%d, unexpected)\n", errno); - return FAILURE; + if (errno == EINVAL) { + printf("OK (EINVAL, expected)\n"); + return SUCCESS; + } + else { + printf("FAIL (errno=%d, unexpected)\n", errno); + return FAILURE; } } printf("FAIL (invalid codeset was accepted)\n"); @@ -209,6 +212,148 @@ int test_iconv_open_does_not_support_invalid_from_codeset() { return FAILURE; } +/* If a sequence of input bytes does not form a valid character or + * shift sequence in the input codeset... conversion shall stop after + * the previous successfully converted character or shift sequence. + * + * + * [EILSEQ] + * Input conversion stopped due to an input byte that does not belong + * to the input codeset. + */ +int test_iconv_invalid_char_is_eilseq() { + iconv_t cd; + const char* tocode = "ASCII"; + + printf("iconv() returns EILSEQ on invalid input..."); + if (_my_iconv_open(&cd, tocode, tocode) == FAILURE) { + printf("ERROR (iconv_open)\n"); + return FAILURE; + } + + size_t insize = 1, outsize = 1; + char* inbuf = (char*)malloc(insize); + char* outbuf = (char*)malloc(outsize); + + inbuf[0] = ASCII_MAX + 1; // not ascii + + size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize); + + if (result == (size_t)(-1)) { + int saved_errno = errno; // iconv_close() clobbers it + + if (_my_iconv_close(&cd) == FAILURE) { + printf("ERROR (iconv_close)\n"); + return FAILURE; + } + + if (saved_errno == EILSEQ) { + printf("OK (EILSEQ, expected)\n"); + return SUCCESS; + } + else { + printf("FAIL (errno=%d, unexpected)\n", saved_errno); + return FAILURE; + } + } + + printf("FAIL (no error)\n"); + return FAILURE; +} + +/* If the input buffer ends with an incomplete character or shift + * sequence, conversion shall stop after the previous successfully + * converted bytes. + * + * [EINVAL] + * Input conversion stopped due to an incomplete character or shift + * sequence at the end of the input buffer. + */ +int test_iconv_incomplete_multibyte_is_einval() { + iconv_t cd; + const char* tocode = "UTF-8"; + + printf("iconv() returns EINVAL on incomplete multibyte..."); + if (_my_iconv_open(&cd, tocode, tocode) == FAILURE) { + printf("ERROR (iconv_open)\n"); + return FAILURE; + } + + size_t insize = 1, outsize = 1; + char* inbuf = (char*)malloc(insize); + char* outbuf = (char*)malloc(outsize); + + // a single byte in the input buffer that demands + // a (nonexistent) subsequent byte + inbuf[0] = MULTIBYTE_MIN; + + size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize); + + if (result == (size_t)(-1)) { + int saved_errno = errno; // iconv_close() clobbers it + + if (_my_iconv_close(&cd) == FAILURE) { + printf("ERROR (iconv_close)\n"); + return FAILURE; + } + + if (saved_errno == EINVAL) { + printf("OK (EINVAL, expected)\n"); + return SUCCESS; + } + else { + printf("FAIL (errno=%d, unexpected)\n", saved_errno); + return FAILURE; + } + } + + printf("FAIL (no error)\n"); + return FAILURE; +} + +int test_iconv_too_big_is_e2big() { + iconv_t cd; + const char* tocode = "ASCII"; + + printf("iconv() returns E2BIG if the input is too big..."); + if (_my_iconv_open(&cd, tocode, tocode) == FAILURE) { + printf("ERROR (iconv_open)\n"); + return FAILURE; + } + + size_t insize = 2, outsize = 1; + char* inbuf = (char*)malloc(insize); + char* outbuf = (char*)malloc(outsize); + + // a single byte in the input buffer that demands + // a (nonexistent) subsequent byte + inbuf[0] = 'h'; + inbuf[1] = 'i'; + + size_t result = iconv(cd, &inbuf, &insize, &outbuf, &outsize); + + if (result == (size_t)(-1)) { + int saved_errno = errno; // iconv_close() clobbers it + + if (_my_iconv_close(&cd) == FAILURE) { + printf("ERROR (iconv_close)\n"); + return FAILURE; + } + + if (saved_errno == E2BIG) { + printf("OK (E2BIG, expected)\n"); + return SUCCESS; + } + else { + printf("FAIL (errno=%d, unexpected)\n", saved_errno); + return FAILURE; + } + } + + printf("FAIL (no error)\n"); + return FAILURE; +} + int main(int argc, char** argv) { int result = test_open_close(); @@ -230,5 +375,9 @@ int main(int argc, char** argv) { result |= test_iconv_open_does_not_support_invalid_to_codeset(); result |= test_iconv_open_does_not_support_invalid_from_codeset(); + result |= test_iconv_invalid_char_is_eilseq(); + result |= test_iconv_too_big_is_e2big(); + result |= test_iconv_incomplete_multibyte_is_einval(); + return result; } -- 2.53.0