summaryrefslogtreecommitdiffstats
path: root/tests/src/primitives-tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/primitives-tests.cpp')
-rw-r--r--tests/src/primitives-tests.cpp394
1 files changed, 394 insertions, 0 deletions
diff --git a/tests/src/primitives-tests.cpp b/tests/src/primitives-tests.cpp
new file mode 100644
index 0000000..0689d27
--- /dev/null
+++ b/tests/src/primitives-tests.cpp
@@ -0,0 +1,394 @@
+/**
+ *
+ * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "sexp-tests.h"
+
+using namespace sexp;
+
+namespace {
+class PrimitivesTests : public testing::Test {
+ protected:
+ static void do_test_advanced(const char *str_in, const char *str_out = nullptr)
+ {
+ std::istringstream iss(str_in);
+ sexp_input_stream_t is(&iss);
+ const auto obj = is.set_byte_size(8)->get_char()->scan_object();
+
+ std::ostringstream oss(std::ios_base::binary);
+ sexp_output_stream_t os(&oss);
+ os.print_advanced(obj);
+ const char *sample = str_out == nullptr ? str_in : str_out;
+ EXPECT_EQ(oss.str(), sample);
+ }
+
+ static void do_test_canonical(const char *str_in, const char *str_out = nullptr)
+ {
+ std::istringstream iss(str_in);
+ sexp_input_stream_t is(&iss);
+ const auto obj = is.set_byte_size(8)->get_char()->scan_object();
+
+ std::ostringstream oss(std::ios_base::binary);
+ sexp_output_stream_t os(&oss);
+ os.print_canonical(obj);
+ const char *sample = str_out == nullptr ? str_in : str_out;
+ EXPECT_EQ(oss.str(), sample);
+ }
+};
+
+TEST_F(PrimitivesTests, EmptyList)
+{
+ do_test_canonical("( )", "()");
+ do_test_advanced("( )", "()");
+}
+
+TEST_F(PrimitivesTests, EmptyString)
+{
+ sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error);
+ do_test_canonical("(\"\")", "(0:)");
+ do_test_advanced("(\"\")", "(\"\")");
+}
+
+TEST_F(PrimitivesTests, String)
+{
+ sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error);
+ do_test_canonical("(ab)", "(2:ab)");
+ do_test_advanced("(ab)", "(ab)");
+}
+
+TEST_F(PrimitivesTests, QuotedStringWithOctal)
+{
+ sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error);
+ do_test_canonical("\"ab\\015\"", "3:ab\r");
+ do_test_advanced("\"ab\\015\"", "#61620D#");
+}
+
+TEST_F(PrimitivesTests, QuotedStringWithEscape)
+{
+ sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error);
+ do_test_canonical("\"ab\\tc\"", "4:ab\tc");
+ do_test_advanced("4:ab\tc", "#61620963#");
+}
+
+TEST_F(PrimitivesTests, HexString)
+{
+ sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error);
+ do_test_canonical("#616263#", "3:abc");
+ do_test_advanced("#616263#", "abc");
+}
+
+TEST_F(PrimitivesTests, ListList)
+{
+ do_test_canonical("(string-level-1 (string-level-2) )",
+ "(14:string-level-1(14:string-level-2))");
+ do_test_advanced("(string-level-1 (string-level-2) )",
+ "(string-level-1 (string-level-2))");
+}
+
+TEST_F(PrimitivesTests, Base64Ofoctet_t)
+{
+ do_test_canonical("|YWJj|", "3:abc");
+ do_test_advanced("|YWJj|", "abc");
+}
+
+TEST_F(PrimitivesTests, Base64OfVerbatium)
+{
+ do_test_canonical("{MzphYmM=}", "3:abc");
+ do_test_advanced("{MzphYmM=}", "abc");
+}
+
+TEST_F(PrimitivesTests, MultilineLinux)
+{
+ do_test_canonical("\"abcd\\\nef\"", "6:abcdef");
+ do_test_advanced("\"abcd\\\nef\"", "abcdef");
+}
+
+TEST_F(PrimitivesTests, MultilineMac)
+{
+ do_test_canonical("\"abcd\\\ref\"", "6:abcdef");
+ do_test_advanced("\"abcd\\\ref\"", "abcdef");
+}
+
+TEST_F(PrimitivesTests, MultilineWin)
+{
+ do_test_canonical("\"abcd\\\r\nef\"", "6:abcdef");
+ do_test_advanced("\"abcd\\\r\nef\"", "abcdef");
+}
+
+TEST_F(PrimitivesTests, MultilineBsd)
+{
+ do_test_canonical("\"abcd\\\n\ref\"", "6:abcdef");
+ do_test_advanced("\"abcd\\\n\ref\"", "abcdef");
+}
+
+TEST_F(PrimitivesTests, Wrap)
+{
+ const char *reallyLong = "(a (b (c ddddddddddddddd"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "ddddddd)))";
+ const char *stillLong = "(1:a(1:b(1:c169:ddddddddd"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "ddddddddddddd)))";
+ const char *broken = "(a\n"
+ " (b\n"
+ " (c\n"
+ " "
+ "\"ddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "dddddddddddddddd\\\n"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddd\\\n"
+ "ddddddddddddddddddddddddddd\")))";
+ do_test_canonical(reallyLong, stillLong);
+ do_test_advanced(reallyLong, broken);
+}
+
+TEST_F(PrimitivesTests, Escapes)
+{
+ do_test_canonical("(\"\\b\\t\\v\\n\\f\\r\\\"\\'\\\\\")", "(9:\b\t\v\n\f\r\"'\\)");
+ do_test_advanced("(\"\\b\\t\\v\\n\\f\\r\\\"\\'\\\\\")", "(|CAkLCgwNIidc|)");
+
+ do_test_canonical("(\"\\040\\041\\042\\043\\044\")", "(5: !\"#$)");
+ do_test_advanced("(\"\\065\\061\\062\\063\\064\")", "(\"51234\")");
+
+ do_test_canonical("(\"\\x40\\x41\\x42\\x43\\x44\")", "(5:@ABCD)");
+ do_test_advanced("(\"\\x65\\x61\\x62\\x63\\x64\")", "(eabcd)");
+}
+
+TEST_F(PrimitivesTests, at4rnp)
+{
+ const char *str_in = "(rnp_block (rnp_list1 rnp_list2))";
+
+ std::istringstream iss(str_in);
+ sexp_input_stream_t is(&iss);
+
+ sexp_list_t lst;
+ lst.parse(is.set_byte_size(8)->get_char());
+
+ EXPECT_EQ(lst.sexp_list_at(0), nullptr);
+ EXPECT_NE(lst.sexp_list_at(1), nullptr);
+
+ EXPECT_NE(lst.sexp_string_at(0), nullptr);
+ EXPECT_EQ(lst.sexp_string_at(1), nullptr);
+
+ const sexp_object_t *obj = lst.sexp_list_at(1);
+
+ if (obj != nullptr) {
+ EXPECT_EQ(obj->sexp_list_at(0), nullptr);
+ EXPECT_EQ(obj->sexp_list_at(1), nullptr);
+ }
+
+ const sexp_string_t *sstr = lst.sexp_string_at(0);
+ EXPECT_STREQ(reinterpret_cast<const char *>(sstr->get_string().c_str()), "rnp_block");
+}
+
+TEST_F(PrimitivesTests, eq4rnp)
+{
+ const char *str_in = "(rnp_block (rnp_list1 rnp_list2))";
+
+ std::istringstream iss(str_in);
+ sexp_input_stream_t is(&iss);
+
+ sexp_list_t lst;
+ lst.parse(is.set_byte_size(8)->get_char());
+
+ EXPECT_TRUE(*lst.at(0) == "rnp_block");
+ EXPECT_FALSE(*lst.at(0) == "not_rnp_block");
+ EXPECT_FALSE(*lst.at(1) == "rnp_block");
+ EXPECT_FALSE(*lst.at(1) == "not_rnp_block");
+
+ EXPECT_TRUE(*lst.sexp_string_at(0) == "rnp_block");
+ EXPECT_FALSE(*lst.sexp_string_at(0) == "not_rnp_block");
+ EXPECT_TRUE(*lst.sexp_simple_string_at(0) == "rnp_block");
+ EXPECT_FALSE(*lst.sexp_simple_string_at(0) == "not_rnp_block");
+
+ EXPECT_TRUE(*lst.sexp_list_at(1)->at(0) == "rnp_list1");
+ EXPECT_TRUE(*lst.sexp_list_at(1)->sexp_string_at(1) == "rnp_list2");
+
+ EXPECT_TRUE(lst.sexp_string_at(0) == std::string("rnp_block"));
+ EXPECT_FALSE(lst.sexp_string_at(0) == std::string("not_rnp_block"));
+ EXPECT_TRUE(lst.sexp_simple_string_at(0) == std::string("rnp_block"));
+ EXPECT_FALSE(lst.sexp_simple_string_at(0) == std::string("not_rnp_block"));
+}
+
+TEST_F(PrimitivesTests, ne4rnp)
+{
+ const char *str_in = "(rnp_block (rnp_list1 rnp_list2))";
+
+ std::istringstream iss(str_in);
+ sexp_input_stream_t is(&iss);
+
+ sexp_list_t lst;
+ lst.parse(is.set_byte_size(8)->get_char());
+
+ EXPECT_FALSE(*lst.at(0) != "rnp_block");
+ EXPECT_TRUE(*lst.at(0) != "not_rnp_block");
+ EXPECT_TRUE(*lst.at(1) != "rnp_block");
+ EXPECT_TRUE(*lst.at(1) != "not_rnp_block");
+
+ EXPECT_FALSE(*lst.sexp_string_at(0) != "rnp_block");
+ EXPECT_TRUE(*lst.sexp_string_at(0) != "not_rnp_block");
+ EXPECT_FALSE(*lst.sexp_simple_string_at(0) != "rnp_block");
+ EXPECT_TRUE(*lst.sexp_simple_string_at(0) != "not_rnp_block");
+
+ EXPECT_FALSE(*lst.sexp_list_at(1)->at(0) != "rnp_list1");
+ EXPECT_FALSE(*lst.sexp_list_at(1)->sexp_string_at(1) != "rnp_list2");
+
+ EXPECT_FALSE(lst.sexp_string_at(0) != std::string("rnp_block"));
+ EXPECT_TRUE(lst.sexp_string_at(0) != std::string("not_rnp_block"));
+ EXPECT_FALSE(lst.sexp_simple_string_at(0) != std::string("rnp_block"));
+ EXPECT_TRUE(lst.sexp_simple_string_at(0) != std::string("not_rnp_block"));
+}
+
+TEST_F(PrimitivesTests, u4rnp)
+{
+ const char *str_in1 = "(unsigned_value \"12345\")";
+ const char *str_in2 = "(14:unsigned_value5:54321)";
+
+ std::istringstream iss1(str_in1);
+ std::istringstream iss2(str_in2);
+
+ sexp_input_stream_t is(&iss1);
+ sexp_list_t lst;
+ lst.parse(is.set_byte_size(8)->get_char());
+ EXPECT_EQ(lst.sexp_string_at(1)->as_unsigned(), 12345);
+
+ lst.clear();
+ lst.parse(is.set_input(&iss2)->set_byte_size(8)->get_char());
+ EXPECT_EQ(lst.sexp_string_at(1)->as_unsigned(), 54321);
+}
+
+TEST_F(PrimitivesTests, proInheritance)
+{
+ sexp_list_t lst;
+ EXPECT_FALSE(lst.is_sexp_string());
+ EXPECT_TRUE(lst.is_sexp_list());
+ EXPECT_EQ(lst.sexp_string_view(), nullptr);
+ EXPECT_EQ(lst.sexp_list_view(), &lst);
+ EXPECT_EQ(lst.as_unsigned(), std::numeric_limits<uint32_t>::max());
+ EXPECT_EQ(lst.sexp_list_at(0), nullptr);
+ EXPECT_EQ(lst.sexp_string_at(0), nullptr);
+ EXPECT_EQ(lst.sexp_simple_string_at(0), nullptr);
+
+ sexp_string_t str;
+ EXPECT_FALSE(str.is_sexp_list());
+ EXPECT_TRUE(str.is_sexp_string());
+ EXPECT_EQ(str.sexp_string_view(), &str);
+ EXPECT_EQ(str.sexp_list_view(), nullptr);
+ EXPECT_EQ(str.sexp_list_at(0), nullptr);
+ EXPECT_EQ(str.sexp_string_at(0), nullptr);
+ EXPECT_EQ(str.sexp_simple_string_at(0), nullptr);
+}
+
+TEST_F(PrimitivesTests, DisplayHint)
+{
+ do_test_canonical("(URL [URI]www.ribose.com)", "(3:URL[3:URI]14:www.ribose.com)");
+ do_test_advanced("(3:URL[3:URI]14:www.ribose.com)", "(URL [URI]www.ribose.com)");
+}
+
+TEST_F(PrimitivesTests, scanToEof)
+{
+ const char *str_in = "ABCD";
+
+ std::istringstream iss(str_in);
+ sexp_input_stream_t is(&iss);
+
+ auto object = is.scan_to_eof();
+ EXPECT_TRUE(object->is_sexp_string());
+
+ is.set_byte_size(4);
+ EXPECT_EQ(is.get_byte_size(), 4);
+
+ EXPECT_EQ(is.get_char(), &is);
+ EXPECT_EQ(is.get_byte_size(), 8);
+}
+
+TEST_F(PrimitivesTests, ChangeOutputByteSizeTest)
+{
+ std::ostringstream oss(std::ios_base::binary);
+ sexp_output_stream_t os(&oss);
+
+ EXPECT_EQ(os.change_output_byte_size(8, sexp_output_stream_t::advanced), &os);
+
+ try {
+ os.change_output_byte_size(7, sexp_output_stream_t::advanced);
+ FAIL() << "sexp::sexp_exception_t expected but has not been thrown";
+ } catch (sexp::sexp_exception_t &e) {
+ EXPECT_STREQ(e.what(), "SEXP ERROR: Illegal output base 7");
+ }
+
+ EXPECT_EQ(os.change_output_byte_size(4, sexp_output_stream_t::advanced), &os);
+
+ try {
+ os.change_output_byte_size(6, sexp_output_stream_t::advanced);
+ FAIL() << "sexp::sexp_exception_t expected but has not been thrown";
+ } catch (sexp::sexp_exception_t &e) {
+ EXPECT_STREQ(e.what(), "SEXP ERROR: Illegal change of output byte size from 4 to 6");
+ }
+}
+
+TEST_F(PrimitivesTests, FlushTest)
+{
+ std::ostringstream oss1(std::ios_base::binary);
+ std::ostringstream oss2(std::ios_base::binary);
+ sexp_output_stream_t os(&oss1);
+
+ EXPECT_EQ(
+ os.change_output_byte_size(6, sexp_output_stream_t::advanced)->print_decimal(1)->flush(),
+ &os);
+ EXPECT_EQ(oss1.str(), "MQ==");
+ os.set_output(&oss2)
+ ->change_output_byte_size(6, sexp_output_stream_t::advanced)
+ ->set_max_column(2)
+ ->print_decimal(2)
+ ->flush();
+ EXPECT_EQ(oss2.str(), "Mg\n==");
+}
+
+TEST_F(PrimitivesTests, ListWrapTest)
+{
+ std::istringstream iss("(abc)");
+ sexp_input_stream_t is(&iss);
+ const auto obj = is.set_byte_size(8)->get_char()->scan_object();
+
+ std::ostringstream oss(std::ios_base::binary);
+ sexp_output_stream_t os(&oss);
+ os.set_max_column(5)->print_advanced(obj);
+ EXPECT_EQ(oss.str(), "(abc\n )");
+}
+
+TEST_F(PrimitivesTests, EnsureHexTest)
+{
+ std::istringstream iss("(3:a\011c)");
+ sexp_input_stream_t is(&iss);
+ const auto obj = is.set_byte_size(8)->get_char()->scan_object();
+
+ std::ostringstream oss(std::ios_base::binary);
+ sexp_output_stream_t os(&oss);
+ os.print_advanced(obj);
+ EXPECT_EQ(oss.str(), "(#610963#)");
+}
+
+} // namespace