new FeatureStatus(DiviFeature::PageRead, ReleaseState::Released, [], 'code'), // Under the wrong key: does not count for page-write. 'page-write' => new FeatureStatus(DiviFeature::PageRead, ReleaseState::Released, [], 'code'), ]); self::assertTrue($matrix->of(DiviFeature::PageRead)->usable()); foreach ([DiviFeature::PageWrite, DiviFeature::ThemeBuilderWrite] as $feature) { $status = $matrix->of($feature); self::assertSame(ReleaseState::Incompatible, $status->state); self::assertSame([CompatibilityMatrix::MISSING], $status->problems); } self::assertCount(count(DiviFeature::cases()) - 1, $matrix->unusable()); } public function testAllReleasedAndAllIncompatible(): void { $released = CompatibilityMatrix::allReleased('database'); $broken = CompatibilityMatrix::allIncompatible('kaputt'); foreach (DiviFeature::cases() as $feature) { self::assertTrue($released->of($feature)->usable()); self::assertSame('database', $released->of($feature)->source); self::assertSame(ReleaseState::Incompatible, $broken->of($feature)->state); self::assertSame(['kaputt'], $broken->of($feature)->problems); self::assertNull($broken->of($feature)->source); } self::assertSame([], $released->unusable()); self::assertSame('code', CompatibilityMatrix::allReleased()->source()); } public function testTheStateIsTheWorstFeatureAndEveryProblemIsListedOnce(): void { $matrix = self::matrix([ 'page-write' => [ReleaseState::Untested, ['a']], 'tb-write' => [ReleaseState::Incompatible, ['b', 'a']], ]); self::assertSame(ReleaseState::Incompatible, $matrix->state()); self::assertSame(['a', 'b'], $matrix->problems()); self::assertNull($matrix->source()); self::assertSame(ReleaseState::Untested, self::matrix(['catalog' => [ReleaseState::Untested, []]])->state()); self::assertSame(ReleaseState::Released, self::matrix([])->state()); } public function testTheSourceOfAReleasedMatrixIsCommonOrNull(): void { self::assertSame('auto', self::matrix([])->source()); $mixed = new CompatibilityMatrix(array_merge( self::features([]), ['roles' => new FeatureStatus(DiviFeature::Roles, ReleaseState::Released, [], 'code')] )); self::assertSame(ReleaseState::Released, $mixed->state()); self::assertNull($mixed->source()); } public function testUsableAndUnusable(): void { $matrix = self::matrix(['catalog' => [ReleaseState::Untested, []]]); self::assertTrue($matrix->usable([DiviFeature::PageWrite, DiviFeature::PageRead])); self::assertFalse($matrix->usable([DiviFeature::PageWrite, DiviFeature::Catalog])); self::assertTrue($matrix->usable([])); self::assertSame( [DiviFeature::Catalog], array_map(static fn (FeatureStatus $status): DiviFeature => $status->feature, $matrix->unusable()) ); } public function testToArrayListsEveryFeatureInCaseOrder(): void { $rows = self::matrix(['tb-write' => [ReleaseState::Incompatible, ['b']]])->toArray(); self::assertSame( array_map(static fn (DiviFeature $feature): string => $feature->value, DiviFeature::cases()), array_column($rows, 'id') ); self::assertContains( ['id' => 'tb-write', 'label' => DiviFeature::ThemeBuilderWrite->label(), 'state' => 'incompatible', 'problems' => ['b'], 'source' => null], $rows ); } /** * @param array}> $locked * @return array */ private static function features(array $locked): array { $features = []; foreach (DiviFeature::cases() as $feature) { [$state, $problems] = $locked[$feature->value] ?? [ReleaseState::Released, []]; $features[$feature->value] = new FeatureStatus( $feature, $state, $problems, $state === ReleaseState::Released ? 'auto' : null ); } return $features; } /** @param array}> $locked */ private static function matrix(array $locked): CompatibilityMatrix { return new CompatibilityMatrix(self::features($locked)); } }