#include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////////////////////////// class SASParserTestsFixture { protected: SASParserTestsFixture() : m_blocksworldTestFile(readFile("data/blocksworld.sas")), m_cavedivingTestFile(readFile("data/cavediving.sas")), m_freecellTestFile(readFile("data/freecell.sas")), m_philosophersTestFile(readFile("data/philosophers.sas")) { } static std::stringstream readFile(const std::string &path) { std::ifstream fileStream(path, std::ios::in); std::stringstream outputStream; if (!fileStream.is_open()) throw std::runtime_error("Could not open file “" + path + "”"); outputStream << fileStream.rdbuf(); return outputStream; } std::stringstream m_blocksworldTestFile; std::stringstream m_cavedivingTestFile; std::stringstream m_freecellTestFile; std::stringstream m_philosophersTestFile; }; //////////////////////////////////////////////////////////////////////////////////////////////////// TEST_CASE_METHOD(SASParserTestsFixture, "[SAS parser] A valid SAS file is parsed correctly", "[SAS parser]") { try { const auto description = plasp::sas::Description::fromStream(m_philosophersTestFile); REQUIRE_FALSE(description.usesActionCosts()); REQUIRE(description.variables().size() == 37u); REQUIRE(description.variables()[0].axiomLayer() == -1); REQUIRE(description.variables()[0].values()[0].sign() == plasp::sas::Value::Sign::Positive); REQUIRE(description.variables()[0].values()[0].name() == "activate(philosopher-0, forks--pid-rfork)"); REQUIRE(description.variables()[36].axiomLayer() == -1); REQUIRE(description.variables()[36].values()[1].sign() == plasp::sas::Value::Sign::Negative); REQUIRE(description.variables()[36].values()[1].name() == "queue-tail-msg(forks-1-, fork)"); REQUIRE(description.mutexGroups().size() == 8u); REQUIRE(description.mutexGroups()[0].facts().size() == 9u); REQUIRE(&description.mutexGroups()[0].facts()[0].value() == &description.variables()[0].values()[0]); REQUIRE(description.mutexGroups()[7].facts().size() == 2u); REQUIRE(&description.mutexGroups()[7].facts()[1].value() == &description.variables()[34].values()[1]); REQUIRE(description.initialState().facts().size() == 37u); REQUIRE(&description.initialState().facts()[0].value() == &description.variables()[0].values()[8]); REQUIRE(&description.initialState().facts()[36].value() == &description.variables()[36].values()[1]); REQUIRE(description.goal().facts().size() == 2u); REQUIRE(&description.goal().facts()[0].value() == &description.variables()[6].values()[0]); REQUIRE(&description.goal().facts()[1].value() == &description.variables()[7].values()[0]); REQUIRE(description.operators().size() == 34u); REQUIRE(description.operators()[0].predicate().name() == "activate-trans"); REQUIRE(description.operators()[0].predicate().arguments().size() == 5u); REQUIRE(description.operators()[0].predicate().arguments()[0] == "philosopher-0"); REQUIRE(description.operators()[0].predicate().arguments()[4] == "state-3"); REQUIRE(description.operators()[0].preconditions().size() == 3u); REQUIRE(&description.operators()[0].preconditions()[0].value() == &description.variables()[4].values()[4]); REQUIRE(&description.operators()[0].preconditions()[1].value() == &description.variables()[16].values()[1]); REQUIRE(&description.operators()[0].preconditions()[2].value() == &description.variables()[0].values()[8]); REQUIRE(description.operators()[0].effects().size() == 1u); REQUIRE(description.operators()[0].effects()[0].conditions().size() == 0u); REQUIRE(&description.operators()[0].effects()[0].postcondition().value() == &description.variables()[0].values()[0]); REQUIRE(description.operators()[33].predicate().name() == "queue-write"); REQUIRE(description.operators()[33].predicate().arguments().size() == 4u); REQUIRE(description.operators()[33].predicate().arguments()[0] == "philosopher-1"); REQUIRE(description.operators()[33].predicate().arguments()[3] == "fork"); REQUIRE(description.operators()[33].preconditions().size() == 2u); REQUIRE(&description.operators()[33].preconditions()[0].value() == &description.variables()[1].values()[3]); REQUIRE(&description.operators()[33].preconditions()[1].value() == &description.variables()[2].values()[2]); REQUIRE(description.operators()[33].effects().size() == 3u); REQUIRE(description.operators()[33].effects()[0].conditions().size() == 0u); REQUIRE(&description.operators()[33].effects()[0].postcondition().value() == &description.variables()[1].values()[7]); REQUIRE(&description.operators()[33].effects()[2].postcondition().value() == &description.variables()[35].values()[0]); REQUIRE(description.axiomRules().size() == 33u); REQUIRE(description.axiomRules()[0].conditions().size() == 4u); REQUIRE(&description.axiomRules()[0].conditions()[0].value() == &description.variables()[0].values()[0]); REQUIRE(&description.axiomRules()[0].conditions()[2].value() == &description.variables()[27].values()[0]); REQUIRE(&description.axiomRules()[0].conditions()[3].value() == &description.variables()[8].values()[1]); REQUIRE(&description.axiomRules()[0].postcondition().value() == &description.variables()[8].values()[0]); REQUIRE(description.axiomRules()[32].conditions().size() == 2u); REQUIRE(&description.axiomRules()[32].conditions()[0].value() == &description.variables()[15].values()[0]); REQUIRE(&description.axiomRules()[32].conditions()[1].value() == &description.variables()[25].values()[0]); REQUIRE(&description.axiomRules()[32].postcondition().value() == &description.variables()[25].values()[1]); } catch (const std::exception &e) { FAIL(e.what()); } // TODO: add whitespace test } //////////////////////////////////////////////////////////////////////////////////////////////////// TEST_CASE_METHOD(SASParserTestsFixture, "[SAS parser] Trailing empty parentheses are removed", "[SAS parser]") { try { const auto description = plasp::sas::Description::fromStream(m_blocksworldTestFile); REQUIRE(description.variables()[4].values()[0].name() == "handempty"); REQUIRE(description.variables()[5].values()[0].name() == "holding(a)"); } catch (const std::exception &e) { FAIL(e.what()); } } //////////////////////////////////////////////////////////////////////////////////////////////////// TEST_CASE_METHOD(SASParserTestsFixture, "[SAS parser] “none” values are correctly parsed", "[SAS parser]") { try { const auto description = plasp::sas::Description::fromStream(m_freecellTestFile); // TODO: compare by identity, not value REQUIRE(description.variables()[0].values()[3] == plasp::sas::Value::None); REQUIRE(description.variables()[5].values()[6] == plasp::sas::Value::None); } catch (const std::exception &e) { FAIL(e.what()); } } //////////////////////////////////////////////////////////////////////////////////////////////////// TEST_CASE_METHOD(SASParserTestsFixture, "[SAS parser] SAS requirements are parsed correctly", "[SAS parser]") { try { const auto description = plasp::sas::Description::fromStream(m_cavedivingTestFile); REQUIRE(description.usesActionCosts()); REQUIRE(description.usesConditionalEffects()); REQUIRE_FALSE(description.usesAxiomRules()); REQUIRE(description.operators().size() == 496u); REQUIRE(description.operators()[0].costs() == 1u); REQUIRE(description.operators()[172].costs() == 10u); REQUIRE(description.operators()[173].costs() == 63u); REQUIRE(description.operators()[172].effects().size() == 3u); REQUIRE(description.operators()[172].effects()[1].conditions().size() == 1u); REQUIRE(&description.operators()[172].effects()[1].conditions()[0].value() == &description.variables()[1].values()[4]); } catch (const std::exception &e) { FAIL(e.what()); } } //////////////////////////////////////////////////////////////////////////////////////////////////// TEST_CASE("[SAS parser] Former issues are fixed", "[SAS parser]") { // Check issue where unexpected whitespaces in SAS files led to a parsing error REQUIRE_NOTHROW(plasp::sas::Description::fromFile("data/issues/issue-6.sas")); }