2024-03-10 07:59:50 +00:00
|
|
|
#pragma once
|
|
|
|
///@file
|
|
|
|
|
2024-03-22 23:45:05 +00:00
|
|
|
#include <functional>
|
2024-03-10 07:59:50 +00:00
|
|
|
#include <sched.h>
|
2024-03-22 23:45:05 +00:00
|
|
|
#include <span>
|
2024-03-10 07:59:50 +00:00
|
|
|
#include <string>
|
|
|
|
|
2024-05-28 10:25:49 +00:00
|
|
|
#include "file-descriptor.hh"
|
2024-03-10 07:59:50 +00:00
|
|
|
#include "tests/terminal-code-eater.hh"
|
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
struct RunningProcess
|
|
|
|
{
|
|
|
|
pid_t pid;
|
|
|
|
Pipe procStdin;
|
|
|
|
Pipe procStdout;
|
|
|
|
|
|
|
|
static RunningProcess start(std::string executable, Strings args);
|
|
|
|
};
|
|
|
|
|
|
|
|
/** DFA that catches repl prompts */
|
|
|
|
class ReplOutputParser
|
|
|
|
{
|
|
|
|
public:
|
2024-03-22 23:45:05 +00:00
|
|
|
ReplOutputParser(std::string prompt) : prompt(prompt)
|
2024-03-10 07:59:50 +00:00
|
|
|
{
|
|
|
|
assert(!prompt.empty());
|
|
|
|
}
|
|
|
|
/** Feeds in a character and returns whether this is an open prompt */
|
|
|
|
bool feed(char c);
|
|
|
|
|
|
|
|
enum class State {
|
|
|
|
Prompt,
|
|
|
|
Context,
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
State state = State::Prompt;
|
|
|
|
size_t pos_in_prompt = 0;
|
|
|
|
std::string const prompt;
|
|
|
|
|
|
|
|
void transition(State state, char responsible_char, bool wasPrompt = false);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TestSession
|
|
|
|
{
|
|
|
|
RunningProcess proc;
|
|
|
|
ReplOutputParser outputParser;
|
|
|
|
TerminalCodeEater eater;
|
|
|
|
std::string outLog;
|
|
|
|
std::string prompt;
|
|
|
|
|
|
|
|
TestSession(std::string prompt, RunningProcess && proc)
|
|
|
|
: proc(std::move(proc))
|
|
|
|
, outputParser(prompt)
|
|
|
|
, eater{}
|
|
|
|
, outLog{}
|
|
|
|
, prompt(prompt)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-03-22 23:45:05 +00:00
|
|
|
/** Waits for the prompt and then returns if a prompt was found */
|
2024-03-10 07:59:50 +00:00
|
|
|
bool waitForPrompt();
|
|
|
|
|
2024-03-22 23:45:05 +00:00
|
|
|
/** Feeds a line of input into the command */
|
2024-03-10 07:59:50 +00:00
|
|
|
void runCommand(std::string command);
|
|
|
|
|
2024-03-22 23:45:05 +00:00
|
|
|
/** Closes the session, closing standard input and waiting for standard
|
|
|
|
* output to close, capturing any remaining output. */
|
2024-03-10 07:59:50 +00:00
|
|
|
void close();
|
2024-03-22 23:45:05 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
/** Waits until the command closes its output */
|
|
|
|
void wait();
|
|
|
|
|
|
|
|
enum class ReadOutThenCallbackResult { Stop, Continue };
|
2024-04-06 21:39:01 +00:00
|
|
|
using ReadOutThenCallback = std::function<ReadOutThenCallbackResult(std::span<const char>)>;
|
2024-03-22 23:45:05 +00:00
|
|
|
/** Reads some chunks of output, calling the callback provided for each
|
|
|
|
* chunk and stopping if it returns Stop.
|
|
|
|
*
|
|
|
|
* @returns false if EOF, true if the callback requested we stop first.
|
|
|
|
* */
|
|
|
|
bool readOutThen(ReadOutThenCallback cb);
|
2024-03-10 07:59:50 +00:00
|
|
|
};
|
|
|
|
};
|