mirror of
https://github.com/holub/mame
synced 2025-04-23 08:49:55 +03:00
netlist: Add basic unit testing support.
* Add google test syntax compatible unit testing support. This is a very limited subset of the google test framework and not intended ever to be a replacement. Adding a dependency to google test for the functionality required was considered to be an overkill. * nltool -c tests runs unit tests if linked in. This is *not* the case for the version of nltool compiled with TOOLS=1. * Added unit tests for plib::pfunction.
This commit is contained in:
parent
ad6505ba63
commit
9e86f5e866
@ -103,6 +103,7 @@ TARGETS = nltool$(EXESUFFIX) nlwav$(EXESUFFIX)
|
||||
|
||||
NLOBJ = $(OBJ)
|
||||
POBJ = $(OBJ)/plib
|
||||
TESTOBJ = $(OBJ)/tests
|
||||
|
||||
DEPEND = $(OBJ)/.depend
|
||||
|
||||
@ -113,12 +114,13 @@ OBJDIRS = $(OBJ) \
|
||||
$(OBJ)/plib \
|
||||
$(OBJ)/devices \
|
||||
$(OBJ)/macro \
|
||||
$(OBJ)/tests \
|
||||
$(OBJ)/tools \
|
||||
$(OBJ)/prg \
|
||||
$(OBJ)/generated \
|
||||
|
||||
|
||||
OBJS = $(POBJS) $(NLOBJS)
|
||||
OBJS = $(POBJS) $(NLOBJS) $(TESTOBJS)
|
||||
|
||||
POBJS := \
|
||||
$(POBJ)/pstring.o \
|
||||
@ -212,6 +214,9 @@ NLOBJS := \
|
||||
$(NLOBJ)/macro/nlm_roms.o \
|
||||
$(NLOBJ)/macro/nlm_ttl74xx.o \
|
||||
|
||||
TESTOBJS := \
|
||||
$(TESTOBJ)/test_pfunction.o \
|
||||
|
||||
VSBUILDS = \
|
||||
$(VSBUILD/netlistlib.vcxproj) \
|
||||
$(VSBUILD/netlistlib.vcxproj.user \
|
||||
@ -234,7 +239,7 @@ ALL_TIDY_FILES = $(ALL_OBJS:.o=.json)
|
||||
SOURCES = $(patsubst $(OBJ)%, $(SRC)%, $(ALL_OBJS:.o=.cpp))
|
||||
ALLFILES = $(SOURCES) $(VSBUILDS) $(DOCS)
|
||||
|
||||
MAKEFILE_TARGETS_WITHOUT_INCLUDE := gcc9 clang clang-5 mingw doc native maketree tidy
|
||||
MAKEFILE_TARGETS_WITHOUT_INCLUDE := gcc9 clang clang-5 mingw doc native maketree tidy runtests
|
||||
|
||||
|
||||
# git archive HEAD --prefix=project-name-version/ \
|
||||
@ -244,7 +249,7 @@ MAKEFILE_TARGETS_WITHOUT_INCLUDE := gcc9 clang clang-5 mingw doc native maketree
|
||||
# PHONY
|
||||
#-------------------------------------------------
|
||||
|
||||
.PHONY: all gcc9 clang clang-5 mingw doc native maketree $(DEPEND) depend
|
||||
.PHONY: all gcc9 clang clang-5 mingw doc native maketree $(DEPEND) depend runtests
|
||||
|
||||
#-------------------------------------------------
|
||||
# all
|
||||
@ -328,6 +333,9 @@ nvcc:
|
||||
-Xcompiler -O6 -Xcompiler -march=native -ccbin g++-8 " \
|
||||
DEPENDCC=g++
|
||||
|
||||
runtests:
|
||||
./nltool$(EXESUFFIX) -c tests
|
||||
|
||||
tidy_db: compile_commands_prefix $(ALL_TIDY_FILES) compile_commands_postfix
|
||||
|
||||
#
|
||||
|
140
src/lib/netlist/plib/ptests.h
Normal file
140
src/lib/netlist/plib/ptests.h
Normal file
@ -0,0 +1,140 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
#ifndef PTESTS_H_
|
||||
#define PTESTS_H_
|
||||
|
||||
///
|
||||
/// \file ptests.h
|
||||
///
|
||||
/// google tests compatible (hopefully) test macros. This is work in progress!
|
||||
///
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
#define EXPECT_EQ(exp1, exp2) PINT_EXPECT(eq, exp1, exp2)
|
||||
#define EXPECT_NE(exp1, exp2) PINT_EXPECT(ne, exp1, exp2)
|
||||
#define EXPECT_GT(exp1, exp2) PINT_EXPECT(gt, exp1, exp2)
|
||||
#define EXPECT_LT(exp1, exp2) PINT_EXPECT(lt, exp1, exp2)
|
||||
#define EXPECT_GE(exp1, exp2) PINT_EXPECT(ge, exp1, exp2)
|
||||
#define EXPECT_LE(exp1, exp2) PINT_EXPECT(le, exp1, exp2)
|
||||
|
||||
#define EXPECT_TRUE(exp1) PINT_EXPECT(eq, exp1, true)
|
||||
#define EXPECT_FALSE(exp1) PINT_EXPECT(eq, exp1, false)
|
||||
|
||||
#define TEST(name, desc) PINT_TEST(name, desc)
|
||||
#define TEST_F(name, desc) PINT_TEST_F(name, desc, name)
|
||||
#define RUN_ALL_TESTS() plib::testing::run_all_tests()
|
||||
|
||||
#define PINT_TEST(name, desc) PINT_TEST_F(name, desc, plib::testing::Test)
|
||||
|
||||
#define PINT_TEST_F(name, desc, base) \
|
||||
class name ## _ ## desc : public base \
|
||||
{ public:\
|
||||
void desc (); \
|
||||
void run() override { desc (); } \
|
||||
}; \
|
||||
plib::testing::reg_entry<name ## _ ## desc> name ## _ ## desc ## _reg(#name, #desc); \
|
||||
void name ## _ ## desc :: desc ()
|
||||
|
||||
#define PINT_EXPECT(comp, exp1, exp2) \
|
||||
if (!plib::testing::internal_assert(plib::testing::comp_ ## comp (), # exp1, # exp2, exp1, exp2)) \
|
||||
std::cout << __FILE__ << ":" << __LINE__ << ":1: error: test failed\n";
|
||||
|
||||
namespace plib
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
|
||||
class Test
|
||||
{
|
||||
public:
|
||||
virtual ~Test() {}
|
||||
virtual void run() {}
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
struct reg_entry_base
|
||||
{
|
||||
using list_t = std::vector<reg_entry_base *>;
|
||||
reg_entry_base(const std::string &n, const std::string &d)
|
||||
: name(n), desc(d)
|
||||
{
|
||||
registry().push_back(this);
|
||||
}
|
||||
virtual ~reg_entry_base() = default;
|
||||
virtual Test *create() { return nullptr; }
|
||||
|
||||
std::string name;
|
||||
std::string desc;
|
||||
public:
|
||||
static list_t & registry()
|
||||
{
|
||||
static list_t prlist;
|
||||
return prlist;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct reg_entry : public reg_entry_base
|
||||
{
|
||||
using reg_entry_base::reg_entry_base;
|
||||
|
||||
virtual Test *create() override { return new T(); }
|
||||
};
|
||||
|
||||
template <typename C, typename T1, typename T2>
|
||||
bool internal_assert(C comp,
|
||||
const char* exp1, const char* exp2,
|
||||
const T1& val1, const T2& val2)
|
||||
{
|
||||
if (comp(val1, val2))
|
||||
{
|
||||
std::cout << "\tOK: " << exp1 << " " << C::opstr() << " " << exp2 << "\n";
|
||||
return true;
|
||||
}
|
||||
std::cout << "\tFAIL: " << exp1 << " " << C::opstr() << " " << exp2
|
||||
<< " <" << val1 << ">,<" << val2 << ">\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int run_all_tests()
|
||||
{
|
||||
for (auto &e : reg_entry_base::registry())
|
||||
{
|
||||
std::cout << e->name << "::" << e->desc << ":\n";
|
||||
Test *t = e->create();
|
||||
t->SetUp();
|
||||
t->run();
|
||||
t->TearDown();
|
||||
delete t;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define DEF_COMP(name, op) \
|
||||
struct comp_ ## name \
|
||||
{ \
|
||||
static const char * opstr() { return #op ; } \
|
||||
template <typename T1, typename T2> \
|
||||
bool operator()(const T1 &v1, const T2 &v2) { return v1 op v2; } \
|
||||
}; \
|
||||
|
||||
DEF_COMP(eq, ==)
|
||||
DEF_COMP(ne, !=)
|
||||
DEF_COMP(gt, >)
|
||||
DEF_COMP(lt, <)
|
||||
DEF_COMP(ge, >=)
|
||||
DEF_COMP(le, <=)
|
||||
|
||||
#undef DEF_COMP
|
||||
|
||||
} // namespace testing
|
||||
} // namespace plib
|
||||
|
||||
|
||||
#endif // PTESTS_H_
|
@ -20,6 +20,8 @@
|
||||
#include "netlist/solver/nld_solver.h"
|
||||
#include "netlist/tools/nl_convert.h"
|
||||
|
||||
#include "plib/ptests.h"
|
||||
|
||||
#include <cstdio> // scanf
|
||||
#include <iomanip> // scanf
|
||||
#include <ios>
|
||||
@ -44,7 +46,7 @@ public:
|
||||
m_errors(0),
|
||||
|
||||
opt_grp1(*this, "General options", "The following options apply to all commands."),
|
||||
opt_cmd (*this, "c", "cmd", 0, std::vector<pstring>({"run","validate","convert","listdevices","static","header","docheader"}), "run|validate|convert|listdevices|static|header|docheader"),
|
||||
opt_cmd (*this, "c", "cmd", 0, std::vector<pstring>({"run","validate","convert","listdevices","static","header","docheader","tests"}), "run|validate|convert|listdevices|static|header|docheader|tests"),
|
||||
opt_includes(*this, "I", "include", "Add the directory to the list of directories to be searched for header files. This option may be specified repeatedly."),
|
||||
opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."),
|
||||
opt_rfolders(*this, "r", "rom", "where to look for data files"),
|
||||
@ -94,7 +96,9 @@ public:
|
||||
opt_ex3(*this, "nltool --cmd=header --tab-width=8 --line-width=80",
|
||||
"Create the header file needed for including netlists as code."),
|
||||
opt_ex4(*this, "nltool --cmd static --output src/lib/netlist/generated/static_solvers.cpp src/mame/audio/nl_*.cpp src/mame/machine/nl_*.cpp",
|
||||
"Create static solvers for the MAME project.")
|
||||
"Create static solvers for the MAME project."),
|
||||
opt_ex5(*this, "nltool --cmd tests",
|
||||
"Run unit tests. In case the unit tests are not linked in, this will do nothing.")
|
||||
{}
|
||||
|
||||
int execute() override;
|
||||
@ -158,6 +162,7 @@ private:
|
||||
plib::option_example opt_ex2;
|
||||
plib::option_example opt_ex3;
|
||||
plib::option_example opt_ex4;
|
||||
plib::option_example opt_ex5;
|
||||
|
||||
struct compile_map_entry
|
||||
{
|
||||
@ -1267,6 +1272,10 @@ int tool_app_t::execute()
|
||||
create_docheader();
|
||||
else if (cmd == "convert")
|
||||
convert();
|
||||
else if (cmd == "tests")
|
||||
{
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
else
|
||||
{
|
||||
perr("Unknown command {}\n", cmd.c_str());
|
||||
|
43
src/lib/netlist/tests/test_pfunction.cpp
Normal file
43
src/lib/netlist/tests/test_pfunction.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
|
||||
///
|
||||
/// \file pfunction_test.cpp
|
||||
///
|
||||
/// tests for pfunction
|
||||
///
|
||||
|
||||
#include "plib/ptests.h"
|
||||
|
||||
#include "plib/pfunction.h"
|
||||
|
||||
#define PFUNCEXPECT(formula, val) \
|
||||
EXPECT_EQ(val, plib::pfunction<double>(formula)());
|
||||
|
||||
TEST(pfunction, operators)
|
||||
{
|
||||
PFUNCEXPECT("1==1", 1.0)
|
||||
PFUNCEXPECT("1 *0 == 2-1-1", 1.0)
|
||||
PFUNCEXPECT("0!=1", 1.0)
|
||||
PFUNCEXPECT("0<1", 1.0)
|
||||
PFUNCEXPECT("1>0", 1.0)
|
||||
PFUNCEXPECT("0<=1", 1.0)
|
||||
PFUNCEXPECT("1>=0", 1.0)
|
||||
PFUNCEXPECT("1<=1", 1.0)
|
||||
PFUNCEXPECT("1>=1", 1.0)
|
||||
EXPECT_EQ(1.0, plib::pfunction<double>("0!=a", {"a"})({1.0}));
|
||||
}
|
||||
|
||||
TEST(pfunction, func_if)
|
||||
{
|
||||
PFUNCEXPECT("if(1>0, 2, 0)", 2.0)
|
||||
PFUNCEXPECT("if(0>1, 2, 3)", 3.0)
|
||||
PFUNCEXPECT("if(sin(1)>0, 2, 3)", 3.0) // fail
|
||||
EXPECT_EQ( 1.0, plib::pfunction<double>("if(A2>2.5, 0-A1, (0.07-(0.005*A1))*if(A0>2.5,1,0-1))", {"A0","A1","A2"})({1.0,-1.0,3.0}));
|
||||
EXPECT_EQ(-0.065, plib::pfunction<double>("if(A2>2.5, 0-A1, (0.07-(0.005*A1))*if(A0>2.5,1,0-1))", {"A0","A1","A2"})({1.0,1.0,1.0}));
|
||||
EXPECT_EQ( 0.065, plib::pfunction<double>("if(A2>2.5, 0-A1, (0.07-(0.005*A1))*if(A0>2.5,1,0-1))", {"A0","A1","A2"})({3.0,1.0,1.0}));
|
||||
//EXPECT(plib::pfunction<double>("if(A2>2.5, A1, if(A0>2.5,1,(0-1)))", {"A0","A1","A2"})({1.0,1.0,1.0}), -1.0)
|
||||
//PFUNCEXPECT("-1>-2", 1.0)
|
||||
EXPECT_TRUE(1.0 == plib::pfunction<double>("0!=a", {"a"})({1.0}));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user