survey_custom_certificate_t.../tests/test_hypothesis_strategies.py
2025-11-29 08:46:04 +07:00

270 lines
9.5 KiB
Python

# -*- coding: utf-8 -*-
"""
Tests for Hypothesis strategies.
This module verifies that the custom Hypothesis strategies generate valid
test data that conforms to the expected formats and constraints.
"""
import unittest
import json
import re
from io import BytesIO
try:
from hypothesis import given, settings, strategies as st
from hypothesis.strategies import composite
HYPOTHESIS_AVAILABLE = True
except ImportError:
HYPOTHESIS_AVAILABLE = False
try:
from docx import Document
DOCX_AVAILABLE = True
except ImportError:
DOCX_AVAILABLE = False
# Import our custom strategies
if HYPOTHESIS_AVAILABLE:
from .hypothesis_strategies import (
placeholder_keys,
text_with_placeholders,
docx_with_placeholders,
placeholder_mappings,
valid_mappings,
participant_data,
docx_with_mappings_and_data,
empty_docx,
docx_with_duplicate_placeholders,
)
@unittest.skipIf(not HYPOTHESIS_AVAILABLE, "Hypothesis not installed")
class TestHypothesisStrategies(unittest.TestCase):
"""Test cases for custom Hypothesis strategies."""
def test_hypothesis_available(self):
"""Verify Hypothesis is available for testing."""
self.assertTrue(HYPOTHESIS_AVAILABLE)
@given(placeholder_keys())
@settings(max_examples=50)
def test_placeholder_keys_format(self, key):
"""Test that placeholder_keys generates valid placeholder formats."""
# Should match the pattern {key.field_name}
pattern = r'^\{key\.[a-zA-Z][a-zA-Z0-9_]*\}$'
self.assertRegex(
key, pattern,
f"Generated key '{key}' does not match expected pattern"
)
@given(text_with_placeholders(min_placeholders=1, max_placeholders=5))
@settings(max_examples=50)
def test_text_with_placeholders_contains_placeholders(self, result):
"""Test that text_with_placeholders generates text with placeholders."""
text, placeholders = result
# Text should be a string
self.assertIsInstance(text, str)
# Placeholders should be a list
self.assertIsInstance(placeholders, list)
# Should have at least one placeholder
self.assertGreater(len(placeholders), 0)
# All placeholders should appear in the text
for placeholder in placeholders:
self.assertIn(placeholder, text)
@unittest.skipIf(not DOCX_AVAILABLE, "python-docx not installed")
@given(docx_with_placeholders(min_placeholders=1, max_placeholders=5))
@settings(max_examples=20)
def test_docx_with_placeholders_is_valid(self, result):
"""Test that docx_with_placeholders generates valid DOCX files."""
docx_binary, placeholders = result
# Should return bytes
self.assertIsInstance(docx_binary, bytes)
# Should have content
self.assertGreater(len(docx_binary), 0)
# Should be a valid DOCX file
try:
doc_stream = BytesIO(docx_binary)
doc = Document(doc_stream)
self.assertIsNotNone(doc)
except Exception as e:
self.fail(f"Generated DOCX is not valid: {e}")
# Placeholders should be a list
self.assertIsInstance(placeholders, list)
# Should have at least one placeholder
self.assertGreater(len(placeholders), 0)
# All placeholders should be unique
self.assertEqual(len(placeholders), len(set(placeholders)))
@given(placeholder_mappings())
@settings(max_examples=50)
def test_placeholder_mappings_structure(self, mapping):
"""Test that placeholder_mappings generates valid mapping structures."""
# Should be a dictionary
self.assertIsInstance(mapping, dict)
# Should have required keys
self.assertIn('key', mapping)
self.assertIn('value_type', mapping)
self.assertIn('value_field', mapping)
self.assertIn('custom_text', mapping)
# key should be a valid placeholder
pattern = r'^\{key\.[a-zA-Z0-9_]+\}$'
self.assertRegex(mapping['key'], pattern)
# value_type should be one of the valid types
self.assertIn(mapping['value_type'], ['survey_field', 'user_field', 'custom_text'])
# If value_type is custom_text, value_field should be empty
if mapping['value_type'] == 'custom_text':
self.assertEqual(mapping['value_field'], '')
else:
# Otherwise, value_field should not be empty
self.assertNotEqual(mapping['value_field'], '')
self.assertEqual(mapping['custom_text'], '')
@given(valid_mappings(min_placeholders=1, max_placeholders=5))
@settings(max_examples=50)
def test_valid_mappings_structure(self, mappings):
"""Test that valid_mappings generates valid complete mapping structures."""
# Should be a dictionary
self.assertIsInstance(mappings, dict)
# Should have 'placeholders' key
self.assertIn('placeholders', mappings)
# placeholders should be a list
self.assertIsInstance(mappings['placeholders'], list)
# Should have at least one placeholder
self.assertGreater(len(mappings['placeholders']), 0)
# All placeholders should have unique keys
keys = [p['key'] for p in mappings['placeholders']]
self.assertEqual(len(keys), len(set(keys)))
# Should be valid JSON serializable
try:
json_str = json.dumps(mappings)
self.assertIsInstance(json_str, str)
except Exception as e:
self.fail(f"Mappings are not JSON serializable: {e}")
@given(participant_data())
@settings(max_examples=50)
def test_participant_data_structure(self, data):
"""Test that participant_data generates valid data structures."""
# Should be a dictionary
self.assertIsInstance(data, dict)
# Should have all required fields
required_fields = [
'survey_title',
'survey_description',
'partner_name',
'partner_email',
'email',
'create_date',
'completion_date',
'scoring_percentage',
'scoring_total',
]
for field in required_fields:
self.assertIn(field, data)
# Email should be valid format
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
self.assertRegex(data['partner_email'], email_pattern)
self.assertRegex(data['email'], email_pattern)
# Dates should be in YYYY-MM-DD format
date_pattern = r'^\d{4}-\d{2}-\d{2}$'
self.assertRegex(data['create_date'], date_pattern)
self.assertRegex(data['completion_date'], date_pattern)
@unittest.skipIf(not DOCX_AVAILABLE, "python-docx not installed")
@given(docx_with_mappings_and_data())
@settings(max_examples=10)
def test_docx_with_mappings_and_data_coordination(self, result):
"""Test that docx_with_mappings_and_data generates coordinated test data."""
docx_binary, mappings, data = result
# DOCX should be valid
self.assertIsInstance(docx_binary, bytes)
self.assertGreater(len(docx_binary), 0)
# Mappings should be valid
self.assertIsInstance(mappings, dict)
self.assertIn('placeholders', mappings)
self.assertIsInstance(mappings['placeholders'], list)
# Data should be valid
self.assertIsInstance(data, dict)
# All mapped fields should exist in data (except custom_text)
for mapping in mappings['placeholders']:
if mapping['value_type'] != 'custom_text':
value_field = mapping['value_field']
self.assertIn(
value_field, data,
f"Mapped field '{value_field}' not found in data"
)
@unittest.skipIf(not DOCX_AVAILABLE, "python-docx not installed")
@given(empty_docx())
@settings(max_examples=10)
def test_empty_docx_is_valid(self, docx_binary):
"""Test that empty_docx generates valid DOCX files."""
# Should return bytes
self.assertIsInstance(docx_binary, bytes)
# Should have content
self.assertGreater(len(docx_binary), 0)
# Should be a valid DOCX file
try:
doc_stream = BytesIO(docx_binary)
doc = Document(doc_stream)
self.assertIsNotNone(doc)
except Exception as e:
self.fail(f"Generated empty DOCX is not valid: {e}")
@unittest.skipIf(not DOCX_AVAILABLE, "python-docx not installed")
@given(docx_with_duplicate_placeholders())
@settings(max_examples=10)
def test_docx_with_duplicate_placeholders_deduplication(self, result):
"""Test that docx_with_duplicate_placeholders returns unique placeholders."""
docx_binary, placeholders = result
# Should return bytes
self.assertIsInstance(docx_binary, bytes)
# Placeholders should be unique
self.assertEqual(len(placeholders), len(set(placeholders)))
# Should be a valid DOCX file
try:
doc_stream = BytesIO(docx_binary)
doc = Document(doc_stream)
self.assertIsNotNone(doc)
except Exception as e:
self.fail(f"Generated DOCX with duplicates is not valid: {e}")
if __name__ == '__main__':
unittest.main()