From 3da73d626bb2f835f2a1bcc4c590ad79f8c3753e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Sat, 7 Mar 2026 12:34:17 +0100 Subject: [PATCH] chore: major code cleanup and type safety using phpstan --- docs/SYMFONY_7.4_UPGRADE_PLAN.md | 484 ------------------ phpstan-baseline.neon | 2 + phpstan.full.neon | 13 + src/Admin/Field/JsonDataField.php | 1 + src/BusProNet/Constants.php | 1 + .../DataProcessor/BookingDataProcessor.php | 4 +- .../DataProcessor/ServiceMappingCollector.php | 10 +- .../Exception/ApiClientException.php | 1 + .../Exception/ResponseParserException.php | 1 + .../Form/ChoiceLoader/CountryChoiceLoader.php | 1 + src/BusProNet/Form/CountryType.php | 1 + src/BusProNet/Model/Insurance.php | 11 +- src/BusProNet/Model/Product.php | 1 + src/BusProNet/Traits/XmlParserTrait.php | 1 + src/BusProNet/Utility/DateCodeUtility.php | 1 + src/BusProNet/Utility/DayTimeUtility.php | 1 + src/BusProNet/XmlLoader/AbstractLoader.php | 1 + .../XmlParser/AvailabilitiesParser.php | 1 + .../XmlParser/BookingUpdateParser.php | 1 + src/BusProNet/XmlParser/BookingsParser.php | 1 + src/BusProNet/XmlParser/CountriesParser.php | 1 + src/BusProNet/XmlParser/MutableDataParser.php | 1 + .../XmlParser/NotificationParser.php | 1 + .../XmlParser/PersonalDataParser.php | 1 + src/BusProNet/XmlParser/ProductsParser.php | 6 +- src/Command/BpnFetchTravelCommand.php | 7 +- src/Command/BpnReplayCommand.php | 18 +- src/Command/BpnXmlSyncCommand.php | 4 +- src/Command/CleanupXMLDumpsCommand.php | 1 + .../DraftBackfillBookingNumberCommand.php | 6 +- src/Command/DraftCleanupCommand.php | 4 +- src/Command/DraftInspectCommand.php | 15 +- src/Command/GenerateKeysCommand.php | 1 + src/Controller/Admin/DashboardController.php | 1 + src/Controller/Api/CountryController.php | 1 + src/Controller/Api/CrmAttributeController.php | 1 + src/Controller/Api/HotelController.php | 1 + src/Controller/Api/LastUpdateController.php | 5 +- src/Controller/Api/ProductController.php | 1 + src/Controller/Api/TravelController.php | 5 +- src/Controller/Api/UserinfoController.php | 3 +- .../Booking/Create/Step1Controller.php | 3 +- .../Booking/Create/Step4Controller.php | 19 +- src/Controller/Booking/IndexController.php | 1 + src/Controller/RegistrationController.php | 1 + src/Controller/ResetPasswordController.php | 1 + src/Controller/SecurityController.php | 1 + .../Env/CsvIntEnvVarProcessor.php | 45 ++ src/Form/BookingCreateStep1Type.php | 1 + src/Form/RoomSelectType.php | 1 + .../Abstract/AbstractFieldStateProvider.php | 6 +- .../AbstractParticipantFieldHandler.php | 15 +- .../Service/Condition/CompositeCondition.php | 14 +- .../Service/Condition/FieldValueCondition.php | 10 +- .../RentalInsuranceAvailableCondition.php | 2 +- .../Condition/RoomSelectionCondition.php | 4 + .../Condition/ServiceSubTypeCondition.php | 26 +- .../ParticipantFieldHandlerRegistry.php | 8 +- .../ParticipantParkingFieldHandler.php | 2 +- src/Form/StepSelectChoiceType.php | 1 + src/Kernel.php | 1 + src/Service/BpnXmlAnonymizer.php | 8 +- src/Service/InsuranceManager.php | 4 +- src/Service/ParticipantEligibilityChecker.php | 2 +- src/Twig/AppRuntime.php | 8 + ...oryAdditionalServicesSelectedValidator.php | 2 +- .../Constraints/ParticipantValidator.php | 2 +- tests/BusProNet/ApiClientReceiveTest.php | 3 + .../DataLoader/HotelDataLoaderTest.php | 22 +- .../DataLoader/PickupDataLoaderTest.php | 14 +- .../DataLoader/TravelDataLoaderTest.php | 18 +- .../BookingDataProcessorTest.php | 120 ++--- tests/BusProNet/Model/BookingTest.php | 28 +- tests/BusProNet/Model/TravelTest.php | 16 +- .../BusProNet/Utility/DayTimeUtilityTest.php | 5 +- .../Utility/TravelCodeUtilityTest.php | 12 +- .../BusProNet/XmlLoader/PickupLoaderTest.php | 8 +- .../BusProNet/XmlParser/AgencyParserTest.php | 48 +- .../XmlParser/BookingInsurancesParserTest.php | 62 ++- .../XmlParser/BookingResponseParserTest.php | 134 ++--- .../XmlParser/InsuranceParserTest.php | 120 ++--- .../EventListener/DomainThemeListenerTest.php | 22 +- tests/Form/Model/AcceptedVouchersTest.php | 20 +- tests/Form/Model/BookingDtoTest.php | 14 +- tests/Form/Model/ParticipantDtoTest.php | 34 +- .../InsuranceMutabilityConditionTest.php | 26 +- .../Condition/SingleRoomTypeConditionTest.php | 24 +- ...articipantAssignedRoomFieldHandlerTest.php | 74 +-- .../ParticipantDropOffFieldHandlerTest.php | 48 +- ...articipantFieldOptionsProviderBabyTest.php | 54 +- ...eldOptionsProviderMandatoryServiceTest.php | 21 +- ...articipantLicensePlateFieldHandlerTest.php | 30 +- .../ParticipantParkingFieldHandlerTest.php | 40 +- ...ionDiscountReplacementFieldHandlerTest.php | 88 ++-- .../ParticipantVegFieldHandlerTest.php | 43 +- tests/Service/BpnXmlAnonymizerTest.php | 36 +- tests/Service/DomainConfigProviderTest.php | 30 +- tests/Service/ErrorCodeGeneratorTest.php | 22 +- tests/Service/InsuranceManagerTest.php | 99 ++-- .../ParticipantEligibilityCheckerTest.php | 14 +- tests/Service/RoomAssignerTest.php | 3 + .../Constraints/ParticipantValidatorTest.php | 3 +- .../RoomSelectionValidatorTest.php | 3 + 103 files changed, 976 insertions(+), 1192 deletions(-) delete mode 100644 docs/SYMFONY_7.4_UPGRADE_PLAN.md create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.full.neon create mode 100644 src/DependencyInjection/Env/CsvIntEnvVarProcessor.php diff --git a/docs/SYMFONY_7.4_UPGRADE_PLAN.md b/docs/SYMFONY_7.4_UPGRADE_PLAN.md deleted file mode 100644 index 8757c130..00000000 --- a/docs/SYMFONY_7.4_UPGRADE_PLAN.md +++ /dev/null @@ -1,484 +0,0 @@ -# Symfony 7.4 Upgrade Plan - -**Project:** MyEP Next Booking -**Current Version:** Symfony 6.4.x (6.4.33) -**Target Version:** Symfony 7.4 (LTS) -**Date:** 2026-02-23 -**Status:** Ready for Upgrade - ---- - -## Executive Summary - -**Estimated Effort: LOW** -**Risk Level: LOW** -**Status: READY FOR UPGRADE** - -The MyEP Next Booking application is well-positioned for a Symfony 7.4 upgrade. The codebase follows modern Symfony best practices, uses PHP 8 features extensively, and avoids most deprecated patterns. All pre-upgrade fixes have been completed. - -**Key Facts:** -- Symfony 7.4 was released on November 27, 2025 -- Requires PHP 8.2.0+ (current: PHP 8.3.30) -- LTS version with bug fixes until November 2028, security fixes until November 2029 -- Symfony 8.0 = Symfony 7.4 minus deprecations (same features, PHP 8.4 required) - -**Pre-Upgrade Status:** -- PHP version: 8.3.30 (compatible; Symfony 7.4 requires 8.2+) -- OAuth2 Server Bundle: 1.1.0 (compatible) -- Stimulus Bundle: 2.32.0 (compatible) -- Doctrine ORM: 3.6.0 (compatible) -- All 433 tests passing -- Email validation mode: Configured (html5) -- 18 test-only deprecation warnings (cosmetic, do not affect runtime) - ---- - -## Previous Plan Status - -The previous upgrade plan (dated 2025-12-06) has been updated. All pre-upgrade tasks are now complete. - -### Completed Items -| Item | Previous Status | Current Status | -|------|----------------|----------------| -| OAuth2 Server Bundle | 1.0.0 | **1.1.0 installed** | -| Stimulus Bundle | 2.31.0 | **2.32.0 installed** | -| PHP 8.2 deprecations (ParticipantDto::$touched) | Planned | **Completed** | -| Doctrine config (controller_resolver) | Planned | **Completed** | -| SecurityController null safety | Needs verification | **Completed** (uses `?->` and `??`) | -| Email validator "loose" mode deprecation | Needs fix | **Completed** (validator.yaml configured) | -| Failing test in BookingDataProcessorTest | Unrelated to upgrade | **Resolved** (test now passes) | - ---- - -## Current State Analysis - -### PHP Version Compatibility - -- **Current Runtime:** PHP 8.3.30 -- **Composer Platform:** PHP 8.3.30 -- **Symfony 7.4 Required:** PHP 8.2.0+ -- **Status:** Compatible - -### Installed Dependencies - -#### Core Symfony Packages (6.4.x) -All 33 Symfony packages currently at 6.4.x need version constraint updates to 7.4.* - -#### Third-Party Bundles - Compatible -| Package | Installed | Symfony 7.4 Compatible | -|---------|-----------|------------------------| -| `doctrine/orm` | 3.6.0 | Yes | -| `doctrine/doctrine-bundle` | 2.18.1 | Yes | -| `doctrine/doctrine-migrations-bundle` | 3.7.0 | Yes | -| `league/oauth2-server-bundle` | 1.1.0 | Yes | -| `symfony/stimulus-bundle` | 2.32.0 | Yes | -| `symfony/webpack-encore-bundle` | 2.4.0 | Yes | -| `symfony/monolog-bundle` | 3.11.0 | Yes | -| `zenstruck/schedule-bundle` | 1.9.0 | Yes | -| `league/flysystem-bundle` | 3.6.1 | Yes | -| `league/flysystem-sftp-v3` | 3.30.0 | Yes | -| `nelexa/zip` | 4.0.2 | Yes (verify post-upgrade) | -| `spatie/crypto` | 2.1.1 | Yes | -| `easycorp/easyadmin-bundle` | 4.29.1 (^4.27) | Yes | - -### Code Quality Assessment - -The codebase implements modern Symfony/PHP patterns: -- All controllers use PHP 8 attributes (`#[Route]`) -- Constructor property promotion used throughout -- Strict types enforced on all files -- Typed properties and return type declarations -- Entities use PHP 8 attributes for ORM mapping -- Modern security system (AbstractLoginFormAuthenticator) -- No deprecated annotation usage - ---- - -## Pre-Upgrade Fixes - COMPLETED - -### 1. Email Validator "loose" Mode Deprecation - DONE - -**Issue:** The default mode for `#[Assert\Email]` is "loose", which is deprecated in Symfony 6.2+ and removed in Symfony 7.0. - -**Resolution:** Framework default configured in `config/packages/validator.yaml`: - -```yaml -framework: - validation: - email_validation_mode: html5 -``` - -All Email constraints in the codebase also explicitly use `mode: 'strict'`: -- `src/Form/Model/ParticipantDto.php` - Has `mode: 'strict'` -- `src/Form/Model/RegistrationDto.php` - Has `mode: 'strict'` -- `src/BusProNet/Model/Communication.php` - Has `mode: 'strict'` -- `src/Controller/ResetPasswordController.php` - Has `mode: 'strict'` - -### 2. Test Deprecation Warnings - COSMETIC ONLY - -**Issue:** 18 deprecation warnings appear during test runs. - -**Cause:** `ParticipantEditDtoTest` creates a standalone validator using `Validation::createValidatorBuilder()` which bypasses the framework's `validator.yaml` configuration. - -**Impact:** These warnings are cosmetic and do not affect: -- Runtime behavior (all Email constraints use explicit `mode: 'strict'`) -- Symfony 7.4 compatibility (no code changes needed) -- Test results (all 433 tests pass) - -**Note:** Warnings can be silenced with `SYMFONY_DEPRECATIONS_HELPER=disabled` if desired. - ---- - -## Required Changes - -### 1. Update Composer Version Constraints - -**File:** `composer.json` - -#### Symfony Core Packages -Update all packages from `6.4.*` to `7.4.*`: - -```json -{ - "require": { - "symfony/asset": "7.4.*", - "symfony/console": "7.4.*", - "symfony/doctrine-messenger": "7.4.*", - "symfony/dom-crawler": "7.4.*", - "symfony/dotenv": "7.4.*", - "symfony/expression-language": "7.4.*", - "symfony/form": "7.4.*", - "symfony/framework-bundle": "7.4.*", - "symfony/html-sanitizer": "7.4.*", - "symfony/http-client": "7.4.*", - "symfony/intl": "7.4.*", - "symfony/lock": "7.4.*", - "symfony/mailer": "7.4.*", - "symfony/mime": "7.4.*", - "symfony/notifier": "7.4.*", - "symfony/process": "7.4.*", - "symfony/property-access": "7.4.*", - "symfony/property-info": "7.4.*", - "symfony/runtime": "7.4.*", - "symfony/security-bundle": "7.4.*", - "symfony/serializer": "7.4.*", - "symfony/string": "7.4.*", - "symfony/translation": "7.4.*", - "symfony/twig-bundle": "7.4.*", - "symfony/uid": "7.4.*", - "symfony/validator": "7.4.*", - "symfony/web-link": "7.4.*", - "symfony/yaml": "7.4.*" - } -} -``` - -#### Development Packages - -```json -{ - "require-dev": { - "symfony/browser-kit": "7.4.*", - "symfony/css-selector": "7.4.*", - "symfony/debug-bundle": "7.4.*", - "symfony/maker-bundle": "^1.0", - "symfony/phpunit-bridge": "7.4.*", - "symfony/stopwatch": "7.4.*", - "symfony/web-profiler-bundle": "7.4.*" - } -} -``` - -Keep `symfony/maker-bundle` at `^1.0` (compatible with Symfony 7.4). - -### 2. Update Symfony Flex Configuration - -**File:** `composer.json` - -```json -{ - "extra": { - "symfony": { - "allow-contrib": true, - "require": "7.4.*", - "docker": true - } - } -} -``` - ---- - -## Potential Breaking Changes - -### 1. Symfony Core Changes (Symfony 7.0 -> 7.4) - -Symfony 7.0 removed all deprecated features from 6.4. Our codebase is fully compliant: - -- **Native Return Types:** Already implemented -- **Attribute-based Configuration:** Already implemented -- **Security System:** Modern authenticator pattern in use -- **Form System:** Modern approach in use -- **No Annotation Usage:** All using PHP 8 attributes - -### 2. Email Validation Mode - -**Breaking Change:** The default `mode` for `Email` constraint changes from `loose` to `html5` in Symfony 7.0. - -**Status:** Already handled - all constraints use explicit `mode: 'strict'` and framework default is set to `html5`. - -### 3. Deprecation Cleanup - -Deprecations accumulated in Symfony 7.1-7.4 will need review: -- Check Symfony Profiler after upgrade for any new deprecation warnings -- Review [UPGRADE-7.0.md](https://github.com/symfony/symfony/blob/7.0/UPGRADE-7.0.md) -- Review [UPGRADE-7.4.md](https://github.com/symfony/symfony/blob/7.4/UPGRADE-7.4.md) - ---- - -## Upgrade Procedure - -### Phase 1: Preparation (15 minutes) - -1. **Create Feature Branch** - ```bash - git checkout -b feature/symfony-7.4-upgrade - ``` - -2. **Backup Current State** - ```bash - git tag before-symfony-7.4-upgrade - ``` - -### Phase 2: Dependency Updates (30 minutes - 1 hour) - -1. **Update composer.json** - - Update all Symfony package constraints to `7.4.*` - - Update `extra.symfony.require` to `"7.4.*"` - - Consider tightening `php` to `>=8.2` (Symfony 7.4 requires 8.2+; optional if already on 8.3) - -2. **Run Composer Update** - ```bash - ddev composer update - ``` - -3. **Review Recipe Updates** - ```bash - ddev composer recipes - ``` - Review any recipe updates from Symfony Flex and apply as needed. - -4. **Clear All Caches** - ```bash - ddev exec bin/console cache:clear - ddev exec bin/console cache:warmup - ddev exec "php -r 'opcache_reset();'" - ``` - -### Phase 3: Testing & Validation (1-2 hours) - -1. **Run PHPUnit Test Suite** - ```bash - ddev exec ./vendor/bin/phpunit - ``` - Check for: - - Test failures - - Deprecation warnings - - Fatal errors - -2. **Run PHP-CS-Fixer** - ```bash - ddev php vendor/bin/php-cs-fixer fix --dry-run --diff - ``` - -3. **Manual Testing - Critical Paths** - - [ ] User authentication (BPN API login) - - [ ] OAuth2 token generation (`/token` endpoint) - - [ ] OAuth2 authorization flow (`/authorize` endpoint) - - [ ] API endpoints (all `/api/*` routes) - - [ ] Booking creation flow (Steps 1-4) - - [ ] Participant form rendering and submission - - [ ] Dynamic field updates (HTMX) - - [ ] Real-time pricing calculations - - [ ] Insurance selection and filtering - - [ ] Transportation service selection - - [ ] Payment method selection - - [ ] Final booking submission to BPN API - - [ ] Booking edit functionality - - [ ] PDF/XML download functionality - - [ ] User registration - - [ ] Password reset - - [ ] Personal data management - - [ ] EasyAdmin CRUD / admin panels - -4. **Check Symfony Profiler** - - Review deprecation warnings (should be minimal) - - Check performance metrics - - Verify no errors in logs - -5. **Test Frontend Assets** - ```bash - npm run build - ``` - - Verify Stimulus controllers load correctly - - Test HTMX interactions - - Verify Toastify notifications - - Check TailwindCSS compilation - -6. **Verify ZIP File Functionality** - - Test any features using `nelexa/zip` (package last updated 2022) - - Verify document generation and downloads work correctly - -### Phase 4: Bug Fixes (0-2 hours) - -Address any issues discovered during testing: - -1. **Review Error Logs** - ```bash - ddev logs - ``` - -2. **Fix Any Remaining Deprecations** - - Use Symfony Profiler to identify deprecations - - Update code to use modern alternatives - -### Phase 5: Deployment (1 hour) - -1. **Deploy to Staging** - ```bash - ddev exec vendor/bin/dep deploy staging - ``` - -2. **Staging Validation** - - Full regression testing - - Performance testing - -3. **Production Deployment** - - Schedule maintenance window - - Deploy during low-traffic period - - Monitor error logs closely - ---- - -## Rollback Plan - -### Immediate Rollback - -If critical issues are discovered: - -1. **Git Revert** - ```bash - git checkout master - git reset --hard before-symfony-7.4-upgrade - ``` - -2. **Restore Dependencies** - ```bash - ddev composer install - ``` - -3. **Clear Caches** - ```bash - ddev exec bin/console cache:clear - ``` - -### Production Rollback - -If issues occur in production: - -```bash -ddev exec vendor/bin/dep rollback production -``` - ---- - -## Testing Checklist - -### Unit Tests -- [ ] All PHPUnit tests pass (433 tests) -- [ ] No new deprecation warnings -- [ ] Code coverage maintained - -### Integration Tests -- [ ] BusProNet API integration -- [ ] XML parsing and data processing -- [ ] Booking price calculations -- [ ] Insurance assignment logic -- [ ] Field handler system - -### Functional Tests -- [ ] User authentication flow -- [ ] OAuth2 token generation -- [ ] API endpoints respond correctly -- [ ] Booking creation (all steps) -- [ ] Form validation -- [ ] HTMX partial updates -- [ ] Dynamic field state changes -- [ ] Real-time pricing updates -- [ ] Toast notifications - -### Browser Testing -- [ ] Chrome (latest) -- [ ] Firefox (latest) -- [ ] Safari (latest) -- [ ] Mobile browsers - ---- - -## Timeline Estimate - -| Phase | Estimated Time | Notes | -|-------|---------------|-------| -| **Phase 1:** Preparation | 15 min | Branch creation | -| **Phase 2:** Dependency Updates | 30 min - 1 hour | composer.json updates, composer update | -| **Phase 3:** Testing & Validation | 1-2 hours | Automated + manual testing | -| **Phase 4:** Bug Fixes | 0-2 hours | Address any issues | -| **Phase 5:** Deployment | 1 hour | Staging deployment | -| **Total** | **2.5-6 hours** | Average: **3.5 hours** | - ---- - -## Future Considerations: Symfony 8.0 - -Symfony 8.0 was released alongside 7.4 (November 2025) with identical features but: -- Requires PHP 8.4 -- No deprecation layers (all deprecated code removed) -- Shorter support window (8 months) - -**Recommendation:** Stay on Symfony 7.4 LTS for stability. Plan PHP 8.4 upgrade separately, then consider Symfony 8.x path. - ---- - -## Success Criteria - -- [ ] All PHPUnit tests pass (433 tests) -- [ ] No deprecation warnings in Symfony Profiler -- [ ] All critical user flows functional -- [ ] OAuth2 authentication working -- [ ] BPN API integration operational -- [ ] Booking creation flow complete -- [ ] Frontend assets compile and load -- [ ] Performance metrics comparable or better -- [ ] No errors in production logs after 24 hours - ---- - -## Additional Resources - -### Official Symfony Documentation -- [Upgrade Major Version Guide](https://symfony.com/doc/current/setup/upgrade_major.html) -- [UPGRADE-7.0.md](https://github.com/symfony/symfony/blob/7.0/UPGRADE-7.0.md) -- [UPGRADE-7.4.md](https://github.com/symfony/symfony/blob/7.4/UPGRADE-7.4.md) -- [Symfony 7.4 Release Notes](https://symfony.com/releases/7.4) -- [Preparing for Symfony 7.4 and 8.0](https://symfony.com/blog/preparing-for-symfony-7-4-and-symfony-8-0) - -### Bundle-Specific Documentation -- [OAuth2 Server Bundle](https://github.com/thephpleague/oauth2-server-bundle) -- [Doctrine ORM 3.x Documentation](https://www.doctrine-project.org/projects/orm.html) - ---- - -**Document Version:** 7.0 -**Previous Version:** 6.0 (dated 2026-01-09) -**Last Updated:** 2026-02-23 -**Status:** Ready for Symfony 7.4 Upgrade (updated for current project state) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 00000000..aab49911 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,2 @@ +parameters: + ignoreErrors: [] diff --git a/phpstan.full.neon b/phpstan.full.neon new file mode 100644 index 00000000..70d5d58f --- /dev/null +++ b/phpstan.full.neon @@ -0,0 +1,13 @@ +includes: + - vendor/phpstan/phpstan-symfony/extension.neon + - vendor/phpstan/phpstan-doctrine/extension.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon + +parameters: + level: 6 + paths: + - src + - tests + tmpDir: var/cache/phpstan + symfony: + containerXmlPath: var/cache/dev/App_KernelDevDebugContainer.xml diff --git a/src/Admin/Field/JsonDataField.php b/src/Admin/Field/JsonDataField.php index 1df8e10c..0bc68a64 100644 --- a/src/Admin/Field/JsonDataField.php +++ b/src/Admin/Field/JsonDataField.php @@ -1,4 +1,5 @@ getAdditionalServicesForParticipantByGroup($index, Constants::TOKEN_PARKING); - if (false === empty($parkingServices)) { + if ([] !== $parkingServices) { $participantData->parking = true; $participantData->parkingService = reset($parkingServices); } else { @@ -320,7 +320,7 @@ class BookingDataProcessor // Add purchase vouchers if any exist $purchaseVouchers = $this->mappingCollector->collectPurchaseVouchers($formData); - if (false === empty($purchaseVouchers)) { + if ([] !== $purchaseVouchers) { $payload['gutscheine']['gutschein'] = []; foreach ($purchaseVouchers as $code) { $payload['gutscheine']['gutschein'][] = [ diff --git a/src/BusProNet/DataProcessor/ServiceMappingCollector.php b/src/BusProNet/DataProcessor/ServiceMappingCollector.php index 71a3deb1..932cdc84 100644 --- a/src/BusProNet/DataProcessor/ServiceMappingCollector.php +++ b/src/BusProNet/DataProcessor/ServiceMappingCollector.php @@ -43,7 +43,7 @@ class ServiceMappingCollector * Groups board, ski passes, rentals, rental insurance, courses, parking, and additional services * by service ID with their participant assignments (1-based). * - * @return array> Map of service ID to participant IDs + * @return array> Map of service ID to participant IDs */ public function collectServiceMappings(BookingDto $bookingDto): array { @@ -99,7 +99,7 @@ class ServiceMappingCollector /** * Collects transportation service mappings. * - * @return array> Map of transportation service ID to participant IDs + * @return array> Map of transportation service ID to participant IDs */ public function collectTransportationMappings(BookingDto $bookingDto): array { @@ -126,7 +126,7 @@ class ServiceMappingCollector * Collects the unified pickup selection which applies to both directions. * The API receives this as outbound pickup data. * - * @return array> Map of pickup ID to participant IDs + * @return array> Map of pickup ID to participant IDs */ public function collectPickupMappings(BookingDto $bookingDto): array { @@ -148,7 +148,7 @@ class ServiceMappingCollector * * Collects the drop-off selection for the inbound/return direction. * - * @return array> Map of drop-off ID to participant IDs + * @return array> Map of drop-off ID to participant IDs */ public function collectDropOffMappings(BookingDto $bookingDto): array { @@ -171,7 +171,7 @@ class ServiceMappingCollector * CRITICAL: Insurance data is only included in CREATE flow, not in UPDATE flow. * IMPORTANT: Excludes synthetic "no insurance" option from BPN transmission. * - * @return array> Map of insurance ID to participant IDs + * @return array> Map of insurance ID to participant IDs */ public function collectInsuranceMappings(BookingDto $bookingDto): array { diff --git a/src/BusProNet/Exception/ApiClientException.php b/src/BusProNet/Exception/ApiClientException.php index 6ce1337c..66c045c0 100644 --- a/src/BusProNet/Exception/ApiClientException.php +++ b/src/BusProNet/Exception/ApiClientException.php @@ -1,4 +1,5 @@ containedInsurances as $containedInsurance) { - if (null !== $containedInsurance->{$urlProperty}) { - $urls[] = $containedInsurance->{$urlProperty}; + $url = match ($urlProperty) { + 'urlInfo' => $containedInsurance->urlInfo, + 'urlProductInfo' => $containedInsurance->urlProductInfo, + 'urlTerms' => $containedInsurance->urlTerms, + default => null, + }; + + if (null !== $url) { + $urls[] = $url; } } diff --git a/src/BusProNet/Model/Product.php b/src/BusProNet/Model/Product.php index 8de580fa..7c18e038 100644 --- a/src/BusProNet/Model/Product.php +++ b/src/BusProNet/Model/Product.php @@ -1,4 +1,5 @@ filterXPath('//produkte/produkt') ->each(function (Crawler $node) use (&$products) { - if (false === empty($node->attr('code'))) { + $code = $node->attr('code'); + if (null !== $code && '' !== $code) { $product = new Product(); $product->id = (int) $node->attr('id'); - $product->code = (string) $node->attr('code'); + $product->code = $code; $product->name = (string) $node->attr('bezeichnung'); $products[$product->id] = $product; diff --git a/src/Command/BpnFetchTravelCommand.php b/src/Command/BpnFetchTravelCommand.php index adcaeb5d..3b814214 100644 --- a/src/Command/BpnFetchTravelCommand.php +++ b/src/Command/BpnFetchTravelCommand.php @@ -50,8 +50,11 @@ class BpnFetchTravelCommand extends Command $io = new SymfonyStyle($input, $output); $travelId = (int) $input->getArgument('travel-id'); - $filename = $input->getOption('filename') ?? sprintf('Ziel_%d.xml', $travelId); - $dryRun = $input->getOption('dry-run'); + $filenameOption = $input->getOption('filename'); + $filename = is_string($filenameOption) && '' !== $filenameOption + ? $filenameOption + : sprintf('Ziel_%d.xml', $travelId); + $dryRun = true === $input->getOption('dry-run'); $io->text(sprintf('Fetching travel data for product ID %d...', $travelId)); diff --git a/src/Command/BpnReplayCommand.php b/src/Command/BpnReplayCommand.php index e14063c6..ece2cb61 100644 --- a/src/Command/BpnReplayCommand.php +++ b/src/Command/BpnReplayCommand.php @@ -39,7 +39,14 @@ class BpnReplayCommand extends Command { $io = new SymfonyStyle($input, $output); - $filePath = $input->getArgument('file'); + $filePathArgument = $input->getArgument('file'); + if (!is_string($filePathArgument) || '' === $filePathArgument) { + $io->error('Invalid file path argument.'); + + return Command::FAILURE; + } + + $filePath = $filePathArgument; if (false === file_exists($filePath)) { $io->error(sprintf('File not found: %s', $filePath)); @@ -84,8 +91,9 @@ class BpnReplayCommand extends Command return Command::FAILURE; } - $outputFile = $input->getOption('output'); - if (null !== $outputFile) { + $outputFileOption = $input->getOption('output'); + if (is_string($outputFileOption) && '' !== $outputFileOption) { + $outputFile = $outputFileOption; if (false === file_put_contents($outputFile, $response)) { $io->error(sprintf('Failed to write response to: %s', $outputFile)); @@ -139,6 +147,8 @@ class BpnReplayCommand extends Command return $xml; } - return $doc->saveXML() ?: $xml; + $formattedXml = $doc->saveXML(); + + return false === $formattedXml ? $xml : $formattedXml; } } diff --git a/src/Command/BpnXmlSyncCommand.php b/src/Command/BpnXmlSyncCommand.php index 001c5063..05bdd589 100644 --- a/src/Command/BpnXmlSyncCommand.php +++ b/src/Command/BpnXmlSyncCommand.php @@ -65,8 +65,8 @@ class BpnXmlSyncCommand extends Command return Command::SUCCESS; } - $force = $input->getOption('force'); - $dryRun = $input->getOption('dry-run'); + $force = true === $input->getOption('force'); + $dryRun = true === $input->getOption('dry-run'); $remoteInfo = $this->readRemoteInfo(); diff --git a/src/Command/CleanupXMLDumpsCommand.php b/src/Command/CleanupXMLDumpsCommand.php index 4ab735ef..08bf671b 100644 --- a/src/Command/CleanupXMLDumpsCommand.php +++ b/src/Command/CleanupXMLDumpsCommand.php @@ -1,4 +1,5 @@ getOption('dry-run'); + $dryRun = true === $input->getOption('dry-run'); $drafts = $this->draftRepository->findBy(['bookingNumber' => null]); @@ -80,7 +80,7 @@ class DraftBackfillBookingNumberCommand extends Command continue; } - if ($dryRun) { + if (true === $dryRun) { $io->text(sprintf( '[DRY RUN] Would set booking number %d for draft %d (bookingId %d)', $bookingNumber, @@ -108,7 +108,7 @@ class DraftBackfillBookingNumberCommand extends Command ] ); - if ($dryRun) { + if (true === $dryRun) { $io->note('Dry run - no changes were made.'); } else { $io->success(sprintf('Updated %d draft(s).', $updated)); diff --git a/src/Command/DraftCleanupCommand.php b/src/Command/DraftCleanupCommand.php index 981eafe1..2a66e23a 100644 --- a/src/Command/DraftCleanupCommand.php +++ b/src/Command/DraftCleanupCommand.php @@ -38,9 +38,9 @@ class DraftCleanupCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); - $dryRun = $input->getOption('dry-run'); + $dryRun = true === $input->getOption('dry-run'); - if ($dryRun) { + if (true === $dryRun) { $expiredDrafts = $this->draftRepository->createQueryBuilder('d') ->where('d.travelDate < :today') ->setParameter('today', new \DateTimeImmutable('today')) diff --git a/src/Command/DraftInspectCommand.php b/src/Command/DraftInspectCommand.php index 9c633184..9f61666f 100644 --- a/src/Command/DraftInspectCommand.php +++ b/src/Command/DraftInspectCommand.php @@ -38,9 +38,12 @@ class DraftInspectCommand extends Command { $io = new SymfonyStyle($input, $output); - $days = $input->getOption('days'); - $bookingId = $input->getOption('booking-id'); - $shouldDelete = $input->getOption('delete'); + $daysOption = $input->getOption('days'); + $bookingIdOption = $input->getOption('booking-id'); + $shouldDelete = true === $input->getOption('delete'); + + $days = is_numeric($daysOption) ? (int) $daysOption : null; + $bookingId = is_numeric($bookingIdOption) ? (int) $bookingIdOption : null; $qb = $this->draftRepository->createQueryBuilder('d') ->join('d.user', 'u') @@ -48,14 +51,14 @@ class DraftInspectCommand extends Command ->orderBy('d.updatedAt', 'DESC'); if (null !== $days) { - $cutoffDate = new \DateTimeImmutable(sprintf('-%d days', (int) $days)); + $cutoffDate = new \DateTimeImmutable(sprintf('-%d days', $days)); $qb->andWhere('d.updatedAt < :cutoff') ->setParameter('cutoff', $cutoffDate); } if (null !== $bookingId) { $qb->andWhere('d.bookingId = :bookingId') - ->setParameter('bookingId', (int) $bookingId); + ->setParameter('bookingId', $bookingId); } $drafts = $qb->getQuery()->getResult(); @@ -97,7 +100,7 @@ class DraftInspectCommand extends Command 'Drafts are preserved when: user cancels, API rejects submission, or user simply leaves', ]); - if ($shouldDelete) { + if (true === $shouldDelete) { if (false === $io->confirm(sprintf('Are you sure you want to delete %d draft(s)?', \count($drafts)), false)) { $io->warning('Deletion cancelled.'); diff --git a/src/Command/GenerateKeysCommand.php b/src/Command/GenerateKeysCommand.php index adfebee8..d270f20c 100644 --- a/src/Command/GenerateKeysCommand.php +++ b/src/Command/GenerateKeysCommand.php @@ -1,4 +1,5 @@ json(['timestamp' => $lastUploadAt->format('Y-m-d H:i:s')]); + return $this->json(['timestamp' => $lastUploadAt?->format('Y-m-d H:i:s')]); } } diff --git a/src/Controller/Api/ProductController.php b/src/Controller/Api/ProductController.php index 086f52d8..14c1e9c7 100644 --- a/src/Controller/Api/ProductController.php +++ b/src/Controller/Api/ProductController.php @@ -1,4 +1,5 @@ sanitize($dateCode); $dateId = $this->travelDataService->mapDateCodeToId($dateCode); - $hotelId = $hotelCode ? $this->travelDataService->mapHotelCodeToId($hotelCode) : null; + $hotelId = null !== $hotelCode && '' !== $hotelCode + ? $this->travelDataService->mapHotelCodeToId($hotelCode) + : null; if (null === $dateId) { return $this->json(['message' => 'Not found'], Response::HTTP_NOT_FOUND); diff --git a/src/Controller/Api/UserinfoController.php b/src/Controller/Api/UserinfoController.php index 1e83a076..26118a7f 100644 --- a/src/Controller/Api/UserinfoController.php +++ b/src/Controller/Api/UserinfoController.php @@ -1,4 +1,5 @@ bookingSessionService->getOrCreateBaselineSnapshot($request, $bookingCreateDto); // Validate step access - allow step 1 or redirect to current step - if ($redirect = $this->validateStepAccess($bookingCreateDto, 1)) { + $redirect = $this->validateStepAccess($bookingCreateDto, 1); + if (null !== $redirect) { return $redirect; } diff --git a/src/Controller/Booking/Create/Step4Controller.php b/src/Controller/Booking/Create/Step4Controller.php index ff5057fb..b6d8208f 100644 --- a/src/Controller/Booking/Create/Step4Controller.php +++ b/src/Controller/Booking/Create/Step4Controller.php @@ -61,7 +61,8 @@ class Step4Controller extends AbstractController $bookingCreateDto = $result; // Validate step access - if ($redirect = $this->validateStepAccess($bookingCreateDto, 4)) { + $redirect = $this->validateStepAccess($bookingCreateDto, 4); + if (null !== $redirect) { return $redirect; } @@ -218,6 +219,22 @@ class Step4Controller extends AbstractController return false !== filter_var($normalizedEmail, FILTER_VALIDATE_EMAIL) ? $normalizedEmail : null; } + /** + * @param array $context + */ + private function handleApiError( + string $logMessage, + array $context, + string $flashMessage, + BookingDto $bookingCreateDto, + FormInterface $form, + ): Response { + $this->logger->error($logMessage, $context); + $this->addFlash('error', $flashMessage); + + return $this->renderStepForm($bookingCreateDto, $form); + } + /** * Clears travel data and availability cache after successful booking. */ diff --git a/src/Controller/Booking/IndexController.php b/src/Controller/Booking/IndexController.php index e51071d0..ab1dbfbe 100644 --- a/src/Controller/Booking/IndexController.php +++ b/src/Controller/Booking/IndexController.php @@ -1,4 +1,5 @@ + */ + public function getEnv(string $prefix, string $name, \Closure $getEnv): array + { + $raw = $getEnv($name); + + if (!\is_string($raw)) { + throw new RuntimeException(sprintf('The "csv_int" env var processor expects a string, got "%s" for "%s".', get_debug_type($raw), $name)); + } + + $values = array_map('trim', explode(',', $raw)); + + if ([] !== array_filter($values, static fn (string $value): bool => '' === $value)) { + throw new RuntimeException(sprintf('Environment variable "%s" contains empty values and cannot be processed as csv_int.', $name)); + } + + $integers = array_map(static function (string $value) use ($name): int { + if (1 !== preg_match('/^[+-]?\d+$/', $value)) { + throw new RuntimeException(sprintf('Environment variable "%s" contains non-integer value "%s".', $name, $value)); + } + + return (int) $value; + }, $values); + + return $integers; + } + + public static function getProvidedTypes(): array + { + return [ + 'csv_int' => 'array', + ]; + } +} diff --git a/src/Form/BookingCreateStep1Type.php b/src/Form/BookingCreateStep1Type.php index 8ad7c3c9..7baf7f63 100644 --- a/src/Form/BookingCreateStep1Type.php +++ b/src/Form/BookingCreateStep1Type.php @@ -1,4 +1,5 @@ fieldStateConditions[$fieldName]) && !empty($this->fieldStateConditions[$fieldName]); + return isset($this->fieldStateConditions[$fieldName]) && [] !== $this->fieldStateConditions[$fieldName]; } /** @@ -210,7 +210,7 @@ abstract class AbstractFieldStateProvider implements FieldStateProviderInterface foreach (array_keys($this->fieldStateConditions) as $fieldName) { $fieldState = $this->getFieldState($fieldName, $bookingDto, $participantIndex, $formData); - if (!empty($fieldState)) { + if ([] !== $fieldState) { $allStates[$fieldName] = $fieldState; } } diff --git a/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php b/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php index d296ea31..d158ef76 100644 --- a/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php +++ b/src/Form/Service/Abstract/AbstractParticipantFieldHandler.php @@ -130,7 +130,7 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle */ protected function normalizeEmptyValue(mixed $value): mixed { - return empty($value) ? null : $value; + return $this->isEmptyValue($value) ? null : $value; } /** @@ -146,13 +146,24 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle */ protected function normalizeIntValue(mixed $value): ?int { - if (empty($value)) { + if ($this->isEmptyValue($value)) { return null; } return is_numeric($value) ? (int) $value : null; } + private function isEmptyValue(mixed $value): bool + { + return null === $value + || false === $value + || 0 === $value + || 0.0 === $value + || '' === $value + || '0' === $value + || [] === $value; + } + /** * Normalizes a checkbox/form toggle value to a boolean. * diff --git a/src/Form/Service/Condition/CompositeCondition.php b/src/Form/Service/Condition/CompositeCondition.php index c93ea5dd..c72ab9e5 100644 --- a/src/Form/Service/Condition/CompositeCondition.php +++ b/src/Form/Service/Condition/CompositeCondition.php @@ -37,7 +37,7 @@ class CompositeCondition implements FieldConditionInterface private const OPERATOR_OR = 'OR'; private const OPERATOR_NOT = 'NOT'; - /** @var FieldConditionInterface[] */ + /** @var non-empty-list */ private readonly array $conditions; /** @@ -131,7 +131,7 @@ class CompositeCondition implements FieldConditionInterface */ public static function and(FieldConditionInterface ...$conditions): self { - if (empty($conditions)) { + if ([] === $conditions) { throw new \InvalidArgumentException('AND condition requires at least one condition'); } @@ -145,7 +145,7 @@ class CompositeCondition implements FieldConditionInterface */ public static function or(FieldConditionInterface ...$conditions): self { - if (empty($conditions)) { + if ([] === $conditions) { throw new \InvalidArgumentException('OR condition requires at least one condition'); } @@ -167,6 +167,8 @@ class CompositeCondition implements FieldConditionInterface * * Returns false as soon as any condition evaluates to false, * avoiding unnecessary evaluation of remaining conditions. + * + * @param array $formData */ /** @param array $formData */ private function evaluateAnd(BookingDto $bookingDto, int $participantIndex, array $formData): bool @@ -185,6 +187,8 @@ class CompositeCondition implements FieldConditionInterface * * Returns true as soon as any condition evaluates to true, * avoiding unnecessary evaluation of remaining conditions. + * + * @param array $formData */ /** @param array $formData */ private function evaluateOr(BookingDto $bookingDto, int $participantIndex, array $formData): bool @@ -200,6 +204,8 @@ class CompositeCondition implements FieldConditionInterface /** * Evaluates NOT logic by inverting the result of the single condition. + * + * @param array $formData */ /** @param array $formData */ private function evaluateNot(BookingDto $bookingDto, int $participantIndex, array $formData): bool @@ -221,6 +227,8 @@ class CompositeCondition implements FieldConditionInterface /** * Validates condition count based on operator requirements. + * + * @param list $conditions */ /** @param list $conditions */ private function validateConditionCount(string $operator, array $conditions): void diff --git a/src/Form/Service/Condition/FieldValueCondition.php b/src/Form/Service/Condition/FieldValueCondition.php index 7d6fbac3..b2a94b8c 100644 --- a/src/Form/Service/Condition/FieldValueCondition.php +++ b/src/Form/Service/Condition/FieldValueCondition.php @@ -174,6 +174,8 @@ class FieldValueCondition implements FieldConditionInterface /** * Retrieves field value from form data or participant data. + * + * @param array $formData */ /** @param array $formData */ private function getFieldValue(array $formData, int $participantIndex, BookingDto $bookingDto): mixed @@ -186,7 +188,9 @@ class FieldValueCondition implements FieldConditionInterface // Then check participant DTO data $participant = $bookingDto->getParticipant($participantIndex); if (null !== $participant && property_exists($participant, $this->fieldName)) { - return $participant->{$this->fieldName}; + $participantValues = get_object_vars($participant); + + return $participantValues[$this->fieldName] ?? null; } // Finally check booking-level form data @@ -212,6 +216,8 @@ class FieldValueCondition implements FieldConditionInterface /** * Checks if field value is in array of expected values. + * + * @param array $expectedValues */ /** @param list $expectedValues */ private function compareIn(mixed $fieldValue, array $expectedValues): bool @@ -230,7 +236,7 @@ class FieldValueCondition implements FieldConditionInterface */ private function isEmpty(mixed $value): bool { - return null === $value || '' === $value || (is_array($value) && empty($value)); + return null === $value || '' === $value || [] === $value; } /** diff --git a/src/Form/Service/Condition/RentalInsuranceAvailableCondition.php b/src/Form/Service/Condition/RentalInsuranceAvailableCondition.php index ea3cf9bf..2b72d1b0 100644 --- a/src/Form/Service/Condition/RentalInsuranceAvailableCondition.php +++ b/src/Form/Service/Condition/RentalInsuranceAvailableCondition.php @@ -33,7 +33,7 @@ class RentalInsuranceAvailableCondition implements FieldConditionInterface true ); - return false === empty($services); + return [] !== $services; } /** diff --git a/src/Form/Service/Condition/RoomSelectionCondition.php b/src/Form/Service/Condition/RoomSelectionCondition.php index 934a9f16..2010788d 100644 --- a/src/Form/Service/Condition/RoomSelectionCondition.php +++ b/src/Form/Service/Condition/RoomSelectionCondition.php @@ -31,6 +31,10 @@ class RoomSelectionCondition implements FieldConditionInterface */ public function __construct(array $requiredRoomCodes, string $matchMode = self::MATCH_MODE_PREFIX) { + if (!in_array($matchMode, [self::MATCH_MODE_PREFIX, self::MATCH_MODE_EXACT], true)) { + throw new \InvalidArgumentException(sprintf('Invalid match mode "%s".', $matchMode)); + } + $this->requiredRoomCodes = array_map('strtolower', $requiredRoomCodes); $this->matchMode = $matchMode; } diff --git a/src/Form/Service/Condition/ServiceSubTypeCondition.php b/src/Form/Service/Condition/ServiceSubTypeCondition.php index dcbb2d7b..c7dd5879 100644 --- a/src/Form/Service/Condition/ServiceSubTypeCondition.php +++ b/src/Form/Service/Condition/ServiceSubTypeCondition.php @@ -6,6 +6,7 @@ namespace App\Form\Service\Condition; use App\BusProNet\Model\Service; use App\Form\Model\BookingDto; +use App\Form\Model\ParticipantDto; use App\Form\Service\Contract\FieldConditionInterface; /** @@ -103,7 +104,7 @@ class ServiceSubTypeCondition implements FieldConditionInterface { $subTypeDescription = is_array($this->expectedSubType) ? '['.implode(', ', $this->expectedSubType).']' - : (string) $this->expectedSubType; + : $this->expectedSubType; return match ($this->operator) { self::OPERATOR_EQUALS => sprintf('Service "%s" sub-type equals %s', $this->serviceFieldName, $subTypeDescription), @@ -160,6 +161,8 @@ class ServiceSubTypeCondition implements FieldConditionInterface /** * Retrieves service from form data or participant data. + * + * @param array $formData */ /** @param array $formData */ private function getService(array $formData, int $participantIndex, BookingDto $bookingDto): ?Service @@ -176,15 +179,30 @@ class ServiceSubTypeCondition implements FieldConditionInterface // Then check participant DTO data $participant = $bookingDto->getParticipant($participantIndex); - if (null !== $participant && property_exists($participant, $this->serviceFieldName)) { - return $participant->{$this->serviceFieldName}; + if (null !== $participant) { + return $this->getServiceFromParticipant($participant); } return null; } + private function getServiceFromParticipant(ParticipantDto $participant): ?Service + { + return match ($this->serviceFieldName) { + 'skiPass' => $participant->skiPass, + 'rentalInsurance' => $participant->rentalInsurance, + 'transportationOutbound' => $participant->transportationOutbound, + 'transportationInbound' => $participant->transportationInbound, + 'veg' => $participant->veg, + 'parkingService' => $participant->parkingService, + default => null, + }; + } + /** * Checks if sub-type is in the expected array. + * + * @param string|list $expectedSubTypes */ /** @param string|list $expectedSubTypes */ private function isSubTypeIn(string $actualSubType, string|array $expectedSubTypes): bool @@ -215,6 +233,8 @@ class ServiceSubTypeCondition implements FieldConditionInterface /** * Validates expected sub-type based on operator requirements. + * + * @param string|list $expectedSubType */ /** @param string|list $expectedSubType */ private function validateExpectedSubType(string $operator, string|array $expectedSubType): void diff --git a/src/Form/Service/ParticipantFieldHandlerRegistry.php b/src/Form/Service/ParticipantFieldHandlerRegistry.php index d375b2b6..3e5bde06 100644 --- a/src/Form/Service/ParticipantFieldHandlerRegistry.php +++ b/src/Form/Service/ParticipantFieldHandlerRegistry.php @@ -274,7 +274,8 @@ class ParticipantFieldHandlerRegistry continue; } - $dtoValue = $participant->{$fieldName}; + $participantValues = get_object_vars($participant); + $dtoValue = $participantValues[$fieldName] ?? null; $submittedValue = $participantData[$fieldName]; // Check if the DTO value differs from submitted value @@ -427,7 +428,7 @@ class ParticipantFieldHandlerRegistry } // Process handlers in dependency order - while (false === empty($queue)) { + while ([] !== $queue) { $current = array_shift($queue); $result[] = $current; @@ -517,7 +518,8 @@ class ParticipantFieldHandlerRegistry // Only sync fields that were in the original submission // This prevents adding extra fields that would cause validation errors if (property_exists($participant, $fieldName) && array_key_exists($fieldName, $participantData)) { - $dtoValue = $participant->{$fieldName}; + $participantValues = get_object_vars($participant); + $dtoValue = $participantValues[$fieldName] ?? null; $participantData[$fieldName] = $this->convertDtoValueToSubmittedFormat($dtoValue); } } diff --git a/src/Form/Service/ParticipantParkingFieldHandler.php b/src/Form/Service/ParticipantParkingFieldHandler.php index 11f05f36..a570a537 100644 --- a/src/Form/Service/ParticipantParkingFieldHandler.php +++ b/src/Form/Service/ParticipantParkingFieldHandler.php @@ -126,7 +126,7 @@ class ParticipantParkingFieldHandler extends AbstractParticipantFieldHandler Constants::TOKEN_PARKING ); - if (empty($parkingServices)) { + if ([] === $parkingServices) { return null; } diff --git a/src/Form/StepSelectChoiceType.php b/src/Form/StepSelectChoiceType.php index 845a6c6c..1cf6e80e 100644 --- a/src/Form/StepSelectChoiceType.php +++ b/src/Form/StepSelectChoiceType.php @@ -1,4 +1,5 @@ resolvePersonId($personNode, (int) $index); + $personId = $this->resolvePersonId($personNode, $index); $identity = $this->getOrCreateIdentity($personId); $this->replaceNameFields($personNode, $identity); @@ -96,7 +96,7 @@ class BpnXmlAnonymizer } if (true === $personNode->hasAttribute('id')) { - $attributeValue = trim((string) $personNode->getAttribute('id')); + $attributeValue = trim($personNode->getAttribute('id')); if ('' !== $attributeValue) { return sprintf('attr-id:%s', $attributeValue); } @@ -115,7 +115,7 @@ class BpnXmlAnonymizer $nameValues[] = trim($nameNode->textContent); } if (true === $personNode->hasAttribute('name')) { - $nameValues[] = trim((string) $personNode->getAttribute('name')); + $nameValues[] = trim($personNode->getAttribute('name')); } $firstNameNode = $this->getDirectChild($personNode, 'vorname'); @@ -123,7 +123,7 @@ class BpnXmlAnonymizer $nameValues[] = trim($firstNameNode->textContent); } if (true === $personNode->hasAttribute('vorname')) { - $nameValues[] = trim((string) $personNode->getAttribute('vorname')); + $nameValues[] = trim($personNode->getAttribute('vorname')); } $communicationNode = $this->getDirectChild($personNode, 'kommunikation'); diff --git a/src/Service/InsuranceManager.php b/src/Service/InsuranceManager.php index 1ce2042c..089931a2 100644 --- a/src/Service/InsuranceManager.php +++ b/src/Service/InsuranceManager.php @@ -136,7 +136,7 @@ class InsuranceManager $eligibleInsurances = $this->getEligibleInsurances($sameTypeInsurances, $participant, $booking, $travelPrice); // Return the first eligible insurance (they should all be equivalent for the same type) - return !empty($eligibleInsurances) ? array_values($eligibleInsurances)[0] : null; + return [] !== $eligibleInsurances ? array_values($eligibleInsurances)[0] : null; } /** @@ -168,7 +168,7 @@ class InsuranceManager foreach ($booking->getParticipants() as $index => $participant) { $travelPrice = $participantPrices[$index] ?? 0.0; $eligibleInsurances = $this->getEligibleInsurances($sameTypeInsurances, $participant, $booking, $travelPrice); - $assignments[$index] = !empty($eligibleInsurances) ? array_values($eligibleInsurances)[0] : null; + $assignments[$index] = [] !== $eligibleInsurances ? array_values($eligibleInsurances)[0] : null; } return $assignments; diff --git a/src/Service/ParticipantEligibilityChecker.php b/src/Service/ParticipantEligibilityChecker.php index 9ea7e260..5a5d9a52 100644 --- a/src/Service/ParticipantEligibilityChecker.php +++ b/src/Service/ParticipantEligibilityChecker.php @@ -70,7 +70,7 @@ class ParticipantEligibilityChecker fn (Service $service) => $this->isSkiPassAvailableForParticipant($service, $bookingDto, $participantIndex) ); - return !empty($availableSkiPasses); + return [] !== $availableSkiPasses; })(); } diff --git a/src/Twig/AppRuntime.php b/src/Twig/AppRuntime.php index b0ded76d..e7aad5f4 100644 --- a/src/Twig/AppRuntime.php +++ b/src/Twig/AppRuntime.php @@ -282,6 +282,14 @@ class AppRuntime implements RuntimeExtensionInterface ); } + private function renderIcon(Environment $environment, string $icon, ?string $classes): string + { + return $environment->render('_partials/_icon.html.twig', [ + 'icon' => $icon, + 'class' => $classes ?? 'w-4 h-4', + ]); + } + /** * Gets the appropriate field state provider based on booking mode. * diff --git a/src/Validator/Constraints/MandatoryAdditionalServicesSelectedValidator.php b/src/Validator/Constraints/MandatoryAdditionalServicesSelectedValidator.php index e0133a4f..1f90995d 100644 --- a/src/Validator/Constraints/MandatoryAdditionalServicesSelectedValidator.php +++ b/src/Validator/Constraints/MandatoryAdditionalServicesSelectedValidator.php @@ -63,7 +63,7 @@ class MandatoryAdditionalServicesSelectedValidator extends ConstraintValidator } ); - if (true === empty($mandatoryAdditionalServices)) { + if ([] === $mandatoryAdditionalServices) { return; } diff --git a/src/Validator/Constraints/ParticipantValidator.php b/src/Validator/Constraints/ParticipantValidator.php index add6eb63..1834542d 100644 --- a/src/Validator/Constraints/ParticipantValidator.php +++ b/src/Validator/Constraints/ParticipantValidator.php @@ -67,7 +67,7 @@ class ParticipantValidator extends ConstraintValidator public function assertBodyDimensionsWhenRentalsSelected(ParticipantDto $participant): void { // Check if any rental services are selected - if (true === empty($participant->rentals)) { + if ([] === $participant->rentals) { return; } diff --git a/tests/BusProNet/ApiClientReceiveTest.php b/tests/BusProNet/ApiClientReceiveTest.php index ae5bdeab..c0fbab85 100644 --- a/tests/BusProNet/ApiClientReceiveTest.php +++ b/tests/BusProNet/ApiClientReceiveTest.php @@ -65,6 +65,9 @@ class ApiClientReceiveTest extends TestCase self::assertSame('0000000005Hello', $result); } + /** + * @param resource $socket + */ private function invokeReceive($socket): string { $method = new \ReflectionMethod(ApiClient::class, 'receive'); diff --git a/tests/BusProNet/DataLoader/HotelDataLoaderTest.php b/tests/BusProNet/DataLoader/HotelDataLoaderTest.php index 694eed25..a38ea5da 100644 --- a/tests/BusProNet/DataLoader/HotelDataLoaderTest.php +++ b/tests/BusProNet/DataLoader/HotelDataLoaderTest.php @@ -27,7 +27,7 @@ class HotelDataLoaderTest extends TestCase '; $filesystem = $this->createMock(FilesystemOperator::class); - $filesystem->expects($this->once()) + $filesystem->expects(self::once()) ->method('read') ->with('hotel.xml') ->willReturn($xmlContent); @@ -37,17 +37,17 @@ class HotelDataLoaderTest extends TestCase $hotels = $loader->loadAll(); - $this->assertIsArray($hotels); - $this->assertArrayHasKey(163113, $hotels); + self::assertIsArray($hotels); + self::assertArrayHasKey(163113, $hotels); $hotel = $hotels[163113]; - $this->assertInstanceOf(Hotel::class, $hotel); - $this->assertEquals(163113, $hotel->id); - $this->assertEquals('L\'Oxalys', $hotel->name); - $this->assertEquals('SBWOXA', $hotel->code); - $this->assertEquals('Val Thorens', $hotel->city); - $this->assertEquals('F', $hotel->country); - $this->assertEquals('Rue des Lacs', $hotel->street); - $this->assertEquals('', $hotel->phone); + self::assertInstanceOf(Hotel::class, $hotel); + self::assertEquals(163113, $hotel->id); + self::assertEquals('L\'Oxalys', $hotel->name); + self::assertEquals('SBWOXA', $hotel->code); + self::assertEquals('Val Thorens', $hotel->city); + self::assertEquals('F', $hotel->country); + self::assertEquals('Rue des Lacs', $hotel->street); + self::assertEquals('', $hotel->phone); } } diff --git a/tests/BusProNet/DataLoader/PickupDataLoaderTest.php b/tests/BusProNet/DataLoader/PickupDataLoaderTest.php index 450afef0..c65091d0 100644 --- a/tests/BusProNet/DataLoader/PickupDataLoaderTest.php +++ b/tests/BusProNet/DataLoader/PickupDataLoaderTest.php @@ -27,7 +27,7 @@ class PickupDataLoaderTest extends TestCase '; $filesystem = $this->createMock(FilesystemOperator::class); - $filesystem->expects($this->once()) + $filesystem->expects(self::once()) ->method('read') ->with('zustiege.xml') ->willReturn($xmlContent); @@ -37,11 +37,11 @@ class PickupDataLoaderTest extends TestCase $pickup = $loader->loadById(1); - $this->assertInstanceOf(Pickup::class, $pickup); - $this->assertEquals(1, $pickup->id); - $this->assertEquals('MS-Hbf', $pickup->code); - $this->assertEquals('Münster', $pickup->city); - $this->assertEquals('48143', $pickup->postalCode); - $this->assertEquals('Hafenstr/Ecke Friedrich-Ebert-Str', $pickup->street); + self::assertInstanceOf(Pickup::class, $pickup); + self::assertEquals(1, $pickup->id); + self::assertEquals('MS-Hbf', $pickup->code); + self::assertEquals('Münster', $pickup->city); + self::assertEquals('48143', $pickup->postalCode); + self::assertEquals('Hafenstr/Ecke Friedrich-Ebert-Str', $pickup->street); } } diff --git a/tests/BusProNet/DataLoader/TravelDataLoaderTest.php b/tests/BusProNet/DataLoader/TravelDataLoaderTest.php index ea546093..e23fe8ab 100644 --- a/tests/BusProNet/DataLoader/TravelDataLoaderTest.php +++ b/tests/BusProNet/DataLoader/TravelDataLoaderTest.php @@ -29,7 +29,7 @@ class TravelDataLoaderTest extends TestCase '; $filesystem = $this->createMock(FilesystemOperator::class); - $filesystem->expects($this->once()) + $filesystem->expects(self::once()) ->method('read') ->with('test_file.xml') ->willReturn($xmlContent); @@ -45,7 +45,7 @@ class TravelDataLoaderTest extends TestCase $expectedTravel->label = 'Davos - Sportclub Waldschlössli'; $expectedTravel->priceFrom = 534.2; - $travelParser->expects($this->once()) + $travelParser->expects(self::once()) ->method('parse') ->willReturn($expectedTravel); @@ -54,12 +54,12 @@ class TravelDataLoaderTest extends TestCase $travel = $loader->loadById(11478, null, 'test_file.xml'); - $this->assertInstanceOf(Travel::class, $travel); - $this->assertEquals('DPWMP060125', $travel->code); - $this->assertEquals('F', $travel->type); - $this->assertInstanceOf(\DateTimeImmutable::class, $travel->dateFrom); - $this->assertInstanceOf(\DateTimeImmutable::class, $travel->dateTo); - $this->assertEquals('Davos - Sportclub Waldschlössli', $travel->label); - $this->assertEquals(534.2, $travel->priceFrom); + self::assertInstanceOf(Travel::class, $travel); + self::assertEquals('DPWMP060125', $travel->code); + self::assertEquals('F', $travel->type); + self::assertInstanceOf(\DateTimeImmutable::class, $travel->dateFrom); + self::assertInstanceOf(\DateTimeImmutable::class, $travel->dateTo); + self::assertEquals('Davos - Sportclub Waldschlössli', $travel->label); + self::assertEquals(534.2, $travel->priceFrom); } } diff --git a/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php b/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php index 08efcf30..d3ccccd4 100644 --- a/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php +++ b/tests/BusProNet/DataProcessor/BookingDataProcessorTest.php @@ -71,16 +71,16 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertIsArray($result); - $this->assertArrayHasKey('idbuchung', $result); - $this->assertArrayHasKey('teilnehmerliste', $result); - $this->assertArrayHasKey('zusatzleistungen', $result); - $this->assertArrayHasKey('beförderungen', $result); - $this->assertArrayHasKey('ferienzielunterbringungen', $result); + self::assertIsArray($result); + self::assertArrayHasKey('idbuchung', $result); + self::assertArrayHasKey('teilnehmerliste', $result); + self::assertArrayHasKey('zusatzleistungen', $result); + self::assertArrayHasKey('beförderungen', $result); + self::assertArrayHasKey('ferienzielunterbringungen', $result); - $this->assertEquals(123, $result['idbuchung']); - $this->assertEquals('ACTIVE', $result['status']); - $this->assertCount(2, $result['teilnehmerliste']['teilnehmer']); + self::assertEquals(123, $result['idbuchung']); + self::assertEquals('ACTIVE', $result['status']); + self::assertCount(2, $result['teilnehmerliste']['teilnehmer']); } public function testCanceledParticipantsAreSkipped(): void @@ -89,9 +89,9 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertCount(2, $result['teilnehmerliste']['teilnehmer']); - $this->assertEquals(1, $result['teilnehmerliste']['teilnehmer'][0]['@id']); - $this->assertEquals(2, $result['teilnehmerliste']['teilnehmer'][1]['@id']); + self::assertCount(2, $result['teilnehmerliste']['teilnehmer']); + self::assertEquals(1, $result['teilnehmerliste']['teilnehmer'][0]['@id']); + self::assertEquals(2, $result['teilnehmerliste']['teilnehmer'][1]['@id']); } public function testAdditionalServicesProcessing(): void @@ -100,13 +100,13 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertNotEmpty($result['zusatzleistungen']['zusatzleistung']); - $this->assertCount(2, $result['zusatzleistungen']['zusatzleistung']); + self::assertNotEmpty($result['zusatzleistungen']['zusatzleistung']); + self::assertCount(2, $result['zusatzleistungen']['zusatzleistung']); $service = $result['zusatzleistungen']['zusatzleistung'][0]; - $this->assertEquals(1, $service['@idleistung']); - $this->assertEquals(1, $service['@anzahl']); - $this->assertEquals('1', $service['@zuordnung']); + self::assertEquals(1, $service['@idleistung']); + self::assertEquals(1, $service['@anzahl']); + self::assertEquals('1', $service['@zuordnung']); } public function testTransportationServicesProcessing(): void @@ -115,8 +115,8 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertNotEmpty($result['beförderungen']['beförderung']); - $this->assertCount(2, $result['beförderungen']['beförderung']); + self::assertNotEmpty($result['beförderungen']['beförderung']); + self::assertCount(2, $result['beförderungen']['beförderung']); } public function testBusPickupLocationsProcessing(): void @@ -125,9 +125,9 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertArrayHasKey('zustiege', $result); - $this->assertNotEmpty($result['zustiege']['zustieg']); - $this->assertEquals(1, $result['zustiege']['zustieg'][0]['@idzustieg']); + self::assertArrayHasKey('zustiege', $result); + self::assertNotEmpty($result['zustiege']['zustieg']); + self::assertEquals(1, $result['zustiege']['zustieg'][0]['@idzustieg']); } public function testNonBusTransportationSkipsPickup(): void @@ -136,8 +136,8 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertArrayHasKey('zustiege', $result); - $this->assertSame([], $result['zustiege']); + self::assertArrayHasKey('zustiege', $result); + self::assertSame([], $result['zustiege']); } public function testUnusedServicesAreRemoved(): void @@ -146,8 +146,8 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertEmpty($result['zusatzleistungen']['zusatzleistung']); - $this->assertEmpty($result['beförderungen']['beförderung']); + self::assertEmpty($result['zusatzleistungen']['zusatzleistung']); + self::assertEmpty($result['beförderungen']['beförderung']); } public function testParticipantPersonalDataUpdate(): void @@ -157,10 +157,10 @@ class BookingDataProcessorTest extends TestCase $this->processor->createUpdateRequestPayload($formData); $participant = $formData->booking->participants[0]; - $this->assertEquals('Updated', $participant->firstName); - $this->assertEquals('Participant', $participant->name); - $this->assertEquals('test@example.com', $participant->communication->email); - $this->assertEquals('+49123456789', $participant->communication->mobile); + self::assertEquals('Updated', $participant->firstName); + self::assertEquals('Participant', $participant->name); + self::assertEquals('test@example.com', $participant->communication->email); + self::assertEquals('+49123456789', $participant->communication->mobile); } public function testCanceledParticipantsPersonalDataIsUpdated(): void @@ -170,8 +170,8 @@ class BookingDataProcessorTest extends TestCase $this->processor->createUpdateRequestPayload($formData); $participant = $formData->booking->participants[0]; - $this->assertEquals('Updated', $participant->firstName); - $this->assertEquals('Participant', $participant->name); + self::assertEquals('Updated', $participant->firstName); + self::assertEquals('Participant', $participant->name); } public function testApplicantDataSyncWithFirstParticipant(): void @@ -183,9 +183,9 @@ class BookingDataProcessorTest extends TestCase $applicant = $formData->booking->applicant; $firstParticipant = $formData->booking->participants[0]; - $this->assertEquals($firstParticipant->height, $applicant->height); - $this->assertEquals($firstParticipant->weight, $applicant->weight); - $this->assertEquals($firstParticipant->shoeSize, $applicant->shoeSize); + self::assertEquals($firstParticipant->height, $applicant->height); + self::assertEquals($firstParticipant->weight, $applicant->weight); + self::assertEquals($firstParticipant->shoeSize, $applicant->shoeSize); } public function testBankAccountIncludedInPayload(): void @@ -194,9 +194,9 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertArrayHasKey('bankverbindung', $result['zahlung']); - $this->assertEquals('Test Bank', $result['zahlung']['bankverbindung']['@kreditinstitut']); - $this->assertEquals('DE89370400440532013000', $result['zahlung']['bankverbindung']['@iban']); + self::assertArrayHasKey('bankverbindung', $result['zahlung']); + self::assertEquals('Test Bank', $result['zahlung']['bankverbindung']['@kreditinstitut']); + self::assertEquals('DE89370400440532013000', $result['zahlung']['bankverbindung']['@iban']); } public function testBankAccountNotIncludedWhenNull(): void @@ -205,7 +205,7 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertArrayNotHasKey('bankverbindung', $result['zahlung']); + self::assertArrayNotHasKey('bankverbindung', $result['zahlung']); } public function testAccommodationRoomsProcessing(): void @@ -214,13 +214,13 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertNotEmpty($result['ferienzielunterbringungen']['ferienzielunterbringung']); + self::assertNotEmpty($result['ferienzielunterbringungen']['ferienzielunterbringung']); $room = $result['ferienzielunterbringungen']['ferienzielunterbringung'][0]; - $this->assertEquals(1, $room['@idzimmer']); - $this->assertEquals('DOUBLE', $room['@kategorie']); - $this->assertEquals('01.01.2024', $room['@anreise']); - $this->assertEquals('07.01.2024', $room['@abreise']); + self::assertEquals(1, $room['@idzimmer']); + self::assertEquals('DOUBLE', $room['@kategorie']); + self::assertEquals('01.01.2024', $room['@anreise']); + self::assertEquals('07.01.2024', $room['@abreise']); } public function testCommunicationObjectCreation(): void @@ -230,8 +230,8 @@ class BookingDataProcessorTest extends TestCase $this->processor->createUpdateRequestPayload($formData); $participant = $formData->booking->participants[0]; - $this->assertInstanceOf(Communication::class, $participant->communication); - $this->assertEquals('new@example.com', $participant->communication->email); + self::assertInstanceOf(Communication::class, $participant->communication); + self::assertEquals('new@example.com', $participant->communication->email); } public function testEmptyPickupsToDoesNotCreateZustiegeSection(): void @@ -240,8 +240,8 @@ class BookingDataProcessorTest extends TestCase $result = $this->processor->createUpdateRequestPayload($formData); - $this->assertArrayHasKey('zustiege', $result); - $this->assertSame([], $result['zustiege']); + self::assertArrayHasKey('zustiege', $result); + self::assertSame([], $result['zustiege']); } private function createCompleteFormData(): BookingDto @@ -543,13 +543,13 @@ class BookingDataProcessorTest extends TestCase // Canceled participant (index 1) should have default names filled $canceledParticipant = $formData->booking->participants[1]; - $this->assertEquals('Teilnehmer:in 2', $canceledParticipant->firstName); - $this->assertEquals('Teilnehmer:in 2', $canceledParticipant->name); + self::assertEquals('Teilnehmer:in 2', $canceledParticipant->firstName); + self::assertEquals('Teilnehmer:in 2', $canceledParticipant->name); // Active participant (index 0) should retain original names from form $activeParticipant = $formData->booking->participants[0]; - $this->assertEquals('Participant0', $activeParticipant->firstName); - $this->assertEquals('LastName', $activeParticipant->name); + self::assertEquals('Participant0', $activeParticipant->firstName); + self::assertEquals('LastName', $activeParticipant->name); } public function testCanceledParticipantNamesNotFilledForNonAgencyBooking(): void @@ -560,8 +560,8 @@ class BookingDataProcessorTest extends TestCase // Canceled participant should retain empty names (non-agency booking) $canceledParticipant = $formData->booking->participants[1]; - $this->assertEquals('', $canceledParticipant->firstName); - $this->assertEquals('', $canceledParticipant->name); + self::assertEquals('', $canceledParticipant->firstName); + self::assertEquals('', $canceledParticipant->name); } public function testConfirmedParticipantEmptyNamesFilledForAgencyBooking(): void @@ -572,13 +572,13 @@ class BookingDataProcessorTest extends TestCase // Confirmed participant (index 1) with empty names should have default names filled $participant = $formData->booking->participants[1]; - $this->assertEquals('Teilnehmer:in 2', $participant->firstName); - $this->assertEquals('Teilnehmer:in 2', $participant->name); + self::assertEquals('Teilnehmer:in 2', $participant->firstName); + self::assertEquals('Teilnehmer:in 2', $participant->name); // Active participant (index 0) should retain original names from form $activeParticipant = $formData->booking->participants[0]; - $this->assertEquals('Participant0', $activeParticipant->firstName); - $this->assertEquals('LastName', $activeParticipant->name); + self::assertEquals('Participant0', $activeParticipant->firstName); + self::assertEquals('LastName', $activeParticipant->name); } public function testConfirmedParticipantPartialEmptyNameFilledForAgencyBooking(): void @@ -589,8 +589,8 @@ class BookingDataProcessorTest extends TestCase // Participant with lastName but empty firstName should get default firstName only $participant = $formData->booking->participants[1]; - $this->assertEquals('Teilnehmer:in 2', $participant->firstName); - $this->assertEquals('Schnekenburger', $participant->name); + self::assertEquals('Teilnehmer:in 2', $participant->firstName); + self::assertEquals('Schnekenburger', $participant->name); } private function createFormDataWithConfirmedParticipantEmptyNames(): BookingDto diff --git a/tests/BusProNet/Model/BookingTest.php b/tests/BusProNet/Model/BookingTest.php index 5e587755..94fe883d 100644 --- a/tests/BusProNet/Model/BookingTest.php +++ b/tests/BusProNet/Model/BookingTest.php @@ -34,16 +34,16 @@ class BookingTest extends TestCase // Test: participant 0 should get the ski pass $result = $booking->getSkiPassForParticipant(0); - $this->assertSame($skiPassService, $result); - $this->assertEquals(123, $result->id); + self::assertSame($skiPassService, $result); + self::assertEquals(123, $result->id); // Test: participant 1 should get null (no ski pass assigned) $result = $booking->getSkiPassForParticipant(1); - $this->assertNull($result); + self::assertNull($result); // Test: participant 2 should get the ski pass $result = $booking->getSkiPassForParticipant(2); - $this->assertSame($skiPassService, $result); + self::assertSame($skiPassService, $result); } public function testGetSkiPassForParticipantReturnsNullWhenNoSkiPasses(): void @@ -59,7 +59,7 @@ class BookingTest extends TestCase $booking->additionalServices = [456 => $otherService]; $result = $booking->getSkiPassForParticipant(0); - $this->assertNull($result); + self::assertNull($result); } public function testGetSkiPassForParticipantReturnsNullWhenNoServices(): void @@ -68,7 +68,7 @@ class BookingTest extends TestCase $booking->additionalServices = []; $result = $booking->getSkiPassForParticipant(0); - $this->assertNull($result); + self::assertNull($result); } public function testGetInsuranceForParticipantReturnsCorrectInsurance(): void @@ -94,21 +94,21 @@ class BookingTest extends TestCase // Test: participant 0 should get insurance1 $result = $booking->getInsuranceForParticipant(0); - $this->assertSame($insurance1, $result); - $this->assertEquals(100, $result->id); + self::assertSame($insurance1, $result); + self::assertEquals(100, $result->id); // Test: participant 1 should get insurance2 $result = $booking->getInsuranceForParticipant(1); - $this->assertSame($insurance2, $result); - $this->assertEquals(200, $result->id); + self::assertSame($insurance2, $result); + self::assertEquals(200, $result->id); // Test: participant 2 should get insurance1 $result = $booking->getInsuranceForParticipant(2); - $this->assertSame($insurance1, $result); + self::assertSame($insurance1, $result); // Test: participant 3 should get null (no insurance assigned) $result = $booking->getInsuranceForParticipant(3); - $this->assertNull($result); + self::assertNull($result); } public function testGetInsuranceForParticipantReturnsNullWhenNoInsurances(): void @@ -117,7 +117,7 @@ class BookingTest extends TestCase $booking->insurances = []; $result = $booking->getInsuranceForParticipant(0); - $this->assertNull($result); + self::assertNull($result); } public function testGetInsuranceForParticipantHandlesEmptyMapping(): void @@ -133,6 +133,6 @@ class BookingTest extends TestCase $booking->insurances = [100 => $insurance]; $result = $booking->getInsuranceForParticipant(0); - $this->assertNull($result, 'Should return null when mapping is empty'); + self::assertNull($result, 'Should return null when mapping is empty'); } } diff --git a/tests/BusProNet/Model/TravelTest.php b/tests/BusProNet/Model/TravelTest.php index 6da2bfba..ad8a4e99 100644 --- a/tests/BusProNet/Model/TravelTest.php +++ b/tests/BusProNet/Model/TravelTest.php @@ -41,12 +41,12 @@ class TravelTest extends TestCase $travel->transportationServices = [$outboundPkw, $inboundPkw]; $outboundResult = $travel->getTransportationServicesByDirection('HIN'); - $this->assertCount(1, $outboundResult); - $this->assertSame($outboundPkw, $outboundResult[0]); + self::assertCount(1, $outboundResult); + self::assertSame($outboundPkw, $outboundResult[0]); $inboundResult = $travel->getTransportationServicesByDirection('RUECK'); - $this->assertCount(1, $inboundResult); - $this->assertSame($inboundPkw, $inboundResult[0]); + self::assertCount(1, $inboundResult); + self::assertSame($inboundPkw, $inboundResult[0]); } /** @@ -77,7 +77,7 @@ class TravelTest extends TestCase $result = $travel->getTransportationServicesByDirection('HIN'); // Both PKW services should be returned (filtering happens at field options provider level) - $this->assertCount(2, $result); + self::assertCount(2, $result); } /** @@ -104,9 +104,9 @@ class TravelTest extends TestCase $result = $travel->getTransportationServicesByDirection('HIN'); - $this->assertCount(2, $result); + self::assertCount(2, $result); // BUS comes before PKW alphabetically - $this->assertSame('BUS', $result[0]->subType); - $this->assertSame('PKW', $result[1]->subType); + self::assertSame('BUS', $result[0]->subType); + self::assertSame('PKW', $result[1]->subType); } } diff --git a/tests/BusProNet/Utility/DayTimeUtilityTest.php b/tests/BusProNet/Utility/DayTimeUtilityTest.php index 8cc95987..c1433c7b 100644 --- a/tests/BusProNet/Utility/DayTimeUtilityTest.php +++ b/tests/BusProNet/Utility/DayTimeUtilityTest.php @@ -15,9 +15,12 @@ class DayTimeUtilityTest extends TestCase $utility = new DayTimeUtility(); $result = $utility->mapTime($time); - $this->assertEquals($dayTime, $result); + self::assertEquals($dayTime, $result); } + /** + * @return array + */ public function dayTimeProvider(): array { return [ diff --git a/tests/BusProNet/Utility/TravelCodeUtilityTest.php b/tests/BusProNet/Utility/TravelCodeUtilityTest.php index b5581cc5..827530b0 100644 --- a/tests/BusProNet/Utility/TravelCodeUtilityTest.php +++ b/tests/BusProNet/Utility/TravelCodeUtilityTest.php @@ -13,15 +13,15 @@ class TravelCodeUtilityTest extends TestCase $travelCode = 'ABCDEF/010125'; $sanitized = $utility->sanitize($travelCode); - $this->assertEquals('ABCDEF010125', $sanitized); + self::assertEquals('ABCDEF010125', $sanitized); $travelCode = 'ABCDEF-010125'; $sanitized = $utility->sanitize($travelCode); - $this->assertEquals('ABCDEF010125', $sanitized); + self::assertEquals('ABCDEF010125', $sanitized); $travelCode = 'abcdef/010125'; $sanitized = $utility->sanitize($travelCode); - $this->assertEquals('ABCDEF010125', $sanitized); + self::assertEquals('ABCDEF010125', $sanitized); } public function testGetBaseCode(): void @@ -30,11 +30,11 @@ class TravelCodeUtilityTest extends TestCase $travelCode = 'ABCDEF010125'; $baseCode = $utility->getBaseCode($travelCode); - $this->assertEquals('ABCDEF', $baseCode); + self::assertEquals('ABCDEF', $baseCode); $travelCode = 'abcdef010125'; $baseCode = $utility->getBaseCode($travelCode); - $this->assertEquals('ABCDEF', $baseCode); + self::assertEquals('ABCDEF', $baseCode); } public function testGetDate(): void @@ -43,6 +43,6 @@ class TravelCodeUtilityTest extends TestCase $travelCode = 'ABCDEF010125'; $date = $utility->getDate($travelCode); - $this->assertEquals('2025-01-01', $date->format('Y-m-d')); + self::assertEquals('2025-01-01', $date->format('Y-m-d')); } } diff --git a/tests/BusProNet/XmlLoader/PickupLoaderTest.php b/tests/BusProNet/XmlLoader/PickupLoaderTest.php index 74afc5b9..9021b32d 100644 --- a/tests/BusProNet/XmlLoader/PickupLoaderTest.php +++ b/tests/BusProNet/XmlLoader/PickupLoaderTest.php @@ -61,10 +61,10 @@ class PickupLoaderTest extends TestCase $this->loader->patchPickupsDetails($travel); // Pickups should be sorted chronologically: 10, 20, 30 - $this->assertSame([10, 20, 30], array_keys($travel->pickups)); + self::assertSame([10, 20, 30], array_keys($travel->pickups)); // Drop-offs should be in reverse order: 30, 20, 10 - $this->assertSame([30, 20, 10], array_keys($travel->dropOffs)); + self::assertSame([30, 20, 10], array_keys($travel->dropOffs)); } public function testDropOffsNotInPickupsAreAppendedAtEnd(): void @@ -94,7 +94,7 @@ class PickupLoaderTest extends TestCase $this->loader->patchPickupsDetails($travel); // Drop-offs: reversed pickups (20, 10), then unmatched (99) - $this->assertSame([20, 10, 99], array_keys($travel->dropOffs)); + self::assertSame([20, 10, 99], array_keys($travel->dropOffs)); } public function testDropOffsWithTimeDataAreSortedChronologically(): void @@ -133,6 +133,6 @@ class PickupLoaderTest extends TestCase $this->loader->patchPickupsDetails($travel); // Drop-offs should be sorted by time, not by reversed pickup order - $this->assertSame([30, 20, 10], array_keys($travel->dropOffs)); + self::assertSame([30, 20, 10], array_keys($travel->dropOffs)); } } diff --git a/tests/BusProNet/XmlParser/AgencyParserTest.php b/tests/BusProNet/XmlParser/AgencyParserTest.php index 83533161..67a2628a 100644 --- a/tests/BusProNet/XmlParser/AgencyParserTest.php +++ b/tests/BusProNet/XmlParser/AgencyParserTest.php @@ -45,25 +45,25 @@ class AgencyParserTest extends TestCase $resultNode = $crawler->filterXPath('//ergebnis'); $agencies = $this->parser->parse($resultNode); - $this->assertCount(2, $agencies); + self::assertCount(2, $agencies); // Test first agency (complete data) - $this->assertEquals(124487, $agencies[0]->id); - $this->assertEquals('ADAC Hansa e.V.', $agencies[0]->name); - $this->assertEquals('295', $agencies[0]->code); - $this->assertEquals('Musterstr. 123', $agencies[0]->street); - $this->assertEquals('99999', $agencies[0]->postCode); - $this->assertEquals('Musterort', $agencies[0]->city); - $this->assertEquals('0361-442930', $agencies[0]->phone); + self::assertEquals(124487, $agencies[0]->id); + self::assertEquals('ADAC Hansa e.V.', $agencies[0]->name); + self::assertEquals('295', $agencies[0]->code); + self::assertEquals('Musterstr. 123', $agencies[0]->street); + self::assertEquals('99999', $agencies[0]->postCode); + self::assertEquals('Musterort', $agencies[0]->city); + self::assertEquals('0361-442930', $agencies[0]->phone); // Test second agency (missing phone) - $this->assertEquals(75861, $agencies[1]->id); - $this->assertEquals('ADAC im Fördepark', $agencies[1]->name); - $this->assertEquals('103', $agencies[1]->code); - $this->assertEquals('Sebastianusstr. 24', $agencies[1]->street); - $this->assertEquals('41468', $agencies[1]->postCode); - $this->assertEquals('Neuss', $agencies[1]->city); - $this->assertNull($agencies[1]->phone); + self::assertEquals(75861, $agencies[1]->id); + self::assertEquals('ADAC im Fördepark', $agencies[1]->name); + self::assertEquals('103', $agencies[1]->code); + self::assertEquals('Sebastianusstr. 24', $agencies[1]->street); + self::assertEquals('41468', $agencies[1]->postCode); + self::assertEquals('Neuss', $agencies[1]->city); + self::assertNull($agencies[1]->phone); } public function testParseMinimalAgency(): void @@ -83,14 +83,14 @@ class AgencyParserTest extends TestCase $resultNode = $crawler->filterXPath('//ergebnis'); $agencies = $this->parser->parse($resultNode); - $this->assertCount(1, $agencies); - $this->assertEquals(12345, $agencies[0]->id); - $this->assertEquals('Test Agency', $agencies[0]->name); - $this->assertEquals('001', $agencies[0]->code); - $this->assertNull($agencies[0]->street); - $this->assertNull($agencies[0]->postCode); - $this->assertNull($agencies[0]->city); - $this->assertNull($agencies[0]->phone); + self::assertCount(1, $agencies); + self::assertEquals(12345, $agencies[0]->id); + self::assertEquals('Test Agency', $agencies[0]->name); + self::assertEquals('001', $agencies[0]->code); + self::assertNull($agencies[0]->street); + self::assertNull($agencies[0]->postCode); + self::assertNull($agencies[0]->city); + self::assertNull($agencies[0]->phone); } public function testParseEmptyAgenciesList(): void @@ -106,6 +106,6 @@ class AgencyParserTest extends TestCase $resultNode = $crawler->filterXPath('//ergebnis'); $agencies = $this->parser->parse($resultNode); - $this->assertCount(0, $agencies); + self::assertCount(0, $agencies); } } diff --git a/tests/BusProNet/XmlParser/BookingInsurancesParserTest.php b/tests/BusProNet/XmlParser/BookingInsurancesParserTest.php index fd7b40b1..44c43940 100644 --- a/tests/BusProNet/XmlParser/BookingInsurancesParserTest.php +++ b/tests/BusProNet/XmlParser/BookingInsurancesParserTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Tests\BusProNet\XmlParser; +use App\BusProNet\Model\Insurance; use App\BusProNet\XmlParser\BookingInsurancesParser; use PHPUnit\Framework\TestCase; use Symfony\Component\DomCrawler\Crawler; @@ -28,15 +29,15 @@ XML; $parser = new BookingInsurancesParser(); $insurances = $parser->parse($insurancesData); - $this->assertCount(1, $insurances); - $this->assertArrayHasKey(177240, $insurances); - - $insurance = $insurances[177240]; - $this->assertEquals(177240, $insurance->id); - $this->assertEquals('Reiseschutz Platin Auto/Bahn/Bus (Europa)', $insurance->label); - $this->assertEquals(45.0, $insurance->price); - $this->assertEquals([0], $insurance->mapping); // zuordnung="1" maps to participant index 0 - $this->assertEquals([0 => 45.0], $insurance->individualPrice); + self::assertCount(1, $insurances); + $insuranceValues = array_values($insurances); + $insurance = $insuranceValues[0] ?? null; + self::assertInstanceOf(Insurance::class, $insurance); + self::assertEquals(177240, $insurance->id); + self::assertEquals('Reiseschutz Platin Auto/Bahn/Bus (Europa)', $insurance->label); + self::assertEquals(45.0, $insurance->price); + self::assertEquals([0], $insurance->mapping); // zuordnung="1" maps to participant index 0 + self::assertEquals([0 => 45.0], $insurance->individualPrice); } public function testParseMultipleInsurances(): void @@ -59,23 +60,36 @@ XML; $parser = new BookingInsurancesParser(); $insurances = $parser->parse($insurancesData); - $this->assertCount(2, $insurances); + self::assertCount(2, $insurances); + + /** @var Insurance|null $insurance1 */ + $insurance1 = null; + /** @var Insurance|null $insurance2 */ + $insurance2 = null; + foreach ($insurances as $insurance) { + if ('100' === (string) $insurance->id) { + $insurance1 = $insurance; + } + if ('200' === (string) $insurance->id) { + $insurance2 = $insurance; + } + } // First insurance - $insurance1 = $insurances[100]; - $this->assertEquals(100, $insurance1->id); - $this->assertEquals('Insurance A', $insurance1->label); - $this->assertEquals(45.0, $insurance1->price); - $this->assertEquals([0], $insurance1->mapping); // zuordnung="1" maps to index 0 - $this->assertEquals([0 => 45.0], $insurance1->individualPrice); + self::assertInstanceOf(Insurance::class, $insurance1); + self::assertEquals(100, $insurance1->id); + self::assertEquals('Insurance A', $insurance1->label); + self::assertEquals(45.0, $insurance1->price); + self::assertEquals([0], $insurance1->mapping); // zuordnung="1" maps to index 0 + self::assertEquals([0 => 45.0], $insurance1->individualPrice); // Second insurance - $insurance2 = $insurances[200]; - $this->assertEquals(200, $insurance2->id); - $this->assertEquals('Insurance B', $insurance2->label); - $this->assertEquals(30.0, $insurance2->price); - $this->assertEquals([1], $insurance2->mapping); // zuordnung="2" maps to index 1 - $this->assertEquals([1 => 30.0], $insurance2->individualPrice); + self::assertInstanceOf(Insurance::class, $insurance2); + self::assertEquals(200, $insurance2->id); + self::assertEquals('Insurance B', $insurance2->label); + self::assertEquals(30.0, $insurance2->price); + self::assertEquals([1], $insurance2->mapping); // zuordnung="2" maps to index 1 + self::assertEquals([1 => 30.0], $insurance2->individualPrice); } public function testParseEmptyInsurancesReturnsEmptyArray(): void @@ -94,7 +108,7 @@ XML; $parser = new BookingInsurancesParser(); $insurances = $parser->parse($insurancesData); - $this->assertCount(0, $insurances); - $this->assertIsArray($insurances); + self::assertCount(0, $insurances); + self::assertIsArray($insurances); } } diff --git a/tests/BusProNet/XmlParser/BookingResponseParserTest.php b/tests/BusProNet/XmlParser/BookingResponseParserTest.php index 90b186fe..3987b2f6 100644 --- a/tests/BusProNet/XmlParser/BookingResponseParserTest.php +++ b/tests/BusProNet/XmlParser/BookingResponseParserTest.php @@ -37,17 +37,17 @@ class BookingResponseParserTest extends TestCase $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); - $this->assertTrue($response->isInquiryValid()); - $this->assertEquals(321530, $response->bookingNumber); - $this->assertEquals(755.0, $response->totalPrice); + self::assertTrue($response->isInquiryValid()); + self::assertEquals(321530, $response->bookingNumber); + self::assertEquals(755.0, $response->totalPrice); // Verify purchase voucher is parsed - $this->assertNotNull($response->paymentTerms); - $this->assertCount(1, $response->paymentTerms->appliedPurchaseVouchers); - $this->assertEquals('G1263', $response->paymentTerms->appliedPurchaseVouchers[0]['nummer']); - $this->assertEquals(100.0, $response->paymentTerms->appliedPurchaseVouchers[0]['betrag']); - $this->assertEquals(100.0, $response->paymentTerms->getPurchaseVoucherDiscount()); - $this->assertEquals(655.0, $response->paymentTerms->finalPaymentAmount); + self::assertNotNull($response->paymentTerms); + self::assertCount(1, $response->paymentTerms->appliedPurchaseVouchers); + self::assertEquals('G1263', $response->paymentTerms->appliedPurchaseVouchers[0]['nummer']); + self::assertEquals(100.0, $response->paymentTerms->appliedPurchaseVouchers[0]['betrag']); + self::assertEquals(100.0, $response->paymentTerms->getPurchaseVoucherDiscount()); + self::assertEquals(655.0, $response->paymentTerms->finalPaymentAmount); } public function testParseBookingResponseWithPromotionalVoucher(): void @@ -70,21 +70,21 @@ class BookingResponseParserTest extends TestCase $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); - $this->assertTrue($response->isInquiryValid()); - $this->assertEquals(615.2, $response->totalPrice); + self::assertTrue($response->isInquiryValid()); + self::assertEquals(615.2, $response->totalPrice); // Verify price items include promotional voucher - $this->assertCount(2, $response->priceItems); + self::assertCount(2, $response->priceItems); $voucherItem = $response->priceItems[1]; - $this->assertEquals('AKTION', $voucherItem->type); - $this->assertEquals('TESTERINO1', $voucherItem->label); - $this->assertEquals(-100.0, $voucherItem->totalPrice); + self::assertEquals('AKTION', $voucherItem->type); + self::assertEquals('TESTERINO1', $voucherItem->label); + self::assertEquals(-100.0, $voucherItem->totalPrice); // Verify voucher discount extraction $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); - $this->assertCount(1, $voucherDiscounts); - $this->assertEquals(100.0, $response->getVoucherDiscountFromPrices()); - $this->assertEquals(100.0, $response->getTotalVoucherDiscount()); + self::assertCount(1, $voucherDiscounts); + self::assertEquals(100.0, $response->getVoucherDiscountFromPrices()); + self::assertEquals(100.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithGoodwillVoucher(): void @@ -105,20 +105,20 @@ class BookingResponseParserTest extends TestCase $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); - $this->assertTrue($response->isInquiryValid()); - $this->assertEquals(0.0, $response->totalPrice); + self::assertTrue($response->isInquiryValid()); + self::assertEquals(0.0, $response->totalPrice); // Verify goodwill voucher is parsed $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); - $this->assertCount(1, $voucherDiscounts); + self::assertCount(1, $voucherDiscounts); $goodwillVoucher = array_values($voucherDiscounts)[0]; - $this->assertEquals('KULANZGUTSCHEIN', $goodwillVoucher->type); - $this->assertEquals('Kulanzgutschein K1904', $goodwillVoucher->label); - $this->assertEquals(-679.0, $goodwillVoucher->totalPrice); + self::assertEquals('KULANZGUTSCHEIN', $goodwillVoucher->type); + self::assertEquals('Kulanzgutschein K1904', $goodwillVoucher->label); + self::assertEquals(-679.0, $goodwillVoucher->totalPrice); - $this->assertEquals(679.0, $response->getVoucherDiscountFromPrices()); - $this->assertEquals(679.0, $response->getTotalVoucherDiscount()); + self::assertEquals(679.0, $response->getVoucherDiscountFromPrices()); + self::assertEquals(679.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithMultipleVouchers(): void @@ -144,13 +144,13 @@ class BookingResponseParserTest extends TestCase $response = $this->parser->parse($crawler->filter('ergebnis')); // Verify all voucher types are parsed - $this->assertEquals(80.0, $response->getVoucherDiscountFromPrices()); // 50 + 30 - $this->assertEquals(100.0, $response->getPurchaseVoucherDiscount()); - $this->assertEquals(180.0, $response->getTotalVoucherDiscount()); // 50 + 30 + 100 + self::assertEquals(80.0, $response->getVoucherDiscountFromPrices()); // 50 + 30 + self::assertEquals(100.0, $response->getPurchaseVoucherDiscount()); + self::assertEquals(180.0, $response->getTotalVoucherDiscount()); // 50 + 30 + 100 // Verify price item vouchers $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); - $this->assertCount(2, $voucherDiscounts); + self::assertCount(2, $voucherDiscounts); } public function testParseBookingResponseWithNoVouchers(): void @@ -172,14 +172,14 @@ class BookingResponseParserTest extends TestCase $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); - $this->assertTrue($response->isInquiryValid()); - $this->assertEquals(679.0, $response->totalPrice); + self::assertTrue($response->isInquiryValid()); + self::assertEquals(679.0, $response->totalPrice); // Verify no voucher discounts - $this->assertCount(0, $response->getVoucherDiscountsFromPrices()); - $this->assertEquals(0.0, $response->getVoucherDiscountFromPrices()); - $this->assertEquals(0.0, $response->getPurchaseVoucherDiscount()); - $this->assertEquals(0.0, $response->getTotalVoucherDiscount()); + self::assertCount(0, $response->getVoucherDiscountsFromPrices()); + self::assertEquals(0.0, $response->getVoucherDiscountFromPrices()); + self::assertEquals(0.0, $response->getPurchaseVoucherDiscount()); + self::assertEquals(0.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithMultiplePurchaseVouchers(): void @@ -204,10 +204,10 @@ class BookingResponseParserTest extends TestCase $response = $this->parser->parse($crawler->filter('ergebnis')); // Verify multiple purchase vouchers are parsed - $this->assertNotNull($response->paymentTerms); - $this->assertCount(2, $response->paymentTerms->appliedPurchaseVouchers); - $this->assertEquals(125.0, $response->paymentTerms->getPurchaseVoucherDiscount()); // 50 + 75 - $this->assertEquals(125.0, $response->getTotalVoucherDiscount()); + self::assertNotNull($response->paymentTerms); + self::assertCount(2, $response->paymentTerms->appliedPurchaseVouchers); + self::assertEquals(125.0, $response->paymentTerms->getPurchaseVoucherDiscount()); // 50 + 75 + self::assertEquals(125.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithGruppenrabatt(): void @@ -231,24 +231,24 @@ class BookingResponseParserTest extends TestCase $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); - $this->assertTrue($response->isInquiryValid()); - $this->assertEquals(3972.0, $response->totalPrice); + self::assertTrue($response->isInquiryValid()); + self::assertEquals(3972.0, $response->totalPrice); // Verify Gruppenrabatt is NOT counted as voucher discount - $this->assertCount(0, $response->getVoucherDiscountsFromPrices()); - $this->assertEquals(0.0, $response->getVoucherDiscountFromPrices()); + self::assertCount(0, $response->getVoucherDiscountsFromPrices()); + self::assertEquals(0.0, $response->getVoucherDiscountFromPrices()); // Verify Gruppenrabatt IS counted as API-applied discount $apiAppliedDiscounts = $response->getApiAppliedDiscounts(); - $this->assertCount(1, $apiAppliedDiscounts); + self::assertCount(1, $apiAppliedDiscounts); $gruppenrabatt = array_values($apiAppliedDiscounts)[0]; - $this->assertEquals('ERM', $gruppenrabatt->type); - $this->assertEquals('GRU', $gruppenrabatt->subType); - $this->assertEquals('Gruppenrabatt', $gruppenrabatt->label); - $this->assertEquals(-90.0, $gruppenrabatt->totalPrice); + self::assertEquals('ERM', $gruppenrabatt->type); + self::assertEquals('GRU', $gruppenrabatt->subType); + self::assertEquals('Gruppenrabatt', $gruppenrabatt->label); + self::assertEquals(-90.0, $gruppenrabatt->totalPrice); - $this->assertEquals(90.0, $response->getApiAppliedDiscountTotal()); + self::assertEquals(90.0, $response->getApiAppliedDiscountTotal()); } public function testParseBookingResponseWithGruppenrabattAndVouchers(): void @@ -273,20 +273,20 @@ class BookingResponseParserTest extends TestCase $response = $this->parser->parse($crawler->filter('ergebnis')); // Voucher discount should only include AKTION - $this->assertEquals(20.0, $response->getVoucherDiscountFromPrices()); + self::assertEquals(20.0, $response->getVoucherDiscountFromPrices()); // API-applied discount should only include ERM (Gruppenrabatt) - $this->assertEquals(50.0, $response->getApiAppliedDiscountTotal()); + self::assertEquals(50.0, $response->getApiAppliedDiscountTotal()); // Verify they are separate and don't overlap $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); $apiDiscounts = $response->getApiAppliedDiscounts(); - $this->assertCount(1, $voucherDiscounts); - $this->assertCount(1, $apiDiscounts); + self::assertCount(1, $voucherDiscounts); + self::assertCount(1, $apiDiscounts); - $this->assertEquals('AKTION', array_values($voucherDiscounts)[0]->type); - $this->assertEquals('ERM', array_values($apiDiscounts)[0]->type); + self::assertEquals('AKTION', array_values($voucherDiscounts)[0]->type); + self::assertEquals('ERM', array_values($apiDiscounts)[0]->type); } public function testParseBookingResponseWithNoApiAppliedDiscounts(): void @@ -309,8 +309,8 @@ class BookingResponseParserTest extends TestCase $response = $this->parser->parse($crawler->filter('ergebnis')); // Verify no API-applied discounts - $this->assertCount(0, $response->getApiAppliedDiscounts()); - $this->assertEquals(0.0, $response->getApiAppliedDiscountTotal()); + self::assertCount(0, $response->getApiAppliedDiscounts()); + self::assertEquals(0.0, $response->getApiAppliedDiscountTotal()); } public function testParseBookingResponseWithTransportationDiscountNotCountedAsApiApplied(): void @@ -336,16 +336,16 @@ class BookingResponseParserTest extends TestCase $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); - $this->assertTrue($response->isInquiryValid()); - $this->assertEquals(1682.0, $response->totalPrice); + self::assertTrue($response->isInquiryValid()); + self::assertEquals(1682.0, $response->totalPrice); // Transportation discount (BEF with negative price) should NOT be counted as API-applied discount // because it's already handled by the local price calculator - $this->assertCount(0, $response->getApiAppliedDiscounts()); - $this->assertEquals(0.0, $response->getApiAppliedDiscountTotal()); + self::assertCount(0, $response->getApiAppliedDiscounts()); + self::assertEquals(0.0, $response->getApiAppliedDiscountTotal()); // Verify no voucher discounts either - $this->assertEquals(0.0, $response->getVoucherDiscountFromPrices()); + self::assertEquals(0.0, $response->getVoucherDiscountFromPrices()); } public function testParseBookingResponseWithBothTransportationAndGruppenrabatt(): void @@ -372,13 +372,13 @@ class BookingResponseParserTest extends TestCase // Only ERM (Gruppenrabatt) should be counted as API-applied discount // BEF transportation discount should NOT be counted $apiAppliedDiscounts = $response->getApiAppliedDiscounts(); - $this->assertCount(1, $apiAppliedDiscounts); + self::assertCount(1, $apiAppliedDiscounts); $gruppenrabatt = array_values($apiAppliedDiscounts)[0]; - $this->assertEquals('ERM', $gruppenrabatt->type); - $this->assertEquals(-100.0, $gruppenrabatt->totalPrice); + self::assertEquals('ERM', $gruppenrabatt->type); + self::assertEquals(-100.0, $gruppenrabatt->totalPrice); // Total API-applied discount should only include Gruppenrabatt (100), not transportation (300) - $this->assertEquals(100.0, $response->getApiAppliedDiscountTotal()); + self::assertEquals(100.0, $response->getApiAppliedDiscountTotal()); } } diff --git a/tests/BusProNet/XmlParser/InsuranceParserTest.php b/tests/BusProNet/XmlParser/InsuranceParserTest.php index 3f6bc3ab..285650e1 100644 --- a/tests/BusProNet/XmlParser/InsuranceParserTest.php +++ b/tests/BusProNet/XmlParser/InsuranceParserTest.php @@ -40,60 +40,60 @@ class InsuranceParserTest extends TestCase $insurances = $this->parser->parse($crawler); // Test all insurances are included (2 regular + 1 complementary + 1 package = 4 total) - $this->assertCount(4, $insurances); + self::assertCount(4, $insurances); // Test travel cancellation insurance (RRV) - $cancellationInsurance = $insurances[178917]; - $this->assertEquals(178917, $cancellationInsurance->id); - $this->assertEquals('903100', $cancellationInsurance->code); - $this->assertEquals('Reise-Rücktritt', $cancellationInsurance->label); - $this->assertEquals('RRV', $cancellationInsurance->subType); - $this->assertEquals(5.0, $cancellationInsurance->price); - $this->assertFalse($cancellationInsurance->familyInsurance); - $this->assertFalse($cancellationInsurance->package); - $this->assertFalse($cancellationInsurance->complementary); + $cancellationInsurance = $insurances['178917']; + self::assertEquals(178917, $cancellationInsurance->id); + self::assertEquals('903100', $cancellationInsurance->code); + self::assertEquals('Reise-Rücktritt', $cancellationInsurance->label); + self::assertEquals('RRV', $cancellationInsurance->subType); + self::assertEquals(5.0, $cancellationInsurance->price); + self::assertFalse($cancellationInsurance->familyInsurance); + self::assertFalse($cancellationInsurance->package); + self::assertFalse($cancellationInsurance->complementary); // Test travel protection insurance (PAK) with family flag - $protectionInsurance = $insurances[177236]; - $this->assertEquals(177236, $protectionInsurance->id); - $this->assertEquals('913320', $protectionInsurance->code); - $this->assertEquals('Reiseschutz Platin', $protectionInsurance->label); // "Auto/Bahn/Bus (Europa)" is normalized away - $this->assertEquals('PAK', $protectionInsurance->subType); - $this->assertEquals(9.0, $protectionInsurance->price); - $this->assertTrue($protectionInsurance->familyInsurance); - $this->assertFalse($protectionInsurance->package); - $this->assertFalse($protectionInsurance->complementary); + $protectionInsurance = $insurances['177236']; + self::assertEquals(177236, $protectionInsurance->id); + self::assertEquals('913320', $protectionInsurance->code); + self::assertEquals('Reiseschutz Platin', $protectionInsurance->label); // "Auto/Bahn/Bus (Europa)" is normalized away + self::assertEquals('PAK', $protectionInsurance->subType); + self::assertEquals(9.0, $protectionInsurance->price); + self::assertTrue($protectionInsurance->familyInsurance); + self::assertFalse($protectionInsurance->package); + self::assertFalse($protectionInsurance->complementary); // Test deductible insurance (OHN) - IS included but marked as complementary - $deductibleInsurance = $insurances[177270]; - $this->assertEquals(177270, $deductibleInsurance->id); - $this->assertEquals('903551', $deductibleInsurance->code); - $this->assertEquals('Selbstbehaltübernahme', $deductibleInsurance->label); - $this->assertEquals('OHN', $deductibleInsurance->subType); - $this->assertEquals(5.0, $deductibleInsurance->price); - $this->assertFalse($deductibleInsurance->familyInsurance); - $this->assertFalse($deductibleInsurance->package); - $this->assertTrue($deductibleInsurance->complementary); // Marked as complementary + $deductibleInsurance = $insurances['177270']; + self::assertEquals(177270, $deductibleInsurance->id); + self::assertEquals('903551', $deductibleInsurance->code); + self::assertEquals('Selbstbehaltübernahme', $deductibleInsurance->label); + self::assertEquals('OHN', $deductibleInsurance->subType); + self::assertEquals(5.0, $deductibleInsurance->price); + self::assertFalse($deductibleInsurance->familyInsurance); + self::assertFalse($deductibleInsurance->package); + self::assertTrue($deductibleInsurance->complementary); // Marked as complementary // Test package - should be family insurance because it contains a family insurance (177236) $package = $insurances['P1000320']; - $this->assertEquals('P1000320', $package->id); - $this->assertEquals('Reiseschutz Platin + Selbstbehaltübernahme', $package->label); // "Auto/Bahn/Bus (Europa)" is normalized away - $this->assertNull($package->subType); // Packages don't have subtypes - $this->assertEquals(14.0, $package->price); - $this->assertTrue($package->familyInsurance); // Should be true because it contains family insurance 177236 - $this->assertTrue($package->package); - $this->assertEquals([177236, 177270], $package->containedInsuranceIds); + self::assertEquals('P1000320', $package->id); + self::assertEquals('Reiseschutz Platin + Selbstbehaltübernahme', $package->label); // "Auto/Bahn/Bus (Europa)" is normalized away + self::assertNull($package->subType); // Packages don't have subtypes + self::assertEquals(14.0, $package->price); + self::assertTrue($package->familyInsurance); // Should be true because it contains family insurance 177236 + self::assertTrue($package->package); + self::assertEquals(['177236', '177270'], $package->containedInsuranceIds); // Test containedInsurances array is populated with actual Insurance objects - $this->assertCount(2, $package->containedInsurances); - $this->assertEquals(177236, $package->containedInsurances[0]->id); - $this->assertEquals(177270, $package->containedInsurances[1]->id); + self::assertCount(2, $package->containedInsurances); + self::assertEquals(177236, $package->containedInsurances[0]->id); + self::assertEquals(177270, $package->containedInsurances[1]->id); // Test URL aggregation from contained insurances - $this->assertEquals(['https://example.com/info2', 'https://example.com/info3'], $package->getAllUrlsInfo()); - $this->assertEquals(['https://example.com/product2', 'https://example.com/product3'], $package->getAllUrlsProductInfo()); - $this->assertEquals(['https://example.com/terms2', 'https://example.com/terms3'], $package->getAllUrlsTerms()); + self::assertEquals(['https://example.com/info2', 'https://example.com/info3'], $package->getAllUrlsInfo()); + self::assertEquals(['https://example.com/product2', 'https://example.com/product3'], $package->getAllUrlsProductInfo()); + self::assertEquals(['https://example.com/terms2', 'https://example.com/terms3'], $package->getAllUrlsTerms()); } public function testParsePackageWithoutSubtype(): void @@ -115,14 +115,14 @@ class InsuranceParserTest extends TestCase $crawler = new Crawler($xmlContent); $insurances = $this->parser->parse($crawler); - $this->assertCount(2, $insurances); + self::assertCount(2, $insurances); // Test package has no subType but has familyInsurance flag $package = $insurances['P1000320']; - $this->assertEquals('P1000320', $package->id); - $this->assertNull($package->subType); - $this->assertTrue($package->familyInsurance); - $this->assertTrue($package->package); + self::assertEquals('P1000320', $package->id); + self::assertNull($package->subType); + self::assertTrue($package->familyInsurance); + self::assertTrue($package->package); } public function testParseInsuranceWithNullSubtype(): void @@ -137,12 +137,12 @@ class InsuranceParserTest extends TestCase $crawler = new Crawler($xmlContent); $insurances = $this->parser->parse($crawler); - $this->assertCount(1, $insurances); + self::assertCount(1, $insurances); - $insurance = $insurances[178917]; - $this->assertEquals(178917, $insurance->id); - $this->assertNull($insurance->subType); // Missing unterart attribute should result in null - $this->assertFalse($insurance->package); + $insurance = $insurances['178917']; + self::assertEquals(178917, $insurance->id); + self::assertNull($insurance->subType); // Missing unterart attribute should result in null + self::assertFalse($insurance->package); } public function testParseEmptyXml(): void @@ -158,7 +158,7 @@ class InsuranceParserTest extends TestCase $crawler = new Crawler($xmlContent); $insurances = $this->parser->parse($crawler); - $this->assertEmpty($insurances); + self::assertEmpty($insurances); } public function testParseZusatzversicherungFiltering(): void @@ -183,15 +183,15 @@ class InsuranceParserTest extends TestCase $insurances = $this->parser->parse($crawler); // Should include: normal insurance (178917), both complementary insurances (177270, 999999), and package (P1000320) - $this->assertCount(4, $insurances); - $this->assertArrayHasKey(178917, $insurances); - $this->assertArrayHasKey(177270, $insurances); - $this->assertArrayHasKey(999999, $insurances); - $this->assertArrayHasKey('P1000320', $insurances); + self::assertCount(4, $insurances); + self::assertArrayHasKey('178917', $insurances); + self::assertArrayHasKey('177270', $insurances); + self::assertArrayHasKey('999999', $insurances); + self::assertArrayHasKey('P1000320', $insurances); // Verify complementary flags - $this->assertFalse($insurances[178917]->complementary); // Normal insurance - $this->assertTrue($insurances[177270]->complementary); // Complementary insurance - $this->assertTrue($insurances[999999]->complementary); // Complementary insurance + self::assertFalse($insurances['178917']->complementary); // Normal insurance + self::assertTrue($insurances['177270']->complementary); // Complementary insurance + self::assertTrue($insurances['999999']->complementary); // Complementary insurance } } diff --git a/tests/EventListener/DomainThemeListenerTest.php b/tests/EventListener/DomainThemeListenerTest.php index ceb1927d..491ef836 100644 --- a/tests/EventListener/DomainThemeListenerTest.php +++ b/tests/EventListener/DomainThemeListenerTest.php @@ -34,7 +34,7 @@ class DomainThemeListenerTest extends TestCase $listener($event); - $this->assertSame('sbw', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); + self::assertSame('sbw', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); } public function testSetsDomainConfigAttribute(): void @@ -53,10 +53,10 @@ class DomainThemeListenerTest extends TestCase $listener($event); $config = $request->attributes->get(DomainThemeListener::DOMAIN_CONFIG_ATTRIBUTE); - $this->assertInstanceOf(DomainConfig::class, $config); - $this->assertSame('sbw', $config->theme); - $this->assertSame('GTM-123', $config->gtmId); - $this->assertSame('https://cmp.example.com', $config->cmpUrl); + self::assertInstanceOf(DomainConfig::class, $config); + self::assertSame('sbw', $config->theme); + self::assertSame('GTM-123', $config->gtmId); + self::assertSame('https://cmp.example.com', $config->cmpUrl); } public function testSetsDefaultThemeForUnknownDomain(): void @@ -70,7 +70,7 @@ class DomainThemeListenerTest extends TestCase $listener($event); - $this->assertSame('base', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); + self::assertSame('base', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); } public function testMatchesPartialDomain(): void @@ -84,7 +84,7 @@ class DomainThemeListenerTest extends TestCase $listener($event); - $this->assertSame('ser', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); + self::assertSame('ser', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); } public function testIgnoresSubRequests(): void @@ -98,7 +98,7 @@ class DomainThemeListenerTest extends TestCase $listener($event); - $this->assertFalse($request->attributes->has(DomainThemeListener::THEME_ATTRIBUTE)); + self::assertFalse($request->attributes->has(DomainThemeListener::THEME_ATTRIBUTE)); } public function testFirstMatchWins(): void @@ -114,7 +114,7 @@ class DomainThemeListenerTest extends TestCase $listener($event); - $this->assertSame('portal', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); + self::assertSame('portal', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); } public function testEmptyMapReturnsDefaultTheme(): void @@ -126,7 +126,7 @@ class DomainThemeListenerTest extends TestCase $listener($event); - $this->assertSame('base', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); + self::assertSame('base', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); } public function testMatchesLocalhostForDevelopment(): void @@ -140,7 +140,7 @@ class DomainThemeListenerTest extends TestCase $listener($event); - $this->assertSame('sbw', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); + self::assertSame('sbw', $request->attributes->get(DomainThemeListener::THEME_ATTRIBUTE)); } /** diff --git a/tests/Form/Model/AcceptedVouchersTest.php b/tests/Form/Model/AcceptedVouchersTest.php index 41e30019..0831d295 100644 --- a/tests/Form/Model/AcceptedVouchersTest.php +++ b/tests/Form/Model/AcceptedVouchersTest.php @@ -26,8 +26,8 @@ class AcceptedVouchersTest extends TestCase amount: 100.00 )); - $this->assertEquals(150.0, $acceptedVouchers->getTotalDiscount()); - $this->assertCount(2, $acceptedVouchers->getVouchers()); + self::assertEquals(150.0, $acceptedVouchers->getTotalDiscount()); + self::assertCount(2, $acceptedVouchers->getVouchers()); } public function testFilterVouchersByType(): void @@ -52,17 +52,17 @@ class AcceptedVouchersTest extends TestCase amount: 75.00 )); - $this->assertCount(1, $acceptedVouchers->getPromotionalVouchers()); - $this->assertCount(1, $acceptedVouchers->getPurchaseVouchers()); - $this->assertCount(1, $acceptedVouchers->getGoodwillVouchers()); + self::assertCount(1, $acceptedVouchers->getPromotionalVouchers()); + self::assertCount(1, $acceptedVouchers->getPurchaseVouchers()); + self::assertCount(1, $acceptedVouchers->getGoodwillVouchers()); } public function testHasVouchersReturnsFalseWhenEmpty(): void { $acceptedVouchers = new AcceptedVouchersDto(); - $this->assertFalse($acceptedVouchers->hasVouchers()); - $this->assertEquals(0, $acceptedVouchers->count()); + self::assertFalse($acceptedVouchers->hasVouchers()); + self::assertEquals(0, $acceptedVouchers->count()); } public function testHasVouchersReturnsTrueWhenNotEmpty(): void @@ -75,8 +75,8 @@ class AcceptedVouchersTest extends TestCase amount: 50.00 )); - $this->assertTrue($acceptedVouchers->hasVouchers()); - $this->assertEquals(1, $acceptedVouchers->count()); + self::assertTrue($acceptedVouchers->hasVouchers()); + self::assertEquals(1, $acceptedVouchers->count()); } public function testFloatPrecisionHandling(): void @@ -102,6 +102,6 @@ class AcceptedVouchersTest extends TestCase )); // Should be exactly 100.00 with proper rounding - $this->assertEquals(100.0, $acceptedVouchers->getTotalDiscount()); + self::assertEquals(100.0, $acceptedVouchers->getTotalDiscount()); } } diff --git a/tests/Form/Model/BookingDtoTest.php b/tests/Form/Model/BookingDtoTest.php index f599b4a3..65c6bd51 100644 --- a/tests/Form/Model/BookingDtoTest.php +++ b/tests/Form/Model/BookingDtoTest.php @@ -24,9 +24,9 @@ class BookingDtoTest extends TestCase $bookingDto = new BookingDto($travel, 1); - $this->assertInstanceOf(BookingDto::class, $bookingDto); - $this->assertSame($travel, $bookingDto->travel); - $this->assertSame(BookingDto::MODE_CREATE, $bookingDto->getMode()); + self::assertInstanceOf(BookingDto::class, $bookingDto); + self::assertSame($travel, $bookingDto->travel); + self::assertSame(BookingDto::MODE_CREATE, $bookingDto->getMode()); } public function testUnserializeHandlesIntTravelId(): void @@ -40,8 +40,8 @@ class BookingDtoTest extends TestCase $serialized = serialize($dto); $restored = unserialize($serialized); - $this->assertInstanceOf(BookingDto::class, $restored); - $this->assertSame(42, $restored->travel->id); + self::assertInstanceOf(BookingDto::class, $restored); + self::assertSame(42, $restored->travel->id); } public function testUnserializeHandlesLegacyTravelObject(): void @@ -60,7 +60,7 @@ class BookingDtoTest extends TestCase $dto = new BookingDto(new Travel(), 1); $dto->__unserialize($data); - $this->assertSame($travel, $dto->travel); - $this->assertSame(42, $dto->travel->id); + self::assertSame($travel, $dto->travel); + self::assertSame(42, $dto->travel->id); } } diff --git a/tests/Form/Model/ParticipantDtoTest.php b/tests/Form/Model/ParticipantDtoTest.php index e7dd3e59..64e89690 100644 --- a/tests/Form/Model/ParticipantDtoTest.php +++ b/tests/Form/Model/ParticipantDtoTest.php @@ -15,7 +15,7 @@ class ParticipantDtoTest extends TestCase $participant = new ParticipantDto(); $participant->dateOfBirth = null; - $this->assertNull($participant->getAge()); + self::assertNull($participant->getAge()); } public function testGetAgeCalculatesCurrentAgeWhenNoReferenceDateProvided(): void @@ -26,7 +26,7 @@ class ParticipantDtoTest extends TestCase $expectedAge = (new \DateTimeImmutable())->diff($participant->dateOfBirth)->y; $actualAge = $participant->getAge(); - $this->assertEquals($expectedAge, $actualAge); + self::assertEquals($expectedAge, $actualAge); } public function testGetAgeCalculatesAgeAtSpecificReferenceDate(): void @@ -37,7 +37,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($referenceDate); - $this->assertEquals(33, $result); // Still 33 years old + self::assertEquals(33, $result); // Still 33 years old } public function testGetAgeCalculatesAgeAtSpecificReferenceDateAfterBirthday(): void @@ -48,7 +48,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($referenceDate); - $this->assertEquals(34, $result); // Now 34 years old + self::assertEquals(34, $result); // Now 34 years old } public function testGetAgeCalculatesAgeForInsuranceEligibilityScenario(): void @@ -61,7 +61,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($travelStartDate); // On 2024-08-01, they are still 34 (birthday not yet reached) - $this->assertEquals(34, $result); + self::assertEquals(34, $result); } public function testGetAgeCalculatesAgeForInsuranceEligibilityScenarioAfterBirthday(): void @@ -74,7 +74,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($travelStartDate); // On 2024-12-26, they just turned 35 - $this->assertEquals(35, $result); + self::assertEquals(35, $result); } public function testGetAgeHandlesLeapYearScenarios(): void @@ -86,7 +86,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($referenceDate); - $this->assertEquals(22, $result); // Still 22, birthday is technically next day + self::assertEquals(22, $result); // Still 22, birthday is technically next day } public function testGetAgeReturnsNullWithReferenceDateWhenDateOfBirthIsNull(): void @@ -97,7 +97,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($referenceDate); - $this->assertNull($result); + self::assertNull($result); } public function testGetAgeWithYoungParticipant(): void @@ -109,7 +109,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($referenceDate); - $this->assertEquals(4, $result); + self::assertEquals(4, $result); } public function testGetAgeWithElderlyParticipant(): void @@ -121,7 +121,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getAge($referenceDate); - $this->assertEquals(84, $result); + self::assertEquals(84, $result); } public function testHasInsuranceReturnsFalseWhenNoInsuranceSelected(): void @@ -131,7 +131,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->hasInsuranceSelected(); - $this->assertFalse($result); + self::assertFalse($result); } public function testHasInsuranceReturnsTrueWhenInsuranceSelected(): void @@ -141,7 +141,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->hasInsuranceSelected(); - $this->assertTrue($result); + self::assertTrue($result); } public function testGetInsuranceLabelReturnsNullWhenNoInsurance(): void @@ -151,7 +151,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getInsuranceLabel(); - $this->assertNull($result); + self::assertNull($result); } public function testGetInsuranceLabelReturnsLabelWhenInsuranceSelected(): void @@ -161,7 +161,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getInsuranceLabel(); - $this->assertEquals('Reise-Rücktritt', $result); + self::assertEquals('Reise-Rücktritt', $result); } public function testGetInsurancePriceReturnsZeroWhenNoInsurance(): void @@ -171,7 +171,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getInsurancePrice(); - $this->assertEquals(0.0, $result); + self::assertEquals(0.0, $result); } public function testGetInsurancePriceReturnsPriceWhenInsuranceSelected(): void @@ -181,7 +181,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getInsurancePrice(); - $this->assertEquals(25.50, $result); + self::assertEquals(25.50, $result); } public function testGetInsurancePriceReturnsZeroWhenInsuranceHasNullPrice(): void @@ -193,7 +193,7 @@ class ParticipantDtoTest extends TestCase $result = $participant->getInsurancePrice(); - $this->assertEquals(0.0, $result); + self::assertEquals(0.0, $result); } private function createInsurance(string $label = 'Test Insurance', float $price = 10.0): Insurance diff --git a/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php b/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php index 75ab5172..b5c28b39 100644 --- a/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php +++ b/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php @@ -38,7 +38,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Insurance should always be editable in create flow'); + self::assertFalse($result, 'Insurance should always be editable in create flow'); } public function testReadonlyWhen40DaysBeforeTravel(): void @@ -51,7 +51,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); + self::assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } public function testReadonlyWhenExactly30DaysBeforeTravel(): void @@ -65,7 +65,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); + self::assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } public function testReadonlyWhen20DaysBeforeTravel(): void @@ -78,7 +78,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Insurance should be readonly when 20 days before travel (standard case)'); + self::assertTrue($result, 'Insurance should be readonly when 20 days before travel (standard case)'); } public function testReadonlyWhen2DaysAfterLateBooking(): void @@ -92,7 +92,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); + self::assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } public function testReadonlyWhenExactly3DaysAfterLateBooking(): void @@ -106,7 +106,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); + self::assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } public function testReadonlyWhen5DaysAfterLateBooking(): void @@ -120,7 +120,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Insurance should be readonly 5 days after late booking'); + self::assertTrue($result, 'Insurance should be readonly 5 days after late booking'); } public function testReadonlyWhenTravelDatePassed(): void @@ -133,24 +133,24 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Insurance should be readonly when travel date has passed'); + self::assertTrue($result, 'Insurance should be readonly when travel date has passed'); } public function testGetDependentFieldsReturnsEmptyArray(): void { $result = $this->condition->getDependentFields(); - $this->assertIsArray($result); - $this->assertEmpty($result, 'Insurance mutability has no field dependencies'); + self::assertIsArray($result); + self::assertEmpty($result, 'Insurance mutability has no field dependencies'); } public function testGetDescriptionReturnsString(): void { $result = $this->condition->getDescription(); - $this->assertIsString($result); - $this->assertStringContainsString('not editable', $result); - $this->assertStringContainsString('edit mode', $result); + self::assertIsString($result); + self::assertStringContainsString('not editable', $result); + self::assertStringContainsString('edit mode', $result); } private function createEditDto(\DateTimeImmutable $travelDate, \DateTimeImmutable $bookingDate): BookingDto diff --git a/tests/Form/Service/Condition/SingleRoomTypeConditionTest.php b/tests/Form/Service/Condition/SingleRoomTypeConditionTest.php index 185582da..c74a31f3 100644 --- a/tests/Form/Service/Condition/SingleRoomTypeConditionTest.php +++ b/tests/Form/Service/Condition/SingleRoomTypeConditionTest.php @@ -25,7 +25,7 @@ class SingleRoomTypeConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Condition should return false when no rooms are selected'); + self::assertFalse($result, 'Condition should return false when no rooms are selected'); } public function testReturnsTrueWhenExactlyOneRoomSelected(): void @@ -36,7 +36,7 @@ class SingleRoomTypeConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Condition should return true when exactly one room type is selected'); + self::assertTrue($result, 'Condition should return true when exactly one room type is selected'); } public function testReturnsFalseWhenTwoRoomsSelected(): void @@ -48,7 +48,7 @@ class SingleRoomTypeConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Condition should return false when two room types are selected'); + self::assertFalse($result, 'Condition should return false when two room types are selected'); } public function testReturnsFalseWhenMultipleRoomsSelected(): void @@ -61,7 +61,7 @@ class SingleRoomTypeConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Condition should return false when multiple room types are selected'); + self::assertFalse($result, 'Condition should return false when multiple room types are selected'); } public function testIgnoresRoomsWithZeroQuantity(): void @@ -74,7 +74,7 @@ class SingleRoomTypeConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Condition should ignore rooms with zero quantity'); + self::assertTrue($result, 'Condition should ignore rooms with zero quantity'); } public function testIgnoresRoomsWithNullQuantity(): void @@ -86,7 +86,7 @@ class SingleRoomTypeConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertTrue($result, 'Condition should ignore rooms with null quantity'); + self::assertTrue($result, 'Condition should ignore rooms with null quantity'); } public function testReturnsFalseWhenAllRoomsHaveZeroQuantity(): void @@ -98,24 +98,24 @@ class SingleRoomTypeConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Condition should return false when all rooms have zero quantity'); + self::assertFalse($result, 'Condition should return false when all rooms have zero quantity'); } public function testGetDependentFieldsReturnsEmptyArray(): void { $result = $this->condition->getDependentFields(); - $this->assertIsArray($result); - $this->assertEmpty($result, 'Single room type condition has no participant-level field dependencies'); + self::assertIsArray($result); + self::assertEmpty($result, 'Single room type condition has no participant-level field dependencies'); } public function testGetDescriptionReturnsString(): void { $result = $this->condition->getDescription(); - $this->assertIsString($result); - $this->assertStringContainsString('readonly', $result); - $this->assertStringContainsString('one room type', $result); + self::assertIsString($result); + self::assertStringContainsString('readonly', $result); + self::assertStringContainsString('one room type', $result); } /** diff --git a/tests/Form/Service/ParticipantAssignedRoomFieldHandlerTest.php b/tests/Form/Service/ParticipantAssignedRoomFieldHandlerTest.php index 907cc458..45ef2921 100644 --- a/tests/Form/Service/ParticipantAssignedRoomFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantAssignedRoomFieldHandlerTest.php @@ -22,24 +22,24 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase public function testGetFieldName(): void { - $this->assertSame('assignedRoomId', $this->handler->getFieldName()); + self::assertSame('assignedRoomId', $this->handler->getFieldName()); } public function testGetDependencies(): void { - $this->assertSame([], $this->handler->getDependencies()); + self::assertSame([], $this->handler->getDependencies()); } public function testShouldProcessReturnsTrueWhenFieldPresent(): void { - $this->assertTrue($this->handler->shouldProcess(['assignedRoomId' => '1'], BookingDto::MODE_CREATE, 0)); - $this->assertTrue($this->handler->shouldProcess(['assignedRoomId' => ''], BookingDto::MODE_EDIT, 5)); + self::assertTrue($this->handler->shouldProcess(['assignedRoomId' => '1'], BookingDto::MODE_CREATE, 0)); + self::assertTrue($this->handler->shouldProcess(['assignedRoomId' => ''], BookingDto::MODE_EDIT, 5)); } public function testShouldProcessReturnsFalseWhenFieldNotPresent(): void { - $this->assertFalse($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); - $this->assertFalse($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); + self::assertFalse($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); + self::assertFalse($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } public function testProcessFieldWithoutParticipant(): void @@ -67,7 +67,7 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertSame(1, $participant->assignedRoomId); + self::assertSame(1, $participant->assignedRoomId); } public function testProcessFieldUnassignsParticipantWhenRoomIdIsEmpty(): void @@ -83,7 +83,7 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->assignedRoomId); + self::assertNull($participant->assignedRoomId); } public function testProcessFieldUnassignsParticipantWhenRoomIdIsNull(): void @@ -99,7 +99,7 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->assignedRoomId); + self::assertNull($participant->assignedRoomId); } public function testProcessFieldUnassignsHighestIndexParticipantWhenRoomAtCapacity(): void @@ -125,9 +125,9 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 2); // Participant 1 (highest index with room 1) should be unassigned - $this->assertSame(1, $participant0->assignedRoomId); // Still assigned (applicant protection) - $this->assertNull($participant1->assignedRoomId); // Unassigned - $this->assertSame(1, $participant2->assignedRoomId); // Newly assigned + self::assertSame(1, $participant0->assignedRoomId); // Still assigned (applicant protection) + self::assertNull($participant1->assignedRoomId); // Unassigned + self::assertSame(1, $participant2->assignedRoomId); // Newly assigned } public function testProcessFieldGeneratesWarningNotificationForUnassignedParticipant(): void @@ -151,13 +151,13 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase // Participant 1 should have a warning notification $notifications = $participant1->notifications; - $this->assertCount(1, $notifications); + self::assertCount(1, $notifications); // Get first notification (notifications are keyed by hash, not numeric index) $firstNotification = reset($notifications); - $this->assertSame('warning', $firstNotification['type']); - $this->assertStringContainsString('Doppelzimmer', $firstNotification['message']); - $this->assertStringContainsString('wurde von', $firstNotification['message']); - $this->assertStringContainsString('entfernt', $firstNotification['message']); + self::assertSame('warning', $firstNotification['type']); + self::assertStringContainsString('Doppelzimmer', $firstNotification['message']); + self::assertStringContainsString('wurde von', $firstNotification['message']); + self::assertStringContainsString('entfernt', $firstNotification['message']); } public function testProcessFieldDoesNotGenerateNotificationForAssignedParticipant(): void @@ -180,7 +180,7 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 2); // Participant 2 (the one being assigned) should NOT have a notification (user-initiated action) - $this->assertEmpty($participant2->notifications); + self::assertEmpty($participant2->notifications); } public function testProcessFieldHandlesRoomChangeWithoutConflict(): void @@ -203,9 +203,9 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); // Both should remain assigned (participant 0's own slot was freed, so no conflict) - $this->assertSame(1, $participant0->assignedRoomId); - $this->assertSame(1, $participant1->assignedRoomId); - $this->assertEmpty($participant1->notifications); + self::assertSame(1, $participant0->assignedRoomId); + self::assertSame(1, $participant1->assignedRoomId); + self::assertEmpty($participant1->notifications); } public function testProcessFieldUnassignsMultipleParticipantsWhenNeeded(): void @@ -234,10 +234,10 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase // All three participants with room 1 should be unassigned (highest indices first: 2, 1, 0) // But we only need to unassign enough to make space (3 participants, only 1 space needed) - $this->assertNull($participant2->assignedRoomId); // Highest index, unassigned first - $this->assertNull($participant1->assignedRoomId); // Second highest, unassigned second - $this->assertNull($participant0->assignedRoomId); // Third highest, unassigned third - $this->assertSame(1, $participant3->assignedRoomId); // Newly assigned + self::assertNull($participant2->assignedRoomId); // Highest index, unassigned first + self::assertNull($participant1->assignedRoomId); // Second highest, unassigned second + self::assertNull($participant0->assignedRoomId); // Third highest, unassigned third + self::assertSame(1, $participant3->assignedRoomId); // Newly assigned } public function testProcessFieldHandlesNoConflictWithMultipleRoomQuantities(): void @@ -265,13 +265,13 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 3); // All should remain assigned (4 beds available, 4 participants) - $this->assertSame(1, $participant0->assignedRoomId); - $this->assertSame(1, $participant1->assignedRoomId); - $this->assertSame(1, $participant2->assignedRoomId); - $this->assertSame(1, $participant3->assignedRoomId); - $this->assertEmpty($participant0->notifications); - $this->assertEmpty($participant1->notifications); - $this->assertEmpty($participant2->notifications); + self::assertSame(1, $participant0->assignedRoomId); + self::assertSame(1, $participant1->assignedRoomId); + self::assertSame(1, $participant2->assignedRoomId); + self::assertSame(1, $participant3->assignedRoomId); + self::assertEmpty($participant0->notifications); + self::assertEmpty($participant1->notifications); + self::assertEmpty($participant2->notifications); } public function testProcessFieldHandlesComplexScenarioWithMultipleRoomTypes(): void @@ -301,10 +301,10 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 3); // Participant 1 (highest index with room 1) should be unassigned - $this->assertSame(1, $participant0->assignedRoomId); - $this->assertNull($participant1->assignedRoomId); // Unassigned - $this->assertSame(2, $participant2->assignedRoomId); // Still in Einzelzimmer - $this->assertSame(1, $participant3->assignedRoomId); // Newly assigned to Doppelzimmer + self::assertSame(1, $participant0->assignedRoomId); + self::assertNull($participant1->assignedRoomId); // Unassigned + self::assertSame(2, $participant2->assignedRoomId); // Still in Einzelzimmer + self::assertSame(1, $participant3->assignedRoomId); // Newly assigned to Doppelzimmer } public function testProcessFieldHandlesEdgeCaseWhenRoomNotFoundInSelections(): void @@ -322,7 +322,7 @@ class ParticipantAssignedRoomFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); // Should still assign (no conflict detection possible, but assignment proceeds) - $this->assertSame(999, $participant->assignedRoomId); + self::assertSame(999, $participant->assignedRoomId); } /** diff --git a/tests/Form/Service/ParticipantDropOffFieldHandlerTest.php b/tests/Form/Service/ParticipantDropOffFieldHandlerTest.php index b36f4838..a9a8d9ac 100644 --- a/tests/Form/Service/ParticipantDropOffFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantDropOffFieldHandlerTest.php @@ -24,12 +24,12 @@ class ParticipantDropOffFieldHandlerTest extends TestCase public function testGetFieldName(): void { - $this->assertSame('dropOff', $this->handler->getFieldName()); + self::assertSame('dropOff', $this->handler->getFieldName()); } public function testGetDependencies(): void { - $this->assertSame( + self::assertSame( ['transportationOutbound', 'transportationInbound', 'pickup'], $this->handler->getDependencies() ); @@ -37,8 +37,8 @@ class ParticipantDropOffFieldHandlerTest extends TestCase public function testShouldProcessAlwaysReturnsTrue(): void { - $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); - $this->assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); + self::assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); + self::assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } public function testProcessFieldWithoutParticipant(): void @@ -69,9 +69,9 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); $participant = $bookingDto->getParticipant(0); - $this->assertNotNull($participant->dropOff); - $this->assertSame(10, $participant->dropOff->id); - $this->assertTrue($participant->differentDropOff); + self::assertNotNull($participant->dropOff); + self::assertSame(10, $participant->dropOff->id); + self::assertTrue($participant->differentDropOff); } public function testBusBusCheckboxUncheckedAssignsMatchingDropOff(): void @@ -98,9 +98,9 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNotNull($participant->dropOff); - $this->assertSame(10, $participant->dropOff->id); - $this->assertFalse($participant->differentDropOff); + self::assertNotNull($participant->dropOff); + self::assertSame(10, $participant->dropOff->id); + self::assertFalse($participant->differentDropOff); } public function testBusBusCheckboxUncheckedNoPickupKeepsDropOffNull(): void @@ -121,8 +121,8 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->dropOff); - $this->assertFalse($participant->differentDropOff); + self::assertNull($participant->dropOff); + self::assertFalse($participant->differentDropOff); } public function testBusBusCheckboxUncheckedPickupWithNoMatchingDropOff(): void @@ -147,8 +147,8 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->dropOff); - $this->assertFalse($participant->differentDropOff); + self::assertNull($participant->dropOff); + self::assertFalse($participant->differentDropOff); } public function testPkwBusValidSelection(): void @@ -167,9 +167,9 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); $participant = $bookingDto->getParticipant(0); - $this->assertNotNull($participant->dropOff); - $this->assertSame(20, $participant->dropOff->id); - $this->assertFalse($participant->differentDropOff); + self::assertNotNull($participant->dropOff); + self::assertSame(20, $participant->dropOff->id); + self::assertFalse($participant->differentDropOff); } public function testBusPkwClearsDropOff(): void @@ -189,8 +189,8 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->dropOff); - $this->assertFalse($participant->differentDropOff); + self::assertNull($participant->dropOff); + self::assertFalse($participant->differentDropOff); } public function testPkwPkwClearsDropOff(): void @@ -209,8 +209,8 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->dropOff); - $this->assertFalse($participant->differentDropOff); + self::assertNull($participant->dropOff); + self::assertFalse($participant->differentDropOff); } public function testInvalidDropOffIdSetsNull(): void @@ -229,7 +229,7 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); $participant = $bookingDto->getParticipant(0); - $this->assertNull($participant->dropOff); + self::assertNull($participant->dropOff); } public function testBusBusCheckboxCheckedNoSelection(): void @@ -248,8 +248,8 @@ class ParticipantDropOffFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); $participant = $bookingDto->getParticipant(0); - $this->assertNull($participant->dropOff); - $this->assertTrue($participant->differentDropOff); + self::assertNull($participant->dropOff); + self::assertTrue($participant->differentDropOff); } private function createDropOff(int $id, string $label): Pickup diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php index be2538f7..44f5c148 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php @@ -15,13 +15,15 @@ use App\Service\BookingPriceCalculator; use App\Service\InsuranceManager; use App\Service\ServiceLabelFormatter; use App\Service\ServiceAvailabilityCalculator; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; class ParticipantFieldOptionsProviderBabyTest extends TestCase { private ParticipantFieldOptionsProvider $provider; - private ServiceAvailabilityCalculator $serviceAvailabilityCalculator; + /** @var ServiceAvailabilityCalculator&MockObject */ + private $serviceAvailabilityCalculator; protected function setUp(): void { @@ -57,9 +59,9 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $choiceIds = array_map(fn (Service $service) => $service->id, $choices); // Baby should see only service with age range 0-14 that includes them - $this->assertContains(1, $choiceIds, 'Service with age range 0-14 should be shown for baby'); - $this->assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for baby (age < 6)'); - $this->assertNotContains(3, $choiceIds, 'Service without age restrictions should be hidden for baby'); + self::assertContains(1, $choiceIds, 'Service with age range 0-14 should be shown for baby'); + self::assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for baby (age < 6)'); + self::assertNotContains(3, $choiceIds, 'Service without age restrictions should be hidden for baby'); } public function testTwoYearOldOnlySeesServicesWithExplicitAgeRange(): void @@ -79,9 +81,9 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $choiceIds = array_map(fn (Service $service) => $service->id, $choices); // 2-year-old should see only service with age range that includes them - $this->assertContains(1, $choiceIds, 'Service with age range 0-14 should be shown for 2-year-old'); - $this->assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for 2-year-old'); - $this->assertNotContains(3, $choiceIds, 'Service without age restrictions should be hidden for 2-year-old'); + self::assertContains(1, $choiceIds, 'Service with age range 0-14 should be shown for 2-year-old'); + self::assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for 2-year-old'); + self::assertNotContains(3, $choiceIds, 'Service without age restrictions should be hidden for 2-year-old'); } public function testThreeYearOldSeesAllApplicableServices(): void @@ -101,9 +103,9 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $choiceIds = array_map(fn (Service $service) => $service->id, $choices); // 3-year-old is not a baby, should see service with age range that includes them AND no-restriction services - $this->assertContains(1, $choiceIds, 'Service with age range 0-14 should be shown for 3-year-old'); - $this->assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for 3-year-old (age < 6)'); - $this->assertContains(3, $choiceIds, 'Service without age restrictions should be shown for non-baby'); + self::assertContains(1, $choiceIds, 'Service with age range 0-14 should be shown for 3-year-old'); + self::assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for 3-year-old (age < 6)'); + self::assertContains(3, $choiceIds, 'Service without age restrictions should be shown for non-baby'); } public function testAdultSeesAllApplicableServices(): void @@ -123,9 +125,9 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $choiceIds = array_map(fn (Service $service) => $service->id, $choices); // Adult should see service without age restrictions but not children services - $this->assertNotContains(1, $choiceIds, 'Service with age range 0-14 should be hidden for adult (age > 14)'); - $this->assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for adult (age > 14)'); - $this->assertContains(3, $choiceIds, 'Service without age restrictions should be shown for adult'); + self::assertNotContains(1, $choiceIds, 'Service with age range 0-14 should be hidden for adult (age > 14)'); + self::assertNotContains(2, $choiceIds, 'Service with age range 6-14 should be hidden for adult (age > 14)'); + self::assertContains(3, $choiceIds, 'Service without age restrictions should be shown for adult'); } public function testBabyGetRegularPkwInTransportation(): void @@ -145,9 +147,9 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $choiceIds = array_map(fn (Service $service) => $service->id, $choices); // Baby should see BUS and regular PKW, but NOT discounted PKW - $this->assertContains(1, $choiceIds, 'BUS should be shown for baby'); - $this->assertContains(3, $choiceIds, 'Regular PKW should be shown for baby'); - $this->assertNotContains(2, $choiceIds, 'Discounted PKW should be hidden for baby'); + self::assertContains(1, $choiceIds, 'BUS should be shown for baby'); + self::assertContains(3, $choiceIds, 'Regular PKW should be shown for baby'); + self::assertNotContains(2, $choiceIds, 'Discounted PKW should be hidden for baby'); } public function testTwoYearOldGetRegularPkwInTransportation(): void @@ -167,9 +169,9 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $choiceIds = array_map(fn (Service $service) => $service->id, $choices); // 2-year-old (at BABY_MAX_AGE) should see BUS and regular PKW, but NOT discounted PKW - $this->assertContains(1, $choiceIds, 'BUS should be shown for 2-year-old'); - $this->assertContains(3, $choiceIds, 'Regular PKW should be shown for 2-year-old'); - $this->assertNotContains(2, $choiceIds, 'Discounted PKW should be hidden for 2-year-old'); + self::assertContains(1, $choiceIds, 'BUS should be shown for 2-year-old'); + self::assertContains(3, $choiceIds, 'Regular PKW should be shown for 2-year-old'); + self::assertNotContains(2, $choiceIds, 'Discounted PKW should be hidden for 2-year-old'); } public function testThreeYearOldGetSmartPkwFiltering(): void @@ -194,9 +196,9 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $choiceIds = array_map(fn (Service $service) => $service->id, $choices); // 3-year-old is not a baby, should get smart filtering (discounted when available) - $this->assertContains(1, $choiceIds, 'BUS should be shown for 3-year-old'); - $this->assertContains(2, $choiceIds, 'Discounted PKW should be shown for 3-year-old when available'); - $this->assertNotContains(3, $choiceIds, 'Regular PKW should be hidden when discounted is available'); + self::assertContains(1, $choiceIds, 'BUS should be shown for 3-year-old'); + self::assertContains(2, $choiceIds, 'Discounted PKW should be shown for 3-year-old when available'); + self::assertNotContains(3, $choiceIds, 'Regular PKW should be hidden when discounted is available'); } public function testBabyFilteringAppliesToMultipleServiceTypes(): void @@ -214,15 +216,15 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $boardOptions = $this->provider->getFieldOptions('board', $bookingDto, 0); $boardChoiceIds = array_map(fn (Service $service) => $service->id, $boardOptions['choices']); - $this->assertContains(10, $boardChoiceIds, 'Board with age range 0-5 should be shown for baby'); - $this->assertNotContains(11, $boardChoiceIds, 'Board without age range should be hidden for baby'); + self::assertContains(10, $boardChoiceIds, 'Board with age range 0-5 should be shown for baby'); + self::assertNotContains(11, $boardChoiceIds, 'Board without age range should be hidden for baby'); // Test courses services $coursesOptions = $this->provider->getFieldOptions('courses', $bookingDto, 0); $coursesChoiceIds = array_map(fn (Service $service) => $service->id, $coursesOptions['choices']); - $this->assertContains(20, $coursesChoiceIds, 'Course with age range 0-3 should be shown for baby'); - $this->assertNotContains(21, $coursesChoiceIds, 'Course without age range should be hidden for baby'); + self::assertContains(20, $coursesChoiceIds, 'Course with age range 0-3 should be shown for baby'); + self::assertNotContains(21, $coursesChoiceIds, 'Course without age range should be hidden for baby'); } private function createTravelWithMixedServices(): Travel diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php index ee2a8e99..45fc719b 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php @@ -59,9 +59,9 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase $choiceAttr = $options['choice_attr']; $attributes = $choiceAttr($mandatoryService); - $this->assertTrue($attributes['readonly']); - $this->assertSame('Diese Leistung ist nicht abwählbar', $attributes['data-tooltip']); - $this->assertArrayNotHasKey('checked', $attributes); + self::assertTrue($attributes['readonly']); + self::assertSame('Diese Leistung ist nicht abwählbar', $attributes['data-tooltip']); + self::assertArrayNotHasKey('checked', $attributes); } public function testMandatoryServiceNotSelectedHasNoReadonlyOrChecked(): void @@ -80,9 +80,9 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase $choiceAttr = $options['choice_attr']; $attributes = $choiceAttr($mandatoryService); - $this->assertArrayNotHasKey('readonly', $attributes); - $this->assertArrayNotHasKey('checked', $attributes); - $this->assertArrayNotHasKey('data-tooltip', $attributes); + self::assertArrayNotHasKey('readonly', $attributes); + self::assertArrayNotHasKey('checked', $attributes); + self::assertArrayNotHasKey('data-tooltip', $attributes); } public function testNonMandatoryServiceUnaffected(): void @@ -109,8 +109,8 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase $choiceAttr = $options['choice_attr']; $attributes = $choiceAttr($nonMandatoryService); - $this->assertArrayNotHasKey('readonly', $attributes); - $this->assertArrayNotHasKey('checked', $attributes); + self::assertArrayNotHasKey('readonly', $attributes); + self::assertArrayNotHasKey('checked', $attributes); } public function testParkingLabelIncludesPrice(): void @@ -144,7 +144,7 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase // Do not set participant — age filtering cannot determine choices, returns empty $options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0); - $this->assertEmpty($options); + self::assertEmpty($options); } private function createMandatoryService(int $id, string $label): Service @@ -160,6 +160,9 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase return $service; } + /** + * @param list $services + */ private function createTravelWithAdditionalServices(array $services): Travel { $travel = new Travel(); diff --git a/tests/Form/Service/ParticipantLicensePlateFieldHandlerTest.php b/tests/Form/Service/ParticipantLicensePlateFieldHandlerTest.php index ae3017df..a11c0cb2 100644 --- a/tests/Form/Service/ParticipantLicensePlateFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantLicensePlateFieldHandlerTest.php @@ -21,18 +21,18 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase public function testGetFieldName(): void { - $this->assertSame('licensePlate', $this->handler->getFieldName()); + self::assertSame('licensePlate', $this->handler->getFieldName()); } public function testGetDependencies(): void { - $this->assertSame(['parking'], $this->handler->getDependencies()); + self::assertSame(['parking'], $this->handler->getDependencies()); } public function testShouldProcessAlwaysReturnsTrue(): void { - $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); - $this->assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); + self::assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); + self::assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } public function testProcessFieldWithoutParticipant(): void @@ -61,7 +61,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->licensePlate); + self::assertNull($participant->licensePlate); } public function testProcessFieldSetsLicensePlateWhenParkingSelected(): void @@ -77,7 +77,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertSame('AB-CD 123', $participant->licensePlate); + self::assertSame('AB-CD 123', $participant->licensePlate); } public function testProcessFieldHandlesEmptyLicensePlate(): void @@ -93,7 +93,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->licensePlate); + self::assertNull($participant->licensePlate); } public function testProcessFieldHandlesNullLicensePlate(): void @@ -109,7 +109,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->licensePlate); + self::assertNull($participant->licensePlate); } public function testProcessFieldTrimsWhitespace(): void @@ -125,7 +125,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertSame('AB-CD 123', $participant->licensePlate); + self::assertSame('AB-CD 123', $participant->licensePlate); } public function testProcessFieldHandlesWhitespaceOnlyAsEmpty(): void @@ -141,7 +141,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->licensePlate); + self::assertNull($participant->licensePlate); } public function testProcessFieldHandlesNonStringValues(): void @@ -156,12 +156,12 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase // Test with integer value $submittedData = ['licensePlate' => 123]; $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->licensePlate); + self::assertNull($participant->licensePlate); // Test with array value $submittedData = ['licensePlate' => ['invalid']]; $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->licensePlate); + self::assertNull($participant->licensePlate); } public function testProcessFieldHandlesMissingLicensePlateField(): void @@ -177,7 +177,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertNull($participant->licensePlate); + self::assertNull($participant->licensePlate); } public function testProcessFieldWithDifferentParticipantIndex(): void @@ -197,7 +197,7 @@ class ParticipantLicensePlateFieldHandlerTest extends TestCase // Process for participant at index 1 $this->handler->processField($submittedData, $bookingDto, 1); - $this->assertNull($participant1->licensePlate); // Should not be affected - $this->assertSame('AB-CD 123', $participant2->licensePlate); // Should be set + self::assertNull($participant1->licensePlate); // Should not be affected + self::assertSame('AB-CD 123', $participant2->licensePlate); // Should be set } } diff --git a/tests/Form/Service/ParticipantParkingFieldHandlerTest.php b/tests/Form/Service/ParticipantParkingFieldHandlerTest.php index 7568e657..ea69d642 100644 --- a/tests/Form/Service/ParticipantParkingFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantParkingFieldHandlerTest.php @@ -23,18 +23,18 @@ class ParticipantParkingFieldHandlerTest extends TestCase public function testGetFieldName(): void { - $this->assertSame('parking', $this->handler->getFieldName()); + self::assertSame('parking', $this->handler->getFieldName()); } public function testGetDependencies(): void { - $this->assertSame(['transportationOutbound', 'transportationInbound', 'dateOfBirth'], $this->handler->getDependencies()); + self::assertSame(['transportationOutbound', 'transportationInbound', 'dateOfBirth'], $this->handler->getDependencies()); } public function testShouldProcessAlwaysReturnsTrue(): void { - $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); - $this->assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); + self::assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); + self::assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } /** @@ -42,7 +42,7 @@ class ParticipantParkingFieldHandlerTest extends TestCase */ public function testNormalizeCheckboxValueReturnsTrueWhenChecked(mixed $value): void { - $this->assertTrue($this->invokeNormalizeCheckboxValue($value)); + self::assertTrue($this->invokeNormalizeCheckboxValue($value)); } /** @@ -50,7 +50,7 @@ class ParticipantParkingFieldHandlerTest extends TestCase */ public function testNormalizeCheckboxValueReturnsFalseWhenUnchecked(mixed $value): void { - $this->assertFalse($this->invokeNormalizeCheckboxValue($value)); + self::assertFalse($this->invokeNormalizeCheckboxValue($value)); } public function testProcessFieldWithoutParticipant(): void @@ -81,8 +81,8 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertFalse($participant->parking); - $this->assertNull($participant->parkingService); + self::assertFalse($participant->parking); + self::assertNull($participant->parkingService); } public function testProcessFieldClearsParkingWhenParticipantIsUnder18(): void @@ -103,8 +103,8 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertFalse($participant->parking); - $this->assertNull($participant->parkingService); + self::assertFalse($participant->parking); + self::assertNull($participant->parkingService); } public function testProcessFieldClearsParkingWhenParticipantIsExactly17(): void @@ -130,7 +130,7 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertFalse($participant->parking); + self::assertFalse($participant->parking); } public function testProcessFieldAllowsParkingForAdultWithPkw(): void @@ -150,7 +150,7 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertTrue($participant->parking); + self::assertTrue($participant->parking); } public function testProcessFieldAllowsParkingForExactly18YearOld(): void @@ -170,7 +170,7 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertTrue($participant->parking); + self::assertTrue($participant->parking); } public function testProcessFieldClearsParkingWhenNoDateOfBirth(): void @@ -190,8 +190,8 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertFalse($participant->parking); - $this->assertNull($participant->parkingService); + self::assertFalse($participant->parking); + self::assertNull($participant->parkingService); } public function testProcessFieldClearsParkingWhenBabyParticipant(): void @@ -212,8 +212,8 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertFalse($participant->parking); - $this->assertNull($participant->parkingService); + self::assertFalse($participant->parking); + self::assertNull($participant->parkingService); } public function testProcessFieldClearsParkingForChildParticipant(): void @@ -234,7 +234,7 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertFalse($participant->parking); + self::assertFalse($participant->parking); } public function testProcessFieldSetsParkingToFalseWhenNotSelected(): void @@ -253,8 +253,8 @@ class ParticipantParkingFieldHandlerTest extends TestCase $this->handler->processField($submittedData, $bookingDto, 0); - $this->assertFalse($participant->parking); - $this->assertNull($participant->parkingService); + self::assertFalse($participant->parking); + self::assertNull($participant->parkingService); } /** diff --git a/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php b/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php index 064ba465..d05e8285 100644 --- a/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantTransportationDiscountReplacementFieldHandlerTest.php @@ -11,11 +11,14 @@ use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; use App\Form\Service\ParticipantTransportationDiscountReplacementFieldHandler; use App\Service\ServiceAvailabilityCalculator; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestCase { private ParticipantTransportationDiscountReplacementFieldHandler $handler; + + /** @var ServiceAvailabilityCalculator&MockObject */ private ServiceAvailabilityCalculator $serviceAvailabilityCalculator; protected function setUp(): void @@ -28,18 +31,18 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC public function testGetFieldName(): void { - $this->assertSame('transportationDiscountReplacement', $this->handler->getFieldName()); + self::assertSame('transportationDiscountReplacement', $this->handler->getFieldName()); } public function testGetDependencies(): void { - $this->assertSame(['transportationOutbound', 'transportationInbound'], $this->handler->getDependencies()); + self::assertSame(['transportationOutbound', 'transportationInbound'], $this->handler->getDependencies()); } public function testShouldProcessAlwaysReturnsTrue(): void { - $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); - $this->assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); + self::assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); + self::assertTrue($this->handler->shouldProcess(['some' => 'data'], BookingDto::MODE_EDIT, 5)); } public function testProcessFieldReplacesDiscountedWithRegularWhenInboundIsBus(): void @@ -65,16 +68,16 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with regular PKW - $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); - $this->assertSame($regularPkw->label, $participant->transportationOutbound->label); + self::assertSame($regularPkw->id, $participant->transportationOutbound->id); + self::assertSame($regularPkw->label, $participant->transportationOutbound->label); // Assert notification was generated - $this->assertCount(1, $participant->notifications); + self::assertCount(1, $participant->notifications); $notification = reset($participant->notifications); // Get first notification (keyed by MD5 hash) - $this->assertSame('warning', $notification['type']); - $this->assertStringContainsString('Hinfahrt automatisch angepasst', $notification['message']); - $this->assertStringContainsString('Selbstorganisiert (-15€ Rabatt)', $notification['message']); - $this->assertStringContainsString('Selbstorganisiert', $notification['message']); + self::assertSame('warning', $notification['type']); + self::assertStringContainsString('Hinfahrt automatisch angepasst', $notification['message']); + self::assertStringContainsString('Selbstorganisiert (-15€ Rabatt)', $notification['message']); + self::assertStringContainsString('Selbstorganisiert', $notification['message']); } public function testProcessFieldRestoresDiscountedPkwWhenInboundChangesToPkw(): void @@ -96,7 +99,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC // Mock availability: discounted PKW is available $this->serviceAvailabilityCalculator - ->expects($this->once()) + ->expects(self::once()) ->method('isServiceUnavailable') ->with($discountedPkw->id, $bookingDto, 0) ->willReturn(false); @@ -107,15 +110,15 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with discounted PKW - $this->assertSame($discountedPkw->id, $participant->transportationOutbound->id); - $this->assertSame($discountedPkw->label, $participant->transportationOutbound->label); + self::assertSame($discountedPkw->id, $participant->transportationOutbound->id); + self::assertSame($discountedPkw->label, $participant->transportationOutbound->label); // Assert notification was generated - $this->assertCount(1, $participant->notifications); + self::assertCount(1, $participant->notifications); $notification = reset($participant->notifications); // Get first notification (keyed by MD5 hash) - $this->assertSame('success', $notification['type']); - $this->assertStringContainsString('Hinfahrt automatisch angepasst', $notification['message']); - $this->assertStringContainsString('wieder verfügbar', $notification['message']); + self::assertSame('success', $notification['type']); + self::assertStringContainsString('Hinfahrt automatisch angepasst', $notification['message']); + self::assertStringContainsString('wieder verfügbar', $notification['message']); } public function testProcessFieldDoesNotRestoreDiscountWhenUnavailable(): void @@ -137,7 +140,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC // Mock availability: discounted PKW is sold out $this->serviceAvailabilityCalculator - ->expects($this->once()) + ->expects(self::once()) ->method('isServiceUnavailable') ->with($discountedPkw->id, $bookingDto, 0) ->willReturn(true); @@ -148,10 +151,10 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW - $this->assertSame($regularPkw, $participant->transportationOutbound); + self::assertSame($regularPkw, $participant->transportationOutbound); // Assert no notification was generated - $this->assertEmpty($participant->notifications); + self::assertEmpty($participant->notifications); } public function testProcessFieldNoReplacementWhenOutboundIsBus(): void @@ -177,10 +180,10 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound remains BUS (no replacement) - $this->assertSame($busOutbound, $participant->transportationOutbound); + self::assertSame($busOutbound, $participant->transportationOutbound); // Assert no notification was generated - $this->assertEmpty($participant->notifications); + self::assertEmpty($participant->notifications); } public function testProcessFieldNoReplacementWhenOutboundIsRegularPkwAndInboundIsBus(): void @@ -206,10 +209,10 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW (already correct) - $this->assertSame($regularPkw, $participant->transportationOutbound); + self::assertSame($regularPkw, $participant->transportationOutbound); // Assert no notification was generated - $this->assertEmpty($participant->notifications); + self::assertEmpty($participant->notifications); } public function testProcessFieldNoReplacementWhenOutboundIsDiscountedAndInboundIsPkw(): void @@ -235,10 +238,10 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound remains discounted PKW (already optimal) - $this->assertSame($discountedPkw, $participant->transportationOutbound); + self::assertSame($discountedPkw, $participant->transportationOutbound); // Assert no notification was generated - $this->assertEmpty($participant->notifications); + self::assertEmpty($participant->notifications); } public function testProcessFieldHandlesNullOutbound(): void @@ -259,8 +262,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert no error and no notification - $this->assertNull($participant->transportationOutbound); - $this->assertEmpty($participant->notifications); + self::assertNull($participant->transportationOutbound); + self::assertEmpty($participant->notifications); } public function testProcessFieldHandlesNullInbound(): void @@ -281,7 +284,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC // Mock availability: discounted PKW is available $this->serviceAvailabilityCalculator - ->expects($this->once()) + ->expects(self::once()) ->method('isServiceUnavailable') ->with($discountedPkw->id, $bookingDto, 0) ->willReturn(false); @@ -292,8 +295,8 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with discounted PKW - $this->assertSame($discountedPkw->id, $participant->transportationOutbound->id); - $this->assertSame($discountedPkw->label, $participant->transportationOutbound->label); + self::assertSame($discountedPkw->id, $participant->transportationOutbound->id); + self::assertSame($discountedPkw->label, $participant->transportationOutbound->label); } public function testProcessFieldHandlesNullParticipant(): void @@ -333,7 +336,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC // Availability calculator should NOT be called for babies $this->serviceAvailabilityCalculator - ->expects($this->never()) + ->expects(self::never()) ->method('isServiceUnavailable'); $submittedData = []; @@ -342,10 +345,10 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW (no discount restoration for babies) - $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); + self::assertSame($regularPkw->id, $participant->transportationOutbound->id); // Assert no notification was generated - $this->assertEmpty($participant->notifications); + self::assertEmpty($participant->notifications); } public function testProcessFieldSkipsDiscountRestorationForTwoYearOldParticipant(): void @@ -369,7 +372,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC // Availability calculator should NOT be called for babies $this->serviceAvailabilityCalculator - ->expects($this->never()) + ->expects(self::never()) ->method('isServiceUnavailable'); $submittedData = []; @@ -378,10 +381,10 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound remains regular PKW - $this->assertSame($regularPkw->id, $participant->transportationOutbound->id); + self::assertSame($regularPkw->id, $participant->transportationOutbound->id); // Assert no notification was generated - $this->assertEmpty($participant->notifications); + self::assertEmpty($participant->notifications); } public function testProcessFieldRestoresDiscountForThreeYearOldParticipant(): void @@ -406,7 +409,7 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC // Mock availability: discounted PKW is available $this->serviceAvailabilityCalculator - ->expects($this->once()) + ->expects(self::once()) ->method('isServiceUnavailable') ->with($discountedPkw->id, $bookingDto, 0) ->willReturn(false); @@ -417,10 +420,10 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC $this->handler->processField($submittedData, $bookingDto, 0); // Assert outbound was replaced with discounted PKW (3-year-old is eligible) - $this->assertSame($discountedPkw->id, $participant->transportationOutbound->id); + self::assertSame($discountedPkw->id, $participant->transportationOutbound->id); // Assert notification was generated - $this->assertCount(1, $participant->notifications); + self::assertCount(1, $participant->notifications); } private function createPkwService(int $id, string $label, float $price, string $direction = DirectionMapper::OUTBOUND_TRAVEL): Service @@ -447,6 +450,9 @@ class ParticipantTransportationDiscountReplacementFieldHandlerTest extends TestC return $service; } + /** + * @param array $services + */ private function createTravelWithServices(array $services): Travel { $travel = new Travel(); diff --git a/tests/Form/Service/ParticipantVegFieldHandlerTest.php b/tests/Form/Service/ParticipantVegFieldHandlerTest.php index f8bac710..e734de85 100644 --- a/tests/Form/Service/ParticipantVegFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantVegFieldHandlerTest.php @@ -10,6 +10,7 @@ use App\BusProNet\Model\Travel; use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; use App\Form\Service\ParticipantVegFieldHandler; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ParticipantVegFieldHandlerTest extends TestCase @@ -23,22 +24,22 @@ class ParticipantVegFieldHandlerTest extends TestCase public function testGetFieldName(): void { - $this->assertEquals('veg', $this->handler->getFieldName()); + self::assertEquals('veg', $this->handler->getFieldName()); } public function testGetDependencies(): void { $dependencies = $this->handler->getDependencies(); - $this->assertEquals(['dateOfBirth'], $dependencies); + self::assertEquals(['dateOfBirth'], $dependencies); } public function testShouldProcessAlwaysReturnsTrue(): void { // Should always process to handle deselection cases - $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); - $this->assertTrue($this->handler->shouldProcess([], BookingDto::MODE_EDIT, 0)); - $this->assertTrue($this->handler->shouldProcess(['veg' => '123'], BookingDto::MODE_CREATE, 0)); + self::assertTrue($this->handler->shouldProcess([], BookingDto::MODE_CREATE, 0)); + self::assertTrue($this->handler->shouldProcess([], BookingDto::MODE_EDIT, 0)); + self::assertTrue($this->handler->shouldProcess(['veg' => '123'], BookingDto::MODE_CREATE, 0)); } public function testProcessFieldDoesNothingWhenNoParticipant(): void @@ -63,7 +64,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField(['veg' => null], $bookingDto, 0); - $this->assertNull($participant->veg); + self::assertNull($participant->veg); } public function testProcessFieldClearsVegWhenEmptyStringSelection(): void @@ -77,7 +78,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField(['veg' => ''], $bookingDto, 0); - $this->assertNull($participant->veg); + self::assertNull($participant->veg); } public function testProcessFieldClearsVegWhenMissingFromData(): void @@ -91,7 +92,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField([], $bookingDto, 0); - $this->assertNull($participant->veg); + self::assertNull($participant->veg); } public function testProcessFieldClearsVegWhenNotFoundInAvailableServices(): void @@ -105,7 +106,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField(['veg' => '123'], $bookingDto, 0); - $this->assertNull($participant->veg); + self::assertNull($participant->veg); } public function testProcessFieldSetsVegWhenAvailable(): void @@ -119,7 +120,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField(['veg' => '123'], $bookingDto, 0); - $this->assertSame($vegService, $participant->veg); + self::assertSame($vegService, $participant->veg); } public function testProcessFieldWorksWithStringAndIntegerIds(): void @@ -133,7 +134,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField(['veg' => '123'], $bookingDto, 0); // String selection - $this->assertSame($vegService, $participant->veg); + self::assertSame($vegService, $participant->veg); } public function testProcessFieldHandlesEmptyServicesArray(): void @@ -146,7 +147,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField(['veg' => '123'], $bookingDto, 0); - $this->assertNull($participant->veg); + self::assertNull($participant->veg); } public function testProcessFieldSelectsFromMultipleVegOptions(): void @@ -161,7 +162,7 @@ class ParticipantVegFieldHandlerTest extends TestCase $this->handler->processField(['veg' => '2'], $bookingDto, 0); - $this->assertSame($vegan, $participant->veg); + self::assertSame($vegan, $participant->veg); } public function testGetFieldStateModificationsReturnsEmptyArray(): void @@ -170,16 +171,16 @@ class ParticipantVegFieldHandlerTest extends TestCase $result = $this->handler->getFieldStateModifications([], $bookingDto, 0); - $this->assertIsArray($result); - $this->assertEmpty($result); + self::assertIsArray($result); + self::assertEmpty($result); } public function testGetAffectedFieldNamesReturnsEmptyArray(): void { $result = $this->handler->getAffectedFieldNames(); - $this->assertIsArray($result); - $this->assertEmpty($result); + self::assertIsArray($result); + self::assertEmpty($result); } private function createService(int $id, string $label = 'Test Service'): Service @@ -192,6 +193,11 @@ class ParticipantVegFieldHandlerTest extends TestCase return $service; } + /** + * @param array $vegServices + * + * @return Travel&MockObject + */ private function createMockTravel(array $vegServices): Travel { $travel = $this->createMock(Travel::class); @@ -202,6 +208,9 @@ class ParticipantVegFieldHandlerTest extends TestCase return $travel; } + /** + * @return BookingDto&MockObject + */ private function createMockBookingDto(?Travel $travel = null): BookingDto { $bookingDto = $this->createMock(BookingDto::class); diff --git a/tests/Service/BpnXmlAnonymizerTest.php b/tests/Service/BpnXmlAnonymizerTest.php index 70190c03..5663be94 100644 --- a/tests/Service/BpnXmlAnonymizerTest.php +++ b/tests/Service/BpnXmlAnonymizerTest.php @@ -59,7 +59,7 @@ XML; $result = $anonymizer->anonymize($xml); $document = new \DOMDocument(); - $this->assertTrue($document->loadXML($result)); + self::assertTrue($document->loadXML($result)); $xpath = new \DOMXPath($document); @@ -70,13 +70,13 @@ XML; $participantOneMobilePhone = trim((string) $xpath->evaluate('string(//teilnehmer[@id="1"]/kommunikation/telefonmobil)')); $participantTwoName = trim((string) $xpath->evaluate('string(//teilnehmer[@id="2"]/name)')); - $this->assertNotSame('Schlegelmilch', $applicantName); - $this->assertSame($applicantName, $participantOneName); - $this->assertStringEndsWith('@example.com', $participantOneEmail); - $this->assertNotSame('02212722760', $participantOneMobilePhone); - $this->assertSame($applicantMobilePhone, $participantOneMobilePhone); - $this->assertNotSame($participantOneName, $participantTwoName); - $this->assertSame(2, $anonymizer->getLastIdentityCount()); + self::assertNotSame('Schlegelmilch', $applicantName); + self::assertSame($applicantName, $participantOneName); + self::assertStringEndsWith('@example.com', $participantOneEmail); + self::assertNotSame('02212722760', $participantOneMobilePhone); + self::assertSame($applicantMobilePhone, $participantOneMobilePhone); + self::assertNotSame($participantOneName, $participantTwoName); + self::assertSame(2, $anonymizer->getLastIdentityCount()); } public function testAnonymizeReplacesKundeAttributes(): void @@ -99,15 +99,15 @@ XML; $result = $anonymizer->anonymize($xml); $document = new \DOMDocument(); - $this->assertTrue($document->loadXML($result)); + self::assertTrue($document->loadXML($result)); $xpath = new \DOMXPath($document); $firstCustomerLastName = trim((string) $xpath->evaluate('string(//kunde[@id="1"]/@name)')); $firstCustomerFirstName = trim((string) $xpath->evaluate('string(//kunde[@id="1"]/@vorname)')); - $this->assertNotSame('Fromme', $firstCustomerLastName); - $this->assertNotSame('Björn', $firstCustomerFirstName); + self::assertNotSame('Fromme', $firstCustomerLastName); + self::assertNotSame('Björn', $firstCustomerFirstName); } public function testAnonymizeThrowsOnInvalidXml(): void @@ -157,15 +157,15 @@ XML; $result = $anonymizer->anonymize($xml); $document = new \DOMDocument(); - $this->assertTrue($document->loadXML($result)); + self::assertTrue($document->loadXML($result)); $xpath = new \DOMXPath($document); $applicantName = trim((string) $xpath->evaluate('string(//anmelder/name)')); $participantName = trim((string) $xpath->evaluate('string(//teilnehmer[@id="1"]/name)')); - $this->assertSame($applicantName, $participantName); - $this->assertSame(1, $anonymizer->getLastIdentityCount()); + self::assertSame($applicantName, $participantName); + self::assertSame(1, $anonymizer->getLastIdentityCount()); } public function testAnonymizeCanReuseIdentityAcrossMultipleXmlDocuments(): void @@ -205,16 +205,16 @@ XML; $anonymizedResponse = $anonymizer->anonymize($responseXml, false); $requestDocument = new \DOMDocument(); - $this->assertTrue($requestDocument->loadXML($anonymizedRequest)); + self::assertTrue($requestDocument->loadXML($anonymizedRequest)); $requestXpath = new \DOMXPath($requestDocument); $requestName = trim((string) $requestXpath->evaluate('string(//anmelder/name)')); $responseDocument = new \DOMDocument(); - $this->assertTrue($responseDocument->loadXML($anonymizedResponse)); + self::assertTrue($responseDocument->loadXML($anonymizedResponse)); $responseXpath = new \DOMXPath($responseDocument); $responseName = trim((string) $responseXpath->evaluate('string(//teilnehmer[@id="1"]/name)')); - $this->assertSame($requestName, $responseName); - $this->assertSame(1, $anonymizer->getLastIdentityCount()); + self::assertSame($requestName, $responseName); + self::assertSame(1, $anonymizer->getLastIdentityCount()); } } diff --git a/tests/Service/DomainConfigProviderTest.php b/tests/Service/DomainConfigProviderTest.php index 0446b617..f6de8326 100644 --- a/tests/Service/DomainConfigProviderTest.php +++ b/tests/Service/DomainConfigProviderTest.php @@ -24,9 +24,9 @@ class DomainConfigProviderTest extends TestCase $config = $provider->getConfig(); - $this->assertSame('custom', $config->theme); - $this->assertSame('GTM-123', $config->gtmId); - $this->assertSame('https://cmp.example.com', $config->cmpUrl); + self::assertSame('custom', $config->theme); + self::assertSame('GTM-123', $config->gtmId); + self::assertSame('https://cmp.example.com', $config->cmpUrl); } public function testReturnsConfigForSubdomainMatch(): void @@ -41,8 +41,8 @@ class DomainConfigProviderTest extends TestCase $config = $provider->getConfig(); - $this->assertSame('custom', $config->theme); - $this->assertSame('GTM-456', $config->gtmId); + self::assertSame('custom', $config->theme); + self::assertSame('GTM-456', $config->gtmId); } public function testReturnsDefaultConfigForUnknownDomain(): void @@ -57,9 +57,9 @@ class DomainConfigProviderTest extends TestCase $config = $provider->getConfig(); - $this->assertSame(DomainConfig::DEFAULT_THEME, $config->theme); - $this->assertSame('', $config->gtmId); - $this->assertSame('', $config->cmpUrl); + self::assertSame(DomainConfig::DEFAULT_THEME, $config->theme); + self::assertSame('', $config->gtmId); + self::assertSame('', $config->cmpUrl); } public function testReturnsDefaultConfigWhenNoRequest(): void @@ -69,7 +69,7 @@ class DomainConfigProviderTest extends TestCase $config = $provider->getConfig(); - $this->assertSame(DomainConfig::DEFAULT_THEME, $config->theme); + self::assertSame(DomainConfig::DEFAULT_THEME, $config->theme); } public function testHandlesMissingConfigValues(): void @@ -82,9 +82,9 @@ class DomainConfigProviderTest extends TestCase $config = $provider->getConfig(); - $this->assertSame('custom', $config->theme); - $this->assertSame('', $config->gtmId); - $this->assertSame('', $config->cmpUrl); + self::assertSame('custom', $config->theme); + self::assertSame('', $config->gtmId); + self::assertSame('', $config->cmpUrl); } public function testCachesConfigForSameHost(): void @@ -100,7 +100,7 @@ class DomainConfigProviderTest extends TestCase $config1 = $provider->getConfigForHost('example.com'); $config2 = $provider->getConfigForHost('example.com'); - $this->assertSame($config1, $config2); + self::assertSame($config1, $config2); } public function testFirstMatchWins(): void @@ -115,7 +115,7 @@ class DomainConfigProviderTest extends TestCase $config = $provider->getConfig(); - $this->assertSame('portal', $config->theme); + self::assertSame('portal', $config->theme); } public function testCaseInsensitiveMatching(): void @@ -128,7 +128,7 @@ class DomainConfigProviderTest extends TestCase $config = $provider->getConfig(); - $this->assertSame('custom', $config->theme); + self::assertSame('custom', $config->theme); } /** diff --git a/tests/Service/ErrorCodeGeneratorTest.php b/tests/Service/ErrorCodeGeneratorTest.php index 25a2fe45..6194a092 100644 --- a/tests/Service/ErrorCodeGeneratorTest.php +++ b/tests/Service/ErrorCodeGeneratorTest.php @@ -24,7 +24,7 @@ class ErrorCodeGeneratorTest extends TestCase { $result = $this->service->getErrorCode(); - $this->assertNull($result); + self::assertNull($result); } public function testReturnsNullWithoutRequestId(): void @@ -34,7 +34,7 @@ class ErrorCodeGeneratorTest extends TestCase $result = $this->service->getErrorCode(); - $this->assertNull($result); + self::assertNull($result); } public function testGeneratesCodeWithRequestId(): void @@ -45,8 +45,8 @@ class ErrorCodeGeneratorTest extends TestCase $result = $this->service->getErrorCode(); - $this->assertNotNull($result); - $this->assertMatchesRegularExpression('/^E-[A-Z0-9]{8}$/', $result); + self::assertNotNull($result); + self::assertMatchesRegularExpression('/^E-[A-Z0-9]{8}$/', $result); } public function testGeneratesConsistentCodeForSameRequestId(): void @@ -58,7 +58,7 @@ class ErrorCodeGeneratorTest extends TestCase $result1 = $this->service->getErrorCode(); $result2 = $this->service->getErrorCode(); - $this->assertSame($result1, $result2); + self::assertSame($result1, $result2); } public function testGeneratesDifferentCodesForDifferentRequestIds(): void @@ -79,7 +79,7 @@ class ErrorCodeGeneratorTest extends TestCase $service2 = new ErrorCodeGenerator($this->requestStack); $result2 = $service2->getErrorCode(); - $this->assertNotSame($result1, $result2); + self::assertNotSame($result1, $result2); } public function testSequenceSuffixesProduceSameCode(): void @@ -100,7 +100,7 @@ class ErrorCodeGeneratorTest extends TestCase $service2 = new ErrorCodeGenerator($this->requestStack); $result2 = $service2->getErrorCode(); - $this->assertSame($result1, $result2); + self::assertSame($result1, $result2); } public function testSequenceSuffixMatchesBaseId(): void @@ -121,19 +121,19 @@ class ErrorCodeGeneratorTest extends TestCase $service2 = new ErrorCodeGenerator($this->requestStack); $result2 = $service2->getErrorCode(); - $this->assertSame($result1, $result2); + self::assertSame($result1, $result2); } public function testHasErrorReturnsFalseByDefault(): void { - $this->assertFalse($this->service->hasError()); + self::assertFalse($this->service->hasError()); } public function testMarkErrorOccurredSetsFlag(): void { $this->service->markErrorOccurred(); - $this->assertTrue($this->service->hasError()); + self::assertTrue($this->service->hasError()); } public function testHasErrorRemainsTrueAfterMultipleCalls(): void @@ -141,6 +141,6 @@ class ErrorCodeGeneratorTest extends TestCase $this->service->markErrorOccurred(); $this->service->markErrorOccurred(); - $this->assertTrue($this->service->hasError()); + self::assertTrue($this->service->hasError()); } } diff --git a/tests/Service/InsuranceManagerTest.php b/tests/Service/InsuranceManagerTest.php index 95d0ab35..7fba343b 100644 --- a/tests/Service/InsuranceManagerTest.php +++ b/tests/Service/InsuranceManagerTest.php @@ -42,8 +42,8 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getSelectableInsurances($travel); - $this->assertCount(1, $result); - $this->assertSame($regularInsurance, $result[0]); + self::assertCount(1, $result); + self::assertSame($regularInsurance, $result[0]); } public function testGetSelectableInsurancesCachesResults(): void @@ -58,7 +58,7 @@ class InsuranceManagerTest extends TestCase $result1 = $this->service->getSelectableInsurances($travel); $result2 = $this->service->getSelectableInsurances($travel); - $this->assertSame($result1, $result2); + self::assertSame($result1, $result2); } public function testGetEligibleInsurancesWithMatchingCriteria(): void @@ -81,8 +81,8 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertCount(1, $result); - $this->assertContains($insurance, $result); + self::assertCount(1, $result); + self::assertContains($insurance, $result); } public function testGetEligibleInsurancesExcludesInsuranceWithAgeTooYoung(): void @@ -94,7 +94,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithAgeTooOld(): void @@ -106,7 +106,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithTravelDateTooEarly(): void @@ -121,7 +121,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithTravelDateTooLate(): void @@ -136,7 +136,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithBookingDateTooEarly(): void @@ -151,7 +151,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithBookingDateTooLate(): void @@ -166,7 +166,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithTravelPriceTooLow(): void @@ -179,7 +179,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithTravelPriceTooHigh(): void @@ -192,7 +192,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithTravelDurationTooShort(): void @@ -204,7 +204,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesExcludesInsuranceWithTravelDurationTooLong(): void @@ -216,7 +216,7 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertEmpty($result); + self::assertEmpty($result); } public function testGetEligibleInsurancesHandlesParticipantWithoutBirthDate(): void @@ -232,9 +232,9 @@ class InsuranceManagerTest extends TestCase // Participants without birth date should have insurances available // (field visibility is controlled by field state conditions, not service logic) - $this->assertNotEmpty($result); - $this->assertCount(1, $result); - $this->assertSame($insurance, $result[0]); + self::assertNotEmpty($result); + self::assertCount(1, $result); + self::assertSame($insurance, $result[0]); } public function testGetEligibleInsurancesWithNullConstraints(): void @@ -247,8 +247,8 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertCount(1, $result); - $this->assertContains($insurance, $result); + self::assertCount(1, $result); + self::assertContains($insurance, $result); } public function testGetEligibleInsurancesWithMultipleInsurances(): void @@ -263,10 +263,10 @@ class InsuranceManagerTest extends TestCase $insurances = [$eligibleInsurance1, $eligibleInsurance2, $ineligibleInsurance]; $result = $this->service->getEligibleInsurances($insurances, $participant, $booking, 500.0); - $this->assertCount(2, $result); - $this->assertContains($eligibleInsurance1, $result); - $this->assertContains($eligibleInsurance2, $result); - $this->assertNotContains($ineligibleInsurance, $result); + self::assertCount(2, $result); + self::assertContains($eligibleInsurance1, $result); + self::assertContains($eligibleInsurance2, $result); + self::assertNotContains($ineligibleInsurance, $result); } public function testGetEligibleInsurancesWithAgeExactlyAtBoundary(): void @@ -278,8 +278,8 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertCount(1, $result); - $this->assertContains($insurance, $result); + self::assertCount(1, $result); + self::assertContains($insurance, $result); } public function testGetEligibleInsurancesWithTravelDurationExactlyAtBoundary(): void @@ -291,8 +291,8 @@ class InsuranceManagerTest extends TestCase $result = $this->service->getEligibleInsurances([$insurance], $participant, $booking, 500.0); - $this->assertCount(1, $result); - $this->assertContains($insurance, $result); + self::assertCount(1, $result); + self::assertContains($insurance, $result); } public function testFilterByTypeForPackages(): void @@ -319,9 +319,9 @@ class InsuranceManagerTest extends TestCase $insurances = [$packageInsurance1, $packageInsurance2, $differentPackage]; $result = $this->service->filterByType($insurances, $packageInsurance1); - $this->assertCount(2, $result); - $this->assertContains($packageInsurance1, $result); - $this->assertContains($packageInsurance2, $result); + self::assertCount(2, $result); + self::assertContains($packageInsurance1, $result); + self::assertContains($packageInsurance2, $result); } public function testFilterByTypeForIndividualInsurances(): void @@ -348,9 +348,9 @@ class InsuranceManagerTest extends TestCase $insurances = [$insurance1, $insurance2, $differentType]; $result = $this->service->filterByType($insurances, $insurance1); - $this->assertCount(2, $result); - $this->assertContains($insurance1, $result); - $this->assertContains($insurance2, $result); + self::assertCount(2, $result); + self::assertContains($insurance1, $result); + self::assertContains($insurance2, $result); } public function testReassignInsuranceForPriceChange(): void @@ -384,7 +384,7 @@ class InsuranceManagerTest extends TestCase 500.0 ); - $this->assertSame($newTierInsurance, $result); + self::assertSame($newTierInsurance, $result); } public function testBatchAssignInsuranceToParticipants(): void @@ -420,9 +420,9 @@ class InsuranceManagerTest extends TestCase $participantPrices ); - $this->assertCount(2, $result); - $this->assertNotNull($result[0]); - $this->assertNotNull($result[1]); + self::assertCount(2, $result); + self::assertNotNull($result[0]); + self::assertNotNull($result[1]); } private function createParticipant(string $dateOfBirth): ParticipantDto @@ -452,6 +452,9 @@ class InsuranceManagerTest extends TestCase return $travel; } + /** + * @param array $properties + */ private function createInsurance(array $properties = []): Insurance { $insurance = new Insurance(); @@ -462,7 +465,25 @@ class InsuranceManagerTest extends TestCase $insurance->familyInsurance = false; foreach ($properties as $property => $value) { - $insurance->$property = $value; + match ($property) { + 'id' => $insurance->id = (string) $value, + 'complementary' => $insurance->complementary = (bool) $value, + 'package' => $insurance->package = (bool) $value, + 'familyInsurance' => $insurance->familyInsurance = (bool) $value, + 'label' => $insurance->label = (string) $value, + 'subType' => $insurance->subType = null === $value ? null : (string) $value, + 'travelDateFrom' => $insurance->travelDateFrom = $value, + 'travelDateTo' => $insurance->travelDateTo = $value, + 'bookingDateFrom' => $insurance->bookingDateFrom = $value, + 'bookingDateTo' => $insurance->bookingDateTo = $value, + 'travelPriceFrom' => $insurance->travelPriceFrom = null === $value ? null : (float) $value, + 'travelPriceTo' => $insurance->travelPriceTo = null === $value ? null : (float) $value, + 'travelDurationFrom' => $insurance->travelDurationFrom = null === $value ? null : (int) $value, + 'travelDurationTo' => $insurance->travelDurationTo = null === $value ? null : (int) $value, + 'ageFrom' => $insurance->ageFrom = null === $value ? null : (int) $value, + 'ageTo' => $insurance->ageTo = null === $value ? null : (int) $value, + default => null, + }; } return $insurance; diff --git a/tests/Service/ParticipantEligibilityCheckerTest.php b/tests/Service/ParticipantEligibilityCheckerTest.php index 657cce2d..81785b40 100644 --- a/tests/Service/ParticipantEligibilityCheckerTest.php +++ b/tests/Service/ParticipantEligibilityCheckerTest.php @@ -34,7 +34,7 @@ class ParticipantEligibilityCheckerTest extends TestCase $result = $this->service->isParticipantEligible($bookingDto, 0); - $this->assertTrue($result, 'Baby participant (1 year old) should be eligible regardless of ski pass availability'); + self::assertTrue($result, 'Baby participant (1 year old) should be eligible regardless of ski pass availability'); } public function testTwoYearOldParticipantIsEligibleAsBaby(): void @@ -50,7 +50,7 @@ class ParticipantEligibilityCheckerTest extends TestCase $result = $this->service->isParticipantEligible($bookingDto, 0); - $this->assertTrue($result, 'Participant at BABY_MAX_AGE (2 years) should be eligible'); + self::assertTrue($result, 'Participant at BABY_MAX_AGE (2 years) should be eligible'); } public function testThreeYearOldParticipantIsNotBabyEligible(): void @@ -66,7 +66,7 @@ class ParticipantEligibilityCheckerTest extends TestCase $result = $this->service->isParticipantEligible($bookingDto, 0); - $this->assertFalse($result, 'Participant over BABY_MAX_AGE (3 years) should not be eligible without ski passes'); + self::assertFalse($result, 'Participant over BABY_MAX_AGE (3 years) should not be eligible without ski passes'); } public function testAdultParticipantWithSkiPassIsEligible(): void @@ -82,7 +82,7 @@ class ParticipantEligibilityCheckerTest extends TestCase $result = $this->service->isParticipantEligible($bookingDto, 0); - $this->assertTrue($result, 'Adult participant with available ski passes should be eligible'); + self::assertTrue($result, 'Adult participant with available ski passes should be eligible'); } public function testParticipantWithoutDateOfBirthIsNotEligible(): void @@ -98,7 +98,7 @@ class ParticipantEligibilityCheckerTest extends TestCase $result = $this->service->isParticipantEligible($bookingDto, 0); - $this->assertFalse($result, 'Participant without date of birth should not be eligible'); + self::assertFalse($result, 'Participant without date of birth should not be eligible'); } public function testNewbornBabyIsEligible(): void @@ -114,7 +114,7 @@ class ParticipantEligibilityCheckerTest extends TestCase $result = $this->service->isParticipantEligible($bookingDto, 0); - $this->assertTrue($result, 'Newborn baby (0 years old) should be eligible'); + self::assertTrue($result, 'Newborn baby (0 years old) should be eligible'); } public function testBabyAgeIsCalculatedAtTravelDate(): void @@ -135,7 +135,7 @@ class ParticipantEligibilityCheckerTest extends TestCase $result = $this->service->isParticipantEligible($bookingDto, 0); - $this->assertTrue($result, 'Age should be calculated at travel date, not current date'); + self::assertTrue($result, 'Age should be calculated at travel date, not current date'); } private function createTravelWithNoSkiPasses(): Travel diff --git a/tests/Service/RoomAssignerTest.php b/tests/Service/RoomAssignerTest.php index 5ff09c25..0c11d133 100644 --- a/tests/Service/RoomAssignerTest.php +++ b/tests/Service/RoomAssignerTest.php @@ -293,6 +293,9 @@ class RoomAssignerTest extends TestCase self::assertNull($bookingDto->participants[1]->assignedRoomId); } + /** + * @param array $selections + */ private function createBookingDtoWithRoomSelections(array $selections): BookingDto { $travel = new Travel(); diff --git a/tests/Validator/Constraints/ParticipantValidatorTest.php b/tests/Validator/Constraints/ParticipantValidatorTest.php index 362a4554..8ec82bf8 100644 --- a/tests/Validator/Constraints/ParticipantValidatorTest.php +++ b/tests/Validator/Constraints/ParticipantValidatorTest.php @@ -11,6 +11,7 @@ use App\Validator\Constraints\Participant; use App\Validator\Constraints\ParticipantValidator; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; +/** @extends ConstraintValidatorTestCase */ class ParticipantValidatorTest extends ConstraintValidatorTestCase { protected function createValidator(): ParticipantValidator @@ -155,7 +156,7 @@ class ParticipantValidatorTest extends ConstraintValidatorTestCase $this->buildViolation('Bitte auswählen') ->atPath('property.path.dropOff') ->assertRaised(); - $this->assertCount(1, $this->context->getViolations()); + self::assertCount(1, $this->context->getViolations()); } public function testParticipantWithNonBusTransportationPassesPickupValidation(): void diff --git a/tests/Validator/Constraints/RoomSelectionValidatorTest.php b/tests/Validator/Constraints/RoomSelectionValidatorTest.php index 0eb2baca..ac8d4ed9 100644 --- a/tests/Validator/Constraints/RoomSelectionValidatorTest.php +++ b/tests/Validator/Constraints/RoomSelectionValidatorTest.php @@ -12,6 +12,9 @@ use App\Validator\Constraints\RoomSelection; use App\Validator\Constraints\RoomSelectionValidator; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; +/** + * @extends ConstraintValidatorTestCase + */ class RoomSelectionValidatorTest extends ConstraintValidatorTestCase { protected function createValidator(): RoomSelectionValidator