From 00863566ec4601c65c435b74e575d49546a1c707 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sat, 7 Dec 2019 03:36:21 +0300 Subject: split server into multiple components In a vague attempt to make header files more readable, split server/ into a number of components. Also, refactor the unit tests to use the "Data-driven test cases" of Boost.Test. --- test/unit_tests/lexer.cpp | 209 +++++++++++++++++++++++++++++----------------- 1 file changed, 134 insertions(+), 75 deletions(-) (limited to 'test/unit_tests/lexer.cpp') diff --git a/test/unit_tests/lexer.cpp b/test/unit_tests/lexer.cpp index 7b513e8..fdc93e1 100644 --- a/test/unit_tests/lexer.cpp +++ b/test/unit_tests/lexer.cpp @@ -1,12 +1,27 @@ -#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include #include -BOOST_AUTO_TEST_CASE(test_lexer_parse_number) { - using namespace math::server::lexer; +BOOST_AUTO_TEST_SUITE(lexer_tests) +namespace bdata = boost::unit_test::data; +using math::server::Lexer; +using math::server::LexerError; +using math::server::lexer::Token; +using math::server::lexer::token::Type; +namespace details = math::server::lexer::details; + +BOOST_AUTO_TEST_CASE(test_parse_number) { // These are valid numbers: BOOST_TEST(details::parse_number("0").value() == 0); BOOST_TEST(details::parse_number("1.").value() == 1.); @@ -25,85 +40,129 @@ BOOST_AUTO_TEST_CASE(test_lexer_parse_number) { BOOST_TEST(!details::parse_number("e12").has_value()); // This is definitely a number, but a malformed one (an exponent must be // followed by some digits). - BOOST_CHECK_THROW(details::parse_number("12e"), Error); + BOOST_CHECK_THROW(details::parse_number("12e"), LexerError); } -BOOST_AUTO_TEST_CASE(test_lexer_parse_const_token) { - using namespace math::server::lexer; - - // TODO: No time to implement the required string conversions, hence the - // extra parentheses. - BOOST_TEST((details::parse_const_token("+").value() == Token::Type::PLUS)); +BOOST_AUTO_TEST_CASE(test_parse_const_token) { + BOOST_TEST(details::parse_const_token("+").value() == Type::PLUS); // parse_* functions only consume a single token: - BOOST_TEST((details::parse_const_token("+++").value() == Token::Type::PLUS)); - BOOST_TEST((details::parse_const_token("-").value() == Token::Type::MINUS)); + BOOST_TEST(details::parse_const_token("+/*").value() == Type::PLUS); + BOOST_TEST(details::parse_const_token("-").value() == Type::MINUS); BOOST_TEST(!details::parse_const_token("&+").has_value()); } -BOOST_AUTO_TEST_CASE(test_lexer_get_tokens) { - using namespace math::server; - using namespace math::server::lexer; +namespace { +namespace get_tokens::valid { - // TODO: No time to implement the required string conversions, hence the - // extra parentheses. - { - Lexer lexer{""}; - BOOST_TEST((lexer.get_tokens() == std::vector{})); - } - { - Lexer lexer{" + - "}; - BOOST_TEST((lexer.get_tokens() == std::vector{ - Token{Token::Type::PLUS}, - Token{Token::Type::MINUS}, - })); - } - { - Lexer lexer{"&"}; - BOOST_CHECK_THROW((lexer.get_tokens()), lexer::Error); - } - { - Lexer lexer{" 1 + 123 & 456"}; - BOOST_CHECK_THROW((lexer.get_tokens()), lexer::Error); - } - { - Lexer lexer{"1+2"}; - BOOST_TEST((lexer.get_tokens() == std::vector{ - Token{1}, - Token{Token::Type::PLUS}, - Token{2}, - })); - } - { - Lexer lexer{"1+2 * (3- 4e-2)"}; - BOOST_TEST((lexer.get_tokens() == std::vector{ - Token{1}, - Token{Token::Type::PLUS}, - Token{2}, - Token{Token::Type::ASTERISK}, - Token{Token::Type::LEFT_PAREN}, - Token{3}, - Token{Token::Type::MINUS}, - Token{4e-2}, - Token{Token::Type::RIGHT_PAREN}, - })); +const std::vector input{ + "", + " + - ", + "1+2", + "1+2 * (3- 4e-2)", + " 2 * (1 + 3 * (1 - -3)) ", +}; + +// Some black magic-fuckery to resolve operator<< for std::vector. +// See https://stackoverflow.com/a/18817428/514684. + +struct Expected { + std::vector m_tokens; +}; + +std::ostream& operator<<(std::ostream& os, const Expected& expected) { + for (const auto& token : expected.m_tokens) { + os << token; } - { - Lexer lexer{" 2 * (1 + 3 * (1 - -3)) "}; - BOOST_TEST((lexer.get_tokens() == std::vector{ - Token{2}, - Token{Token::Type::ASTERISK}, - Token{Token::Type::LEFT_PAREN}, - Token{1}, - Token{Token::Type::PLUS}, - Token{3}, - Token{Token::Type::ASTERISK}, - Token{Token::Type::LEFT_PAREN}, - Token{1}, - Token{Token::Type::MINUS}, - Token{Token::Type::MINUS}, - Token{3}, - Token{Token::Type::RIGHT_PAREN}, - Token{Token::Type::RIGHT_PAREN}, - })); + return os; +} + +const std::vector expected{ + {{}}, + {{ + Token{Type::PLUS}, + Token{Type::MINUS}, + }}, + {{ + Token{1}, + Token{Type::PLUS}, + Token{2}, + }}, + {{ + Token{1}, + Token{Type::PLUS}, + Token{2}, + Token{Type::ASTERISK}, + Token{Type::LEFT_PAREN}, + Token{3}, + Token{Type::MINUS}, + Token{4e-2}, + Token{Type::RIGHT_PAREN}, + }}, + {{ + Token{2}, + Token{Type::ASTERISK}, + Token{Type::LEFT_PAREN}, + Token{1}, + Token{Type::PLUS}, + Token{3}, + Token{Type::ASTERISK}, + Token{Type::LEFT_PAREN}, + Token{1}, + Token{Type::MINUS}, + Token{Type::MINUS}, + Token{3}, + Token{Type::RIGHT_PAREN}, + Token{Type::RIGHT_PAREN}, + }}, +}; + +} + +namespace get_tokens::invalid { + +const std::vector input{ + "&", + " 1 + 123 & 456", +}; + +const std::vector error_msg{ + "server error: lexer error: invalid input at: &", + "server error: lexer error: invalid input at: & 456", +}; + +} +} + +BOOST_DATA_TEST_CASE( + test_get_tokens_valid, + bdata::make(get_tokens::valid::input) ^ get_tokens::valid::expected, + input, + expected) { + + Lexer lexer{input}; + const auto actual = lexer.get_tokens(); + BOOST_CHECK_EQUAL_COLLECTIONS(actual.cbegin(), actual.cend(), + expected.m_tokens.cbegin(), + expected.m_tokens.cend()); +} + +BOOST_DATA_TEST_CASE( + test_get_tokens_invalid, + bdata::make(get_tokens::invalid::input) ^ get_tokens::invalid::error_msg, + input, + error_msg) { + + BOOST_REQUIRE_THROW(do { + Lexer lexer{input}; + lexer.get_tokens(); + } while (0), LexerError); + + try { + Lexer lexer{input}; + lexer.get_tokens(); + } catch (const LexerError& e) { + BOOST_TEST(error_msg == e.what()); } } + +BOOST_AUTO_TEST_SUITE_END() -- cgit v1.2.3