]> git.draconx.ca Git - dxcommon.git/commitdiff
help_print_optstring: Test fullwidth/halfwidth character output.
authorNick Bowler <nbowler@draconx.ca>
Thu, 16 Nov 2023 01:04:16 +0000 (20:04 -0500)
committerNick Bowler <nbowler@draconx.ca>
Thu, 16 Nov 2023 01:04:16 +0000 (20:04 -0500)
This function is supposed to support proper alignment with translated
strings possibly containing fullwidth characters, but we have no
test coverage of that aspect whatsoever.

Let's try to have at least some basic tests, which is made a bit
tricky since Autotest/m4sh busts the locale (but we can work around
this problem).

Makefile.am
configure.ac
snippet/test-nls.at [new file with mode: 0644]
t/.gitignore
t/nls/gettext.h [new file with mode: 0644]
t/nls/mbswidth.c [new file with mode: 0644]
t/nls/mbswidth.h [new file with mode: 0644]
tests/functions.at
testsuite.at

index e064ddf905943e4153e1d20a1b50bc8c9ccbfd1f..e859c4d7b3a6b7f8e27d3cf54b4cb8655e5b32b6 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright © 2015 Nick Bowler
+# Copyright © 2015, 2019, 2021-2023 Nick Bowler
 #
 # License WTFPL2: Do What The Fuck You Want To Public License, version 2.
 # This is free software: you are free to do what the fuck you want to.
@@ -6,7 +6,7 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-AM_CFLAGS = -I$(top_srcdir)/src
+AM_CPPFLAGS = -I$(top_srcdir)/src
 
 check_LIBRARIES = t/libdummy.a t/libempty.a
 
@@ -19,19 +19,33 @@ t_packtests64_SOURCES = t/packtests64.c src/pack.c src/tap.c
 
 if HAVE_STRUCT_OPTION
 check_PROGRAMS += t/helpdesc t/helpopt t/helpopt2
+
+if HAVE_WCWIDTH
+check_PROGRAMS += t/helpopt3
+endif
 endif
 
 EXTRA_LIBRARIES = libglohelp.a
 libglohelp_a_SOURCES = src/help.c
-libglohelp_a_CFLAGS = -DHELP_GETOPT_LONG_ONLY
+libglohelp_a_CPPFLAGS = -DHELP_GETOPT_LONG_ONLY
 libglohelp_a_SHORTNAME = glo
 
+EXTRA_LIBRARIES += libnlshelp.a
+libnlshelp_a_SOURCES = src/help.c t/nls/mbswidth.c
+libnlshelp_a_CPPFLAGS = -DENABLE_NLS -I$(top_srcdir)/t/nls
+libnlshelp_a_SHORTNAME = nls
+
 t_helpdesc_SOURCES = t/helpdesc.c src/help.c src/tap.c
 t_helpopt_SOURCES = t/helpopt.c src/help.c src/tap.c
+
 t_helpopt2_SOURCES = t/helpopt.c src/tap.c
 t_helpopt2_LDADD = $(libglohelp_a_OBJECTS)
 EXTRA_t_helpopt2_DEPENDENCIES = $(t_helpopt2_LDADD)
 
+t_helpopt3_SOURCES = t/helpopt.c src/tap.c
+t_helpopt3_LDADD = $(libnlshelp_a_OBJECTS)
+EXTRA_t_helpopt3_DEPENDENCIES = $(t_helpopt3_LDADD)
+
 check_PROGRAMS += t/copysym
 t_copysym_SOURCES = t/copysym.c src/tap.c
 t_copysym_LDADD = $(libnlscopysym_a_OBJECTS)
@@ -39,7 +53,7 @@ EXTRA_t_copysym_DEPENDENCIES = $(t_copysym_LDADD)
 
 EXTRA_LIBRARIES += libnlscopysym.a
 libnlscopysym_a_SOURCES = src/copysym.c
-libnlscopysym_a_CFLAGS = -DENABLE_NLS
+libnlscopysym_a_CPPFLAGS = -DENABLE_NLS
 libnlscopysym_a_SHORTNAME = nls
 
 DISTCLEANFILES =
index 47abd447402df497614d2847240bfa1fc9d0d18d..0aabe4737d3d8e1001eaea6b2756cea7615d4d66 100644 (file)
@@ -1,4 +1,4 @@
-dnl Copyright © 2015, 2019-2022 Nick Bowler
+dnl Copyright © 2015, 2019-2023 Nick Bowler
 dnl
 dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
 dnl This is free software: you are free to do what the fuck you want to.
@@ -20,6 +20,10 @@ AM_SILENT_RULES([yes])
 
 DX_INIT([.])
 
+AC_USE_SYSTEM_EXTENSIONS
+AC_CHECK_FUNCS_ONCE([wcwidth])
+AM_CONDITIONAL([HAVE_WCWIDTH], [test x"$ac_cv_func_wcwidth" = x"yes"])
+
 AC_CONFIG_TESTDIR([.])
 DX_PROG_AUTOTEST
 AM_CONDITIONAL([HAVE_AUTOTEST], [test x"$dx_cv_autotest_works" = x"yes"])
diff --git a/snippet/test-nls.at b/snippet/test-nls.at
new file mode 100644 (file)
index 0000000..103cb5b
--- /dev/null
@@ -0,0 +1,77 @@
+# Copyright © 2023 Nick Bowler
+#
+# Helper macros for finding a locale using a specific character set.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+# TEST_UTF8_LOCALE([variable], [action-if-found], [action-if-not-found])
+#
+# Try to find a supported UTF-8 locale.  If any is found, the given shell
+# variable is set to the name of one such locale, and action-if-found is
+# expanded.
+#
+# If no suitable locale is found, then variable is set to the empty string
+# and action-if-not-found is expanded.  If no action is specified, the
+# default action in this scenario is to skip the current test group.
+#
+# Since m4sh overrides LC_ALL, it is recommended to use the locale by
+# setting LC_ALL to the detected value when running a program.
+m4_defun([TEST_UTF8_LOCALE],
+[AS_VAR_SET([$1], [`_TEST_UTF8_LOCALE`])
+AS_VAR_IF([$1], [""], [m4_default([$3], [AT_SKIP_IF([:])])], [$2])])
+
+m4_defun([_TEST_UTF8_LOCALE], [m4_require([_TEST_NLS_SETUP])dnl
+test_find_locale_charmap '[[Uu][Tt][Ff]-*8]'])
+
+# Output shell function definitions to implement locale detection.
+#
+# - test_check_locale_charmap name regex
+#
+#   Returns success if setting LC_ALL to the given locale name results in a
+#   charmap string that matches the given regex (as interpreted by 'grep').
+#
+# - test_find_locale_charmap regex
+#
+#   Try to find any locale for which test_check_locale_charmap is successful
+#   with the given regex.  If a matching locale is found, it is printed to
+#   standard output.
+#
+#   By default, the user's own LC_CTYPE is preferred.  Otherwise, the first
+#   match in the output of "locale -a" is chosen.
+
+m4_defun_once([_TEST_NLS_SETUP], [m4_divert_push([HEADER-COPYRIGHT])
+# save user locale setting before m4sh clobbers it
+_orig_LC_ALL=$LC_ALL
+
+m4_divert([PREPARE_TESTS])
+test_check_locale_charmap () {
+  LC_ALL=$[1] locale -ck charmap 2>&AS_MESSAGE_LOG_FD | grep "$[2]" >/dev/null 2>&1
+}
+
+test_find_locale_charmap () {
+  save_LC_ALL=$LC_ALL
+  LC_ALL=$_orig_LC_ALL
+  re=$[1]
+
+  init_ctype=`locale 2>&AS_MESSAGE_LOG_FD | $AWK -F= '$[1] == "LC_CTYPE" {
+    $[1] = ""; sub(/^ "/, ""); sub(/"$/, ""); print
+  }'`
+
+  LC_ALL=$save_LC_ALL
+  if test_check_locale_charmap "$init_ctype" "$re"; then
+    AS_ECHO(["$init_ctype"])
+    return;
+  fi
+
+  set x `locale -a | grep "$re"`; shift
+  for arg; do
+    if test_check_locale_charmap "$arg" "$re"; then
+      AS_ECHO(["$arg"])
+      return;
+    fi
+  done
+}
+m4_divert_pop([PREPARE_TESTS])
+])
index 7f1544127ab5feb4ab9519135f76b059f0b9f89b..8b12d4a65f600aeaf4259f938eefa43a0b3f95c4 100644 (file)
@@ -2,5 +2,6 @@
 /helpdesc
 /helpopt
 /helpopt2
+/helpopt3
 /packtest[su]
 /packtest[su]64
diff --git a/t/nls/gettext.h b/t/nls/gettext.h
new file mode 100644 (file)
index 0000000..b8a8060
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright © 2023 Nick Bowler
+ *
+ * Stub gettext macros for test purposes.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#ifndef TEST_NLS_GETTEXT_H_
+#define TEST_NLS_GETTEXT_H_
+
+#define gettext(s) (s)
+#define pgettext_expr(a, s) (s)
+
+#endif
diff --git a/t/nls/mbswidth.c b/t/nls/mbswidth.c
new file mode 100644 (file)
index 0000000..e8e7c33
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2023 Nick Bowler
+ *
+ * Simplified mbsnwidth for test purposes.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#include <string.h>
+#include <locale.h>
+#include <wchar.h>
+
+#include "mbswidth.h"
+
+int mbsnwidth(const char *buf, size_t buflen, int flags)
+{
+       static int initialized;
+       mbstate_t ps;
+       int ret = 0;
+
+       if (!initialized) {
+               setlocale(LC_CTYPE, "");
+               initialized = 1;
+       }
+
+       memset(&ps, 0, sizeof ps);
+       while (buflen > 0) {
+               wchar_t wc;
+               size_t l;
+               int w;
+
+               l = mbrtowc(&wc, buf, buflen, &ps);
+               if (l == (size_t)-1 || l == (size_t)-2)
+                       return -1;
+               else if (l == 0)
+                       break;
+
+               buflen -= l;
+               buf += l;
+
+               w = wcwidth(wc);
+               if (w < 0)
+                       return -1;
+               ret += w;
+       }
+
+       return ret;
+}
diff --git a/t/nls/mbswidth.h b/t/nls/mbswidth.h
new file mode 100644 (file)
index 0000000..1c4fc56
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2023 Nick Bowler
+ *
+ * Simplified mbsnwidth for test purposes.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#ifndef TEST_NLS_MBSWIDTH_H_
+#define TEST_NLS_MBSWIDTH_H_
+
+#include <stddef.h>
+
+int mbsnwidth(const char *buf, size_t n, int flags);
+
+#endif
index 165376c97f59cf23d1c6c865e7003f1a78776850..fd1e10f5588460f36882c766285a5b56759011fa 100644 (file)
@@ -110,6 +110,23 @@ AT_CHECK([m4_join([ ],
 
 AT_CLEANUP
 
+AT_SETUP([help_print_optstring (NLS fullwidth/halfwidth)])
+AT_KEYWORDS([help nls])
+
+AT_SKIP_IF([test ! -x "$builddir/t/helpopt3"])
+TEST_UTF8_LOCALE([locale_utf8])
+
+AT_CHECK([m4_join([ ],
+  [LC_ALL=$locale_utf8 "$builddir/t/helpopt3"],
+  [--全角],
+  [--ハンカク],
+  )], [0],
+[[  --全角   8
+  --ハンカク       8
+]])
+
+AT_CLEANUP
+
 AT_BANNER([Miscellaneous functions])
 
 TEST_TAP_SIMPLE([copyright_symbol], [copysym], [], [])
index 2076d70e637550118d19c5620f334cd70e87fe0c..7e93427d4a333c8e06dadd5cdb5a04e61bc5a5ae 100644 (file)
@@ -1,5 +1,5 @@
 AT_COPYRIGHT([dnl
-Copyright © 2015,2019-2023 Nick Bowler
+Copyright © 2015, 2019-2023 Nick Bowler
 License WTFPL2: Do What The Fuck You Want To Public License, version 2.
 This is free software: you are free to do what the fuck you want to.
 There is NO WARRANTY, to the extent permitted by law.])
@@ -8,6 +8,7 @@ AT_INIT
 AT_COLOR_TESTS
 
 m4_include([snippet/test-tap.at])
+m4_include([snippet/test-nls.at])
 
 m4_divert_push([PREPARE_TESTS])dnl
 # Reduce influence from the toplevel "make" invocation on test cases.