S006 Edge Cases
| ID | Scenario | Expected Behavior |
|---|---|---|
| S006-EC-001 | settings key is entirely absent from parity.yaml | Settings::fromConfig() uses $config['settings'] ?? [] which yields an empty array. All settings fields receive their defaults: namespaceRoots = {'app': 'App', 'tests': 'Tests'}, sourceExtension = ".php", testSuffix = "Test", testExtension = ".php", namespaceSeparator = "\\". No error is raised. |
| S006-EC-002 | parity.yaml file exists but is completely empty (zero bytes) | Yaml::parse('') returns null. loadConfig() checks is_array($config) which is false for null, so it returns null. The check command receives null from loadConfig() and returns exit code 1. |
| S006-EC-003 | coverage_xml is a string "clover.xml" instead of an array | resolveCoveragePaths() checks is_array($coverageXml) which is false, so it wraps the string: ['clover.xml']. No error. The single candidate is used for coverage file discovery. |
| S006-EC-004 | namespace_roots key is absent from the settings block | Default ['app' => 'App', 'tests' => 'Tests'] is applied via null coalescing. No error. NamespaceHelper operates with standard PHP/Laravel roots. |
| S006-EC-005 | Config contains unknown top-level keys (e.g., plugins: [...], experimental: true) | Unknown keys are silently ignored. The system only reads known keys (settings, coverage_xml, min_coverage, min_coverage_global, min_matched_coverage, structure). Forward-compatible -- future config keys do not break older versions. |
| S006-EC-006 | A structure entry has paths: {} (empty object, missing source and test) | resolvePath() returns (string) ($entry['paths']['source'] ?? '') which is "". The source directory resolves to $projectRoot . '/' which may or may not exist. If it does not exist as a directory, the check command prints Source path does not exist: and skips the entry. |
| S006-EC-007 | structure key is present with value [] (empty array) | The check command detects $structures === [], prints warning: No structure entries in parity.yaml., and returns exit code 0 (success, since no violations are possible). |
| S006-EC-008 | file_map in a structure entry is set to a non-array value (e.g., file_map: true or file_map: null) | The check command evaluates isset($entry['file_map']) && is_array($entry['file_map']). For non-array values this is false, so $fileMap defaults to [] (empty array). No error. All files use standard naming. |
| S006-EC-009 | min_coverage is provided as a string "80" instead of a number 80 | The (float) cast in fromConfig() converts the string to 80.0. YAML parsing may also convert unquoted numbers automatically. No error in either case. |
| S006-EC-010 | min_coverage is set to a negative value (e.g., -10) or a value above 100 (e.g., 150) | The system does not validate coverage threshold ranges. (float) -10 produces -10.0 and (float) 150 produces 150.0. With -10, all files trivially pass the threshold. With 150, all files trivially fail. No error is raised at config parse time. |
| S006-EC-011 | A structure entry contains both modern (paths, rules) and legacy (source_path, enforce_attribute) keys | The modern keys take precedence. resolvePath() checks $entry['paths'] first and uses it if present. resolveStructureRules() checks for $entry['rules'] first and uses the modern format if present. Legacy keys are ignored when modern keys exist. |
| S006-EC-012 | parity.yaml contains valid YAML that parses to a scalar (e.g., file contains only 42 or "hello") | Yaml::parse() returns a non-array value. loadConfig() checks is_array($config) which is false, returns null. The check command receives null and returns exit code 1. |
| S006-EC-013 | test_extension is not set but source_extension is set to ".ts" | fromConfig() evaluates $settingsBlock['test_extension'] ?? ($settingsBlock['source_extension'] ?? '.php'). Since test_extension is absent, it falls through to source_extension which is ".ts". Result: testExtension = ".ts". The test_extension correctly inherits from source_extension. |
| S006-EC-014 | coverage_xml is an array containing non-string elements (e.g., [clover.xml, 42, true, null]) | resolveCoveragePaths() returns the array as-is without type validation. During coverage file discovery, each candidate is cast to string via (string) $candidate when building the path. 42 becomes "42", true becomes "1", null becomes "". These are unlikely to match real files but no error is raised at config parse time. |
| S006-EC-015 | Structure entry has rules: [minimum-coverage: {min: 80}] but no test-exists in the list | resolveStructureRules() inspects the rules array, finds that test-exists is not present (checking both string entries and map keys), and auto-prepends it. The resolved rules become [test-exists, minimum-coverage]. |

