#include "Parsing/Header/Impl/HeaderLexer.h" #include "Parsing/Mock/MockParserLineStream.h" #include #include #include using namespace Catch::Matchers; namespace test::parsing::header::impl::header_lexer { void ExpectCharacterToken(HeaderLexer& lexer, char c) { REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::CHARACTER); REQUIRE(lexer.GetToken(0).CharacterValue() == c); lexer.PopTokens(1); } void ExpectIntegerToken(HeaderLexer& lexer, int number) { REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::INTEGER); REQUIRE(lexer.GetToken(0).IntegerValue() == number); lexer.PopTokens(1); } void ExpectFloatingPointToken(HeaderLexer& lexer, double number) { REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::FLOATING_POINT); const auto a = lexer.GetToken(0).FloatingPointValue(); REQUIRE_THAT(lexer.GetToken(0).FloatingPointValue(), WithinRel(number)); lexer.PopTokens(1); } void ExpectIdentifierToken(HeaderLexer& lexer, const std::string& identifier) { REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::IDENTIFIER); REQUIRE(lexer.GetToken(0).IdentifierValue() == identifier); lexer.PopTokens(1); } void ExpectStringToken(HeaderLexer& lexer, const std::string& c) { REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::STRING); REQUIRE(lexer.GetToken(0).StringValue() == c); lexer.PopTokens(1); } void ExpectTokenWithType(HeaderLexer& lexer, HeaderParserValueType type) { REQUIRE(lexer.GetToken(0).m_type == type); lexer.PopTokens(1); } TEST_CASE("HeaderLexer: Ensure can parse simple hex numbers", "[parsing][header]") { const std::vector lines{"0x1A4", " 0xABC ", " 0xAAA", "0xBBB "}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectIntegerToken(lexer, 0x1a4); ExpectIntegerToken(lexer, 0xabc); ExpectIntegerToken(lexer, 0xaaa); ExpectIntegerToken(lexer, 0xbbb); REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::END_OF_FILE); } TEST_CASE("HeaderLexer: Ensure can parse simple hex numbers surrounded by identifiers", "[parsing][header]") { const std::vector lines{"abc 0xABC cba", "aaa 0xAAA", "0xBBB bbb"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectIdentifierToken(lexer, "abc"); ExpectIntegerToken(lexer, 0xabc); ExpectIdentifierToken(lexer, "cba"); ExpectIdentifierToken(lexer, "aaa"); ExpectIntegerToken(lexer, 0xaaa); ExpectIntegerToken(lexer, 0xbbb); ExpectIdentifierToken(lexer, "bbb"); REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::END_OF_FILE); } TEST_CASE("HeaderLexer: Ensure can parse simple hex numbers surrounded by symbols", "[parsing][header]") { const std::vector lines{ "0x25:0xABC,0x1a4", }; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectIntegerToken(lexer, 0x25); ExpectCharacterToken(lexer, ':'); ExpectIntegerToken(lexer, 0xABC); ExpectCharacterToken(lexer, ','); ExpectIntegerToken(lexer, 0x1a4); REQUIRE(lexer.GetToken(0).m_type == HeaderParserValueType::END_OF_FILE); } TEST_CASE("HeaderLexer: Ensure throws exception when parsing incomplete hex number", "[parsing][header]") { const std::vector lines{"0x"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); REQUIRE_THROWS_AS(lexer.GetToken(0), ParsingException); } TEST_CASE("HeaderLexer: Ensure throws exception when parsing invalid hex number", "[parsing][header]") { const std::vector lines{"0xGEGE"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); REQUIRE_THROWS_AS(lexer.GetToken(0), ParsingException); } TEST_CASE("HeaderLexer: Ensure throws exception when parsing invalid hex number that starts with a valid letter", "[parsing][header]") { const std::vector lines{"0xEGEG"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); REQUIRE_THROWS_AS(lexer.GetToken(0), ParsingException); } TEST_CASE("HeaderLexer: Ensure can parse simple integers", "[parsing][header]") { const std::vector lines{" 524 ", "4221111 1337 ", "0 420"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectIntegerToken(lexer, 524); ExpectIntegerToken(lexer, 4221111); ExpectIntegerToken(lexer, 1337); ExpectIntegerToken(lexer, 0); ExpectIntegerToken(lexer, 420); } TEST_CASE("HeaderLexer: Ensure can parse integers surrounded by identifiers", "[parsing][header]") { const std::vector lines{"aa 6 bb", "123456789 ccc", "0 d 420"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectIdentifierToken(lexer, "aa"); ExpectIntegerToken(lexer, 6); ExpectIdentifierToken(lexer, "bb"); ExpectIntegerToken(lexer, 123456789); ExpectIdentifierToken(lexer, "ccc"); ExpectIntegerToken(lexer, 0); ExpectIdentifierToken(lexer, "d"); ExpectIntegerToken(lexer, 420); } TEST_CASE("HeaderLexer: Ensure parses negative numbers as character and number", "[parsing][header]") { const std::vector lines{"-1337"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '-'); ExpectIntegerToken(lexer, 1337); } TEST_CASE("HeaderLexer: Ensure recognizes numbers surrounded by characters", "[parsing][header]") { const std::vector lines{"(1337)"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '('); ExpectIntegerToken(lexer, 1337); ExpectCharacterToken(lexer, ')'); } TEST_CASE("HeaderLexer: Ensure parses simple floating point numbers", "[parsing][header]") { const std::vector lines{"420.1337"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectFloatingPointToken(lexer, 420.1337); } TEST_CASE("HeaderLexer: Ensure parses simple floating point numbers surrounded by identifiers", "[parsing][header]") { const std::vector lines{"aa 50.24 a", "b 36.999", "59595.2414 c"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectIdentifierToken(lexer, "aa"); ExpectFloatingPointToken(lexer, 50.24); ExpectIdentifierToken(lexer, "a"); ExpectIdentifierToken(lexer, "b"); ExpectFloatingPointToken(lexer, 36.999); ExpectFloatingPointToken(lexer, 59595.2414); ExpectIdentifierToken(lexer, "c"); } TEST_CASE("HeaderLexer: Ensure recognizes floating point numbers surrounded by characters", "[parsing][header]") { const std::vector lines{"(1337.420)"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '('); ExpectFloatingPointToken(lexer, 1337.420); ExpectCharacterToken(lexer, ')'); } TEST_CASE("HeaderLexer: Ensure can separate identifiers with symbols", "[parsing][header]") { const std::vector lines{"hello|world hello_+universe"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectIdentifierToken(lexer, "hello"); ExpectCharacterToken(lexer, '|'); ExpectIdentifierToken(lexer, "world"); ExpectIdentifierToken(lexer, "hello_"); ExpectCharacterToken(lexer, '+'); ExpectIdentifierToken(lexer, "universe"); } TEST_CASE("HeaderLexer: Can recognize shift left", "[parsing][header]") { const std::vector lines{"< lines{"<=hello<=world<="}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectTokenWithType(lexer, HeaderParserValueType::LESS_EQUAL); ExpectIdentifierToken(lexer, "hello"); ExpectTokenWithType(lexer, HeaderParserValueType::LESS_EQUAL); ExpectIdentifierToken(lexer, "world"); ExpectTokenWithType(lexer, HeaderParserValueType::LESS_EQUAL); } TEST_CASE("HeaderLexer: Can recognize less", "[parsing][header]") { const std::vector lines{"<%hello lines{">>hello>>world>>"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectTokenWithType(lexer, HeaderParserValueType::SHIFT_RIGHT); ExpectIdentifierToken(lexer, "hello"); ExpectTokenWithType(lexer, HeaderParserValueType::SHIFT_RIGHT); ExpectIdentifierToken(lexer, "world"); ExpectTokenWithType(lexer, HeaderParserValueType::SHIFT_RIGHT); } TEST_CASE("HeaderLexer: Can recognize greater equals", "[parsing][header]") { const std::vector lines{">=hello>=world>="}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectTokenWithType(lexer, HeaderParserValueType::GREATER_EQUAL); ExpectIdentifierToken(lexer, "hello"); ExpectTokenWithType(lexer, HeaderParserValueType::GREATER_EQUAL); ExpectIdentifierToken(lexer, "world"); ExpectTokenWithType(lexer, HeaderParserValueType::GREATER_EQUAL); } TEST_CASE("HeaderLexer: Can recognize greater", "[parsing][header]") { const std::vector lines{">%hello>world>&"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '>'); ExpectCharacterToken(lexer, '%'); ExpectIdentifierToken(lexer, "hello"); ExpectCharacterToken(lexer, '>'); ExpectIdentifierToken(lexer, "world"); ExpectCharacterToken(lexer, '>'); ExpectCharacterToken(lexer, '&'); } TEST_CASE("HeaderLexer: Can recognize equals", "[parsing][header]") { const std::vector lines{"==hello==world=="}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectTokenWithType(lexer, HeaderParserValueType::EQUALS); ExpectIdentifierToken(lexer, "hello"); ExpectTokenWithType(lexer, HeaderParserValueType::EQUALS); ExpectIdentifierToken(lexer, "world"); ExpectTokenWithType(lexer, HeaderParserValueType::EQUALS); } TEST_CASE("HeaderLexer: Can recognize assign", "[parsing][header]") { const std::vector lines{"=%hello=world=&"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '='); ExpectCharacterToken(lexer, '%'); ExpectIdentifierToken(lexer, "hello"); ExpectCharacterToken(lexer, '='); ExpectIdentifierToken(lexer, "world"); ExpectCharacterToken(lexer, '='); ExpectCharacterToken(lexer, '&'); } TEST_CASE("HeaderLexer: Can recognize logical and", "[parsing][header]") { const std::vector lines{"&&hello&&world&&"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectTokenWithType(lexer, HeaderParserValueType::LOGICAL_AND); ExpectIdentifierToken(lexer, "hello"); ExpectTokenWithType(lexer, HeaderParserValueType::LOGICAL_AND); ExpectIdentifierToken(lexer, "world"); ExpectTokenWithType(lexer, HeaderParserValueType::LOGICAL_AND); } TEST_CASE("HeaderLexer: Can recognize ampersand", "[parsing][header]") { const std::vector lines{"&%hello&world&+"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '&'); ExpectCharacterToken(lexer, '%'); ExpectIdentifierToken(lexer, "hello"); ExpectCharacterToken(lexer, '&'); ExpectIdentifierToken(lexer, "world"); ExpectCharacterToken(lexer, '&'); ExpectCharacterToken(lexer, '+'); } TEST_CASE("HeaderLexer: Can recognize logical or", "[parsing][header]") { const std::vector lines{"||hello||world||"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectTokenWithType(lexer, HeaderParserValueType::LOGICAL_OR); ExpectIdentifierToken(lexer, "hello"); ExpectTokenWithType(lexer, HeaderParserValueType::LOGICAL_OR); ExpectIdentifierToken(lexer, "world"); ExpectTokenWithType(lexer, HeaderParserValueType::LOGICAL_OR); } TEST_CASE("HeaderLexer: Can recognize pipe", "[parsing][header]") { const std::vector lines{"|%hello|world|&"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '|'); ExpectCharacterToken(lexer, '%'); ExpectIdentifierToken(lexer, "hello"); ExpectCharacterToken(lexer, '|'); ExpectIdentifierToken(lexer, "world"); ExpectCharacterToken(lexer, '|'); ExpectCharacterToken(lexer, '&'); } TEST_CASE("HeaderLexer: Can recognize not equals", "[parsing][header]") { const std::vector lines{"!=hello!=world!="}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectTokenWithType(lexer, HeaderParserValueType::NOT_EQUAL); ExpectIdentifierToken(lexer, "hello"); ExpectTokenWithType(lexer, HeaderParserValueType::NOT_EQUAL); ExpectIdentifierToken(lexer, "world"); ExpectTokenWithType(lexer, HeaderParserValueType::NOT_EQUAL); } TEST_CASE("HeaderLexer: Can recognize exclamation mark", "[parsing][header]") { const std::vector lines{"!%hello!world!&"}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectCharacterToken(lexer, '!'); ExpectCharacterToken(lexer, '%'); ExpectIdentifierToken(lexer, "hello"); ExpectCharacterToken(lexer, '!'); ExpectIdentifierToken(lexer, "world"); ExpectCharacterToken(lexer, '!'); ExpectCharacterToken(lexer, '&'); } TEST_CASE("HeaderLexer: Can recognize strings", "[parsing][header]") { const std::vector lines{"\"hello world\"", "a\"hi there\"bbb", " \"nice\"", "\"meme\" "}; MockParserLineStream mockStream(lines); HeaderLexer lexer(&mockStream); ExpectStringToken(lexer, "hello world"); ExpectIdentifierToken(lexer, "a"); ExpectStringToken(lexer, "hi there"); ExpectIdentifierToken(lexer, "bbb"); ExpectStringToken(lexer, "nice"); ExpectStringToken(lexer, "meme"); } } // namespace test::parsing::header::impl::header_lexer