270 lines
9.5 KiB
Python
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()
|