-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_hasher.py
More file actions
179 lines (135 loc) · 6.1 KB
/
test_hasher.py
File metadata and controls
179 lines (135 loc) · 6.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
"""
Tests for HashGuardian - Text Integrity Checker
Run: pytest test_hasher.py -v
"""
import pytest
import os
import json
from hasher import (
compute_hash, compute_all_hashes, save_hash,
verify_text, compare_texts, list_snapshots,
delete_snapshot, ALGORITHMS, VAULT_FILE
)
TEST_VAULT = "test_vault.json"
@pytest.fixture(autouse=True)
def use_test_vault(monkeypatch, tmp_path):
"""Redirect vault to a temp file for each test."""
import hasher
vault_path = tmp_path / "vault.json"
monkeypatch.setattr(hasher, "VAULT_FILE", str(vault_path))
# ── compute_hash ──────────────────────────────────────────────
class TestComputeHash:
def test_sha256_known_value(self):
h = compute_hash("hello")
assert h == "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
def test_md5_known_value(self):
h = compute_hash("hello", "md5")
assert h == "5d41402abc4b2a76b9719d911017c592"
def test_sha1_known_value(self):
h = compute_hash("hello", "sha1")
assert h == "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
def test_sha512_returns_128_chars(self):
h = compute_hash("hello", "sha512")
assert len(h) == 128
def test_all_algorithms_work(self):
for algo in ALGORITHMS:
h = compute_hash("test", algo)
assert isinstance(h, str) and len(h) > 0
def test_different_texts_give_different_hashes(self):
assert compute_hash("hello") != compute_hash("Hello")
def test_same_text_always_same_hash(self):
assert compute_hash("consistency") == compute_hash("consistency")
def test_empty_string(self):
h = compute_hash("")
assert isinstance(h, str) and len(h) == 64 # sha256
def test_unicode_text(self):
h = compute_hash("héllo wörld 🔐")
assert isinstance(h, str) and len(h) == 64
def test_invalid_algorithm_raises(self):
with pytest.raises(ValueError):
compute_hash("hello", "fakehash")
# ── compute_all_hashes ────────────────────────────────────────
class TestComputeAllHashes:
def test_returns_all_algorithms(self):
result = compute_all_hashes("test")
assert set(result.keys()) == set(ALGORITHMS)
def test_all_values_are_strings(self):
result = compute_all_hashes("test")
for v in result.values():
assert isinstance(v, str)
# ── save_hash & verify_text ───────────────────────────────────
class TestSaveAndVerify:
def test_save_returns_entry(self):
entry = save_hash("mysnap", "original text")
assert entry["label"] == "mysnap"
assert entry["algorithm"] == "sha256"
assert "hash" in entry
assert "timestamp" in entry
def test_verify_intact(self):
save_hash("snap1", "the quick brown fox")
result = verify_text("snap1", "the quick brown fox")
assert result["status"] == "INTACT"
assert result["is_intact"] is True
def test_verify_modified(self):
save_hash("snap2", "original content")
result = verify_text("snap2", "modified content")
assert result["status"] == "MODIFIED"
assert result["is_intact"] is False
def test_verify_not_found(self):
result = verify_text("nonexistent", "some text")
assert result["status"] == "NOT_FOUND"
def test_verify_tracks_length(self):
save_hash("snap3", "hello")
result = verify_text("snap3", "hello world")
assert result["original_length"] == 5
assert result["current_length"] == 11
def test_save_with_md5(self):
save_hash("snap_md5", "test", algorithm="md5")
result = verify_text("snap_md5", "test")
assert result["is_intact"] is True
def test_single_char_change_detected(self):
save_hash("snap4", "Hello World")
result = verify_text("snap4", "Hello world") # lowercase w
assert result["is_intact"] is False
def test_whitespace_change_detected(self):
save_hash("snap5", "hello world")
result = verify_text("snap5", "hello world") # extra space
assert result["is_intact"] is False
# ── compare_texts ─────────────────────────────────────────────
class TestCompareTexts:
def test_identical_texts(self):
result = compare_texts("same", "same")
assert result["identical"] is True
def test_different_texts(self):
result = compare_texts("text one", "text two")
assert result["identical"] is False
def test_returns_both_hashes(self):
result = compare_texts("a", "b")
assert "hash_1" in result and "hash_2" in result
def test_empty_strings(self):
result = compare_texts("", "")
assert result["identical"] is True
def test_custom_algorithm(self):
result = compare_texts("hello", "hello", algorithm="md5")
assert result["algorithm"] == "md5"
assert result["identical"] is True
# ── list & delete ─────────────────────────────────────────────
class TestListAndDelete:
def test_list_empty_vault(self):
assert list_snapshots() == []
def test_list_after_saves(self):
save_hash("a", "text a")
save_hash("b", "text b")
snaps = list_snapshots()
assert len(snaps) == 2
def test_delete_existing(self):
save_hash("to_delete", "bye")
assert delete_snapshot("to_delete") is True
assert verify_text("to_delete", "bye")["status"] == "NOT_FOUND"
def test_delete_nonexistent(self):
assert delete_snapshot("ghost") is False
def test_overwrite_snapshot(self):
save_hash("over", "version 1")
save_hash("over", "version 2")
result = verify_text("over", "version 2")
assert result["is_intact"] is True