From a35f9bcd72c56c354466ce2fedb629a990034439 Mon Sep 17 00:00:00 2001 From: Edmund Miller Date: Fri, 11 Jul 2025 14:23:23 -0500 Subject: [PATCH 1/4] feat: Add lint check for version snapshot content validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new lint check `test_snap_version_content` to ensure version information in test snapshots contains actual content instead of MD5/SHA hash values. This addresses the issue where version snapshots were storing hash values like "versions.yml:md5,949da9c6297b613b50e24c421576f3f1" instead of actual version content like {"ALE": {"ale": "20180904"}}. Changes: - Add version content validation in module_tests.py with regex patterns - Add comprehensive tests for both invalid (hash) and valid (content) cases - Add pytest issue marker support for linking tests to GitHub issues - Update pyproject.toml with new pytest marker configuration Fixes: https://github.com/nf-core/modules/issues/6505 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- nf_core/modules/lint/module_tests.py | 30 ++++++++++ pyproject.toml | 6 +- tests/modules/lint/test_module_tests.py | 73 +++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/nf_core/modules/lint/module_tests.py b/nf_core/modules/lint/module_tests.py index 6826b2e743..199edae128 100644 --- a/nf_core/modules/lint/module_tests.py +++ b/nf_core/modules/lint/module_tests.py @@ -170,6 +170,36 @@ def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): snap_file, ) ) + # Check if version content is actual content vs MD5 hash + # Related to: https://github.com/nf-core/modules/issues/6505 + # Ensures version snapshots contain actual content instead of hash values + version_content_valid = True + version_hash_patterns = [ + r"versions\.yml:md5,[\da-f]+", # MD5 hash pattern + r"versions\.yml:sha[\d]*,[\da-f]+", # SHA hash pattern + ] + + for pattern in version_hash_patterns: + if re.search(pattern, str(snap_content[test_name])): + version_content_valid = False + break + + if version_content_valid: + module.passed.append( + ( + "test_snap_version_content", + "version information contains actual content instead of hash", + snap_file, + ) + ) + else: + module.failed.append( + ( + "test_snap_version_content", + "version information should contain actual content, not MD5/SHA hash", + snap_file, + ) + ) else: module.failed.append( ( diff --git a/pyproject.toml b/pyproject.toml index 42da317707..43d6b68233 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,11 @@ build-backend = "setuptools.build_meta" requires = ["setuptools>=40.6.0", "wheel"] [tool.pytest.ini_options] -markers = ["datafiles: load datafiles", "integration"] +markers = [ + "datafiles: load datafiles", + "integration", + "issue: mark test with related issue URL" +] testpaths = ["tests"] python_files = ["test_*.py"] asyncio_mode = "auto" diff --git a/tests/modules/lint/test_module_tests.py b/tests/modules/lint/test_module_tests.py index b5f361c7d8..8b9423457c 100644 --- a/tests/modules/lint/test_module_tests.py +++ b/tests/modules/lint/test_module_tests.py @@ -1,6 +1,7 @@ import json from pathlib import Path +import pytest from git.repo import Repo import nf_core.modules.lint @@ -213,3 +214,75 @@ def test_modules_empty_file_in_stub_snapshot(self): # reset the file with open(snap_file, "w") as fh: fh.write(content) + + @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") + def test_modules_version_snapshot_content_md5_hash(self): + """Test linting a nf-test module with version information as MD5 hash instead of actual content, which should fail. + + Related to: https://github.com/nf-core/modules/issues/6505 + Fixed in: https://github.com/nf-core/tools/pull/3676 + """ + snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" + snap = json.load(snap_file.open()) + content = snap_file.read_text() + + # Add a version entry with MD5 hash format (the old way that should be flagged) + snap["my test"]["content"][0]["versions"] = "versions.yml:md5,949da9c6297b613b50e24c421576f3f1" + + with open(snap_file, "w") as fh: + json.dump(snap, fh) + + module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) + module_lint.lint(print_results=False, module="bpipe/test") + + # Should fail because version is using MD5 hash instead of actual content + # Filter for only our specific test + version_content_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_version_content"] + assert len(version_content_failures) == 1, ( + f"Expected 1 test_snap_version_content failure, got {len(version_content_failures)}" + ) + assert version_content_failures[0].lint_test == "test_snap_version_content" + + # reset the file + with open(snap_file, "w") as fh: + fh.write(content) + + @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") + def test_modules_version_snapshot_content_valid(self): + """Test linting a nf-test module with version information as actual content, which should pass. + + Related to: https://github.com/nf-core/modules/issues/6505 + Fixed in: https://github.com/nf-core/tools/pull/3676 + """ + snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" + snap = json.load(snap_file.open()) + content = snap_file.read_text() + + # Add a version entry with actual content (the new way that should pass) + snap["my test"]["content"][0]["versions"] = {"ALE": {"ale": "20180904"}} + + with open(snap_file, "w") as fh: + json.dump(snap, fh) + + module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) + module_lint.lint(print_results=False, module="bpipe/test") + + # Should pass because version contains actual content + # Filter for only our specific test + version_content_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_version_content"] + assert len(version_content_failures) == 0, ( + f"Expected 0 test_snap_version_content failures, got {len(version_content_failures)}" + ) + + # Check for test_snap_version_content in passed tests + version_content_passed = [ + x + for x in module_lint.passed + if (hasattr(x, "lint_test") and x.lint_test == "test_snap_version_content") + or (isinstance(x, tuple) and len(x) > 0 and x[0] == "test_snap_version_content") + ] + assert len(version_content_passed) > 0, "test_snap_version_content not found in passed tests" + + # reset the file + with open(snap_file, "w") as fh: + fh.write(content) From ff546d64fd61bb71550181d9c98343b9ba738f1e Mon Sep 17 00:00:00 2001 From: Edmund Miller Date: Tue, 26 Aug 2025 11:36:48 -0500 Subject: [PATCH 2/4] refactor: Improve version snapshot content validation with enhanced regex and error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Extract version checking logic into dedicated helper functions for better modularity - Implement more precise regex patterns with proper word boundaries to avoid false positives - Optimize performance by reducing string conversions from multiple to single per test - Add comprehensive test coverage for SHA hashes, mixed scenarios, and edge cases - Enhance error messages with clearer guidance and examples for developers - Improve code maintainability and readability through separation of concerns 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- nf_core/modules/lint/module_tests.py | 91 ++++++++++++++++------- tests/modules/lint/test_module_tests.py | 99 +++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 26 deletions(-) diff --git a/nf_core/modules/lint/module_tests.py b/nf_core/modules/lint/module_tests.py index 199edae128..4c2c6d1d65 100644 --- a/nf_core/modules/lint/module_tests.py +++ b/nf_core/modules/lint/module_tests.py @@ -15,6 +15,59 @@ log = logging.getLogger(__name__) +def _check_version_content_format(snap_content, test_name, snap_file): + """ + Check if version content uses actual YAML data vs hash format. + + Args: + snap_content: Parsed JSON snapshot content + test_name: Name of the test being checked + snap_file: Path to snapshot file (for error reporting) + + Returns: + Tuple for passed test if valid, None if invalid or no version data found + """ + # Check if this test contains version data and if it's in hash format + if _contains_version_hash(snap_content[test_name]): + return None # Invalid - contains hash format + + # Valid - either contains actual content or no version hash detected + return ( + "test_snap_version_content", + "version information contains actual content instead of hash", + snap_file, + ) + + +def _contains_version_hash(test_content): + """ + Check if test content contains version information in hash format. + + Uses precise regex patterns to detect version hash formats while avoiding + false positives from similar strings. + + Args: + test_content: Content of a single test from snapshot + + Returns: + bool: True if hash format detected, False otherwise + """ + # More precise regex patterns with proper boundaries + version_hash_patterns = [ + r"\bversions\.yml:md5,[a-f0-9]{32}\b", # Exact MD5 format (32 hex chars) + r"\bversions\.yml:sha[0-9]*,[a-f0-9]+\b", # SHA format with variable length + ] + + # Convert to string only once and search efficiently + content_str = str(test_content) + + for pattern in version_hash_patterns: + if re.search(pattern, content_str): + return True + + return False + + def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): """ Lint the tests of a module in ``nf-core/modules`` @@ -170,36 +223,22 @@ def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): snap_file, ) ) - # Check if version content is actual content vs MD5 hash + # Check if version content is actual content vs MD5/SHA hash # Related to: https://github.com/nf-core/modules/issues/6505 # Ensures version snapshots contain actual content instead of hash values - version_content_valid = True - version_hash_patterns = [ - r"versions\.yml:md5,[\da-f]+", # MD5 hash pattern - r"versions\.yml:sha[\d]*,[\da-f]+", # SHA hash pattern - ] - - for pattern in version_hash_patterns: - if re.search(pattern, str(snap_content[test_name])): - version_content_valid = False - break - - if version_content_valid: - module.passed.append( - ( - "test_snap_version_content", - "version information contains actual content instead of hash", - snap_file, - ) - ) + version_check_result = _check_version_content_format(snap_content, test_name, snap_file) + if version_check_result: + module.passed.append(version_check_result) else: - module.failed.append( - ( - "test_snap_version_content", - "version information should contain actual content, not MD5/SHA hash", - snap_file, + # Only add failure if we found hash patterns + if _contains_version_hash(snap_content[test_name]): + module.failed.append( + ( + "test_snap_version_content", + "Version information should contain actual YAML content (e.g., {'tool': {'version': '1.0'}}), not hash format like 'versions.yml:md5,hash'", + snap_file, + ) ) - ) else: module.failed.append( ( diff --git a/tests/modules/lint/test_module_tests.py b/tests/modules/lint/test_module_tests.py index 8b9423457c..9f1cfe9b78 100644 --- a/tests/modules/lint/test_module_tests.py +++ b/tests/modules/lint/test_module_tests.py @@ -286,3 +286,102 @@ def test_modules_version_snapshot_content_valid(self): # reset the file with open(snap_file, "w") as fh: fh.write(content) + + @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") + def test_modules_version_snapshot_content_sha_hash(self): + """Test linting a nf-test module with version information as SHA hash, which should fail. + + Related to: https://github.com/nf-core/modules/issues/6505 + Fixed in: https://github.com/nf-core/tools/pull/3676 + """ + snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" + snap = json.load(snap_file.open()) + content = snap_file.read_text() + + # Add a version entry with SHA hash format (should be flagged) + snap["my test"]["content"][0]["versions"] = ( + "versions.yml:sha256,e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ) + + with open(snap_file, "w") as fh: + json.dump(snap, fh) + + module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) + module_lint.lint(print_results=False, module="bpipe/test") + + # Should fail because version is using SHA hash instead of actual content + version_content_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_version_content"] + assert len(version_content_failures) == 1, ( + f"Expected 1 test_snap_version_content failure, got {len(version_content_failures)}" + ) + + # reset the file + with open(snap_file, "w") as fh: + fh.write(content) + + @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") + def test_modules_version_snapshot_content_mixed_scenario(self): + """Test linting with mixed version content - some valid, some hash format. + + Related to: https://github.com/nf-core/modules/issues/6505 + Fixed in: https://github.com/nf-core/tools/pull/3676 + """ + snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" + snap = json.load(snap_file.open()) + content = snap_file.read_text() + + # Create a scenario with multiple tests - one with hash, one with valid content + snap["test_with_hash"] = {"content": [{"versions": "versions.yml:md5,949da9c6297b613b50e24c421576f3f1"}]} + snap["test_with_valid_content"] = {"content": [{"versions": {"BPIPE": {"bpipe": "0.9.11"}}}]} + + with open(snap_file, "w") as fh: + json.dump(snap, fh) + + module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) + module_lint.lint(print_results=False, module="bpipe/test") + + # Should have failure for the hash test + version_content_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_version_content"] + assert len(version_content_failures) >= 1, "Expected at least 1 failure for hash format" + + # Should have pass for the valid content test + version_content_passed = [ + x + for x in module_lint.passed + if (hasattr(x, "lint_test") and x.lint_test == "test_snap_version_content") + or (isinstance(x, tuple) and len(x) > 0 and x[0] == "test_snap_version_content") + ] + assert len(version_content_passed) >= 1, "Expected at least 1 pass for valid content" + + # reset the file + with open(snap_file, "w") as fh: + fh.write(content) + + @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") + def test_modules_version_snapshot_no_version_content(self): + """Test linting when no version information is present - should not trigger version content check. + + Related to: https://github.com/nf-core/modules/issues/6505 + Fixed in: https://github.com/nf-core/tools/pull/3676 + """ + snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" + snap = json.load(snap_file.open()) + content = snap_file.read_text() + + # Remove version information entirely + if "content" in snap["my test"] and snap["my test"]["content"]: + snap["my test"]["content"][0].pop("versions", None) + + with open(snap_file, "w") as fh: + json.dump(snap, fh) + + module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) + module_lint.lint(print_results=False, module="bpipe/test") + + # Should not have version content check failures when no version data present + version_content_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_version_content"] + assert len(version_content_failures) == 0, "Should not have version content failures when no versions present" + + # reset the file + with open(snap_file, "w") as fh: + fh.write(content) From 11bcdcb7bd32fba3f6e0dc28526f153aa5e5946f Mon Sep 17 00:00:00 2001 From: Edmund Miller Date: Tue, 26 Aug 2025 12:13:58 -0500 Subject: [PATCH 3/4] fix: Fix version content validation loop logic and improve test coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix critical indentation issue where version checking ran outside the test loop - Remove redundant _check_version_content_format function for cleaner logic - Ensure version content validation runs for each test individually - Improve regex patterns with word boundaries for more precise hash detection - Add comprehensive test coverage for SHA hashes, mixed scenarios, and edge cases - All new tests now pass correctly after fixing the loop structure Related to: https://github.com/nf-core/modules/issues/6505 Fixed in: https://github.com/nf-core/tools/pull/3676 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- nf_core/modules/lint/module_tests.py | 73 +++++++++---------------- tests/modules/lint/test_module_tests.py | 16 ++++-- 2 files changed, 39 insertions(+), 50 deletions(-) diff --git a/nf_core/modules/lint/module_tests.py b/nf_core/modules/lint/module_tests.py index 4c2c6d1d65..8618e6dc64 100644 --- a/nf_core/modules/lint/module_tests.py +++ b/nf_core/modules/lint/module_tests.py @@ -15,30 +15,6 @@ log = logging.getLogger(__name__) -def _check_version_content_format(snap_content, test_name, snap_file): - """ - Check if version content uses actual YAML data vs hash format. - - Args: - snap_content: Parsed JSON snapshot content - test_name: Name of the test being checked - snap_file: Path to snapshot file (for error reporting) - - Returns: - Tuple for passed test if valid, None if invalid or no version data found - """ - # Check if this test contains version data and if it's in hash format - if _contains_version_hash(snap_content[test_name]): - return None # Invalid - contains hash format - - # Valid - either contains actual content or no version hash detected - return ( - "test_snap_version_content", - "version information contains actual content instead of hash", - snap_file, - ) - - def _contains_version_hash(test_content): """ Check if test content contains version information in hash format. @@ -215,23 +191,19 @@ def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): snap_file, ) ) - if "versions" in str(snap_content[test_name]) or "versions" in str(snap_content.keys()): - module.passed.append( - ( - "test_snap_versions", - "versions found in snapshot file", - snap_file, + if "versions" in str(snap_content[test_name]) or "versions" in str(snap_content.keys()): + module.passed.append( + ( + "test_snap_versions", + "versions found in snapshot file", + snap_file, + ) ) - ) - # Check if version content is actual content vs MD5/SHA hash - # Related to: https://github.com/nf-core/modules/issues/6505 - # Ensures version snapshots contain actual content instead of hash values - version_check_result = _check_version_content_format(snap_content, test_name, snap_file) - if version_check_result: - module.passed.append(version_check_result) - else: - # Only add failure if we found hash patterns + # Check if version content is actual content vs MD5/SHA hash + # Related to: https://github.com/nf-core/modules/issues/6505 + # Ensures version snapshots contain actual content instead of hash values if _contains_version_hash(snap_content[test_name]): + # Invalid - contains hash format module.failed.append( ( "test_snap_version_content", @@ -239,14 +211,23 @@ def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): snap_file, ) ) - else: - module.failed.append( - ( - "test_snap_versions", - "versions not found in snapshot file", - snap_file, + else: + # Valid - either contains actual content or no version hash detected + module.passed.append( + ( + "test_snap_version_content", + "version information contains actual content instead of hash", + snap_file, + ) + ) + else: + module.failed.append( + ( + "test_snap_versions", + "versions not found in snapshot file", + snap_file, + ) ) - ) except json.decoder.JSONDecodeError as e: module.failed.append( ( diff --git a/tests/modules/lint/test_module_tests.py b/tests/modules/lint/test_module_tests.py index 9f1cfe9b78..ce09330e9e 100644 --- a/tests/modules/lint/test_module_tests.py +++ b/tests/modules/lint/test_module_tests.py @@ -135,12 +135,20 @@ def test_nftest_failing_linting(self): module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) module_lint.lint(print_results=False, module="kallisto/quant") - assert len(module_lint.failed) == 2, f"Linting failed with {[x.__dict__ for x in module_lint.failed]}" + assert len(module_lint.failed) == 4, f"Linting failed with {[x.__dict__ for x in module_lint.failed]}" assert len(module_lint.passed) >= 0 assert len(module_lint.warned) >= 0 - assert module_lint.failed[0].lint_test == "meta_yml_valid" - assert module_lint.failed[1].lint_test == "test_main_tags" - assert "kallisto/index" in module_lint.failed[1].message + + # Check for expected failure types + failed_tests = [x.lint_test for x in module_lint.failed] + assert "meta_yml_valid" in failed_tests + assert "test_main_tags" in failed_tests + assert failed_tests.count("test_snap_version_content") == 2 # Should appear twice for the two version entries + + # Check test_main_tags failure contains the expected message + main_tags_failures = [x for x in module_lint.failed if x.lint_test == "test_main_tags"] + assert len(main_tags_failures) == 1 + assert "kallisto/index" in main_tags_failures[0].message def test_modules_absent_version(self): """Test linting a nf-test module if the versions is absent in the snapshot file `""" From 1ddf9ce1092e36b24951dc5c66d1bee179a3d262 Mon Sep 17 00:00:00 2001 From: Edmund Miller Date: Sat, 27 Sep 2025 20:24:35 +0200 Subject: [PATCH 4/4] fix: Address PR review feedback - Clean up AI-generated comments and verbose documentation - Improve version hash detection to handle both content and keys - Add test case for version hash in snapshot keys scenario - Update CHANGELOG.md with feature description - Preserve all existing pytest-workflow logic for separate PR Addresses feedback from @mashehu and @mirpedrol Related to: https://github.com/nf-core/modules/issues/6505 --- CHANGELOG.md | 1 + nf_core/modules/lint/module_tests.py | 43 +++++---- tests/modules/lint/test_module_tests.py | 110 +++++++----------------- 3 files changed, 51 insertions(+), 103 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f475519df0..5aa3e23b80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Support modules with `exec:` blocks ([#3633](https://github.com/nf-core/tools/pull/3633)) - feat: nf-core modules bump-version supports specifying the toolkit ([#3608](https://github.com/nf-core/tools/pull/3608)) +- Lint for version captures in modules - detect hash format instead of actual YAML content ([#3676](https://github.com/nf-core/tools/pull/3676)) ### Subworkflows diff --git a/nf_core/modules/lint/module_tests.py b/nf_core/modules/lint/module_tests.py index 8618e6dc64..892c95d948 100644 --- a/nf_core/modules/lint/module_tests.py +++ b/nf_core/modules/lint/module_tests.py @@ -16,25 +16,12 @@ def _contains_version_hash(test_content): - """ - Check if test content contains version information in hash format. - - Uses precise regex patterns to detect version hash formats while avoiding - false positives from similar strings. - - Args: - test_content: Content of a single test from snapshot - - Returns: - bool: True if hash format detected, False otherwise - """ - # More precise regex patterns with proper boundaries + """Check if test content contains version information in hash format rather than actual YAML content.""" version_hash_patterns = [ - r"\bversions\.yml:md5,[a-f0-9]{32}\b", # Exact MD5 format (32 hex chars) - r"\bversions\.yml:sha[0-9]*,[a-f0-9]+\b", # SHA format with variable length + r"\bversions\.yml:md5,[a-f0-9]{32}\b", + r"\bversions\.yml:sha[0-9]*,[a-f0-9]+\b", ] - # Convert to string only once and search efficiently content_str = str(test_content) for pattern in version_hash_patterns: @@ -44,6 +31,22 @@ def _contains_version_hash(test_content): return False +def _check_snapshot_for_version_hash(snap_content, test_name): + """Check both snapshot content and keys for version hash patterns.""" + # Check test content for version hashes + if _contains_version_hash(snap_content[test_name]): + return True + + # Check specific test's keys for version hashes + test_data = snap_content.get(test_name, {}) + if isinstance(test_data, dict): + for key in test_data.keys(): + if _contains_version_hash(str(key)): + return True + + return False + + def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): """ Lint the tests of a module in ``nf-core/modules`` @@ -199,11 +202,8 @@ def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): snap_file, ) ) - # Check if version content is actual content vs MD5/SHA hash - # Related to: https://github.com/nf-core/modules/issues/6505 - # Ensures version snapshots contain actual content instead of hash values - if _contains_version_hash(snap_content[test_name]): - # Invalid - contains hash format + # Check if version content contains hash instead of actual YAML content + if _check_snapshot_for_version_hash(snap_content, test_name): module.failed.append( ( "test_snap_version_content", @@ -212,7 +212,6 @@ def module_tests(_, module: NFCoreComponent, allow_missing: bool = False): ) ) else: - # Valid - either contains actual content or no version hash detected module.passed.append( ( "test_snap_version_content", diff --git a/tests/modules/lint/test_module_tests.py b/tests/modules/lint/test_module_tests.py index ce09330e9e..6c9d7db378 100644 --- a/tests/modules/lint/test_module_tests.py +++ b/tests/modules/lint/test_module_tests.py @@ -171,7 +171,7 @@ def test_modules_empty_file_in_snapshot(self): """Test linting a nf-test module with an empty file sha sum in the test snapshot, which should make it fail (if it is not a stub)""" snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" snap = json.load(snap_file.open()) - content = snap_file.read_text() + snap_file.read_text() snap["my test"]["content"][0]["0"] = "test:md5,d41d8cd98f00b204e9800998ecf8427e" with open(snap_file, "w") as fh: @@ -184,15 +184,11 @@ def test_modules_empty_file_in_snapshot(self): assert len(module_lint.warned) >= 0 assert module_lint.failed[0].lint_test == "test_snap_md5sum" - # reset the file - with open(snap_file, "w") as fh: - fh.write(content) - def test_modules_empty_file_in_stub_snapshot(self): """Test linting a nf-test module with an empty file sha sum in the stub test snapshot, which should make it not fail""" snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" snap = json.load(snap_file.open()) - content = snap_file.read_text() + snap_file.read_text() snap["my_test_stub"] = {"content": [{"0": "test:md5,d41d8cd98f00b204e9800998ecf8427e", "versions": {}}]} with open(snap_file, "w") as fh: @@ -219,20 +215,12 @@ def test_modules_empty_file_in_stub_snapshot(self): assert found_test, "test_snap_md5sum not found in passed tests" - # reset the file - with open(snap_file, "w") as fh: - fh.write(content) - @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") def test_modules_version_snapshot_content_md5_hash(self): - """Test linting a nf-test module with version information as MD5 hash instead of actual content, which should fail. - - Related to: https://github.com/nf-core/modules/issues/6505 - Fixed in: https://github.com/nf-core/tools/pull/3676 - """ + """Test linting a nf-test module with version information as MD5 hash instead of actual content, which should fail.""" snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" snap = json.load(snap_file.open()) - content = snap_file.read_text() + snap_file.read_text() # Add a version entry with MD5 hash format (the old way that should be flagged) snap["my test"]["content"][0]["versions"] = "versions.yml:md5,949da9c6297b613b50e24c421576f3f1" @@ -249,22 +237,13 @@ def test_modules_version_snapshot_content_md5_hash(self): assert len(version_content_failures) == 1, ( f"Expected 1 test_snap_version_content failure, got {len(version_content_failures)}" ) - assert version_content_failures[0].lint_test == "test_snap_version_content" - - # reset the file - with open(snap_file, "w") as fh: - fh.write(content) @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") def test_modules_version_snapshot_content_valid(self): - """Test linting a nf-test module with version information as actual content, which should pass. - - Related to: https://github.com/nf-core/modules/issues/6505 - Fixed in: https://github.com/nf-core/tools/pull/3676 - """ + """Test linting a nf-test module with version information as actual content, which should pass.""" snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" snap = json.load(snap_file.open()) - content = snap_file.read_text() + snap_file.read_text() # Add a version entry with actual content (the new way that should pass) snap["my test"]["content"][0]["versions"] = {"ALE": {"ale": "20180904"}} @@ -291,20 +270,12 @@ def test_modules_version_snapshot_content_valid(self): ] assert len(version_content_passed) > 0, "test_snap_version_content not found in passed tests" - # reset the file - with open(snap_file, "w") as fh: - fh.write(content) - @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") def test_modules_version_snapshot_content_sha_hash(self): - """Test linting a nf-test module with version information as SHA hash, which should fail. - - Related to: https://github.com/nf-core/modules/issues/6505 - Fixed in: https://github.com/nf-core/tools/pull/3676 - """ + """Test linting a nf-test module with version information as SHA hash, which should fail.""" snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" snap = json.load(snap_file.open()) - content = snap_file.read_text() + snap_file.read_text() # Add a version entry with SHA hash format (should be flagged) snap["my test"]["content"][0]["versions"] = ( @@ -323,24 +294,16 @@ def test_modules_version_snapshot_content_sha_hash(self): f"Expected 1 test_snap_version_content failure, got {len(version_content_failures)}" ) - # reset the file - with open(snap_file, "w") as fh: - fh.write(content) - @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") - def test_modules_version_snapshot_content_mixed_scenario(self): - """Test linting with mixed version content - some valid, some hash format. - - Related to: https://github.com/nf-core/modules/issues/6505 - Fixed in: https://github.com/nf-core/tools/pull/3676 - """ + def test_modules_version_snapshot_no_version_content(self): + """Test linting when no version information is present - should not trigger version content check.""" snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" snap = json.load(snap_file.open()) - content = snap_file.read_text() + snap_file.read_text() - # Create a scenario with multiple tests - one with hash, one with valid content - snap["test_with_hash"] = {"content": [{"versions": "versions.yml:md5,949da9c6297b613b50e24c421576f3f1"}]} - snap["test_with_valid_content"] = {"content": [{"versions": {"BPIPE": {"bpipe": "0.9.11"}}}]} + # Remove version information entirely + if "content" in snap["my test"] and snap["my test"]["content"]: + snap["my test"]["content"][0].pop("versions", None) with open(snap_file, "w") as fh: json.dump(snap, fh) @@ -348,37 +311,26 @@ def test_modules_version_snapshot_content_mixed_scenario(self): module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) module_lint.lint(print_results=False, module="bpipe/test") - # Should have failure for the hash test + # Should not have version content check failures when no version data present version_content_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_version_content"] - assert len(version_content_failures) >= 1, "Expected at least 1 failure for hash format" - - # Should have pass for the valid content test - version_content_passed = [ - x - for x in module_lint.passed - if (hasattr(x, "lint_test") and x.lint_test == "test_snap_version_content") - or (isinstance(x, tuple) and len(x) > 0 and x[0] == "test_snap_version_content") - ] - assert len(version_content_passed) >= 1, "Expected at least 1 pass for valid content" + assert len(version_content_failures) == 0, "Should not have version content failures when no versions present" - # reset the file - with open(snap_file, "w") as fh: - fh.write(content) + # Should have test_snap_versions failure since no versions are present + version_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_versions"] + assert len(version_failures) == 1, "Expected test_snap_versions failure when no versions present" @pytest.mark.issue("https://github.com/nf-core/modules/issues/6505") - def test_modules_version_snapshot_no_version_content(self): - """Test linting when no version information is present - should not trigger version content check. - - Related to: https://github.com/nf-core/modules/issues/6505 - Fixed in: https://github.com/nf-core/tools/pull/3676 - """ + def test_modules_version_snapshot_hash_in_keys(self): + """Test linting when version hash appears in snapshot keys rather than content.""" snap_file = self.bpipe_test_module_path / "tests" / "main.nf.test.snap" snap = json.load(snap_file.open()) - content = snap_file.read_text() + snap_file.read_text() - # Remove version information entirely - if "content" in snap["my test"] and snap["my test"]["content"]: - snap["my test"]["content"][0].pop("versions", None) + # Create a test where version hash appears in the test keys + snap["test_with_hash_key"] = { + "content": [{"versions.yml:md5,949da9c6297b613b50e24c421576f3f1": "some_value"}], + "versions": {"BPIPE": {"bpipe": "0.9.11"}}, + } with open(snap_file, "w") as fh: json.dump(snap, fh) @@ -386,10 +338,6 @@ def test_modules_version_snapshot_no_version_content(self): module_lint = nf_core.modules.lint.ModuleLint(directory=self.nfcore_modules) module_lint.lint(print_results=False, module="bpipe/test") - # Should not have version content check failures when no version data present + # Should fail because version hash is in the keys version_content_failures = [x for x in module_lint.failed if x.lint_test == "test_snap_version_content"] - assert len(version_content_failures) == 0, "Should not have version content failures when no versions present" - - # reset the file - with open(snap_file, "w") as fh: - fh.write(content) + assert len(version_content_failures) >= 1, "Expected failure for hash in keys"