From dc32f374f027c8ad4b45a92790baf55c31ba239d Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Wed, 12 May 2021 01:03:13 -0400 Subject: [PATCH 1/2] firebase_test_framework.cc: Provide an easy way to edit the command-line arguments in integration tests --- .../src/firebase_test_framework.cc | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/testing/test_framework/src/firebase_test_framework.cc b/testing/test_framework/src/firebase_test_framework.cc index ac80942c2f..7934a83090 100644 --- a/testing/test_framework/src/firebase_test_framework.cc +++ b/testing/test_framework/src/firebase_test_framework.cc @@ -15,6 +15,9 @@ #include "firebase_test_framework.h" // NOLINT #include +#include +#include +#include #include "firebase/future.h" @@ -294,7 +297,57 @@ std::ostream& operator<<(std::ostream& os, const Variant& v) { } } // namespace firebase +namespace { + +/** + * Makes changes to argc and argv before passing them to `InitGoogleTest`. + * + * This function is a convenience function for developers to edit during + * development/debugging to customize the the arguments specified to googletest + * when directly specifying command-line arguments is not available, such as on + * Android and iOS. For example, to debug a specific test, add the + * --gtest_filter argument, and to list all tests add the --gtest_list_tests + * argument. + * + * @param argc A pointer to the `argc` that will be specified to + * `InitGoogleTest`; the integer to which this pointer points will be updated + * with the new length of `argv`. + * @param argv The `argv` that contains the arguments that would have otherwise + * been specified to `InitGoogleTest()`; they will not be modified. + * + * @return The new `argv` to be specified to `InitGoogleTest()`. + */ +char** EditMainArgsForGoogleTest(int* argc, char* argv[]) { + // Put the args into a vector of strings because modifying string objects in + // a vector is far easier than modifying a char** array. + std::vector args_vector; + for (int i = 0; i < *argc; ++i) { + args_vector.push_back(argv[i]); + } + + // This is where you can add elements to the `args_vector` vector that will be + // specified to googletest. + // e.g. args_vector.push_back("--gtest_list_tests"); + + // Write the elements of the vector back into argv and modify argc. + // The memory leaks produced below are acceptable because they would last the + // entire lifetime of the application anyways. + char** new_argv = new char*[args_vector.size()]; + for (int i = 0; i < args_vector.size(); ++i) { + const char* arg = args_vector[i].c_str(); + char* arg_copy = new char[std::strlen(arg) + 1]; + std::strcpy(arg_copy, arg); + new_argv[i] = arg_copy; + } + + *argc = static_cast(args_vector.size()); + return new_argv; +} + +} // namespace + extern "C" int common_main(int argc, char* argv[]) { + argv = EditMainArgsForGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv); firebase_test_framework::FirebaseTest::SetArgs(argc, argv); app_framework::SetLogLevel(app_framework::kDebug); From 8b5662921884983fdc232a3470c9baab870522e3 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Tue, 18 May 2021 00:19:34 -0400 Subject: [PATCH 2/2] firebase_test_framework.cc: a bit of refactoring and early exit if no changes to the args were made --- .../src/firebase_test_framework.cc | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/testing/test_framework/src/firebase_test_framework.cc b/testing/test_framework/src/firebase_test_framework.cc index 7934a83090..bea4b91d6c 100644 --- a/testing/test_framework/src/firebase_test_framework.cc +++ b/testing/test_framework/src/firebase_test_framework.cc @@ -299,6 +299,27 @@ std::ostream& operator<<(std::ostream& os, const Variant& v) { namespace { +std::vector ArgcArgvToVector(int argc, char* argv[]) { + std::vector args_vector; + for (int i = 0; i < argc; ++i) { + args_vector.push_back(argv[i]); + } + return args_vector; +} + +char** VectorToArgcArgv(const std::vector& args_vector, + int* argc) { + char** argv = new char*[args_vector.size()]; + for (int i = 0; i < args_vector.size(); ++i) { + const char* arg = args_vector[i].c_str(); + char* arg_copy = new char[std::strlen(arg) + 1]; + std::strcpy(arg_copy, arg); + argv[i] = arg_copy; + } + *argc = static_cast(args_vector.size()); + return argv; +} + /** * Makes changes to argc and argv before passing them to `InitGoogleTest`. * @@ -320,28 +341,22 @@ namespace { char** EditMainArgsForGoogleTest(int* argc, char* argv[]) { // Put the args into a vector of strings because modifying string objects in // a vector is far easier than modifying a char** array. - std::vector args_vector; - for (int i = 0; i < *argc; ++i) { - args_vector.push_back(argv[i]); - } + const std::vector original_args = ArgcArgvToVector(*argc, argv); + std::vector modified_args(original_args); - // This is where you can add elements to the `args_vector` vector that will be - // specified to googletest. - // e.g. args_vector.push_back("--gtest_list_tests"); + // Add elements to the `modified_args` vector to specify to googletest. + // e.g. modified_args.push_back("--gtest_list_tests"); + // e.g. modified_args.push_back("--gtest_filter=MyTestFixture.MyTest"); - // Write the elements of the vector back into argv and modify argc. - // The memory leaks produced below are acceptable because they would last the - // entire lifetime of the application anyways. - char** new_argv = new char*[args_vector.size()]; - for (int i = 0; i < args_vector.size(); ++i) { - const char* arg = args_vector[i].c_str(); - char* arg_copy = new char[std::strlen(arg) + 1]; - std::strcpy(arg_copy, arg); - new_argv[i] = arg_copy; + // Avoid the memory leaks documented below if there were no arg changes. + if (modified_args == original_args) { + return argv; } - *argc = static_cast(args_vector.size()); - return new_argv; + // Create a new `argv` with the elements from the `modified_args` vector and + // write the new count back to `argc`. The memory leaks produced by + // `VectorToArgcArgv` acceptable because they last for the entire application. + return VectorToArgcArgv(modified_args, argc); } } // namespace