From e73c936699e8834f94bc677431fe8b260eaa5b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 18 Jun 2015 18:08:05 +0200 Subject: [PATCH] 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. --- src/servers/launch/SettingsParser.cpp | 90 +++++++- src/servers/launch/SettingsParser.h | 4 + .../DriverSettingsMessageAdapterTest.cpp | 49 ---- src/tests/servers/Jamfile | 1 + src/tests/servers/launch/Jamfile | 16 ++ .../servers/launch/LaunchDaemonTestAddon.cpp | 21 ++ .../servers/launch/SettingsParserTest.cpp | 215 ++++++++++++++++++ src/tests/servers/launch/SettingsParserTest.h | 37 +++ 8 files changed, 376 insertions(+), 57 deletions(-) create mode 100644 src/tests/servers/launch/Jamfile create mode 100644 src/tests/servers/launch/LaunchDaemonTestAddon.cpp create mode 100644 src/tests/servers/launch/SettingsParserTest.cpp create mode 100644 src/tests/servers/launch/SettingsParserTest.h diff --git a/src/servers/launch/SettingsParser.cpp b/src/servers/launch/SettingsParser.cpp index d9e61a3ce3..71b78c8402 100644 --- a/src/servers/launch/SettingsParser.cpp +++ b/src/servers/launch/SettingsParser.cpp @@ -9,6 +9,65 @@ #include +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 = ⌖ + 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 diff --git a/src/servers/launch/SettingsParser.h b/src/servers/launch/SettingsParser.h index 673e8e7278..4ae40b9b35 100644 --- a/src/servers/launch/SettingsParser.h +++ b/src/servers/launch/SettingsParser.h @@ -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 }; diff --git a/src/tests/kits/shared/DriverSettingsMessageAdapterTest.cpp b/src/tests/kits/shared/DriverSettingsMessageAdapterTest.cpp index 5afa7633ef..b369a6b316 100644 --- a/src/tests/kits/shared/DriverSettingsMessageAdapterTest.cpp +++ b/src/tests/kits/shared/DriverSettingsMessageAdapterTest.cpp @@ -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)); } diff --git a/src/tests/servers/Jamfile b/src/tests/servers/Jamfile index 1b5753e496..49dd4704ff 100644 --- a/src/tests/servers/Jamfile +++ b/src/tests/servers/Jamfile @@ -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 ; diff --git a/src/tests/servers/launch/Jamfile b/src/tests/servers/launch/Jamfile new file mode 100644 index 0000000000..90be9b7ffd --- /dev/null +++ b/src/tests/servers/launch/Jamfile @@ -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++ ] +; diff --git a/src/tests/servers/launch/LaunchDaemonTestAddon.cpp b/src/tests/servers/launch/LaunchDaemonTestAddon.cpp new file mode 100644 index 0000000000..38e272e61c --- /dev/null +++ b/src/tests/servers/launch/LaunchDaemonTestAddon.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include "SettingsParserTest.h" + + +BTestSuite* +getTestSuite() +{ + BTestSuite* suite = new BTestSuite("LaunchDaemon"); + + SettingsParserTest::AddTests(*suite); + + return suite; +} diff --git a/src/tests/servers/launch/SettingsParserTest.cpp b/src/tests/servers/launch/SettingsParserTest.cpp new file mode 100644 index 0000000000..17f0a035ab --- /dev/null +++ b/src/tests/servers/launch/SettingsParserTest.cpp @@ -0,0 +1,215 @@ +/* + * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "SettingsParserTest.h" + +#include + +#include +#include + +#include +#include + +#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::TestConditionsMultiLine", + &SettingsParserTest::TestConditionsMultiLine)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestConditionsFlat", + &SettingsParserTest::TestConditionsFlat)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestConditionsFlatWithNot", + &SettingsParserTest::TestConditionsFlatWithNot)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestConditionsFlatWithArgs", + &SettingsParserTest::TestConditionsFlatWithArgs)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestConditionsFlatWithNotAndArgs", + &SettingsParserTest::TestConditionsFlatWithNotAndArgs)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestConditionsMultiLineFlatNot", + &SettingsParserTest::TestConditionsMultiLineFlatNot)); + suite.addTest(new CppUnit::TestCaller( + "SettingsParserTest::TestConditionsMultiLineFlatNotWithArgs", + &SettingsParserTest::TestConditionsMultiLineFlatNotWithArgs)); + suite.addTest(new CppUnit::TestCaller( + "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); +} diff --git a/src/tests/servers/launch/SettingsParserTest.h b/src/tests/servers/launch/SettingsParserTest.h new file mode 100644 index 0000000000..bd99269c23 --- /dev/null +++ b/src/tests/servers/launch/SettingsParserTest.h @@ -0,0 +1,37 @@ +/* + * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef SETTINGS_PARSER_TEST_H +#define SETTINGS_PARSER_TEST_H + + +#include +#include + +#include + + +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