// Copyright (c) 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // --- // Author: Marius Eriksen // // For now, this unit test does not cover all features of // commandlineflags.cc #include "config.h" #include #include #include // for unlink() #include // for mkdir() #include // for isinf() and isnan() #include #include #include "google/gflags.h" using std::vector; using std::string; // Returns the number of elements in an array. We don't use the safer // version in base/basictypes.h as commandlineflags is open-sourced. #define GET_ARRAY_SIZE(arr) (sizeof(arr)/sizeof(*(arr))) DECLARE_string(tryfromenv); // in commandlineflags.cc DEFINE_string(test_tmpdir, "/tmp/gflags_unittest", "Dir we use for temp files"); DEFINE_string(srcdir, google::StringFromEnv("SRCDIR", "."), "Source-dir root, needed to find gflags_unittest_flagfile"); DEFINE_bool(test_bool, false, "tests bool-ness"); DEFINE_int32(test_int32, -1, ""); DEFINE_int64(test_int64, -2, ""); DEFINE_uint64(test_uint64, 2, ""); DEFINE_double(test_double, -1.0, ""); DEFINE_string(test_string, "initial", ""); // // The below ugliness gets some additional code coverage in the -helpxml // and -helpmatch test cases having to do with string lengths and formatting // DEFINE_bool(test_bool_with_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_quite_long_name, false, "extremely_extremely_extremely_extremely_extremely_extremely_extremely_extremely_long_meaning"); DEFINE_string(test_str1, "initial", ""); DEFINE_string(test_str2, "initial", ""); DEFINE_string(test_str3, "initial", ""); // This is used to test setting tryfromenv manually DEFINE_string(test_tryfromenv, "initial", ""); // These are never used in this unittest, but can be used by // commandlineflags_unittest.sh when it needs to specify flags // that are legal for commandlineflags_unittest but don't need to // be a particular value. DEFINE_bool(unused_bool, true, "unused bool-ness"); DEFINE_int32(unused_int32, -1001, ""); DEFINE_int64(unused_int64, -2001, ""); DEFINE_uint64(unused_uint64, 2000, ""); DEFINE_double(unused_double, -1000.0, ""); DEFINE_string(unused_string, "unused", ""); _START_GOOGLE_NAMESPACE_ // The following is some bare-bones testing infrastructure #define EXPECT_TRUE(cond) \ do { \ if (!(cond)) { \ fprintf(stderr, "Check failed: %s\n", #cond); \ exit(1); \ } \ } while (0) #define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond)) #define EXPECT_OP(op, val1, val2) \ do { \ if (!((val1) op (val2))) { \ fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \ exit(1); \ } \ } while (0) #define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2) #define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2) #define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2) #define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2) #define EXPECT_NAN(arg) \ do { \ if (!isnan(arg)) { \ fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \ exit(1); \ } \ } while (0) #define EXPECT_INF(arg) \ do { \ if (!isinf(arg)) { \ fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \ exit(1); \ } \ } while (0) #define EXPECT_DOUBLE_EQ(val1, val2) \ do { \ if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \ fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \ exit(1); \ } \ } while (0) #define EXPECT_STREQ(val1, val2) \ do { \ if (strcmp((val1), (val2)) != 0) { \ fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \ exit(1); \ } \ } while (0) static bool g_called_exit; static void CalledExit(int) { g_called_exit = true; } #define EXPECT_DEATH(fn, msg) \ do { \ g_called_exit = false; \ extern void (*commandlineflags_exitfunc)(int); /* in gflags.cc */ \ commandlineflags_exitfunc = &CalledExit; \ fn; \ commandlineflags_exitfunc = &exit; /* set back to its default */ \ if (!g_called_exit) { \ fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \ exit(1); \ } \ } while (0) vector g_testlist; // the tests to run #define TEST(a, b) \ struct Test_##a##_##b { \ Test_##a##_##b() { g_testlist.push_back(&Run); } \ static void Run() { FlagSaver fs; RunTest(); } \ static void RunTest(); \ }; \ static Test_##a##_##b g_test_##a##_##b; \ void Test_##a##_##b::RunTest() static int RUN_ALL_TESTS() { vector::const_iterator it; for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { (*it)(); } fprintf(stderr, "Passed %d tests\n\nPASS\n", (int)g_testlist.size()); return 0; } // Death tests for "help" options. // // The help system automatically calls exit(1) when you specify any of // the help-related flags ("-helpmatch", "-helpxml") so we can't test // those mainline. // Tests that "-helpmatch" causes the process to die. TEST(ReadFlagsFromStringDeathTest, HelpMatch) { EXPECT_DEATH(ReadFlagsFromString("-helpmatch=base", GetArgv0(), true), ""); } // Tests that "-helpxml" causes the process to die. TEST(ReadFlagsFromStringDeathTest, HelpXml) { EXPECT_DEATH(ReadFlagsFromString("-helpxml", GetArgv0(), true), ""); } // A subroutine needed for testing reading flags from a string. void TestFlagString(const string& flags, const string& expected_string, bool expected_bool, int32 expected_int32, double expected_double) { EXPECT_TRUE(ReadFlagsFromString(flags, GetArgv0(), // errors are fatal true)); EXPECT_EQ(expected_string, FLAGS_test_string); EXPECT_EQ(expected_bool, FLAGS_test_bool); EXPECT_EQ(expected_int32, FLAGS_test_int32); EXPECT_DOUBLE_EQ(expected_double, FLAGS_test_double); } // Tests reading flags from a string. TEST(FlagFileTest, ReadFlagsFromString) { TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "-test_bool=true\n" " -test_int32=1\n" "-test_double=0.0\n", // Expected values "continued", true, 1, 0.0); TestFlagString( // Flag string "# let's make sure it can update values\n" "-test_string=initial\n" "-test_bool=false\n" "-test_int32=123\n" "-test_double=123.0\n", // Expected values "initial", false, 123, 123.0); } // Tests the filename part of the flagfile TEST(FlagFileTest, FilenamesOurfileLast) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "not_our_filename\n" "-test_bool=true\n" " -test_int32=1\n" "gflags_unittest\n" "-test_double=1000.0\n", // Expected values "continued", false, -1, 1000.0); } TEST(FlagFileTest, FilenamesOurfileFirst) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "gflags_unittest\n" "-test_bool=true\n" " -test_int32=1\n" "not_our_filename\n" "-test_double=1000.0\n", // Expected values "continued", true, 1, -1.0); } TEST(FlagFileTest, FilenamesOurfileGlob) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "*flags*\n" "-test_bool=true\n" " -test_int32=1\n" "flags\n" "-test_double=1000.0\n", // Expected values "continued", true, 1, -1.0); } TEST(FlagFileTest, FilenamesOurfileInBigList) { FLAGS_test_string = "initial"; FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_double = -1.0; TestFlagString( // Flag string "-test_string=continued\n" "# some comments are in order\n" "# some\n" " # comments\n" "#are\n" " #trickier\n" "# than others\n" "*first* *flags* *third*\n" "-test_bool=true\n" " -test_int32=1\n" "flags\n" "-test_double=1000.0\n", // Expected values "continued", true, 1, -1.0); } // Tests that a failed flag-from-string read keeps flags at default values TEST(FlagFileTest, FailReadFlagsFromString) { FLAGS_test_int32 = 119; string flags("# let's make sure it can update values\n" "-test_string=non_initial\n" "-test_bool=false\n" "-test_int32=123\n" "-test_double=illegal\n"); EXPECT_FALSE(ReadFlagsFromString(flags, GetArgv0(), // errors are fatal false)); EXPECT_EQ(119, FLAGS_test_int32); EXPECT_EQ("initial", FLAGS_test_string); } // Tests that flags can be set to ordinary values. TEST(SetFlagValueTest, OrdinaryValues) { EXPECT_EQ("initial", FLAGS_test_str1); SetCommandLineOptionWithMode("test_str1", "second", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str1); // set; was default SetCommandLineOptionWithMode("test_str1", "third", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str1); // already set once FLAGS_test_str1 = "initial"; SetCommandLineOptionWithMode("test_str1", "third", SET_FLAG_IF_DEFAULT); EXPECT_EQ("initial", FLAGS_test_str1); // still already set before SetCommandLineOptionWithMode("test_str1", "third", SET_FLAGS_VALUE); EXPECT_EQ("third", FLAGS_test_str1); // changed value SetCommandLineOptionWithMode("test_str1", "fourth", SET_FLAGS_DEFAULT); EXPECT_EQ("third", FLAGS_test_str1); // value not changed (already set before) EXPECT_EQ("initial", FLAGS_test_str2); SetCommandLineOptionWithMode("test_str2", "second", SET_FLAGS_DEFAULT); EXPECT_EQ("second", FLAGS_test_str2); // changed (was default) FLAGS_test_str2 = "extra"; EXPECT_EQ("extra", FLAGS_test_str2); FLAGS_test_str2 = "second"; SetCommandLineOptionWithMode("test_str2", "third", SET_FLAGS_DEFAULT); EXPECT_EQ("third", FLAGS_test_str2); // still changed (was equal to default) SetCommandLineOptionWithMode("test_str2", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("fourth", FLAGS_test_str2); // changed (was default) EXPECT_EQ("initial", FLAGS_test_str3); SetCommandLineOptionWithMode("test_str3", "second", SET_FLAGS_DEFAULT); EXPECT_EQ("second", FLAGS_test_str3); // changed FLAGS_test_str3 = "third"; SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAGS_DEFAULT); EXPECT_EQ("third", FLAGS_test_str3); // not changed (was set) SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("third", FLAGS_test_str3); // not changed (was set) SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAGS_VALUE); EXPECT_EQ("fourth", FLAGS_test_str3); // changed value } // Tests that flags can be set to exceptional values. TEST(SetFlagValueTest, ExceptionalValues) { EXPECT_EQ("test_double set to inf\n", SetCommandLineOption("test_double", "inf")); EXPECT_INF(FLAGS_test_double); EXPECT_EQ("test_double set to inf\n", SetCommandLineOption("test_double", "INF")); EXPECT_INF(FLAGS_test_double); // set some bad values EXPECT_EQ("", SetCommandLineOption("test_double", "0.1xxx")); EXPECT_EQ("", SetCommandLineOption("test_double", " ")); EXPECT_EQ("", SetCommandLineOption("test_double", "")); EXPECT_EQ("test_double set to -inf\n", SetCommandLineOption("test_double", "-inf")); EXPECT_INF(FLAGS_test_double); EXPECT_GT(0, FLAGS_test_double); EXPECT_EQ("test_double set to nan\n", SetCommandLineOption("test_double", "NaN")); EXPECT_NAN(FLAGS_test_double); } // Tests that integer flags can be specified in many ways TEST(SetFlagValueTest, DifferentRadices) { EXPECT_EQ("test_int32 set to 12\n", SetCommandLineOption("test_int32", "12")); EXPECT_EQ("test_int32 set to 16\n", SetCommandLineOption("test_int32", "0x10")); EXPECT_EQ("test_int32 set to 34\n", SetCommandLineOption("test_int32", "0X22")); // Leading 0 is *not* octal; it's still decimal EXPECT_EQ("test_int32 set to 10\n", SetCommandLineOption("test_int32", "010")); } // Tests what happens when you try to set a flag to an illegal value TEST(SetFlagValueTest, IllegalValues) { FLAGS_test_bool = true; FLAGS_test_int32 = 119; FLAGS_test_int64 = 1191; FLAGS_test_uint64 = 11911; EXPECT_EQ("", SetCommandLineOption("test_bool", "12")); EXPECT_EQ("", SetCommandLineOption("test_int32", "7000000000000")); // TODO(csilvers): uncomment this when we disallow negative numbers for uint64 #if 0 EXPECT_EQ("", SetCommandLineOption("test_uint64", "-1")); #endif EXPECT_EQ("", SetCommandLineOption("test_int64", "not a number!")); // Test the empty string with each type of input EXPECT_EQ("", SetCommandLineOption("test_bool", "")); EXPECT_EQ("", SetCommandLineOption("test_int32", "")); EXPECT_EQ("", SetCommandLineOption("test_int64", "")); EXPECT_EQ("", SetCommandLineOption("test_uint64", "")); EXPECT_EQ("", SetCommandLineOption("test_double", "")); EXPECT_EQ("test_string set to \n", SetCommandLineOption("test_string", "")); EXPECT_EQ(true, FLAGS_test_bool); EXPECT_EQ(119, FLAGS_test_int32); EXPECT_EQ(1191, FLAGS_test_int64); EXPECT_EQ(11911, FLAGS_test_uint64); } // Tests that the FooFromEnv does the right thing TEST(FromEnvTest, LegalValues) { setenv("BOOL_VAL1", "true", 1); setenv("BOOL_VAL2", "false", 1); setenv("BOOL_VAL3", "1", 1); setenv("BOOL_VAL4", "F", 1); EXPECT_EQ(true, BoolFromEnv("BOOL_VAL1", false)); EXPECT_EQ(false, BoolFromEnv("BOOL_VAL2", true)); EXPECT_EQ(true, BoolFromEnv("BOOL_VAL3", false)); EXPECT_EQ(false, BoolFromEnv("BOOL_VAL4", true)); EXPECT_EQ(true, BoolFromEnv("BOOL_VAL_UNKNOWN", true)); EXPECT_EQ(false, BoolFromEnv("BOOL_VAL_UNKNOWN", false)); setenv("INT_VAL1", "1", 1); setenv("INT_VAL2", "-1", 1); EXPECT_EQ(1, Int32FromEnv("INT_VAL1", 10)); EXPECT_EQ(-1, Int32FromEnv("INT_VAL2", 10)); EXPECT_EQ(10, Int32FromEnv("INT_VAL_UNKNOWN", 10)); setenv("INT_VAL3", "1099511627776", 1); EXPECT_EQ(1, Int64FromEnv("INT_VAL1", 20)); EXPECT_EQ(-1, Int64FromEnv("INT_VAL2", 20)); EXPECT_EQ(1099511627776LL, Int64FromEnv("INT_VAL3", 20)); EXPECT_EQ(20, Int64FromEnv("INT_VAL_UNKNOWN", 20)); EXPECT_EQ(1, Uint64FromEnv("INT_VAL1", 30)); EXPECT_EQ(1099511627776ULL, Uint64FromEnv("INT_VAL3", 30)); EXPECT_EQ(30, Uint64FromEnv("INT_VAL_UNKNOWN", 30)); // I pick values here that can be easily represented exactly in floating-point setenv("DOUBLE_VAL1", "0.0", 1); setenv("DOUBLE_VAL2", "1.0", 1); setenv("DOUBLE_VAL3", "-1.0", 1); EXPECT_EQ(0.0, DoubleFromEnv("DOUBLE_VAL1", 40.0)); EXPECT_EQ(1.0, DoubleFromEnv("DOUBLE_VAL2", 40.0)); EXPECT_EQ(-1.0, DoubleFromEnv("DOUBLE_VAL3", 40.0)); EXPECT_EQ(40.0, DoubleFromEnv("DOUBLE_VAL_UNKNOWN", 40.0)); setenv("STRING_VAL1", "", 1); setenv("STRING_VAL2", "my happy string!", 1); EXPECT_STREQ("", StringFromEnv("STRING_VAL1", "unknown")); EXPECT_STREQ("my happy string!", StringFromEnv("STRING_VAL2", "unknown")); EXPECT_STREQ("unknown", StringFromEnv("STRING_VAL_UNKNOWN", "unknown")); } // Tests that the FooFromEnv dies on parse-error TEST(FromEnvTest, IllegalValues) { setenv("BOOL_BAD1", "so true!",1 ); setenv("BOOL_BAD2", "", 1); EXPECT_DEATH(BoolFromEnv("BOOL_BAD1", false), "error parsing env variable"); EXPECT_DEATH(BoolFromEnv("BOOL_BAD2", true), "error parsing env variable"); setenv("INT_BAD1", "one", 1); setenv("INT_BAD2", "100000000000000000", 1); setenv("INT_BAD3", "0xx10", 1); setenv("INT_BAD4", "", 1); EXPECT_DEATH(Int32FromEnv("INT_BAD1", 10), "error parsing env variable"); EXPECT_DEATH(Int32FromEnv("INT_BAD2", 10), "error parsing env variable"); EXPECT_DEATH(Int32FromEnv("INT_BAD3", 10), "error parsing env variable"); EXPECT_DEATH(Int32FromEnv("INT_BAD4", 10), "error parsing env variable"); setenv("BIGINT_BAD1", "18446744073709551616000", 1); EXPECT_DEATH(Int64FromEnv("INT_BAD1", 20), "error parsing env variable"); EXPECT_DEATH(Int64FromEnv("INT_BAD3", 20), "error parsing env variable"); EXPECT_DEATH(Int64FromEnv("INT_BAD4", 20), "error parsing env variable"); EXPECT_DEATH(Int64FromEnv("BIGINT_BAD1", 200), "error parsing env variable"); setenv("BIGINT_BAD2", "-1", 1); EXPECT_DEATH(Uint64FromEnv("INT_BAD1", 30), "error parsing env variable"); EXPECT_DEATH(Uint64FromEnv("INT_BAD3", 30), "error parsing env variable"); EXPECT_DEATH(Uint64FromEnv("INT_BAD4", 30), "error parsing env variable"); EXPECT_DEATH(Uint64FromEnv("BIGINT_BAD1", 30), "error parsing env variable"); // TODO(csilvers): uncomment this when we disallow negative numbers for uint64 #if 0 EXPECT_DEATH(Uint64FromEnv("BIGINT_BAD2", 30), "error parsing env variable"); #endif setenv("DOUBLE_BAD1", "0.0.0", 1); setenv("DOUBLE_BAD2", "", 1); EXPECT_DEATH(DoubleFromEnv("DOUBLE_BAD1", 40.0), "error parsing env variable"); EXPECT_DEATH(DoubleFromEnv("DOUBLE_BAD2", 40.0), "error parsing env variable"); } // Tests that FlagSaver can save the states of string flags. TEST(FlagSaverTest, CanSaveStringFlagStates) { // 1. Initializes the flags. // State of flag test_str1: // default value - "initial" // current value - "initial" // not set - true SetCommandLineOptionWithMode("test_str2", "second", SET_FLAGS_VALUE); // State of flag test_str2: // default value - "initial" // current value - "second" // not set - false SetCommandLineOptionWithMode("test_str3", "second", SET_FLAGS_DEFAULT); // State of flag test_str3: // default value - "second" // current value - "second" // not set - true // 2. Saves the flag states. { FlagSaver fs; // 3. Modifies the flag states. SetCommandLineOptionWithMode("test_str1", "second", SET_FLAGS_VALUE); EXPECT_EQ("second", FLAGS_test_str1); // State of flag test_str1: // default value - "second" // current value - "second" // not set - true SetCommandLineOptionWithMode("test_str2", "third", SET_FLAGS_DEFAULT); EXPECT_EQ("second", FLAGS_test_str2); // State of flag test_str2: // default value - "third" // current value - "second" // not set - false SetCommandLineOptionWithMode("test_str3", "third", SET_FLAGS_VALUE); EXPECT_EQ("third", FLAGS_test_str3); // State of flag test_str1: // default value - "second" // current value - "third" // not set - false // 4. Restores the flag states. } // 5. Verifies that the states were restored. // Verifies that the value of test_str1 was restored. EXPECT_EQ("initial", FLAGS_test_str1); // Verifies that the "not set" attribute of test_str1 was restored to true. SetCommandLineOptionWithMode("test_str1", "second", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str1); // Verifies that the value of test_str2 was restored. EXPECT_EQ("second", FLAGS_test_str2); // Verifies that the "not set" attribute of test_str2 was restored to false. SetCommandLineOptionWithMode("test_str2", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("second", FLAGS_test_str2); // Verifies that the value of test_str3 was restored. EXPECT_EQ("second", FLAGS_test_str3); // Verifies that the "not set" attribute of test_str3 was restored to true. SetCommandLineOptionWithMode("test_str3", "fourth", SET_FLAG_IF_DEFAULT); EXPECT_EQ("fourth", FLAGS_test_str3); } // Tests that FlagSaver can save the values of various-typed flags. TEST(FlagSaverTest, CanSaveVariousTypedFlagValues) { // Initializes the flags. FLAGS_test_bool = false; FLAGS_test_int32 = -1; FLAGS_test_int64 = -2; FLAGS_test_uint64 = 3; FLAGS_test_double = 4.0; FLAGS_test_string = "good"; // Saves the flag states. { FlagSaver fs; // Modifies the flags. FLAGS_test_bool = true; FLAGS_test_int32 = -5; FLAGS_test_int64 = -6; FLAGS_test_uint64 = 7; FLAGS_test_double = 8.0; FLAGS_test_string = "bad"; // Restores the flag states. } // Verifies the flag values were restored. EXPECT_FALSE(FLAGS_test_bool); EXPECT_EQ(-1, FLAGS_test_int32); EXPECT_EQ(-2, FLAGS_test_int64); EXPECT_EQ(3, FLAGS_test_uint64); EXPECT_DOUBLE_EQ(4.0, FLAGS_test_double); EXPECT_EQ("good", FLAGS_test_string); } TEST(GetAllFlagsTest, BaseTest) { vector flags; GetAllFlags(&flags); bool found_test_bool = false; vector::const_iterator i; for (i = flags.begin(); i != flags.end(); ++i) { if (i->name == "test_bool") { found_test_bool = true; EXPECT_EQ(i->type, "bool"); EXPECT_EQ(i->default_value, "false"); break; } } EXPECT_EQ(true, found_test_bool); } TEST(ShowUsageWithFlagsTest, BaseTest) { // TODO(csilvers): test this by allowing output other than to stdout. // Not urgent since this functionality is tested via // gflags_unittest.sh, though only through use of --help. } TEST(ShowUsageWithFlagsRestrictTest, BaseTest) { // TODO(csilvers): test this by allowing output other than to stdout. // Not urgent since this functionality is tested via // gflags_unittest.sh, though only through use of --helpmatch. } // Note: all these argv-based tests depend on SetArgv being called // before InitGoogle() in main(), below. TEST(GetArgvsTest, BaseTest) { vector argvs = GetArgvs(); EXPECT_EQ(4, argvs.size()); EXPECT_EQ("/test/argv/for/gflags_unittest", argvs[0]); EXPECT_EQ("argv 2", argvs[1]); EXPECT_EQ("3rd argv", argvs[2]); EXPECT_EQ("argv #4", argvs[3]); } TEST(GetArgvTest, BaseTest) { EXPECT_STREQ("/test/argv/for/gflags_unittest " "argv 2 3rd argv argv #4", GetArgv()); } TEST(GetArgv0Test, BaseTest) { EXPECT_STREQ("/test/argv/for/gflags_unittest", GetArgv0()); } TEST(GetArgvSumTest, BaseTest) { // This number is just the sum of the ASCII values of all the chars // in GetArgv(). EXPECT_EQ(4904, GetArgvSum()); } TEST(ProgramInvocationNameTest, BaseTest) { EXPECT_STREQ("/test/argv/for/gflags_unittest", ProgramInvocationName()); } TEST(ProgramInvocationShortNameTest, BaseTest) { EXPECT_STREQ("gflags_unittest", ProgramInvocationShortName()); } TEST(ProgramUsageTest, BaseTest) { // Depends on 1st arg to InitGoogle in main() EXPECT_STREQ("/test/argv/for/gflags_unittest: " " [...]\nDoes something useless.\n", ProgramUsage()); } TEST(GetCommandLineOptionTest, NameExistsAndIsDefault) { string value("will be changed"); bool r = GetCommandLineOption("test_bool", &value); EXPECT_EQ(true, r); EXPECT_EQ("false", value); r = GetCommandLineOption("test_int32", &value); EXPECT_EQ(true, r); EXPECT_EQ("-1", value); } TEST(GetCommandLineOptionTest, NameExistsAndWasAssigned) { FLAGS_test_int32 = 400; string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_EQ(true, r); EXPECT_EQ("400", value); } TEST(GetCommandLineOptionTest, NameExistsAndWasSet) { SetCommandLineOption("test_int32", "700"); string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_EQ(true, r); EXPECT_EQ("700", value); } TEST(GetCommandLineOptionTest, NameExistsAndWasNotSet) { // This doesn't set the flag's value, but rather its default value. // is_default is still true, but the 'default' value returned has changed! SetCommandLineOptionWithMode("test_int32", "800", SET_FLAGS_DEFAULT); string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_EQ(true, r); EXPECT_EQ("800", value); EXPECT_EQ(true, GetCommandLineFlagInfoOrDie("test_int32").is_default); } TEST(GetCommandLineOptionTest, NameExistsAndWasConditionallySet) { SetCommandLineOptionWithMode("test_int32", "900", SET_FLAG_IF_DEFAULT); string value("will be changed"); const bool r = GetCommandLineOption("test_int32", &value); EXPECT_EQ(true, r); EXPECT_EQ("900", value); } TEST(GetCommandLineOptionTest, NameDoesNotExist) { string value("will not be changed"); const bool r = GetCommandLineOption("test_int3210", &value); EXPECT_EQ(false, r); EXPECT_EQ("will not be changed", value); } TEST(GetCommandLineFlagInfoTest, FlagExists) { CommandLineFlagInfo info; bool r = GetCommandLineFlagInfo("test_int32", &info); EXPECT_EQ(true, r); EXPECT_EQ("test_int32", info.name); EXPECT_EQ("int32", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("-1", info.current_value); EXPECT_EQ("-1", info.default_value); EXPECT_EQ(true, info.is_default); FLAGS_test_bool = true; r = GetCommandLineFlagInfo("test_bool", &info); EXPECT_EQ(true, r); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("true", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_EQ(false, info.is_default); FLAGS_test_bool = false; r = GetCommandLineFlagInfo("test_bool", &info); EXPECT_EQ(true, r); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("false", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_EQ(false, info.is_default); // value is same, but flag *was* modified } TEST(GetCommandLineFlagInfoTest, FlagDoesNotExist) { CommandLineFlagInfo info; // Set to some random values that GetCommandLineFlagInfo should not change info.name = "name"; info.type = "type"; info.current_value = "curr"; info.default_value = "def"; info.filename = "/"; info.is_default = false; bool r = GetCommandLineFlagInfo("test_int3210", &info); EXPECT_EQ(false, r); EXPECT_EQ("name", info.name); EXPECT_EQ("type", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("curr", info.current_value); EXPECT_EQ("def", info.default_value); EXPECT_EQ("/", info.filename); EXPECT_EQ(false, info.is_default); } TEST(GetCommandLineFlagInfoOrDieTest, FlagExistsAndIsDefault) { CommandLineFlagInfo info; info = GetCommandLineFlagInfoOrDie("test_int32"); EXPECT_EQ("test_int32", info.name); EXPECT_EQ("int32", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("-1", info.current_value); EXPECT_EQ("-1", info.default_value); EXPECT_EQ(true, info.is_default); info = GetCommandLineFlagInfoOrDie("test_bool"); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("false", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_EQ(true, info.is_default); } TEST(GetCommandLineFlagInfoOrDieTest, FlagExistsAndWasAssigned) { FLAGS_test_int32 = 400; CommandLineFlagInfo info; info = GetCommandLineFlagInfoOrDie("test_int32"); EXPECT_EQ("test_int32", info.name); EXPECT_EQ("int32", info.type); EXPECT_EQ("", info.description); EXPECT_EQ("400", info.current_value); EXPECT_EQ("-1", info.default_value); EXPECT_EQ(false, info.is_default); FLAGS_test_bool = true; info = GetCommandLineFlagInfoOrDie("test_bool"); EXPECT_EQ("test_bool", info.name); EXPECT_EQ("bool", info.type); EXPECT_EQ("tests bool-ness", info.description); EXPECT_EQ("true", info.current_value); EXPECT_EQ("false", info.default_value); EXPECT_EQ(false, info.is_default); } TEST(GetCommandLineFlagInfoOrDieTest, FlagDoesNotExist) { EXPECT_DEATH(GetCommandLineFlagInfoOrDie("test_int3210"), ".*: flag test_int3210 does not exist"); } // These are lightly tested because they're deprecated. Basically, // the tests are meant to cover how existing users use these functions, // but not necessarily how new users could use them. TEST(DeprecatedFunctionsTest, CommandlineFlagsIntoString) { string s = CommandlineFlagsIntoString(); EXPECT_NE(string::npos, s.find("--test_bool=")); } TEST(DeprecatedFunctionsTest, AppendFlagsIntoFile) { FLAGS_test_int32 = 10; // just to make the test more interesting string filename(FLAGS_test_tmpdir + "/flagfile"); unlink(filename.c_str()); // just to be safe const bool r = AppendFlagsIntoFile(filename, "not the real argv0"); EXPECT_EQ(true, r); FILE* fp = fopen(filename.c_str(), "r"); EXPECT_TRUE(fp != NULL); char line[8192]; fgets(line, sizeof(line)-1, fp); // first line should be progname EXPECT_STREQ("not the real argv0\n", line); bool found_bool = false, found_int32 = false; while (fgets(line, sizeof(line)-1, fp)) { line[sizeof(line)-1] = '\0'; // just to be safe if (strcmp(line, "--test_bool=false\n") == 0) found_bool = true; if (strcmp(line, "--test_int32=10\n") == 0) found_int32 = true; } EXPECT_EQ(true, found_int32); EXPECT_EQ(true, found_bool); fclose(fp); } TEST(DeprecatedFunctionsTest, ReadFromFlagsFile) { FLAGS_test_int32 = -10; // just to make the test more interesting string filename(FLAGS_test_tmpdir + "/flagfile2"); unlink(filename.c_str()); // just to be safe bool r = AppendFlagsIntoFile(filename, GetArgv0()); EXPECT_EQ(true, r); FLAGS_test_int32 = -11; r = ReadFromFlagsFile(filename, GetArgv0(), true); EXPECT_EQ(true, r); EXPECT_EQ(-10, FLAGS_test_int32); } TEST(DeprecatedFunctionsTest, ReadFromFlagsFileFailure) { FLAGS_test_int32 = -20; string filename(FLAGS_test_tmpdir + "/flagfile3"); FILE* fp = fopen(filename.c_str(), "w"); EXPECT_TRUE(fp != NULL); // Note the error in the bool assignment below... fprintf(fp, "%s\n--test_int32=-21\n--test_bool=not_a_bool!\n", GetArgv0()); fclose(fp); FLAGS_test_int32 = -22; const bool r = ReadFromFlagsFile(filename, GetArgv0(), false); EXPECT_EQ(false, r); EXPECT_EQ(-22, FLAGS_test_int32); // the -21 from the flagsfile didn't take } TEST(FlagsSetBeforeInitGoogleTest, TryFromEnv) { EXPECT_EQ("pre-set", FLAGS_test_tryfromenv); } // The following test case verifies that ParseCommandLineFlags() and // ParseCommandLineNonHelpFlags() uses the last definition of a flag // in case it's defined more than once. DEFINE_int32(test_flag, -1, "used for testing commandlineflags.cc"); // Returns the definition of the --flagfile flag to be used in the tests. const char* GetFlagFileFlag() { static const string flagfile_flag = string("--flagfile=") + FLAGS_srcdir + "/src/gflags_unittest_flagfile"; return flagfile_flag.c_str(); } // Parses and returns the --test_flag flag. // If with_help is true, calls ParseCommandLineFlags; otherwise calls // ParseCommandLineNonHelpFlags. int32 ParseTestFlag(bool with_help, int argc, const char** const_argv) { FlagSaver fs; // Restores the flags before returning. // Makes a copy of the input array s.t. it can be reused // (ParseCommandLineFlags() will alter the array). char** const argv_save = new char*[argc + 1]; char** argv = argv_save; memcpy(argv, const_argv, sizeof(*argv)*(argc + 1)); if (with_help) { ParseCommandLineFlags(&argc, &argv, true); } else { ParseCommandLineNonHelpFlags(&argc, &argv, true); } delete[] argv_save; return FLAGS_test_flag; } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedTwiceOnCommandLine) { const char* argv[] = { "my_test", "--test_flag=1", "--test_flag=2", NULL, }; EXPECT_EQ(2, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv)); EXPECT_EQ(2, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedTwiceInFlagFile) { const char* argv[] = { "my_test", GetFlagFileFlag(), NULL, }; EXPECT_EQ(2, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv)); EXPECT_EQ(2, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedInCommandLineAndThenFlagFile) { const char* argv[] = { "my_test", "--test_flag=0", GetFlagFileFlag(), NULL, }; EXPECT_EQ(2, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv)); EXPECT_EQ(2, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedInFlagFileAndThenCommandLine) { const char* argv[] = { "my_test", GetFlagFileFlag(), "--test_flag=3", NULL, }; EXPECT_EQ(3, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv)); EXPECT_EQ(3, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv)); } TEST(ParseCommandLineFlagsUsesLastDefinitionTest, WhenFlagIsDefinedInCommandLineAndFlagFileAndThenCommandLine) { const char* argv[] = { "my_test", "--test_flag=0", GetFlagFileFlag(), "--test_flag=3", NULL, }; EXPECT_EQ(3, ParseTestFlag(true, GET_ARRAY_SIZE(argv) - 1, argv)); EXPECT_EQ(3, ParseTestFlag(false, GET_ARRAY_SIZE(argv) - 1, argv)); } static int Main(int argc, char **argv) { // We need to call SetArgv before InitGoogle, so our "test" argv will // win out over this executable's real argv. That makes running this // test with a real --help flag kinda annoying, unfortunately. const char* test_argv[] = { "/test/argv/for/gflags_unittest", "argv 2", "3rd argv", "argv #4" }; SetArgv(GET_ARRAY_SIZE(test_argv), test_argv); // The first arg is the usage message, also important for testing. string usage_message = (string(GetArgv0()) + ": [...]\nDoes something useless.\n"); // We test setting tryfromenv manually, and making sure initgoogle still // evaluates it. FLAGS_tryfromenv = "test_tryfromenv"; setenv("FLAGS_test_tryfromenv", "pre-set", 1); SetUsageMessage(usage_message.c_str()); ParseCommandLineFlags(&argc, &argv, true); mkdir(FLAGS_test_tmpdir.c_str(), 0755); return RUN_ALL_TESTS(); } _END_GOOGLE_NAMESPACE_ int main(int argc, char** argv) { return GOOGLE_NAMESPACE::Main(argc, argv); }