Repository: cpputest/cpputest (cpp)

Issue:
Request: Option to display source file and line numbers for each test
I am working with someone on a Visual Studio Code Extension for cpputest.
One option it has is to be able to click on a test in the gui and it brings you to the source code for that test.

It currently does this by running objdump on the binary.  This has turned out to be very slow.  1 minute on a test executable with 1000 tests.

It would be better/faster if there was a way to compile in the source code and line numbers for each test and make that available via a command line option.

Any chance this could be included in a future release?


Discussion:
It would be something that I would accept a pull request from. It should be trivial as this info is already stored. We also already have two other command line options (the -l ones) that list things without executing the code.

Patch:
diff --git a/include/CppUTest/CommandLineArguments.h b/include/CppUTest/CommandLineArguments.h
--- a/include/CppUTest/CommandLineArguments.h
+++ b/include/CppUTest/CommandLineArguments.h
@@ -47,6 +47,7 @@ class CommandLineArguments
     bool isColor() const;
     bool isListingTestGroupNames() const;
     bool isListingTestGroupAndCaseNames() const;
+    bool isListingTestLocations() const;
     bool isRunIgnored() const;
     size_t getRepeatCount() const;
     bool isShuffling() const;
@@ -80,6 +81,7 @@ class CommandLineArguments
     bool runTestsAsSeperateProcess_;
     bool listTestGroupNames_;
     bool listTestGroupAndCaseNames_;
+    bool listTestLocations_;
     bool runIgnored_;
     bool reversing_;
     bool crashOnFail_;
diff --git a/include/CppUTest/TestRegistry.h b/include/CppUTest/TestRegistry.h
--- a/include/CppUTest/TestRegistry.h
+++ b/include/CppUTest/TestRegistry.h
@@ -55,6 +55,7 @@ class TestRegistry
     virtual void reverseTests();
     virtual void listTestGroupNames(TestResult& result);
     virtual void listTestGroupAndCaseNames(TestResult& result);
+    virtual void listTestLocations(TestResult& result);
     virtual void setNameFilters(const TestFilter* filters);
     virtual void setGroupFilters(const TestFilter* filters);
     virtual void installPlugin(TestPlugin* plugin);
diff --git a/src/CppUTest/CommandLineArguments.cpp b/src/CppUTest/CommandLineArguments.cpp
--- a/src/CppUTest/CommandLineArguments.cpp
+++ b/src/CppUTest/CommandLineArguments.cpp
@@ -30,7 +30,7 @@
 #include "CppUTest/PlatformSpecificFunctions.h"
 
 CommandLineArguments::CommandLineArguments(int ac, const char *const *av) :
-    ac_(ac), av_(av), needHelp_(false), verbose_(false), veryVerbose_(false), color_(false), runTestsAsSeperateProcess_(false), listTestGroupNames_(false), listTestGroupAndCaseNames_(false), runIgnored_(false), reversing_(false), crashOnFail_(false), shuffling_(false), shufflingPreSeeded_(false), repeat_(1), shuffleSeed_(0), groupFilters_(NULLPTR), nameFilters_(NULLPTR), outputType_(OUTPUT_ECLIPSE)
+    ac_(ac), av_(av), needHelp_(false), verbose_(false), veryVerbose_(false), color_(false), runTestsAsSeperateProcess_(false), listTestGroupNames_(false), listTestGroupAndCaseNames_(false), listTestLocations_(false), runIgnored_(false), reversing_(false), crashOnFail_(false), shuffling_(false), shufflingPreSeeded_(false), repeat_(1), shuffleSeed_(0), groupFilters_(NULLPTR), nameFilters_(NULLPTR), outputType_(OUTPUT_ECLIPSE)
 {
 }
 
@@ -65,6 +65,7 @@ bool CommandLineArguments::parse(TestPlugin* plugin)
         else if (argument == "-b") reversing_ = true;
         else if (argument == "-lg") listTestGroupNames_ = true;
         else if (argument == "-ln") listTestGroupAndCaseNames_ = true;
+        else if (argument == "-ll") listTestLocations_ = true;
         else if (argument == "-ri") runIgnored_ = true;
         else if (argument == "-f") crashOnFail_ = true;
         else if (argument.startsWith("-r")) setRepeatCount(ac_, av_, i);
@@ -171,6 +172,11 @@ bool CommandLineArguments::isListingTestGroupAndCaseNames() const
     return listTestGroupAndCaseNames_;
 }
 
+bool CommandLineArguments::isListingTestLocations() const
+{
+    return listTestLocations_;
+}
+
 bool CommandLineArguments::isRunIgnored() const
 {
     return runIgnored_;
diff --git a/src/CppUTest/CommandLineTestRunner.cpp b/src/CppUTest/CommandLineTestRunner.cpp
--- a/src/CppUTest/CommandLineTestRunner.cpp
+++ b/src/CppUTest/CommandLineTestRunner.cpp
@@ -120,6 +120,13 @@ int CommandLineTestRunner::runAllTests()
         return 0;
     }
 
+    if (arguments_->isListingTestLocations())
+    {
+        TestResult tr(*output_);
+        registry_->listTestLocations(tr);
+        return 0;
+    }
+
     if (arguments_->isReversing())
         registry_->reverseTests();
 
diff --git a/src/CppUTest/TestRegistry.cpp b/src/CppUTest/TestRegistry.cpp
--- a/src/CppUTest/TestRegistry.cpp
+++ b/src/CppUTest/TestRegistry.cpp
@@ -123,6 +123,26 @@ void TestRegistry::listTestGroupAndCaseNames(TestResult& result)
     result.print(groupAndNameList.asCharString());
 }
 
+void TestRegistry::listTestLocations(TestResult& result)
+{
+    SimpleString testLocations;
+
+    for (UtestShell *test = tests_; test != NULLPTR; test = test->getNext()) {
+            SimpleString testLocation;
+            testLocation += test->getGroup();
+            testLocation += ".";
+            testLocation += test->getName();
+            testLocation += ".";
+            testLocation += test->getFile();
+            testLocation += ".";
+            testLocation += StringFromFormat("%d\n",test->getLineNumber());
+
+            testLocations += testLocation;
+    }
+
+    result.print(testLocations.asCharString());
+}
+
 bool TestRegistry::endOfGroup(UtestShell* test)
 {
     return (!test || !test->getNext() || test->getGroup() != test->getNext()->getGroup());


Test patch:
diff --git a/tests/CppUTest/CommandLineTestRunnerTest.cpp b/tests/CppUTest/CommandLineTestRunnerTest.cpp
--- a/tests/CppUTest/CommandLineTestRunnerTest.cpp
+++ b/tests/CppUTest/CommandLineTestRunnerTest.cpp
@@ -269,6 +269,16 @@ TEST(CommandLineTestRunner, listTestGroupAndCaseNamesShouldWorkProperly)
     STRCMP_CONTAINS("group1.test1", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
 }
 
+TEST(CommandLineTestRunner, listTestLocationsShouldWorkProperly)
+{
+    const char* argv[] = { "tests.exe", "-ll" };
+
+    CommandLineTestRunnerWithStringBufferOutput commandLineTestRunner(2, argv, &registry);
+    commandLineTestRunner.runAllTestsMain();
+
+    STRCMP_CONTAINS("group1.test1", commandLineTestRunner.fakeConsoleOutputWhichIsReallyABuffer->getOutput().asCharString());
+}
+
 TEST(CommandLineTestRunner, randomShuffleSeedIsPrintedAndRandFuncIsExercised)
 {
     // more than 1 item in test list ensures that shuffle algorithm calls rand_()
diff --git a/tests/CppUTest/TestRegistryTest.cpp b/tests/CppUTest/TestRegistryTest.cpp
--- a/tests/CppUTest/TestRegistryTest.cpp
+++ b/tests/CppUTest/TestRegistryTest.cpp
@@ -361,6 +361,29 @@ TEST(TestRegistry, listTestGroupAndCaseNames_shouldListBackwardsGroupATestaAfter
     STRCMP_EQUAL("GROUP_A.test_aa GROUP_B.test_b GROUP_A.test_a", s.asCharString());
 }
 
+TEST(TestRegistry, listTestLocations_shouldListBackwardsGroupATestaAfterGroupAtestaa)
+{
+    test1->setGroupName("GROUP_A");
+    test1->setTestName("test_a");
+    test1->setFileName("cpptest_simple/my_tests/testa.cpp");
+    test1->setLineNumber(100);
+    myRegistry->addTest(test1);
+    test2->setGroupName("GROUP_B");
+    test2->setTestName("test_b");
+    test2->setFileName("cpptest_simple/my tests/testb.cpp");
+    test2->setLineNumber(200);
+    myRegistry->addTest(test2);
+    test3->setGroupName("GROUP_A");
+    test3->setTestName("test_aa");
+    test3->setFileName("cpptest_simple/my_tests/testaa.cpp");
+    test3->setLineNumber(300);
+    myRegistry->addTest(test3);
+
+    myRegistry->listTestLocations(*result);
+    SimpleString s = output->getOutput();
+    STRCMP_EQUAL("GROUP_A.test_aa.cpptest_simple/my_tests/testaa.cpp.300\nGROUP_B.test_b.cpptest_simple/my tests/testb.cpp.200\nGROUP_A.test_a.cpptest_simple/my_tests/testa.cpp.100\n", s.asCharString());
+}
+
 TEST(TestRegistry, shuffleEmptyListIsNoOp)
 {
     CHECK_TRUE(myRegistry->getFirstTest() == NULLPTR);