1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-09-01 18:32:37 +02:00

Added yaml tree builder tests. Fixed nasty bug in parser handler.

This commit is contained in:
Stefan de Bruijn
2021-06-04 23:00:46 +02:00
parent 869b2aea8d
commit d316af61ab
6 changed files with 265 additions and 23 deletions

View File

@@ -110,6 +110,7 @@ namespace Configuration {
if (last == token_.indent_) {
// Yes, the token continues where we left off:
current_ = token_;
// Tokenize();
} else {
current_ = TokenData();
current_.indent_ = last;

View File

@@ -28,66 +28,86 @@
namespace Configuration {
class ParserHandler : public Configuration::HandlerBase {
private:
Configuration::Parser& parser_;
Configuration::Parser& _parser;
bool _previousIsLeave = false;
void checkPreviousLeave() {
// When a section does a 'leave', the token becomes invalid, and we need to do a
// moveNext. See the tests for the yaml parser for what the parser expects.
// So, let's introduce that here:
if (_previousIsLeave) {
_parser.moveNext();
}
_previousIsLeave = false;
}
protected:
void handleDetail(const char* name, Configuration::Configurable* value) override {
if (value != nullptr && parser_.is(name)) {
if (value != nullptr && _parser.is(name)) {
log_debug("Parsing configurable " << name);
checkPreviousLeave();
parser_.enter();
for (; !parser_.isEndSection(); parser_.moveNext()) {
_parser.enter();
for (; !_parser.isEndSection(); _parser.moveNext()) {
value->handle(*this);
}
parser_.leave();
_parser.leave();
_previousIsLeave = true;
}
}
bool matchesUninitialized(const char* name) override { return parser_.is(name); }
bool matchesUninitialized(const char* name) override { return _parser.is(name); }
public:
ParserHandler(Configuration::Parser& parser) : parser_(parser) {}
ParserHandler(Configuration::Parser& parser) : _parser(parser) {}
void handle(const char* name, int32_t& value, int32_t minValue, int32_t maxValue) override {
if (parser_.is(name)) {
value = parser_.intValue();
if (_parser.is(name)) {
checkPreviousLeave();
value = _parser.intValue();
}
}
void handle(const char* name, int& value, EnumItem* e) override {
if (parser_.is(name)) {
value = parser_.enumValue(e);
if (_parser.is(name)) {
checkPreviousLeave();
value = _parser.enumValue(e);
}
}
void handle(const char* name, bool& value) override {
if (parser_.is(name)) {
value = parser_.boolValue();
if (_parser.is(name)) {
checkPreviousLeave();
value = _parser.boolValue();
}
}
void handle(const char* name, float& value, float minValue, float maxValue) override {
if (parser_.is(name)) {
value = parser_.floatValue();
if (_parser.is(name)) {
checkPreviousLeave();
value = _parser.floatValue();
}
}
void handle(const char* name, StringRange& value, int minLength, int maxLength) override {
if (parser_.is(name)) {
value = parser_.stringValue();
if (_parser.is(name)) {
checkPreviousLeave();
value = _parser.stringValue();
}
}
void handle(const char* name, Pin& value) override {
if (parser_.is(name)) {
auto parsed = parser_.pinValue();
if (_parser.is(name)) {
checkPreviousLeave();
auto parsed = _parser.pinValue();
value.swap(parsed);
}
}
void handle(const char* name, IPAddress& value) override {
if (parser_.is(name)) {
value = parser_.ipValue();
if (_parser.is(name)) {
checkPreviousLeave();
value = _parser.ipValue();
}
}

View File

@@ -23,7 +23,7 @@
# include <iostream>
DebugStream::DebugStream(const char* name) {
std::cout << '[MSG:' << name << ": ";
std::cout << "[MSG:" << name << ": ";
}
void DebugStream::add(char c) {
std::cout << c;

View File

@@ -0,0 +1,199 @@
#include "../TestFramework.h"
#include <string>
#include <src/Configuration/Tokenizer.h>
#include <src/Configuration/Parser.h>
#include <src/Configuration/ParserHandler.h>
#include <src/Configuration/Configurable.h>
namespace Configuration {
class TestBasic : public Configurable {
public:
String a;
String b;
String c;
void validate() const {}
void handle(HandlerBase& handler) {
handler.handle("a", a);
handler.handle("b", b);
handler.handle("c", c);
}
};
class TestBasic2 : public Configurable {
public:
String aap;
int banaan;
void validate() const {}
void handle(HandlerBase& handler) {
handler.handle("aap", aap);
handler.handle("banaan", banaan);
}
};
class TestHierarchical : public Configurable {
public:
TestBasic* n1 = nullptr;
TestBasic2* n2 = nullptr;
int foo = 0;
void validate() const {}
void handle(HandlerBase& handler) {
handler.handle("n1", n1);
handler.handle("n2", n2);
handler.handle("foo", foo);
}
};
struct Helper {
template <typename T>
static inline void Parse(const char* config, T& test) {
Parser p(config, config + strlen(config));
ParserHandler handler(p);
test.handle(handler);
for (; !p.isEndSection(); p.moveNext()) {
test.handle(handler);
}
}
};
Test(YamlTreeBuilder, BasicProperties) {
const char* config = "a: aap\n"
"b: banaan\n"
"\n"
"c: chocolade";
TestBasic test;
Helper::Parse(config, test);
Assert(test.a == "aap");
Assert(test.b == "banaan");
Assert(test.c == "chocolade");
}
Test(YamlTreeBuilder, BasicPropertiesInvert) {
const char* config = "c: chocolade\n"
"b: banaan\n"
"a: aap\n";
TestBasic test;
Helper::Parse(config, test);
Assert(test.a == "aap");
Assert(test.b == "banaan");
Assert(test.c == "chocolade");
}
Test(YamlTreeBuilder, BasicProperties2) {
const char* config = "aap: aap\n"
"banaan: 2\n";
TestBasic2 test;
Helper::Parse(config, test);
Assert(test.aap == "aap");
Assert(test.banaan == 2);
}
Test(YamlTreeBuilder, BasicPropertiesInvert2) {
const char* config = "banaan: 2\n"
"aap: aap\n";
TestBasic2 test;
Helper::Parse(config, test);
Assert(test.aap == "aap");
Assert(test.banaan == 2);
}
Test(YamlTreeBuilder, Hierarchical1) {
const char* config = "n1:\n"
" a: aap\n"
" b: banaan\n"
" \n"
" c: chocolade\n"
"n2:\n"
" banaan: 2\n"
" aap: aap\n"
"foo: 2\n";
TestHierarchical test;
Helper::Parse(config, test);
{
Assert(test.n1 != nullptr);
Assert(test.n1->a == "aap");
Assert(test.n1->b == "banaan");
Assert(test.n1->c == "chocolade");
}
{
Assert(test.n2 != nullptr);
Assert(test.n2->banaan == 2);
Assert(test.n2->aap == "aap");
}
Assert(test.foo == 2);
}
Test(YamlTreeBuilder, Hierarchical2) {
const char* config = "n2:\n"
" banaan: 2\n"
" aap: aap\n"
"n1:\n"
" a: aap\n"
" b: banaan\n"
" \n"
" c: chocolade\n"
"foo: 2\n";
TestHierarchical test;
Helper::Parse(config, test);
{
Assert(test.n1 != nullptr);
Assert(test.n1->a == "aap");
Assert(test.n1->b == "banaan");
Assert(test.n1->c == "chocolade");
}
{
Assert(test.n2 != nullptr);
Assert(test.n2->banaan == 2);
Assert(test.n2->aap == "aap");
}
Assert(test.foo == 2);
}
Test(YamlTreeBuilder, Hierarchical3) {
const char* config = "foo: 2\n"
"n2:\n"
" banaan: 2\n"
" aap: aap\n"
"n1:\n"
" a: aap\n"
" b: banaan\n"
" \n"
" c: chocolade\n";
TestHierarchical test;
Helper::Parse(config, test);
{
Assert(test.n1 != nullptr);
Assert(test.n1->a == "aap");
Assert(test.n1->b == "banaan");
Assert(test.n1->c == "chocolade");
}
{
Assert(test.n2 != nullptr);
Assert(test.n2->banaan == 2);
Assert(test.n2->aap == "aap");
}
Assert(test.foo == 2);
}
}

View File

@@ -44,6 +44,7 @@
<ClInclude Include="Grbl_Esp32\src\Configuration\ParserHandler.h" />
<ClInclude Include="Grbl_Esp32\src\Configuration\Tokenizer.h" />
<ClInclude Include="Grbl_Esp32\src\Configuration\TokenKind.h" />
<ClInclude Include="Grbl_Esp32\src\Logging.h" />
<ClInclude Include="Grbl_Esp32\src\Pin.h" />
<ClInclude Include="Grbl_Esp32\src\Pins\ErrorPinDetail.h" />
<ClInclude Include="Grbl_Esp32\src\Pins\GPIOPinDetail.h" />
@@ -53,6 +54,7 @@
<ClInclude Include="Grbl_Esp32\src\Pins\PinDetail.h" />
<ClInclude Include="Grbl_Esp32\src\Pins\PinOptionsParser.h" />
<ClInclude Include="Grbl_Esp32\src\Pins\VoidPinDetail.h" />
<ClInclude Include="Grbl_Esp32\src\SimpleOutputStream.h" />
<ClInclude Include="Grbl_Esp32\src\StackTrace\AssertionFailed.h" />
<ClInclude Include="Grbl_Esp32\src\StackTrace\debug_helpers.h" />
<ClInclude Include="Grbl_Esp32\test\TestFactory.h" />
@@ -65,6 +67,7 @@
<ItemGroup>
<ClCompile Include="Grbl_Esp32\src\Configuration\Parser.cpp" />
<ClCompile Include="Grbl_Esp32\src\Configuration\Tokenizer.cpp" />
<ClCompile Include="Grbl_Esp32\src\Logging.cpp" />
<ClCompile Include="Grbl_Esp32\src\Pin.cpp" />
<ClCompile Include="Grbl_Esp32\src\Pins\ErrorPinDetail.cpp" />
<ClCompile Include="Grbl_Esp32\src\Pins\GPIOPinDetail.cpp" />
@@ -74,10 +77,12 @@
<ClCompile Include="Grbl_Esp32\src\Pins\PinDetail.cpp" />
<ClCompile Include="Grbl_Esp32\src\Pins\PinOptionsParser.cpp" />
<ClCompile Include="Grbl_Esp32\src\Pins\VoidPinDetail.cpp" />
<ClCompile Include="Grbl_Esp32\src\SimpleOutputStream.cpp" />
<ClCompile Include="Grbl_Esp32\src\StackTrace\AssertionFailed.cpp" />
<ClCompile Include="Grbl_Esp32\src\StackTrace\debug_helpers.cpp" />
<ClCompile Include="Grbl_Esp32\test\Configuration\YamlComplete.cpp" />
<ClCompile Include="Grbl_Esp32\test\Configuration\YamlParser.cpp" />
<ClCompile Include="Grbl_Esp32\test\Configuration\YamlTreeBuilder.cpp" />
<ClCompile Include="Grbl_Esp32\test\Pins\BasicGPIO.cpp" />
<ClCompile Include="Grbl_Esp32\test\Pins\Error.cpp" />
<ClCompile Include="Grbl_Esp32\test\Pins\GPIO.cpp" />

View File

@@ -93,6 +93,12 @@
<ClInclude Include="X86TestSupport\IPAddress.h">
<Filter>X86TestSupport</Filter>
</ClInclude>
<ClInclude Include="Grbl_Esp32\src\SimpleOutputStream.h">
<Filter>src</Filter>
</ClInclude>
<ClInclude Include="Grbl_Esp32\src\Logging.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Grbl_Esp32\test\TestFrameworkTest.cpp">
@@ -170,7 +176,18 @@
<ClCompile Include="Grbl_Esp32\src\Configuration\Parser.cpp">
<Filter>src\Configuration</Filter>
</ClCompile>
<ClCompile Include="Grbl_Esp32\test\Configuration\YamlComplete.cpp" />
<ClCompile Include="Grbl_Esp32\test\Configuration\YamlComplete.cpp">
<Filter>test\Configuration</Filter>
</ClCompile>
<ClCompile Include="Grbl_Esp32\test\Configuration\YamlTreeBuilder.cpp">
<Filter>test\Configuration</Filter>
</ClCompile>
<ClCompile Include="Grbl_Esp32\src\SimpleOutputStream.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="Grbl_Esp32\src\Logging.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Grbl_Esp32\test\UnitTests.md">