launch_daemon: Started working on condition parsing.

* Moved related test code from DriverSettingsMessageAdapterTest to the
  SettingsParser class.
* Added SettingsParserTest class -- most tests already succeed, but not
  all; support for the flattened "not" is not working yet.
This commit is contained in:
Axel Dörfler
2015-07-22 20:42:32 +02:00
parent 68a3c0f919
commit e73c936699
8 changed files with 376 additions and 57 deletions
+82 -8
View File
@@ -9,6 +9,65 @@
#include <DriverSettingsMessageAdapter.h>
class ConditionConverter : public DriverSettingsConverter {
public:
status_t ConvertFromDriverSettings(const driver_parameter& parameter,
const char* name, int32 index, uint32 type, BMessage& target)
{
BMessage message;
if (strcmp(parameter.name, "if") == 0) {
// Parse values directly following "if", with special
// handling for the "not" operator.
if (index != 0)
return B_OK;
BMessage* add = &target;
bool not = parameter.value_count > 1
&& strcmp(parameter.values[0], "not") == 0;
if (not) {
add = &message;
index++;
}
const char* condition = parameter.values[index];
BMessage args;
for (index++; index < parameter.value_count; index++) {
status_t status = args.AddString("args",
parameter.values[index]);
if (status != B_OK)
return status;
}
status_t status = add->AddMessage(condition, &args);
if (status == B_OK && not)
status = target.AddMessage("not", &message);
return status;
}
message.AddString("args", parameter.values[index]);
return target.AddMessage(parameter.name, &message);
}
status_t ConvertEmptyFromDriverSettings(
const driver_parameter& parameter, const char* name, uint32 type,
BMessage& target)
{
if (parameter.parameter_count != 0)
return B_OK;
BMessage message;
return target.AddMessage(name, &message);
}
};
const static settings_template kConditionTemplate[] = {
{B_STRING_TYPE, NULL, NULL, true, new ConditionConverter()},
{B_MESSAGE_TYPE, "not", kConditionTemplate},
{B_MESSAGE_TYPE, "and", kConditionTemplate},
{B_MESSAGE_TYPE, "or", kConditionTemplate},
{0, NULL, NULL}
};
const static settings_template kPortTemplate[] = {
{B_STRING_TYPE, "name", NULL, true},
{B_INT32_TYPE, "capacity", NULL},
@@ -21,18 +80,11 @@ const static settings_template kJobTemplate[] = {
{B_STRING_TYPE, "requires", NULL},
{B_BOOL_TYPE, "legacy", NULL},
{B_MESSAGE_TYPE, "port", kPortTemplate},
{B_MESSAGE_TYPE, "if", kConditionTemplate},
{B_BOOL_TYPE, "no_safemode", NULL},
{0, NULL, NULL}
};
const static settings_template kConditionTemplate[] = {
{B_STRING_TYPE, NULL, NULL, true},
{B_MESSAGE_TYPE, "not", kConditionTemplate},
{B_MESSAGE_TYPE, "and", kConditionTemplate},
{B_MESSAGE_TYPE, "or", kConditionTemplate},
{0, NULL, NULL}
};
const static settings_template kTargetTemplate[] = {
{B_STRING_TYPE, "name", NULL, true},
{B_BOOL_TYPE, "reset", NULL},
@@ -61,3 +113,25 @@ SettingsParser::ParseFile(const char* path, BMessage& settings)
DriverSettingsMessageAdapter adapter;
return adapter.ConvertFromDriverSettings(path, kSettingsTemplate, settings);
}
#ifdef TEST_HAIKU
status_t
SettingsParser::Parse(const char* text, BMessage& settings)
{
void* driverSettings = parse_driver_settings_string(text);
if (driverSettings == NULL)
return B_BAD_VALUE;
DriverSettingsMessageAdapter adapter;
status_t status = adapter.ConvertFromDriverSettings(
*get_driver_settings(driverSettings), kSettingsTemplate, settings);
delete_driver_settings(driverSettings);
return status;
}
#endif // TEST_HAIKU
+4
View File
@@ -14,6 +14,10 @@ public:
SettingsParser();
status_t ParseFile(const char* path, BMessage& settings);
#ifdef TEST_HAIKU
status_t Parse(const char* text, BMessage& settings);
#endif
};
@@ -325,55 +325,6 @@ DriverSettingsMessageAdapterTest::TestWildcard()
CPPUNIT_ASSERT_EQUAL(BString("works"),
BString(subMessage.GetString("still", "-")));
CPPUNIT_ASSERT_EQUAL(1, subMessage.CountNames(B_ANY_TYPE));
class WildcardConverter : public DriverSettingsConverter {
public:
status_t ConvertFromDriverSettings(const driver_parameter& parameter,
const char* name, int32 index, uint32 type, BMessage& target)
{
BMessage message;
message.AddString("args", parameter.values[index]);
return target.AddMessage(parameter.name, &message);
}
status_t ConvertEmptyFromDriverSettings(
const driver_parameter& parameter, const char* name, uint32 type,
BMessage& target)
{
if (parameter.parameter_count != 0)
return B_OK;
BMessage message;
return target.AddMessage(name, &message);
}
} converter;
const settings_template kSubTemplateC[] = {
{B_STRING_TYPE, NULL, NULL, true, &converter},
{}
};
const settings_template kTemplateC[] = {
{B_MESSAGE_TYPE, "if", kSubTemplateC},
{}
};
Settings settingsD("if {\n"
"\tsafemode\n"
"\tfile_exists one\n"
"}\n");
CPPUNIT_ASSERT_EQUAL(B_OK, settingsD.ToMessage(kTemplateC, message));
CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE));
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("if", &subMessage));
CPPUNIT_ASSERT_EQUAL(2, subMessage.CountNames(B_ANY_TYPE));
BMessage subSubMessage;
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindMessage("safemode",
&subSubMessage));
CPPUNIT_ASSERT(subSubMessage.IsEmpty());
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindMessage("file_exists",
&subSubMessage));
CPPUNIT_ASSERT_EQUAL(BString("one"),
BString(subSubMessage.GetString("args", 0, "-")));
CPPUNIT_ASSERT_EQUAL(1, subSubMessage.CountNames(B_ANY_TYPE));
}
+1
View File
@@ -3,4 +3,5 @@ SubDir HAIKU_TOP src tests servers ;
SubInclude HAIKU_TOP src tests servers app ;
SubInclude HAIKU_TOP src tests servers debug ;
SubInclude HAIKU_TOP src tests servers input ;
SubInclude HAIKU_TOP src tests servers launch ;
SubInclude HAIKU_TOP src tests servers registrar ;
+16
View File
@@ -0,0 +1,16 @@
SubDir HAIKU_TOP src tests servers launch ;
AddSubDirSupportedPlatforms libbe_test ;
UsePrivateHeaders app shared support ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src servers launch ] ;
UnitTestLib liblaunch_daemontest.so :
LaunchDaemonTestAddon.cpp
SettingsParserTest.cpp
SettingsParser.cpp
: be libshared.a [ TargetLibstdc++ ] [ TargetLibsupc++ ]
;
@@ -0,0 +1,21 @@
/*
* Copyright 2015, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <TestSuite.h>
#include <TestSuiteAddon.h>
#include "SettingsParserTest.h"
BTestSuite*
getTestSuite()
{
BTestSuite* suite = new BTestSuite("LaunchDaemon");
SettingsParserTest::AddTests(*suite);
return suite;
}
@@ -0,0 +1,215 @@
/*
* Copyright 2015, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "SettingsParserTest.h"
#include <stdlib.h>
#include <driver_settings.h>
#include <String.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
#include "SettingsParser.h"
SettingsParserTest::SettingsParserTest()
{
}
SettingsParserTest::~SettingsParserTest()
{
}
void
SettingsParserTest::TestConditionsMultiLine()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, _ParseCondition("if {\n"
"\tsafemode\n"
"\tfile_exists one\n"
"}\n", message));
CPPUNIT_ASSERT_EQUAL(2, message.CountNames(B_ANY_TYPE));
BMessage subMessage;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("safemode", &subMessage));
CPPUNIT_ASSERT(subMessage.IsEmpty());
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("file_exists",
&subMessage));
CPPUNIT_ASSERT_EQUAL(BString("one"),
BString(subMessage.GetString("args", 0, "-")));
CPPUNIT_ASSERT_EQUAL(1, subMessage.CountNames(B_ANY_TYPE));
}
void
SettingsParserTest::TestConditionsFlat()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, _ParseCondition("if safemode\n", message));
CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE));
BMessage args;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("safemode", &args));
CPPUNIT_ASSERT(args.IsEmpty());
}
void
SettingsParserTest::TestConditionsFlatWithNot()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, _ParseCondition("if not safemode\n", message));
CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE));
BMessage subMessage;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("not",
&subMessage));
BMessage args;
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindMessage("safemode", &args));
CPPUNIT_ASSERT(args.IsEmpty());
}
void
SettingsParserTest::TestConditionsFlatWithArgs()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK,
_ParseCondition("if file_exists one\n", message));
CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE));
BMessage args;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("file_exists", &args));
CPPUNIT_ASSERT_EQUAL(BString("one"),
BString(args.GetString("args", 0, "-")));
CPPUNIT_ASSERT_EQUAL(1, args.CountNames(B_ANY_TYPE));
}
void
SettingsParserTest::TestConditionsFlatWithNotAndArgs()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK,
_ParseCondition("if not file_exists one\n", message));
CPPUNIT_ASSERT_EQUAL(1, message.CountNames(B_ANY_TYPE));
BMessage subMessage;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("not",
&subMessage));
BMessage args;
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindMessage("file_exists", &args));
CPPUNIT_ASSERT_EQUAL(BString("one"),
BString(args.GetString("args", 0, "-")));
CPPUNIT_ASSERT_EQUAL(1, args.CountNames(B_ANY_TYPE));
}
void
SettingsParserTest::TestConditionsMultiLineFlatNot()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, _ParseCondition("if {\n"
"\tnot safemode\n"
"}\n", message));
message.PrintToStream();
}
void
SettingsParserTest::TestConditionsMultiLineFlatNotWithArgs()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, _ParseCondition("if {\n"
"\tnot file_exists one\n"
"}\n", message));
message.PrintToStream();
}
void
SettingsParserTest::TestConditionsMultiLineNot()
{
BMessage message;
CPPUNIT_ASSERT_EQUAL(B_OK, _ParseCondition("if {\n"
"\tnot {\n"
"\t\tsafemode\n"
"\t}\n"
"}\n", message));
BMessage subMessage;
CPPUNIT_ASSERT_EQUAL(B_OK, message.FindMessage("not", &subMessage));
BMessage args;
CPPUNIT_ASSERT_EQUAL(B_OK, subMessage.FindMessage("safemode", &args));
CPPUNIT_ASSERT(args.IsEmpty());
}
/*static*/ void
SettingsParserTest::AddTests(BTestSuite& parent)
{
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("SettingsParserTest");
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsMultiLine",
&SettingsParserTest::TestConditionsMultiLine));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsFlat",
&SettingsParserTest::TestConditionsFlat));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsFlatWithNot",
&SettingsParserTest::TestConditionsFlatWithNot));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsFlatWithArgs",
&SettingsParserTest::TestConditionsFlatWithArgs));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsFlatWithNotAndArgs",
&SettingsParserTest::TestConditionsFlatWithNotAndArgs));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsMultiLineFlatNot",
&SettingsParserTest::TestConditionsMultiLineFlatNot));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsMultiLineFlatNotWithArgs",
&SettingsParserTest::TestConditionsMultiLineFlatNotWithArgs));
suite.addTest(new CppUnit::TestCaller<SettingsParserTest>(
"SettingsParserTest::TestConditionsMultiLineNot",
&SettingsParserTest::TestConditionsMultiLineNot));
parent.addTest("SettingsParserTest", &suite);
}
status_t
SettingsParserTest::_ParseCondition(const char* text, BMessage& message)
{
SettingsParser parser;
BString input("job A {\n");
input << text << "\n}\n";
BMessage jobs;
status_t status = parser.Parse(input, jobs);
if (status != B_OK)
return status;
BMessage job;
status = jobs.FindMessage("job", 0, &job);
if (status != B_OK)
return status;
CPPUNIT_ASSERT_EQUAL(2, job.CountNames(B_ANY_TYPE));
CPPUNIT_ASSERT_EQUAL(BString("A"), BString(job.GetString("name")));
return job.FindMessage("if", &message);
}
@@ -0,0 +1,37 @@
/*
* Copyright 2015, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef SETTINGS_PARSER_TEST_H
#define SETTINGS_PARSER_TEST_H
#include <TestCase.h>
#include <TestSuite.h>
#include <Message.h>
class SettingsParserTest : public CppUnit::TestCase {
public:
SettingsParserTest();
virtual ~SettingsParserTest();
void TestConditionsMultiLine();
void TestConditionsFlat();
void TestConditionsFlatWithNot();
void TestConditionsFlatWithArgs();
void TestConditionsFlatWithNotAndArgs();
void TestConditionsMultiLineFlatNot();
void TestConditionsMultiLineFlatNotWithArgs();
void TestConditionsMultiLineNot();
static void AddTests(BTestSuite& suite);
private:
status_t _ParseCondition(const char* text,
BMessage& message);
};
#endif // SETTINGS_PARSER_TEST_H