1 //-----------------------------------------------------------------------------
2 /** @file libboardgame_base/tests/TreeReaderTest.cpp
3 @author Markus Enzenberger
4 @copyright GNU General Public License version 3 or later */
5 //-----------------------------------------------------------------------------
6
7 #include "libboardgame_base/TreeReader.h"
8
9 #include <sstream>
10 #include "libboardgame_base/TreeWriter.h"
11 #include "libboardgame_test/Test.h"
12
13 using namespace std;
14 using namespace libboardgame_base;
15
16 //-----------------------------------------------------------------------------
17
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_basic)18 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_basic)
19 {
20 istringstream in("(;B[aa];W[bb])");
21 TreeReader reader;
22 reader.read(in);
23 auto& root = reader.get_tree();
24 LIBBOARDGAME_CHECK(root.has_property("B"));
25 LIBBOARDGAME_CHECK(root.has_single_child());
26 auto& child = root.get_child();
27 LIBBOARDGAME_CHECK(child.has_property("W"));
28 LIBBOARDGAME_CHECK(! child.has_children());
29 }
30
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_basic_2)31 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_basic_2)
32 {
33 istringstream in("(;C[1](;C[2.1])(;C[2.2]))");
34 TreeReader reader;
35 reader.read(in);
36 auto& root = reader.get_tree();
37 LIBBOARDGAME_CHECK_EQUAL(root.get_property("C"), "1");
38 LIBBOARDGAME_CHECK_EQUAL(root.get_nu_children(), 2u);
39 LIBBOARDGAME_CHECK_EQUAL(root.get_child(0).get_property("C"), "2.1");
40 LIBBOARDGAME_CHECK_EQUAL(root.get_child(1).get_property("C"), "2.2");
41 }
42
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_multiprop_with_whitespace)43 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_multiprop_with_whitespace)
44 {
45 istringstream in("(;A [1]\n[2] [3]\t[4]\r\n[5])");
46 TreeReader reader;
47 reader.read(in);
48 auto& root = reader.get_tree();
49 auto values = root.get_multi_property("A");
50 LIBBOARDGAME_CHECK_EQUAL(values.size(), 5u);
51 LIBBOARDGAME_CHECK_EQUAL(values[0], "1");
52 LIBBOARDGAME_CHECK_EQUAL(values[1], "2");
53 LIBBOARDGAME_CHECK_EQUAL(values[2], "3");
54 LIBBOARDGAME_CHECK_EQUAL(values[3], "4");
55 LIBBOARDGAME_CHECK_EQUAL(values[4], "5");
56 }
57
58 /** Test that a property value with a unicode character is preserved after
59 reading and writing.
60 In previous versions this was broken because of a bug in the replacement
61 of non-newline whitespaces (as required by SGF) by the writer. (The bug
62 occurred only on some platforms depending on the std::isspace()
63 implementation.) */
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_unicode)64 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_unicode)
65 {
66 SgfNode root;
67 const char* id = "C";
68 const char* value = u8"ü";
69 root.set_property(id, value);
70 ostringstream out;
71 TreeWriter writer(out, root);
72 writer.write();
73 istringstream in(out.str());
74 TreeReader reader;
75 reader.read(in);
76 LIBBOARDGAME_CHECK_EQUAL(reader.get_tree().get_property(id), value);
77 }
78
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_property_after_newline)79 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_property_after_newline)
80 {
81 istringstream in("(;FF[4]\n"
82 "CA[UTF-8])");
83 TreeReader reader;
84 reader.read(in);
85 auto& root = reader.get_tree();
86 LIBBOARDGAME_CHECK(root.has_property("FF"));
87 LIBBOARDGAME_CHECK(root.has_property("CA"));
88 }
89
90 /** Test cross-platform handling of property values containing newlines.
91 The reader should convert all platform-dependent newline sequences (LF,
92 CR+LF, CR) into LF, such that property values containing newlines are
93 independent on the platform that was used to write the file. */
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_newline)94 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_newline)
95 {
96 {
97 istringstream in("(;C[1\n2])");
98 TreeReader reader;
99 reader.read(in);
100 auto& root = reader.get_tree();
101 LIBBOARDGAME_CHECK_EQUAL(root.get_property("C"), "1\n2");
102 }
103 {
104 istringstream in("(;C[1\r\n2])");
105 TreeReader reader;
106 reader.read(in);
107 auto& root = reader.get_tree();
108 LIBBOARDGAME_CHECK_EQUAL(root.get_property("C"), "1\n2");
109 }
110 {
111 istringstream in("(;C[1\r2])");
112 TreeReader reader;
113 reader.read(in);
114 auto& root = reader.get_tree();
115 LIBBOARDGAME_CHECK_EQUAL(root.get_property("C"), "1\n2");
116 }
117 }
118
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_property_without_value)119 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_property_without_value)
120 {
121 istringstream in("(;B)");
122 TreeReader reader;
123 LIBBOARDGAME_CHECK_THROW(reader.read(in), TreeReader::ReadError);
124 }
125
LIBBOARDGAME_TEST_CASE(sgf_tree_reader_text_before_node)126 LIBBOARDGAME_TEST_CASE(sgf_tree_reader_text_before_node)
127 {
128 istringstream in("(B;)");
129 TreeReader reader;
130 LIBBOARDGAME_CHECK_THROW(reader.read(in), TreeReader::ReadError);
131 }
132
133 //-----------------------------------------------------------------------------
134