Build tool
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BXParser.t.cc 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #include <initializer_list>
  2. #include <unordered_set>
  3. #include "BXParser.h"
  4. #include "catch.hpp"
  5. static BXVariables parse(const char *str) {
  6. bufio::ISStream stream(str);
  7. BXParser parser(stream);
  8. BXVariables vars;
  9. parser.parse(vars);
  10. return vars;
  11. }
  12. std::string stringify(std::vector<std::string> &vec) {
  13. if (vec.size() == 0) {
  14. return "(empty)";
  15. }
  16. std::string s;
  17. for (auto &val: vec) {
  18. if (s.size() == 0) {
  19. s += '\'' + val + '\'';
  20. } else {
  21. s += " '" + val + '\'';
  22. }
  23. }
  24. return s;
  25. }
  26. static void expecteq(
  27. const char *str,
  28. const std::initializer_list<std::pair<
  29. std::string, std::vector<std::string>>> list) {
  30. INFO("Source: " << str);
  31. bufio::ISStream stream(str);
  32. BXParser parser(stream);
  33. BXVariables vars;
  34. parser.parse(vars);
  35. std::unordered_set<std::string> keyset;
  36. for (auto &expected: list) {
  37. keyset.insert(expected.first);
  38. auto it = vars.find(expected.first);
  39. if (it == vars.end()) {
  40. FAIL("Missing key '" << expected.first << "'!");
  41. }
  42. if (it->second != expected.second) {
  43. INFO("Value: " << stringify(it->second));
  44. FAIL("Value of key '" << expected.first << "' doesn't match!");
  45. }
  46. }
  47. for (auto &pair: vars) {
  48. if (keyset.find(pair.first) == keyset.end()) {
  49. FAIL("Unexpected key '" << pair.first << "'!");
  50. }
  51. }
  52. }
  53. static void lexeq(BXVariables &vars, const char *str, std::initializer_list<BXParser::Token> list) {
  54. INFO("Source: " << str);
  55. bufio::ISStream stream(str);
  56. BXParser parser(stream);
  57. parser.readToken(vars);
  58. size_t i = 1;
  59. for (auto &expected: list) {
  60. BXParser::Token tok = parser.readToken(vars);
  61. if (tok.kind != expected.kind) {
  62. INFO("Expected: " << (int)expected.kind);
  63. INFO("Actual: " << (int)tok.kind);
  64. FAIL("Token " << i << " doesn't match");
  65. }
  66. if (tok.str != expected.str) {
  67. INFO("Expected: '" << expected.str << '\'');
  68. INFO("Actual: '" << tok.str << '\'');
  69. FAIL("Token " << i << "'s string doesn't match");
  70. }
  71. if (tok.kind == BXParser::TokenKind::E_O_F) {
  72. return;
  73. }
  74. i += 1;
  75. }
  76. }
  77. static void lexeq(const char *str, std::initializer_list<BXParser::Token> list) {
  78. BXVariables vars;
  79. lexeq(vars, str, list);
  80. }
  81. TEST_CASE("BXParser lex", "[BXParser][lex]") {
  82. lexeq("hello world", {
  83. { BXParser::TokenKind::STRING, "hello" },
  84. { BXParser::TokenKind::STRING, "world" },
  85. { BXParser::TokenKind::E_O_F },
  86. });
  87. lexeq("hello := what's up", {
  88. { BXParser::TokenKind::STRING, "hello" },
  89. { BXParser::TokenKind::COLON_EQUALS },
  90. { BXParser::TokenKind::STRING, "what's" },
  91. { BXParser::TokenKind::STRING, "up" },
  92. { BXParser::TokenKind::E_O_F },
  93. });
  94. lexeq("\t\t \t, := += =+\n\n\r\nhello", {
  95. { BXParser::TokenKind::INDENTATION },
  96. { BXParser::TokenKind::COMMA },
  97. { BXParser::TokenKind::COLON_EQUALS },
  98. { BXParser::TokenKind::PLUS_EQUALS },
  99. { BXParser::TokenKind::EQUALS_PLUS },
  100. { BXParser::TokenKind::NEWLINE },
  101. { BXParser::TokenKind::STRING, "hello" },
  102. { BXParser::TokenKind::E_O_F },
  103. });
  104. }
  105. TEST_CASE("BXParser lex string interpolation", "[BXParser][lex]") {
  106. BXVariables vars = {
  107. { "foo", { "hello"} },
  108. };
  109. lexeq(vars, "hey \"$foo\" lol", {
  110. { BXParser::TokenKind::STRING, "hey" },
  111. { BXParser::TokenKind::STRING, "hello" },
  112. { BXParser::TokenKind::STRING, "lol" },
  113. });
  114. lexeq(vars, "hey \"no$foo\" lol", {
  115. { BXParser::TokenKind::STRING, "hey" },
  116. { BXParser::TokenKind::STRING, "nohello" },
  117. { BXParser::TokenKind::STRING, "lol" },
  118. });
  119. lexeq(vars, "hey \"Xx${foo}xX\" lol", {
  120. { BXParser::TokenKind::STRING, "hey" },
  121. { BXParser::TokenKind::STRING, "XxhelloxX" },
  122. { BXParser::TokenKind::STRING, "lol" },
  123. });
  124. }
  125. TEST_CASE("BXParser lex string interpolation without quotes", "[BXParser][lex]") {
  126. BXVariables vars = {
  127. { "foo", { "hello"} },
  128. };
  129. lexeq(vars, "hey Xx$foo lol", {
  130. { BXParser::TokenKind::STRING, "hey" },
  131. { BXParser::TokenKind::STRING, "Xxhello" },
  132. { BXParser::TokenKind::STRING, "lol" },
  133. });
  134. lexeq(vars, "hey Xx${ foo }xX lol", {
  135. { BXParser::TokenKind::STRING, "hey" },
  136. { BXParser::TokenKind::STRING, "XxhelloxX" },
  137. { BXParser::TokenKind::STRING, "lol" },
  138. });
  139. }
  140. TEST_CASE("BXParser lex array expansion", "[BXParser][lex]") {
  141. lexeq("hey $foo lol", {
  142. { BXParser::TokenKind::STRING, "hey" },
  143. { BXParser::TokenKind::EXPANSION, "foo" },
  144. { BXParser::TokenKind::STRING, "lol" },
  145. });
  146. lexeq("hey ${foo} lol", {
  147. { BXParser::TokenKind::STRING, "hey" },
  148. { BXParser::TokenKind::EXPANSION, "foo" },
  149. { BXParser::TokenKind::STRING, "lol" },
  150. });
  151. lexeq("hey ${ \tfoo\n \n} lol", {
  152. { BXParser::TokenKind::STRING, "hey" },
  153. { BXParser::TokenKind::EXPANSION, "foo" },
  154. { BXParser::TokenKind::STRING, "lol" },
  155. });
  156. }
  157. TEST_CASE("BXParser parsing", "[BXParser][parse]") {
  158. expecteq("hello := 10, world := 20", {
  159. { "hello", { "10" } },
  160. { "world", { "20" } },
  161. });
  162. expecteq("foo := hello world, bar := 10 20 30, baz := 0", {
  163. { "foo", { "hello", "world" } },
  164. { "bar", { "10", "20", "30" } },
  165. { "baz", { "0" } },
  166. });
  167. }
  168. TEST_CASE("BXParser parsing variables", "[BXParser][parse]") {
  169. expecteq("foo := \"hello world\", bar := $foo", {
  170. { "foo", { "hello world" } },
  171. { "bar", { "hello world" } },
  172. });
  173. expecteq("foo := hello world, bar := hey $foo what's up", {
  174. { "foo", { "hello", "world" } },
  175. { "bar", { "hey", "hello", "world", "what's", "up" } },
  176. });
  177. }
  178. TEST_CASE("BXParser append/prepend", "[BXParser][parse]") {
  179. expecteq("foo := 10, foo += 20, foo += 30", {
  180. { "foo", { "10", "20", "30" } },
  181. });
  182. expecteq("foo := 10, foo =+ 20, foo =+ 30", {
  183. { "foo", { "30", "20", "10" } },
  184. });
  185. }
  186. TEST_CASE("BXParser |=", "[BXParser][parse]") {
  187. expecteq("foo := 10, foo |= 10, foo |= 20", {
  188. { "foo", { "10", "20" } },
  189. });
  190. }
  191. TEST_CASE("BXParser newline separation", "[BXParser][parse]") {
  192. expecteq(
  193. "foo := 10 20\n"
  194. "bar := 30 40\n", {
  195. { "foo", { "10", "20" } },
  196. { "bar", { "30", "40" } },
  197. });
  198. }
  199. TEST_CASE("BXParser newline continuation", "[BXParser][parse]") {
  200. expecteq(
  201. "foo := 10 20\n"
  202. "\t30 40\n"
  203. "bar := hello world\n"
  204. "\tbaz \":=\" 30\n", {
  205. { "foo", { "10", "20", "30", "40" } },
  206. { "bar", { "hello", "world", "baz", ":=", "30" } },
  207. });
  208. }