Skip to content

Commit

Permalink
adds failing test case for #12060
Browse files Browse the repository at this point in the history
Signed-off-by: George Peter Banyard <girgias@php.net>
  • Loading branch information
ju1ius authored and Girgias committed Sep 5, 2023
1 parent f1f608b commit 9658d9a
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 2 deletions.
2 changes: 1 addition & 1 deletion ext/zend_test/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ PHP_ARG_ENABLE([zend-test],
[Enable zend_test extension])])

if test "$PHP_ZEND_TEST" != "no"; then
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi
2 changes: 1 addition & 1 deletion ext/zend_test/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
ARG_ENABLE("zend-test", "enable zend_test extension", "no");

if (PHP_ZEND_TEST != "no") {
EXTENSION("zend_test", "test.c observer.c fiber.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS ");
}
121 changes: 121 additions & 0 deletions ext/zend_test/iterators.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/

#include "iterators.h"
#include "zend_API.h"
#include "iterators_arginfo.h"

#include <zend_interfaces.h>
#include "php.h"

#define DUMP(s) php_output_write((s), sizeof((s)) - 1)

static zend_class_entry *traversable_test_ce;

// Dummy iterator that yields numbers from 0..4,
// while printing operations to the output buffer
typedef struct {
zend_object_iterator intern;
zval current;
} test_traversable_it;

static test_traversable_it *test_traversable_it_fetch(zend_object_iterator *iter) {
return (test_traversable_it *)iter;
}

static void test_traversable_it_dtor(zend_object_iterator *iter) {
DUMP("TraversableTest::drop\n");
test_traversable_it *iterator = test_traversable_it_fetch(iter);
zval_ptr_dtor(&iterator->intern.data);
}

static void test_traversable_it_rewind(zend_object_iterator *iter) {
DUMP("TraversableTest::rewind\n");
test_traversable_it *iterator = test_traversable_it_fetch(iter);
ZVAL_LONG(&iterator->current, 0);
}

static void test_traversable_it_next(zend_object_iterator *iter) {
DUMP("TraversableTest::next\n");
test_traversable_it *iterator = test_traversable_it_fetch(iter);
ZVAL_LONG(&iterator->current, Z_LVAL(iterator->current) + 1);
}

static int test_traversable_it_valid(zend_object_iterator *iter) {
DUMP("TraversableTest::valid\n");
test_traversable_it *iterator = test_traversable_it_fetch(iter);
if (Z_LVAL(iterator->current) < 4) {
return SUCCESS;
}
return FAILURE;
}

static void test_traversable_it_key(zend_object_iterator *iter, zval *return_value) {
DUMP("TraversableTest::key\n");
test_traversable_it *iterator = test_traversable_it_fetch(iter);
ZVAL_LONG(return_value, Z_LVAL(iterator->current));
}

static zval *test_traversable_it_current(zend_object_iterator *iter) {
DUMP("TraversableTest::current\n");
test_traversable_it *iterator = test_traversable_it_fetch(iter);
return &iterator->current;
}

static const zend_object_iterator_funcs test_traversable_it_vtable = {
test_traversable_it_dtor,
test_traversable_it_valid,
test_traversable_it_current,
test_traversable_it_key,
test_traversable_it_next,
test_traversable_it_rewind,
NULL, // invalidate_current
NULL, // get_gc
};

static zend_object_iterator *test_traversable_get_iterator(
zend_class_entry *ce,
zval *object,
int by_ref
) {
test_traversable_it *iterator;

if (by_ref) {
zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
return NULL;
}

iterator = emalloc(sizeof(test_traversable_it));
zend_iterator_init((zend_object_iterator*)iterator);

ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
iterator->intern.funcs = &test_traversable_it_vtable;
ZVAL_LONG(&iterator->current, 0);

return (zend_object_iterator*)iterator;
}

ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct) {
ZEND_PARSE_PARAMETERS_NONE();
}

ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator) {
ZEND_PARSE_PARAMETERS_NONE();
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
}

void zend_test_iterators_init(void) {
traversable_test_ce = register_class_ZendTest_Iterators_TraversableTest(zend_ce_aggregate);
traversable_test_ce->get_iterator = test_traversable_get_iterator;
}
21 changes: 21 additions & 0 deletions ext/zend_test/iterators.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| https://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/

#ifndef ZEND_TEST_ITERATORS_H
#define ZEND_TEST_ITERATORS_H

void zend_test_iterators_init(void);

#endif

14 changes: 14 additions & 0 deletions ext/zend_test/iterators.stub.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

/**
* @generate-class-entries static
* @undocumentable
*/

namespace ZendTest\Iterators;

final class TraversableTest implements \IteratorAggregate
{
public function __construct() {}
public function getIterator(): \Iterator {}
}
31 changes: 31 additions & 0 deletions ext/zend_test/iterators_arginfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: f9558686a7393ddd4ba3302e811f70d4496317ee */

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTest_Iterators_TraversableTest___construct, 0, 0, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ZendTest_Iterators_TraversableTest_getIterator, 0, 0, Iterator, 0)
ZEND_END_ARG_INFO()


static ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct);
static ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator);


static const zend_function_entry class_ZendTest_Iterators_TraversableTest_methods[] = {
ZEND_ME(ZendTest_Iterators_TraversableTest, __construct, arginfo_class_ZendTest_Iterators_TraversableTest___construct, ZEND_ACC_PUBLIC)
ZEND_ME(ZendTest_Iterators_TraversableTest, getIterator, arginfo_class_ZendTest_Iterators_TraversableTest_getIterator, ZEND_ACC_PUBLIC)
ZEND_FE_END
};

static zend_class_entry *register_class_ZendTest_Iterators_TraversableTest(zend_class_entry *class_entry_IteratorAggregate)
{
zend_class_entry ce, *class_entry;

INIT_NS_CLASS_ENTRY(ce, "ZendTest\\Iterators", "TraversableTest", class_ZendTest_Iterators_TraversableTest_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
class_entry->ce_flags |= ZEND_ACC_FINAL;
zend_class_implements(class_entry, 1, class_entry_IteratorAggregate);

return class_entry;
}
2 changes: 2 additions & 0 deletions ext/zend_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "php_test.h"
#include "observer.h"
#include "fiber.h"
#include "iterators.h"
#include "zend_attributes.h"
#include "zend_enum.h"
#include "zend_interfaces.h"
Expand Down Expand Up @@ -660,6 +661,7 @@ PHP_MINIT_FUNCTION(zend_test)

zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
zend_test_fiber_init();
zend_test_iterators_init();

return SUCCESS;
}
Expand Down
40 changes: 40 additions & 0 deletions ext/zend_test/tests/iterators/double-rewind.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--TEST--
Tests that internal iterator's rewind function is called once
--EXTENSIONS--
zend_test
--FILE--
<?php

$subject = new \ZendTest\Iterators\TraversableTest();
$it = $subject->getIterator();
var_dump($it);
foreach ($it as $key => $value) {
echo "{$key} => {$value}\n";
}
?>
--EXPECT--
object(InternalIterator)#3 (0) {
}
TraversableTest::rewind
TraversableTest::valid
TraversableTest::current
TraversableTest::key
0 => 0
TraversableTest::next
TraversableTest::valid
TraversableTest::current
TraversableTest::key
1 => 1
TraversableTest::next
TraversableTest::valid
TraversableTest::current
TraversableTest::key
2 => 2
TraversableTest::next
TraversableTest::valid
TraversableTest::current
TraversableTest::key
3 => 3
TraversableTest::next
TraversableTest::valid
TraversableTest::drop

0 comments on commit 9658d9a

Please sign in to comment.