tests: lib: c_libc: tests for strerror, strerror_r

Add tests for strerror() and strerror_r()

Signed-off-by: Christopher Friedt <cfriedt@fb.com>
diff --git a/tests/lib/c_lib/Kconfig b/tests/lib/c_lib/Kconfig
new file mode 100644
index 0000000..4b04d89
--- /dev/null
+++ b/tests/lib/c_lib/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: Apache-2.0
+# Copyright (c) 2022 Meta
+
+mainmenu "Strerror test parameters"
+
+source "Kconfig.zephyr"
+
+config MINIMAL_LIBC_DISABLE_STRING_ERROR_TABLE
+	depends on MINIMAL_LIBC
+	bool
+	default y if !MINIMAL_LIBC_STRING_ERROR_TABLE
+	default n if MINIMAL_LIBC_STRING_ERROR_TABLE
+	help
+	  This option is only here to simplify conditional expressions
+	  in test_strerror.c rather than inverting logic for the
+	  global MINIMAL_LIBC_STRING_ERROR_TABLE option.
diff --git a/tests/lib/c_lib/src/test_strerror.c b/tests/lib/c_lib/src/test_strerror.c
new file mode 100644
index 0000000..d3b8e33
--- /dev/null
+++ b/tests/lib/c_lib/src/test_strerror.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2022 Meta
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <ztest.h>
+
+ZTEST(test_c_lib, test_strerror)
+{
+	const char *expected;
+	const char *actual;
+
+	errno = 4242;
+	if (IS_ENABLED(CONFIG_MINIMAL_LIBC_DISABLE_STRING_ERROR_TABLE)) {
+		expected = "";
+		actual = strerror(EINVAL);
+
+		zassert_equal(0, strcmp("", strerror(EINVAL)), "");
+	} else {
+		expected = "Invalid argument";
+		actual = strerror(EINVAL);
+
+		zassert_equal(0, strcmp(expected, actual),
+			      "mismatch: exp: %s act: %s", expected, actual);
+	}
+
+	/* do not change errno on success */
+	zassert_equal(4242, errno, "");
+
+	/* consistent behaviour w.r.t. errno with invalid input */
+	errno = 0;
+	expected = "";
+	actual = strerror(-42);
+	zassert_equal(0, strcmp(expected, actual), "mismatch: exp: %s act: %s",
+		      expected, actual);
+	actual = strerror(4242);
+	zassert_equal(0, strcmp(expected, actual), "mismatch: exp: %s act: %s",
+		      expected, actual);
+	/* do not change errno on failure (for consistence) */
+	zassert_equal(0, errno, "");
+
+	/* consistent behaviour for "Success" */
+	if (!IS_ENABLED(CONFIG_MINIMAL_LIBC_DISABLE_STRING_ERROR_TABLE)) {
+		expected = "Success";
+		actual = strerror(0);
+		zassert_equal(0, strcmp(expected, actual),
+			      "mismatch: exp: %s act: %s", expected, actual);
+	}
+}
+
+ZTEST(test_c_lib, test_strerror_r)
+{
+	const char *expected;
+	char actual[] = {'1', 'n', 'v', 'a', '1', '1', 'd', ' ',  'a',
+			 '2', 'g', 'u', 'm', '3', 'n', '7', 0x00, 0x42};
+	static const size_t n = sizeof(actual);
+
+	if (IS_ENABLED(CONFIG_NEWLIB_LIBC) || IS_ENABLED(CONFIG_ARCMWDT_LIBC)) {
+		/* FIXME: Please see Issue #46846 */
+		ztest_test_skip();
+	}
+
+	errno = 4242;
+	if (IS_ENABLED(CONFIG_MINIMAL_LIBC_DISABLE_STRING_ERROR_TABLE)) {
+		expected = "";
+		zassert_equal(0, strerror_r(EINVAL, actual, n), "");
+		zassert_equal(0, strncmp(expected, actual, n),
+			      "mismatch: exp: %s act: %s", expected, actual);
+	} else {
+		expected = "Invalid argument";
+		zassert_equal(0, strerror_r(EINVAL, actual, n), "%d",
+			      strerror_r(EINVAL, actual, n));
+		zassert_equal(0, strncmp(expected, actual, n),
+			      "mismatch: exp: %s act: %s", expected, actual);
+		/* only the necessary buffer area is written */
+		zassert_equal(0x42, (uint8_t)actual[n - 1],
+			      "exp: %02x act: %02x", 0x42,
+			      (uint8_t)actual[n - 1]);
+
+		zassert_equal(ERANGE, strerror_r(EINVAL, actual, 0), "");
+	}
+
+	/* do not change errno on success */
+	zassert_equal(4242, errno, "");
+
+	errno = 0;
+	zassert_equal(EINVAL, strerror_r(-42, actual, n), "");
+	zassert_equal(EINVAL, strerror_r(4242, actual, n), "");
+	/* do not change errno on failure */
+	zassert_equal(0, errno, "");
+}
diff --git a/tests/lib/c_lib/testcase.yaml b/tests/lib/c_lib/testcase.yaml
index 8c7ffa3..f63f4d9 100644
--- a/tests/lib/c_lib/testcase.yaml
+++ b/tests/lib/c_lib/testcase.yaml
@@ -1,9 +1,19 @@
+common:
+  tags: clib
+  platform_exclude: native_posix native_posix_64 nrf52_bsim
 tests:
   libraries.libc:
-    tags: clib ignore_faults
-    platform_exclude: native_posix native_posix_64 nrf52_bsim
+    tags: ignore_faults
   libraries.picolibc:
     filter: CONFIG_PICOLIBC_SUPPORTED
-    tags: clib picolibc ignore_faults
+    tags: picolibc ignore_faults
     extra_configs:
       - CONFIG_PICOLIBC=y
+  libraries.libc.minimal.strerror_table:
+    extra_configs:
+      - CONFIG_MINIMAL_LIBC=y
+      - CONFIG_MINIMAL_LIBC_STRING_ERROR_TABLE=y
+  libraries.libc.minimal.no_strerror_table:
+    extra_configs:
+      - CONFIG_MINIMAL_LIBC=y
+      - CONFIG_MINIMAL_LIBC_STRING_ERROR_TABLE=n