#!/usr/bin/env python3 """ Test script for GBP Audit Service field checks. This validates that the _check_hours and _check_photos methods correctly use the google_opening_hours and google_photos_count fields. Run: python3 tests/test_gbp_audit_field_checks.py """ import sys import json from dataclasses import dataclass from typing import Optional, Any # Mock SQLAlchemy classes before importing the service class MockSession: """Mock SQLAlchemy session""" def query(self, *args, **kwargs): return MockQuery() def add(self, *args): pass def commit(self): pass def refresh(self, *args): pass class MockQuery: """Mock query object""" def filter(self, *args, **kwargs): return self def order_by(self, *args): return self def first(self): return None def all(self): return [] def limit(self, *args): return self # Mock the database imports @dataclass class MockCompany: """Mock Company model""" id: int = 1 name: str = "Test Company" address_street: str = "ul. Testowa 1" address_city: str = "Gdynia" address_postal: str = "81-300" address_full: str = "ul. Testowa 1, 81-300 Gdynia" phone: str = "+48 123 456 789" website: str = "https://example.com" description_short: str = "Test company description" description_full: str = "Test company full description with more than one hundred characters to meet the minimum requirement for a complete description." category_id: int = 1 category: Any = None services_offered: str = "Service 1, Service 2, Service 3" services: list = None contacts: list = None status: str = "active" @dataclass class MockCategory: """Mock Category model""" id: int = 1 name: str = "IT" @dataclass class MockCompanyWebsiteAnalysis: """Mock CompanyWebsiteAnalysis model with GBP fields""" id: int = 1 company_id: int = 1 google_rating: float = 4.8 google_reviews_count: int = 35 google_place_id: str = "ChIJtestplaceid" google_business_status: str = "OPERATIONAL" google_opening_hours: Optional[dict] = None google_photos_count: Optional[int] = None analyzed_at: str = "2026-01-08" def test_check_hours(): """Test _check_hours method with google_opening_hours field""" print("\n=== Testing _check_hours() ===") # Create mock objects company = MockCompany() company.category = MockCategory() # Test 1: With opening hours data analysis_with_hours = MockCompanyWebsiteAnalysis( google_opening_hours={ "open_now": True, "weekday_text": [ "poniedziałek: 08:00–16:00", "wtorek: 08:00–16:00", "środa: 08:00–16:00", "czwartek: 08:00–16:00", "piątek: 08:00–16:00", "sobota: Zamknięte", "niedziela: Zamknięte" ] } ) # Simulate the _check_hours logic max_score = 8 # FIELD_WEIGHTS['hours'] if analysis_with_hours and analysis_with_hours.google_opening_hours: status = 'complete' value = analysis_with_hours.google_opening_hours score = max_score recommendation = None else: status = 'missing' value = None score = 0 recommendation = 'Dodaj godziny otwarcia firmy.' print(f" Test 1 (with hours): status={status}, score={score}/{max_score}") assert status == 'complete', f"Expected 'complete', got '{status}'" assert score == max_score, f"Expected {max_score}, got {score}" assert value is not None, "Expected value to be set" print(" ✅ PASSED") # Test 2: Without opening hours data (None) analysis_no_hours = MockCompanyWebsiteAnalysis(google_opening_hours=None) if analysis_no_hours and analysis_no_hours.google_opening_hours: status = 'complete' score = max_score else: status = 'missing' score = 0 print(f" Test 2 (no hours): status={status}, score={score}/{max_score}") assert status == 'missing', f"Expected 'missing', got '{status}'" assert score == 0, f"Expected 0, got {score}" print(" ✅ PASSED") # Test 3: No analysis object at all analysis_none = None if analysis_none and analysis_none.google_opening_hours: status = 'complete' score = max_score else: status = 'missing' score = 0 print(f" Test 3 (no analysis): status={status}, score={score}/{max_score}") assert status == 'missing', f"Expected 'missing', got '{status}'" print(" ✅ PASSED") return True def test_check_photos(): """Test _check_photos method with google_photos_count field""" print("\n=== Testing _check_photos() ===") # Photo requirements from the service PHOTO_REQUIREMENTS = { 'minimum': 3, 'recommended': 10, 'optimal': 25, } max_score = 15 # FIELD_WEIGHTS['photos'] # Test 1: With 10+ photos (complete) analysis_many_photos = MockCompanyWebsiteAnalysis(google_photos_count=10) photo_count = 0 if analysis_many_photos and analysis_many_photos.google_photos_count: photo_count = analysis_many_photos.google_photos_count if photo_count >= PHOTO_REQUIREMENTS['recommended']: status = 'complete' score = max_score elif photo_count >= PHOTO_REQUIREMENTS['minimum']: status = 'partial' partial_score = max_score * (photo_count / PHOTO_REQUIREMENTS['recommended']) score = min(partial_score, max_score * 0.7) else: status = 'missing' score = 0 print(f" Test 1 (10 photos): status={status}, score={score}/{max_score}, count={photo_count}") assert status == 'complete', f"Expected 'complete', got '{status}'" assert score == max_score, f"Expected {max_score}, got {score}" print(" ✅ PASSED") # Test 2: With 5 photos (partial) analysis_some_photos = MockCompanyWebsiteAnalysis(google_photos_count=5) photo_count = 0 if analysis_some_photos and analysis_some_photos.google_photos_count: photo_count = analysis_some_photos.google_photos_count if photo_count >= PHOTO_REQUIREMENTS['recommended']: status = 'complete' score = max_score elif photo_count >= PHOTO_REQUIREMENTS['minimum']: status = 'partial' partial_score = max_score * (photo_count / PHOTO_REQUIREMENTS['recommended']) score = min(partial_score, max_score * 0.7) else: status = 'missing' score = 0 print(f" Test 2 (5 photos): status={status}, score={score}/{max_score}, count={photo_count}") assert status == 'partial', f"Expected 'partial', got '{status}'" assert score > 0, f"Expected score > 0, got {score}" print(" ✅ PASSED") # Test 3: With 0 photos (missing) analysis_no_photos = MockCompanyWebsiteAnalysis(google_photos_count=0) photo_count = 0 if analysis_no_photos and analysis_no_photos.google_photos_count: photo_count = analysis_no_photos.google_photos_count if photo_count >= PHOTO_REQUIREMENTS['recommended']: status = 'complete' score = max_score elif photo_count >= PHOTO_REQUIREMENTS['minimum']: status = 'partial' score = max_score * 0.7 else: status = 'missing' score = 0 print(f" Test 3 (0 photos): status={status}, score={score}/{max_score}, count={photo_count}") assert status == 'missing', f"Expected 'missing', got '{status}'" assert score == 0, f"Expected 0, got {score}" print(" ✅ PASSED") # Test 4: No analysis object analysis_none = None photo_count = 0 if analysis_none and analysis_none.google_photos_count: photo_count = analysis_none.google_photos_count if photo_count >= PHOTO_REQUIREMENTS['recommended']: status = 'complete' elif photo_count >= PHOTO_REQUIREMENTS['minimum']: status = 'partial' else: status = 'missing' print(f" Test 4 (no analysis): status={status}, count={photo_count}") assert status == 'missing', f"Expected 'missing', got '{status}'" print(" ✅ PASSED") return True def test_field_weights(): """Verify field weights are properly configured""" print("\n=== Testing Field Weights ===") FIELD_WEIGHTS = { 'name': 10, 'address': 10, 'phone': 8, 'website': 8, 'hours': 8, 'categories': 10, 'photos': 15, 'description': 12, 'services': 10, 'reviews': 9, } total = sum(FIELD_WEIGHTS.values()) print(f" Total weight: {total}/100") assert total == 100, f"Expected total weight 100, got {total}" print(" ✅ PASSED") # Check individual weights assert FIELD_WEIGHTS['hours'] == 8, "hours weight should be 8" assert FIELD_WEIGHTS['photos'] == 15, "photos weight should be 15" print(" hours weight: 8 ✅") print(" photos weight: 15 ✅") return True def main(): """Run all tests""" print("=" * 60) print("GBP Audit Service - Field Checks Test") print("=" * 60) all_passed = True try: all_passed &= test_field_weights() all_passed &= test_check_hours() all_passed &= test_check_photos() except AssertionError as e: print(f"\n❌ TEST FAILED: {e}") all_passed = False except Exception as e: print(f"\n❌ ERROR: {e}") all_passed = False print("\n" + "=" * 60) if all_passed: print("✅ ALL TESTS PASSED") print("=" * 60) return 0 else: print("❌ SOME TESTS FAILED") print("=" * 60) return 1 if __name__ == '__main__': sys.exit(main())