Im using gtest as the test framework for my project and I need to use the following parameter value which is passed as a gtest parameter, inside the test case
./gtest_bin --gtest_repeat=5
Currently what I'm doing is, I've created a custom Listener extended from "EmptyTestEventListener" and pass the iteration value to a global variable when the callback to the following function is received as following,
customListener class
class customListener : public testing::EmptyTestEventListener
{
customListener(int *iteration) : m_iteration(iteration) {}
virtual void OnTestIterationStart(const testing::UnitTest& unit_test, int iteration)
{
*m_iteration = iteration;
}
}
main
int g_iteration;
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
if(argc > 1)
g_array_length = atoi(argv[1]);
testing::TestEventListeners& listners = testing::UnitTest::GetInstance()->listeners();
listners.Append(new printers::customListener(&g_iteration));
return RUN_ALL_TESTS();
}
Is there an easier way to get this gtest parameter value?
If generalized, Is there a way to get any gtest specific parameter value that can used inside a testcase?
IMPORTANT NOTE
Please use with great care - as this is not documented feature and
might be changed (i.e. it might stop working) in next gtest/gmock
versions.
You can access any flag by ::testing::GTEST_FLAG(flag_name) - in your case - ::testing::GTEST_FLAG(repeat).
I got this information indirectly from this manual and by examining gtest.h file.
Related
I'm working with a large C++ project that presently produces 66 different binaries. Each entrypoint contains its own global variables and main() function, though there's a lot of common code that's provided through a shared library.
For ease of distribution, I would like to distribute a single statically-linked binary, like you'd get from a Go or Rust project. Instead of invoking:
./ProgramFoo
./ProgramBar
I'd like to have a single combined binary that "execs" itself into one of those tools behind the scenes based on argv parameters, sort of like how busybox works:
./CombinedProgram ProgramFoo
./CombinedProgram ProgramBar
Look, I get that there's a "right" way to do this — refactor all 66 source files. Replace all global state with class singletons. Replace all the main() functions with entrypoint functions that could be dispatched from a single, unifying main() function. That sounds like a lot of work and a fair amount of disruption to all the other developers on the project. Is there truly no alternative on the compiler/linker level?
(I also don't want to just archive the binaries inside the CombinedProgram, write them to disk, and exec them. Boo. If I wanted a tarball, I'd just use a tarball.)
My understanding of C/C++ binary production is that the compiler will insert a crt0 startup routine that will initialize all my global state and then invoke main() with the appropriate parameters. Could I... perhaps... sneak some code in before that crt0 that peeks at argv and then proceeds down the correct code path?
Is there truly no alternative on the compiler/linker level?
Not really. Refactoring is the best / least work way to accomplish your task.
% cc -o one busy.c ; ln one two ; ./one ; ./two
one
two
The main() needs to look at ARGV[0] to determine how it was called. Then act on that information.
Simplest example:
#include <stdio.h>
#include <string.h>
int one(int argc, char **argv) {
printf("one\n");
return 1;
}
int two(int argc, char **argv) {
printf("two\n");
return 2;
}
int main(int argc, char **argv) {
char *end = argv[0];
int len = strlen(end);
end += len; // jump to the end of the command.
if (argc >= 1) {
if (!strcmp(end-3, "one")) {
return one(argc, argv);
} else if (!strcmp(end-3, "two")) {
return two(argc, argv);
}
}
}
I don't know of a tool that automatically refactors the commands into functions. The alternative is having one file determine what to do and then exec one of the 66 other statically-linked binaries.
I want to check the value of a variable that I set inside the main function, but the if statement is not inside a function.
Here is what I have so far.
bool condition;
#if(condition)
:
:
:
some code
#endif
int main(int argc, char *argv[])
{
condition = processArgs(argc, argv);
}
From my understanding macros are executed during compilation time and not run time. Is there another way to check the value of the variable condition outside functions. The value of the variable condition is set depending on the command line arguments passed by the user.
So how do I use if statements outside the scope of functions? Because macro if does not work.
If you are doing those tasks using macros(I guessed from the question) then you can try doing:
#define _condition(x) Condition(x)
bool Condition(bool result)
{
if(!result)
{
///some code
}
return false;
}
int main(int argc, char *argv[])
{
bool result=processArgs(argc, argv);
_condition(result);
}
This way you'll be defining a macro for checking the value of the result variable that I added. The macro _condition will call the function for you and you can add any more code in the function without making a mess of the macro because one cant possibly put a function like defining a macro. If you were not doing macros then you can try calling the function directly and not using macros. Macros are a very useful yet complicated stuff so it is hard to make such large functions that you did in the function
You want to add a function:
void myFunction(bool condition)
{
if (condition)
{
// some code
}
// some code
}
int main(int argc, char *argv[])
{
bool condition = processArgs(argc, argv);
myFunction(condition);
}
that way, you tell the compiler when to run it, and what condition to use.
I have integration tests in my Catch2 project that depend on some expensive global state being set up. I'd like to only initialize that global state when the test runner will actually be testing the systems that depend on it.
What I have appears to work, but it's a little horrifying... it depends on rather a lot of implementation details in the Catch config.
Here's my main:
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
...
int main(int argc, const char* argv[])
{
// Construct a fake TestCaseInfo to match against the [integration] tag
const char * expensive_tag = "integration";
Catch::SourceLineInfo fake_source_line("?", 0)
Catch::TestCaseInfo fake_test_case("?", "?", "?", {expensive_tag}, fake_source_line);
Catch::Session session;
session.applyCommandLine(argc, argv);
auto test_spec = session.config().testSpec();
const bool want_integration_tests = test_spec.matches(fake_test_spec);
if(want_integration_tests)
{
do_expensive_setup();
}
return session.run();
}
And then my test file is just:
#include "catch.hpp"
...
TEST_CASE("expensive-to-initialize system", "[.integration]")
{
REQUIRE(expensive_setup_is_done());
SECTION("has property 1") { ... }
SECTION("has property 2") { ... }
...
}
Note that because there are multiple sections (and, in my actual project, multiple test cases) that depend on the global setup, I can't just move the initialization into the top of the TEST_CASE.
Is there a better way?
Just do the initialization on demand, using something like std::call_once:
TEST_CASE("expensive-to-initialize system", "[.integration]")
{
static std::once_flag init_flag;
std::call_once(init_flag, do_expensive_setup);
// ...
}
This will ensure that do_expensive_setup is called one time, but only if needed. If there are multiple places that need this setup, just wrap this in a function.
Note that if do_expensive_setup throws, it will may be called a second time. But once the function successfully exits, that's it.
For some reason, I can't start gtest tests from commandline, so I can't pass any arguments to it. I want to run InitGoogleTest already with a parameter defined in code.
Somewhere on the Internet I found a solution like this:
int main(int argc, char **argv) {
char *option[] = { "test.exe", //it doesn't have meaning, just dummy
"--gtest_output=xml:filename" };
int argc1 = 2;
::testing::InitGoogleTest(&argc1, option);
return RUN_ALL_TESTS();
}
This solution didn't produce any errors but didn't create any xml with report either.
Can anyone suggest how to force gtest to write xml from Init?
You can override the output flag by adding
::testing::GTEST_FLAG(output) = "xml:filename";
before the call to InitGoogleTest. You can read more on it at Google Test docs.
I am trying to learn how to make a program in C++ that when you run it, you can tell it to run and specify options all in one line. For example you can do ipconfig /all in CMD and it runs ipconfig.exe with the option /all. Another example would be shutdown -f which tells the computer to shutdown with the option -f. For example, I want to make a program that downloads something from a URL and call it for example downloader. From command line one would type downloader http://filehere.com /h which would download the file with the /h option which I would define its property in my program. I don't want code or guides on how to make a downloader I am just trying to learn how to specify options like the /h. Are there any guides out there that you know of and could post or any sample code? I have tried searching for guides, but I think I just don't know what this operation is actually called. Thank you.
You typically define your main function to take two arguments: int argc and char *argv[], such as:
int
main(int argc, char *argv[])
{
...
The first argument is how many parameters your program received, argv is a pointer to them. Note, this isn't mandated, you can name them whatever you want, but that's the convention. Just make sure your types match up.
You can use an option-parsing library, but those are often OS-specific. One simple way to check if you received a /h is:
int got_h = 0;
for (int i=0; i<argc; ++i)
if (strcmp(argv[i], "/h") == 0)
got_h = 1;
...
if (got_h)
...
argv[argc] will always be NULL to make iterating through them easier.
Some more information here: http://www.site.uottawa.ca/~lucia/courses/2131-05/labs/Lab3/CommandLineArguments.html
The main function takes two arguments, traditionally named argc and argv:
int main (int argc, char * argv[])
{
// ...
}
argc contains the number of arguments passed on the command line, and the argv array contains such arguments (with argv[0] being the name used to invoke your program); the last element of the argv array (i.e. argv[argc]) contains a NULL pointer.
Depending upon your proficiency and inclination to use pointers, you may prefer to capture the command line as a vector<string>:
// UNTESTED CODE
int main(int argc, char **argv) {
std::vector<std::string> args(argv+1, argv+argc);
if(args.empty()) {
std::cout << "Usage: downloader URL [options]\n";
return 1;
}
if(std::find(args.begin(), args.end(), "/h") != args.end()) {
option_h = true;
}
Download(args[0]);
}