mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-07-28 14:47:22 -07:00
fix: tab completion on custom file-path prompts
The "p. Enter a custom path" branches of the OMEN and Markov training pickers, the combipow wordlist prompt, and the rule cleanup/optimize output-path prompts used a bare input() with no readline completer, so TAB did nothing. Route them through select_file_with_autocomplete. Also drop the path completer after each selection so later numeric-menu and y/n prompts don't inherit stale file-path tab completion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9db39be438
commit
a7233c2f4f
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
Dates are omitted for releases predating this file; see the git tags for exact timing.
|
||||
|
||||
## [2.14.1] - 2026-07-25
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Tab completion on custom file-path prompts.** The `p. Enter a custom path`
|
||||
branches of the OMEN and Markov training pickers, the combipow wordlist
|
||||
prompt, and the rule cleanup/optimize output-path prompts used a bare
|
||||
`input()` with no readline completer, so TAB did nothing. They now route
|
||||
through `select_file_with_autocomplete` for consistent path autocompletion.
|
||||
- **Stale completer leak.** `select_file_with_autocomplete` and the
|
||||
`_configure_readline`-based pickers now drop the path completer after a
|
||||
selection, so later numeric-menu and y/n prompts no longer inherit file-path
|
||||
tab completion.
|
||||
|
||||
## [2.14.0] - 2026-07-24
|
||||
|
||||
### Added
|
||||
|
||||
+32
-8
@@ -183,6 +183,7 @@ def quick_crack(ctx: Any) -> None:
|
||||
print("Please enter a valid wordlist or wordlist directory.")
|
||||
except ValueError:
|
||||
print("Please enter a valid number.")
|
||||
readline.set_completer(None)
|
||||
|
||||
selected_rules = _select_rules(ctx)
|
||||
if selected_rules is None:
|
||||
@@ -488,6 +489,7 @@ def _prompt_wordlist_paths(ctx, max_count: int) -> list[str]:
|
||||
count += 1
|
||||
else:
|
||||
print(f"Not found: {resolved}")
|
||||
readline.set_completer(None)
|
||||
return collected
|
||||
|
||||
|
||||
@@ -620,8 +622,10 @@ def _omen_pick_training_wordlist(ctx: Any, title: str = "Training Wordlists"):
|
||||
if sel.lower() == "q":
|
||||
return None
|
||||
if sel.lower() == "p":
|
||||
path = input("\n\tPath to wordlist: ").strip()
|
||||
return path if path else None
|
||||
path = ctx.select_file_with_autocomplete(
|
||||
"\tPath to wordlist (tab to autocomplete)"
|
||||
)
|
||||
return path.strip() if path else None
|
||||
try:
|
||||
idx = int(sel)
|
||||
if 1 <= idx <= len(wordlist_files):
|
||||
@@ -717,8 +721,10 @@ def _markov_pick_training_source(ctx: Any):
|
||||
if sel == "0" and has_cracked:
|
||||
return out_path
|
||||
if sel.lower() == "p":
|
||||
path = input("\n\tPath to training file: ").strip()
|
||||
return path if path else None
|
||||
path = ctx.select_file_with_autocomplete(
|
||||
"\tPath to training file (tab to autocomplete)"
|
||||
)
|
||||
return path.strip() if path else None
|
||||
try:
|
||||
idx = int(sel)
|
||||
if 1 <= idx <= len(wordlist_files):
|
||||
@@ -795,7 +801,10 @@ def combipow_crack(ctx: Any) -> None:
|
||||
_notify.prompt_notify_for_attack("Combipow")
|
||||
wordlist = None
|
||||
while wordlist is None:
|
||||
path = input("\nEnter path to wordlist (max 63 lines recommended): ").strip()
|
||||
path = ctx.select_file_with_autocomplete(
|
||||
"Enter path to wordlist (max 63 lines recommended, tab to autocomplete)"
|
||||
)
|
||||
path = path.strip() if path else ""
|
||||
if not path:
|
||||
continue
|
||||
if not os.path.isfile(path):
|
||||
@@ -889,9 +898,11 @@ def generate_rules_crack(ctx: Any) -> None:
|
||||
wordlist_choice = raw_choice
|
||||
else:
|
||||
print("[!] Wordlist not found. Please enter a valid path.")
|
||||
readline.set_completer(None)
|
||||
return
|
||||
except ValueError:
|
||||
print("Please enter a valid number.")
|
||||
readline.set_completer(None)
|
||||
|
||||
ctx.hcatGenerateRules(ctx.hcatHashType, ctx.hcatHashFile, rule_count, wordlist_choice)
|
||||
|
||||
@@ -967,6 +978,7 @@ def permute_crack(ctx: Any) -> None:
|
||||
print("[!] A directory was provided. Please enter a single wordlist file.")
|
||||
continue
|
||||
wordlist_path = raw
|
||||
readline.set_completer(None)
|
||||
|
||||
ctx.hcatPermute(ctx.hcatHashType, ctx.hcatHashFile, wordlist_path)
|
||||
|
||||
@@ -1015,7 +1027,10 @@ def _rule_select_file(ctx: Any, prompt: str = "Rule file: ") -> str:
|
||||
return None
|
||||
|
||||
_configure_readline(rule_completer)
|
||||
try:
|
||||
return input(prompt).strip()
|
||||
finally:
|
||||
readline.set_completer(None)
|
||||
|
||||
|
||||
def rule_cleanup_handler(ctx: Any) -> None:
|
||||
@@ -1026,7 +1041,10 @@ def rule_cleanup_handler(ctx: Any) -> None:
|
||||
if not infile or not os.path.isfile(infile):
|
||||
print(f"[!] File not found: {infile}")
|
||||
return
|
||||
outfile = input("Output file path: ").strip()
|
||||
outfile = ctx.select_file_with_autocomplete(
|
||||
"Output file path (tab to autocomplete)"
|
||||
)
|
||||
outfile = outfile.strip() if outfile else ""
|
||||
if not outfile:
|
||||
print("[!] Output path required.")
|
||||
return
|
||||
@@ -1044,7 +1062,10 @@ def rule_optimize_handler(ctx: Any) -> None:
|
||||
if not infile or not os.path.isfile(infile):
|
||||
print(f"[!] File not found: {infile}")
|
||||
return
|
||||
outfile = input("Output file path: ").strip()
|
||||
outfile = ctx.select_file_with_autocomplete(
|
||||
"Output file path (tab to autocomplete)"
|
||||
)
|
||||
outfile = outfile.strip() if outfile else ""
|
||||
if not outfile:
|
||||
print("[!] Output path required.")
|
||||
return
|
||||
@@ -1064,7 +1085,10 @@ def rule_cleanup_and_optimize_handler(ctx: Any) -> None:
|
||||
if not infile or not os.path.isfile(infile):
|
||||
print(f"[!] File not found: {infile}")
|
||||
return
|
||||
outfile = input("Output file path: ").strip()
|
||||
outfile = ctx.select_file_with_autocomplete(
|
||||
"Output file path (tab to autocomplete)"
|
||||
)
|
||||
outfile = outfile.strip() if outfile else ""
|
||||
if not outfile:
|
||||
print("[!] Output path required.")
|
||||
return
|
||||
|
||||
@@ -1230,7 +1230,12 @@ def select_file_with_autocomplete(
|
||||
full_prompt += f" (default: {default})"
|
||||
full_prompt += ": "
|
||||
|
||||
try:
|
||||
result = input(full_prompt).strip()
|
||||
finally:
|
||||
# Drop the path completer so later plain prompts (numeric menus, y/n)
|
||||
# don't inherit stale file-path tab completion.
|
||||
readline.set_completer(None)
|
||||
if not result and base_dir:
|
||||
result = base_dir
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ class TestCombipowCrack:
|
||||
ctx = _make_ctx()
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("correct\nhorse\nbattery\n")
|
||||
with patch("builtins.input", side_effect=[str(wl), ""]):
|
||||
ctx.select_file_with_autocomplete.side_effect = [str(wl)]
|
||||
with patch("builtins.input", side_effect=[""]):
|
||||
attacks.combipow_crack(ctx)
|
||||
ctx.hcatCombipow.assert_called_once()
|
||||
call_args = ctx.hcatCombipow.call_args
|
||||
@@ -75,12 +76,23 @@ class TestCombipowCrack:
|
||||
)
|
||||
assert use_space is True
|
||||
|
||||
def test_wordlist_path_uses_autocomplete_not_input(self, tmp_path):
|
||||
attacks = _load_attacks()
|
||||
ctx = _make_ctx()
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("correct\nhorse\n")
|
||||
ctx.select_file_with_autocomplete.side_effect = [str(wl)]
|
||||
with patch("builtins.input", side_effect=[""]):
|
||||
attacks.combipow_crack(ctx)
|
||||
ctx.select_file_with_autocomplete.assert_called_once()
|
||||
|
||||
def test_calls_hcatCombipow_without_space_sep(self, tmp_path):
|
||||
attacks = _load_attacks()
|
||||
ctx = _make_ctx()
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("correct\nhorse\nbattery\n")
|
||||
with patch("builtins.input", side_effect=[str(wl), "n"]):
|
||||
ctx.select_file_with_autocomplete.side_effect = [str(wl)]
|
||||
with patch("builtins.input", side_effect=["n"]):
|
||||
attacks.combipow_crack(ctx)
|
||||
ctx.hcatCombipow.assert_called_once()
|
||||
call_args = ctx.hcatCombipow.call_args
|
||||
@@ -94,7 +106,8 @@ class TestCombipowCrack:
|
||||
ctx = _make_ctx()
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("\n".join(f"word{i}" for i in range(64)) + "\n")
|
||||
with patch("builtins.input", return_value=str(wl)):
|
||||
ctx.select_file_with_autocomplete.side_effect = [str(wl)]
|
||||
with patch("builtins.input", side_effect=[]):
|
||||
attacks.combipow_crack(ctx)
|
||||
ctx.hcatCombipow.assert_not_called()
|
||||
|
||||
@@ -103,7 +116,8 @@ class TestCombipowCrack:
|
||||
ctx = _make_ctx()
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("\n".join(f"word{i}" for i in range(63)) + "\n")
|
||||
with patch("builtins.input", side_effect=[str(wl), ""]):
|
||||
ctx.select_file_with_autocomplete.side_effect = [str(wl)]
|
||||
with patch("builtins.input", side_effect=[""]):
|
||||
attacks.combipow_crack(ctx)
|
||||
ctx.hcatCombipow.assert_called_once()
|
||||
|
||||
@@ -112,7 +126,8 @@ class TestCombipowCrack:
|
||||
ctx = _make_ctx()
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("test\n")
|
||||
with patch("builtins.input", side_effect=["/nonexistent.txt", str(wl), ""]):
|
||||
ctx.select_file_with_autocomplete.side_effect = ["/nonexistent.txt", str(wl)]
|
||||
with patch("builtins.input", side_effect=[""]):
|
||||
attacks.combipow_crack(ctx)
|
||||
ctx.hcatCombipow.assert_called_once()
|
||||
|
||||
@@ -121,7 +136,8 @@ class TestCombipowCrack:
|
||||
ctx = _make_ctx(hash_type="3200", hash_file="/tmp/bcrypt.txt")
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("word1\nword2\n")
|
||||
with patch("builtins.input", side_effect=[str(wl), ""]):
|
||||
ctx.select_file_with_autocomplete.side_effect = [str(wl)]
|
||||
with patch("builtins.input", side_effect=[""]):
|
||||
attacks.combipow_crack(ctx)
|
||||
ctx.hcatCombipow.assert_called_once()
|
||||
args = ctx.hcatCombipow.call_args[0]
|
||||
@@ -134,7 +150,8 @@ class TestCombipowCrack:
|
||||
ctx = _make_ctx()
|
||||
wl = tmp_path / "words.txt"
|
||||
wl.write_text("\n".join(f"word{i}" for i in range(31)) + "\n")
|
||||
with patch("builtins.input", side_effect=[str(wl), ""]):
|
||||
ctx.select_file_with_autocomplete.side_effect = [str(wl)]
|
||||
with patch("builtins.input", side_effect=[""]):
|
||||
attacks.combipow_crack(ctx)
|
||||
captured = capsys.readouterr()
|
||||
assert "large" in captured.out.lower() or "warning" in captured.out.lower()
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
"""Regression tests: custom-path prompts must offer tab autocomplete.
|
||||
|
||||
Previously the "p. Enter a custom path" branches (OMEN, Markov) and the
|
||||
combipow wordlist prompt used a bare ``input()`` with no readline completer,
|
||||
so TAB did nothing. They now route through ``select_file_with_autocomplete``.
|
||||
Also covers the canonical selector dropping its completer afterward so later
|
||||
plain prompts don't inherit stale file-path completion.
|
||||
"""
|
||||
|
||||
import os
|
||||
import readline
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
os.environ["HATE_CRACK_SKIP_INIT"] = "1"
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def _load_attacks():
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
import hate_crack.attacks as attacks # noqa: PLC0415
|
||||
|
||||
return attacks
|
||||
|
||||
|
||||
def _make_ctx():
|
||||
ctx = MagicMock()
|
||||
ctx.hcatHashType = "1000"
|
||||
ctx.hcatHashFile = "/tmp/hashes.txt"
|
||||
ctx.hcatWordlists = "/tmp/wordlists"
|
||||
ctx.list_wordlist_files.return_value = []
|
||||
return ctx
|
||||
|
||||
|
||||
class TestOmenCustomPath:
|
||||
def test_custom_path_uses_autocomplete(self):
|
||||
attacks = _load_attacks()
|
||||
ctx = _make_ctx()
|
||||
ctx.select_file_with_autocomplete.return_value = "/data/custom.txt"
|
||||
with patch("builtins.input", side_effect=["p"]):
|
||||
result = attacks._omen_pick_training_wordlist(ctx)
|
||||
ctx.select_file_with_autocomplete.assert_called_once()
|
||||
assert result == "/data/custom.txt"
|
||||
|
||||
def test_custom_path_blank_returns_none(self):
|
||||
attacks = _load_attacks()
|
||||
ctx = _make_ctx()
|
||||
ctx.select_file_with_autocomplete.return_value = None
|
||||
with patch("builtins.input", side_effect=["p"]):
|
||||
result = attacks._omen_pick_training_wordlist(ctx)
|
||||
assert result is None
|
||||
|
||||
|
||||
class TestMarkovCustomPath:
|
||||
def test_custom_path_uses_autocomplete(self):
|
||||
attacks = _load_attacks()
|
||||
ctx = _make_ctx()
|
||||
ctx.select_file_with_autocomplete.return_value = "/data/train.txt"
|
||||
# out file absent -> "0" option not offered
|
||||
with patch("builtins.input", side_effect=["p"]):
|
||||
result = attacks._markov_pick_training_source(ctx)
|
||||
ctx.select_file_with_autocomplete.assert_called_once()
|
||||
assert result == "/data/train.txt"
|
||||
|
||||
|
||||
class TestSelectorResetsCompleter:
|
||||
def test_completer_reset_after_selection(self):
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
import hate_crack.main as m # noqa: PLC0415
|
||||
|
||||
sentinel = object()
|
||||
readline.set_completer(lambda t, s: None)
|
||||
with patch("builtins.input", return_value="/some/path"):
|
||||
m.select_file_with_autocomplete("Pick a file")
|
||||
assert readline.get_completer() is None
|
||||
del sentinel
|
||||
@@ -355,12 +355,14 @@ class TestOmenAttackHandler:
|
||||
def test_custom_path_for_training(self, tmp_path):
|
||||
ctx = self._make_ctx(tmp_path, model_valid=False)
|
||||
self._setup_rules_dir(tmp_path)
|
||||
ctx.select_file_with_autocomplete.return_value = "/custom/wordlist.txt"
|
||||
with patch("os.path.isfile", return_value=True), patch(
|
||||
"builtins.input", side_effect=["p", "/custom/wordlist.txt", "", "0"]
|
||||
"builtins.input", side_effect=["p", "", "0"]
|
||||
):
|
||||
from hate_crack.attacks import omen_attack
|
||||
|
||||
omen_attack(ctx)
|
||||
ctx.select_file_with_autocomplete.assert_called_once()
|
||||
ctx.hcatOmenTrain.assert_called_once_with("/custom/wordlist.txt")
|
||||
|
||||
def test_rules_passed_to_hcatOmen(self, tmp_path):
|
||||
|
||||
+28
-14
@@ -26,7 +26,8 @@ class TestRuleCleanupHandler:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\nu\n")
|
||||
outfile = tmp_path / "clean.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_handler(ctx)
|
||||
ctx.rules_cleanup.assert_called_once_with(str(infile), str(outfile))
|
||||
|
||||
@@ -40,7 +41,8 @@ class TestRuleCleanupHandler:
|
||||
ctx = _make_ctx()
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
with patch("builtins.input", side_effect=[str(infile), ""]):
|
||||
ctx.select_file_with_autocomplete.return_value = ""
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_handler(ctx)
|
||||
ctx.rules_cleanup.assert_not_called()
|
||||
|
||||
@@ -49,7 +51,8 @@ class TestRuleCleanupHandler:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "clean.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_handler(ctx)
|
||||
assert "[+] Done." in capsys.readouterr().out
|
||||
|
||||
@@ -59,7 +62,8 @@ class TestRuleCleanupHandler:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "clean.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_handler(ctx)
|
||||
assert "[!] Cleanup failed." in capsys.readouterr().out
|
||||
|
||||
@@ -70,7 +74,8 @@ class TestRuleOptimizeHandler:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\nu\n")
|
||||
outfile = tmp_path / "optimized.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_optimize_handler(ctx)
|
||||
ctx.rules_optimize.assert_called_once_with(str(infile), str(outfile))
|
||||
|
||||
@@ -84,7 +89,8 @@ class TestRuleOptimizeHandler:
|
||||
ctx = _make_ctx()
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
with patch("builtins.input", side_effect=[str(infile), ""]):
|
||||
ctx.select_file_with_autocomplete.return_value = ""
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_optimize_handler(ctx)
|
||||
ctx.rules_optimize.assert_not_called()
|
||||
|
||||
@@ -93,7 +99,8 @@ class TestRuleOptimizeHandler:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "optimized.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_optimize_handler(ctx)
|
||||
assert "[+] Done." in capsys.readouterr().out
|
||||
|
||||
@@ -103,7 +110,8 @@ class TestRuleOptimizeHandler:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "optimized.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_optimize_handler(ctx)
|
||||
assert "[!] Optimize failed." in capsys.readouterr().out
|
||||
|
||||
@@ -114,7 +122,8 @@ class TestRuleCleanupAndOptimize:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\nu\n")
|
||||
outfile = tmp_path / "final.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_and_optimize_handler(ctx)
|
||||
ctx.rules_cleanup.assert_called_once()
|
||||
ctx.rules_optimize.assert_called_once()
|
||||
@@ -125,7 +134,8 @@ class TestRuleCleanupAndOptimize:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "out.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_and_optimize_handler(ctx)
|
||||
ctx.rules_optimize.assert_not_called()
|
||||
|
||||
@@ -139,7 +149,8 @@ class TestRuleCleanupAndOptimize:
|
||||
ctx = _make_ctx()
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
with patch("builtins.input", side_effect=[str(infile), ""]):
|
||||
ctx.select_file_with_autocomplete.return_value = ""
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_and_optimize_handler(ctx)
|
||||
ctx.rules_cleanup.assert_not_called()
|
||||
|
||||
@@ -155,7 +166,8 @@ class TestRuleCleanupAndOptimize:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "final.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_and_optimize_handler(ctx)
|
||||
assert captured_tmp, "rules_cleanup should have been called"
|
||||
assert not os.path.exists(captured_tmp[0]), "temp file should be cleaned up"
|
||||
@@ -172,7 +184,8 @@ class TestRuleCleanupAndOptimize:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "out.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_and_optimize_handler(ctx)
|
||||
if captured_tmp:
|
||||
assert not os.path.exists(captured_tmp[0]), "temp file should be cleaned up"
|
||||
@@ -182,7 +195,8 @@ class TestRuleCleanupAndOptimize:
|
||||
infile = tmp_path / "test.rule"
|
||||
infile.write_text("l\n")
|
||||
outfile = tmp_path / "final.rule"
|
||||
with patch("builtins.input", side_effect=[str(infile), str(outfile)]):
|
||||
ctx.select_file_with_autocomplete.return_value = str(outfile)
|
||||
with patch("builtins.input", side_effect=[str(infile)]):
|
||||
rule_cleanup_and_optimize_handler(ctx)
|
||||
assert "[+] Done." in capsys.readouterr().out
|
||||
|
||||
|
||||
Reference in New Issue
Block a user