aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/test/unit_tests/lexer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit_tests/lexer.cpp')
-rw-r--r--test/unit_tests/lexer.cpp209
1 files changed, 134 insertions, 75 deletions
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 <server/lexer.hpp>
+#include <server/lexer/error.hpp>
+#include <server/lexer/lexer.hpp>
+#include <server/lexer/token.hpp>
+#include <server/lexer/token_type.hpp>
+#include <boost/test/data/test_case.hpp>
+#include <boost/test/data/monomorphic.hpp>
#include <boost/test/unit_test.hpp>
+#include <ostream>
+#include <string>
+#include <string_view>
#include <vector>
-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<Token>{}));
- }
- {
- Lexer lexer{" + - "};
- BOOST_TEST((lexer.get_tokens() == std::vector<Token>{
- 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>{
- Token{1},
- Token{Token::Type::PLUS},
- Token{2},
- }));
- }
- {
- Lexer lexer{"1+2 * (3- 4e-2)"};
- BOOST_TEST((lexer.get_tokens() == std::vector<Token>{
- 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<std::string_view> input{
+ "",
+ " + - ",
+ "1+2",
+ "1+2 * (3- 4e-2)",
+ " 2 * (1 + 3 * (1 - -3)) ",
+};
+
+// Some black magic-fuckery to resolve operator<< for std::vector<Token>.
+// See https://stackoverflow.com/a/18817428/514684.
+
+struct Expected {
+ std::vector<Token> 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>{
- 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> 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<std::string_view> input{
+ "&",
+ " 1 + 123 & 456",
+};
+
+const std::vector<std::string> 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()