Skip to content

S007: Path & Namespace Mapping

FieldValue
SpecS007
FeaturePath & Namespace Mapping
Date2026-04-23
StatusDraft
Authorspec-writer-agent

Overview

Path & Namespace Mapping is the core resolution layer that connects PHP source files to their expected test files and converts file paths to fully qualified class names (FQCNs). Every other Parity module depends on this mapping being correct: the rules system needs accurate test paths to check existence, coverage linkers need accurate FQCNs to validate declarations, and the output layer needs both to produce meaningful reports.

The module has three responsibilities. First, the NamespaceHelper class converts between relative file paths and PHP FQCNs using configurable PSR-4 style namespace_roots mappings (e.g. app/ maps to App\). Second, the source-to-test path derivation algorithm takes a source file path, strips the source directory prefix, appends a configurable test suffix, and places it under the corresponding test directory. Third, file_map overrides allow explicit source-to-test path mappings that bypass the algorithmic derivation entirely, supporting non-standard naming conventions.

Multiple structure blocks can coexist in a single parity.yaml, each defining independent source-to-test mappings with their own rules. A source file in app/Http/Controllers/ might map to tests/Feature/Controllers/ while app/Services/ maps to tests/Unit/Services/. The mapping logic must handle overlapping prefixes, deeply nested subdirectories, platform-specific path separators, and edge cases like missing namespace roots or files at the root of a source directory.

User Scenarios

S007-US-001 [P1] As a developer, I want Parity to automatically derive the expected test file path from any source file path so that I do not need to specify each mapping manually.

S007-US-002 [P1] As a developer, I want Parity to convert file paths to FQCNs so that coverage linkers can match CoversClass declarations against the correct source class.

S007-US-003 [P1] As a developer with non-standard test naming, I want to use file_map to override the default path derivation so that Parity can handle legacy or unusual file relationships.

S007-US-004 [P1] As a developer on a Laravel project, I want to configure multiple structure blocks (unit, feature, integration) so that different parts of my codebase map to different test directories.

S007-US-005 [P2] As a developer on a non-PHP project, I want to configure custom namespace_separator, source_extension, test_suffix, and test_extension so that Parity can work with other languages.

Requirements Summary

IDTypePriorityTitleStatus
S007-FR-001FunctionalP1pathToFqcn converts relative paths to FQCNsDraft
S007-FR-002FunctionalP1Namespace root matching is case-insensitive on first segmentDraft
S007-FR-003FunctionalP1Default fallback when no namespace root matchesDraft
S007-FR-004FunctionalP1pathToFqcn strips source extension before conversionDraft
S007-FR-005FunctionalP1pathToFqcn normalizes backslashes to forward slashesDraft
S007-FR-006FunctionalP1pathToFqcn strips leading slash from inputDraft
S007-FR-007FunctionalP1sourcePathToTestPath derives test path from source pathDraft
S007-FR-008FunctionalP1sourcePathToTestPath appends test suffix before extensionDraft
S007-FR-009FunctionalP1sourcePathToTestPath preserves subdirectory structureDraft
S007-FR-010FunctionalP1sourcePathToTestPath handles source file not under source baseDraft
S007-FR-011FunctionalP1file_map overrides bypass algorithmic derivationDraft
S007-FR-012FunctionalP1file_map paths are relative to structure source/test dirsDraft
S007-FR-013FunctionalP1Multiple structure blocks operate independentlyDraft
S007-FR-014FunctionalP1normalizeRelativePath produces consistent pathsDraft
S007-FR-015FunctionalP2Configurable namespace separatorDraft
S007-FR-016FunctionalP2Configurable source and test extensionsDraft
S007-FR-017FunctionalP1NamespaceHelper constructor accepts Settings or raw rootsDraft
S007-IF-001InterfaceP1NamespaceHelper::pathToFqcn signatureDraft
S007-IF-002InterfaceP1NamespaceHelper::sourcePathToTestPath signatureDraft
S007-IF-003InterfaceP1NamespaceHelper::normalizeRelativePath signatureDraft
S007-IF-004InterfaceP1NamespaceHelper constructor overloadsDraft
S007-IF-005InterfaceP1Structure block config schemaDraft
S007-IF-006InterfaceP1file_map config schemaDraft
S007-AS-001AcceptanceP1Standard Laravel source-to-FQCN conversionDraft
S007-AS-002AcceptanceP1Standard test path derivationDraft
S007-AS-003AcceptanceP1file_map override appliedDraft
S007-AS-004AcceptanceP1Multiple structure blocks each resolve independentlyDraft
S007-AS-005AcceptanceP1Deeply nested path conversionDraft
S007-AS-006AcceptanceP1Test directory FQCN resolutionDraft
S007-AS-007AcceptanceP2Custom namespace separatorDraft
S007-AS-008AcceptanceP1End-to-end check command uses mappingDraft
S007-EC-001Edge CaseP1Missing namespace root for first segmentDraft
S007-EC-002Edge CaseP1Leading backslash in input pathDraft
S007-EC-003Edge CaseP1Windows backslash path separatorsDraft
S007-EC-004Edge CaseP1Double slashes in pathDraft
S007-EC-005Edge CaseP1Source file at root of source directory (no subdirectory)Draft
S007-EC-006Edge CaseP1Source path does not start with source base prefixDraft
S007-EC-007Edge CaseP2Empty file_map valueDraft
S007-EC-008Edge CaseP1Trailing slashes in source/test base pathsDraft
S007-EC-009Edge CaseP2Namespace root with nested directory prefixDraft
S007-EC-010Edge CaseP1Case mismatch between path and namespace rootDraft
S007-EC-011Edge CaseP2Source extension not present on input pathDraft
S007-EC-012Edge CaseP2Empty or single-segment pathDraft
S007-SC-001SuccessP1All PSR-4 path-to-FQCN conversions are correctDraft
S007-SC-002SuccessP1All source-to-test path derivations are correctDraft
S007-SC-003SuccessP1file_map overrides take precedence over derivationDraft
S007-SC-004SuccessP1Path normalization is idempotentDraft
S007-SC-005SuccessP1Multiple structure blocks produce no cross-contaminationDraft

Cross-Spec Dependencies

  • Depends on: S006 (Configuration -- provides namespace_roots, test_suffix, test_extension, source_extension, namespace_separator, structure blocks, and file_map config)
  • Required by: S002 (Rules System -- test-exists rule relies on derived test paths), S004 (Coverage Linkers -- uses FQCNs produced by pathToFqcn to validate coverage declarations), S001 (CLI Commands -- check command orchestrates the full mapping pipeline)