1#!/bin/bash
2
3# Copyright (c) 2006, Google Inc.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met:
9#
10#     * Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer.
12#     * Redistributions in binary form must reproduce the above
13# copyright notice, this list of conditions and the following disclaimer
14# in the documentation and/or other materials provided with the
15# distribution.
16#     * Neither the name of Google Inc. nor the names of its
17# contributors may be used to endorse or promote products derived from
18# this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32# ---
33# Author: Craig Silverstein
34#
35# Just tries to run the gflags_unittest with various flags
36# defined in gflags.cc, and make sure they give the
37# appropriate exit status and appropriate error message.
38
39if [ -z "$1" ]; then
40  echo "USAGE: $0 <unittest exe> [top_srcdir] [tmpdir]"
41  exit 1
42fi
43EXE="$1"
44SRCDIR="${2:-./}"
45TMPDIR="${3:-/tmp/gflags}"
46EXE2="${EXE}2"    # eg, gflags_unittest2
47EXE3="${EXE}3"    # eg, gflags_unittest3
48
49# $1: executable
50# $2: line-number $3: expected return code.  $4: substring of expected output.
51# $5: a substring you *don't* expect to find in the output.  $6+ flags
52ExpectExe() {
53  local executable="$1"
54  shift
55  local line_number="$1"
56  shift
57  local expected_rc="$1"
58  shift
59  local expected_output="$1"
60  shift
61  local unexpected_output="$1"
62  shift
63
64    # We always add --srcdir because it's needed for correctness
65    "$executable" --srcdir="$SRCDIR" "$@" > "$TMPDIR/test.$line_number" 2>&1
66
67  local actual_rc=$?
68  if [ $actual_rc != $expected_rc ]; then
69    echo "Test on line $line_number failed:" \
70         "expected rc $expected_rc, got $actual_rc"
71    exit 1;
72  fi
73  if [ -n "$expected_output" ] &&
74     ! fgrep -e "$expected_output" "$TMPDIR/test.$line_number" >/dev/null; then
75    echo "Test on line $line_number failed:" \
76         "did not find expected substring '$expected_output'"
77    exit 1;
78  fi
79  if [ -n "$unexpected_output" ] &&
80     fgrep -e "$unexpected_output" "$TMPDIR/test.$line_number" >/dev/null; then
81    echo "Test line $line_number failed:" \
82         "found unexpected substring '$unexpected_output'"
83    exit 1;
84  fi
85}
86
87# $1: line-number $2: expected return code.  $3: substring of expected output.
88# $4: a substring you *don't* expect to find in the output.  $5+ flags
89Expect() {
90  ExpectExe "$EXE" "$@"
91}
92
93rm -rf "$TMPDIR"
94mkdir "$TMPDIR" || exit 2
95
96# Create a few flagfiles we can use later
97echo "--version" > "$TMPDIR/flagfile.1"
98echo "--foo=bar" > "$TMPDIR/flagfile.2"
99echo "--nounused_bool" >> "$TMPDIR/flagfile.2"
100echo "--flagfile=$TMPDIR/flagfile.2" > "$TMPDIR/flagfile.3"
101
102# Set a few environment variables (useful for --tryfromenv)
103export FLAGS_undefok=foo,bar
104export FLAGS_weirdo=
105export FLAGS_version=true
106export FLAGS_help=false
107
108# First, just make sure the unittest works as-is
109Expect $LINENO 0 "PASS" ""
110
111# --help should show all flags, including flags from gflags_reporting
112Expect $LINENO 1 "/gflags_reporting.cc" "" --help
113
114# Make sure that --help prints even very long helpstrings.
115Expect $LINENO 1 "end of a long helpstring" "" --help
116
117# Make sure --help reflects flag changes made before flag-parsing
118Expect $LINENO 1 \
119     "-changed_bool1 (changed) type: bool default: true" "" --help
120Expect $LINENO 1 \
121     "-changed_bool2 (changed) type: bool default: false currently: true" "" \
122     --help
123# And on the command-line, too
124Expect $LINENO 1 \
125     "-changeable_string_var () type: string default: \"1\" currently: \"2\"" \
126     "" --changeable_string_var 2 --help
127
128# --nohelp and --help=false should be as if we didn't say anything
129Expect $LINENO 0 "PASS" "" --nohelp
130Expect $LINENO 0 "PASS" "" --help=false
131
132# --helpfull is the same as help
133Expect $LINENO 1 "/gflags_reporting.cc" "" -helpfull
134
135# --helpshort should show only flags from the unittest itself
136Expect $LINENO 1 "/gflags_unittest.cc" \
137       "/gflags_reporting.cc" --helpshort
138
139# --helpshort should show the tldflag we created in the unittest dir
140Expect $LINENO 1 "tldflag1" "/google.cc" --helpshort
141Expect $LINENO 1 "tldflag2" "/google.cc" --helpshort
142
143# --helpshort should work if the main source file is suffixed with [_-]main
144ExpectExe "$EXE2" $LINENO 1 "/gflags_unittest-main.cc" \
145          "/gflags_reporting.cc" --helpshort
146ExpectExe "$EXE3" $LINENO 1 "/gflags_unittest_main.cc" \
147          "/gflags_reporting.cc" --helpshort
148
149# --helpon needs an argument
150Expect $LINENO 1 \
151     "'--helpon' is missing its argument; flag description: show help on" \
152     "" --helpon
153
154# --helpon argument indicates what file we'll show args from
155Expect $LINENO 1 "/gflags.cc" "/gflags_unittest.cc" \
156  --helpon=gflags
157
158# another way of specifying the argument
159Expect $LINENO 1 "/gflags.cc" "/gflags_unittest.cc" \
160       --helpon gflags
161
162# test another argument
163Expect $LINENO 1 "/gflags_unittest.cc" "/gflags.cc" \
164  --helpon=gflags_unittest
165
166# helpmatch is like helpon but takes substrings
167Expect $LINENO 1 "/gflags_reporting.cc" \
168       "/gflags_unittest.cc" -helpmatch reporting
169Expect $LINENO 1 "/gflags_unittest.cc" \
170       "/gflags.cc" -helpmatch=unittest
171
172# if no flags are found with helpmatch or helpon, suggest --help
173Expect $LINENO 1 "No modules matched" "/gflags_unittest.cc" \
174  -helpmatch=nosuchsubstring
175Expect $LINENO 1 "No modules matched" "/gflags_unittest.cc" \
176  -helpon=nosuchmodule
177
178# helppackage shows all the flags in the same dir as this unittest
179# --help should show all flags, including flags from google.cc
180Expect $LINENO 1 "/gflags_reporting.cc" "" --helppackage
181
182# xml!
183Expect $LINENO 1 "/gflags_unittest.cc</file>" \
184  "/gflags_unittest.cc:" --helpxml
185
186# just print the version info and exit
187Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" --version
188Expect $LINENO 0 "version test_version" "gflags_unittest.cc" --version
189
190# --undefok is a fun flag...
191Expect $LINENO 1 "unknown command line flag 'foo'" "" --undefok= --foo --unused_bool
192Expect $LINENO 0 "PASS" "" --undefok=foo --foo --unused_bool
193# If you say foo is ok to be undefined, we'll accept --nofoo as well
194Expect $LINENO 0 "PASS" "" --undefok=foo --nofoo --unused_bool
195# It's ok if the foo is in the middle
196Expect $LINENO 0 "PASS" "" --undefok=fee,fi,foo,fum --foo --unused_bool
197# But the spelling has to be just right...
198Expect $LINENO 1 "unknown command line flag 'foo'" "" --undefok=fo --foo --unused_bool
199Expect $LINENO 1 "unknown command line flag 'foo'" "" --undefok=foot --foo --unused_bool
200
201# See if we can successfully load our flags from the flagfile
202Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \
203  --flagfile="$TMPDIR/flagfile.1"
204Expect $LINENO 0 "PASS" "" --flagfile="$TMPDIR/flagfile.2"
205Expect $LINENO 0 "PASS" "" --flagfile="$TMPDIR/flagfile.3"
206
207# Also try to load flags from the environment
208Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \
209  --fromenv=version
210Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \
211  --tryfromenv=version
212Expect $LINENO 0 "PASS" "" --fromenv=help
213Expect $LINENO 0 "PASS" "" --tryfromenv=help
214Expect $LINENO 1 "helpfull not found in environment" "" --fromenv=helpfull
215Expect $LINENO 0 "PASS" "" --tryfromenv=helpfull
216Expect $LINENO 0 "PASS" "" --tryfromenv=undefok --foo
217Expect $LINENO 1 "unknown command line flag" "" --tryfromenv=weirdo
218Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \
219  --tryfromenv=test_bool,version,unused_bool
220Expect $LINENO 1 "not found in environment" "" --fromenv=test_bool
221Expect $LINENO 1 "unknown command line flag" "" --fromenv=test_bool,ok
222# Here, the --version overrides the fromenv
223Expect $LINENO 0 "gflags_unittest" "gflags_unittest.cc" \
224  --fromenv=test_bool,version,ok
225
226# Make sure -- by itself stops argv processing
227Expect $LINENO 0 "PASS" "" -- --help
228
229
230# And we should die if the flag value doesn't pass the validator
231Expect $LINENO 1 "ERROR: failed validation of new value 'true' for flag 'always_fail'" "" --always_fail
232
233# TODO(user) And if locking in validators fails.
234# Expect $LINENO 0 "PASS" "" --deadlock_if_cant_lock
235
236echo "PASS"
237exit 0
238