Merge branch 'master' of github.com:kward/shflags
diff --git a/.githooks/generic b/.githooks/generic
new file mode 100755
index 0000000..b1b5cd0
--- /dev/null
+++ b/.githooks/generic
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# A generic git hook proxy.
+# https://git-scm.com/docs/githooks
+
+run() {
+  hook=$1
+  file=$2
+
+  n=$(echo "${file}" |sed "s/^.*${hook}\.//")
+  echo "running ${n} ${hook}"
+  ${file}
+}
+
+die() {
+  echo 'error: hook did not succeed' >&2
+  exit 1
+}
+
+# Redirect output to stderr.
+exec 1>&2
+
+githooks='.githooks'
+basename=$(basename "$0")
+
+for f in $(cd ${githooks} && echo *); do
+  case "${f}" in
+    pre-commit.*)
+      # Called by "git commit" with no arguments.
+      [ "${basename}" = 'pre-commit' ] || continue
+      run pre-commit "${githooks}/${f}" || die
+      ;;
+  esac
+done
diff --git a/.githooks/pre-commit.shellcheck b/.githooks/pre-commit.shellcheck
new file mode 100755
index 0000000..99a318c
--- /dev/null
+++ b/.githooks/pre-commit.shellcheck
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Git hook to run ShellCheck.
+#
+# ShellCheck <https://www.shellcheck.net/>
+
+# Treat unset variables as an error when performing parameter expansion.
+set -u
+
+if ! command -v shellcheck >/dev/null; then
+  echo 'unable to locate shellcheck' >&2
+  return 0
+fi
+
+for f in $(git diff --cached --name-only); do
+  cmd=':'
+  case "${f}" in
+    shflags|shflags_test_helpers) cmd="shellcheck -s sh ${f}" ;;
+    *.sh) cmd="shellcheck ${f}" ;;
+  esac
+  if ! ${cmd}; then
+    echo "shellcheck error for '${f}'" >&2
+  fi
+done
diff --git a/.travis.yml b/.travis.yml
index 66a0c25..8d82c6a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,19 +7,23 @@
   # Execute the unit tests.
   - ./test_runner
 
-os:
-  - linux
-  - osx
-
 addons:
   apt:
     packages:
       - ksh
+      - mksh
       - zsh
 
 matrix:
   include:
     - os: linux
+      # Ubuntu Bionic 18.04
+      dist: bionic
+    - os: linux
+      # Ubuntu Xenial 16.04
+      dist: xenial
+    - os: osx
+    - os: linux
       script:
         # Run the source through ShellCheck (http://www.shellcheck.net).
         - shellcheck *_test.sh
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9915b70..cfc4918 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -16,7 +16,7 @@
 }
 ```
 
-One-line functions are allowed if they can fit within the 80 char line limit.
+One-line functions are allowed if they are for a single command.
 
 ```sh
 doSomething() { echo 'done!'; }
@@ -118,10 +118,11 @@
 fi
 ```
 
-Lines of code should be no longer than 80 characters unless absolutely
-necessary. When lines are wrapped using the backslash character '\', subsequent
-lines should be indented with four (4) spaces so as to differentiate from the
-standard spacing of two characters, and tabs may not be used.
+Lines of code have no line limit, although the general preference is to wrap
+lines at reasonable boundaries (e.g., between if/then/else clauses). When long
+lines are wrapped using the backslash character '\', subsequent lines should be
+indented with four (4) spaces so as to differentiate from the standard spacing
+of two characters, and tabs may not be used.
 
 ```sh
 for x in some set of very long set of arguments that make for a very long \
diff --git a/init_githooks.sh b/init_githooks.sh
new file mode 100755
index 0000000..19a380f
--- /dev/null
+++ b/init_githooks.sh
@@ -0,0 +1,47 @@
+#! /bin/sh
+#
+# Initialize the local git hooks this repository.
+# https://git-scm.com/docs/githooks
+
+topLevel=$(git rev-parse --show-toplevel)
+if ! cd "${topLevel}"; then
+  echo "filed to cd into topLevel directory '${topLevel}'"
+  exit 1
+fi
+
+hooksDir="${topLevel}/.githooks"
+if ! hooksPath=$(git config core.hooksPath); then
+  hooksPath="${topLevel}/.git/hooks"
+fi
+
+src="${hooksDir}/generic"
+echo "linking hooks..."
+for hook in \
+  applypatch-msg \
+  pre-applypatch \
+  post-applypatch \
+  pre-commit \
+  pre-merge-commit \
+  prepare-commit-msg \
+  commit-msg \
+  post-commit \
+  pre-rebase \
+  post-checkout \
+  post-merge \
+  pre-push \
+  pre-receive \
+  update \
+  post-receive \
+  post-update \
+  push-to-checkout \
+  pre-auto-gc \
+  post-rewrite \
+  sendemail-validate \
+  fsmonitor-watchman \
+  p4-pre-submit \
+  post-index-change
+do
+  echo "- ${hook}"
+  dest="${hooksPath}/${hook}"
+  ln -sf "${src}" "${dest}"
+done
diff --git a/shflags b/shflags
index e907ba7..35fb137 100644
--- a/shflags
+++ b/shflags
@@ -91,7 +91,7 @@
 #   shellcheck disable=SC2166
 
 # Return if FLAGS already loaded.
-[ -n "${FLAGS_VERSION:-}" ] && return 0
+if [ -n "${FLAGS_VERSION:-}" ]; then return 0; fi
 FLAGS_VERSION='1.2.4pre'
 
 # Return values that scripts can use.
@@ -99,27 +99,38 @@
 FLAGS_FALSE=1
 FLAGS_ERROR=2
 
-# Logging levels.
-FLAGS_LEVEL_DEBUG=0
-FLAGS_LEVEL_INFO=1
-FLAGS_LEVEL_WARN=2
-FLAGS_LEVEL_ERROR=3
-FLAGS_LEVEL_FATAL=4
-__FLAGS_LEVEL_DEFAULT=${FLAGS_LEVEL_WARN}
-
-# Determine some reasonable command defaults.
-__FLAGS_EXPR_CMD='expr --'
-__FLAGS_UNAME_S=`uname -s`
-if [ "${__FLAGS_UNAME_S}" = 'BSD' ]; then
-  __FLAGS_EXPR_CMD='gexpr --'
-else
-  _flags_output_=`${__FLAGS_EXPR_CMD} 2>&1`
-  if [ $? -eq ${FLAGS_TRUE} -a "${_flags_output_}" = '--' ]; then
-    # We are likely running inside BusyBox.
-    __FLAGS_EXPR_CMD='expr'
+# shlib_expr_cmd determines a reasonable default `expr` command.
+# https://github.com/kward/shlib
+#
+# Use like:
+#   EXPR_CMD=$(shlib_expr_cmd)
+#   ${EXPR_CMD} 1 + 1
+#
+# Args:
+#   none
+# Output:
+#   string: expr command
+# Return
+#   int: 0 upon success
+shlib_expr_cmd() {
+  if [ "$(uname -s)" = 'BSD' ]; then
+    echo 'gexpr --'
+    return 0
   fi
-  unset _flags_output_
-fi
+
+  _shlib_expr_cmd_='expr --'
+  # shellcheck disable=SC2003
+  if _shlib_output_=$(${_shlib_expr_cmd_} 2>&1); then
+    if [ "${_shlib_output_}" = '--' ]; then
+      # We are likely running inside BusyBox.
+      _shlib_expr_cmd_='expr'
+    fi
+  fi
+
+  echo "${_shlib_expr_cmd_}"
+  unset _shlib_expr_cmd_ _shlib_output_
+}
+__FLAGS_EXPR_CMD=`shlib_expr_cmd`
 
 # Commands a user can override if desired.
 FLAGS_EXPR_CMD=${FLAGS_EXPR_CMD:-${__FLAGS_EXPR_CMD}}
@@ -129,26 +140,28 @@
 # Logging functions.
 #
 
-__flags_level=0 # Default logging level.
+# Logging levels.
+FLAGS_LEVEL_DEBUG=0
+FLAGS_LEVEL_INFO=1
+FLAGS_LEVEL_WARN=2
+FLAGS_LEVEL_ERROR=3
+FLAGS_LEVEL_FATAL=4
+__FLAGS_LEVEL_DEFAULT=${FLAGS_LEVEL_WARN}
+__flags_level=${__FLAGS_LEVEL_DEFAULT} # Current logging level.
 
 _flags_debug() {
-  [ ${__flags_level} -le ${FLAGS_LEVEL_DEBUG} ] || return
-  echo "flags:DEBUG $*" >&2
+  if [ ${__flags_level} -le ${FLAGS_LEVEL_DEBUG} ]; then echo "flags:DEBUG $*" >&2; fi
 }
 _flags_info() {
-  [ ${__flags_level} -le ${FLAGS_LEVEL_INFO} ] || return
-  echo "flags:INFO $*" >&2
+  if [ ${__flags_level} -le ${FLAGS_LEVEL_INFO} ]; then echo "flags:INFO $*" >&2; fi
 }
 _flags_warn() {
-  [ ${__flags_level} -le ${FLAGS_LEVEL_WARN} ] || return
-  echo "flags:WARN $*" >&2
+  if [ ${__flags_level} -le ${FLAGS_LEVEL_WARN} ]; then echo "flags:WARN $*" >&2; fi
 }
 _flags_error() {
-  [ ${__flags_level} -le ${FLAGS_LEVEL_ERROR} ] || return
-  echo "flags:ERROR $*" >&2
+  if [ ${__flags_level} -le ${FLAGS_LEVEL_ERROR} ]; then echo "flags:ERROR $*" >&2; fi
 }
 _flags_fatal() {
-  [ ${__flags_level} -le ${FLAGS_LEVEL_FATAL} ] || return
   echo "flags:FATAL $*" >&2
   exit ${FLAGS_ERROR}
 }
@@ -156,7 +169,7 @@
 # Get the logging level.
 flags_loggingLevel() { echo ${__flags_level}; }
 
-# Set the logging level.
+# Set the logging level by overriding the `__flags_level` variable.
 #
 # Args:
 #   _flags_level_: integer: new logging level
@@ -165,9 +178,9 @@
 flags_setLoggingLevel() {
   [ $# -ne 1 ] && _flags_fatal "flags_setLevel(): logging level missing"
   _flags_level_=$1
-  [ "${_flags_level_}" -ge "${FLAGS_LEVEL_DEBUG}" \
-    -a "${_flags_level_}" -le "${FLAGS_LEVEL_FATAL}" ] \
-      || _flags_fatal "Invalid logging level '${_flags_level_}' specified."
+  if ! [ "${_flags_level_}" -ge "${FLAGS_LEVEL_DEBUG}" -a "${_flags_level_}" -le "${FLAGS_LEVEL_FATAL}" ]; then
+    _flags_fatal "Invalid logging level '${_flags_level_}' specified."
+  fi
   __flags_level=$1
   unset _flags_level_
 }
@@ -320,8 +333,7 @@
   _flags_usName_="`_flags_underscoreName "${_flags_name_}"`"
 
   # Check whether the flag name is reserved.
-  _flags_itemInList "${_flags_usName_}" "${__FLAGS_RESERVED_LIST}"
-  if [ $? -eq ${FLAGS_TRUE} ]; then
+  if _flags_itemInList "${_flags_usName_}" "${__FLAGS_RESERVED_LIST}"; then
     flags_error="flag name (${_flags_name_}) is reserved"
     _flags_return_=${FLAGS_ERROR}
   fi
@@ -345,9 +357,7 @@
   fi
 
   # Check for existing short name definition.
-  if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
-      -a "${_flags_short_}" != "${__FLAGS_NULL}" ]
-  then
+  if [ ${_flags_return_} -eq ${FLAGS_TRUE} -a "${_flags_short_}" != "${__FLAGS_NULL}" ]; then
     if _flags_itemInList "${_flags_short_}" "${__flags_shortNames}"; then
       flags_error="flag short name (${_flags_short_}) already defined"
       _flags_warn "${flags_error}"
@@ -1201,7 +1211,7 @@
   unset flags_name_ flags_type_ flags_strToEval_ flags_usName_
 }
 
-#
+#-----------------------------------------------------------------------------
 # Initialization
 #
 
diff --git a/shflags_defines_test.sh b/shflags_defines_test.sh
index f2e1d71..7f5baf7 100755
--- a/shflags_defines_test.sh
+++ b/shflags_defines_test.sh
@@ -3,7 +3,7 @@
 #
 # shFlags unit test for the flag definition methods
 #
-# Copyright 2008-2017 Kate Ward. All Rights Reserved.
+# Copyright 2008-2020 Kate Ward. All Rights Reserved.
 # Released under the Apache 2.0 license.
 #
 # Author: kate.ward@forestent.com (Kate Ward)
@@ -14,7 +14,10 @@
 #   shellcheck disable=SC1090,SC1091
 
 # Exit immediately if a simple command exits with a non-zero status.
-#set -e
+set -e
+
+# Treat unset variables as an error when performing parameter expansion.
+set -u
 
 # These variables will be overridden by the test helpers.
 stdoutF="${TMPDIR:-/tmp}/STDOUT"
@@ -25,172 +28,165 @@
 
 testFlagsDefine() {
   # No arguments.
-  _flags_define >"${stdoutF}" 2>"${stderrF}"
-  assertFalse '_flags_define() with no arguments should have failed.' $?
+  if _flags_define >"${stdoutF}" 2>"${stderrF}"
+  then :; else
+    assertEquals '_flags_define() with no arguments should error' "${FLAGS_ERROR}" $?
+  fi
   assertErrorMsg '' 'no arguments'
 
   # One argument.
-  _flags_define arg1 >"${stdoutF}" 2>"${stderrF}"
-  assertFalse '_flags_define() call with one argument should fail' $?
+  if _flags_define arg1 >"${stdoutF}" 2>"${stderrF}"
+  then :; else
+    assertEquals '_flags_define() call with one argument should error' "${FLAGS_ERROR}" $?
+  fi
   assertErrorMsg '' 'one argument'
 
   # Two arguments.
-  _flags_define arg1 arg2 >"${stdoutF}" 2>"${stderrF}"
-  assertFalse '_flags_define() call with two arguments should fail' $?
+  if _flags_define arg1 arg2 >"${stdoutF}" 2>"${stderrF}"
+  then :; else
+    assertEquals '_flags_define() call with two arguments should error' "${FLAGS_ERROR}" $?
+  fi
   assertErrorMsg '' 'two arguments'
 
   # Three arguments.
-  _flags_define arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}"
-  assertFalse '_flags_define() call with three arguments should fail' $?
+  if _flags_define arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}"
+  then :; else
+    assertEquals '_flags_define() call with three arguments should error' "${FLAGS_ERROR}" $?
+  fi
   assertErrorMsg '' 'three arguments'
 
   # Multiple definition. Assumes working boolean definition (tested elsewhere).
-  _flags_define "${__FLAGS_TYPE_BOOLEAN}" multiDefBool true 'multi def #1' m
-  _flags_define "${__FLAGS_TYPE_BOOLEAN}" multiDefBool false 'multi def #2' m \
-      >"${stdoutF}" 2>"${stderrF}"
-  assertFalse '_flags_define() with existing flag name should fail' $?
-  assertTrue \
-      '_flags_define() should not overwrite previously defined default.' \
-      "${FLAGS_multiDefBool:-}"
+  if ! _flags_define "${__FLAGS_TYPE_BOOLEAN}" multiDefBool true 'multi def #1' m; then
+    fail "didn't expect _flags_define for 'multi def #1' to fail"
+  fi
+  if _flags_define "${__FLAGS_TYPE_BOOLEAN}" multiDefBool false 'multi def #2' m >"${stdoutF}" 2>"${stderrF}"
+  then :; else
+    assertEquals '_flags_define() with existing flag name should fail' "${FLAGS_FALSE}" $?
+  fi
+  assertTrue '_flags_define() should not overwrite previously defined default.' "${FLAGS_multiDefBool:-}"
   assertWarnMsg '' 'existing flag'
 
   # Duplicate dashed and underscored definition.
-  _flags_define "${__FLAGS_TYPE_STRING}" long-name 'foo' 'dashed name' l
-  _flags_define "${__FLAGS_TYPE_STRING}" long_name 'bar' 'underscored name' l \
-      >"${stdoutF}" 2>"${stderrF}"
-  assertFalse '_flags_define() with existing flag name should fail' $?
+  if ! _flags_define "${__FLAGS_TYPE_STRING}" long-name 'foo' 'dashed name' l; then
+    fail "didn't expect _flags_define() for 'dashed name' to fail"
+  fi
+  if _flags_define "${__FLAGS_TYPE_STRING}" long_name 'bar' 'underscored name' l >"${stdoutF}" 2>"${stderrF}"
+  then :; else
+    assertEquals '_flags_define() with duplicate dashed and underscored definition should fail' "${FLAGS_FALSE}" $?
+  fi
   # shellcheck disable=SC2154
-  assertEquals \
-      '_flags_define() should not overwrite previously defined default.' \
-      "${FLAGS_long_name}" 'foo'
+  assertEquals '_flags_define() should not overwrite previously defined default.' "${FLAGS_long_name}" 'foo'
   assertWarnMsg '' 'already exists'
 
   # TODO(kward): test requirement of enhanced getopt.
 
   # Invalid type.
-  _flags_define invalid arg2 arg3 arg4 i >"${stdoutF}" 2>"${stderrF}"
-  assertFalse '_flags_define() with "invalid" type should have failed.' $?
+  if _flags_define invalid arg2 arg3 arg4 i >"${stdoutF}" 2>"${stderrF}"
+  then :; else
+    assertEquals '_flags_define() with "invalid" type should have failed.' "${FLAGS_ERROR}" $?
+  fi
   assertErrorMsg 'unrecognized flag type' 'invalid type'
 }
 
 testBoolean() {
-  # Test true defaults.
-  for default in 'true' 't' 0; do
+  while read -r desc ok default want; do
     flags_reset
-    DEFINE_boolean boolVal "${default}" 'my boolean' b
-    rtrn=$?
-    assertTrue \
-        "DEFINE_boolean() call with default of '${default}' failed." \
-        "${FLAGS_boolVal:-}"
-    assertTrue \
-        "DEFINE_boolean() call with default of '${default}' returned failure." \
-        ${rtrn}
-  done
 
-  # test false defaults
-  for default in 'false' 'f' 1; do
-    flags_reset
-    DEFINE_boolean boolVal "${default}" 'my boolean' b
-    rtrn=$?
-    assertFalse \
-        "DEFINE_boolean() call with default of '${default}' failed." \
-        "${FLAGS_boolVal:-}"
-    assertTrue \
-        "DEFINE_boolean() call with default of '${default}' returned failure." \
-        ${rtrn}
-  done
-
-  # Test invalid default.
-  flags_reset
-  DEFINE_boolean boolVal 'invalid' 'my boolean' b >"${stdoutF}" 2>"${stderrF}"
-  assertFalse 'DEFINE_boolean() call with invalid default did not fail.' $?
-  assertErrorMsg
+    if DEFINE_boolean boolVal "${default}" 'my boolean' b >"${stdoutF}" 2>"${stderrF}"
+    then
+      assertEquals "${desc}: incorrect FLAGS_boolVal value" "${FLAGS_boolVal:-}" "${want}"
+    else
+      got=$?
+      if [ "${ok}" -eq "${FLAGS_TRUE}" ]; then
+        assertEquals "${desc}: DEFINE_boolean() failed unexpectedly" "${want}" "${got}"
+      else
+        assertEquals "${desc}: DEFINE_boolean() expected different return value" "${want}" "${got}"
+        assertErrorMsg
+      fi
+    fi
+  done <<EOF
+true_long   ${FLAGS_TRUE}  true    ${FLAGS_TRUE}
+true_short  ${FLAGS_TRUE}  t       ${FLAGS_TRUE}
+true_int    ${FLAGS_TRUE}  0       ${FLAGS_TRUE}
+false_long  ${FLAGS_TRUE}  false   ${FLAGS_FALSE}
+false_short ${FLAGS_TRUE}  f       ${FLAGS_FALSE}
+false_int   ${FLAGS_TRUE}  1       ${FLAGS_FALSE}
+invalid     ${FLAGS_FALSE} invalid ${FLAGS_ERROR}
+EOF
 }
 
 testFloat() {
-  # Test valid defaults.
+  # Valid defaults.
   for default in ${TH_FLOAT_VALID}; do
     flags_reset
-    DEFINE_float floatVal "${default}" "float: ${default}" f
-    rtrn=$?
-    assertSame "DEFINE_float() call with valid default failed." \
-        "${default}" "${FLAGS_floatVal:-}"
-    assertTrue \
-        "DEFINE_float() call with valid default of '${default}' returned failure." \
-        ${rtrn}
+    desc="valid_float_val='${default}'"
+    if DEFINE_float floatVal "${default}" 'valid float' f
+    then
+      got="${FLAGS_floatVal:-}" want="${default}"
+      assertEquals "${desc}: incorrect FLAGS_floatVal value" "${want}" "${got}"
+    else
+      assertEquals "${desc}: DEFINE_float() failed unexpectedly." "${FLAGS_TRUE}" $?
+    fi
   done
 
-  # Test invalid defaults.
-  flags_reset
-  DEFINE_float floatVal 'invalid' 'invalid float: string' f \
-      >"${stdoutF}" 2>"${stderrF}"
-  assertFalse 'DEFINE_float() call with string value default did not fail.' $?
-  assertErrorMsg
+  # Invalid defaults.
+  for default in ${TH_FLOAT_INVALID}; do
+    flags_reset
+    desc="invalid_float_val='${default}'"
+    if DEFINE_float floatVal "${default}" 'invalid float' f >"${stdoutF}" 2>"${stderrF}"
+    then
+      fail "${desc}: expected DEFINE_float() to fail"
+    else
+      assertEquals "${desc}: DEFINE_float() expected error" "${FLAGS_ERROR}" $?
+      assertErrorMsg
+    fi
+  done
 }
 
 testInteger() {
-  # Test valid defaults.
+  # Valid defaults.
   for default in ${TH_INT_VALID}; do
     flags_reset
-    DEFINE_integer intVal "${default}" "integer: ${default}" i
-    rtrn=$?
-    assertSame \
-        "DEFINE_integer() call with valid default failed." \
-        "${default}" "${FLAGS_intVal:-}"
-    assertTrue \
-        "DEFINE_integer() call with valid default of '${default}' returned failure." \
-        ${rtrn}
+    desc="valid_int_val='${default}'"
+    if DEFINE_integer intVal "${default}" 'valid integer' i
+    then
+      got="${FLAGS_intVal:-}" want="${default}"
+      assertEquals "${desc}: incorrect FLAGS_intVal value" "${want}" "${got}"
+    else
+      assertEquals "${desc}: DEFINE_integer() failed unexpectedly." "${FLAGS_TRUE}" $?
+    fi
   done
 
-  # Test invalid defaults.
-  flags_reset
-  DEFINE_integer intVal 1.234 'invalid integer: float' i \
-      >"${stdoutF}" 2>"${stderrF}"
-  assertFalse 'DEFINE_integer() call with float value default did not fail.' $?
-  assertErrorMsg 'invalid default' 'float default'
-
-  DEFINE_integer intVal -1.234 'invalid integer: negative float' i \
-      >"${stdoutF}" 2>"${stderrF}"
-  assertFalse \
-      'DEFINE_integer() call with negative float value default did not fail.' \
-      $?
-  assertErrorMsg 'invalid default' 'negative float default'
-
-  DEFINE_integer intVal 'invalid' 'invalid integer: string' i \
-      >"${stdoutF}" 2>"${stderrF}"
-  assertFalse \
-      'DEFINE_integer() call with string value default did not fail.' \
-      $?
-  assertErrorMsg 'invalid default' 'string default'
+  # Invalid defaults.
+  for default in ${TH_INT_INVALID}; do
+    flags_reset
+    desc="invalid_int_val='${default}'"
+    if DEFINE_integer intVal "${default}" 'invalid integer' i >"${stdoutF}" 2>"${stderrF}"
+    then
+      fail "${desc}: expected DEFINE_integer() to fail"
+    else
+      assertEquals "${desc}: DEFINE_integer() expected error." "${FLAGS_ERROR}" $?
+      assertErrorMsg
+    fi
+  done
 }
 
-testString()
-{
-  # test valid defaults
-  for default in \
-      ${TH_BOOL_VALID} \
-      ${TH_FLOAT_VALID} \
-      ${TH_INT_VALID} \
-      'also valid'
+testString() {
+  # Valid defaults.
+  for default in ${TH_BOOL_VALID} ${TH_FLOAT_VALID} ${TH_INT_VALID} 'also valid' ''
   do
     flags_reset
-    DEFINE_string strVal "${default}" "string: ${default}" s
-    rtrn=$?
-    assertSame \
-        "DEFINE_string() call with valid default failed." \
-        "${default}" "${FLAGS_strVal:-}"
-    assertTrue \
-        "DEFINE_string() call with valid default of '${default}' returned failure." \
-        ${rtrn}
+    desc="valid_string_val='${default}'"
+    if DEFINE_string strVal "${default}" "string: ${default}" s
+    then
+      got="${FLAGS_strVal:-}" want="${default}"
+      assertEquals "${desc}: incorrect FLAGS_strVal value" "${want}" "${got}"
+    else
+      assertEquals "${desc}: DEFINE_string() failed unexpectedly." "${FLAGS_TRUE}" $?
+    fi
   done
 
-  # test "empty" strings
-  flags_reset
-  DEFINE_string str '' "string: empty single quotes" s
-  rtrn=$?
-  assertSame \
-      "DEFINE_string() call with valid default failed." \
-      '' "${FLAGS_str:-}"
+  # There are no known invalid defaults.
 }
 
 testShortNameLength() {
@@ -199,11 +195,13 @@
 }
 
 testFlagNameIsReserved() {
-  ( DEFINE_string TRUE '' 'true is a reserved flag name' t \
-      >"${stdoutF}" 2>"${stderrF}" )
-  rtrn=$?
-  assertEquals "${FLAGS_ERROR}" "${rtrn}"
-  assertErrorMsg 'flag name (TRUE) is reserved'
+  if DEFINE_string TRUE '' 'true is a reserved flag name' t >"${stdoutF}" 2>"${stderrF}"
+  then
+    fail "expected DEFINE with reserved flag name to fail"
+  else
+    assertEquals "expected error from DEFINE with reserved flag" "${FLAGS_ERROR}" $?
+    assertErrorMsg 'flag name (TRUE) is reserved'
+  fi
 }
 
 oneTimeSetUp() {