Skip to content

Commit 971279f

Browse files
author
Greg Bowler
authored
Update tests (#77)
* build: upgrade phpunit config * tweak: only close if already open * test: test coverage for curl class * test: test coverage for curlobjectlookup class * test: test coverage for curlobjectlookup class * test: test coverage for curlmulti class * test: test coverage for curlshare class * test: test coverage for curlmultiinfo class
1 parent 80f946c commit 971279f

14 files changed

+706
-139
lines changed

composer.lock

Lines changed: 96 additions & 90 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Curl.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ public function __construct(string $url = null) {
2020
* @see http://php.net/manual/en/function.curl-close.php
2121
*/
2222
public function __destruct() {
23-
curl_close($this->ch);
23+
if(isset($this->ch)) {
24+
curl_close($this->ch);
25+
}
2426
}
2527

2628
/**
@@ -200,7 +202,7 @@ public function getHandle():CurlHandle {
200202
*/
201203
public function getAllInfo():array {
202204
/** @var array<string, mixed>|false $result */
203-
$result = curl_getinfo($this->ch, 0);
205+
$result = curl_getinfo($this->ch);
204206
return $result ?: [];
205207
}
206208
}

src/CurlMulti.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public function __destruct() {
1818
* Returns a text error message describing the given CURLM error code.
1919
* @see http://php.net/manual/en/function.curl-multi-strerror.php
2020
*/
21-
public static function strerror(int $errorNum):string {
21+
public static function strError(int $errorNum):string {
2222
return curl_multi_strerror($errorNum);
2323
}
2424

@@ -27,7 +27,8 @@ public static function strerror(int $errorNum):string {
2727
* @throws CurlException if a CURLM_XXX error is made
2828
*/
2929
public function add(CurlInterface $curl):void {
30-
// $curl->setOpt(CURLOPT_RETURNTRANSFER, true);
30+
// The RETURNTRANSFER option must be set to be able to use the internal buffers.
31+
$curl->setOpt(CURLOPT_RETURNTRANSFER, true);
3132
curl_multi_add_handle($this->mh, $curl->getHandle());
3233
}
3334

src/CurlMultiInfo.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function __construct(array $curlMultiInfoRead) {
2323
* The CURLMSG_DONE constant. Other return values are currently not
2424
* available.
2525
*/
26-
public function getMessage():string {
26+
public function getMessage():int {
2727
return $this->message;
2828
}
2929

src/CurlMultiInfoInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ interface CurlMultiInfoInterface {
77
* The CURLMSG_DONE constant. Other return values are currently not
88
* available.
99
*/
10-
public function getMessage():string;
10+
public function getMessage():int;
1111

1212
/**
1313
* @see curl_multi_info_read

src/CurlMultiInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function __destruct();
1717
* Returns a text error message describing the given CURLM error code.
1818
* @see http://php.net/manual/en/function.curl-multi-strerror.php
1919
*/
20-
public static function strerror(int $errorNum):string;
20+
public static function strError(int $errorNum):string;
2121

2222
/**
2323
* @see curl_multi_add_handle()

src/CurlVersion.php

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,25 @@
22
namespace Gt\Curl;
33

44
class CurlVersion implements CurlVersionInterface {
5-
/** @param array<string, string> $curlVersionData */
6-
public function __construct(
7-
protected array $curlVersionData
8-
) {}
5+
public readonly int $versionNumber;
6+
public readonly string $version;
7+
public readonly int $sslVersionNumber;
8+
public readonly string $sslVersion;
9+
public readonly string $host;
10+
public readonly int $age;
11+
public readonly int $features;
12+
/** @var array<string> */
13+
public readonly array $protocols;
914

10-
/** @return null|string|array<string, mixed> */
11-
public function __get(string $key):null|string|array {
12-
$key = $this->toSnakeCase($key);
13-
return $this->curlVersionData[$key] ?? null;
14-
}
15-
16-
protected function toSnakeCase(string $input):string {
17-
preg_match_all(
18-
"!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!",
19-
$input,
20-
$matches
21-
);
22-
23-
$pieces = $matches[0];
24-
25-
foreach($pieces as &$piece) {
26-
$piece = ($piece === strtoupper($piece))
27-
? strtolower($piece)
28-
: lcfirst($piece);
29-
}
30-
31-
return implode('_', $pieces);
15+
/** @param array<string, string|int|array<string>> $curlVersionData */
16+
public function __construct(array $curlVersionData) {
17+
$this->versionNumber = $curlVersionData["version_number"] ?? 0;
18+
$this->version = $curlVersionData["version"] ?? "";
19+
$this->sslVersionNumber = $curlVersionData["ssl_version_number"] ?? 0;
20+
$this->sslVersion = $curlVersionData["ssl_version"] ?? "";
21+
$this->host = $curlVersionData["host"] ?? "";
22+
$this->age = $curlVersionData["age"] ?? 0;
23+
$this->features = $curlVersionData["features"] ?? 0;
24+
$this->protocols = $curlVersionData["protocols"] ?? [];
3225
}
3326
}

test/phpunit/CurlMultiInfoTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
namespace Gt\Curl\Test;
3+
4+
use Gt\Curl\CurlMultiInfo;
5+
use PHPUnit\Framework\TestCase;
6+
7+
class CurlMultiInfoTest extends TestCase {
8+
public function testGetMessage():void {
9+
$sut = new CurlMultiInfo([
10+
"msg" => CURLMSG_DONE,
11+
"result" => CURLE_OK,
12+
"handle" => curl_init(),
13+
]);
14+
self::assertSame(CURLMSG_DONE, $sut->getMessage());
15+
}
16+
17+
public function testGetResult():void {
18+
$sut = new CurlMultiInfo([
19+
"msg" => CURLMSG_DONE,
20+
"result" => CURLE_OK,
21+
"handle" => curl_init(),
22+
]);
23+
self::assertSame(CURLE_OK, $sut->getResult());
24+
}
25+
}

test/phpunit/CurlMultiTest.php

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
<?php
2+
namespace Gt\Curl\Test;
3+
4+
use CurlMultiHandle;
5+
use Exception;
6+
use Gt\Curl\Curl;
7+
use Gt\Curl\CurlInterface;
8+
use Gt\Curl\CurlMulti;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class CurlMultiTest extends TestCase {
12+
public function testStrError():void {
13+
self::assertSame("No error", CurlMulti::strError(CURLM_OK));
14+
self::assertSame("Invalid multi handle", CurlMulti::strError(CURLM_BAD_HANDLE));
15+
self::assertSame("Invalid easy handle", CurlMulti::strError(CURLM_BAD_EASY_HANDLE));
16+
self::assertSame("Out of memory", CurlMulti::strError(CURLM_OUT_OF_MEMORY));
17+
self::assertSame("Internal error", CurlMulti::strError(CURLM_INTERNAL_ERROR));
18+
}
19+
20+
public function testAdd():void {
21+
$curlInterface = self::createMock(CurlInterface::class);
22+
$curlInterface->expects(self::once())
23+
->method("setOpt")
24+
->with(CURLOPT_RETURNTRANSFER, true);
25+
$curlInterface->expects(self::once())
26+
->method("getHandle")
27+
->willReturn(curl_init());
28+
$sut = new CurlMulti();
29+
$sut->add($curlInterface);
30+
}
31+
32+
public function testClose():void {
33+
$sut = new CurlMulti();
34+
$exception = null;
35+
try {
36+
$sut->close();
37+
}
38+
catch(Exception $exception) {}
39+
self::assertNull($exception);
40+
}
41+
42+
public function testErrno():void {
43+
$sut = new CurlMulti();
44+
self::assertSame(CURLM_OK, $sut->errno());
45+
}
46+
47+
public function testGetContent_empty():void {
48+
$sut = new CurlMulti();
49+
$curl = new Curl();
50+
$sut->add($curl);
51+
self::assertSame("", $sut->getContent($curl));
52+
}
53+
54+
public function testGetContent():void {
55+
$expectedMessage = "Hello, PHP.Gt!";
56+
// Start a basic HTTP server that responds with a known response.
57+
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
58+
file_put_contents($tmpFile, $expectedMessage);
59+
$desc = [
60+
0 => ["pipe", "r"],
61+
1 => ["pipe", "w"],
62+
2 => ["pipe", "w"],
63+
];
64+
$port = rand(10000, 65535);
65+
while(true) {
66+
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
67+
$socket = @fsockopen(
68+
"localhost",
69+
$port,
70+
$errorCode,
71+
$errorMessage,
72+
0.1
73+
);
74+
if($socket) {
75+
break;
76+
}
77+
}
78+
$curl = new Curl("http://localhost:$port");
79+
$sut = new CurlMulti();
80+
$sut->add($curl);
81+
$stillRunning = 0;
82+
do {
83+
$sut->exec($stillRunning);
84+
}
85+
while($stillRunning > 0);
86+
self::assertSame($expectedMessage, $sut->getContent($curl));
87+
}
88+
89+
public function testGetHandle():void {
90+
$sut = new CurlMulti();
91+
self::assertInstanceOf(CurlMultiHandle::class, $sut->getHandle());
92+
}
93+
94+
public function testInfoRead_nullWhenNotStarted():void {
95+
$sut = new CurlMulti();
96+
self::assertNull($sut->infoRead());
97+
}
98+
99+
public function testInfoRead():void {
100+
$expectedMessage = "Hello, PHP.Gt!";
101+
// Start a basic HTTP server that responds with a known response.
102+
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
103+
file_put_contents($tmpFile, $expectedMessage);
104+
$desc = [
105+
0 => ["pipe", "r"],
106+
1 => ["pipe", "w"],
107+
2 => ["pipe", "w"],
108+
];
109+
$port = rand(10000, 65535);
110+
while(true) {
111+
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
112+
$socket = @fsockopen(
113+
"localhost",
114+
$port,
115+
$errorCode,
116+
$errorMessage,
117+
0.1
118+
);
119+
if($socket) {
120+
break;
121+
}
122+
}
123+
$curl1 = new Curl("http://localhost:$port");
124+
$curl2 = new Curl("http://localhost:$port");
125+
$sut = new CurlMulti();
126+
$sut->add($curl1);
127+
$sut->add($curl2);
128+
$stillRunning = 0;
129+
do {
130+
$sut->exec($stillRunning);
131+
$info = $sut->infoRead();
132+
}
133+
while($stillRunning > 0);
134+
self::assertSame(CURLMSG_DONE, $info->getMessage());
135+
}
136+
137+
public function testRemove():void {
138+
$expectedMessage = "Hello, PHP.Gt!";
139+
// Start a basic HTTP server that responds with a known response.
140+
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
141+
file_put_contents($tmpFile, $expectedMessage);
142+
$desc = [
143+
0 => ["pipe", "r"],
144+
1 => ["pipe", "w"],
145+
2 => ["pipe", "w"],
146+
];
147+
$port = rand(10000, 65535);
148+
while(true) {
149+
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
150+
$socket = @fsockopen(
151+
"localhost",
152+
$port,
153+
$errorCode,
154+
$errorMessage,
155+
0.1
156+
);
157+
if($socket) {
158+
break;
159+
}
160+
}
161+
$curl1 = new Curl("http://localhost:$port");
162+
$curl2 = new Curl("http://localhost:$port");
163+
$sut = new CurlMulti();
164+
$sut->add($curl1);
165+
$sut->add($curl2);
166+
$sut->remove($curl1);
167+
$stillRunning = 0;
168+
do {
169+
$sut->exec($stillRunning);
170+
$info = $sut->infoRead();
171+
}
172+
while($stillRunning > 0);
173+
self::assertSame($curl2, $info->getHandle());
174+
}
175+
176+
public function testSelect():void {
177+
$expectedMessage = "Hello, PHP.Gt!";
178+
// Start a basic HTTP server that responds with a known response.
179+
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
180+
file_put_contents($tmpFile, $expectedMessage);
181+
$desc = [
182+
0 => ["pipe", "r"],
183+
1 => ["pipe", "w"],
184+
2 => ["pipe", "w"],
185+
];
186+
$port = rand(10000, 65535);
187+
while(true) {
188+
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
189+
$socket = @fsockopen(
190+
"localhost",
191+
$port,
192+
$errorCode,
193+
$errorMessage,
194+
0.1
195+
);
196+
if($socket) {
197+
break;
198+
}
199+
}
200+
$curl1 = new Curl("http://localhost:$port");
201+
$curl2 = new Curl("http://localhost:$port");
202+
$sut = new CurlMulti();
203+
$sut->add($curl1);
204+
$sut->add($curl2);
205+
$sut->remove($curl1);
206+
$stillRunning = 0;
207+
do {
208+
$sut->exec($stillRunning);
209+
}
210+
// Note: we're only waiting for one of the curl requests to finish, so there
211+
// will be one left running when `select` is called.
212+
while($stillRunning > 1);
213+
self::assertSame(1, $sut->select(0.1));
214+
}
215+
216+
public function testSetOpt():void {
217+
$sut = new CurlMulti();
218+
$exception = null;
219+
try {
220+
$sut->setOpt(CURLMOPT_MAXCONNECTS, 1);
221+
}
222+
catch(Exception $exception) {}
223+
self::assertNull($exception);
224+
}
225+
}

0 commit comments

Comments
 (0)