mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-06 22:29:23 +00:00
Parse multicall commands once per call
Keep the change to d, f, p and t multicalls. Parse each column lazily on first use and evaluate it through rpc::call_object, preserving per-target argument expansion. Compared unpatched and patched builds on macOS: output was byte-identical across the test harness, including an erase-mid-call check.
This commit is contained in:
@@ -2,7 +2,10 @@
|
||||
|
||||
#include "test/rpc/test_command.h"
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "rpc/command.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommand);
|
||||
|
||||
@@ -83,3 +86,50 @@ TestCommand::test_stack_double() {
|
||||
rpc::command_base::pop_stack(&stack_first, last_stack_first);
|
||||
CPPUNIT_ASSERT(command_stack_all_empty());
|
||||
}
|
||||
|
||||
void
|
||||
TestCommand::test_preparsed_commands() {
|
||||
unsigned int prepare_count = 0;
|
||||
rpc::preparsed_commands commands([&prepare_count](auto& prepared) {
|
||||
++prepare_count;
|
||||
// Reentrant access must not invoke the same callback recursively.
|
||||
prepared.prepare_if_needed();
|
||||
prepared.push_back(rpc::parse_command_object("string.length=abc"));
|
||||
});
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0u, prepare_count);
|
||||
CPPUNIT_ASSERT(commands.empty());
|
||||
|
||||
commands.prepare_if_needed();
|
||||
CPPUNIT_ASSERT_EQUAL(1u, prepare_count);
|
||||
|
||||
size_t count = 0;
|
||||
for (auto& itr : commands) {
|
||||
CPPUNIT_ASSERT(itr.is_dict_key());
|
||||
++count;
|
||||
}
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(size_t(1), count);
|
||||
CPPUNIT_ASSERT_EQUAL(1u, prepare_count);
|
||||
|
||||
for (auto& itr : commands)
|
||||
CPPUNIT_ASSERT(itr.is_dict_key());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1u, prepare_count);
|
||||
}
|
||||
|
||||
void
|
||||
TestCommand::test_parse_command_object() {
|
||||
auto command = rpc::parse_command_object("\tstring.length=abc ");
|
||||
CPPUNIT_ASSERT(command.is_dict_key());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("string.length"), command.as_dict_key());
|
||||
|
||||
// This helper has no way to return the next-command pointer, so it must not
|
||||
// silently accept a multipart command separated by ';'.
|
||||
CPPUNIT_ASSERT_THROW(rpc::parse_command_object("string.length=abc;string.length=def"), torrent::input_error);
|
||||
|
||||
// Unlike parse_command (which parses command files), this helper handles one
|
||||
// multicall command and must reject newline boundaries, including CRLF.
|
||||
CPPUNIT_ASSERT_THROW(rpc::parse_command_object("string.length=abc\nstring.length=def"), torrent::input_error);
|
||||
CPPUNIT_ASSERT_THROW(rpc::parse_command_object("string.length=abc\r\nstring.length=def"), torrent::input_error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user