Skip to content

Commit 29f3c20

Browse files
committed
torcontrol: Add unit tests for Tor reply parsers
1 parent d8e03c0 commit 29f3c20

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ BITCOIN_TESTS =\
7878
test/testutil.cpp \
7979
test/testutil.h \
8080
test/timedata_tests.cpp \
81+
test/torcontrol_tests.cpp \
8182
test/transaction_tests.cpp \
8283
test/txvalidationcache_tests.cpp \
8384
test/versionbits_tests.cpp \

src/test/torcontrol_tests.cpp

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
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+
#include "test/test_bitcoin.h"
6+
#include "torcontrol.cpp"
7+
8+
#include <boost/test/unit_test.hpp>
9+
10+
11+
BOOST_FIXTURE_TEST_SUITE(torcontrol_tests, BasicTestingSetup)
12+
13+
void CheckSplitTorReplyLine(std::string input, std::string command, std::string args)
14+
{
15+
BOOST_TEST_MESSAGE(std::string("CheckSplitTorReplyLine(") + input + ")");
16+
auto ret = SplitTorReplyLine(input);
17+
BOOST_CHECK_EQUAL(ret.first, command);
18+
BOOST_CHECK_EQUAL(ret.second, args);
19+
}
20+
21+
BOOST_AUTO_TEST_CASE(util_SplitTorReplyLine)
22+
{
23+
// Data we should receive during normal usage
24+
CheckSplitTorReplyLine(
25+
"PROTOCOLINFO PIVERSION",
26+
"PROTOCOLINFO", "PIVERSION");
27+
CheckSplitTorReplyLine(
28+
"AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"",
29+
"AUTH", "METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"");
30+
CheckSplitTorReplyLine(
31+
"AUTH METHODS=NULL",
32+
"AUTH", "METHODS=NULL");
33+
CheckSplitTorReplyLine(
34+
"AUTH METHODS=HASHEDPASSWORD",
35+
"AUTH", "METHODS=HASHEDPASSWORD");
36+
CheckSplitTorReplyLine(
37+
"VERSION Tor=\"0.2.9.8 (git-a0df013ea241b026)\"",
38+
"VERSION", "Tor=\"0.2.9.8 (git-a0df013ea241b026)\"");
39+
CheckSplitTorReplyLine(
40+
"AUTHCHALLENGE SERVERHASH=aaaa SERVERNONCE=bbbb",
41+
"AUTHCHALLENGE", "SERVERHASH=aaaa SERVERNONCE=bbbb");
42+
43+
// Other valid inputs
44+
CheckSplitTorReplyLine("COMMAND", "COMMAND", "");
45+
CheckSplitTorReplyLine("COMMAND SOME ARGS", "COMMAND", "SOME ARGS");
46+
47+
// These inputs are valid because PROTOCOLINFO accepts an OtherLine that is
48+
// just an OptArguments, which enables multiple spaces to be present
49+
// between the command and arguments.
50+
CheckSplitTorReplyLine("COMMAND ARGS", "COMMAND", " ARGS");
51+
CheckSplitTorReplyLine("COMMAND EVEN+more ARGS", "COMMAND", " EVEN+more ARGS");
52+
}
53+
54+
void CheckParseTorReplyMapping(std::string input, std::map<std::string,std::string> expected)
55+
{
56+
BOOST_TEST_MESSAGE(std::string("CheckParseTorReplyMapping(") + input + ")");
57+
auto ret = ParseTorReplyMapping(input);
58+
BOOST_CHECK_EQUAL(ret.size(), expected.size());
59+
auto r_it = ret.begin();
60+
auto e_it = expected.begin();
61+
while (r_it != ret.end() && e_it != expected.end()) {
62+
BOOST_CHECK_EQUAL(r_it->first, e_it->first);
63+
BOOST_CHECK_EQUAL(r_it->second, e_it->second);
64+
r_it++;
65+
e_it++;
66+
}
67+
}
68+
69+
BOOST_AUTO_TEST_CASE(util_ParseTorReplyMapping)
70+
{
71+
// Data we should receive during normal usage
72+
CheckParseTorReplyMapping(
73+
"METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"", {
74+
{"METHODS", "COOKIE,SAFECOOKIE"},
75+
{"COOKIEFILE", "/home/x/.tor/control_auth_cookie"},
76+
});
77+
CheckParseTorReplyMapping(
78+
"METHODS=NULL", {
79+
{"METHODS", "NULL"},
80+
});
81+
CheckParseTorReplyMapping(
82+
"METHODS=HASHEDPASSWORD", {
83+
{"METHODS", "HASHEDPASSWORD"},
84+
});
85+
CheckParseTorReplyMapping(
86+
"Tor=\"0.2.9.8 (git-a0df013ea241b026)\"", {
87+
{"Tor", "0.2.9.8 (git-a0df013ea241b026)"},
88+
});
89+
CheckParseTorReplyMapping(
90+
"SERVERHASH=aaaa SERVERNONCE=bbbb", {
91+
{"SERVERHASH", "aaaa"},
92+
{"SERVERNONCE", "bbbb"},
93+
});
94+
CheckParseTorReplyMapping(
95+
"ServiceID=exampleonion1234", {
96+
{"ServiceID", "exampleonion1234"},
97+
});
98+
CheckParseTorReplyMapping(
99+
"PrivateKey=RSA1024:BLOB", {
100+
{"PrivateKey", "RSA1024:BLOB"},
101+
});
102+
CheckParseTorReplyMapping(
103+
"ClientAuth=bob:BLOB", {
104+
{"ClientAuth", "bob:BLOB"},
105+
});
106+
107+
// Other valid inputs
108+
CheckParseTorReplyMapping(
109+
"Foo=Bar=Baz Spam=Eggs", {
110+
{"Foo", "Bar=Baz"},
111+
{"Spam", "Eggs"},
112+
});
113+
CheckParseTorReplyMapping(
114+
"Foo=\"Bar=Baz\"", {
115+
{"Foo", "Bar=Baz"},
116+
});
117+
CheckParseTorReplyMapping(
118+
"Foo=\"Bar Baz\"", {
119+
{"Foo", "Bar Baz"},
120+
});
121+
122+
// Escapes (which are left escaped by the parser)
123+
CheckParseTorReplyMapping(
124+
"Foo=\"Bar\\ Baz\"", {
125+
{"Foo", "Bar\\ Baz"},
126+
});
127+
CheckParseTorReplyMapping(
128+
"Foo=\"Bar\\Baz\"", {
129+
{"Foo", "Bar\\Baz"},
130+
});
131+
CheckParseTorReplyMapping(
132+
"Foo=\"Bar\\@Baz\"", {
133+
{"Foo", "Bar\\@Baz"},
134+
});
135+
CheckParseTorReplyMapping(
136+
"Foo=\"Bar\\\"Baz\" Spam=\"\\\"Eggs\\\"\"", {
137+
{"Foo", "Bar\\\"Baz"},
138+
{"Spam", "\\\"Eggs\\\""},
139+
});
140+
CheckParseTorReplyMapping(
141+
"Foo=\"Bar\\\\Baz\"", {
142+
{"Foo", "Bar\\\\Baz"},
143+
});
144+
145+
// A more complex valid grammar. PROTOCOLINFO accepts a VersionLine that
146+
// takes a key=value pair followed by an OptArguments, making this valid.
147+
// Because an OptArguments contains no semantic data, there is no point in
148+
// parsing it.
149+
CheckParseTorReplyMapping(
150+
"SOME=args,here MORE optional=arguments here", {
151+
{"SOME", "args,here"},
152+
});
153+
154+
// Inputs that are effectively invalid under the target grammar.
155+
// PROTOCOLINFO accepts an OtherLine that is just an OptArguments, which
156+
// would make these inputs valid. However,
157+
// - This parser is never used in that situation, because the
158+
// SplitTorReplyLine parser enables OtherLine to be skipped.
159+
// - Even if these were valid, an OptArguments contains no semantic data,
160+
// so there is no point in parsing it.
161+
CheckParseTorReplyMapping("ARGS", {});
162+
CheckParseTorReplyMapping("MORE ARGS", {});
163+
CheckParseTorReplyMapping("MORE ARGS", {});
164+
CheckParseTorReplyMapping("EVEN more=ARGS", {});
165+
CheckParseTorReplyMapping("EVEN+more ARGS", {});
166+
}
167+
168+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)