Skip to content

Commit bc6a7a3

Browse files
committed
Fix: allow MixedStore to accept true, false, null and floats as keys + related tests
1 parent f668300 commit bc6a7a3

File tree

2 files changed

+221
-10
lines changed

2 files changed

+221
-10
lines changed

src/Utils/MixedStore.php

Lines changed: 95 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ class MixedStore implements \ArrayAccess
1616
/**
1717
* @var array
1818
*/
19-
private $scalarStore;
19+
private $standardStore;
20+
21+
/**
22+
* @var array
23+
*/
24+
private $floatStore;
2025

2126
/**
2227
* @var \SplObjectStorage
@@ -43,15 +48,49 @@ class MixedStore implements \ArrayAccess
4348
*/
4449
private $lastArrayValue;
4550

51+
/**
52+
* @var mixed
53+
*/
54+
private $nullValue;
55+
56+
/**
57+
* @var bool
58+
*/
59+
private $nullValueIsSet;
60+
61+
/**
62+
* @var mixed
63+
*/
64+
private $trueValue;
65+
66+
/**
67+
* @var bool
68+
*/
69+
private $trueValueIsSet;
70+
71+
/**
72+
* @var mixed
73+
*/
74+
private $falseValue;
75+
76+
/**
77+
* @var bool
78+
*/
79+
private $falseValueIsSet;
80+
4681
/**
4782
* MixedStore constructor.
4883
*/
4984
public function __construct()
5085
{
51-
$this->scalarStore = [];
86+
$this->standardStore = [];
87+
$this->floatStore = [];
5288
$this->objectStore = new \SplObjectStorage();
5389
$this->arrayKeys = [];
5490
$this->arrayValues = [];
91+
$this->nullValueIsSet = false;
92+
$this->trueValueIsSet = false;
93+
$this->falseValueIsSet = false;
5594
}
5695

5796
/**
@@ -68,8 +107,17 @@ public function __construct()
68107
*/
69108
public function offsetExists($offset)
70109
{
71-
if (is_scalar($offset)) {
72-
return array_key_exists($offset, $this->scalarStore);
110+
if (false === $offset) {
111+
return $this->falseValueIsSet;
112+
}
113+
if (true === $offset) {
114+
return $this->trueValueIsSet;
115+
}
116+
if (is_int($offset) || is_string($offset)) {
117+
return array_key_exists($offset, $this->standardStore);
118+
}
119+
if (is_float($offset)) {
120+
return array_key_exists((string) $offset, $this->floatStore);
73121
}
74122
if (is_object($offset)) {
75123
return $this->objectStore->offsetExists($offset);
@@ -83,6 +131,9 @@ public function offsetExists($offset)
83131
}
84132
}
85133
}
134+
if (null === $offset) {
135+
return $this->nullValueIsSet;
136+
}
86137
return false;
87138
}
88139

@@ -97,8 +148,17 @@ public function offsetExists($offset)
97148
*/
98149
public function offsetGet($offset)
99150
{
100-
if (is_scalar($offset)) {
101-
return $this->scalarStore[$offset];
151+
if (true === $offset) {
152+
return $this->trueValue;
153+
}
154+
if (false === $offset) {
155+
return $this->falseValue;
156+
}
157+
if (is_int($offset) || is_string($offset)) {
158+
return $this->standardStore[$offset];
159+
}
160+
if (is_float($offset)) {
161+
return $this->floatStore[(string)$offset];
102162
}
103163
if (is_object($offset)) {
104164
return $this->objectStore->offsetGet($offset);
@@ -114,6 +174,9 @@ public function offsetGet($offset)
114174
}
115175
}
116176
}
177+
if (null === $offset) {
178+
return $this->nullValue;
179+
}
117180
return null;
118181
}
119182

@@ -131,13 +194,24 @@ public function offsetGet($offset)
131194
*/
132195
public function offsetSet($offset, $value)
133196
{
134-
if (is_scalar($offset)) {
135-
$this->scalarStore[$offset] = $value;
197+
if (false === $offset) {
198+
$this->falseValue = $value;
199+
$this->falseValueIsSet = true;
200+
} else if (true === $offset) {
201+
$this->trueValue = $value;
202+
$this->trueValueIsSet = true;
203+
} else if (is_int($offset) || is_string($offset)) {
204+
$this->standardStore[$offset] = $value;
205+
} else if (is_float($offset)) {
206+
$this->floatStore[(string)$offset] = $value;
136207
} else if (is_object($offset)) {
137208
$this->objectStore[$offset] = $value;
138209
} else if (is_array($offset)) {
139210
$this->arrayKeys[] = $offset;
140211
$this->arrayValues[] = $value;
212+
} else if (null === $offset) {
213+
$this->nullValue = $value;
214+
$this->nullValueIsSet = true;
141215
} else {
142216
throw new \InvalidArgumentException("Unexpected offset type: " . Utils::printSafe($offset));
143217
}
@@ -154,8 +228,16 @@ public function offsetSet($offset, $value)
154228
*/
155229
public function offsetUnset($offset)
156230
{
157-
if (is_scalar($offset)) {
158-
unset($this->scalarStore[$offset]);
231+
if (true === $offset) {
232+
$this->trueValue = null;
233+
$this->trueValueIsSet = false;
234+
} else if (false === $offset) {
235+
$this->falseValue = null;
236+
$this->falseValueIsSet = false;
237+
} else if (is_int($offset) || is_string($offset)) {
238+
unset($this->standardStore[$offset]);
239+
} else if (is_float($offset)) {
240+
unset($this->floatStore[(string)$offset]);
159241
} else if (is_object($offset)) {
160242
$this->objectStore->offsetUnset($offset);
161243
} else if (is_array($offset)) {
@@ -165,6 +247,9 @@ public function offsetUnset($offset)
165247
array_splice($this->arrayKeys, $index, 1);
166248
array_splice($this->arrayValues, $index, 1);
167249
}
250+
} else if (null === $offset) {
251+
$this->nullValue = null;
252+
$this->nullValueIsSet = false;
168253
}
169254
}
170255
}

tests/Utils/MixedStoreTest.php

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
namespace GraphQL\Tests\Utils;
3+
4+
5+
use GraphQL\Utils;
6+
use GraphQL\Utils\MixedStore;
7+
8+
class MixedStoreTest extends \PHPUnit_Framework_TestCase
9+
{
10+
/**
11+
* @var MixedStore
12+
*/
13+
private $mixedStore;
14+
15+
public function setUp()
16+
{
17+
$this->mixedStore = new MixedStore();
18+
}
19+
20+
public function getPossibleValues()
21+
{
22+
return [
23+
null,
24+
false,
25+
true,
26+
'',
27+
'0',
28+
'1',
29+
'a',
30+
[],
31+
new \stdClass(),
32+
function() {},
33+
new MixedStore()
34+
];
35+
}
36+
37+
public function testAcceptsNullKeys()
38+
{
39+
foreach ($this->getPossibleValues() as $value) {
40+
$this->assertAcceptsKeyValue(null, $value);
41+
}
42+
}
43+
44+
public function testAcceptsBoolKeys()
45+
{
46+
foreach ($this->getPossibleValues() as $value) {
47+
$this->assertAcceptsKeyValue(false, $value);
48+
}
49+
foreach ($this->getPossibleValues() as $value) {
50+
$this->assertAcceptsKeyValue(true, $value);
51+
}
52+
}
53+
54+
public function testAcceptsIntKeys()
55+
{
56+
foreach ($this->getPossibleValues() as $value) {
57+
$this->assertAcceptsKeyValue(-100000, $value);
58+
$this->assertAcceptsKeyValue(-1, $value);
59+
$this->assertAcceptsKeyValue(0, $value);
60+
$this->assertAcceptsKeyValue(1, $value);
61+
$this->assertAcceptsKeyValue(1000000, $value);
62+
}
63+
}
64+
65+
public function testAcceptsFloatKeys()
66+
{
67+
foreach ($this->getPossibleValues() as $value) {
68+
$this->assertAcceptsKeyValue(-100000.5, $value);
69+
$this->assertAcceptsKeyValue(-1.6, $value);
70+
$this->assertAcceptsKeyValue(-0.0001, $value);
71+
$this->assertAcceptsKeyValue(0.0000, $value);
72+
$this->assertAcceptsKeyValue(0.0001, $value);
73+
$this->assertAcceptsKeyValue(1.6, $value);
74+
$this->assertAcceptsKeyValue(1000000.5, $value);
75+
}
76+
}
77+
78+
public function testAcceptsArrayKeys()
79+
{
80+
foreach ($this->getPossibleValues() as $value) {
81+
$this->assertAcceptsKeyValue([], $value);
82+
$this->assertAcceptsKeyValue([null], $value);
83+
$this->assertAcceptsKeyValue([[]], $value);
84+
$this->assertAcceptsKeyValue([new \stdClass()], $value);
85+
$this->assertAcceptsKeyValue(['a', 'b'], $value);
86+
$this->assertAcceptsKeyValue(['a' => 'b'], $value);
87+
}
88+
}
89+
90+
public function testAcceptsObjectKeys()
91+
{
92+
foreach ($this->getPossibleValues() as $value) {
93+
$this->assertAcceptsKeyValue(new \stdClass(), $value);
94+
$this->assertAcceptsKeyValue(new MixedStore(), $value);
95+
$this->assertAcceptsKeyValue(function() {}, $value);
96+
}
97+
}
98+
99+
private function assertAcceptsKeyValue($key, $value)
100+
{
101+
$err = 'Failed assertion that MixedStore accepts key ' .
102+
Utils::printSafe($key) . ' with value ' . Utils::printSafe($value);
103+
104+
$this->assertFalse($this->mixedStore->offsetExists($key), $err);
105+
$this->mixedStore->offsetSet($key, $value);
106+
$this->assertTrue($this->mixedStore->offsetExists($key), $err);
107+
$this->assertSame($value, $this->mixedStore->offsetGet($key), $err);
108+
$this->mixedStore->offsetUnset($key);
109+
$this->assertFalse($this->mixedStore->offsetExists($key), $err);
110+
$this->assertProvidesArrayAccess($key, $value);
111+
}
112+
113+
private function assertProvidesArrayAccess($key, $value)
114+
{
115+
$err = 'Failed assertion that MixedStore provides array access for key ' .
116+
Utils::printSafe($key) . ' with value ' . Utils::printSafe($value);
117+
118+
$this->assertFalse(isset($this->mixedStore[$key]), $err);
119+
$this->mixedStore[$key] = $value;
120+
$this->assertTrue(isset($this->mixedStore[$key]), $err);
121+
$this->assertEquals(!empty($value), !empty($this->mixedStore[$key]), $err);
122+
$this->assertSame($value, $this->mixedStore[$key], $err);
123+
unset($this->mixedStore[$key]);
124+
$this->assertFalse(isset($this->mixedStore[$key]), $err);
125+
}
126+
}

0 commit comments

Comments
 (0)