parser_test.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // SExp - A S-Expression Parser for C++
  2. // Copyright (C) 2015 Ingo Ruhnke <grumbel@gmail.com>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include <gtest/gtest.h>
  17. #include <iostream>
  18. #include <sstream>
  19. #include "sexp/io.hpp"
  20. #include "sexp/parser.hpp"
  21. #include "sexp/util.hpp"
  22. #include "sexp/value.hpp"
  23. TEST(ParserTest, single)
  24. {
  25. auto result = sexp::Parser::from_string("(1 2.5 foo \"TEXT\" bar)");
  26. auto expected = sexp::Value::list(sexp::Value::integer(1),
  27. sexp::Value::real(2.5),
  28. sexp::Value::symbol("foo"),
  29. sexp::Value::string("TEXT"),
  30. sexp::Value::symbol("bar"));
  31. ASSERT_EQ(expected, result);
  32. }
  33. TEST(ParserTest, single_fail)
  34. {
  35. std::istringstream in("(1 2.5 foo \"TEXT\" bar bar) 5");
  36. ASSERT_THROW({
  37. sexp::Value cons = sexp::Parser::from_stream(in);
  38. },
  39. std::runtime_error);
  40. }
  41. TEST(ParserTest, parse_many)
  42. {
  43. std::istringstream in("1 2.5 foo \"TEXT\" bar");
  44. std::vector<sexp::Value> value = sexp::Parser::from_stream_many(in);
  45. ASSERT_EQ(5, value.size());
  46. ASSERT_EQ(value[0].get_type(), sexp::Value::Type::INTEGER);
  47. ASSERT_EQ(value[1].get_type(), sexp::Value::Type::REAL);
  48. ASSERT_EQ(value[2].get_type(), sexp::Value::Type::SYMBOL);
  49. ASSERT_EQ(value[3].get_type(), sexp::Value::Type::STRING);
  50. ASSERT_EQ(value[4].get_type(), sexp::Value::Type::SYMBOL);
  51. }
  52. TEST(ParserTest, parse_positive_integer)
  53. {
  54. auto sx = sexp::Parser::from_string("12345");
  55. ASSERT_EQ(12345, sx.as_int());
  56. }
  57. TEST(ParserTest, parse_negative_integer)
  58. {
  59. {
  60. auto sx = sexp::Parser::from_string("-12345");
  61. ASSERT_EQ(-12345, sx.as_int());
  62. }
  63. {
  64. sexp::Value sx = sexp::Parser::from_string("-");
  65. ASSERT_TRUE(sx.is_symbol());
  66. }
  67. }
  68. TEST(ParserTest, parse_positive_real)
  69. {
  70. {
  71. auto sx = sexp::Parser::from_string("0.125");
  72. ASSERT_EQ(sexp::Value::Type::REAL, sx.get_type());
  73. ASSERT_EQ(0.125F, sx.as_float());
  74. }
  75. {
  76. auto sx = sexp::Parser::from_string(".125");
  77. ASSERT_EQ(sexp::Value::Type::REAL, sx.get_type());
  78. ASSERT_EQ(0.125F, sx.as_float());
  79. }
  80. }
  81. TEST(ParserTest, parse_negative_real)
  82. {
  83. {
  84. auto sx = sexp::Parser::from_string("-0.125");
  85. ASSERT_EQ(sexp::Value::Type::REAL, sx.get_type());
  86. ASSERT_EQ(-0.125F, sx.as_float());
  87. }
  88. {
  89. auto sx = sexp::Parser::from_string("-.125");
  90. ASSERT_EQ(sexp::Value::Type::REAL, sx.get_type());
  91. ASSERT_EQ(-0.125F, sx.as_float());
  92. }
  93. }
  94. TEST(ParserTest, parse_scientific_real)
  95. {
  96. {
  97. auto sx = sexp::Parser::from_string("1.2345e-13");
  98. ASSERT_EQ(sexp::Value::Type::REAL, sx.get_type());
  99. ASSERT_EQ(1.2345e-13F, sx.as_float());
  100. }
  101. {
  102. auto sx = sexp::Parser::from_string("-1.2345e+13");
  103. ASSERT_EQ(sexp::Value::Type::REAL, sx.get_type());
  104. ASSERT_EQ(-1.2345e+13F, sx.as_float());
  105. }
  106. }
  107. TEST(ParserTest, parse_string)
  108. {
  109. {
  110. auto sx = sexp::Parser::from_string("\"Hello\\nWorld\"");
  111. ASSERT_EQ(sexp::Value::Type::STRING, sx.get_type());
  112. ASSERT_EQ("Hello\nWorld", sx.as_string());
  113. }
  114. {
  115. auto sx = sexp::Parser::from_string("\"\\\"Hello\\nWorld\\\"\"");
  116. ASSERT_EQ(sexp::Value::Type::STRING, sx.get_type());
  117. ASSERT_EQ("\"Hello\nWorld\"", sx.as_string());
  118. }
  119. }
  120. TEST(ParserTest, parse_symbol)
  121. {
  122. {
  123. auto sx = sexp::Parser::from_string("HelloWorld");
  124. ASSERT_EQ(sexp::Value::Type::SYMBOL, sx.get_type());
  125. ASSERT_EQ("HelloWorld", sx.as_string());
  126. }
  127. {
  128. auto sx = sexp::Parser::from_string("5.6.7");
  129. ASSERT_EQ(sexp::Value::Type::SYMBOL, sx.get_type());
  130. ASSERT_EQ("5.6.7", sx.as_string());
  131. }
  132. }
  133. TEST(ParserTest, parse_cons)
  134. {
  135. char const* sx_str = "(1 \"foo\" (bar))";
  136. auto sx = sexp::Parser::from_string(sx_str, false);
  137. ASSERT_TRUE(sx.is_cons());
  138. ASSERT_EQ(sexp::Value::Type::CONS, sx.get_type());
  139. ASSERT_EQ(sx_str, sx.str());
  140. }
  141. TEST(ParserTest, parse_cons_depth_limit)
  142. {
  143. auto sx = sexp::Parser::from_string("(1 \"foo\" (bar foo (foo 1) 2 (\"bar\" . 4)))", false, 1);
  144. ASSERT_TRUE(sx.is_cons());
  145. ASSERT_EQ(sexp::Value::Type::CONS, sx.get_type());
  146. ASSERT_EQ("(1 \"foo\" (bar foo 2))", sx.str());
  147. }
  148. TEST(ParserTest, parse_array)
  149. {
  150. char const* sx_str = "#(1 \"foo\" #(bar))";
  151. auto sx = sexp::Parser::from_string(sx_str);
  152. ASSERT_TRUE(sx.is_array());
  153. ASSERT_EQ(sexp::Value::Type::ARRAY, sx.get_type());
  154. ASSERT_EQ(sx_str, sx.str());
  155. }
  156. TEST(ParserTest, parse_array_depth_limit)
  157. {
  158. auto sx = sexp::Parser::from_string("#(1 \"foo\" #(bar foo #(foo 1) 2 #(\"bar\" 4)))", false, 1);
  159. ASSERT_TRUE(sx.is_array());
  160. ASSERT_EQ(sexp::Value::Type::ARRAY, sx.get_type());
  161. ASSERT_EQ("#(1 \"foo\" #(bar foo 2))", sx.str());
  162. }
  163. // FIXME: Compare data structure or use simple strings?!
  164. // "(foo . bar)" as string is ambigous in the current parser as . can be handled as symbol, not pair
  165. TEST(ParserTest, simple_pair)
  166. {
  167. sexp::Value sx = sexp::Parser::from_string("(foo . bar)");
  168. ASSERT_EQ("(foo . bar)", sx.str());
  169. ASSERT_EQ("foo", sx.get_car().as_string());
  170. ASSERT_EQ("bar", sx.get_cdr().as_string());
  171. ASSERT_EQ(sexp::Value::Type::CONS, sx.get_type());
  172. ASSERT_EQ(sexp::Value::Type::SYMBOL, sx.get_car().get_type());
  173. ASSERT_EQ(sexp::Value::Type::SYMBOL, sx.get_cdr().get_type());
  174. ASSERT_EQ("(foo . bar)", sexp::Parser::from_string("(foo . bar)").str());
  175. }
  176. TEST(ParserTest, list_pair)
  177. {
  178. sexp::Value sx = sexp::Parser::from_string("(1 2 3 4 5 . 6)");
  179. ASSERT_EQ("(1 2 3 4 5 . 6)", sx.str());
  180. }
  181. TEST(ParserTest, line_numbers)
  182. {
  183. sexp::Value sx = sexp::Parser::from_string("("
  184. "line1\n"
  185. "line2\n"
  186. "line3\n"
  187. ")\n");
  188. ASSERT_EQ(1, sexp::list_ref(sx, 0).get_line());
  189. ASSERT_EQ(2, sexp::list_ref(sx, 1).get_line());
  190. ASSERT_EQ(3, sexp::list_ref(sx, 2).get_line());
  191. }
  192. // C++ locale support comes in the form of ugly global state that
  193. // spreads over most string formating functions, changing locale can
  194. // break a lot of stuff.
  195. class ParserLocaleTest : public ::testing::Test
  196. {
  197. private:
  198. std::locale m_oldlocale;
  199. protected:
  200. ParserLocaleTest() : m_oldlocale()
  201. {}
  202. virtual void SetUp() override
  203. {
  204. try {
  205. // This will fail when the locale is not installed on the system,
  206. // just ignore the test it in that case and let the test succeed.
  207. std::locale::global(std::locale("de_DE.UTF-8"));
  208. } catch (std::exception const& err) {
  209. std::cerr << "warning: failed to setup locale: " << err.what() << std::endl;
  210. }
  211. }
  212. virtual void TearDown() override
  213. {
  214. std::locale::global(m_oldlocale);
  215. }
  216. };
  217. TEST_F(ParserLocaleTest, locale_safe_input)
  218. {
  219. sexp::Value sx = sexp::Parser::from_string("0.015625");
  220. ASSERT_EQ(0.015625F, sx.as_float());
  221. }
  222. TEST_F(ParserLocaleTest, locale_safe_output)
  223. {
  224. sexp::Value sx = sexp::Value::real(0.015625f);
  225. ASSERT_EQ("0.015625", sx.str());
  226. }
  227. /* EOF */