From 5490902dfc04ec39234742632a6a85fcecdfc74b Mon Sep 17 00:00:00 2001 From: Alexandre Lissy Date: Thu, 21 Oct 2021 14:18:06 +0000 Subject: [PATCH] Bug 1723505 - Introduce GeckoArgs r=nika Differential Revision: https://phabricator.services.mozilla.com/D120241 --- toolkit/xre/GeckoArgs.h | 128 +++++++++++++++++ toolkit/xre/moz.build | 1 + toolkit/xre/test/gtest/TestGeckoArgs.cpp | 176 +++++++++++++++++++++++ toolkit/xre/test/gtest/moz.build | 1 + 4 files changed, 306 insertions(+) create mode 100644 toolkit/xre/GeckoArgs.h create mode 100644 toolkit/xre/test/gtest/TestGeckoArgs.cpp diff --git a/toolkit/xre/GeckoArgs.h b/toolkit/xre/GeckoArgs.h new file mode 100644 index 000000000000..72cc03455bef --- /dev/null +++ b/toolkit/xre/GeckoArgs.h @@ -0,0 +1,128 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_GeckoArgs_h +#define mozilla_GeckoArgs_h + +#include "mozilla/CmdLineAndEnvUtils.h" +#include "mozilla/Maybe.h" + +#include +#include +#include +#include +#include + +namespace mozilla { + +namespace geckoargs { + +template +struct CommandLineArg { + Maybe Get(int& aArgc, char** aArgv, + const CheckArgFlag aFlags = CheckArgFlag::RemoveArg); + + const char* Name() { return sName; }; + + void Put(std::vector& aArgs); + void Put(T aValue, std::vector& aArgs); + + const char* sName; + const char* sMatch; +}; + +/// Get() + +template <> +inline Maybe CommandLineArg::Get( + int& aArgc, char** aArgv, const CheckArgFlag aFlags) { + MOZ_ASSERT(aArgv, "aArgv must be initialized before CheckArg()"); + const char* rv = nullptr; + if (ARG_FOUND == CheckArg(aArgc, aArgv, sMatch, &rv, aFlags)) { + return Some(rv); + } + return Nothing(); +} + +template <> +inline Maybe CommandLineArg::Get(int& aArgc, char** aArgv, + const CheckArgFlag aFlags) { + MOZ_ASSERT(aArgv, "aArgv must be initialized before CheckArg()"); + if (ARG_FOUND == + CheckArg(aArgc, aArgv, sMatch, (const char**)nullptr, aFlags)) { + return Some(true); + } + return Nothing(); +} + +template <> +inline Maybe CommandLineArg::Get( + int& aArgc, char** aArgv, const CheckArgFlag aFlags) { + MOZ_ASSERT(aArgv, "aArgv must be initialized before CheckArg()"); + const char* rv = nullptr; + if (ARG_FOUND == CheckArg(aArgc, aArgv, sMatch, &rv, aFlags)) { + errno = 0; + char* endptr = nullptr; + uint64_t conv = std::strtoull(rv, &endptr, 10); + if (errno == 0 && endptr && *endptr == '\0') { + return Some(conv); + } + } + return Nothing(); +} + +/// Put() + +template <> +inline void CommandLineArg::Put(const char* aValue, + std::vector& aArgs) { + aArgs.push_back(Name()); + aArgs.push_back(aValue); +} + +template <> +inline void CommandLineArg::Put(bool aValue, + std::vector& aArgs) { + if (aValue) { + aArgs.push_back(Name()); + } +} + +template <> +inline void CommandLineArg::Put(std::vector& aArgs) { + Put(true, aArgs); +} + +template <> +inline void CommandLineArg::Put(uint64_t aValue, + std::vector& aArgs) { + aArgs.push_back(Name()); + aArgs.push_back(std::to_string(aValue)); +} + +static CommandLineArg sParentBuildID{"-parentBuildID", + "parentbuildid"}; +static CommandLineArg sAppDir{"-appDir", "appdir"}; +static CommandLineArg sProfile{"-profile", "profile"}; + +static CommandLineArg sJsInitHandle{"-jsInitHandle", "jsinithandle"}; +static CommandLineArg sJsInitLen{"-jsInitLen", "jsinitlen"}; +static CommandLineArg sPrefsHandle{"-prefsHandle", "prefshandle"}; +static CommandLineArg sPrefsLen{"-prefsLen", "prefslen"}; +static CommandLineArg sPrefMapHandle{"-prefMapHandle", + "prefmaphandle"}; +static CommandLineArg sPrefMapSize{"-prefMapSize", "prefmapsize"}; + +static CommandLineArg sChildID{"-childID", "childid"}; + +static CommandLineArg sSafeMode{"-safeMode", "safemode"}; + +static CommandLineArg sIsForBrowser{"-isForBrowser", "isforbrowser"}; +static CommandLineArg sNotForBrowser{"-notForBrowser", "notforbrowser"}; + +} // namespace geckoargs + +} // namespace mozilla + +#endif // mozilla_GeckoArgs_h diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index 37687c5642f0..35801bd991ce 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -38,6 +38,7 @@ EXPORTS.mozilla += [ "AutoSQLiteLifetime.h", "Bootstrap.h", "CmdLineAndEnvUtils.h", + "GeckoArgs.h", "MultiInstanceLock.h", "SafeMode.h", ] diff --git a/toolkit/xre/test/gtest/TestGeckoArgs.cpp b/toolkit/xre/test/gtest/TestGeckoArgs.cpp new file mode 100644 index 000000000000..e761843ca72e --- /dev/null +++ b/toolkit/xre/test/gtest/TestGeckoArgs.cpp @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" + +#include "mozilla/ArrayUtils.h" +#include "mozilla/GeckoArgs.h" + +using namespace mozilla; +using namespace mozilla::geckoargs; + +static CommandLineArg kCharParam{"-charParam", "charparam"}; +static CommandLineArg kUint64Param{"-Uint64Param", "uint64param"}; +static CommandLineArg kFlag{"-Flag", "flag"}; + +template +bool CheckArgv(char** aArgv, const char* const (&aExpected)[N]) { + for (size_t i = 0; i < N; ++i) { + if (aArgv[i] == nullptr && aExpected[i] == nullptr) { + return true; + } + if (strcmp(aArgv[i], aExpected[i]) != 0) { + return false; + } + } + return true; +} + +char kFirefox[] = "$HOME/bin/firefox/firefox-bin"; + +TEST(GeckoArgs, const_char_ptr) +{ + char kCharParamStr[] = "-charParam"; + char kCharParamValue[] = "paramValue"; + + { + char* argv[] = {kFirefox, kCharParamStr, kCharParamValue, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 4); + + Maybe charParam = kCharParam.Get(argc, argv); + EXPECT_TRUE(charParam.isSome()); + EXPECT_EQ(*charParam, kCharParamValue); + + const char* const expArgv[] = {kFirefox, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + char kBlahBlah[] = "-blahblah"; + char* argv[] = {kFirefox, kCharParamStr, kBlahBlah, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 4); + + Maybe charParam = kCharParam.Get(argc, argv); + EXPECT_TRUE(charParam.isNothing()); + + const char* const expArgv[] = {kFirefox, kBlahBlah, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + std::vector extraArgs; + EXPECT_EQ(extraArgs.size(), 0U); + kCharParam.Put("ParamValue", extraArgs); + EXPECT_EQ(extraArgs.size(), 2U); + EXPECT_EQ(extraArgs[0], "-charParam"); + EXPECT_EQ(extraArgs[1], "ParamValue"); + } + { EXPECT_EQ(kCharParam.Name(), "-charParam"); } +} + +TEST(GeckoArgs, uint64) +{ + char kUint64ParamStr[] = "-Uint64Param"; + + { + char* argv[] = {kFirefox, kUint64ParamStr, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 3); + + Maybe uint64Param = kUint64Param.Get(argc, argv); + EXPECT_TRUE(uint64Param.isNothing()); + + const char* const expArgv[] = {kFirefox, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + char* argv[] = {kFirefox, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 2); + + Maybe uint64Param = kUint64Param.Get(argc, argv); + EXPECT_TRUE(uint64Param.isNothing()); + + const char* const expArgv[] = {kFirefox, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + char kUint64ParamValue[] = "42"; + char* argv[] = {kFirefox, kUint64ParamStr, kUint64ParamValue, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 4); + + Maybe uint64Param = kUint64Param.Get(argc, argv); + EXPECT_TRUE(uint64Param.isSome()); + EXPECT_EQ(*uint64Param, 42U); + + const char* const expArgv[] = {kFirefox, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + char kUint64ParamValue[] = "aa"; + char* argv[] = {kFirefox, kUint64ParamStr, kUint64ParamValue, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 4); + + Maybe uint64Param = kUint64Param.Get(argc, argv); + EXPECT_TRUE(uint64Param.isNothing()); + + const char* const expArgv[] = {kFirefox, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + std::vector extraArgs; + EXPECT_EQ(extraArgs.size(), 0U); + kUint64Param.Put(1234, extraArgs); + EXPECT_EQ(extraArgs.size(), 2U); + EXPECT_EQ(extraArgs[0], "-Uint64Param"); + EXPECT_EQ(extraArgs[1], "1234"); + } + { EXPECT_EQ(kUint64Param.Name(), "-Uint64Param"); } +} + +TEST(GeckoArgs, bool) +{ + char kFlagStr[] = "-Flag"; + + { + char* argv[] = {kFirefox, kFlagStr, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 3); + + Maybe Flag = kFlag.Get(argc, argv); + EXPECT_TRUE(Flag.isSome()); + EXPECT_TRUE(*Flag); + + const char* const expArgv[] = {kFirefox, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + char* argv[] = {kFirefox, nullptr}; + int argc = ArrayLength(argv); + EXPECT_EQ(argc, 2); + + Maybe Flag = kFlag.Get(argc, argv); + EXPECT_TRUE(Flag.isNothing()); + + const char* const expArgv[] = {kFirefox, nullptr}; + EXPECT_TRUE(CheckArgv(argv, expArgv)); + } + { + std::vector extraArgs; + EXPECT_EQ(extraArgs.size(), 0U); + kFlag.Put(true, extraArgs); + EXPECT_EQ(extraArgs.size(), 1U); + EXPECT_EQ(extraArgs[0], "-Flag"); + } + { + std::vector extraArgs; + EXPECT_EQ(extraArgs.size(), 0U); + kFlag.Put(false, extraArgs); + EXPECT_EQ(extraArgs.size(), 0U); + } + { EXPECT_EQ(kFlag.Name(), "-Flag"); } +} diff --git a/toolkit/xre/test/gtest/moz.build b/toolkit/xre/test/gtest/moz.build index 9ea869fe6075..8c650241a3bd 100644 --- a/toolkit/xre/test/gtest/moz.build +++ b/toolkit/xre/test/gtest/moz.build @@ -8,6 +8,7 @@ Library("xretest") UNIFIED_SOURCES = [ "TestCompatVersionCompare.cpp", + "TestGeckoArgs.cpp", ] LOCAL_INCLUDES += [