]> gitweb.michael.orlitzky.com - iconv-quirks.git/commitdiff
main.c: begin adding real tests
authorMichael Orlitzky <michael@orlitzky.com>
Sat, 4 Jul 2026 20:07:57 +0000 (16:07 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Sat, 4 Jul 2026 20:07:57 +0000 (16:07 -0400)
main.c

diff --git a/main.c b/main.c
index fb4f9bdfeccbaa71b2c91fbfc601e15bbda6bab5..38df4780b70d8e209ebd18458862bd29abfccd2a 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
-#include <stdio.h>
 #include <errno.h>
 #include <iconv.h>
+#include <stdio.h>
+#include <string.h>
 
 /* The various invalid sequences can be inferred from the table of
  * valid ones,
  * (d) 0xC0, 0xC1, 0xF5-0xFF are never valid
  */
 
-#define ICONV_OPEN_FAILED 1
-#define ICONV_CLOSE_FAILED 2
+#define SUCCESS 0
+#define FAILURE 1
 
-int main(int argc, char** argv) {
-  const char* tocode = "UTF-8";
-  const char* fromcode = "UTF-8";
-
-  iconv_t cd = iconv_open(tocode, fromcode);
-  if (cd == (iconv_t)(-1)) {
+/* Open a conversion descriptor by reference. Wraps the boilerplate
+ * error reporting when iconv_open() fails.
+ */
+int _my_iconv_open(iconv_t* cd, const char *tocode, const char *fromcode) {
+  *cd = iconv_open(tocode, fromcode);
+  if (*cd == (iconv_t)(-1)) {
     /* The errno values are standard, but we have no way of knowing
      * if the implementation follows the standard! */
     fprintf(stderr,
@@ -56,15 +57,20 @@ int main(int argc, char** argv) {
        fprintf(stderr, "EINVAL");
        break;
       default:
-       fprintf(stderr, "UNKNOWN");
+       fprintf(stderr, "UNKNOWN (%d)", errno);
     }
     fprintf(stderr, "\n");
-    return ICONV_OPEN_FAILED;
+    return FAILURE;
   }
 
-  /* actual conversion takes place here */
+  return SUCCESS;
+}
 
-  if (iconv_close(cd) == -1) {
+/* Close a conversion descriptor by reference. Wraps the boilerplate
+ * error reporting when iconv_close() fails.
+ */
+int _my_iconv_close(iconv_t* cd) {
+  if (iconv_close(*cd) == -1) {
     /* The underlying type of iconv_t is unspecified, so we can't
      * easily print the argument here. */
     fprintf(stderr, "ERROR: iconv_close() returned ");
@@ -73,11 +79,156 @@ int main(int argc, char** argv) {
        fprintf(stderr, "EBADF");
        break;
       default:
-       fprintf(stderr, "UNKNOWN");
+       fprintf(stderr, "UNKNOWN (%d)", errno);
     }
     fprintf(stderr, "\n");
-    return ICONV_CLOSE_FAILED;
+    return FAILURE;
+  }
+
+  return SUCCESS;
+}
+
+/*
+ * Open and close a conversion descriptor (basic sanity test).
+ */
+int test_open_close() {
+  iconv_t cd;
+  const char* tocode = "ASCII";
+  const char* fromcode = "ASCII";
+
+  printf("can iconv_open() and iconv_close() a conversion descriptor...");
+  if (_my_iconv_open(&cd, tocode, fromcode) == FAILURE) {
+    printf("FAIL\n");
+    return FAILURE;
+  }
+
+  if (_my_iconv_close(&cd) == SUCCESS) {
+    printf("OK\n");
+  }
+  else {
+    printf("FAIL\n");
+    return FAILURE;
+  }
+
+
+  return SUCCESS;
+}
+
+
+/*
+ * Ensure that iconv_open() supports the given indicator suffix.
+ */
+int test_iconv_open_supports_suffix(const char* suffix) {
+  const char* fromcode = "ASCII";
+  char tocode[64] = "ASCII";
+  strcat(tocode, suffix);
+
+  printf("iconv_open() supports %s suffix...", suffix);
+  iconv_t cd = iconv_open(tocode, fromcode);
+  if (cd == (iconv_t)(-1)) {
+    switch (errno) {
+      case EINVAL:
+       printf("OK (EINVAL, not supported)\n");
+       return SUCCESS;
+      default:
+       printf("FAIL (errno=%d, unexpected error)\n", errno);
+        return FAILURE;
+    }
+  }
+  printf("yes\n");
+  iconv_close(cd);
+  return SUCCESS;
+}
+
+
+/*
+ * Check that iconv_open() fails with EINVAL when given a bogus
+ * indicator suffix.
+ */
+int test_iconv_open_does_not_support_invalid_suffix() {
+  const char* fromcode = "ASCII";
+  const char* tocode = "ASCII//INVALID";
+
+  printf("iconv_open() does not support //INVALID...");
+  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;
+    }
   }
+  printf("FAIL (invalid suffix was accepted)\n");
+  iconv_close(cd);
+  return FAILURE;
+}
+
+
+int test_iconv_open_does_not_support_invalid_to_codeset() {
+  const char* fromcode = "ASCII";
+  const char* tocode = "ASDJFI$@#%t234tWER";
+
+  printf("iconv_open() does not support invalid \"to\" 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;
+    }
+  }
+  printf("FAIL (invalid codeset was accepted)\n");
+  iconv_close(cd);
+  return FAILURE;
+}
+
+int test_iconv_open_does_not_support_invalid_from_codeset() {
+  const char* fromcode = "ASDJFI$@#%t234tWER";
+  const char* tocode = "ASCII";
+
+  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;
+    }
+  }
+  printf("FAIL (invalid codeset was accepted)\n");
+  iconv_close(cd);
+  return FAILURE;
+}
+
+int main(int argc, char** argv) {
+  int result = test_open_close();
+
+  /* These three are named explicitly by POSIX which says that you are
+   * free to append them to the destination codeset, but support is
+   * not guaranteed; iconv_open() is allowed to fail with an EINVAL
+   * to indicate an unsupported suffix. */
+  result |= test_iconv_open_supports_suffix("//IGNORE");
+  result |= test_iconv_open_supports_suffix("//NON_IDENTICAL_DISCARD");
+  result |= test_iconv_open_supports_suffix("//TRANSLIT");
+
+  /* The supported codeset names and suffixes are implementation-
+   * defined, making this a bit ambiguous, but POSIX declares EINVAL
+   * to be the error code associated with unrecognized or unsupported
+   * values. (This doesn't stop an implementation from "supporting"
+   * invalid values by ignoring them, but for now let's assume no one
+   * is doing that.) */
+  result |= test_iconv_open_does_not_support_invalid_suffix();
+  result |= test_iconv_open_does_not_support_invalid_to_codeset();
+  result |= test_iconv_open_does_not_support_invalid_from_codeset();
 
-  return 0;
+  return result;
 }