# -*- 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()