Skip to content

Commit d55b0d8

Browse files
committed
fixed EnumSet::[attach|detach]Enumerators() in case an error happens in the middle of modifying
1 parent 9ad0522 commit d55b0d8

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

src/EnumSet.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,16 @@ public function withEnumerator($enumerator): self
140140
*/
141141
public function attachEnumerators(iterable $enumerators): void
142142
{
143-
foreach ($enumerators as $enumerator) {
144-
$this->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
143+
$bitset = $this->bitset;
144+
145+
try {
146+
foreach ($enumerators as $enumerator) {
147+
$this->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
148+
}
149+
} catch (\Throwable $e) {
150+
// reset all changes until error happened
151+
$this->bitset = $bitset;
152+
throw $e;
145153
}
146154
}
147155

@@ -192,8 +200,16 @@ public function withoutEnumerator($enumerator): self
192200
*/
193201
public function detachEnumerators(iterable $enumerators): void
194202
{
195-
foreach ($enumerators as $enumerator) {
196-
$this->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
203+
$bitset = $this->bitset;
204+
205+
try {
206+
foreach ($enumerators as $enumerator) {
207+
$this->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
208+
}
209+
} catch (\Throwable $e) {
210+
// reset all changes until error happened
211+
$this->bitset = $bitset;
212+
throw $e;
197213
}
198214
}
199215

tests/MabeEnumTest/EnumSetTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,36 @@ public function getIntegerEnumerations()
270270
];
271271
}
272272

273+
public function testAttachAtOnceAllOrNone()
274+
{
275+
$set = new EnumSet(EnumBasic::class);
276+
$set->attachEnumerator(EnumBasic::ONE);
277+
278+
try {
279+
$set->attachEnumerators([EnumBasic::TWO, 'unknown']);
280+
} catch (InvalidArgumentException $e) {
281+
// exception expected
282+
} finally {
283+
$this->assertTrue($set->contains(EnumBasic::ONE));
284+
$this->assertFalse($set->contains(EnumBasic::TWO));
285+
}
286+
}
287+
288+
public function testDetachAtOnceAllOrNone()
289+
{
290+
$set = new EnumSet(EnumBasic::class);
291+
$set->attachEnumerators([EnumBasic::ONE]);
292+
293+
try {
294+
$set->detachEnumerators([EnumBasic::ONE, EnumBasic::TWO, 'unknown']);
295+
} catch (InvalidArgumentException $e) {
296+
// exception expected
297+
} finally {
298+
$this->assertTrue($set->contains(EnumBasic::ONE));
299+
$this->assertFalse($set->contains(EnumBasic::TWO));
300+
}
301+
}
302+
273303
public function testGetBit()
274304
{
275305
$set = new EnumSet(EnumBasic::class);

0 commit comments

Comments
 (0)