soleprint init commit

This commit is contained in:
buenosairesam
2025-12-24 05:38:37 -03:00
commit 329c401ff5
96 changed files with 11564 additions and 0 deletions

View File

@@ -0,0 +1,175 @@
"""
Map tests to Gherkin scenarios based on metadata.
Tests can declare their Gherkin metadata via docstrings:
```python
def test_coverage_check(self):
'''
Feature: Reservar turno veterinario
Scenario: Verificar cobertura en zona disponible
Tags: @smoke @coverage
'''
```
Or via class docstrings:
```python
class TestCoverageFlow(ContractHTTPTestCase):
"""
Feature: Reservar turno veterinario
Tags: @coverage
"""
```
"""
import re
from typing import Optional
from dataclasses import dataclass
@dataclass
class TestGherkinMetadata:
"""Gherkin metadata extracted from a test."""
feature: Optional[str] = None
scenario: Optional[str] = None
tags: list[str] = None
def __post_init__(self):
if self.tags is None:
self.tags = []
def extract_gherkin_metadata(docstring: Optional[str]) -> TestGherkinMetadata:
"""
Extract Gherkin metadata from a test docstring.
Looks for:
- Feature: <name>
- Scenario: <name>
- Tags: @tag1 @tag2
Args:
docstring: Test or class docstring
Returns:
TestGherkinMetadata with extracted info
"""
if not docstring:
return TestGherkinMetadata()
# Extract Feature
feature = None
feature_match = re.search(r"Feature:\s*(.+)", docstring)
if feature_match:
feature = feature_match.group(1).strip()
# Extract Scenario (also try Spanish: Escenario)
scenario = None
scenario_match = re.search(r"(Scenario|Escenario):\s*(.+)", docstring)
if scenario_match:
scenario = scenario_match.group(2).strip()
# Extract Tags
tags = []
tags_match = re.search(r"Tags:\s*(.+)", docstring)
if tags_match:
tags_str = tags_match.group(1).strip()
tags = re.findall(r"@[\w-]+", tags_str)
return TestGherkinMetadata(
feature=feature,
scenario=scenario,
tags=tags
)
def has_gherkin_metadata(docstring: Optional[str]) -> bool:
"""Check if a docstring contains Gherkin metadata."""
if not docstring:
return False
return bool(
re.search(r"Feature:\s*", docstring) or
re.search(r"Scenario:\s*", docstring) or
re.search(r"Escenario:\s*", docstring) or
re.search(r"Tags:\s*@", docstring)
)
def match_test_to_feature(
test_metadata: TestGherkinMetadata,
feature_names: list[str]
) -> Optional[str]:
"""
Match a test's feature metadata to an actual feature name.
Uses fuzzy matching if exact match not found.
Args:
test_metadata: Extracted test metadata
feature_names: List of available feature names
Returns:
Matched feature name or None
"""
if not test_metadata.feature:
return None
# Exact match
if test_metadata.feature in feature_names:
return test_metadata.feature
# Case-insensitive match
test_feature_lower = test_metadata.feature.lower()
for feature_name in feature_names:
if feature_name.lower() == test_feature_lower:
return feature_name
# Partial match (feature name contains test feature or vice versa)
for feature_name in feature_names:
if test_feature_lower in feature_name.lower():
return feature_name
if feature_name.lower() in test_feature_lower:
return feature_name
return None
def match_test_to_scenario(
test_metadata: TestGherkinMetadata,
scenario_names: list[str]
) -> Optional[str]:
"""
Match a test's scenario metadata to an actual scenario name.
Uses fuzzy matching if exact match not found.
Args:
test_metadata: Extracted test metadata
scenario_names: List of available scenario names
Returns:
Matched scenario name or None
"""
if not test_metadata.scenario:
return None
# Exact match
if test_metadata.scenario in scenario_names:
return test_metadata.scenario
# Case-insensitive match
test_scenario_lower = test_metadata.scenario.lower()
for scenario_name in scenario_names:
if scenario_name.lower() == test_scenario_lower:
return scenario_name
# Partial match
for scenario_name in scenario_names:
if test_scenario_lower in scenario_name.lower():
return scenario_name
if scenario_name.lower() in test_scenario_lower:
return scenario_name
return None