Branch data Line data Source code
1 : : // Copyright (c) 2017 The Zcash developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : : //
5 : :
6 : : #include <boost/test/unit_test.hpp>
7 : :
8 : : #include <map>
9 : : #include <string>
10 : : #include <utility>
11 : :
12 : :
13 : : std::pair<std::string, std::string> SplitTorReplyLine(const std::string& s);
14 : : std::map<std::string, std::string> ParseTorReplyMapping(const std::string& s);
15 : :
16 : :
17 : 0 : BOOST_AUTO_TEST_SUITE(torcontrol_tests)
18 : :
19 : 0 : static void CheckSplitTorReplyLine(std::string input, std::string command, std::string args)
20 : : {
21 : 0 : auto ret = SplitTorReplyLine(input);
22 : 0 : BOOST_CHECK_EQUAL(ret.first, command);
23 : 0 : BOOST_CHECK_EQUAL(ret.second, args);
24 : 0 : }
25 : :
26 : 0 : BOOST_AUTO_TEST_CASE(util_SplitTorReplyLine)
27 : : {
28 : : // Data we should receive during normal usage
29 : 0 : CheckSplitTorReplyLine(
30 : 0 : "PROTOCOLINFO PIVERSION",
31 : 0 : "PROTOCOLINFO", "PIVERSION");
32 : 0 : CheckSplitTorReplyLine(
33 : 0 : "AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"",
34 : 0 : "AUTH", "METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"");
35 : 0 : CheckSplitTorReplyLine(
36 : 0 : "AUTH METHODS=NULL",
37 : 0 : "AUTH", "METHODS=NULL");
38 : 0 : CheckSplitTorReplyLine(
39 : 0 : "AUTH METHODS=HASHEDPASSWORD",
40 : 0 : "AUTH", "METHODS=HASHEDPASSWORD");
41 : 0 : CheckSplitTorReplyLine(
42 : 0 : "VERSION Tor=\"0.2.9.8 (git-a0df013ea241b026)\"",
43 : 0 : "VERSION", "Tor=\"0.2.9.8 (git-a0df013ea241b026)\"");
44 : 0 : CheckSplitTorReplyLine(
45 : 0 : "AUTHCHALLENGE SERVERHASH=aaaa SERVERNONCE=bbbb",
46 : 0 : "AUTHCHALLENGE", "SERVERHASH=aaaa SERVERNONCE=bbbb");
47 : :
48 : : // Other valid inputs
49 : 0 : CheckSplitTorReplyLine("COMMAND", "COMMAND", "");
50 : 0 : CheckSplitTorReplyLine("COMMAND SOME ARGS", "COMMAND", "SOME ARGS");
51 : :
52 : : // These inputs are valid because PROTOCOLINFO accepts an OtherLine that is
53 : : // just an OptArguments, which enables multiple spaces to be present
54 : : // between the command and arguments.
55 : 0 : CheckSplitTorReplyLine("COMMAND ARGS", "COMMAND", " ARGS");
56 : 0 : CheckSplitTorReplyLine("COMMAND EVEN+more ARGS", "COMMAND", " EVEN+more ARGS");
57 : 0 : }
58 : :
59 : 0 : static void CheckParseTorReplyMapping(std::string input, std::map<std::string,std::string> expected)
60 : : {
61 : 0 : auto ret = ParseTorReplyMapping(input);
62 : 0 : BOOST_CHECK_EQUAL(ret.size(), expected.size());
63 : 0 : auto r_it = ret.begin();
64 : 0 : auto e_it = expected.begin();
65 : 0 : while (r_it != ret.end() && e_it != expected.end()) {
66 : 0 : BOOST_CHECK_EQUAL(r_it->first, e_it->first);
67 : 0 : BOOST_CHECK_EQUAL(r_it->second, e_it->second);
68 : 0 : r_it++;
69 : 0 : e_it++;
70 : : }
71 : 0 : }
72 : :
73 : 0 : BOOST_AUTO_TEST_CASE(util_ParseTorReplyMapping)
74 : 0 : {
75 : : // Data we should receive during normal usage
76 : 0 : CheckParseTorReplyMapping(
77 : 0 : "METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"", {
78 : 0 : {"METHODS", "COOKIE,SAFECOOKIE"},
79 : 0 : {"COOKIEFILE", "/home/x/.tor/control_auth_cookie"},
80 : : });
81 : 0 : CheckParseTorReplyMapping(
82 : 0 : "METHODS=NULL", {
83 : 0 : {"METHODS", "NULL"},
84 : : });
85 : 0 : CheckParseTorReplyMapping(
86 : 0 : "METHODS=HASHEDPASSWORD", {
87 : 0 : {"METHODS", "HASHEDPASSWORD"},
88 : : });
89 : 0 : CheckParseTorReplyMapping(
90 : 0 : "Tor=\"0.2.9.8 (git-a0df013ea241b026)\"", {
91 : 0 : {"Tor", "0.2.9.8 (git-a0df013ea241b026)"},
92 : : });
93 : 0 : CheckParseTorReplyMapping(
94 : 0 : "SERVERHASH=aaaa SERVERNONCE=bbbb", {
95 : 0 : {"SERVERHASH", "aaaa"},
96 : 0 : {"SERVERNONCE", "bbbb"},
97 : : });
98 : 0 : CheckParseTorReplyMapping(
99 : 0 : "ServiceID=exampleonion1234", {
100 : 0 : {"ServiceID", "exampleonion1234"},
101 : : });
102 : 0 : CheckParseTorReplyMapping(
103 : 0 : "PrivateKey=RSA1024:BLOB", {
104 : 0 : {"PrivateKey", "RSA1024:BLOB"},
105 : : });
106 : 0 : CheckParseTorReplyMapping(
107 : 0 : "ClientAuth=bob:BLOB", {
108 : 0 : {"ClientAuth", "bob:BLOB"},
109 : : });
110 : :
111 : : // Other valid inputs
112 : 0 : CheckParseTorReplyMapping(
113 : 0 : "Foo=Bar=Baz Spam=Eggs", {
114 : 0 : {"Foo", "Bar=Baz"},
115 : 0 : {"Spam", "Eggs"},
116 : : });
117 : 0 : CheckParseTorReplyMapping(
118 : 0 : "Foo=\"Bar=Baz\"", {
119 : 0 : {"Foo", "Bar=Baz"},
120 : : });
121 : 0 : CheckParseTorReplyMapping(
122 : 0 : "Foo=\"Bar Baz\"", {
123 : 0 : {"Foo", "Bar Baz"},
124 : : });
125 : :
126 : : // Escapes
127 : 0 : CheckParseTorReplyMapping(
128 : 0 : "Foo=\"Bar\\ Baz\"", {
129 : 0 : {"Foo", "Bar Baz"},
130 : : });
131 : 0 : CheckParseTorReplyMapping(
132 : 0 : "Foo=\"Bar\\Baz\"", {
133 : 0 : {"Foo", "BarBaz"},
134 : : });
135 : 0 : CheckParseTorReplyMapping(
136 : 0 : "Foo=\"Bar\\@Baz\"", {
137 : 0 : {"Foo", "Bar@Baz"},
138 : : });
139 : 0 : CheckParseTorReplyMapping(
140 : 0 : "Foo=\"Bar\\\"Baz\" Spam=\"\\\"Eggs\\\"\"", {
141 : 0 : {"Foo", "Bar\"Baz"},
142 : 0 : {"Spam", "\"Eggs\""},
143 : : });
144 : 0 : CheckParseTorReplyMapping(
145 : 0 : "Foo=\"Bar\\\\Baz\"", {
146 : 0 : {"Foo", "Bar\\Baz"},
147 : : });
148 : :
149 : : // C escapes
150 : 0 : CheckParseTorReplyMapping(
151 : 0 : "Foo=\"Bar\\nBaz\\t\" Spam=\"\\rEggs\" Octals=\"\\1a\\11\\17\\18\\81\\377\\378\\400\\2222\" Final=Check", {
152 : 0 : {"Foo", "Bar\nBaz\t"},
153 : 0 : {"Spam", "\rEggs"},
154 : 0 : {"Octals", "\1a\11\17\1" "881\377\37" "8\40" "0\222" "2"},
155 : 0 : {"Final", "Check"},
156 : : });
157 : 0 : CheckParseTorReplyMapping(
158 : 0 : "Valid=Mapping Escaped=\"Escape\\\\\"", {
159 : 0 : {"Valid", "Mapping"},
160 : 0 : {"Escaped", "Escape\\"},
161 : : });
162 : 0 : CheckParseTorReplyMapping(
163 : 0 : "Valid=Mapping Bare=\"Escape\\\"", {});
164 : 0 : CheckParseTorReplyMapping(
165 : 0 : "OneOctal=\"OneEnd\\1\" TwoOctal=\"TwoEnd\\11\"", {
166 : 0 : {"OneOctal", "OneEnd\1"},
167 : 0 : {"TwoOctal", "TwoEnd\11"},
168 : : });
169 : :
170 : : // Special handling for null case
171 : : // (needed because string comparison reads the null as end-of-string)
172 : 0 : auto ret = ParseTorReplyMapping("Null=\"\\0\"");
173 : 0 : BOOST_CHECK_EQUAL(ret.size(), 1U);
174 : 0 : auto r_it = ret.begin();
175 : 0 : BOOST_CHECK_EQUAL(r_it->first, "Null");
176 : 0 : BOOST_CHECK_EQUAL(r_it->second.size(), 1U);
177 : 0 : BOOST_CHECK_EQUAL(r_it->second[0], '\0');
178 : :
179 : : // A more complex valid grammar. PROTOCOLINFO accepts a VersionLine that
180 : : // takes a key=value pair followed by an OptArguments, making this valid.
181 : : // Because an OptArguments contains no semantic data, there is no point in
182 : : // parsing it.
183 : 0 : CheckParseTorReplyMapping(
184 : 0 : "SOME=args,here MORE optional=arguments here", {
185 : 0 : {"SOME", "args,here"},
186 : : });
187 : :
188 : : // Inputs that are effectively invalid under the target grammar.
189 : : // PROTOCOLINFO accepts an OtherLine that is just an OptArguments, which
190 : : // would make these inputs valid. However,
191 : : // - This parser is never used in that situation, because the
192 : : // SplitTorReplyLine parser enables OtherLine to be skipped.
193 : : // - Even if these were valid, an OptArguments contains no semantic data,
194 : : // so there is no point in parsing it.
195 : 0 : CheckParseTorReplyMapping("ARGS", {});
196 : 0 : CheckParseTorReplyMapping("MORE ARGS", {});
197 : 0 : CheckParseTorReplyMapping("MORE ARGS", {});
198 : 0 : CheckParseTorReplyMapping("EVEN more=ARGS", {});
199 : 0 : CheckParseTorReplyMapping("EVEN+more ARGS", {});
200 : 0 : }
201 : :
202 : 0 : BOOST_AUTO_TEST_SUITE_END()
|