├── .gitignore ├── tests ├── singleCase │ ├── test.conf │ └── singleCase.hh ├── threeCases │ ├── test.conf │ ├── main.cpp │ ├── firstCase.hh │ ├── thirdCase.hh │ └── secondCase.hh ├── namespaceSingleCase │ ├── test.conf │ └── singleCase.hh ├── oneFailOverThree │ ├── main.cpp │ ├── test.conf │ ├── firstCase.hh │ ├── thirdCase.hh │ └── secondCase.hh ├── outputOptionCreateFile │ ├── test.conf │ └── singleCase.hh ├── twoFailsOverThree │ ├── main.cpp │ ├── test.conf │ ├── firstCase.hh │ ├── thirdCase.hh │ └── secondCase.hh ├── namespaceSelectable │ ├── main.cpp │ ├── test.conf │ ├── firstCase.hh │ ├── thirdCase.hh │ └── secondCase.hh ├── oneMultipleFailsOverThree │ ├── main.cpp │ ├── test.conf │ ├── firstCase.hh │ ├── thirdCase.hh │ └── secondCase.hh ├── outputOptionOnMultipleCase │ ├── main.cpp │ ├── test.conf │ ├── thirdCase.hh │ ├── secondCase.hh │ └── firstCase.hh ├── threeCasesButOneSelected │ ├── main.cpp │ ├── test.conf │ ├── firstCase.hh │ ├── thirdCase.hh │ └── secondCase.hh ├── threeCasesButTwoSelected │ ├── main.cpp │ ├── test.conf │ ├── firstCase.hh │ ├── thirdCase.hh │ └── secondCase.hh ├── twoMultipleFailsOverThree │ ├── main.cpp │ ├── test.conf │ ├── firstCase.hh │ ├── secondCase.hh │ └── thirdCase.hh ├── base.pri ├── resultParsing.sh └── runAll.sh ├── .travis.yml ├── README.md ├── LICENSE.md └── MultiTests.hh /.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | moc/ 3 | Makefile 4 | *.pro 5 | multiTestsCaseRunner 6 | *.log 7 | *.out 8 | -------------------------------------------------------------------------------- /tests/singleCase/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="" 2 | checkNbCases="1" 3 | checksStr+=( "All test should succeed"="All tests succeed" ) 4 | -------------------------------------------------------------------------------- /tests/threeCases/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="" 2 | checkNbCases="3" 3 | checksStr+=( "All test should succeed"="All tests succeed" ) 4 | -------------------------------------------------------------------------------- /tests/threeCases/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/namespaceSingleCase/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="" 2 | checkNbCases="1" 3 | checksStr+=( "All test should succeed"="test_space::Dummy_test" ) 4 | -------------------------------------------------------------------------------- /tests/oneFailOverThree/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/outputOptionCreateFile/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="-o test.out" 2 | checkNbCases="0" 3 | checksFileExist+=("Force output to file"="test.out") 4 | -------------------------------------------------------------------------------- /tests/twoFailsOverThree/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/namespaceSelectable/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/oneMultipleFailsOverThree/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/outputOptionOnMultipleCase/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/threeCasesButOneSelected/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/threeCasesButTwoSelected/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/twoMultipleFailsOverThree/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "firstCase.hh" 3 | #include "secondCase.hh" 4 | #include "thirdCase.hh" 5 | 6 | MULTI_TESTS_MAIN 7 | -------------------------------------------------------------------------------- /tests/namespaceSelectable/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="-case test_space::SecondCase_test" 2 | checkNbCases="1" 3 | checksStr+=( "Test must have been selected"="test_space::SecondCase_test" ) 4 | -------------------------------------------------------------------------------- /tests/threeCasesButOneSelected/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="-case SecondCase_test" 2 | checkNbCases="1" 3 | checksStr+=( "All test should succeed"="All tests succeed" ) 4 | checksStr+=( "Case selection is correct"="Start testing of SecondCase_test" ) 5 | -------------------------------------------------------------------------------- /tests/oneFailOverThree/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="" 2 | checkNbCases="3" 3 | checksStr+=( "Error detected"="ERRORS during tests") 4 | checksStr+=( "Error count"="1 error in 1 case(s), over a total of 3 tests cases") 5 | checksStr+=( "Detect failing cases"="Case(s) that failed : SecondCase_test") 6 | -------------------------------------------------------------------------------- /tests/oneMultipleFailsOverThree/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="" 2 | checkNbCases="3" 3 | checksStr+=( "Error detected"="ERRORS during tests") 4 | checksStr+=( "Error count"="2 error in 1 case(s), over a total of 3 tests cases") 5 | checksStr+=( "Detect failing cases"="Case(s) that failed : SecondCase_test") 6 | -------------------------------------------------------------------------------- /tests/twoFailsOverThree/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="" 2 | checkNbCases="3" 3 | checksStr+=( "Error detected"="ERRORS during tests") 4 | checksStr+=( "Error count"="2 error in 2 case(s), over a total of 3 tests cases") 5 | checksStr+=( "Detect failing cases"="Case(s) that failed : SecondCase_test / ThirdCase_test") 6 | -------------------------------------------------------------------------------- /tests/twoMultipleFailsOverThree/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="" 2 | checkNbCases="3" 3 | checksStr+=( "Error detected"="ERRORS during tests") 4 | checksStr+=( "Error count"="5 error in 2 case(s), over a total of 3 tests cases") 5 | checksStr+=( "Detect failing cases"="Case(s) that failed : SecondCase_test / ThirdCase_test") 6 | -------------------------------------------------------------------------------- /tests/outputOptionOnMultipleCase/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="-o testoutput.out" 2 | checkNbCases="0" 3 | checksFileExist+=("First case summary is inside a file"="testoutput.out") 4 | checksFileExist+=("Second case summary is inside a file"="testoutput_0001.out") 5 | checksFileExist+=("Third case summary is inside a file"="testoutput_0002.out") 6 | -------------------------------------------------------------------------------- /tests/threeCasesButTwoSelected/test.conf: -------------------------------------------------------------------------------- 1 | runnerOptions="-case SecondCase_test -case FirstCase_test" 2 | checkNbCases="2" 3 | checksStr+=( "All test should succeed"="All tests succeed" ) 4 | checksStr+=( "Case selection is correct"="Start testing of FirstCase_test" ) 5 | checksStr+=( "Case selection is correct"="Start testing of SecondCase_test" ) 6 | -------------------------------------------------------------------------------- /tests/threeCases/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCases/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/oneFailOverThree/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/oneFailOverThree/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCases/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(SecondCase_test); 17 | 18 | #endif /* SECONDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/twoFailsOverThree/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/twoFailsOverThree/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void failureToo(void){ 12 | QVERIFY(false); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/namespaceSelectable/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/namespaceSelectable/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/oneFailOverThree/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void failure(void){ 12 | QCOMPARE(1,3); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(SecondCase_test); 17 | 18 | #endif /* SECONDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/twoFailsOverThree/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void failure(void){ 12 | QCOMPARE(1,3); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(SecondCase_test); 17 | 18 | #endif /* SECONDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/oneMultipleFailsOverThree/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/oneMultipleFailsOverThree/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/outputOptionOnMultipleCase/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCasesButOneSelected/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCasesButOneSelected/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCasesButTwoSelected/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCasesButTwoSelected/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(ThirdCase_test); 17 | 18 | #endif /* THIRDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/twoMultipleFailsOverThree/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class FirstCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(FirstCase_test); 17 | 18 | #endif /* FIRSTCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/outputOptionOnMultipleCase/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(SecondCase_test); 17 | 18 | #endif /* SECONDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCasesButOneSelected/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(SecondCase_test); 17 | 18 | #endif /* SECONDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/threeCasesButTwoSelected/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(SecondCase_test); 17 | 18 | #endif /* SECONDCASE_HH_ */ 19 | -------------------------------------------------------------------------------- /tests/singleCase/singleCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef TESTDUMMY_HH_ 2 | #define TESTDUMMY_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class Dummy_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(Dummy_test); 17 | 18 | 19 | MULTI_TESTS_MAIN 20 | 21 | #endif /* TESTDUMMY_HH_ */ 22 | -------------------------------------------------------------------------------- /tests/outputOptionCreateFile/singleCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef TESTDUMMY_HH_ 2 | #define TESTDUMMY_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class Dummy_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void obviousTest(void){ 12 | QCOMPARE(1,1); 13 | } 14 | }; 15 | 16 | TEST_DECLARE(Dummy_test); 17 | 18 | 19 | MULTI_TESTS_MAIN 20 | 21 | #endif /* TESTDUMMY_HH_ */ 22 | -------------------------------------------------------------------------------- /tests/namespaceSelectable/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | namespace test_space{ 7 | class SecondCase_test : public QObject{ 8 | Q_OBJECT 9 | 10 | private slots: 11 | // Test functions 12 | void obviousTest(void){ 13 | QCOMPARE(1,1); 14 | } 15 | }; 16 | 17 | TEST_DECLARE(SecondCase_test); 18 | 19 | } 20 | 21 | #endif /* SECONDCASE_HH_ */ 22 | -------------------------------------------------------------------------------- /tests/namespaceSingleCase/singleCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef TESTDUMMY_HH_ 2 | #define TESTDUMMY_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | namespace test_space{ 7 | 8 | class Dummy_test : public QObject{ 9 | Q_OBJECT 10 | 11 | private slots: 12 | // Test functions 13 | void obviousTest(void){ 14 | QCOMPARE(1,1); 15 | } 16 | }; 17 | 18 | TEST_DECLARE(Dummy_test); 19 | 20 | } 21 | 22 | MULTI_TESTS_MAIN 23 | 24 | #endif /* TESTDUMMY_HH_ */ 25 | -------------------------------------------------------------------------------- /tests/twoMultipleFailsOverThree/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void failure(void){ 12 | QCOMPARE(1,3); 13 | } 14 | void anotherFailure(void){ 15 | QFAIL("test"); 16 | } 17 | }; 18 | 19 | TEST_DECLARE(SecondCase_test); 20 | 21 | #endif /* SECONDCASE_HH_ */ 22 | -------------------------------------------------------------------------------- /tests/oneMultipleFailsOverThree/secondCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef SECONDCASE_HH_ 2 | #define SECONDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class SecondCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void failureOne(void){ 12 | QCOMPARE(1,3); 13 | } 14 | void failureTwo(void){ 15 | QFAIL("Always a failure"); 16 | } 17 | }; 18 | 19 | TEST_DECLARE(SecondCase_test); 20 | 21 | #endif /* SECONDCASE_HH_ */ 22 | -------------------------------------------------------------------------------- /tests/twoMultipleFailsOverThree/thirdCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef THIRDCASE_HH_ 2 | #define THIRDCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | class ThirdCase_test : public QObject{ 7 | Q_OBJECT 8 | 9 | private slots: 10 | // Test functions 11 | void failureToo(void){ 12 | QVERIFY(false); 13 | } 14 | void andItsContinue(void){ 15 | QVERIFY(false); 16 | } 17 | void reallyAllWrong(void){ 18 | QVERIFY(false); 19 | } 20 | }; 21 | 22 | TEST_DECLARE(ThirdCase_test); 23 | 24 | #endif /* THIRDCASE_HH_ */ 25 | -------------------------------------------------------------------------------- /tests/base.pri: -------------------------------------------------------------------------------- 1 | # Outputs directories 2 | MOC_DIR = ./moc 3 | RCC_DIR = ./rcc 4 | OBJECTS_DIR = ./obj 5 | 6 | # C++11 options 7 | _QT_BASE=$$(QT_BASE) 8 | 9 | equals( _QT_BASE, "48cpp98") { 10 | message("Configuration for C++98 (QT_BASE is '$$(QT_BASE)' )") 11 | } 12 | !equals( _QT_BASE, "48cpp98") { 13 | message("Configuration for C++11 (QT_BASE is '$$(QT_BASE)' )") 14 | CONFIG += c++11 15 | QMAKE_CXXFLAGS += -std=c++11 16 | } 17 | 18 | # Flag Qt Version 19 | greaterThan(QT_MAJOR_VERSION, 4): DEFINES += QT5 20 | lessThan(QT_MAJOR_VERSION, 5): CONFIG += qtestlib 21 | greaterThan(QT_MAJOR_VERSION, 4): QT += testlib widgets 22 | 23 | # For more simplicity, all targets have same name 24 | TARGET = multiTestsCaseRunner 25 | -------------------------------------------------------------------------------- /tests/outputOptionOnMultipleCase/firstCase.hh: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTCASE_HH_ 2 | #define FIRSTCASE_HH_ 3 | 4 | #include "../../MultiTests.hh" 5 | 6 | #include 7 | 8 | class FirstCase_test : public QObject{ 9 | Q_OBJECT 10 | 11 | private slots: 12 | // Test functions 13 | void regExTestser(void){ 14 | QString regEx = ".*_\\d+$"; 15 | 16 | QVERIFY( !QString("test").contains( QRegExp(regEx) ) ); 17 | QVERIFY( !QString("test1").contains( QRegExp(regEx) ) ); 18 | QVERIFY( QString("test_1").contains( QRegExp(regEx) ) ); 19 | QVERIFY( QString("test_00").contains( QRegExp(regEx) ) ); 20 | QVERIFY( QString("test_11").contains( QRegExp(regEx) ) ); 21 | QVERIFY( QString("test_00001").contains( QRegExp(regEx) ) ); 22 | QVERIFY( !QString("test_a").contains( QRegExp(regEx) ) ); 23 | QVERIFY( !QString("test_ad1").contains( QRegExp(regEx) ) ); 24 | QVERIFY( QString("test_1_1").contains( QRegExp(regEx) ) ); 25 | QVERIFY( !QString("test_1_a").contains( QRegExp(regEx) ) ); 26 | } 27 | }; 28 | 29 | TEST_DECLARE(FirstCase_test); 30 | 31 | #endif /* FIRSTCASE_HH_ */ 32 | -------------------------------------------------------------------------------- /tests/resultParsing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | scriptSuccess=0 4 | 5 | log(){ 6 | # Log a successfull step 7 | # param1 : decription of step 8 | echo "===> [ OK ] $1" 9 | } 10 | 11 | error(){ 12 | # Log a failure step (and set scriptSuccess to failure status) 13 | # param1 : decription of step 14 | echo "===> [FAIL] $1" 15 | scriptSuccess=1 16 | } 17 | 18 | testIntEqual(){ 19 | # Test that two integers are equals 20 | # param1 : The expected value 21 | # param2 : The value we get 22 | # param3 : Description of test 23 | if [ $1 -ne $2 ] 24 | then 25 | error "$3 : expected $1, get $2" 26 | else 27 | log "$3 : $1" 28 | fi 29 | } 30 | 31 | logParse(){ 32 | # Parse log result for extract important metrics 33 | nbCaseStarted=`grep -o "Start testing of " output.log | wc -l` 34 | } 35 | 36 | testLogContain(){ 37 | # Test that the run log contain a string 38 | # param1 : The string to look for 39 | # param2 : Description of test 40 | if grep -q -o "$1" "output.log" 41 | then 42 | log "$2 : log contain '$1'" 43 | else 44 | error "$2 : log do not contain '$1'" 45 | fi 46 | } 47 | 48 | testFileExist(){ 49 | # Test that a file exist 50 | # param1 : The file name 51 | # param2 : Description of test 52 | if [ -e "$1" ] 53 | then 54 | log "$2 : File '$1' exist" 55 | else 56 | error "$2 : File '$1' do not exist" 57 | fi 58 | } 59 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | sudo: required 4 | dist: trusty 5 | 6 | compiler: 7 | - g++ 8 | 9 | env: 10 | - QT_BASE=48 11 | - QT_BASE=51 12 | - QT_BASE=52 13 | - QT_BASE=53 14 | - QT_BASE=54 15 | - QT_BASE=55 16 | - QT_BASE=56 17 | - QT_BASE=57 18 | 19 | 20 | before_install: 21 | - if [ "$CXX" = "g++" ]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y; fi 22 | - if [ "$QT_BASE" = "48" ]; then sudo add-apt-repository ppa:beineri/opt-qt487-trusty -y; fi 23 | - if [ "$QT_BASE" = "51" ]; then sudo add-apt-repository ppa:beineri/opt-qt511-trusty -y; fi 24 | - if [ "$QT_BASE" = "52" ]; then sudo add-apt-repository ppa:beineri/opt-qt521-trusty -y; fi 25 | - if [ "$QT_BASE" = "53" ]; then sudo add-apt-repository ppa:beineri/opt-qt532-trusty -y; fi 26 | - if [ "$QT_BASE" = "54" ]; then sudo add-apt-repository ppa:beineri/opt-qt542-trusty -y; fi 27 | - if [ "$QT_BASE" = "55" ]; then sudo add-apt-repository ppa:beineri/opt-qt551-trusty -y; fi 28 | - if [ "$QT_BASE" = "56" ]; then sudo add-apt-repository ppa:beineri/opt-qt562-trusty -y; fi 29 | - if [ "$QT_BASE" = "57" ]; then sudo add-apt-repository ppa:beineri/opt-qt571-trusty -y; fi 30 | - sudo apt-get update -qq 31 | - export DISPLAY=:99.0 32 | - sh -e /etc/init.d/xvfb start 33 | 34 | install: 35 | - if [ "$CXX" = "g++" ] && [ "$QT_BASE" != "48cpp98" ]; then sudo apt-get install -qq g++-4.8 gcc-4.8; fi 36 | - if [ "$CXX" = "g++" ] && [ "$QT_BASE" != "48cpp98" ]; then sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 60; fi 37 | - if [ "$CXX" = "g++" ] && [ "$QT_BASE" != "48cpp98" ]; then sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 60; fi 38 | - if [ "$QT_BASE" = "48" ]; then sudo apt-get install -qq opt-qt4-qmake opt-qt4-dev-tools; source /opt/qt-4.8/bin/qt-4.8-env.sh; fi 39 | - if [ "$QT_BASE" = "51" ]; then sudo apt-get install -qq qt51base; source /opt/qt51/bin/qt51-env.sh; fi 40 | - if [ "$QT_BASE" = "52" ]; then sudo apt-get install -qq qt52base; source /opt/qt52/bin/qt52-env.sh; fi 41 | - if [ "$QT_BASE" = "53" ]; then sudo apt-get install -qq qt53base; source /opt/qt53/bin/qt53-env.sh; fi 42 | - if [ "$QT_BASE" = "54" ]; then sudo apt-get install -qq qt54base; source /opt/qt54/bin/qt54-env.sh; fi 43 | - if [ "$QT_BASE" = "55" ]; then sudo apt-get install -qq qt55base; source /opt/qt55/bin/qt55-env.sh; fi 44 | - if [ "$QT_BASE" = "56" ]; then sudo apt-get install -qq qt56base; source /opt/qt56/bin/qt56-env.sh; fi 45 | - if [ "$QT_BASE" = "57" ]; then sudo apt-get install -qq qt57base; source /opt/qt57/bin/qt57-env.sh; fi 46 | 47 | script: 48 | - g++ --version 49 | - qmake --version 50 | - ./tests/runAll.sh --verbose 51 | 52 | notifications: 53 | email: 54 | on_success: change 55 | on_failure: change 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qt Multiple tests [![Build Status](https://travis-ci.org/e-j/qt-multiple-tests.svg?branch=master)](https://travis-ci.org/e-j/qt-multiple-tests) 2 | 3 | ## Purpose 4 | 5 | The [Qt Test library](http://doc.qt.io/qt-5/qtest-overview.html), as based on a lightweight philosophy, don't provide any facilities for run multiple tests cases in a single application. But that's can be a very useful feature for medium size applications. 6 | 7 | **Qt Multiple tests** provide an easy solution : include an additionnal header and you are able to create several tests cases in your test suite. A single binary will allow to run one or all test cases. Reporting and re-run test is simplified. Parsing unit tests results will be simplified for external tools (IDE, continuous integration) 8 | 9 | **Qt Multiple tests** is a rework on a original example provided by Rob Caldecott in his two of his posts : [Running Multiple Unit Tests ](http://qtcreator.blogspot.fr/2009/10/running-multiple-unit-tests.html) and [Sample Multiple Unit Test Project ](http://qtcreator.blogspot.fr/2010/04/sample-multiple-unit-test-project.html). 10 | 11 | ## Features 12 | 13 | * Simplicity of use : just include the header [`MultiTests.hh`](MultiTests.hh) to your project 14 | * Choose to run all or a selection of the test case : option `-case ` 15 | * List all tests functions from a case (or all cases) : option `-functions` 16 | * Summary of tests results in verbose output 17 | * Support some Qt Test runner options. For example you can have XML report 18 | * Qt4 / Qt5 compatibility 19 | * For Qt4 : Provide the exception thrown test (as exists in Qt5) 20 | 21 | ## Requirements 22 | * A Qt application in QTest mode 23 | - For Qt4 : `CONFIG += qtestlib` 24 | - For Qt5 : `QT += testlib widgets` 25 | 26 | 27 | ## How to use it 28 | 29 | 1. Add the [`MultiTests.hh`](MultiTests.hh) file to your project 30 | 2. Create a test case. Register it using **`TEST_DECLARE`** 31 | 32 | ```cpp 33 | #ifndef TESTDUMMY_HH_ 34 | #define TESTDUMMY_HH_ 35 | 36 | #include "MultiTests.hh" 37 | 38 | class Dummy_test : public QObject 39 | { 40 | Q_OBJECT 41 | 42 | private slots: 43 | // Test functions 44 | void obviousTest(void){ 45 | QCOMPARE(1,1); 46 | } 47 | }; 48 | 49 | TEST_DECLARE(Dummy_test); 50 | 51 | #endif /* TESTDUMMY_HH_ */ 52 | ``` 53 | 54 | 3. When you want to compile the unit tests, just run the **`MULTI_TESTS_MAIN`** instead of your `main` function : 55 | 56 | ```cpp 57 | #ifdef UNITTEST_MODE 58 | #include "MultiTests.hh" 59 | MULTI_TESTS_MAIN 60 | // Else run normal main function 61 | #endif 62 | ``` 63 | 4. Compile the application and run it : the test case is executed 64 | 5. Repeat the step 2 for add more tests cases 65 | 66 | 67 | Example of execution : 68 | 69 | ``` 70 | ********* Start testing of Dummy_test ********* 71 | Config: Using QTest library 4.8.6, Qt 4.8.6 72 | PASS : Dummy_test::initTestCase() 73 | PASS : Dummy_test::obviousTest() 74 | PASS : Dummy_test::cleanupTestCase() 75 | ********* Finished testing of Dummy_test ********* 76 | ********* Start testing of StylesHandler_test ********* 77 | Config: Using QTest library 4.8.6, Qt 4.8.6 78 | PASS : StylesHandler_test::initTestCase() 79 | FAIL! : StylesHandler_test::totalFailure() Compared values are not the same 80 | Actual (m_data->content()): In7sh4oaZj6G0gf 81 | Expected (QString("153")): 153 82 | Loc: [tests/StylesHandler_test.cpp(67)] 83 | PASS : StylesHandler_test::styleExist() 84 | PASS : StylesHandler_test::cleanupTestCase() 85 | Totals: 4 passed, 0 failed, 0 skipped 86 | ********* Finished testing of StylesHandler_test ********* 87 | ********* Start testing of VarTypes_test ********* 88 | Config: Using QTest library 4.8.6, Qt 4.8.6 89 | PASS : VarTypes_test::initTestCase() 90 | PASS : VarTypes_test::varUnknowUndefined() 91 | PASS : VarTypes_test::varSearchValue() 92 | PASS : VarTypes_test::cleanupTestCase() 93 | Totals: 10 passed, 0 failed, 0 skipped 94 | ********* Finished testing of VarTypes_test ********* 95 | ======================================== 96 | ======================================== 97 | ======= ERRORS during tests !!! ======= 98 | 1 error in 1 case(s), over a total of 3 tests cases 99 | Case(s) that failed : StylesHandler_test 100 | Executed in 0 seconds (49 ms) 101 | ``` 102 | 103 | ## License 104 | 105 | This project is under LGPLv3. 106 | See the [LICENSE](LICENSE.md) file for license rights and limitations 107 | 108 | 109 | ## Next steps 110 | 111 | This helpful project is still a work in progress and can be improved in many ways. 112 | Missing features and to do work are listed into the issues section. 113 | -------------------------------------------------------------------------------- /tests/runAll.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | readonly PROGNAME=$(basename $0) 3 | readonly PROGDIR=$(readlink -m $(dirname $0)) 4 | readonly ARGS="$@" 5 | readonly ARGS_ARRAY=($@) 6 | 7 | # Constants 8 | readonly BIN_RUNNER=multiTestsCaseRunner 9 | readonly SPECIFIC_SCRIPT=specific.sh 10 | readonly RUNNER_OUTPUT=output.log 11 | readonly CONFIGURATION_FILENAME=test.conf 12 | 13 | testConfig(){ 14 | # Configure bash environment for test execution 15 | source $PROGDIR/resultParsing.sh 16 | set -e # Exit script as soon as one command fail 17 | } 18 | 19 | usage() { 20 | echo "Script for run a bunch of test on qt-multiple-tests project" 21 | echo "Each test is a directory containing a Qt QTest simple project" 22 | echo "That will be run" 23 | echo "Usage : $PROGNAME [options]" 24 | echo " " 25 | echo "Options : " 26 | echo "--verbose -v : Output compilation and each of project runner" 27 | echo "--clean -c : Clean project directory before compile and after success" 28 | 29 | echo " " 30 | echo "--help -h : Display this Help on usage" 31 | } 32 | 33 | cmdline() { 34 | # got this idea from here: 35 | # http://kirk.webfinish.com/2009/10/bash-shell-script-to-use-getopts-with-gnu-style-long-positional-parameters/ 36 | local arg= 37 | for arg 38 | do 39 | local delim="" 40 | case "$arg" in 41 | #translate --gnu-long-options to -g (short options) 42 | --help) args="${args}-h ";; 43 | --clean) args="${args}-c ";; 44 | --verbose) args="${args}-v ";; 45 | #pass through anything else 46 | *) [[ "${arg:0:1}" == "-" ]] || delim="\"" 47 | args="${args}${delim}${arg}${delim} ";; 48 | esac 49 | done 50 | 51 | #Reset the positional parameters to the short options 52 | eval set -- $args 53 | 54 | while getopts "hvc" OPTION 55 | do 56 | case $OPTION in 57 | h) 58 | usage 59 | exit 0 60 | ;; 61 | v) 62 | readonly MODE_VERBOSE=1 63 | ;; 64 | c) 65 | readonly MODE_CLEANING=1 66 | ;; 67 | esac 68 | done 69 | 70 | return 0 71 | } 72 | 73 | echoWhenVerbose(){ 74 | if [[ -n $MODE_VERBOSE ]]; then 75 | echo $1 76 | fi 77 | } 78 | 79 | projectClean(){ 80 | rm -f $BIN_RUNNER $RUNNER_OUTPUT 81 | rm -f Makefile *.pro 82 | rm -rf moc/ obj/ 83 | rm -rf *.log *.out 84 | } 85 | projectPrepare(){ 86 | qmake -project 87 | echo "include(../base.pri)" >> *.pro 88 | qmake 89 | } 90 | projectCompile(){ 91 | if [[ -n $MODE_VERBOSE ]]; then 92 | make -j4 93 | else 94 | make -j4 1> /dev/null 95 | fi 96 | } 97 | projectRun(){ 98 | 99 | echoWhenVerbose "==> Launch ./$BIN_RUNNER $runnerOptions" 100 | ./$BIN_RUNNER $runnerOptions &> $RUNNER_OUTPUT || true 101 | if [[ -n $MODE_VERBOSE ]]; then 102 | cat $RUNNER_OUTPUT 103 | fi 104 | } 105 | 106 | testConfigurationUnset(){ 107 | runnerOptions="" 108 | checkNbCases="" 109 | # Pseudo-Associative map of checks for log content 110 | unset checksStr 111 | declare -a checksStr 112 | # Pseudo-Associative map of checks for file exists 113 | unset checksFileExist 114 | declare -a checksFileExist 115 | } 116 | 117 | testConfigurationLoad(){ 118 | echoWhenVerbose "=> Load configuration from file" 119 | source $CONFIGURATION_FILENAME 120 | 121 | local re='^[0-9]+$' 122 | if ! [[ $checkNbCases =~ $re ]] ; then 123 | checkNbCases="0" 124 | fi 125 | } 126 | 127 | testChecks(){ 128 | logParse 129 | 130 | testIntEqual $checkNbCases $nbCaseStarted "Number of tests cases" 131 | 132 | for currentCheckStr in "${checksStr[@]}" ; do 133 | local key=${currentCheckStr%%=*} 134 | local value=${currentCheckStr#*=} 135 | testLogContain "$value" "$key" 136 | done 137 | 138 | for currentCheckFileExist in "${checksFileExist[@]}" ; do 139 | local key=${currentCheckFileExist%%=*} 140 | local value=${currentCheckFileExist#*=} 141 | testFileExist "$value" "$key" 142 | done 143 | } 144 | 145 | testCurrentDir(){ 146 | if [ -e "$CONFIGURATION_FILENAME" ]; then 147 | echo "> Case "${dir##*/}" " 148 | 149 | testConfigurationUnset 150 | testConfigurationLoad 151 | 152 | if [[ -n $MODE_CLEANING ]]; then 153 | projectClean 154 | fi 155 | 156 | projectPrepare 157 | projectCompile 158 | projectRun 159 | 160 | testChecks 161 | 162 | if [[ -n $MODE_CLEANING ]]; then 163 | projectClean 164 | fi 165 | fi 166 | 167 | } 168 | 169 | proceedAllTests(){ 170 | for dir in ./tests/*/ 171 | do 172 | dir=${dir%*/} 173 | 174 | cd $dir 175 | testCurrentDir 176 | cd ../../ 177 | 178 | done 179 | } 180 | 181 | main() { 182 | cmdline $ARGS 183 | testConfig 184 | 185 | proceedAllTests 186 | 187 | exit $scriptSuccess 188 | } 189 | 190 | main 191 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /MultiTests.hh: -------------------------------------------------------------------------------- 1 | #ifndef MULTITESTS_H 2 | #define MULTITESTS_H 3 | 4 | #if QT_VERSION >= 0x050000 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #ifndef nullptr 18 | // If C++ is not C++11 compatible 19 | #define nullptr 0 20 | #endif 21 | 22 | namespace MultiTests { 23 | typedef QList TestCasesList; 24 | 25 | inline TestCasesList& allTestCases() { 26 | static TestCasesList list; 27 | return list; 28 | } 29 | 30 | /** 31 | * @brief Try to find Test object into the list of registered ones 32 | * @param object - The object to find 33 | * @return TRUE if object was already registered, FALSE else 34 | */ 35 | inline bool findObject(QObject* object) { 36 | TestCasesList& list = allTestCases(); 37 | if (list.contains(object)) { 38 | return true; 39 | } 40 | foreach (QObject* test, list){ 41 | if (test->metaObject()->className() == object->metaObject()->className()) { 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | /** 49 | * @brief Try to find a test object in list of registered one by it's name 50 | * @param name - The test name to look upon for 51 | * @return A pointer to the QObject* test object if found, or nullptr if no object match that name 52 | */ 53 | inline QObject* findTestByName(QString name){ 54 | TestCasesList& list = allTestCases(); 55 | foreach (QObject* test, list){ 56 | if (test->metaObject()->className() == name) { 57 | return test; 58 | } 59 | } 60 | return nullptr; 61 | } 62 | 63 | /** 64 | * @brief Add a test object to the list of test to run 65 | * @param object - Pointer to object to add to list 66 | */ 67 | inline void addTest(QObject* object) { 68 | if (!findObject(object)) { 69 | allTestCases().append(object); 70 | } 71 | } 72 | /** 73 | * @brief Know if run arguments of program contain an arguments 74 | * @param args - List of arguments 75 | * @param argToFind - The argument to find into all arguments 76 | * @param argIndex - Reference to retrieve the index of list where argument was found 77 | * @param startIndex - The index to start the search, default is 0 78 | * @return TRUE if arguments is find, FALSE else 79 | */ 80 | inline bool argContain(QStringList args,QString argToFind,int& argIndex, 81 | int startIndex = 0){ 82 | 83 | int tempIndex = args.indexOf(argToFind,startIndex); 84 | if( tempIndex!=-1 ){ 85 | argIndex = tempIndex; 86 | return true; 87 | } 88 | return false; 89 | } 90 | 91 | 92 | /** 93 | * @brief Know if a method of an object is a test slot 94 | * @param sl - Reference to QMetaMethod of method to test 95 | * @return TRUE if that method is a test slot, FALSE else 96 | */ 97 | inline bool isValidTestSlot(const QMetaMethod &sl) { 98 | if (sl.access() != QMetaMethod::Private || sl.parameterTypes().size() != 0 99 | /*|| sl.returnType() != QMetaType::Void*/ || sl.methodType() != QMetaMethod::Slot) 100 | return false; 101 | QByteArray name; 102 | #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) 103 | name = QByteArray::fromRawData(sl.signature(),2048); 104 | #else 105 | name = sl.methodSignature(); 106 | #endif 107 | if (name.isEmpty() || name.size()<2 ) 108 | return false; 109 | name.remove(name.size()-2,2); 110 | if (name.endsWith("_data")) 111 | return false; 112 | if (name == "initTestCase" || name == "cleanupTestCase" || name == "cleanup" || name == "init") 113 | return false; 114 | return true; 115 | } 116 | /** 117 | * @brief List all test function of a case 118 | * @param testObj - Pointer to the test object to list 119 | */ 120 | inline void listTestFunctionsFromCase(QObject * testObj){ 121 | qDebug() << "==" << qPrintable(testObj->metaObject()->className()) <<"=="; 122 | for (int i = 0; i < testObj->metaObject()->methodCount(); ++i) { 123 | QMetaMethod sl = testObj->metaObject()->method(i); 124 | if (isValidTestSlot(sl)) { 125 | #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) 126 | qDebug() << sl.signature(); 127 | #else 128 | qDebug() << sl.methodSignature(); 129 | #endif 130 | } 131 | } 132 | } 133 | 134 | /** 135 | * @brief Transform the C arguments list style to a QStringList 136 | * @param argc - Count of arguments 137 | * @param argv - Array of arguments 138 | * @return A QStringList of arguments 139 | */ 140 | inline QStringList argumentsToList(int argc, char *argv[]) { 141 | QStringList argumentsList; 142 | for(int argIndex=0;argIndexmetaObject()->className(); 171 | } 172 | return TestCasesList(); 173 | } 174 | } 175 | 176 | } 177 | else{ 178 | // Run all registered tests 179 | selectedCases = allTestCases(); 180 | } 181 | return selectedCases; 182 | } 183 | 184 | /** 185 | * @brief Update the output filename (-o or --output argument) 186 | * @param arguments - Reference to the list of arguments 187 | * @param caseIndex - Index of current case test 188 | */ 189 | inline void updateOutputFile(QStringList& arguments,int caseIndex){ 190 | int argIndex = 0; 191 | while( argContain(arguments,"-o",argIndex,argIndex) && 192 | (argIndex+1)= 0x050000 227 | qApp->setAttribute(Qt::AA_Use96Dpi, true); 228 | #endif 229 | 230 | 231 | QDateTime start = QDateTime::currentDateTime(); 232 | casesToRun = selectTestCasesToRun(arguments); 233 | 234 | // If option -functions, need a global running 235 | if( arguments.contains("-functions") ){ 236 | foreach (QObject* test, casesToRun){ 237 | listTestFunctionsFromCase(test); 238 | } 239 | return 0; 240 | } 241 | 242 | foreach (QObject* test,casesToRun){ 243 | try { 244 | int currentNbError = QTest::qExec(test,arguments); 245 | if( currentNbError>0 ){ 246 | ret+= currentNbError; 247 | failedTestCase.append( test->metaObject()->className() ); 248 | } 249 | } 250 | catch(...){ 251 | ret++; 252 | failedTestCase.append( test->metaObject()->className() ); 253 | } 254 | caseIndex++; 255 | updateOutputFile(arguments,caseIndex); 256 | } 257 | 258 | int nbMsecs = start.msecsTo( QDateTime::currentDateTime() ); 259 | int nbSecs = start.secsTo( QDateTime::currentDateTime() ); 260 | 261 | if( ret>0 ){ 262 | qCritical() << "========================================"; 263 | qCritical() << "========================================"; 264 | qCritical() << "======= ERRORS during tests !!! ======="; 265 | qCritical() << qPrintable( 266 | QString("%1 error in %2 case(s), over a total of %3 tests cases") 267 | .arg(ret).arg(failedTestCase.size()).arg(casesToRun.size())); 268 | qCritical() << "Case(s) that failed : " << qPrintable(failedTestCase.join(" / ")); 269 | } 270 | else{ 271 | qWarning() << qPrintable( 272 | QString("======= All tests succeed (%1 tests cases) =======").arg(casesToRun.size())); 273 | } 274 | qWarning() << qPrintable( 275 | QString("Executed in %1 seconds (%2 ms)").arg(nbSecs).arg(nbMsecs) 276 | ); 277 | 278 | return ret; 279 | } 280 | } 281 | 282 | 283 | 284 | template 285 | class MultiTests_Case 286 | { 287 | public: 288 | QSharedPointer child; 289 | 290 | MultiTests_Case(const QString& name) : 291 | child(new T) { 292 | child->setObjectName(name); 293 | MultiTests::addTest(child.data()); 294 | } 295 | }; 296 | 297 | #define TEST_DECLARE(className) static MultiTests_Case autoT_##className(#className); 298 | 299 | #define MULTI_TESTS_MAIN_NOAPP \ 300 | int main(int argc, char *argv[]) \ 301 | { \ 302 | srand (time(NULL)); \ 303 | return MultiTests::run(argc, argv); \ 304 | } 305 | 306 | 307 | #define MULTI_TESTS_MAIN \ 308 | int main(int argc, char *argv[]) \ 309 | { \ 310 | QApplication app(argc, argv); \ 311 | srand (time(NULL)); \ 312 | return MultiTests::run(argc, argv); \ 313 | } 314 | 315 | #include 316 | 317 | #ifndef QVERIFY_EXCEPTION_THROWN 318 | // Add to the test function a test on raised exception (and type of it) 319 | // If the function (func) don't raise an exception of (exceptionClass) or a derived, 320 | // Test fail as QFAIL with (description) 321 | #define QVERIFY_EXCEPTION_THROWN( func,exceptionClass ) \ 322 | { \ 323 | bool caught = false; \ 324 | try { \ 325 | func; \ 326 | } catch ( exceptionClass& e ) { \ 327 | if ( typeid( e ) == typeid( exceptionClass ) ) { \ 328 | /*qDebug() << "Caught";*/ \ 329 | } else { \ 330 | /*qDebug() << "Derived exception caught";*/ \ 331 | } \ 332 | caught = true; \ 333 | } catch ( ... ) {} \ 334 | if ( !caught ) { QFAIL(qPrintable(QString("Nothing thrown where expected") )); } \ 335 | } 336 | #endif 337 | 338 | #endif // MULTITESTS_H 339 | --------------------------------------------------------------------------------