parser_test.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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_array)
  134. {
  135. char const* sx_str = "#(1 \"foo\" #(bar))";
  136. auto sx = sexp::Parser::from_string(sx_str);
  137. ASSERT_TRUE(sx.is_array());
  138. ASSERT_EQ(sexp::Value::Type::ARRAY, sx.get_type());
  139. ASSERT_EQ(sx_str, sx.str());
  140. }
  141. // FIXME: Compare data structure or use simple strings?!
  142. // "(foo . bar)" as string is ambigous in the current parser as . can be handled as symbol, not pair
  143. TEST(ParserTest, simple_pair)
  144. {
  145. sexp::Value sx = sexp::Parser::from_string("(foo . bar)");
  146. ASSERT_EQ("(foo . bar)", sx.str());
  147. ASSERT_EQ("foo", sx.get_car().as_string());
  148. ASSERT_EQ("bar", sx.get_cdr().as_string());
  149. ASSERT_EQ(sexp::Value::Type::CONS, sx.get_type());
  150. ASSERT_EQ(sexp::Value::Type::SYMBOL, sx.get_car().get_type());
  151. ASSERT_EQ(sexp::Value::Type::SYMBOL, sx.get_cdr().get_type());
  152. ASSERT_EQ("(foo . bar)", sexp::Parser::from_string("(foo . bar)").str());
  153. }
  154. TEST(ParserTest, list_pair)
  155. {
  156. sexp::Value sx = sexp::Parser::from_string("(1 2 3 4 5 . 6)");
  157. ASSERT_EQ("(1 2 3 4 5 . 6)", sx.str());
  158. }
  159. TEST(ParserTest, line_numbers)
  160. {
  161. sexp::Value sx = sexp::Parser::from_string("("
  162. "line1\n"
  163. "line2\n"
  164. "line3\n"
  165. ")\n");
  166. ASSERT_EQ(1, sexp::list_ref(sx, 0).get_line());
  167. ASSERT_EQ(2, sexp::list_ref(sx, 1).get_line());
  168. ASSERT_EQ(3, sexp::list_ref(sx, 2).get_line());
  169. }
  170. // C++ locale support comes in the form of ugly global state that
  171. // spreads over most string formating functions, changing locale can
  172. // break a lot of stuff.
  173. class ParserLocaleTest : public ::testing::Test
  174. {
  175. private:
  176. std::locale m_oldlocale;
  177. protected:
  178. ParserLocaleTest() : m_oldlocale()
  179. {}
  180. virtual void SetUp() override
  181. {
  182. try {
  183. // This will fail when the locale is not installed on the system,
  184. // just ignore the test it in that case and let the test succeed.
  185. std::locale::global(std::locale("de_DE.UTF-8"));
  186. } catch (std::exception const& err) {
  187. std::cerr << "warning: failed to setup locale: " << err.what() << std::endl;
  188. }
  189. }
  190. virtual void TearDown() override
  191. {
  192. std::locale::global(m_oldlocale);
  193. }
  194. };
  195. TEST_F(ParserLocaleTest, locale_safe_input)
  196. {
  197. sexp::Value sx = sexp::Parser::from_string("0.015625");
  198. ASSERT_EQ(0.015625F, sx.as_float());
  199. }
  200. TEST_F(ParserLocaleTest, locale_safe_output)
  201. {
  202. sexp::Value sx = sexp::Value::real(0.015625f);
  203. ASSERT_EQ("0.015625", sx.str());
  204. }
  205. /* EOF */