Skip to content

Commit 32264a7

Browse files
committed
stream: add tests for new stream error handling
1 parent 93d0152 commit 32264a7

7 files changed

+367
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Stream errors - exception mode for terminal errors
3+
--FILE--
4+
<?php
5+
6+
$context = stream_context_create([
7+
'stream' => [
8+
'error_mode' => STREAM_ERROR_MODE_EXCEPTION,
9+
]
10+
]);
11+
12+
try {
13+
$stream = fopen('php://nonexistent', 'r', false, $context);
14+
} catch (StreamException $e) {
15+
echo "Caught: " . $e->getMessage() . "\n";
16+
echo "Code: " . $e->getCode() . "\n";
17+
echo "Wrapper: " . $e->getWrapperName() . "\n";
18+
}
19+
20+
?>
21+
--EXPECTF--
22+
Caught: Failed to open stream: operation failed
23+
Code: 36
24+
Wrapper: PHP
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
--TEST--
2+
Stream errors - silent mode with mixed error stores
3+
--FILE--
4+
<?php
5+
6+
class TestStream {
7+
public $context;
8+
private $position = 0;
9+
10+
public function stream_open($path, $mode, $options, &$opened_path) {
11+
return true;
12+
}
13+
14+
public function stream_read($count) {
15+
$this->position += $count;
16+
return str_repeat('x', $count + 10);
17+
}
18+
19+
public function stream_eof() {
20+
return $this->position >= 100;
21+
}
22+
23+
public function stream_stat() {
24+
return [];
25+
}
26+
}
27+
28+
stream_wrapper_register('test', 'TestStream');
29+
30+
function stream_test_errors($title, $context) {
31+
$stream = fopen('test://foo', 'r', false, $context);
32+
try {
33+
echo $title . "\n";
34+
$readin = fopen( 'php://stdin', 'r' );
35+
$data = fread( $stream, 10 );
36+
37+
$read = [$readin, $stream];
38+
$write = NULL;
39+
$except = NULL;
40+
stream_select($read, $write, $except, 0);
41+
} catch (StreamException $e) {
42+
echo 'EXCEPTION: ' . $e->getMessage() . "\n";
43+
}
44+
45+
$errors = stream_get_errors($stream);
46+
var_dump($errors);
47+
}
48+
49+
stream_test_errors('ALL', stream_context_create([
50+
'stream' => [
51+
'error_mode' => STREAM_ERROR_MODE_SILENT,
52+
'error_store' => STREAM_ERROR_STORE_ALL,
53+
]
54+
]));
55+
stream_test_errors('NON TERMINAL', stream_context_create([
56+
'stream' => [
57+
'error_mode' => STREAM_ERROR_MODE_SILENT,
58+
'error_store' => STREAM_ERROR_STORE_NON_TERMINAL,
59+
]
60+
]));
61+
stream_test_errors('TERMINAL', stream_context_create([
62+
'stream' => [
63+
'error_mode' => STREAM_ERROR_MODE_SILENT,
64+
'error_store' => STREAM_ERROR_STORE_TERMINAL,
65+
]
66+
]));
67+
stream_test_errors('AUTO EXCEPTION', stream_context_create([
68+
'stream' => [
69+
'error_mode' => STREAM_ERROR_MODE_EXCEPTION,
70+
'error_store' => STREAM_ERROR_STORE_AUTO,
71+
]
72+
]));
73+
stream_test_errors('AUTO ERROR', stream_context_create([
74+
'stream' => [
75+
'error_mode' => STREAM_ERROR_MODE_ERROR,
76+
'error_store' => STREAM_ERROR_STORE_AUTO,
77+
]
78+
]));
79+
80+
?>
81+
--EXPECTF--
82+
ALL
83+
array(3) {
84+
[0]=>
85+
array(5) {
86+
["message"]=>
87+
string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost"
88+
["code"]=>
89+
int(161)
90+
["severity"]=>
91+
int(2)
92+
["terminal"]=>
93+
bool(false)
94+
["wrapper"]=>
95+
string(10) "user-space"
96+
}
97+
[1]=>
98+
array(5) {
99+
["message"]=>
100+
string(43) "TestStream::stream_cast is not implemented!"
101+
["code"]=>
102+
int(70)
103+
["severity"]=>
104+
int(2)
105+
["terminal"]=>
106+
bool(true)
107+
["wrapper"]=>
108+
string(10) "user-space"
109+
}
110+
[2]=>
111+
array(5) {
112+
["message"]=>
113+
string(73) "Cannot represent a stream of type user-space as a select()able descriptor"
114+
["code"]=>
115+
int(101)
116+
["severity"]=>
117+
int(2)
118+
["terminal"]=>
119+
bool(true)
120+
["wrapper"]=>
121+
string(10) "user-space"
122+
}
123+
}
124+
NON TERMINAL
125+
array(1) {
126+
[0]=>
127+
array(5) {
128+
["message"]=>
129+
string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost"
130+
["code"]=>
131+
int(161)
132+
["severity"]=>
133+
int(2)
134+
["terminal"]=>
135+
bool(false)
136+
["wrapper"]=>
137+
string(10) "user-space"
138+
}
139+
}
140+
TERMINAL
141+
array(2) {
142+
[0]=>
143+
array(5) {
144+
["message"]=>
145+
string(43) "TestStream::stream_cast is not implemented!"
146+
["code"]=>
147+
int(70)
148+
["severity"]=>
149+
int(2)
150+
["terminal"]=>
151+
bool(true)
152+
["wrapper"]=>
153+
string(10) "user-space"
154+
}
155+
[1]=>
156+
array(5) {
157+
["message"]=>
158+
string(73) "Cannot represent a stream of type user-space as a select()able descriptor"
159+
["code"]=>
160+
int(101)
161+
["severity"]=>
162+
int(2)
163+
["terminal"]=>
164+
bool(true)
165+
["wrapper"]=>
166+
string(10) "user-space"
167+
}
168+
}
169+
AUTO EXCEPTION
170+
EXCEPTION: Cannot represent a stream of type user-space as a select()able descriptor
171+
array(1) {
172+
[0]=>
173+
array(5) {
174+
["message"]=>
175+
string(113) "TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost"
176+
["code"]=>
177+
int(161)
178+
["severity"]=>
179+
int(2)
180+
["terminal"]=>
181+
bool(false)
182+
["wrapper"]=>
183+
string(10) "user-space"
184+
}
185+
}
186+
AUTO ERROR
187+
188+
Warning: fread(): TestStream::stream_read - read 10 bytes more data than requested (8202 read, 8192 max) - excess data will be lost in %s on line %d
189+
190+
Warning: stream_select(): TestStream::stream_cast is not implemented! in %s on line %d
191+
192+
Warning: stream_select(): Cannot represent a stream of type user-space as a select()able descriptor in %s on line %d
193+
array(0) {
194+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
Stream errors - error_store AUTO mode behavior
3+
--FILE--
4+
<?php
5+
6+
// AUTO with ERROR mode should store NONE
7+
$context1 = stream_context_create([
8+
'stream' => [
9+
'error_mode' => STREAM_ERROR_MODE_ERROR,
10+
'error_store' => STREAM_ERROR_STORE_AUTO,
11+
]
12+
]);
13+
14+
@fopen('php://nonexistent', 'r', false, $context1);
15+
$errors1 = stream_get_errors('PHP');
16+
echo "ERROR mode AUTO: " . count($errors1) . "\n";
17+
18+
// AUTO with EXCEPTION mode should store NON_TERM
19+
$context2 = stream_context_create([
20+
'stream' => [
21+
'error_mode' => STREAM_ERROR_MODE_EXCEPTION,
22+
'error_store' => STREAM_ERROR_STORE_AUTO,
23+
]
24+
]);
25+
26+
try {
27+
fopen('php://nonexistent2', 'r', false, $context2);
28+
} catch (StreamException $e) {}
29+
30+
$errors2 = stream_get_errors('PHP');
31+
echo "EXCEPTION mode AUTO: " . count($errors2) . "\n";
32+
33+
// AUTO with SILENT mode should store ALL
34+
$context3 = stream_context_create([
35+
'stream' => [
36+
'error_mode' => STREAM_ERROR_MODE_SILENT,
37+
'error_store' => STREAM_ERROR_STORE_AUTO,
38+
]
39+
]);
40+
41+
fopen('php://nonexistent3', 'r', false, $context3);
42+
$errors3 = stream_get_errors('PHP');
43+
echo "SILENT mode AUTO: " . count($errors3) . "\n";
44+
45+
?>
46+
--EXPECTF--
47+
ERROR mode AUTO: 0
48+
EXCEPTION mode AUTO: %d
49+
SILENT mode AUTO: %d
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Stream errors - custom error handler
3+
--FILE--
4+
<?php
5+
6+
$handler_called = false;
7+
8+
$context = stream_context_create([
9+
'stream' => [
10+
'error_mode' => STREAM_ERROR_MODE_SILENT,
11+
'error_handler' => function($wrapper, $stream, $code, $message, $param) use (&$handler_called) {
12+
$handler_called = true;
13+
echo "Handler called\n";
14+
echo "Wrapper: $wrapper\n";
15+
echo "Code: $code\n";
16+
echo "Message: $message\n";
17+
echo "Param: " . ($param ?? 'null') . "\n";
18+
}
19+
]
20+
]);
21+
22+
$stream = fopen('php://nonexistent', 'r', false, $context);
23+
24+
var_dump($handler_called);
25+
26+
?>
27+
--EXPECT--
28+
Handler called
29+
Wrapper: PHP
30+
Code: 36
31+
Message: Failed to open stream: operation failed
32+
Param: php://nonexistent
33+
bool(true)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Stream errors - silent mode with error storage
3+
--FILE--
4+
<?php
5+
6+
$context = stream_context_create([
7+
'stream' => [
8+
'error_mode' => STREAM_ERROR_MODE_SILENT,
9+
]
10+
]);
11+
12+
$stream = fopen('php://nonexistent', 'r', false, $context);
13+
var_dump($stream);
14+
15+
$errors = stream_get_errors();
16+
echo "Error count: " . count($errors) . "\n";
17+
if (count($errors) > 0) {
18+
echo "First error code: " . $errors[0]['code'] . "\n";
19+
echo "First error wrapper: " . $errors[0]['wrapper'] . "\n";
20+
}
21+
22+
?>
23+
--EXPECT--
24+
bool(false)
25+
Error count: 1
26+
First error code: 36
27+
First error wrapper: PHP
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Stream errors - error_store NONE option
3+
--FILE--
4+
<?php
5+
6+
$context = stream_context_create([
7+
'stream' => [
8+
'error_mode' => STREAM_ERROR_MODE_SILENT,
9+
'error_store' => STREAM_ERROR_STORE_NONE,
10+
]
11+
]);
12+
13+
$stream = fopen('php://nonexistent', 'r', false, $context);
14+
15+
$errors = stream_get_errors();
16+
echo "Error count: " . count($errors) . "\n";
17+
18+
?>
19+
--EXPECT--
20+
Error count: 0
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Stream errors - error mode with standard error reporting
3+
--FILE--
4+
<?php
5+
6+
$context = stream_context_create([
7+
'stream' => [
8+
'error_mode' => STREAM_ERROR_MODE_ERROR,
9+
]
10+
]);
11+
12+
// This will trigger a warning
13+
$stream = fopen('php://nonexistent', 'r', false, $context);
14+
15+
var_dump($stream);
16+
17+
?>
18+
--EXPECTF--
19+
Warning: fopen(php://nonexistent): Failed to open stream: %s in %s on line %d
20+
bool(false)

0 commit comments

Comments
 (0)