--- /dev/null
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <ccan/tap/tap.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <err.h>
+#include "utils.h"
+
+/* We don't actually want it to exit... */
+static jmp_buf exited;
+#define errx save_and_jump
+
+static void save_and_jump(int ecode, const char *fmt, ...);
+
+#include <ccan/opt/helpers.c>
+#include <ccan/opt/opt.c>
+#include <ccan/opt/usage.c>
+#include <ccan/opt/parse.c>
+
+static char *output = NULL;
+
+static int saved_vprintf(const char *fmt, va_list ap)
+{
+ char *p;
+ int ret = vasprintf(&p, fmt, ap);
+
+ if (output) {
+ output = realloc(output, strlen(output) + strlen(p) + 1);
+ strcat(output, p);
+ free(p);
+ } else
+ output = p;
+ return ret;
+}
+
+static void save_and_jump(int ecode, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ saved_vprintf(fmt, ap);
+ va_end(ap);
+ longjmp(exited, ecode + 1);
+}
+
+static void reset(void)
+{
+ free(output);
+ output = NULL;
+ free(opt_table);
+ opt_table = NULL;
+ opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int exitval;
+
+ plan_tests(14);
+
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ /* Bad type. */
+ _opt_register("-a", OPT_SUBTABLE, (void *)opt_version_and_exit,
+ NULL, NULL, "1.2.3", "");
+ fail("_opt_register returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ ok1(strstr(output, "Option -a: unknown entry type"));
+ }
+ reset();
+
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ /* NULL description. */
+ opt_register_noarg("-a", test_noarg, "", NULL);
+ fail("_opt_register returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ ok1(strstr(output, "Option -a: description cannot be NULL"));
+ }
+ reset();
+
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ /* Bad option name. */
+ opt_register_noarg("a", test_noarg, "", "");
+ fail("_opt_register returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ ok1(strstr(output, "Option a: does not begin with '-'"));
+ }
+
+ reset();
+
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ /* Bad option name. */
+ opt_register_noarg("--", test_noarg, "", "");
+ fail("_opt_register returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ ok1(strstr(output, "Option --: invalid long option '--'"));
+ }
+
+ reset();
+
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ /* Bad option name. */
+ opt_register_noarg("--a|-aaa", test_noarg, "", "");
+ fail("_opt_register returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ ok1(strstr(output,
+ "Option --a|-aaa: invalid short option '-aaa'"));
+ }
+ reset();
+
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ /* Documentation for non-optios. */
+ opt_register_noarg("--a foo", test_noarg, "", "");
+ fail("_opt_register returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ ok1(strstr(output,
+ "Option --a foo: does not take arguments 'foo'"));
+ }
+ reset();
+
+ exitval = setjmp(exited);
+ if (exitval == 0) {
+ /* Documentation for non-optios. */
+ opt_register_noarg("--a=foo", test_noarg, "", "");
+ fail("_opt_register returned?");
+ } else {
+ ok1(exitval - 1 == 1);
+ ok1(strstr(output,
+ "Option --a=foo: does not take arguments 'foo'"));
+ }
+ return exit_status();
+}