aboutsummaryrefslogtreecommitdiff
path: root/tests/functional/repl_characterization/repl_characterization.cc
diff options
context:
space:
mode:
authorRebecca Turner <rbt@sent.as>2024-03-22 16:45:05 -0700
committerRebecca Turner <rbt@sent.as>2024-04-05 13:14:21 -0700
commitee423f391d33246801de86c73330c8442df09dc8 (patch)
treeb2be1785079e942098925f414d33848069779281 /tests/functional/repl_characterization/repl_characterization.cc
parent83d720b7304f6479f48dca8f3062e966f359e9b4 (diff)
Rewrite REPL test parser
- Use a recursive descent parser so that it's easy to extend. - Add `@args` to enable customizing command-line arguments - Add `@should-start` to enable `nix repl` tests that error before entering the REPL - Make sure to read all stdout output before comparing. This catches some extra output we were tossing out before! Change-Id: I5522555df4c313024ab15cd10f9f04e7293bda3a
Diffstat (limited to 'tests/functional/repl_characterization/repl_characterization.cc')
-rw-r--r--tests/functional/repl_characterization/repl_characterization.cc164
1 files changed, 111 insertions, 53 deletions
diff --git a/tests/functional/repl_characterization/repl_characterization.cc b/tests/functional/repl_characterization/repl_characterization.cc
index 68a66b2f3..fa5a7ba74 100644
--- a/tests/functional/repl_characterization/repl_characterization.cc
+++ b/tests/functional/repl_characterization/repl_characterization.cc
@@ -1,16 +1,17 @@
#include <gtest/gtest.h>
+#include <boost/algorithm/string/replace.hpp>
+#include <optional>
#include <string>
#include <string_view>
-#include <optional>
#include <unistd.h>
-#include <boost/algorithm/string/replace.hpp>
+#include "escape-string.hh"
#include "test-session.hh"
-#include "util.hh"
#include "tests/characterization.hh"
#include "tests/cli-literate-parser.hh"
#include "tests/terminal-code-eater.hh"
+#include "util.hh"
using namespace std::string_literals;
@@ -40,92 +41,149 @@ public:
return unitTestData + "/" + testStem;
}
- void runReplTest(std::string_view const & content, std::vector<std::string> extraArgs = {}) const
+ void runReplTest(const std::string content, std::vector<std::string> extraArgs = {}) const
{
- auto syntax = CLILiterateParser::parse(std::string(REPL_PROMPT), content);
+ auto parsed = cli_literate_parser::parse(
+ content, cli_literate_parser::Config{.prompt = std::string(REPL_PROMPT), .indent = 2}
+ );
+ parsed.interpolatePwd(unitTestData);
// FIXME: why does this need two --quiets
- // show-trace is on by default due to test configuration, but is not a standard
- Strings args{"--quiet", "repl", "--quiet", "--option", "show-trace", "false", "--offline", "--extra-experimental-features", "repl-automation"};
+ // show-trace is on by default due to test configuration, but is not a
+ // standard
+ Strings args{
+ "--quiet",
+ "repl",
+ "--quiet",
+ "--option",
+ "show-trace",
+ "false",
+ "--offline",
+ "--extra-experimental-features",
+ "repl-automation",
+ };
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
+ args.insert(args.end(), parsed.args.begin(), parsed.args.end());
auto nixBin = canonPath(getEnvNonEmpty("NIX_BIN_DIR").value_or(NIX_BIN_DIR));
auto process = RunningProcess::start(nixBin + "/nix", args);
- auto session = TestSession{std::string(AUTOMATION_PROMPT), std::move(process)};
-
- for (auto & bit : syntax) {
- if (bit.kind != CLILiterateParser::NodeKind::COMMAND) {
- continue;
- }
-
- if (!session.waitForPrompt()) {
- ASSERT_TRUE(false);
- }
- session.runCommand(bit.text);
+ auto session = TestSession(std::string(AUTOMATION_PROMPT), std::move(process));
+
+ for (auto & event : parsed.syntax) {
+ std::visit(
+ overloaded{
+ [&](const cli_literate_parser::Command & e) {
+ ASSERT_TRUE(session.waitForPrompt());
+ if (e.text == ":quit") {
+ // If we quit the repl explicitly, we won't have a
+ // prompt when we're done.
+ parsed.shouldStart = false;
+ }
+ session.runCommand(e.text);
+ },
+ [&](const auto & e) {},
+ },
+ event
+ );
}
- if (!session.waitForPrompt()) {
- ASSERT_TRUE(false);
+ if (parsed.shouldStart) {
+ ASSERT_TRUE(session.waitForPrompt());
}
session.close();
- auto replacedOutLog = boost::algorithm::replace_all_copy(session.outLog, unitTestData, "TEST_DATA");
+ auto replacedOutLog =
+ boost::algorithm::replace_all_copy(session.outLog, unitTestData, "$TEST_DATA");
auto cleanedOutLog = trimOutLog(replacedOutLog);
- auto parsedOutLog = CLILiterateParser::parse(std::string(AUTOMATION_PROMPT), cleanedOutLog, 0);
+ auto parsedOutLog = cli_literate_parser::parse(
+ std::string(cleanedOutLog),
+ cli_literate_parser::Config{.prompt = std::string(AUTOMATION_PROMPT), .indent = 0}
+ );
- parsedOutLog = CLILiterateParser::tidyOutputForComparison(std::move(parsedOutLog));
- syntax = CLILiterateParser::tidyOutputForComparison(std::move(syntax));
+ auto expected = parsed.tidyOutputForComparison();
+ auto actual = parsedOutLog.tidyOutputForComparison();
- ASSERT_EQ(parsedOutLog, syntax);
+ ASSERT_EQ(expected, actual);
+ }
+
+ void runReplTestPath(const std::string_view & nameBase, std::vector<std::string> extraArgs)
+ {
+ auto nixPath = goldenMaster(nameBase + ".nix");
+ if (pathExists(nixPath)) {
+ extraArgs.push_back("-f");
+ extraArgs.push_back(nixPath);
+ }
+ readTest(nameBase + ".test", [this, extraArgs](std::string input) {
+ runReplTest(input, extraArgs);
+ });
+ }
+
+ void runReplTestPath(const std::string_view & nameBase)
+ {
+ runReplTestPath(nameBase, {});
+ }
+
+ void runDebuggerTest(const std::string_view & nameBase)
+ {
+ runReplTestPath(nameBase, {"--debugger"});
}
};
-TEST_F(ReplSessionTest, parses)
+TEST_F(ReplSessionTest, round_trip)
{
- writeTest("basic.ast", [this]() {
+ writeTest("basic.test", [this]() {
const std::string content = readFile(goldenMaster("basic.test"));
- auto parser = CLILiterateParser{std::string(REPL_PROMPT)};
- parser.feed(content);
+ auto parsed = cli_literate_parser::parse(
+ content, cli_literate_parser::Config{.prompt = std::string(REPL_PROMPT)}
+ );
std::ostringstream out{};
- for (auto & bit : parser.syntax()) {
- out << bit.print() << "\n";
+ for (auto & node : parsed.syntax) {
+ cli_literate_parser::unparseNode(out, node, true);
}
return out.str();
});
+}
+TEST_F(ReplSessionTest, tidy)
+{
+ writeTest("basic.ast", [this]() {
+ const std::string content = readFile(goldenMaster("basic.test"));
+ auto parsed = cli_literate_parser::parse(
+ content, cli_literate_parser::Config{.prompt = std::string(REPL_PROMPT)}
+ );
+ std::ostringstream out{};
+ for (auto & node : parsed.syntax) {
+ out << debugNode(node) << "\n";
+ }
+ return out.str();
+ });
writeTest("basic_tidied.ast", [this]() {
const std::string content = readFile(goldenMaster("basic.test"));
- auto syntax = CLILiterateParser::parse(std::string(REPL_PROMPT), content);
-
- syntax = CLILiterateParser::tidyOutputForComparison(std::move(syntax));
-
+ auto parsed = cli_literate_parser::parse(
+ content, cli_literate_parser::Config{.prompt = std::string(REPL_PROMPT)}
+ );
+ auto tidied = parsed.tidyOutputForComparison();
std::ostringstream out{};
- for (auto & bit : syntax) {
- out << bit.print() << "\n";
+ for (auto & node : tidied) {
+ out << debugNode(node) << "\n";
}
return out.str();
});
}
-TEST_F(ReplSessionTest, repl_basic)
-{
- readTest("basic_repl.test", [this](std::string input) { runReplTest(input); });
-}
-
-#define DEBUGGER_TEST(name) \
+#define REPL_TEST(name) \
TEST_F(ReplSessionTest, name) \
- { \
- readTest(#name ".test", [this](std::string input) { \
- runReplTest(input, {"--debugger", "-f", goldenMaster(#name ".nix")}); \
- }); \
+ { \
+ runReplTestPath(#name); \
}
-DEBUGGER_TEST(regression_9918);
-DEBUGGER_TEST(regression_9917);
-DEBUGGER_TEST(regression_l145);
-DEBUGGER_TEST(stack_vars);
-DEBUGGER_TEST(no_nested_debuggers);
+REPL_TEST(basic_repl);
+REPL_TEST(no_nested_debuggers);
+REPL_TEST(regression_9917);
+REPL_TEST(regression_9918);
+REPL_TEST(regression_l145);
+REPL_TEST(stack_vars);
-};
+}; // namespace nix