diff options
author | Abseil Team <absl-team@google.com> | 2019-08-08 10:56:58 -0700 |
---|---|---|
committer | CJ Johnson <johnsoncj@google.com> | 2019-08-08 14:19:45 -0400 |
commit | aa844899c937bde5d2b24f276b59997e5b668bde (patch) | |
tree | cd18e64150abc74b85bbbf6abf990f66fa47cacd /absl/flags/parse_test.cc | |
parent | fcb104594b0bb4b8ac306cb2f55ecdad40974683 (diff) | |
download | abseil-aa844899c937bde5d2b24f276b59997e5b668bde.tar.gz abseil-aa844899c937bde5d2b24f276b59997e5b668bde.tar.bz2 abseil-aa844899c937bde5d2b24f276b59997e5b668bde.zip |
Creation of LTS branch "lts_2019_08_08"
- 9ee91d3e430fb33a4590486573792eb0fa146c2d Export of internal Abseil changes by Abseil Team <absl-team@google.com>
- 8efba58a3b656e9b41fb0471ae6453425a61c520 Export of internal Abseil changes by Abseil Team <absl-team@google.com>
- b49b8d16b67ec6912899684b732e6367f258cfdb Export of internal Abseil changes by Abseil Team <absl-team@google.com>
- 67222ffc4c83d918ce8395aa61769eeb77df4c4d Export of internal Abseil changes by Abseil Team <absl-team@google.com>
- c5c4db4f5191fe5e76cbf68dcc71fb28702f7d2b Export of internal Abseil changes by Abseil Team <absl-team@google.com>
- 14550beb3b7b97195e483fb74b5efb906395c31e Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 52e88ee56b72cf32bc66534d942c7398ce481331 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 36d37ab992038f52276ca66b9da80c1cf0f57dc2 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- ad1485c8986246b2ae9105e512738d0e97aec887 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- f3840bc5e33ce4932e35986cf3718450c6f02af2 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 278b26058c036833a4f7f3047d3f4d9296527f87 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- c6c3c1b498e4ee939b24be59cae29d59c3863be8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 44efe96dfca674a17b45ca53fc77fb69f1e29bf4 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 3c98fcc0461bd2a4b9c149d4748a7373a225cf4b Merge pull request #340 from jtsylve/macos_cxx17_fix by Matt Calabrese <38107210+mattcalabrese-google@users.noreply.github.com>
- 74d91756c11bc22f9b0108b94da9326f7f9e376f Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- e6b050212c859fbaf67abac76105da10ec348274 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- c964fcffac27bd4a9ff67fe393410dd1146ef8b8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 72e09a54d993b192db32be14c65adf7e9bd08c31 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- d65e19dfcd8697076f68598c0131c6930cdcd74d Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 5162fc83d2f3b79a9753ed59594c43966afdd37a Merge pull request #336 from shields/patch-2 by Shaindel Schwartz <31392632+shaindelschwartz@users.noreply.github.com>
- 0389f7bf58fa41f35b3ad60be61d32f31e4f8ed6 Merge pull request #335 from shields/patch-1 by Shaindel Schwartz <31392632+shaindelschwartz@users.noreply.github.com>
- e9324d926a9189e222741fce6e676f0944661a72 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 43ef2148c0936ebf7cb4be6b19927a9d9d145b8f Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- a13d3df2b3ba68aeead92e2d078fba0510d55024 Merge pull request #323 from gosnik/master by Gennadiy Rozental <rogeeff@google.com>
- 310a11865c97c5cdcc42a4ee2c2e3578423afe69 Merge pull request #324 from RasPat1/patch-1 by Gennadiy Rozental <rogeeff@google.com>
- 8f11724067248acc330b4d1f12f0c76d03f2cfb1 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- b1dd425423380126f6441ce4fbb6f8f6c75b793a Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 361cb8a9db2f2130442389fd80593255be26d681 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 0238ab0a831f179518c1a814f9584e99da2d75a3 Merge pull request #321 from christoph-cullmann/c4245_fix... by Xiaoyi Zhang <zhangxy988@gmail.com>
- 61c9bf3e3e1c28a4aa6d7f1be4b37fd473bb5529 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- bc9101f9982391019521161a36179b52555ed212 Merge pull request #320 from christoph-cullmann/master by Xiaoyi Zhang <zhangxy988@gmail.com>
- 2f76a9bf50046e396138cc8eeb3cdc17b7a5ac24 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 4adaf5490921f13028b55018c9f550277de5aebb Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 27c30ec671cb7b5ba84c4e79feff7fd0b0ac6338 Avoid undefined behavior when nullptr is passed to memcpy... by Roman Gershman <romange@gmail.com>
- ce65f5ac3cbf897bb5e3de1a51d80fd00866abaa Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- a18fc7461e7409c2ad64e28537261db1e02e76fa Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 8a394b19c149cab50534b04c5e21d42bc2217a7d Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- daf381e8535a1f1f1b8a75966a74e7cca63dee89 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- fa00c321073c7ea40a4fc3dfc8a06309eae3d025 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 436ba6c4a0ea3a06eca6e055f9c8d296bf3bae12 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 0cbdc774b97f7e80ab60dbe2ed4eaca3b2e33fc8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 27c2f6e2f3b5929fbd322b0f0ca392eb02efd9f8 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- aa468ad75539619b47979911297efbb629c52e44 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- cd86d0d20ab167c33b23d3875db68d1d4bad3a3b Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 33841c5c963aa9c3f096ef8e6c1e71624b941940 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- ca3f87560a0eef716195cadf66dc6b938a579ec6 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- d902eb869bcfacc1bad14933ed9af4bed006d481 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- a02f62f456f2c4a7ecf2be3104fe0c6e16fbad9a Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 0b545b460141b882b244a1efcef7621d59278160 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- dbae8764fbd429bf7d7745e24bcf73962177a7c0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 044da8a29c923506af0f0b46bc46f43c1e1300b5 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 6cc6ac44e065b9e8975fadfd6ccb99cbcf89aac4 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 666fc1266bccfd8e6eaaa084e7b42580bb8eb199 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 93dfcf74cb5fccae3da07897d8613ae6cab958a0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 2c8421e1c6cef0da9e8a20b01c15256ec9ec116d Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 5b65c4af5107176555b23a638e5947686410ac1f Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- eab2078b53c9e3d9d240135c09d27e3393acb50a Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 253eb7416421661873afbaa33828a850db978541 [CMake] Set correct flags for clang-cl (#278) by Loo Rong Jie <loorongjie@gmail.com>
- e75672f6afc7e8f23ee7b532e86d1b3b9be3984e Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- bf29470384a101b307873b26d358433138c857fc Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 6fd827124facd8336981e73218997f9e73029b4f Merge pull request #280 from chiumichael/master by Derek Mauro <761129+derekmauro@users.noreply.github.com>
- 7c7754fb3ed9ffb57d35fe8658f3ba4d73a31e72 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 256be563447a315f2a7993ec669460ba475fa86a Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 88a152ae747c3c42dc9167d46c590929b048d436 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- c1cecb25a94c075725e9d2640f6b978a8f61957b Implement Span::first and Span::last from C++20 (#274) by Girts <girtsf@users.noreply.github.com>
- 38b704384cd2f17590b3922b97744be0b43622c9 Changed HTTP URLs to HTTPS where possible (#270) by nik7273 <nik8470@gmail.com>
- febc5ee6a92d0eb7dac1fceaa6c648cf6521b4dc Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 9fdf5e5b805412cb2a2e624d3e9a11588120465f Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 419f3184f8ebcdb23105295eadd2a569f3351eb9 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- b312c3cb53a0aad75a85ac2bf57c4a614fbd48d4 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 308ce31528a7edfa39f5f6d36142278a0ae1bf45 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 93d155bc4414f6c121bb1f19dba9fdb27c8943bc Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 426eaa4aa44e4580418bee46c1bd13911151bfb1 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 2901ec32a919311384d6ad4194e2d927c06831f7 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- d78310fe5a82f2e0e6e16509ef8079c8d7e4674e Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- a4cb1c8ba61531a63f9d309eea01ac1d43d8371d Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 540e2537b92cd4abfae6ceddfe24304345461f32 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 89ea0c5ff34aaa5855cfc7aa41f323b8a0ef0ede Merge pull request #255 from uilianries/hotfix/conan by ahedberg <ahedberg@google.com>
- 5e0dcf72c64fae912184d2e0de87195fe8f0a425 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 0dffca4e36791c7beeda04da10460b534283948a Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 6b4201f9ef650637510a21b8d6cbcc3bee4a606f Fix GCC8 warnings by Boris Staletic <boris.staletic@gmail.com>
- 0b1e6d417b414aad9282e32e8c49c719edeb63c1 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- efccc502606bed768e50a6cd5806d8eb13e4e935 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 5e6a78131f7bd5940218462c07d88cdefdd75dbe Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 5eea0f713c14ac17788b83e496f11903f8e2bbb0 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 66f9becbb98ecc083f4db349b4b1e0ca9de93b15 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 018b4db1d73ec8238e6dc4b17fd9e1fd7468d0ed Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 9449ae94397f2fd683851348e25ed8c93f75b3b9 Merge pull request #243 from ThomsonTan/FixIntrinsic by Alex Strelnikov <strel@google.com>
- b16aeb6756bdab08cdf12d40baab5b51f7d15b16 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 7ffbe09f3d85504bd018783bbe1e2c12992fe47c Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 01b471d9f3ebef27f5aaca14b66509099fa8cd6c Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 7bd8f36c741c7cbe311611d7981bf38ba04c6fef Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 968a34ffdaadd7db062a9621dfbdf8b2d16e05af Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 3e2e9b5557e76d098de4b8a2a659125b98ca519b Merge pull request #231 from uilianries/feature/conan by Mark Barolak <mbxx@users.noreply.github.com>
- 111ca7060a6ff50115ca85b59f6b5d8c8c5e9105 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 389ec3f906f018661a5308458d623d01f96d7b23 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 8fbcdb90952c57828c4a9c2f6d79fcd7cae9088f Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 455dc17ba1af9635f0b60155bc565bc572a1e722 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- f197d7c72a54064cfde5a2058f1513a4a0ee36fb Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
- 284378a71b32dfb3af4e3661f585e671d1b603a3 Export of internal Abseil changes. by Abseil Team <absl-team@google.com>
GitOrigin-RevId: 9ee91d3e430fb33a4590486573792eb0fa146c2d
Change-Id: Ia06e548bc106cc9d136f6c65714be6645317aced
Diffstat (limited to 'absl/flags/parse_test.cc')
-rw-r--r-- | absl/flags/parse_test.cc | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc new file mode 100644 index 00000000..447a3bc7 --- /dev/null +++ b/absl/flags/parse_test.cc @@ -0,0 +1,858 @@ +// +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/flags/parse.h" + +#include <fstream> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/base/internal/scoped_set_env.h" +#include "absl/flags/flag.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/substitute.h" +#include "absl/types/span.h" + +#ifdef _WIN32 +#include <windows.h> +#endif + +namespace { + +using absl::base_internal::ScopedSetEnv; + +struct UDT { + UDT() = default; + UDT(const UDT&) = default; + UDT(int v) : value(v) {} // NOLINT + + int value; +}; + +bool AbslParseFlag(absl::string_view in, UDT* udt, std::string* err) { + if (in == "A") { + udt->value = 1; + return true; + } + if (in == "AAA") { + udt->value = 10; + return true; + } + + *err = "Use values A, AAA instead"; + return false; +} +std::string AbslUnparseFlag(const UDT& udt) { + return udt.value == 1 ? "A" : "AAA"; +} + +std::string GetTestTmpDirEnvVar(const char* const env_var_name) { +#ifdef _WIN32 + char buf[MAX_PATH]; + auto get_res = GetEnvironmentVariableA(env_var_name, buf, sizeof(buf)); + if (get_res >= sizeof(buf) || get_res == 0) { + return ""; + } + + return std::string(buf, get_res); +#else + const char* val = ::getenv(env_var_name); + if (val == nullptr) { + return ""; + } + + return val; +#endif +} + +const std::string& GetTestTempDir() { + static std::string* temp_dir_name = []() -> std::string* { + std::string* res = new std::string(GetTestTmpDirEnvVar("TEST_TMPDIR")); + + if (res->empty()) { + *res = GetTestTmpDirEnvVar("TMPDIR"); + } + + if (res->empty()) { +#ifdef _WIN32 + char temp_path_buffer[MAX_PATH]; + + auto len = GetTempPathA(MAX_PATH, temp_path_buffer); + if (len < MAX_PATH && len != 0) { + std::string temp_dir_name = absl::StrCat( + temp_path_buffer, "\\parse_test.", GetCurrentProcessId()); + if (CreateDirectoryA(temp_dir_name.c_str(), nullptr)) { + *res = temp_dir_name; + } + } +#else + char temp_dir_template[] = "/tmp/parse_test.XXXXXX"; + if (auto* unique_name = ::mkdtemp(temp_dir_template)) { + *res = unique_name; + } +#endif + + if (res->empty()) { + ABSL_INTERNAL_LOG(FATAL, + "Failed to make temporary directory for data files"); + } + } + +#ifdef _WIN32 + *res += "\\"; +#else + *res += "/"; +#endif + + return res; + }(); + + return *temp_dir_name; +} + +struct FlagfileData { + const absl::string_view file_name; + const absl::Span<const char* const> file_lines; +}; + +// clang-format off +constexpr const char* const ff1_data[] = { + "# comment ", + " # comment ", + "", + " ", + "--int_flag=-1", + " --string_flag=q2w2 ", + " ## ", + " --double_flag=0.1", + "--bool_flag=Y " +}; + +constexpr const char* const ff2_data[] = { + "# Setting legacy flag", + "--legacy_int=1111", + "--legacy_bool", + "--nobool_flag", + "--legacy_str=aqsw", + "--int_flag=100", + " ## =============" +}; +// clang-format on + +// Builds flagfile flag in the flagfile_flag buffer and returns it. This +// function also creates a temporary flagfile based on FlagfileData input. +// We create a flagfile in a temporary directory with the name specified in +// FlagfileData and populate it with lines specifed in FlagfileData. If $0 is +// referenced in any of the lines in FlagfileData they are replaced with +// temporary directory location. This way we can test inclusion of one flagfile +// from another flagfile. +const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd, + std::string* flagfile_flag) { + *flagfile_flag = "--flagfile="; + absl::string_view separator; + for (const auto& flagfile_data : ffd) { + std::string flagfile_name = + absl::StrCat(GetTestTempDir(), flagfile_data.file_name); + + std::ofstream flagfile_out(flagfile_name); + for (auto line : flagfile_data.file_lines) { + flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n"; + } + + absl::StrAppend(flagfile_flag, separator, flagfile_name); + separator = ","; + } + + return flagfile_flag->c_str(); +} + +} // namespace + +ABSL_FLAG(int, int_flag, 1, ""); +ABSL_FLAG(double, double_flag, 1.1, ""); +ABSL_FLAG(std::string, string_flag, "a", ""); +ABSL_FLAG(bool, bool_flag, false, ""); +ABSL_FLAG(UDT, udt_flag, -1, ""); +ABSL_RETIRED_FLAG(int, legacy_int, 1, ""); +ABSL_RETIRED_FLAG(bool, legacy_bool, false, ""); +ABSL_RETIRED_FLAG(std::string, legacy_str, "l", ""); + +namespace { + +namespace flags = absl::flags_internal; +using testing::ElementsAreArray; + +class ParseTest : public testing::Test { + private: + flags::FlagSaver flag_saver_; +}; + +// -------------------------------------------------------------------- + +template <int N> +std::vector<char*> InvokeParse(const char* (&in_argv)[N]) { + return absl::ParseCommandLine(N, const_cast<char**>(in_argv)); +} + +// -------------------------------------------------------------------- + +template <int N> +void TestParse(const char* (&in_argv)[N], int int_flag_value, + double double_flag_val, absl::string_view string_flag_val, + bool bool_flag_val, int exp_position_args = 0) { + auto out_args = InvokeParse(in_argv); + + EXPECT_EQ(out_args.size(), 1 + exp_position_args); + EXPECT_STREQ(out_args[0], "testbin"); + + EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), int_flag_value); + EXPECT_NEAR(absl::GetFlag(FLAGS_double_flag), double_flag_val, 0.0001); + EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), string_flag_val); + EXPECT_EQ(absl::GetFlag(FLAGS_bool_flag), bool_flag_val); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestEmptyArgv) { + const char* in_argv[] = {"testbin"}; + + auto out_args = InvokeParse(in_argv); + + EXPECT_EQ(out_args.size(), 1); + EXPECT_STREQ(out_args[0], "testbin"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestValidIntArg) { + const char* in_args1[] = { + "testbin", + "--int_flag=10", + }; + TestParse(in_args1, 10, 1.1, "a", false); + + const char* in_args2[] = { + "testbin", + "-int_flag=020", + }; + TestParse(in_args2, 20, 1.1, "a", false); + + const char* in_args3[] = { + "testbin", + "--int_flag", + "-30", + }; + TestParse(in_args3, -30, 1.1, "a", false); + + const char* in_args4[] = { + "testbin", + "-int_flag", + "0x21", + }; + TestParse(in_args4, 33, 1.1, "a", false); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestValidDoubleArg) { + const char* in_args1[] = { + "testbin", + "--double_flag=2.3", + }; + TestParse(in_args1, 1, 2.3, "a", false); + + const char* in_args2[] = { + "testbin", + "--double_flag=0x1.2", + }; + TestParse(in_args2, 1, 1.125, "a", false); + + const char* in_args3[] = { + "testbin", + "--double_flag", + "99.7", + }; + TestParse(in_args3, 1, 99.7, "a", false); + + const char* in_args4[] = { + "testbin", + "--double_flag", + "0x20.1", + }; + TestParse(in_args4, 1, 32.0625, "a", false); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestValidStringArg) { + const char* in_args1[] = { + "testbin", + "--string_flag=aqswde", + }; + TestParse(in_args1, 1, 1.1, "aqswde", false); + + const char* in_args2[] = { + "testbin", + "-string_flag=a=b=c", + }; + TestParse(in_args2, 1, 1.1, "a=b=c", false); + + const char* in_args3[] = { + "testbin", + "--string_flag", + "zaxscd", + }; + TestParse(in_args3, 1, 1.1, "zaxscd", false); + + const char* in_args4[] = { + "testbin", + "-string_flag", + "--int_flag", + }; + TestParse(in_args4, 1, 1.1, "--int_flag", false); + + const char* in_args5[] = { + "testbin", + "--string_flag", + "--no_a_flag=11", + }; + TestParse(in_args5, 1, 1.1, "--no_a_flag=11", false); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestValidBoolArg) { + const char* in_args1[] = { + "testbin", + "--bool_flag", + }; + TestParse(in_args1, 1, 1.1, "a", true); + + const char* in_args2[] = { + "testbin", + "--nobool_flag", + }; + TestParse(in_args2, 1, 1.1, "a", false); + + const char* in_args3[] = { + "testbin", + "--bool_flag=true", + }; + TestParse(in_args3, 1, 1.1, "a", true); + + const char* in_args4[] = { + "testbin", + "-bool_flag=false", + }; + TestParse(in_args4, 1, 1.1, "a", false); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestValidUDTArg) { + const char* in_args1[] = { + "testbin", + "--udt_flag=A", + }; + InvokeParse(in_args1); + + EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 1); + + const char* in_args2[] = {"testbin", "--udt_flag", "AAA"}; + InvokeParse(in_args2); + + EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 10); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestValidMultipleArg) { + const char* in_args1[] = { + "testbin", "--bool_flag", "--int_flag=2", + "--double_flag=0.1", "--string_flag=asd", + }; + TestParse(in_args1, 2, 0.1, "asd", true); + + const char* in_args2[] = { + "testbin", "--string_flag=", "--nobool_flag", "--int_flag", + "-011", "--double_flag", "-1e-2", + }; + TestParse(in_args2, -11, -0.01, "", false); + + const char* in_args3[] = { + "testbin", "--int_flag", "-0", "--string_flag", "\"\"", + "--bool_flag=true", "--double_flag=1e18", + }; + TestParse(in_args3, 0, 1e18, "\"\"", true); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestPositionalArgs) { + const char* in_args1[] = { + "testbin", + "p1", + "p2", + }; + TestParse(in_args1, 1, 1.1, "a", false, 2); + + auto out_args1 = InvokeParse(in_args1); + + EXPECT_STREQ(out_args1[1], "p1"); + EXPECT_STREQ(out_args1[2], "p2"); + + const char* in_args2[] = { + "testbin", + "--int_flag=2", + "p1", + }; + TestParse(in_args2, 2, 1.1, "a", false, 1); + + auto out_args2 = InvokeParse(in_args2); + + EXPECT_STREQ(out_args2[1], "p1"); + + const char* in_args3[] = {"testbin", "p1", "--int_flag=3", + "p2", "--bool_flag", "true"}; + TestParse(in_args3, 3, 1.1, "a", true, 3); + + auto out_args3 = InvokeParse(in_args3); + + EXPECT_STREQ(out_args3[1], "p1"); + EXPECT_STREQ(out_args3[2], "p2"); + EXPECT_STREQ(out_args3[3], "true"); + + const char* in_args4[] = { + "testbin", + "--", + "p1", + "p2", + }; + TestParse(in_args4, 3, 1.1, "a", true, 2); + + auto out_args4 = InvokeParse(in_args4); + + EXPECT_STREQ(out_args4[1], "p1"); + EXPECT_STREQ(out_args4[2], "p2"); + + const char* in_args5[] = { + "testbin", "p1", "--int_flag=4", "--", "--bool_flag", "false", "p2", + }; + TestParse(in_args5, 4, 1.1, "a", true, 4); + + auto out_args5 = InvokeParse(in_args5); + + EXPECT_STREQ(out_args5[1], "p1"); + EXPECT_STREQ(out_args5[2], "--bool_flag"); + EXPECT_STREQ(out_args5[3], "false"); + EXPECT_STREQ(out_args5[4], "p2"); +} + +// -------------------------------------------------------------------- + +using ParseDeathTest = ParseTest; + +TEST_F(ParseDeathTest, TestUndefinedArg) { + const char* in_args1[] = { + "testbin", + "--undefined_flag", + }; + EXPECT_DEATH(InvokeParse(in_args1), + "Unknown command line flag 'undefined_flag'"); + + const char* in_args2[] = { + "testbin", + "--noprefixed_flag", + }; + EXPECT_DEATH(InvokeParse(in_args2), + "Unknown command line flag 'noprefixed_flag'"); + + const char* in_args3[] = { + "testbin", + "--Int_flag=1", + }; + EXPECT_DEATH(InvokeParse(in_args3), "Unknown command line flag 'Int_flag'"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) { + const char* in_args1[] = { + "testbin", + "--bool_flag=", + }; + EXPECT_DEATH( + InvokeParse(in_args1), + "Missing the value after assignment for the boolean flag 'bool_flag'"); + + const char* in_args2[] = { + "testbin", + "--nobool_flag=true", + }; + EXPECT_DEATH(InvokeParse(in_args2), + "Negative form with assignment is not valid for the boolean " + "flag 'bool_flag'"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestInvalidNonBoolFlagFormat) { + const char* in_args1[] = { + "testbin", + "--nostring_flag", + }; + EXPECT_DEATH(InvokeParse(in_args1), + "Negative form is not valid for the flag 'string_flag'"); + + const char* in_args2[] = { + "testbin", + "--int_flag", + }; + EXPECT_DEATH(InvokeParse(in_args2), + "Missing the value for the flag 'int_flag'"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) { + const char* in_args1[] = { + "testbin", + "--udt_flag=1", + }; + EXPECT_DEATH(InvokeParse(in_args1), + "Illegal value '1' specified for flag 'udt_flag'; Use values A, " + "AAA instead"); + + const char* in_args2[] = { + "testbin", + "--udt_flag", + "AA", + }; + EXPECT_DEATH(InvokeParse(in_args2), + "Illegal value 'AA' specified for flag 'udt_flag'; Use values " + "A, AAA instead"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestLegacyFlags) { + const char* in_args1[] = { + "testbin", + "--legacy_int=11", + }; + TestParse(in_args1, 1, 1.1, "a", false); + + const char* in_args2[] = { + "testbin", + "--legacy_bool", + }; + TestParse(in_args2, 1, 1.1, "a", false); + + const char* in_args3[] = { + "testbin", "--legacy_int", "22", "--int_flag=2", + "--legacy_bool", "true", "--legacy_str", "--string_flag=qwe", + }; + TestParse(in_args3, 2, 1.1, "a", false, 1); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestSimpleValidFlagfile) { + std::string flagfile_flag; + + const char* in_args1[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, + &flagfile_flag), + }; + TestParse(in_args1, -1, 0.1, "q2w2 ", true); + + const char* in_args2[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}}, + &flagfile_flag), + }; + TestParse(in_args2, 100, 0.1, "q2w2 ", false); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestValidMultiFlagfile) { + std::string flagfile_flag; + + const char* in_args1[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}, + {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, + &flagfile_flag), + }; + TestParse(in_args1, -1, 0.1, "q2w2 ", true); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestFlagfileMixedWithRegularFlags) { + std::string flagfile_flag; + + const char* in_args1[] = { + "testbin", "--int_flag=3", + GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, + &flagfile_flag), + "-double_flag=0.2"}; + TestParse(in_args1, -1, 0.2, "q2w2 ", true); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestFlagfileInFlagfile) { + std::string flagfile_flag; + + constexpr const char* const ff3_data[] = { + "--flagfile=$0/parse_test.ff1", + "--flagfile=$0/parse_test.ff2", + }; + + const char* in_args1[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}}, + &flagfile_flag), + }; + TestParse(in_args1, 100, 0.1, "q2w2 ", false); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestInvalidFlagfiles) { + std::string flagfile_flag; + + constexpr const char* const ff4_data[] = { + "--unknown_flag=10" + }; + + const char* in_args1[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff4", + absl::MakeConstSpan(ff4_data)}}, &flagfile_flag), + }; + EXPECT_DEATH(InvokeParse(in_args1), + "Unknown command line flag 'unknown_flag'"); + + constexpr const char* const ff5_data[] = { + "--int_flag 10", + }; + + const char* in_args2[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff5", + absl::MakeConstSpan(ff5_data)}}, &flagfile_flag), + }; + EXPECT_DEATH(InvokeParse(in_args2), + "Unknown command line flag 'int_flag 10'"); + + constexpr const char* const ff6_data[] = { + "--int_flag=10", "--", "arg1", "arg2", "arg3", + }; + + const char* in_args3[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}}, + &flagfile_flag), + }; + EXPECT_DEATH(InvokeParse(in_args3), + "Flagfile can't contain position arguments or --"); + + const char* in_args4[] = { + "testbin", + "--flagfile=invalid_flag_file", + }; + EXPECT_DEATH(InvokeParse(in_args4), "Can't open flagfile invalid_flag_file"); + + constexpr const char* const ff7_data[] = { + "--int_flag=10", + "*bin*", + "--str_flag=aqsw", + }; + + const char* in_args5[] = { + "testbin", + GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}}, + &flagfile_flag), + }; + EXPECT_DEATH(InvokeParse(in_args5), + "Unexpected line in the flagfile .*: \\*bin\\*"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestReadingRequiredFlagsFromEnv) { + const char* in_args1[] = {"testbin", + "--fromenv=int_flag,bool_flag,string_flag"}; + + ScopedSetEnv set_int_flag("FLAGS_int_flag", "33"); + ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "True"); + ScopedSetEnv set_string_flag("FLAGS_string_flag", "AQ12"); + + TestParse(in_args1, 33, 1.1, "AQ12", true); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) { + const char* in_args1[] = {"testbin", "--fromenv=int_flag"}; + + EXPECT_DEATH(InvokeParse(in_args1), + "FLAGS_int_flag not found in environment"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestRecursiveFlagsFromEnv) { + const char* in_args1[] = {"testbin", "--fromenv=tryfromenv"}; + + ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag"); + + EXPECT_DEATH(InvokeParse(in_args1), "Infinite recursion on flag tryfromenv"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestReadingOptionalFlagsFromEnv) { + const char* in_args1[] = { + "testbin", "--tryfromenv=int_flag,bool_flag,string_flag,other_flag"}; + + ScopedSetEnv set_int_flag("FLAGS_int_flag", "17"); + ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "Y"); + + TestParse(in_args1, 17, 1.1, "a", true); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestReadingFlagsFromEnvMoxedWithRegularFlags) { + const char* in_args1[] = { + "testbin", + "--bool_flag=T", + "--tryfromenv=int_flag,bool_flag", + "--int_flag=-21", + }; + + ScopedSetEnv set_int_flag("FLAGS_int_flag", "-15"); + ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "F"); + + TestParse(in_args1, -21, 1.1, "a", false); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestKeepParsedArgs) { + const char* in_args1[] = { + "testbin", "arg1", "--bool_flag", + "--int_flag=211", "arg2", "--double_flag=1.1", + "--string_flag", "asd", "--", + "arg3", "arg4", + }; + + auto out_args1 = InvokeParse(in_args1); + + EXPECT_THAT( + out_args1, + ElementsAreArray({absl::string_view("testbin"), absl::string_view("arg1"), + absl::string_view("arg2"), absl::string_view("arg3"), + absl::string_view("arg4")})); + + auto out_args2 = flags::ParseCommandLineImpl( + 11, const_cast<char**>(in_args1), flags::ArgvListAction::kKeepParsedArgs, + flags::UsageFlagsAction::kHandleUsage, + flags::OnUndefinedFlag::kAbortIfUndefined); + + EXPECT_THAT( + out_args2, + ElementsAreArray({absl::string_view("testbin"), + absl::string_view("--bool_flag"), + absl::string_view("--int_flag=211"), + absl::string_view("--double_flag=1.1"), + absl::string_view("--string_flag"), + absl::string_view("asd"), absl::string_view("--"), + absl::string_view("arg1"), absl::string_view("arg2"), + absl::string_view("arg3"), absl::string_view("arg4")})); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestIgnoreUndefinedFlags) { + const char* in_args1[] = { + "testbin", + "arg1", + "--undef_flag=aa", + "--int_flag=21", + }; + + auto out_args1 = flags::ParseCommandLineImpl( + 4, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs, + flags::UsageFlagsAction::kHandleUsage, + flags::OnUndefinedFlag::kIgnoreUndefined); + + EXPECT_THAT(out_args1, ElementsAreArray({absl::string_view("testbin"), + absl::string_view("arg1")})); + + EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 21); + + const char* in_args2[] = { + "testbin", + "arg1", + "--undef_flag=aa", + "--string_flag=AA", + }; + + auto out_args2 = flags::ParseCommandLineImpl( + 4, const_cast<char**>(in_args2), flags::ArgvListAction::kKeepParsedArgs, + flags::UsageFlagsAction::kHandleUsage, + flags::OnUndefinedFlag::kIgnoreUndefined); + + EXPECT_THAT( + out_args2, + ElementsAreArray( + {absl::string_view("testbin"), absl::string_view("--undef_flag=aa"), + absl::string_view("--string_flag=AA"), absl::string_view("arg1")})); + + EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "AA"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, TestHelpFlagHandling) { + const char* in_args1[] = { + "testbin", + "--help", + }; + + EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1), ""); + + const char* in_args2[] = { + "testbin", + "--help", + "--int_flag=3", + }; + + auto out_args2 = flags::ParseCommandLineImpl( + 3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs, + flags::UsageFlagsAction::kIgnoreUsage, + flags::OnUndefinedFlag::kAbortIfUndefined); + + EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3); +} + +} // namespace |