Prechádzať zdrojové kódy

Fix bug in HSCAN-based iterator when hash have integer fields.

When iterating a hash containing integer fields our iterator abstraction
based on HSCAN was always returning "0" as a field name after the first
$field => $value pair due to a wrong assumption on how the PHP function
array_shift() (which is used internally to advance to the next pair in
our buffered response to HSCAN) works.

The ZSCAN-based iterator had this very same bug which was already fixed
in 24e19a9 so I am not sure how this one went unnoticed until now.
Daniele Alessandri 8 rokov pred
rodič
commit
0baad16064

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

@@ -50,7 +50,11 @@ class HashKey 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]);
+        }
     }
 }

+ 45 - 0
tests/Predis/Collection/Iterator/HashKeyTest.php

@@ -56,6 +56,51 @@ class HashKeyTest extends PredisTestCase
         $this->assertFalse($iterator->valid());
     }
 
+    /**
+     * @link https://github.com/nrk/predis/pull/330
+     * @link https://github.com/nrk/predis/issues/331
+     * @group disconnected
+     */
+    public function testIterationWithIntegerFields()
+    {
+        $client = $this->getMock('Predis\Client', array('getProfile', 'hscan'));
+
+        $client->expects($this->any())
+               ->method('getProfile')
+               ->will($this->returnValue(Profile\Factory::get('2.8')));
+        $client->expects($this->once())
+               ->method('hscan')
+               ->with('key:hash', 0, array())
+               ->will($this->returnValue(array(0, array(
+                    1 => 'a', 2 => 'b', 3 => 100, 'foo' => 'bar'
+               ))));
+
+        $iterator = new HashKey($client, 'key:hash');
+
+        $iterator->rewind();
+        $this->assertTrue($iterator->valid());
+        $this->assertSame('a', $iterator->current());
+        $this->assertSame(1, $iterator->key());
+
+        $iterator->next();
+        $this->assertTrue($iterator->valid());
+        $this->assertSame('b', $iterator->current());
+        $this->assertSame(2, $iterator->key());
+
+        $iterator->next();
+        $this->assertTrue($iterator->valid());
+        $this->assertSame(100, $iterator->current());
+        $this->assertSame(3, $iterator->key());
+
+        $iterator->next();
+        $this->assertTrue($iterator->valid());
+        $this->assertSame('bar', $iterator->current());
+        $this->assertSame('foo', $iterator->key());
+
+        $iterator->next();
+        $this->assertFalse($iterator->valid());
+    }
+
     /**
      * @group disconnected
      */