Skip to content

Commit bbb17c7

Browse files
committed
fix #73, EnumSet::setBinaryBitset*() throws InvalidArgumentException on out-of-range bits
1 parent 1aa683f commit bbb17c7

File tree

2 files changed

+54
-35
lines changed

2 files changed

+54
-35
lines changed

src/EnumSet.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -431,18 +431,26 @@ public function setBinaryBitsetLe($bitset)
431431
// add "\0" if the given bitset is not long enough
432432
$bitset .= str_repeat("\0", $size - $sizeIn);
433433
} elseif ($sizeIn > $size) {
434+
if (trim(substr($bitset, $size), "\0") !== '') {
435+
throw new InvalidArgumentException('Out-Of-Range bits detected');
436+
}
434437
$bitset = substr($bitset, 0, $size);
435438
}
436439

437440
// truncate out-of-range bits of last byte
438441
$lastByteMaxOrd = $this->ordinalMax % 8;
439-
if ($lastByteMaxOrd === 0) {
440-
$this->bitset = $bitset;
441-
} else {
442-
$lastByte = chr((1 << $lastByteMaxOrd) - 1) & $bitset[$size - 1];
443-
$this->bitset = substr($bitset, 0, -1) . $lastByte;
442+
if ($lastByteMaxOrd !== 0) {
443+
$lastByte = $bitset[$size - 1];
444+
$lastByteExpected = chr((1 << $lastByteMaxOrd) - 1) & $lastByte;
445+
if ($lastByte !== $lastByteExpected) {
446+
throw new InvalidArgumentException('Out-Of-Range bits detected');
447+
}
448+
449+
$this->bitset = substr($bitset, 0, -1) . $lastByteExpected;
444450
}
445451

452+
$this->bitset = $bitset;
453+
446454
// reset the iterator position
447455
$this->rewind();
448456
}

tests/MabeEnumTest/EnumSetTest.php

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -327,35 +327,6 @@ public function testSetBinaryBitsetLe()
327327
$this->assertTrue($enumSet->count() == 3);
328328
}
329329

330-
public function testSetBinaryBitsetLeTruncateHighBits()
331-
{
332-
// using Enum66 to make sure the max. ordinal number gets converted into a bitset
333-
// Enum65 has max. ordinal number of 1 of the last byte. -> 00000001
334-
// Enum66 has max. ordinal number of 2 of the last byte. -> 00000011
335-
$enumSet = new EnumSet(Enum66::class);
336-
foreach (Enum66::getEnumerators() as $enumerator) {
337-
$enumSet->attach($enumerator);
338-
}
339-
340-
$bitset = $enumSet->getBinaryBitsetLe();
341-
$newBitset = substr($bitset, 0, -1) . "\xff\xff";
342-
$enumSet->setBinaryBitsetLe($newBitset);
343-
344-
$this->assertSame(bin2hex($bitset), bin2hex($enumSet->getBinaryBitsetLe()));
345-
}
346-
347-
public function testSetBinaryBitsetBe()
348-
{
349-
$enumSet = new EnumSet(Enum65::class);
350-
$enumSet->setBinaryBitsetBe("\x01\x80\x00\x00\x00\x00\x00\x00\x01");
351-
352-
$this->assertTrue($enumSet->contains(Enum65::ONE));
353-
$this->assertFalse($enumSet->contains(Enum65::TWO));
354-
$this->assertTrue($enumSet->contains(Enum65::SIXTYFIVE));
355-
$this->assertTrue($enumSet->contains(Enum65::SIXTYFOUR));
356-
$this->assertTrue($enumSet->count() == 3);
357-
}
358-
359330
public function testSetBinaryBitsetLeShort()
360331
{
361332
$enumSet = new EnumSet(Enum65::class);
@@ -366,10 +337,38 @@ public function testSetBinaryBitsetLeShort()
366337
public function testSetBinaryBitsetLeLong()
367338
{
368339
$enumSet = new EnumSet(EnumBasic::class);
369-
$enumSet->setBinaryBitsetLe("\x0A\xFF\xFF\xFF\xFF\xFF");
340+
$enumSet->setBinaryBitsetLe("\x0A\xFF\x00\x00\x00\x00");
370341
$this->assertSame("\x0A\xFF", $enumSet->getBinaryBitsetLe());
371342
}
372343

344+
public function testSetBinaryBitsetLeOutOrRangeBitsOfExtendedBytes1()
345+
{
346+
$enumSet = new EnumSet(EnumBasic::class);
347+
348+
$this->setExpectedException(InvalidArgumentException::class, 'Out-Of-Range');
349+
$enumSet->setBinaryBitsetLe("\x0A\xFF\x01");
350+
}
351+
352+
public function testSetBinaryBitsetLeOutOrRangeBitsOfExtendedBytes2()
353+
{
354+
$enumSet = new EnumSet(EnumBasic::class);
355+
356+
$this->setExpectedException(InvalidArgumentException::class, 'Out-Of-Range');
357+
$enumSet->setBinaryBitsetLe("\x0A\xFF\x00\x02");
358+
}
359+
360+
public function testSetBinaryBitsetLeOutOrRangeBitsOfLastValidByte()
361+
{
362+
// using Enum65 to detect Out-Of-Range bits of last valid byte
363+
// Enum65 has max. ordinal number of 2 of the last byte. -> 0001
364+
$enumSet = new EnumSet(Enum65::class);
365+
$bitset = $enumSet->getBinaryBitsetLe();
366+
$newBitset = substr($bitset, 0, -1) . "\x02";
367+
368+
$this->setExpectedException(InvalidArgumentException::class, 'Out-Of-Range');
369+
$enumSet->setBinaryBitsetLe($newBitset);
370+
}
371+
373372
public function testSetBinaryBitsetLeArgumentExceptionIfNotString()
374373
{
375374
$this->setExpectedException(InvalidArgumentException::class);
@@ -378,6 +377,18 @@ public function testSetBinaryBitsetLeArgumentExceptionIfNotString()
378377
$enum->setBinaryBitsetLe(0);
379378
}
380379

380+
public function testSetBinaryBitsetBe()
381+
{
382+
$enumSet = new EnumSet(Enum65::class);
383+
$enumSet->setBinaryBitsetBe("\x01\x80\x00\x00\x00\x00\x00\x00\x01");
384+
385+
$this->assertTrue($enumSet->contains(Enum65::ONE));
386+
$this->assertFalse($enumSet->contains(Enum65::TWO));
387+
$this->assertTrue($enumSet->contains(Enum65::SIXTYFIVE));
388+
$this->assertTrue($enumSet->contains(Enum65::SIXTYFOUR));
389+
$this->assertTrue($enumSet->count() == 3);
390+
}
391+
381392
public function testSetBinaryBitsetBeArgumentExceptionIfNotString()
382393
{
383394
$this->setExpectedException(InvalidArgumentException::class);

0 commit comments

Comments
 (0)