Skip to content

Commit 5dc93aa

Browse files
authored
test: coverage improvements and chores (#65)
## This PR - test: add shared base hook classes cases - fix!: rename finallyAfter to finally in AbstractHook - refactor: default to set NoOpProvider - chore: cleanup commented code for $_SESSION - test: can get version from Client - feat: hook execution reversal - test: cases for NoOpClient - test: implement decapitalize unit tests ### Related Issues Fixes #54 Fixes #64 Fixes #55 Fixes #63 Fixes #57 Fixes #62 Fixes #59 Fixes #60 Signed-off-by: Tom Carrio <[email protected]>
1 parent 446648a commit 5dc93aa

File tree

7 files changed

+343
-28
lines changed

7 files changed

+343
-28
lines changed

src/OpenFeatureAPI.php

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,13 @@
1919
use function array_merge;
2020
use function is_null;
2121

22-
class OpenFeatureAPI implements API, LoggerAwareInterface
22+
final class OpenFeatureAPI implements API, LoggerAwareInterface
2323
{
2424
use LoggerAwareTrait;
2525

2626
private static ?OpenFeatureAPI $instance = null;
2727

28-
//// TODO: Support global using $_SESSION?
29-
// private const GLOBAL_OPEN_FEATURE_KEY = '__OPENFEATURE_INSTANCE_ID__';
30-
31-
private ?Provider $provider = null;
28+
private Provider $provider;
3229

3330
/** @var Hook[] $hooks */
3431
private array $hooks = [];
@@ -43,15 +40,6 @@ class OpenFeatureAPI implements API, LoggerAwareInterface
4340
*/
4441
public static function getInstance(): API
4542
{
46-
//// TODO: Support global using $_SESSION?
47-
// if (isset($_SESSION)) {
48-
// if (is_null($_SESSION[self::GLOBAL_OPEN_FEATURE_KEY])) {
49-
// $_SESSION[self::GLOBAL_OPEN_FEATURE_KEY] = new self();
50-
// }
51-
52-
// return $_SESSION[self::GLOBAL_OPEN_FEATURE_KEY];
53-
// }
54-
5543
if (is_null(self::$instance)) {
5644
self::$instance = new self();
5745
}
@@ -70,15 +58,11 @@ public static function getInstance(): API
7058
*/
7159
private function __construct()
7260
{
73-
// no-op
61+
$this->provider = new NoOpProvider();
7462
}
7563

7664
public function getProvider(): Provider
7765
{
78-
if (!$this->provider) {
79-
return new NoOpProvider();
80-
}
81-
8266
return $this->provider;
8367
}
8468

src/OpenFeatureClient.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use Throwable;
3838

3939
use function array_merge;
40+
use function array_reverse;
4041
use function sprintf;
4142

4243
class OpenFeatureClient implements Client, LoggerAwareInterface
@@ -331,13 +332,8 @@ private function evaluateFlag(
331332
$options->getHooks(),
332333
$provider->getHooks(),
333334
);
334-
// TODO: Should we do a complete reversal of $mergedBeforeHooks instead?
335-
$mergedRemainingHooks = array_merge(
336-
$provider->getHooks(),
337-
$options->getHooks(),
338-
$this->getHooks(),
339-
$api->getHooks(),
340-
);
335+
336+
$mergedRemainingHooks = array_reverse(array_merge([], $mergedBeforeHooks));
341337

342338
try {
343339
$contextFromBeforeHook = $hookExecutor->beforeHooks($flagValueType, $hookContext, $mergedBeforeHooks, $hookHints);

src/implementation/hooks/AbstractHook.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ abstract public function after(HookContext $context, ResolutionDetails $details,
1919

2020
abstract public function error(HookContext $context, Throwable $error, HookHints $hints): void;
2121

22-
abstract public function finallyAfter(HookContext $context, HookHints $hints): void;
22+
abstract public function finally(HookContext $context, HookHints $hints): void;
2323

2424
abstract public function supportsFlagValueType(string $flagValueType): bool;
2525
}

tests/unit/BaseHooksTest.php

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenFeature\Test\unit;
6+
7+
use OpenFeature\Test\TestCase;
8+
use OpenFeature\implementation\hooks\BooleanHook;
9+
use OpenFeature\implementation\hooks\FloatHook;
10+
use OpenFeature\implementation\hooks\IntegerHook;
11+
use OpenFeature\implementation\hooks\ObjectHook;
12+
use OpenFeature\implementation\hooks\StringHook;
13+
use OpenFeature\interfaces\flags\EvaluationContext;
14+
use OpenFeature\interfaces\flags\FlagValueType;
15+
use OpenFeature\interfaces\hooks\HookContext;
16+
use OpenFeature\interfaces\hooks\HookHints;
17+
use OpenFeature\interfaces\provider\ResolutionDetails;
18+
use Throwable;
19+
20+
class BaseHooksTest extends TestCase
21+
{
22+
/**
23+
* @dataProvider dataBooleanHook
24+
*/
25+
public function testBooleanHook(string $flagValueType, bool $supportsFlagValueType): void
26+
{
27+
$testBooleanHook = new class extends BooleanHook {
28+
public function before(HookContext $context, HookHints $hints): ?EvaluationContext
29+
{
30+
return null;
31+
}
32+
33+
public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
34+
{
35+
// no-op
36+
}
37+
38+
public function error(HookContext $context, Throwable $error, HookHints $hints): void
39+
{
40+
// no-op
41+
}
42+
43+
public function finally(HookContext $context, HookHints $hints): void
44+
{
45+
// no-op
46+
}
47+
};
48+
49+
$this->assertEquals($supportsFlagValueType, $testBooleanHook->supportsFlagValueType($flagValueType));
50+
}
51+
52+
/**
53+
* @return Array<Array<mixed>>
54+
*/
55+
public function dataBooleanHook(): array
56+
{
57+
return [
58+
[FlagValueType::BOOLEAN, true],
59+
[FlagValueType::FLOAT, false],
60+
[FlagValueType::INTEGER, false],
61+
[FlagValueType::OBJECT, false],
62+
[FlagValueType::STRING, false],
63+
];
64+
}
65+
66+
/**
67+
* @dataProvider dataFloatHook
68+
*/
69+
public function testFloatHook(string $flagValueType, bool $supportsFlagValueType): void
70+
{
71+
$testFloatHook = new class extends FloatHook {
72+
public function before(HookContext $context, HookHints $hints): ?EvaluationContext
73+
{
74+
return null;
75+
}
76+
77+
public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
78+
{
79+
// no-op
80+
}
81+
82+
public function error(HookContext $context, Throwable $error, HookHints $hints): void
83+
{
84+
// no-op
85+
}
86+
87+
public function finally(HookContext $context, HookHints $hints): void
88+
{
89+
// no-op
90+
}
91+
};
92+
93+
$this->assertEquals($supportsFlagValueType, $testFloatHook->supportsFlagValueType($flagValueType));
94+
}
95+
96+
/**
97+
* @return Array<Array<mixed>>
98+
*/
99+
public function dataFloatHook(): array
100+
{
101+
return [
102+
[FlagValueType::BOOLEAN, false],
103+
[FlagValueType::FLOAT, true],
104+
[FlagValueType::INTEGER, false],
105+
[FlagValueType::OBJECT, false],
106+
[FlagValueType::STRING, false],
107+
];
108+
}
109+
110+
/**
111+
* @dataProvider dataIntegerHook
112+
*/
113+
public function testIntegerHook(string $flagValueType, bool $supportsFlagValueType): void
114+
{
115+
$testIntegerHook = new class extends IntegerHook {
116+
public function before(HookContext $context, HookHints $hints): ?EvaluationContext
117+
{
118+
return null;
119+
}
120+
121+
public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
122+
{
123+
// no-op
124+
}
125+
126+
public function error(HookContext $context, Throwable $error, HookHints $hints): void
127+
{
128+
// no-op
129+
}
130+
131+
public function finally(HookContext $context, HookHints $hints): void
132+
{
133+
// no-op
134+
}
135+
};
136+
137+
$this->assertEquals($supportsFlagValueType, $testIntegerHook->supportsFlagValueType($flagValueType));
138+
}
139+
140+
/**
141+
* @return Array<Array<mixed>>
142+
*/
143+
public function dataIntegerHook(): array
144+
{
145+
return [
146+
[FlagValueType::BOOLEAN, false],
147+
[FlagValueType::FLOAT, false],
148+
[FlagValueType::INTEGER, true],
149+
[FlagValueType::OBJECT, false],
150+
[FlagValueType::STRING, false],
151+
];
152+
}
153+
154+
/**
155+
* @dataProvider dataObjectHook
156+
*/
157+
public function testObjectHook(string $flagValueType, bool $supportsFlagValueType): void
158+
{
159+
$testObjectHook = new class extends ObjectHook {
160+
public function before(HookContext $context, HookHints $hints): ?EvaluationContext
161+
{
162+
return null;
163+
}
164+
165+
public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
166+
{
167+
// no-op
168+
}
169+
170+
public function error(HookContext $context, Throwable $error, HookHints $hints): void
171+
{
172+
// no-op
173+
}
174+
175+
public function finally(HookContext $context, HookHints $hints): void
176+
{
177+
// no-op
178+
}
179+
};
180+
181+
$this->assertEquals($supportsFlagValueType, $testObjectHook->supportsFlagValueType($flagValueType));
182+
}
183+
184+
/**
185+
* @return Array<Array<mixed>>
186+
*/
187+
public function dataObjectHook(): array
188+
{
189+
return [
190+
[FlagValueType::BOOLEAN, false],
191+
[FlagValueType::FLOAT, false],
192+
[FlagValueType::INTEGER, false],
193+
[FlagValueType::OBJECT, true],
194+
[FlagValueType::STRING, false],
195+
];
196+
}
197+
198+
/**
199+
* @dataProvider dataStringHook
200+
*/
201+
public function testStringHook(string $flagValueType, bool $supportsFlagValueType): void
202+
{
203+
$testStringHook = new class extends StringHook {
204+
public function before(HookContext $context, HookHints $hints): ?EvaluationContext
205+
{
206+
return null;
207+
}
208+
209+
public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
210+
{
211+
// no-op
212+
}
213+
214+
public function error(HookContext $context, Throwable $error, HookHints $hints): void
215+
{
216+
// no-op
217+
}
218+
219+
public function finally(HookContext $context, HookHints $hints): void
220+
{
221+
// no-op
222+
}
223+
};
224+
225+
$this->assertEquals($supportsFlagValueType, $testStringHook->supportsFlagValueType($flagValueType));
226+
}
227+
228+
/**
229+
* @return Array<Array<mixed>>
230+
*/
231+
public function dataStringHook(): array
232+
{
233+
return [
234+
[FlagValueType::BOOLEAN, false],
235+
[FlagValueType::FLOAT, false],
236+
[FlagValueType::INTEGER, false],
237+
[FlagValueType::OBJECT, false],
238+
[FlagValueType::STRING, true],
239+
];
240+
}
241+
}

tests/unit/NoOpClientTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
use OpenFeature\implementation\flags\EvaluationContext;
1010
use OpenFeature\implementation\flags\EvaluationDetailsBuilder;
1111
use OpenFeature\implementation\flags\NoOpClient;
12+
use OpenFeature\interfaces\hooks\Hook;
13+
use OpenFeature\interfaces\hooks\HookContext;
14+
use OpenFeature\interfaces\hooks\HookHints;
15+
use OpenFeature\interfaces\provider\ResolutionDetails;
16+
use Throwable;
1217

1318
class NoOpClientTest extends TestCase
1419
{
@@ -156,4 +161,55 @@ public function testGetHooks(): void
156161

157162
$this->assertEquals($expectedValue, $actualValue);
158163
}
164+
165+
public function testSetEvaluationContext(): void
166+
{
167+
$evaluationContext = new EvaluationContext('override-targeting-key');
168+
169+
$this->client->setEvaluationContext($evaluationContext);
170+
171+
$actualValue = $this->client->getEvaluationContext();
172+
173+
$expectedValue = new EvaluationContext('no-op-targeting-key');
174+
175+
$this->assertEquals($expectedValue, $actualValue);
176+
}
177+
178+
public function testSetHooks(): void
179+
{
180+
$fakeHook = new class implements Hook {
181+
public function before(HookContext $context, HookHints $hints): ?EvaluationContext
182+
{
183+
return null;
184+
}
185+
186+
public function after(HookContext $context, ResolutionDetails $details, HookHints $hints): void
187+
{
188+
// no-op
189+
}
190+
191+
public function error(HookContext $context, Throwable $error, HookHints $hints): void
192+
{
193+
// no-op
194+
}
195+
196+
public function finally(HookContext $context, HookHints $hints): void
197+
{
198+
// no-op
199+
}
200+
201+
public function supportsFlagValueType(string $flagValueType): bool
202+
{
203+
return true;
204+
}
205+
};
206+
207+
$this->client->setHooks([$fakeHook]);
208+
209+
$actualValue = $this->client->getHooks();
210+
211+
$expectedValue = [];
212+
213+
$this->assertEquals($expectedValue, $actualValue);
214+
}
159215
}

0 commit comments

Comments
 (0)