Removes helpers nothing calls, test-only wrappers and their tests, the unused config writer, three unused images, and the prompt registry the nodes wrote to but nothing read, which grew with every run.
188 lines
6.4 KiB
Python
188 lines
6.4 KiB
Python
"""
|
|
Tests for hashing utilities.
|
|
|
|
Tests and generate_prompt_hash, which are
|
|
currently untested. generate_prompt_hash is covered in test_basic.py
|
|
but we add edge cases here.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import unittest
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from tests.background_stops import stop_tracker # noqa: E402
|
|
from utils.hashing import (
|
|
generate_prompt_hash,
|
|
STRIPPED_CODE_POINTS,
|
|
prompt_key,
|
|
register_prompt_functions,
|
|
stored_prompt_text,
|
|
stored_prompt_text_sql,
|
|
)
|
|
|
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
|
|
class TestSingleHashImplementation(unittest.TestCase):
|
|
"""generate_prompt_hash is the only prompt hash; nothing re-implements it."""
|
|
|
|
def test_node_base_delegates_to_generate_prompt_hash(self):
|
|
from prompt_manager_base import PromptManagerBase
|
|
|
|
node = PromptManagerBase.__new__(PromptManagerBase)
|
|
self.assertEqual(node._generate_hash(" A "), generate_prompt_hash(" A "))
|
|
self.assertEqual(node._generate_hash(" A "), generate_prompt_hash("a"))
|
|
|
|
def test_tracker_and_monitor_use_generate_prompt_hash(self):
|
|
for relative in (
|
|
os.path.join("utils", "prompt_tracker.py"),
|
|
os.path.join("utils", "image_monitor.py"),
|
|
"prompt_manager_base.py",
|
|
):
|
|
with open(os.path.join(ROOT, relative), encoding="utf-8") as f:
|
|
source = f.read()
|
|
self.assertFalse("hashlib.sha256" in source, f"inline hash in {relative}")
|
|
self.assertTrue("generate_prompt_hash" in source, relative)
|
|
|
|
def test_tracker_finds_an_existing_prompt_by_the_shared_hash(self):
|
|
import unittest.mock as mock
|
|
|
|
from utils.prompt_tracker import PromptTracker
|
|
|
|
db = mock.Mock()
|
|
db.get_prompt_by_hash.return_value = {"id": 42}
|
|
tracker = PromptTracker(db)
|
|
self.addCleanup(stop_tracker, self, tracker)
|
|
tracker.set_current_prompt(" Hello World ")
|
|
db.get_prompt_by_hash.assert_called_once_with(
|
|
generate_prompt_hash(" Hello World ")
|
|
)
|
|
self.assertEqual(tracker.get_current_prompt()["id"], 42)
|
|
|
|
def test_node_base_has_no_browser_opener(self):
|
|
from prompt_manager_base import PromptManagerBase
|
|
|
|
self.assertFalse(hasattr(PromptManagerBase, "_open_web_interface"))
|
|
self.assertFalse(os.path.exists(os.path.join(ROOT, "restart_gallery.py")))
|
|
|
|
|
|
class TestGeneratePromptHashEdgeCases(unittest.TestCase):
|
|
"""Additional edge cases for generate_prompt_hash."""
|
|
|
|
def test_non_string_raises_type_error(self):
|
|
with self.assertRaises(TypeError):
|
|
generate_prompt_hash(123)
|
|
|
|
def test_none_raises_type_error(self):
|
|
with self.assertRaises(TypeError):
|
|
generate_prompt_hash(None)
|
|
|
|
def test_empty_string(self):
|
|
h = generate_prompt_hash("")
|
|
self.assertEqual(len(h), 64)
|
|
|
|
def test_unicode_hash(self):
|
|
h = generate_prompt_hash("émojis 🎨 日本語")
|
|
self.assertEqual(len(h), 64)
|
|
|
|
def test_very_long_text(self):
|
|
h = generate_prompt_hash("x" * 100000)
|
|
self.assertEqual(len(h), 64)
|
|
|
|
|
|
class TestStoredPromptText(unittest.TestCase):
|
|
"""SQLite strips exactly the characters Python's str.strip() does (#438)."""
|
|
|
|
WHITESPACE = "".join(c for c in map(chr, range(0x110000)) if c.isspace())
|
|
|
|
def sql_strip(self, value):
|
|
import sqlite3
|
|
|
|
conn = sqlite3.connect(":memory:")
|
|
try:
|
|
return conn.execute(
|
|
f"SELECT {stored_prompt_text_sql('?')}", (value,)
|
|
).fetchone()[0]
|
|
finally:
|
|
conn.close()
|
|
|
|
def test_code_points_are_exactly_python_whitespace(self):
|
|
self.assertEqual("".join(map(chr, STRIPPED_CODE_POINTS)), self.WHITESPACE)
|
|
|
|
def test_python_rule_is_the_hash_strip(self):
|
|
self.assertEqual(stored_prompt_text(" a lighthouse\n"), "a lighthouse")
|
|
self.assertEqual(
|
|
generate_prompt_hash(stored_prompt_text(" A b\u3000")),
|
|
generate_prompt_hash(" A b\u3000"),
|
|
)
|
|
|
|
def test_sql_strips_every_python_whitespace_character(self):
|
|
for char in self.WHITESPACE:
|
|
with self.subTest(code=hex(ord(char))):
|
|
value = f"{char}a{char}b{char}"
|
|
self.assertEqual(self.sql_strip(value), stored_prompt_text(value))
|
|
mixed = self.WHITESPACE + "a lighthouse é" + self.WHITESPACE
|
|
self.assertEqual(self.sql_strip(mixed), "a lighthouse é")
|
|
|
|
def test_sql_keeps_what_python_keeps(self):
|
|
for value in ("\u200ba\u200b", "\ufeffa", "a\u0301", "", "x"):
|
|
with self.subTest(value=repr(value)):
|
|
self.assertEqual(self.sql_strip(value), stored_prompt_text(value))
|
|
|
|
|
|
class TestPromptKey(unittest.TestCase):
|
|
"""History compares the hash's own key; SQL calls Python for it (#460)."""
|
|
|
|
CASES = (
|
|
"A Lighthouse",
|
|
" \u00c9t\u00c9\n",
|
|
"\u03a3\u03a3",
|
|
"\u0130stanbul",
|
|
"\u1e9e",
|
|
"\u212a",
|
|
"ok",
|
|
)
|
|
|
|
def test_key_is_the_hash_normalization(self):
|
|
import hashlib
|
|
|
|
for value in self.CASES:
|
|
with self.subTest(value=repr(value)):
|
|
self.assertEqual(
|
|
generate_prompt_hash(value),
|
|
hashlib.sha256(prompt_key(value).encode("utf-8")).hexdigest(),
|
|
)
|
|
self.assertEqual(prompt_key(" A Lighthouse\n"), "a lighthouse")
|
|
|
|
def test_sql_functions_give_pythons_result_where_sql_lower_does_not(self):
|
|
import sqlite3
|
|
|
|
conn = sqlite3.connect(":memory:")
|
|
try:
|
|
register_prompt_functions(conn)
|
|
for value in self.CASES:
|
|
with self.subTest(value=repr(value)):
|
|
key, digest = conn.execute(
|
|
"SELECT pm_prompt_key(?), pm_prompt_hash(?)", (value, value)
|
|
).fetchone()
|
|
self.assertEqual(key, prompt_key(value))
|
|
self.assertEqual(digest, generate_prompt_hash(value))
|
|
self.assertEqual(
|
|
conn.execute(
|
|
"SELECT pm_prompt_key(1), pm_prompt_hash(NULL)"
|
|
).fetchone(),
|
|
(None, None),
|
|
)
|
|
# SQLite's own lower() folds ASCII only
|
|
self.assertNotEqual(
|
|
conn.execute("SELECT lower(?)", ("\u00c9",)).fetchone()[0], "\u00e9"
|
|
)
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|