mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-07-28 14:47:22 -07:00
Merge branch 'fix/custom-path-tab-completion': tab completion on custom file-path prompts (v2.14.1)
This commit is contained in:
@@ -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.
|
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
|
## [2.14.0] - 2026-07-24
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+33
-9
@@ -181,6 +181,7 @@ def quick_crack(ctx: Any) -> None:
|
|||||||
print("Please enter a valid wordlist or wordlist directory.")
|
print("Please enter a valid wordlist or wordlist directory.")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Please enter a valid number.")
|
print("Please enter a valid number.")
|
||||||
|
readline.set_completer(None)
|
||||||
|
|
||||||
selected_rules = _select_rules(ctx)
|
selected_rules = _select_rules(ctx)
|
||||||
if selected_rules is None:
|
if selected_rules is None:
|
||||||
@@ -492,6 +493,7 @@ def _prompt_wordlist_paths(ctx, max_count: int) -> list[str]:
|
|||||||
count += 1
|
count += 1
|
||||||
else:
|
else:
|
||||||
print(f"Not found: {resolved}")
|
print(f"Not found: {resolved}")
|
||||||
|
readline.set_completer(None)
|
||||||
return collected
|
return collected
|
||||||
|
|
||||||
|
|
||||||
@@ -626,8 +628,10 @@ def _omen_pick_training_wordlist(ctx: Any, title: str = "Training Wordlists"):
|
|||||||
if sel.lower() == "q":
|
if sel.lower() == "q":
|
||||||
return None
|
return None
|
||||||
if sel.lower() == "p":
|
if sel.lower() == "p":
|
||||||
path = input("\n\tPath to wordlist: ").strip()
|
path = ctx.select_file_with_autocomplete(
|
||||||
return path if path else None
|
"\tPath to wordlist (tab to autocomplete)"
|
||||||
|
)
|
||||||
|
return path.strip() if path else None
|
||||||
try:
|
try:
|
||||||
idx = int(sel)
|
idx = int(sel)
|
||||||
if 1 <= idx <= len(wordlist_files):
|
if 1 <= idx <= len(wordlist_files):
|
||||||
@@ -727,8 +731,10 @@ def _markov_pick_training_source(ctx: Any):
|
|||||||
if sel == "0" and has_cracked:
|
if sel == "0" and has_cracked:
|
||||||
return out_path
|
return out_path
|
||||||
if sel.lower() == "p":
|
if sel.lower() == "p":
|
||||||
path = input("\n\tPath to training file: ").strip()
|
path = ctx.select_file_with_autocomplete(
|
||||||
return path if path else None
|
"\tPath to training file (tab to autocomplete)"
|
||||||
|
)
|
||||||
|
return path.strip() if path else None
|
||||||
try:
|
try:
|
||||||
idx = int(sel)
|
idx = int(sel)
|
||||||
if 1 <= idx <= len(wordlist_files):
|
if 1 <= idx <= len(wordlist_files):
|
||||||
@@ -805,7 +811,10 @@ def combipow_crack(ctx: Any) -> None:
|
|||||||
_notify.prompt_notify_for_attack("Combipow")
|
_notify.prompt_notify_for_attack("Combipow")
|
||||||
wordlist = None
|
wordlist = None
|
||||||
while wordlist is 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:
|
if not path:
|
||||||
continue
|
continue
|
||||||
if not os.path.isfile(path):
|
if not os.path.isfile(path):
|
||||||
@@ -901,9 +910,11 @@ def generate_rules_crack(ctx: Any) -> None:
|
|||||||
wordlist_choice = raw_choice
|
wordlist_choice = raw_choice
|
||||||
else:
|
else:
|
||||||
print("[!] Wordlist not found. Please enter a valid path.")
|
print("[!] Wordlist not found. Please enter a valid path.")
|
||||||
|
readline.set_completer(None)
|
||||||
return
|
return
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Please enter a valid number.")
|
print("Please enter a valid number.")
|
||||||
|
readline.set_completer(None)
|
||||||
|
|
||||||
ctx.hcatGenerateRules(
|
ctx.hcatGenerateRules(
|
||||||
ctx.hcatHashType, ctx.hcatHashFile, rule_count, wordlist_choice
|
ctx.hcatHashType, ctx.hcatHashFile, rule_count, wordlist_choice
|
||||||
@@ -981,6 +992,7 @@ def permute_crack(ctx: Any) -> None:
|
|||||||
print("[!] A directory was provided. Please enter a single wordlist file.")
|
print("[!] A directory was provided. Please enter a single wordlist file.")
|
||||||
continue
|
continue
|
||||||
wordlist_path = raw
|
wordlist_path = raw
|
||||||
|
readline.set_completer(None)
|
||||||
|
|
||||||
ctx.hcatPermute(ctx.hcatHashType, ctx.hcatHashFile, wordlist_path)
|
ctx.hcatPermute(ctx.hcatHashType, ctx.hcatHashFile, wordlist_path)
|
||||||
|
|
||||||
@@ -1028,7 +1040,10 @@ def _rule_select_file(ctx: Any, prompt: str = "Rule file: ") -> str:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
_configure_readline(rule_completer)
|
_configure_readline(rule_completer)
|
||||||
return input(prompt).strip()
|
try:
|
||||||
|
return input(prompt).strip()
|
||||||
|
finally:
|
||||||
|
readline.set_completer(None)
|
||||||
|
|
||||||
|
|
||||||
def rule_cleanup_handler(ctx: Any) -> None:
|
def rule_cleanup_handler(ctx: Any) -> None:
|
||||||
@@ -1039,7 +1054,10 @@ def rule_cleanup_handler(ctx: Any) -> None:
|
|||||||
if not infile or not os.path.isfile(infile):
|
if not infile or not os.path.isfile(infile):
|
||||||
print(f"[!] File not found: {infile}")
|
print(f"[!] File not found: {infile}")
|
||||||
return
|
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:
|
if not outfile:
|
||||||
print("[!] Output path required.")
|
print("[!] Output path required.")
|
||||||
return
|
return
|
||||||
@@ -1057,7 +1075,10 @@ def rule_optimize_handler(ctx: Any) -> None:
|
|||||||
if not infile or not os.path.isfile(infile):
|
if not infile or not os.path.isfile(infile):
|
||||||
print(f"[!] File not found: {infile}")
|
print(f"[!] File not found: {infile}")
|
||||||
return
|
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:
|
if not outfile:
|
||||||
print("[!] Output path required.")
|
print("[!] Output path required.")
|
||||||
return
|
return
|
||||||
@@ -1077,7 +1098,10 @@ def rule_cleanup_and_optimize_handler(ctx: Any) -> None:
|
|||||||
if not infile or not os.path.isfile(infile):
|
if not infile or not os.path.isfile(infile):
|
||||||
print(f"[!] File not found: {infile}")
|
print(f"[!] File not found: {infile}")
|
||||||
return
|
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:
|
if not outfile:
|
||||||
print("[!] Output path required.")
|
print("[!] Output path required.")
|
||||||
return
|
return
|
||||||
|
|||||||
+6
-1
@@ -1238,7 +1238,12 @@ def select_file_with_autocomplete(
|
|||||||
full_prompt += f" (default: {default})"
|
full_prompt += f" (default: {default})"
|
||||||
full_prompt += ": "
|
full_prompt += ": "
|
||||||
|
|
||||||
result = input(full_prompt).strip()
|
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:
|
if not result and base_dir:
|
||||||
result = base_dir
|
result = base_dir
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ class TestCombipowCrack:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
wl = tmp_path / "words.txt"
|
wl = tmp_path / "words.txt"
|
||||||
wl.write_text("correct\nhorse\nbattery\n")
|
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)
|
attacks.combipow_crack(ctx)
|
||||||
ctx.hcatCombipow.assert_called_once()
|
ctx.hcatCombipow.assert_called_once()
|
||||||
call_args = ctx.hcatCombipow.call_args
|
call_args = ctx.hcatCombipow.call_args
|
||||||
@@ -75,12 +76,23 @@ class TestCombipowCrack:
|
|||||||
)
|
)
|
||||||
assert use_space is True
|
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):
|
def test_calls_hcatCombipow_without_space_sep(self, tmp_path):
|
||||||
attacks = _load_attacks()
|
attacks = _load_attacks()
|
||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
wl = tmp_path / "words.txt"
|
wl = tmp_path / "words.txt"
|
||||||
wl.write_text("correct\nhorse\nbattery\n")
|
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)
|
attacks.combipow_crack(ctx)
|
||||||
ctx.hcatCombipow.assert_called_once()
|
ctx.hcatCombipow.assert_called_once()
|
||||||
call_args = ctx.hcatCombipow.call_args
|
call_args = ctx.hcatCombipow.call_args
|
||||||
@@ -94,7 +106,8 @@ class TestCombipowCrack:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
wl = tmp_path / "words.txt"
|
wl = tmp_path / "words.txt"
|
||||||
wl.write_text("\n".join(f"word{i}" for i in range(64)) + "\n")
|
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)
|
attacks.combipow_crack(ctx)
|
||||||
ctx.hcatCombipow.assert_not_called()
|
ctx.hcatCombipow.assert_not_called()
|
||||||
|
|
||||||
@@ -103,7 +116,8 @@ class TestCombipowCrack:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
wl = tmp_path / "words.txt"
|
wl = tmp_path / "words.txt"
|
||||||
wl.write_text("\n".join(f"word{i}" for i in range(63)) + "\n")
|
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)
|
attacks.combipow_crack(ctx)
|
||||||
ctx.hcatCombipow.assert_called_once()
|
ctx.hcatCombipow.assert_called_once()
|
||||||
|
|
||||||
@@ -112,7 +126,8 @@ class TestCombipowCrack:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
wl = tmp_path / "words.txt"
|
wl = tmp_path / "words.txt"
|
||||||
wl.write_text("test\n")
|
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)
|
attacks.combipow_crack(ctx)
|
||||||
ctx.hcatCombipow.assert_called_once()
|
ctx.hcatCombipow.assert_called_once()
|
||||||
|
|
||||||
@@ -121,7 +136,8 @@ class TestCombipowCrack:
|
|||||||
ctx = _make_ctx(hash_type="3200", hash_file="/tmp/bcrypt.txt")
|
ctx = _make_ctx(hash_type="3200", hash_file="/tmp/bcrypt.txt")
|
||||||
wl = tmp_path / "words.txt"
|
wl = tmp_path / "words.txt"
|
||||||
wl.write_text("word1\nword2\n")
|
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)
|
attacks.combipow_crack(ctx)
|
||||||
ctx.hcatCombipow.assert_called_once()
|
ctx.hcatCombipow.assert_called_once()
|
||||||
args = ctx.hcatCombipow.call_args[0]
|
args = ctx.hcatCombipow.call_args[0]
|
||||||
@@ -134,7 +150,8 @@ class TestCombipowCrack:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
wl = tmp_path / "words.txt"
|
wl = tmp_path / "words.txt"
|
||||||
wl.write_text("\n".join(f"word{i}" for i in range(31)) + "\n")
|
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)
|
attacks.combipow_crack(ctx)
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert "large" in captured.out.lower() or "warning" in captured.out.lower()
|
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):
|
def test_custom_path_for_training(self, tmp_path):
|
||||||
ctx = self._make_ctx(tmp_path, model_valid=False)
|
ctx = self._make_ctx(tmp_path, model_valid=False)
|
||||||
self._setup_rules_dir(tmp_path)
|
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(
|
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
|
from hate_crack.attacks import omen_attack
|
||||||
|
|
||||||
omen_attack(ctx)
|
omen_attack(ctx)
|
||||||
|
ctx.select_file_with_autocomplete.assert_called_once()
|
||||||
ctx.hcatOmenTrain.assert_called_once_with("/custom/wordlist.txt")
|
ctx.hcatOmenTrain.assert_called_once_with("/custom/wordlist.txt")
|
||||||
|
|
||||||
def test_rules_passed_to_hcatOmen(self, tmp_path):
|
def test_rules_passed_to_hcatOmen(self, tmp_path):
|
||||||
|
|||||||
+28
-14
@@ -26,7 +26,8 @@ class TestRuleCleanupHandler:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\nu\n")
|
infile.write_text("l\nu\n")
|
||||||
outfile = tmp_path / "clean.rule"
|
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)
|
rule_cleanup_handler(ctx)
|
||||||
ctx.rules_cleanup.assert_called_once_with(str(infile), str(outfile))
|
ctx.rules_cleanup.assert_called_once_with(str(infile), str(outfile))
|
||||||
|
|
||||||
@@ -40,7 +41,8 @@ class TestRuleCleanupHandler:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
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)
|
rule_cleanup_handler(ctx)
|
||||||
ctx.rules_cleanup.assert_not_called()
|
ctx.rules_cleanup.assert_not_called()
|
||||||
|
|
||||||
@@ -49,7 +51,8 @@ class TestRuleCleanupHandler:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "clean.rule"
|
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)
|
rule_cleanup_handler(ctx)
|
||||||
assert "[+] Done." in capsys.readouterr().out
|
assert "[+] Done." in capsys.readouterr().out
|
||||||
|
|
||||||
@@ -59,7 +62,8 @@ class TestRuleCleanupHandler:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "clean.rule"
|
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)
|
rule_cleanup_handler(ctx)
|
||||||
assert "[!] Cleanup failed." in capsys.readouterr().out
|
assert "[!] Cleanup failed." in capsys.readouterr().out
|
||||||
|
|
||||||
@@ -70,7 +74,8 @@ class TestRuleOptimizeHandler:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\nu\n")
|
infile.write_text("l\nu\n")
|
||||||
outfile = tmp_path / "optimized.rule"
|
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)
|
rule_optimize_handler(ctx)
|
||||||
ctx.rules_optimize.assert_called_once_with(str(infile), str(outfile))
|
ctx.rules_optimize.assert_called_once_with(str(infile), str(outfile))
|
||||||
|
|
||||||
@@ -84,7 +89,8 @@ class TestRuleOptimizeHandler:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
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)
|
rule_optimize_handler(ctx)
|
||||||
ctx.rules_optimize.assert_not_called()
|
ctx.rules_optimize.assert_not_called()
|
||||||
|
|
||||||
@@ -93,7 +99,8 @@ class TestRuleOptimizeHandler:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "optimized.rule"
|
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)
|
rule_optimize_handler(ctx)
|
||||||
assert "[+] Done." in capsys.readouterr().out
|
assert "[+] Done." in capsys.readouterr().out
|
||||||
|
|
||||||
@@ -103,7 +110,8 @@ class TestRuleOptimizeHandler:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "optimized.rule"
|
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)
|
rule_optimize_handler(ctx)
|
||||||
assert "[!] Optimize failed." in capsys.readouterr().out
|
assert "[!] Optimize failed." in capsys.readouterr().out
|
||||||
|
|
||||||
@@ -114,7 +122,8 @@ class TestRuleCleanupAndOptimize:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\nu\n")
|
infile.write_text("l\nu\n")
|
||||||
outfile = tmp_path / "final.rule"
|
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)
|
rule_cleanup_and_optimize_handler(ctx)
|
||||||
ctx.rules_cleanup.assert_called_once()
|
ctx.rules_cleanup.assert_called_once()
|
||||||
ctx.rules_optimize.assert_called_once()
|
ctx.rules_optimize.assert_called_once()
|
||||||
@@ -125,7 +134,8 @@ class TestRuleCleanupAndOptimize:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "out.rule"
|
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)
|
rule_cleanup_and_optimize_handler(ctx)
|
||||||
ctx.rules_optimize.assert_not_called()
|
ctx.rules_optimize.assert_not_called()
|
||||||
|
|
||||||
@@ -139,7 +149,8 @@ class TestRuleCleanupAndOptimize:
|
|||||||
ctx = _make_ctx()
|
ctx = _make_ctx()
|
||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
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)
|
rule_cleanup_and_optimize_handler(ctx)
|
||||||
ctx.rules_cleanup.assert_not_called()
|
ctx.rules_cleanup.assert_not_called()
|
||||||
|
|
||||||
@@ -155,7 +166,8 @@ class TestRuleCleanupAndOptimize:
|
|||||||
infile = tmp_path / "test.rule"
|
infile = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "final.rule"
|
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)
|
rule_cleanup_and_optimize_handler(ctx)
|
||||||
assert captured_tmp, "rules_cleanup should have been called"
|
assert captured_tmp, "rules_cleanup should have been called"
|
||||||
assert not os.path.exists(captured_tmp[0]), "temp file should be cleaned up"
|
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 = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "out.rule"
|
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)
|
rule_cleanup_and_optimize_handler(ctx)
|
||||||
if captured_tmp:
|
if captured_tmp:
|
||||||
assert not os.path.exists(captured_tmp[0]), "temp file should be cleaned up"
|
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 = tmp_path / "test.rule"
|
||||||
infile.write_text("l\n")
|
infile.write_text("l\n")
|
||||||
outfile = tmp_path / "final.rule"
|
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)
|
rule_cleanup_and_optimize_handler(ctx)
|
||||||
assert "[+] Done." in capsys.readouterr().out
|
assert "[+] Done." in capsys.readouterr().out
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user