PluginProbe ʕ •ᴥ•ʔ
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More / 2.11.0
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More v2.11.0
2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.7 2.6.8 2.6.5 2.6.4 2.6.3 2.6.2 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 trunk 1.0 1.0.1 1.0.2 1.0.3 1.1 1.1.1 1.1.2 1.2.0 2.0 2.1.0 2.1.1 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1
reviews-feed / tests / Unit / Smash1987NestedSourceErrorShapeTest.php
reviews-feed / tests / Unit Last commit date
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
Smash1987NestedSourceErrorShapeTest.php
220 lines
1 <?php
2
3 namespace SmashBalloon\Reviews\Tests\Unit;
4
5 use PHPUnit\Framework\TestCase;
6 use SmashBalloon\Reviews\Common\Builder\SBR_Feed_Saver_Manager;
7
8 /**
9 * SMASH-1987 — a relay source error can arrive as an object, and every check in
10 * process_source_apikey() compared it to a string.
11 *
12 * Captured verbatim from staging on 2026-08-25, adding a TripAdvisor source with an
13 * invalid key. Note the HTTP 200 and envelope `success: true`: the only failure signal
14 * is inside `info`.
15 *
16 * {"message":"OK","success":true,"data":{"info":{
17 * "errorId":"sourceConnectionError",
18 * "error":{"provider":"tripadvisor","message":"Please make sure you have provided
19 * the right API Key.","reason":"Invalid API Key","error":"invalidKey"}}}}
20 *
21 * Consequences before the fix, all measured: the error gate missed it, `$checkValidKey`
22 * evaluated TRUE because an array is never equal to 'invalidKey' (so a bad key would be
23 * stored as valid), `apikey => invalid` was never set, and the response carried no
24 * message — indistinguishable from success to the modal.
25 */
26 final class Smash1987NestedSourceErrorShapeTest extends TestCase
27 {
28 /**
29 * @return array<string,mixed>
30 */
31 private static function nestedShape(): array
32 {
33 return [
34 'info' => [
35 'errorId' => 'sourceConnectionError',
36 'error' => [
37 'provider' => 'tripadvisor',
38 'message' => 'Please make sure you have provided the right API Key.',
39 'status' => 'User is not authorized to access this resource with an explicit deny in an identity-based policy',
40 'placeId' => '13871137',
41 'reason' => 'Invalid API Key',
42 'error' => 'invalidKey',
43 ],
44 ],
45 ];
46 }
47
48 public function test_the_code_is_read_out_of_the_nested_object(): void
49 {
50 $this->assertSame('invalidKey', SBR_Feed_Saver_Manager::get_source_error_code(self::nestedShape()));
51 }
52
53 public function test_the_message_is_read_out_of_the_nested_object(): void
54 {
55 $this->assertSame(
56 'Please make sure you have provided the right API Key.',
57 SBR_Feed_Saver_Manager::get_source_error_message(self::nestedShape())
58 );
59 }
60
61 /**
62 * The inversion that made a bad key look good. Kept as an explicit assertion
63 * because it is the part with a write side effect.
64 */
65 public function test_a_nested_invalid_key_is_not_treated_as_a_valid_key(): void
66 {
67 $info = self::nestedShape();
68 $error_code = SBR_Feed_Saver_Manager::get_source_error_code($info);
69
70 $checkValidKey = (
71 $error_code !== null && $error_code !== 'invalidKey'
72 )
73 || !empty($info['info']['id'])
74 || !empty($info['info']['successId']);
75
76 $this->assertFalse($checkValidKey, 'an invalid key must never satisfy the store-the-key gate');
77
78 // The pre-fix expression, pinned so a revert fails here rather than in production.
79 $old = (
80 !empty($info['info']['error']) && $info['info']['error'] !== 'invalidKey'
81 )
82 || !empty($info['info']['id']);
83 $this->assertTrue($old, 'if this is false the shape changed and this test is moot');
84 }
85
86 /**
87 * BACKWARDS COMPATIBILITY (Rule 6) — the string shape other providers send must
88 * resolve exactly as it did, so this fix cannot alter their behaviour.
89 *
90 * @dataProvider stringShapeProvider
91 */
92 public function test_string_shapes_are_unchanged(string $code): void
93 {
94 $this->assertSame(
95 $code,
96 SBR_Feed_Saver_Manager::get_source_error_code(['info' => ['error' => $code]])
97 );
98 }
99
100 /**
101 * @return array<string,array{0:string}>
102 */
103 public static function stringShapeProvider(): array
104 {
105 return [
106 'invalidKey' => ['invalidKey'],
107 'invalidLocation' => ['invalidLocation'],
108 'someFutureCode' => ['someFutureCode'],
109 ];
110 }
111
112 /**
113 * @dataProvider noErrorProvider
114 * @param array<string,mixed> $info
115 */
116 public function test_a_successful_response_reports_no_error(array $info): void
117 {
118 $this->assertNull(SBR_Feed_Saver_Manager::get_source_error_code($info));
119 }
120
121 /**
122 * @return array<string,array{0:array<string,mixed>}>
123 */
124 public static function noErrorProvider(): array
125 {
126 return [
127 'source added' => [['info' => ['id' => '13871137', 'name' => 'Hotel Colline de France']]],
128 'empty error key' => [['info' => ['id' => '1', 'error' => '']]],
129 'no info at all' => [[]],
130 'info not array' => [['info' => 'unexpected']],
131 ];
132 }
133
134 /**
135 * An errorId alone is failure, but not a NAMED failure.
136 *
137 * The first version of this fix returned the errorId from get_source_error_code(),
138 * which fed the gate deciding whether to store a submitted key. An errorId is never
139 * literally 'invalidKey', so that gate opened and an invalid key was persisted as
140 * valid — worse than the bug being fixed, and a regression against the pre-fix code,
141 * where an absent info.error left the gate shut.
142 */
143 public function test_an_error_id_alone_is_not_a_named_code(): void
144 {
145 $info = ['info' => ['errorId' => 'sourceConnectionError']];
146
147 $this->assertNull(
148 SBR_Feed_Saver_Manager::get_source_error_code($info),
149 'an opaque errorId must not present itself as a specific error code'
150 );
151 $this->assertSame(
152 'sourceConnectionError',
153 SBR_Feed_Saver_Manager::get_source_error_id($info),
154 'but it must still be reportable as a failure'
155 );
156 }
157
158 /**
159 * The gate itself, pinned. This is the expression in process_source_apikey() that
160 * decides whether update_provider_apikey() runs.
161 *
162 * @dataProvider gateProvider
163 * @param array<string,mixed> $info
164 */
165 public function test_only_a_named_non_key_error_may_store_the_key(array $info, bool $expected, string $why): void
166 {
167 $error_code = SBR_Feed_Saver_Manager::get_source_error_code($info);
168
169 $checkValidKey = (
170 $error_code !== null && $error_code !== 'invalidKey'
171 )
172 || !empty($info['info']['id'])
173 || !empty($info['info']['successId']);
174
175 $this->assertSame($expected, $checkValidKey, $why);
176 }
177
178 /**
179 * @return array<string,array{0:array<string,mixed>,1:bool,2:string}>
180 */
181 public static function gateProvider(): array
182 {
183 return [
184 'errorId only' => [
185 ['info' => ['errorId' => 'sourceConnectionError']],
186 false,
187 'an unnamed failure is no evidence the key works',
188 ],
189 'nested invalidKey' => [
190 ['info' => ['errorId' => 'sourceConnectionError', 'error' => ['error' => 'invalidKey']]],
191 false,
192 'an invalid key must never store',
193 ],
194 'string invalidKey' => [
195 ['info' => ['error' => 'invalidKey']],
196 false,
197 'the string shape must behave as it always did',
198 ],
199 'invalidLocation' => [
200 ['info' => ['error' => 'invalidLocation']],
201 true,
202 'a wrong location proves the key reached far enough to be told so',
203 ],
204 'source returned' => [
205 ['info' => ['id' => '13871137']],
206 true,
207 'a created source is the plainest evidence of a working key',
208 ],
209 ];
210 }
211
212 public function test_the_message_falls_back_when_the_relay_sends_only_a_code(): void
213 {
214 $this->assertNotSame(
215 '',
216 SBR_Feed_Saver_Manager::get_source_error_message(['info' => ['error' => 'invalidKey']])
217 );
218 }
219 }
220