Browse Source

Fix bug in ZSCAN-based iterator when sorted sets have integer members.

When iterating a sorted set containing integer members, our iterator
abstraction based on ZSCAN was always returning "0" as a member value
after the first $member => $score pair because of a wrong assumption
on how the PHP function array_shift() (used internally to advance to
the next pair in our buffered response to ZSCAN) works.

Fixes #216.
Daniele Alessandri 10 years ago
parent
commit
24e19a9b76

+ 3 - 0
CHANGELOG.md

@@ -1,6 +1,9 @@
 v1.0.1 (2014-xx-xx)
 ================================================================================
 
+- __FIX__: broken values returned by `Predis\Collection\Iterator\SortedSetKey`
+  when iterating sorted set containing integer members (ISSUE #216).
+
 - __FIX__: applied a minor workaround for a bug in old versions of PHP < 5.3.9
   affecting inheritance.
 

+ 6 - 2
src/Collection/Iterator/SortedSetKey.php

@@ -49,7 +49,11 @@ class SortedSetKey extends CursorBasedIterator
      */
     protected function extractNext()
     {
-        $this->position = key($this->elements);
-        $this->current = array_shift($this->elements);
+        if ($kv = each($this->elements)) {
+            $this->position = $kv[0];
+            $this->current = $kv[1];
+
+            unset($this->elements[$this->position]);
+        }
     }
 }

+ 39 - 0
tests/Predis/Collection/Iterator/SortedSetKeyTest.php

@@ -56,6 +56,45 @@ class SortedSetKeyTest extends PredisTestCase
         $this->assertFalse($iterator->valid());
     }
 
+    /**
+     * @link https://github.com/nrk/predis/issues/216
+     * @group disconnected
+     */
+    public function testIterationWithIntegerMembers()
+    {
+        $client = $this->getMock('Predis\Client', array('getProfile', 'zscan'));
+
+        $client->expects($this->any())
+               ->method('getProfile')
+               ->will($this->returnValue(Profile\Factory::get('2.8')));
+        $client->expects($this->once())
+               ->method('zscan')
+               ->with('key:zset', 0, array())
+               ->will($this->returnValue(array(0, array(
+                    0 => 0, 101 => 1, 102 => 2,
+               ))));
+
+        $iterator = new SortedSetKey($client, 'key:zset');
+
+        $iterator->rewind();
+        $this->assertTrue($iterator->valid());
+        $this->assertSame(0, $iterator->current());
+        $this->assertSame(0, $iterator->key());
+
+        $iterator->next();
+        $this->assertTrue($iterator->valid());
+        $this->assertSame(1, $iterator->current());
+        $this->assertSame(101, $iterator->key());
+
+        $iterator->next();
+        $this->assertTrue($iterator->valid());
+        $this->assertSame(2, $iterator->current());
+        $this->assertSame(102, $iterator->key());
+
+        $iterator->next();
+        $this->assertFalse($iterator->valid());
+    }
+
     /**
      * @group disconnected
      */