|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- #include <initializer_list>
- #include <unordered_set>
-
- #include "BXParser.h"
- #include "catch.hpp"
-
- static BXVariables parse(const char *str) {
- bufio::ISStream stream(str);
- BXParser parser(stream);
- BXVariables vars;
- parser.parse(vars);
- return vars;
- }
-
- std::string stringify(std::vector<std::string> &vec) {
- if (vec.size() == 0) {
- return "(empty)";
- }
-
- std::string s;
- for (auto &val: vec) {
- if (s.size() == 0) {
- s += '\'' + val + '\'';
- } else {
- s += " '" + val + '\'';
- }
- }
-
- return s;
- }
-
- static void expecteq(
- const char *str,
- const std::initializer_list<std::pair<
- std::string, std::vector<std::string>>> list) {
- INFO("Source: " << str);
- bufio::ISStream stream(str);
- BXParser parser(stream);
- BXVariables vars;
- parser.parse(vars);
-
- std::unordered_set<std::string> keyset;
-
- for (auto &expected: list) {
- keyset.insert(expected.first);
-
- auto it = vars.find(expected.first);
- if (it == vars.end()) {
- FAIL("Missing key '" << expected.first << "'!");
- }
-
- if (it->second != expected.second) {
- INFO("Value: " << stringify(it->second));
- FAIL("Value of key '" << expected.first << "' doesn't match!");
- }
- }
-
- for (auto &pair: vars) {
- if (keyset.find(pair.first) == keyset.end()) {
- FAIL("Unexpected key '" << pair.first << "'!");
- }
- }
- }
-
- static void lexeq(BXVariables &vars, const char *str, std::initializer_list<BXParser::Token> list) {
- INFO("Source: " << str);
- bufio::ISStream stream(str);
- BXParser parser(stream);
- parser.readToken(vars);
-
- size_t i = 1;
- for (auto &expected: list) {
- BXParser::Token tok = parser.readToken(vars);
- if (tok.kind != expected.kind) {
- INFO("Expected: " << (int)expected.kind);
- INFO("Actual: " << (int)tok.kind);
- FAIL("Token " << i << " doesn't match");
- }
-
- if (tok.str != expected.str) {
- INFO("Expected: '" << expected.str << '\'');
- INFO("Actual: '" << tok.str << '\'');
- FAIL("Token " << i << "'s string doesn't match");
- }
-
- if (tok.kind == BXParser::TokenKind::E_O_F) {
- return;
- }
-
- i += 1;
- }
- }
-
- static void lexeq(const char *str, std::initializer_list<BXParser::Token> list) {
- BXVariables vars;
- lexeq(vars, str, list);
- }
-
- TEST_CASE("BXParser lex", "[BXParser][lex]") {
- lexeq("hello world", {
- { BXParser::TokenKind::STRING, "hello" },
- { BXParser::TokenKind::STRING, "world" },
- { BXParser::TokenKind::E_O_F },
- });
-
- lexeq("hello := what's up", {
- { BXParser::TokenKind::STRING, "hello" },
- { BXParser::TokenKind::COLON_EQUALS },
- { BXParser::TokenKind::STRING, "what's" },
- { BXParser::TokenKind::STRING, "up" },
- { BXParser::TokenKind::E_O_F },
- });
-
- lexeq("\t\t \t, := += =+\n\n\r\nhello", {
- { BXParser::TokenKind::INDENTATION },
- { BXParser::TokenKind::COMMA },
- { BXParser::TokenKind::COLON_EQUALS },
- { BXParser::TokenKind::PLUS_EQUALS },
- { BXParser::TokenKind::EQUALS_PLUS },
- { BXParser::TokenKind::NEWLINE },
- { BXParser::TokenKind::STRING, "hello" },
- { BXParser::TokenKind::E_O_F },
- });
- }
-
- TEST_CASE("BXParser lex string interpolation", "[BXParser][lex]") {
- BXVariables vars = {
- { "foo", { "hello"} },
- };
-
- lexeq(vars, "hey \"$foo\" lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::STRING, "hello" },
- { BXParser::TokenKind::STRING, "lol" },
- });
-
- lexeq(vars, "hey \"no$foo\" lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::STRING, "nohello" },
- { BXParser::TokenKind::STRING, "lol" },
- });
-
- lexeq(vars, "hey \"Xx${foo}xX\" lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::STRING, "XxhelloxX" },
- { BXParser::TokenKind::STRING, "lol" },
- });
- }
-
- TEST_CASE("BXParser lex string interpolation without quotes", "[BXParser][lex]") {
- BXVariables vars = {
- { "foo", { "hello"} },
- };
-
- lexeq(vars, "hey Xx$foo lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::STRING, "Xxhello" },
- { BXParser::TokenKind::STRING, "lol" },
- });
-
- lexeq(vars, "hey Xx${ foo }xX lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::STRING, "XxhelloxX" },
- { BXParser::TokenKind::STRING, "lol" },
- });
- }
-
- TEST_CASE("BXParser lex array expansion", "[BXParser][lex]") {
- lexeq("hey $foo lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::EXPANSION, "foo" },
- { BXParser::TokenKind::STRING, "lol" },
- });
-
- lexeq("hey ${foo} lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::EXPANSION, "foo" },
- { BXParser::TokenKind::STRING, "lol" },
- });
-
- lexeq("hey ${ \tfoo\n \n} lol", {
- { BXParser::TokenKind::STRING, "hey" },
- { BXParser::TokenKind::EXPANSION, "foo" },
- { BXParser::TokenKind::STRING, "lol" },
- });
- }
-
- TEST_CASE("BXParser parsing", "[BXParser][parse]") {
- expecteq("hello := 10, world := 20", {
- { "hello", { "10" } },
- { "world", { "20" } },
- });
-
- expecteq("foo := hello world, bar := 10 20 30, baz := 0", {
- { "foo", { "hello", "world" } },
- { "bar", { "10", "20", "30" } },
- { "baz", { "0" } },
- });
- }
-
- TEST_CASE("BXParser parsing variables", "[BXParser][parse]") {
- expecteq("foo := \"hello world\", bar := $foo", {
- { "foo", { "hello world" } },
- { "bar", { "hello world" } },
- });
-
- expecteq("foo := hello world, bar := hey $foo what's up", {
- { "foo", { "hello", "world" } },
- { "bar", { "hey", "hello", "world", "what's", "up" } },
- });
- }
-
- TEST_CASE("BXParser append/prepend", "[BXParser][parse]") {
- expecteq("foo := 10, foo += 20, foo += 30", {
- { "foo", { "10", "20", "30" } },
- });
-
- expecteq("foo := 10, foo =+ 20, foo =+ 30", {
- { "foo", { "30", "20", "10" } },
- });
- }
-
- TEST_CASE("BXParser |=", "[BXParser][parse]") {
- expecteq("foo := 10, foo |= 10, foo |= 20", {
- { "foo", { "10", "20" } },
- });
- }
-
- TEST_CASE("BXParser newline separation", "[BXParser][parse]") {
- expecteq(
- "foo := 10 20\n"
- "bar := 30 40\n", {
- { "foo", { "10", "20" } },
- { "bar", { "30", "40" } },
- });
- }
-
- TEST_CASE("BXParser newline continuation", "[BXParser][parse]") {
- expecteq(
- "foo := 10 20\n"
- "\t30 40\n"
- "bar := hello world\n"
- "\tbaz \":=\" 30\n", {
- { "foo", { "10", "20", "30", "40" } },
- { "bar", { "hello", "world", "baz", ":=", "30" } },
- });
- }
|