Skip to content

Commit

Permalink
Update tests (#77)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
g105b authored Mar 27, 2023
1 parent 80f946c commit 971279f
Show file tree
Hide file tree
Showing 14 changed files with 706 additions and 139 deletions.
186 changes: 96 additions & 90 deletions composer.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions src/Curl.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ public function __construct(string $url = null) {
* @see http://php.net/manual/en/function.curl-close.php
*/
public function __destruct() {
curl_close($this->ch);
if(isset($this->ch)) {
curl_close($this->ch);
}
}

/**
Expand Down Expand Up @@ -200,7 +202,7 @@ public function getHandle():CurlHandle {
*/
public function getAllInfo():array {
/** @var array<string, mixed>|false $result */
$result = curl_getinfo($this->ch, 0);
$result = curl_getinfo($this->ch);
return $result ?: [];
}
}
5 changes: 3 additions & 2 deletions src/CurlMulti.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function __destruct() {
* Returns a text error message describing the given CURLM error code.
* @see http://php.net/manual/en/function.curl-multi-strerror.php
*/
public static function strerror(int $errorNum):string {
public static function strError(int $errorNum):string {
return curl_multi_strerror($errorNum);
}

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

Expand Down
2 changes: 1 addition & 1 deletion src/CurlMultiInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function __construct(array $curlMultiInfoRead) {
* The CURLMSG_DONE constant. Other return values are currently not
* available.
*/
public function getMessage():string {
public function getMessage():int {
return $this->message;
}

Expand Down
2 changes: 1 addition & 1 deletion src/CurlMultiInfoInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface CurlMultiInfoInterface {
* The CURLMSG_DONE constant. Other return values are currently not
* available.
*/
public function getMessage():string;
public function getMessage():int;

/**
* @see curl_multi_info_read
Expand Down
2 changes: 1 addition & 1 deletion src/CurlMultiInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function __destruct();
* Returns a text error message describing the given CURLM error code.
* @see http://php.net/manual/en/function.curl-multi-strerror.php
*/
public static function strerror(int $errorNum):string;
public static function strError(int $errorNum):string;

/**
* @see curl_multi_add_handle()
Expand Down
45 changes: 19 additions & 26 deletions src/CurlVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,25 @@
namespace Gt\Curl;

class CurlVersion implements CurlVersionInterface {
/** @param array<string, string> $curlVersionData */
public function __construct(
protected array $curlVersionData
) {}
public readonly int $versionNumber;
public readonly string $version;
public readonly int $sslVersionNumber;
public readonly string $sslVersion;
public readonly string $host;
public readonly int $age;
public readonly int $features;
/** @var array<string> */
public readonly array $protocols;

/** @return null|string|array<string, mixed> */
public function __get(string $key):null|string|array {
$key = $this->toSnakeCase($key);
return $this->curlVersionData[$key] ?? null;
}

protected function toSnakeCase(string $input):string {
preg_match_all(
"!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!",
$input,
$matches
);

$pieces = $matches[0];

foreach($pieces as &$piece) {
$piece = ($piece === strtoupper($piece))
? strtolower($piece)
: lcfirst($piece);
}

return implode('_', $pieces);
/** @param array<string, string|int|array<string>> $curlVersionData */
public function __construct(array $curlVersionData) {
$this->versionNumber = $curlVersionData["version_number"] ?? 0;
$this->version = $curlVersionData["version"] ?? "";
$this->sslVersionNumber = $curlVersionData["ssl_version_number"] ?? 0;
$this->sslVersion = $curlVersionData["ssl_version"] ?? "";
$this->host = $curlVersionData["host"] ?? "";
$this->age = $curlVersionData["age"] ?? 0;
$this->features = $curlVersionData["features"] ?? 0;
$this->protocols = $curlVersionData["protocols"] ?? [];
}
}
25 changes: 25 additions & 0 deletions test/phpunit/CurlMultiInfoTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php
namespace Gt\Curl\Test;

use Gt\Curl\CurlMultiInfo;
use PHPUnit\Framework\TestCase;

class CurlMultiInfoTest extends TestCase {
public function testGetMessage():void {
$sut = new CurlMultiInfo([
"msg" => CURLMSG_DONE,
"result" => CURLE_OK,
"handle" => curl_init(),
]);
self::assertSame(CURLMSG_DONE, $sut->getMessage());
}

public function testGetResult():void {
$sut = new CurlMultiInfo([
"msg" => CURLMSG_DONE,
"result" => CURLE_OK,
"handle" => curl_init(),
]);
self::assertSame(CURLE_OK, $sut->getResult());
}
}
225 changes: 225 additions & 0 deletions test/phpunit/CurlMultiTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
<?php
namespace Gt\Curl\Test;

use CurlMultiHandle;
use Exception;
use Gt\Curl\Curl;
use Gt\Curl\CurlInterface;
use Gt\Curl\CurlMulti;
use PHPUnit\Framework\TestCase;

class CurlMultiTest extends TestCase {
public function testStrError():void {
self::assertSame("No error", CurlMulti::strError(CURLM_OK));
self::assertSame("Invalid multi handle", CurlMulti::strError(CURLM_BAD_HANDLE));
self::assertSame("Invalid easy handle", CurlMulti::strError(CURLM_BAD_EASY_HANDLE));
self::assertSame("Out of memory", CurlMulti::strError(CURLM_OUT_OF_MEMORY));
self::assertSame("Internal error", CurlMulti::strError(CURLM_INTERNAL_ERROR));
}

public function testAdd():void {
$curlInterface = self::createMock(CurlInterface::class);
$curlInterface->expects(self::once())
->method("setOpt")
->with(CURLOPT_RETURNTRANSFER, true);
$curlInterface->expects(self::once())
->method("getHandle")
->willReturn(curl_init());
$sut = new CurlMulti();
$sut->add($curlInterface);
}

public function testClose():void {
$sut = new CurlMulti();
$exception = null;
try {
$sut->close();
}
catch(Exception $exception) {}
self::assertNull($exception);
}

public function testErrno():void {
$sut = new CurlMulti();
self::assertSame(CURLM_OK, $sut->errno());
}

public function testGetContent_empty():void {
$sut = new CurlMulti();
$curl = new Curl();
$sut->add($curl);
self::assertSame("", $sut->getContent($curl));
}

public function testGetContent():void {
$expectedMessage = "Hello, PHP.Gt!";
// Start a basic HTTP server that responds with a known response.
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
file_put_contents($tmpFile, $expectedMessage);
$desc = [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
2 => ["pipe", "w"],
];
$port = rand(10000, 65535);
while(true) {
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
$socket = @fsockopen(
"localhost",
$port,
$errorCode,
$errorMessage,
0.1
);
if($socket) {
break;
}
}
$curl = new Curl("http://localhost:$port");
$sut = new CurlMulti();
$sut->add($curl);
$stillRunning = 0;
do {
$sut->exec($stillRunning);
}
while($stillRunning > 0);
self::assertSame($expectedMessage, $sut->getContent($curl));
}

public function testGetHandle():void {
$sut = new CurlMulti();
self::assertInstanceOf(CurlMultiHandle::class, $sut->getHandle());
}

public function testInfoRead_nullWhenNotStarted():void {
$sut = new CurlMulti();
self::assertNull($sut->infoRead());
}

public function testInfoRead():void {
$expectedMessage = "Hello, PHP.Gt!";
// Start a basic HTTP server that responds with a known response.
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
file_put_contents($tmpFile, $expectedMessage);
$desc = [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
2 => ["pipe", "w"],
];
$port = rand(10000, 65535);
while(true) {
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
$socket = @fsockopen(
"localhost",
$port,
$errorCode,
$errorMessage,
0.1
);
if($socket) {
break;
}
}
$curl1 = new Curl("http://localhost:$port");
$curl2 = new Curl("http://localhost:$port");
$sut = new CurlMulti();
$sut->add($curl1);
$sut->add($curl2);
$stillRunning = 0;
do {
$sut->exec($stillRunning);
$info = $sut->infoRead();
}
while($stillRunning > 0);
self::assertSame(CURLMSG_DONE, $info->getMessage());
}

public function testRemove():void {
$expectedMessage = "Hello, PHP.Gt!";
// Start a basic HTTP server that responds with a known response.
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
file_put_contents($tmpFile, $expectedMessage);
$desc = [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
2 => ["pipe", "w"],
];
$port = rand(10000, 65535);
while(true) {
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
$socket = @fsockopen(
"localhost",
$port,
$errorCode,
$errorMessage,
0.1
);
if($socket) {
break;
}
}
$curl1 = new Curl("http://localhost:$port");
$curl2 = new Curl("http://localhost:$port");
$sut = new CurlMulti();
$sut->add($curl1);
$sut->add($curl2);
$sut->remove($curl1);
$stillRunning = 0;
do {
$sut->exec($stillRunning);
$info = $sut->infoRead();
}
while($stillRunning > 0);
self::assertSame($curl2, $info->getHandle());
}

public function testSelect():void {
$expectedMessage = "Hello, PHP.Gt!";
// Start a basic HTTP server that responds with a known response.
$tmpFile = tempnam(sys_get_temp_dir(), "phpgt-curl-test-");
file_put_contents($tmpFile, $expectedMessage);
$desc = [
0 => ["pipe", "r"],
1 => ["pipe", "w"],
2 => ["pipe", "w"],
];
$port = rand(10000, 65535);
while(true) {
proc_open(["php", "-S", "0.0.0.0:$port", $tmpFile], $desc, $pipes);
$socket = @fsockopen(
"localhost",
$port,
$errorCode,
$errorMessage,
0.1
);
if($socket) {
break;
}
}
$curl1 = new Curl("http://localhost:$port");
$curl2 = new Curl("http://localhost:$port");
$sut = new CurlMulti();
$sut->add($curl1);
$sut->add($curl2);
$sut->remove($curl1);
$stillRunning = 0;
do {
$sut->exec($stillRunning);
}
// Note: we're only waiting for one of the curl requests to finish, so there
// will be one left running when `select` is called.
while($stillRunning > 1);
self::assertSame(1, $sut->select(0.1));
}

public function testSetOpt():void {
$sut = new CurlMulti();
$exception = null;
try {
$sut->setOpt(CURLMOPT_MAXCONNECTS, 1);
}
catch(Exception $exception) {}
self::assertNull($exception);
}
}
Loading

0 comments on commit 971279f

Please sign in to comment.