Doubles
1 week ago
Providers
1 week ago
BulkRearmOnGrowthTest.php
1 week ago
BulkReviewsUpdateStuckStateTest.php
1 week ago
ClearCacheRelayResetTest.php
1 week ago
DeleteSourceRelayFailureTest.php
1 week ago
ErrorHandlerFalsyOptionTest.php
1 week ago
FeedCacheUpdateServiceTest.php
1 week ago
FeedMalformedPayloadTest.php
1 week ago
ForceKeylessRefetchTest.php
1 week ago
LicenseDeactivateStaleStateTest.php
1 week ago
MediaFinderMemoTest.php
1 week ago
MultiSourceAggregationTest.php
1 week ago
ReconcileMigratedLicenseRoutineTest.php
1 week ago
ReconcileRemovalTest.php
1 week ago
RegisterWebsiteRoutineTest.php
1 week ago
RelaySlowEndpointsTest.php
1 week ago
RemoteRequestMemoTest.php
1 week ago
ReviewAlertHeaderTotalsTest.php
1 week ago
ReviewAlertPageTargetingTest.php
1 week ago
ReviewAlertStarFillTest.php
1 week ago
ShortcodeNeutralizationTest.php
1 week ago
SiteMigrationRecoveryTest.php
1 week ago
Smash1130UsageTrackingHardeningTest.php
1 week ago
Smash1130UsageTrackingHooksTest.php
1 week ago
Smash1583HeaderParityTest.php
1 week ago
Smash1631MultiLanguageBulkTest.php
1 week ago
Smash1631UpdateSingleLangScopeTest.php
1 week ago
Smash1706TripAdvisorPlaceIdTest.php
1 week ago
Smash1756SchemaServiceTest.php
1 week ago
Smash1785AvatarLocalUrlGuardTest.php
1 week ago
Smash1785AvatarReHealTest.php
1 week ago
Smash1795ReviewTextXssTest.php
1 week ago
Smash1835TripAdvisorKeyShapeTest.php
1 week ago
Smash1973WordpressOrgPlaceIdNullTest.php
1 week ago
Smash1987NestedSourceErrorShapeTest.php
1 week ago
Smash782BookingHeaderRatingTest.php
1 week ago
Smash782CountryFlagEmojiTest.php
1 week ago
Smash782ExternalRefreshCronTest.php
1 week ago
Smash782ExtrasTemplateTest.php
1 week ago
Smash782ReviewAlertProviderDataTest.php
1 week ago
SourceIdLookupTest.php
1 week ago
WpmlGetCurrentLanguageTest.php
1 week ago
WpmlLanguageMappingTest.php
1 week ago
Smash1835TripAdvisorKeyShapeTest.php
98 lines
| 1 | <?php |
| 2 | |
| 3 | namespace SmashBalloon\Reviews\Tests\Unit; |
| 4 | |
| 5 | use PHPUnit\Framework\TestCase; |
| 6 | use SmashBalloon\Reviews\Common\Util; |
| 7 | |
| 8 | /** |
| 9 | * Pins Util::is_tripadvisor_terra_key() — the discriminator that decides whether |
| 10 | * a site sees the Content API sunset notice (SMASH-1835). |
| 11 | * |
| 12 | * TripAdvisor deprecates every legacy Content API key on 2026-08-31. Legacy keys |
| 13 | * are 32 hex characters, Terra issues UUIDs, and the two sets cannot overlap, |
| 14 | * which is what lets both the relay route per key and the plugin warn only the |
| 15 | * sites that actually have to act. Get this wrong in either direction and the |
| 16 | * cost is real: a false positive nags someone who already migrated, a false |
| 17 | * negative leaves a site silently heading into a dead API. |
| 18 | * |
| 19 | * The shipped contract is a denylist, not an allowlist: the notice fires for any |
| 20 | * stored key that is NOT a Terra UUID, rather than only for a 32-hex one. Those |
| 21 | * agree today, because 32-hex and UUIDs are the only two shapes in the field. |
| 22 | * They diverge if TripAdvisor ever issues a Terra credential in a third shape, |
| 23 | * and it errs toward warning — deliberately, since a missed warning ends in a |
| 24 | * dead feed while a spurious one is a support conversation. |
| 25 | * |
| 26 | * Mirror of TripAdvisor::looksLikeTerraKey() in sb-relay — if one moves, so does |
| 27 | * the other. |
| 28 | * |
| 29 | * Pure static, so it runs in the plain-PHPUnit suite with no WordPress. |
| 30 | */ |
| 31 | final class Smash1835TripAdvisorKeyShapeTest extends TestCase |
| 32 | { |
| 33 | /** |
| 34 | * @dataProvider provideKeys |
| 35 | * |
| 36 | * @param string $key |
| 37 | * @param bool $expected |
| 38 | */ |
| 39 | public function test_is_tripadvisor_terra_key($key, $expected): void |
| 40 | { |
| 41 | $this->assertSame($expected, Util::is_tripadvisor_terra_key($key)); |
| 42 | } |
| 43 | |
| 44 | /** @return array<string, array{0: string, 1: bool}> */ |
| 45 | public static function provideKeys(): array |
| 46 | { |
| 47 | return [ |
| 48 | // --- Terra: UUID layout. Shape taken from a real Terra key. --- |
| 49 | 'uuid lowercase' => ['3f1c9a52-7b64-4d0e-9c31-8a5f2e6b0d47', true], |
| 50 | 'uuid uppercase' => ['3F1C9A52-7B64-4D0E-9C31-8A5F2E6B0D47', true], |
| 51 | 'uuid mixed case' => ['3f1C9a52-7B64-4d0E-9c31-8A5f2E6b0D47', true], |
| 52 | |
| 53 | // --- Legacy: 32 hex, no dashes. Must never read as Terra, or the |
| 54 | // site loses the notice and walks into the sunset unwarned. --- |
| 55 | 'legacy 32 hex' => ['a3f19c527b644d0e9c318a5f2e6b0d47', false], |
| 56 | 'legacy 32 hex uppercase' => ['A3F19C527B644D0E9C318A5F2E6B0D47', false], |
| 57 | |
| 58 | // --- Near misses. A UUID-ish string that is not one must not pass. --- |
| 59 | 'uuid minus one char' => ['3f1c9a52-7b64-4d0e-9c31-8a5f2e6b0d4', false], |
| 60 | 'uuid plus one char' => ['3f1c9a52-7b64-4d0e-9c31-8a5f2e6b0d477', false], |
| 61 | 'uuid with a non-hex letter' => ['3f1c9a52-7b64-4d0e-9c31-8a5f2e6b0dZZ', false], |
| 62 | 'dashes in the wrong places' => ['3f1c9a5-27b644-d0e9c31-8a5f2e6b0d47', false], |
| 63 | '32 hex with dashes stripped from a uuid' => ['3f1c9a527b644d0e9c318a5f2e6b0d47', false], |
| 64 | |
| 65 | // --- Junk. None of this should be treated as migrated. --- |
| 66 | 'empty' => ['', false], |
| 67 | 'whitespace only' => [' ', false], |
| 68 | 'uuid with surrounding whitespace' => [' 3f1c9a52-7b64-4d0e-9c31-8a5f2e6b0d47 ', false], |
| 69 | 'arbitrary word' => ['not-a-key', false], |
| 70 | ]; |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * The helper takes whatever is in the options row, which is not guaranteed to |
| 75 | * be a string. A non-string must be "not migrated" rather than a TypeError on |
| 76 | * preg_match(). |
| 77 | * |
| 78 | * @dataProvider provideNonStrings |
| 79 | * |
| 80 | * @param mixed $key |
| 81 | */ |
| 82 | public function test_non_string_is_not_a_terra_key($key): void |
| 83 | { |
| 84 | $this->assertFalse(Util::is_tripadvisor_terra_key($key)); |
| 85 | } |
| 86 | |
| 87 | /** @return array<string, array{0: mixed}> */ |
| 88 | public static function provideNonStrings(): array |
| 89 | { |
| 90 | return [ |
| 91 | 'null' => [null], |
| 92 | 'int' => [12345], |
| 93 | 'array' => [['3f1c9a52-7b64-4d0e-9c31-8a5f2e6b0d47']], |
| 94 | 'bool' => [false], |
| 95 | ]; |
| 96 | } |
| 97 | } |
| 98 |