Browse Source

Test: Implement simple TestSuite/TestCase

master
Riyyi 3 years ago
parent
commit
4df96a6c75
  1. 10
      test/macro.h
  2. 119
      test/main.cpp
  3. 45
      test/testcase.h
  4. 40
      test/testsuite.cpp
  5. 34
      test/testsuite.h

10
test/macro.h

@ -9,10 +9,12 @@
printf("FAIL: %s:%d: EXPECT(%s) failed\n", __FILE__, __LINE__, #x); \
}
#define EXPECT_EQ(a, b) \
if (a != b) { \
std::cout << "FAIL: " << __FILE__ << ":" << __LINE__ \
<< ": EXPECT_EQ(" << #a << ", " << #b ") failed with lhs=" << a << " and rhs=" << b << std::endl; \
#define EXPECT_EQ(a, b) \
if (a != b) { \
std::cout << "FAIL: " << __FILE__ << ":" << __LINE__ \
<< ": EXPECT_EQ(" << #a << ", " << #b ") failed with" \
<< " lhs='" << a << "' and rhs='" << b << "'" << std::endl; \
Test::TestSuite::the().currentTestCaseFailed(); \
}
#endif // TEST_H

119
test/main.cpp

@ -1,120 +1,8 @@
#include <cstdio> // fopen, printf, stdout
#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;
}
#include "testsuite.h"
int main(int, const char*[])
{
output = stdout;
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, "");
}
Test::TestSuite::the().run();
// // bool tests
// test('o', "option", { "-o" }, true);
@ -150,8 +38,5 @@ int main(int, const char*[])
// ./help -o something -a my-value
// -a has required argument, but something should stop option parsing
printf("Completed running tests\n");
fclose(null);
return 0;
}

45
test/testcase.h

@ -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

40
test/testsuite.cpp

@ -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

34
test/testsuite.h

@ -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
Loading…
Cancel
Save