// Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // #include "test/test_bitcoin.h" #include "torcontrol.cpp" #include BOOST_FIXTURE_TEST_SUITE(torcontrol_tests, BasicTestingSetup) void CheckSplitTorReplyLine(std::string input, std::string command, std::string args) { BOOST_TEST_MESSAGE(std::string("CheckSplitTorReplyLine(") + input + ")"); auto ret = SplitTorReplyLine(input); BOOST_CHECK_EQUAL(ret.first, command); BOOST_CHECK_EQUAL(ret.second, args); } BOOST_AUTO_TEST_CASE(util_SplitTorReplyLine) { // Data we should receive during normal usage CheckSplitTorReplyLine( "PROTOCOLINFO PIVERSION", "PROTOCOLINFO", "PIVERSION"); CheckSplitTorReplyLine( "AUTH METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"", "AUTH", "METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\""); CheckSplitTorReplyLine( "AUTH METHODS=NULL", "AUTH", "METHODS=NULL"); CheckSplitTorReplyLine( "AUTH METHODS=HASHEDPASSWORD", "AUTH", "METHODS=HASHEDPASSWORD"); CheckSplitTorReplyLine( "VERSION Tor=\"0.2.9.8 (git-a0df013ea241b026)\"", "VERSION", "Tor=\"0.2.9.8 (git-a0df013ea241b026)\""); CheckSplitTorReplyLine( "AUTHCHALLENGE SERVERHASH=aaaa SERVERNONCE=bbbb", "AUTHCHALLENGE", "SERVERHASH=aaaa SERVERNONCE=bbbb"); // Other valid inputs CheckSplitTorReplyLine("COMMAND", "COMMAND", ""); CheckSplitTorReplyLine("COMMAND SOME ARGS", "COMMAND", "SOME ARGS"); // These inputs are valid because PROTOCOLINFO accepts an OtherLine that is // just an OptArguments, which enables multiple spaces to be present // between the command and arguments. CheckSplitTorReplyLine("COMMAND ARGS", "COMMAND", " ARGS"); CheckSplitTorReplyLine("COMMAND EVEN+more ARGS", "COMMAND", " EVEN+more ARGS"); } void CheckParseTorReplyMapping(std::string input, std::map expected) { BOOST_TEST_MESSAGE(std::string("CheckParseTorReplyMapping(") + input + ")"); auto ret = ParseTorReplyMapping(input); BOOST_CHECK_EQUAL(ret.size(), expected.size()); auto r_it = ret.begin(); auto e_it = expected.begin(); while (r_it != ret.end() && e_it != expected.end()) { BOOST_CHECK_EQUAL(r_it->first, e_it->first); BOOST_CHECK_EQUAL(r_it->second, e_it->second); r_it++; e_it++; } } BOOST_AUTO_TEST_CASE(util_ParseTorReplyMapping) { // Data we should receive during normal usage CheckParseTorReplyMapping( "METHODS=COOKIE,SAFECOOKIE COOKIEFILE=\"/home/x/.tor/control_auth_cookie\"", { {"METHODS", "COOKIE,SAFECOOKIE"}, {"COOKIEFILE", "/home/x/.tor/control_auth_cookie"}, }); CheckParseTorReplyMapping( "METHODS=NULL", { {"METHODS", "NULL"}, }); CheckParseTorReplyMapping( "METHODS=HASHEDPASSWORD", { {"METHODS", "HASHEDPASSWORD"}, }); CheckParseTorReplyMapping( "Tor=\"0.2.9.8 (git-a0df013ea241b026)\"", { {"Tor", "0.2.9.8 (git-a0df013ea241b026)"}, }); CheckParseTorReplyMapping( "SERVERHASH=aaaa SERVERNONCE=bbbb", { {"SERVERHASH", "aaaa"}, {"SERVERNONCE", "bbbb"}, }); CheckParseTorReplyMapping( "ServiceID=exampleonion1234", { {"ServiceID", "exampleonion1234"}, }); CheckParseTorReplyMapping( "PrivateKey=RSA1024:BLOB", { {"PrivateKey", "RSA1024:BLOB"}, }); CheckParseTorReplyMapping( "ClientAuth=bob:BLOB", { {"ClientAuth", "bob:BLOB"}, }); // Other valid inputs CheckParseTorReplyMapping( "Foo=Bar=Baz Spam=Eggs", { {"Foo", "Bar=Baz"}, {"Spam", "Eggs"}, }); CheckParseTorReplyMapping( "Foo=\"Bar=Baz\"", { {"Foo", "Bar=Baz"}, }); CheckParseTorReplyMapping( "Foo=\"Bar Baz\"", { {"Foo", "Bar Baz"}, }); // Escapes (which are left escaped by the parser) CheckParseTorReplyMapping( "Foo=\"Bar\\ Baz\"", { {"Foo", "Bar\\ Baz"}, }); CheckParseTorReplyMapping( "Foo=\"Bar\\Baz\"", { {"Foo", "Bar\\Baz"}, }); CheckParseTorReplyMapping( "Foo=\"Bar\\@Baz\"", { {"Foo", "Bar\\@Baz"}, }); CheckParseTorReplyMapping( "Foo=\"Bar\\\"Baz\" Spam=\"\\\"Eggs\\\"\"", { {"Foo", "Bar\\\"Baz"}, {"Spam", "\\\"Eggs\\\""}, }); CheckParseTorReplyMapping( "Foo=\"Bar\\\\Baz\"", { {"Foo", "Bar\\\\Baz"}, }); // A more complex valid grammar. PROTOCOLINFO accepts a VersionLine that // takes a key=value pair followed by an OptArguments, making this valid. // Because an OptArguments contains no semantic data, there is no point in // parsing it. CheckParseTorReplyMapping( "SOME=args,here MORE optional=arguments here", { {"SOME", "args,here"}, }); // Inputs that are effectively invalid under the target grammar. // PROTOCOLINFO accepts an OtherLine that is just an OptArguments, which // would make these inputs valid. However, // - This parser is never used in that situation, because the // SplitTorReplyLine parser enables OtherLine to be skipped. // - Even if these were valid, an OptArguments contains no semantic data, // so there is no point in parsing it. CheckParseTorReplyMapping("ARGS", {}); CheckParseTorReplyMapping("MORE ARGS", {}); CheckParseTorReplyMapping("MORE ARGS", {}); CheckParseTorReplyMapping("EVEN more=ARGS", {}); CheckParseTorReplyMapping("EVEN+more ARGS", {}); } BOOST_AUTO_TEST_SUITE_END()