Skip to content

Commit ea59453

Browse files
committed
Improve test_merge_conflict via new prompt_yes_or_no
1 parent 5ec6e88 commit ea59453

7 files changed

Lines changed: 99 additions & 20 deletions

File tree

src/subcommand/merge_subcommand.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <git2/types.h>
88
#include <termcolor/termcolor.hpp>
99

10+
#include "../utils/input_output.hpp"
1011
#include "../wrapper/status_wrapper.hpp"
1112

1213
merge_subcommand::merge_subcommand(const libgit2_object&, CLI::App& app)
@@ -181,10 +182,8 @@ void merge_subcommand::run()
181182

182183
std::cout << "Warning: 'merge --abort' is not implemented yet. A 'reset --hard HEAD' will be executed."
183184
<< std::endl;
184-
std::cout << "Do you want to continue [y/N] ?" << std::endl;
185-
std::string answer;
186-
std::cin >> answer;
187-
if (answer == "y")
185+
auto answer = prompt_yes_or_no("Do you want to continue [y/N] ? ", false);
186+
if (answer)
188187
{
189188
repo.state_cleanup();
190189
index.conflict_cleanup();

src/utils/input_output.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,25 @@ std::string prompt_input(const std::string_view prompt, bool echo /* = true */)
9494
// Maybe sanitise input, removing escape codes?
9595
return input;
9696
}
97+
98+
bool prompt_yes_or_no(const std::string_view prompt, bool default_return)
99+
{
100+
while (true)
101+
{
102+
auto input = prompt_input(prompt);
103+
if (input.empty())
104+
{
105+
return default_return;
106+
}
107+
auto first_char = std::tolower(input.front());
108+
if (first_char == 'y')
109+
{
110+
return true;
111+
}
112+
else if (first_char == 'n')
113+
{
114+
return false;
115+
}
116+
// Repeat prompt.
117+
}
118+
}

src/utils/input_output.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,9 @@ class echo_control : noncopyable_nonmovable
6262
// stdin from the user. The `echo` argument controls whether stdin is echoed
6363
// to stdout, use `false` for passwords.
6464
std::string prompt_input(const std::string_view prompt, bool echo = true);
65+
66+
// Display a prompt on stdout and accept a yes or no answer on stdin.
67+
// Return true if the first character on stdin is 'y' or 'Y', false if it is
68+
// 'n' or 'N', or default_return if the input is empty which occurs if the user
69+
// presses enter only. Otherwise the input is ambiguous so repeat the prompt.
70+
bool prompt_yes_or_no(const std::string_view prompt, bool default_return);

test/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def commit_env_config(monkeypatch):
5252

5353

5454
@pytest.fixture
55-
def repo_init_with_commit(commit_env_config, git2cpp_path, tmp_path, run_in_tmp_path):
55+
def repo_init_with_commit(commit_env_config, git2cpp_path, tmp_path):
5656
cmd_init = [git2cpp_path, "init", ".", "-b", "main"]
5757
p_init = subprocess.run(cmd_init, capture_output=True, cwd=tmp_path, text=True)
5858
assert p_init.returncode == 0

test/test_fixtures.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,39 @@ def test_env_vars():
3737
assert git_lines == ["GIT_CORS_PROXY=http://localhost:8881/"]
3838
else:
3939
assert git_lines == []
40+
41+
42+
def test_repo_init_with_commit(repo_init_with_commit, git2cpp_path, tmp_path):
43+
assert (tmp_path / "initial.txt").exists()
44+
assert (tmp_path / "initial.txt").is_file()
45+
assert (tmp_path / "initial.txt").read_text() == "initial"
46+
47+
git_dir = tmp_path / ".git"
48+
assert git_dir.exists()
49+
assert git_dir.is_dir()
50+
51+
assert sorted(tmp_path.iterdir()) == [
52+
git_dir,
53+
tmp_path / "initial.txt",
54+
]
55+
56+
assert sorted(git_dir.iterdir()) == [
57+
git_dir / "HEAD",
58+
git_dir / "config",
59+
git_dir / "description",
60+
git_dir / "hooks",
61+
git_dir / "index",
62+
git_dir / "info",
63+
git_dir / "logs",
64+
git_dir / "objects",
65+
git_dir / "refs",
66+
]
67+
68+
cmd = [git2cpp_path, "log"]
69+
p = subprocess.run(cmd, capture_output=True, cwd=tmp_path, text=True)
70+
assert p.returncode == 0
71+
lines = p.stdout.splitlines()
72+
assert "commit" in lines[0]
73+
assert lines[1].startswith("Author:")
74+
assert lines[2].startswith("Date:")
75+
assert "Initial commit" in lines[4]

test/test_merge.py

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,21 @@ def test_merge_commit(repo_init_with_commit, commit_env_config, git2cpp_path, tm
9797
assert p_merge_2.stdout == "Already up-to-date\n"
9898

9999

100-
@pytest.mark.parametrize("flag", ["--abort", "--quit", "--continue"])
101-
def test_merge_conflict(repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path, flag):
100+
@pytest.mark.parametrize(
101+
"flag, abort_input",
102+
[
103+
("--abort", "y"),
104+
("--abort", "Y"),
105+
("--abort", "n"),
106+
("--abort", "N"),
107+
("--abort", ""),
108+
("--quit", None),
109+
("--continue", None),
110+
],
111+
)
112+
def test_merge_conflict(
113+
repo_init_with_commit, commit_env_config, git2cpp_path, tmp_path, flag, abort_input
114+
):
102115
assert (tmp_path / "initial.txt").exists()
103116

104117
checkout_cmd = [git2cpp_path, "checkout", "-b", "foregone"]
@@ -140,18 +153,18 @@ def test_merge_conflict(repo_init_with_commit, commit_env_config, git2cpp_path,
140153

141154
flag_cmd = [git2cpp_path, "merge", flag]
142155
if flag == "--abort":
143-
for answer in {"y", ""}:
144-
p_abort = subprocess.run(
145-
flag_cmd, input=answer, capture_output=True, cwd=tmp_path, text=True
146-
)
147-
assert p_abort.returncode == 0
148-
assert (tmp_path / "mook_file.txt").exists()
149-
text = (tmp_path / "mook_file.txt").read_text()
150-
if answer == "y":
151-
assert "BLA" in text
152-
assert "bla" not in text
153-
else:
154-
assert "Abort." in p_abort.stdout
156+
p_abort = subprocess.run(
157+
flag_cmd, input=abort_input, capture_output=True, cwd=tmp_path, text=True
158+
)
159+
160+
assert p_abort.returncode == 0
161+
assert (tmp_path / "mook_file.txt").exists()
162+
text = (tmp_path / "mook_file.txt").read_text()
163+
if abort_input.lower() == "y":
164+
assert "BLA" in text
165+
assert "bla" not in text
166+
else:
167+
assert "Abort." in p_abort.stdout
155168

156169
elif flag == "--quit":
157170
pass

wasm/test/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ async function shellRun(
4747

4848
if (input !== undefined && input !== null) {
4949
async function delayThenStdin(): Promise<void> {
50-
const chars = input! + '\x04'; // EOT
50+
let chars = input!;
51+
if (!chars.endsWith('\n')) {
52+
chars += '\n';
53+
}
5154
await delay(100);
5255
for (const char of chars) {
5356
await shell.input(char);

0 commit comments

Comments
 (0)