Test: Implement simple TestSuite/TestCase
This commit is contained in:
+6
-4
@@ -9,10 +9,12 @@
|
|||||||
printf("FAIL: %s:%d: EXPECT(%s) failed\n", __FILE__, __LINE__, #x); \
|
printf("FAIL: %s:%d: EXPECT(%s) failed\n", __FILE__, __LINE__, #x); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EXPECT_EQ(a, b) \
|
#define EXPECT_EQ(a, b) \
|
||||||
if (a != b) { \
|
if (a != b) { \
|
||||||
std::cout << "FAIL: " << __FILE__ << ":" << __LINE__ \
|
std::cout << "FAIL: " << __FILE__ << ":" << __LINE__ \
|
||||||
<< ": EXPECT_EQ(" << #a << ", " << #b ") failed with lhs=" << a << " and rhs=" << b << std::endl; \
|
<< ": EXPECT_EQ(" << #a << ", " << #b ") failed with" \
|
||||||
|
<< " lhs='" << a << "' and rhs='" << b << "'" << std::endl; \
|
||||||
|
Test::TestSuite::the().currentTestCaseFailed(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TEST_H
|
#endif // TEST_H
|
||||||
|
|||||||
+2
-117
@@ -1,120 +1,8 @@
|
|||||||
#include <cstdio> // fopen, printf, stdout
|
#include "testsuite.h"
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "macro.h"
|
|
||||||
#include "util/argparser.h"
|
|
||||||
|
|
||||||
FILE* output;
|
|
||||||
FILE* null;
|
|
||||||
|
|
||||||
bool runParser(std::vector<const char*> arguments, std::function<void(Util::ArgParser&)> initializer = {})
|
|
||||||
{
|
|
||||||
stdout = null;
|
|
||||||
|
|
||||||
Util::ArgParser parser;
|
|
||||||
if (initializer) {
|
|
||||||
initializer(parser);
|
|
||||||
}
|
|
||||||
|
|
||||||
arguments.insert(arguments.begin(), "app");
|
|
||||||
auto result = parser.parse(arguments.size(), arguments.data());
|
|
||||||
|
|
||||||
stdout = output;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int, const char*[])
|
int main(int, const char*[])
|
||||||
{
|
{
|
||||||
output = stdout;
|
Test::TestSuite::the().run();
|
||||||
null = fopen("/dev/null", "w"); // Windows: nul
|
|
||||||
|
|
||||||
printf("Test project\n");
|
|
||||||
|
|
||||||
// No arguments
|
|
||||||
{
|
|
||||||
auto result = runParser({});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool options
|
|
||||||
{
|
|
||||||
// Short option
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
auto result = runParser({ "-b" }, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, 'b', nullptr, nullptr, nullptr);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, true);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Short option, not given
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
auto result = runParser({}, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, 'b', nullptr, nullptr, nullptr);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, false);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Long option
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
auto result = runParser({ "--bool" }, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, '\0', "bool", nullptr, nullptr);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, true);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Long option, not given
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
auto result = runParser({}, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, '\0', "bool", nullptr, nullptr);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, false);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Allow both short and long option, provide short
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
auto result = runParser({ "-b" }, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, 'b', "bool", nullptr, nullptr);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, true);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Allow both short and long option, provide long
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
auto result = runParser({ "--bool" }, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, 'b', "bool", nullptr, nullptr);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, true);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Allow both short and long option, provide both
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
auto result = runParser({ "-b", "--bool" }, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, 'b', "bool", nullptr, nullptr);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ..
|
|
||||||
{
|
|
||||||
//
|
|
||||||
bool boolOpt1 = false;
|
|
||||||
std::string stringOpt1 = "";
|
|
||||||
auto result = runParser({ "-b", "something", "-s", "my-value" }, [&](auto& parser) {
|
|
||||||
parser.addOption(boolOpt1, 'b', nullptr, nullptr, nullptr);
|
|
||||||
parser.addOption(stringOpt1, 's', nullptr, nullptr, nullptr, nullptr, Util::ArgParser::Required::Yes);
|
|
||||||
});
|
|
||||||
EXPECT_EQ(result, true);
|
|
||||||
EXPECT_EQ(boolOpt1, true);
|
|
||||||
EXPECT_EQ(stringOpt1, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// // bool tests
|
// // bool tests
|
||||||
// test('o', "option", { "-o" }, true);
|
// test('o', "option", { "-o" }, true);
|
||||||
@@ -150,8 +38,5 @@ int main(int, const char*[])
|
|||||||
// ./help -o something -a my-value
|
// ./help -o something -a my-value
|
||||||
// -a has required argument, but something should stop option parsing
|
// -a has required argument, but something should stop option parsing
|
||||||
|
|
||||||
printf("Completed running tests\n");
|
|
||||||
|
|
||||||
fclose(null);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef TEST_CASE_H
|
||||||
|
#define TEST_CASE_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define __TEST_CASE_FUNCTION(x) __test##x
|
||||||
|
#define __TEST_CASE_STRUCT(x) __testStruct##x
|
||||||
|
|
||||||
|
#define TEST_CASE(x) \
|
||||||
|
static void __TEST_CASE_FUNCTION(x)(); \
|
||||||
|
struct __TEST_CASE_STRUCT(x) { \
|
||||||
|
__TEST_CASE_STRUCT(x) \
|
||||||
|
() \
|
||||||
|
{ \
|
||||||
|
Test::TestSuite::the().addCase( \
|
||||||
|
*new Test::TestCase(#x, __TEST_CASE_FUNCTION(x))); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
static struct __TEST_CASE_STRUCT(x) __TEST_CASE_STRUCT(x); \
|
||||||
|
static void __TEST_CASE_FUNCTION(x)()
|
||||||
|
|
||||||
|
namespace Test {
|
||||||
|
|
||||||
|
using testFunction = std::function<void()>;
|
||||||
|
|
||||||
|
class TestCase {
|
||||||
|
public:
|
||||||
|
TestCase(const char* name, testFunction&& function)
|
||||||
|
: m_name(name)
|
||||||
|
, m_function(function)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name() const { return m_name; }
|
||||||
|
const testFunction& function() const { return m_function; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_name { nullptr };
|
||||||
|
testFunction m_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Test
|
||||||
|
|
||||||
|
#endif // TEST_CASE_H
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include <cstddef> // size_t
|
||||||
|
#include <cstdio> // fclose, fopen, printf, stdout
|
||||||
|
|
||||||
|
#include "testsuite.h"
|
||||||
|
|
||||||
|
namespace Test {
|
||||||
|
|
||||||
|
TestSuite::TestSuite(s)
|
||||||
|
{
|
||||||
|
m_outputStd = stdout;
|
||||||
|
m_outputNull = fopen("/dev/null", "w"); // Windows: nul
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSuite::~TestSuite()
|
||||||
|
{
|
||||||
|
fclose(m_outputNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSuite::run()
|
||||||
|
{
|
||||||
|
printf("TestSuite: %d cases have been added!\n", (int)m_cases.size());
|
||||||
|
|
||||||
|
size_t caseFailedCount = 0;
|
||||||
|
|
||||||
|
for(auto& testCase : m_cases) {
|
||||||
|
printf("%s\n", testCase.name());
|
||||||
|
m_currentTestCasePassed = true;
|
||||||
|
|
||||||
|
testCase.function()();
|
||||||
|
|
||||||
|
if (!m_currentTestCasePassed) {
|
||||||
|
caseFailedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int percentagePassed = (1 - caseFailedCount / (float)m_cases.size()) * 100;
|
||||||
|
printf("Passed %d%% of tests\n", percentagePassed);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Test
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef TEST_SUITE_H
|
||||||
|
#define TEST_SUITE_H
|
||||||
|
|
||||||
|
#include <cstdio> // FILE
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "testcase.h"
|
||||||
|
#include "util/singleton.h"
|
||||||
|
|
||||||
|
namespace Test {
|
||||||
|
|
||||||
|
class TestSuite final : public Util::Singleton<TestSuite> {
|
||||||
|
public:
|
||||||
|
TestSuite(s);
|
||||||
|
virtual ~TestSuite();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void addCase(const TestCase& testCase) { m_cases.push_back(testCase); }
|
||||||
|
void currentTestCaseFailed() { m_currentTestCasePassed = false; }
|
||||||
|
|
||||||
|
FILE* outputStd() const { return m_outputStd; }
|
||||||
|
FILE* outputNull() const { return m_outputNull; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_currentTestCasePassed { true };
|
||||||
|
FILE* m_outputStd { nullptr };
|
||||||
|
FILE* m_outputNull { nullptr };
|
||||||
|
|
||||||
|
std::vector<TestCase> m_cases;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Test
|
||||||
|
|
||||||
|
#endif // TEST_SUITE_H
|
||||||
Reference in New Issue
Block a user