From 42968cbd3a7fc214dd54ef4df11cb3aca46625e2 Mon Sep 17 00:00:00 2001 From: sakarpaisen Date: Thu, 22 Oct 2026 16:02:15 +0300 Subject: [PATCH] Add an optional uppercase digest to the hash generator hash_text takes uppercase: bool = False. The digest is computed once and only the hexadecimal string is reformatted, so the algorithm name, the default lowercase output and error handling are unchanged. Tests cover the default, the documented abc example, all three algorithms and empty text; the guide and docstring document the option. --- docs/tool-guide.md | 7 +++++-- src/mcp_tools_lab/tools/hashing.py | 11 ++++++++--- tests/test_hashing.py | 26 ++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/docs/tool-guide.md b/docs/tool-guide.md index ed54a58..5912597 100644 --- a/docs/tool-guide.md +++ b/docs/tool-guide.md @@ -40,10 +40,13 @@ Header cells that are empty or whitespace-only are reported by zero-based positi `empty_header_indices`; a blank name is a warning, not an invalid document, and the original names are kept in `columns` unchanged. -## hash_text(text, algorithm="sha256") +## hash_text(text, algorithm="sha256", uppercase=False) Algorithms: `sha256`, `sha512`, `blake2b`. Returns `algorithm` and lowercase -hexadecimal `digest`. Text is encoded as UTF-8. Empty strings are supported. +hexadecimal `digest`. Pass `uppercase=True` for an uppercase digest; the +`algorithm` name is unchanged either way. For example, +`hash_text("abc", uppercase=True)` starts with `BA7816BF`. Text is encoded as +UTF-8. Empty strings are supported. These hashes compare content; this tool does not provide password storage. Unknown algorithms raise `ValueError`. diff --git a/src/mcp_tools_lab/tools/hashing.py b/src/mcp_tools_lab/tools/hashing.py index e66e761..44161d3 100644 --- a/src/mcp_tools_lab/tools/hashing.py +++ b/src/mcp_tools_lab/tools/hashing.py @@ -4,9 +4,14 @@ from typing import Literal -def hash_text(text: str, algorithm: Literal["sha256", "sha512", "blake2b"] = "sha256") -> dict: - """Hash UTF-8 text using SHA-256, SHA-512, or BLAKE2b; return lowercase hex.""" +def hash_text(text: str, algorithm: Literal["sha256", "sha512", "blake2b"] = "sha256", uppercase: bool = False) -> dict: + """Hash UTF-8 text using SHA-256, SHA-512, or BLAKE2b; return hex. + + The digest is lowercase by default. Pass uppercase=True for an uppercase + digest; the algorithm name is returned unchanged. + """ algorithms = {"sha256": hashlib.sha256, "sha512": hashlib.sha512, "blake2b": hashlib.blake2b} if algorithm not in algorithms: raise ValueError("algorithm must be sha256, sha512, or blake2b.") - return {"algorithm": algorithm, "digest": algorithms[algorithm](text.encode("utf-8")).hexdigest()} + digest = algorithms[algorithm](text.encode("utf-8")).hexdigest() + return {"algorithm": algorithm, "digest": digest.upper() if uppercase else digest} diff --git a/tests/test_hashing.py b/tests/test_hashing.py index e8e8be4..4e8e6b2 100644 --- a/tests/test_hashing.py +++ b/tests/test_hashing.py @@ -16,3 +16,29 @@ def test_algorithms(algorithm, length): def test_unsupported_algorithm(): with pytest.raises(ValueError, match="algorithm"): hash_text("abc", "md5") + + +def test_uppercase_digest(): + result = hash_text("abc", uppercase=True) + assert result["digest"] == "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD" + assert result["algorithm"] == "sha256" + + +def test_uppercase_is_optional_and_algorithm_is_unchanged(): + assert hash_text("abc")["digest"].startswith("ba7816bf") + assert hash_text("abc", uppercase=False) == hash_text("abc") + + +@pytest.mark.parametrize("algorithm", ["sha256", "sha512", "blake2b"]) +def test_uppercase_supports_every_algorithm(algorithm): + lower = hash_text("abc", algorithm) + upper = hash_text("abc", algorithm, uppercase=True) + assert upper["algorithm"] == algorithm + assert upper["digest"] == lower["digest"].upper() + assert len(upper["digest"]) == len(lower["digest"]) + + +def test_uppercase_empty_text(): + result = hash_text("", uppercase=True) + assert result["digest"] == hash_text("", "sha256")["digest"].upper() + assert result["digest"] == "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"