commit
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
$server = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errstr);
|
||||
|
||||
if (!$server) {
|
||||
die("Error: $errstr ($errno)");
|
||||
}
|
||||
|
||||
function send_sse($client, $id, $event, $data, $retry = 3000) {
|
||||
$sseData = "id: $id\n";
|
||||
$sseData .= "event: $event\n";
|
||||
$sseData .= "data: " . json_encode($data) . "\n";
|
||||
$sseData .= "retry: $retry\n\n"; // The retry comment is optional and should follow client's needs
|
||||
|
||||
fwrite($client, $sseData);
|
||||
fflush($client);
|
||||
}
|
||||
|
||||
while ($client = @stream_socket_accept($server)) {
|
||||
// 读取请求
|
||||
$request = fread($client, 1024);
|
||||
list($headers, $body) = explode("\r\n\r\n", $request, 2);
|
||||
// 简单解析请求头
|
||||
$headerLines = explode("\r\n", $headers);
|
||||
$requestLine = array_shift($headerLines);
|
||||
preg_match('/\btimeout:\s*true\b/i', $headers, $timeoutMatch);
|
||||
preg_match('/\b(bodytype):[ ]*([\w\d]+)\b/i', $headers, $bodyTypeMatch);
|
||||
$bodyType = isset($bodyTypeMatch[2]) ? $bodyTypeMatch[2] : null;
|
||||
preg_match('/^(GET|POST|PUT|DELETE)\s(\/\S*)\sHTTP\/1.1/', $requestLine, $matches);
|
||||
$method = $matches[1];
|
||||
$path = $matches[2];
|
||||
|
||||
|
||||
$headerAssoc = [];
|
||||
|
||||
foreach ($headerLines as $header) {
|
||||
list($name, $value) = explode(": ", $header, 2);
|
||||
$headerAssoc[strtolower($name)] = $value;
|
||||
}
|
||||
if (substr($path, 0, 4) === '/sse') {
|
||||
$responseHeaders = "HTTP/1.1 200 OK\r\n" .
|
||||
"Content-Type: text/event-stream;charset=UTF-8\r\n" .
|
||||
"Cache-Control: no-cache\r\n" .
|
||||
"Connection: keep-alive\r\n";
|
||||
foreach ($headerAssoc as $name => $value) {
|
||||
$responseHeaders .= $name . ": " . $value . "\r\n";
|
||||
}
|
||||
$responseHeaders .= "\r\n";
|
||||
fwrite($client, $responseHeaders);
|
||||
// 刷新缓冲区,确保头部被立刻发送
|
||||
flush();
|
||||
|
||||
// 模拟发送事件流
|
||||
$count = 0;
|
||||
while ($count < 5) {
|
||||
$data = [
|
||||
"count" => $count
|
||||
];
|
||||
$sseData = "id: sse-test\n";
|
||||
$sseData .= "event: flow\n";
|
||||
$sseData .= "data: " . json_encode($data) . "\n";
|
||||
$sseData .= "retry: 3000\n\n"; // 重试时间可选
|
||||
fwrite($client, $sseData);
|
||||
|
||||
// 再次刷新缓冲区,以确保数据被发送
|
||||
flush();
|
||||
|
||||
// 等待100毫秒
|
||||
usleep(100000);
|
||||
$count++;
|
||||
}
|
||||
fclose($client);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($timeoutMatch) {
|
||||
// 模拟超时
|
||||
sleep(5);
|
||||
$responseHeaders = "HTTP/1.1 500 Internal Server Error\r\n" .
|
||||
"Content-Type: text/plain\r\n" .
|
||||
"Connection: close\r\n\r\n";
|
||||
fwrite($client, $responseHeaders . "Server Timeout");
|
||||
} else {
|
||||
$headerAssoc = [];
|
||||
foreach ($headerLines as $headerLine) {
|
||||
list($key, $value) = explode(': ', $headerLine, 2);
|
||||
$headerAssoc[strtolower($key)] = trim($value);
|
||||
}
|
||||
|
||||
// 获取路径和请求方法
|
||||
preg_match('/^(GET|POST|PUT|DELETE)\s(\/\S*)\sHTTP\/1.1/', $requestLine, $matches);
|
||||
$method = $matches[1];
|
||||
$path = $matches[2];
|
||||
|
||||
// 构建响应头
|
||||
$responseHeaders = "HTTP/1.1 200 OK\r\n" .
|
||||
"Connection: close\r\n" .
|
||||
"Content-Type: application/json\r\n" .
|
||||
"x-acs-request-id: A45EE076-334D-5012-9746-A8F828D20FD4\r\n" .
|
||||
"http-method: $method\r\n" .
|
||||
"pathname: $path\r\n" .
|
||||
"raw-body: $body\r\n";
|
||||
|
||||
// 构建响应体
|
||||
$responseBody = "";
|
||||
|
||||
echo $bodyType."\n";
|
||||
|
||||
switch ($bodyType) {
|
||||
case 'array':
|
||||
$responseBody = json_encode(["AppId", "ClassId", "UserId"]);
|
||||
break;
|
||||
case 'error':
|
||||
$responseHeaders = "HTTP/1.1 400 Bad Request\r\n" .
|
||||
"Connection: close\r\n" .
|
||||
"Content-Type: application/json\r\n" .
|
||||
"x-acs-request-id: A45EE076-334D-5012-9746-A8F828D20FD4\r\n" .
|
||||
"http-method: $method\r\n" .
|
||||
"pathname: $path\r\n";
|
||||
$responseBody = json_encode([
|
||||
"Code" => "error code",
|
||||
"Message" => "error message",
|
||||
"RequestId" => "A45EE076-334D-5012-9746-A8F828D20FD4",
|
||||
"Description" => "error description",
|
||||
"AccessDeniedDetail" => new stdClass()
|
||||
]);
|
||||
break;
|
||||
case 'error1':
|
||||
$responseHeaders = "HTTP/1.1 400 Bad Request\r\n" .
|
||||
"Connection: close\r\n" .
|
||||
"Content-Type: application/json\r\n" .
|
||||
"x-acs-request-id: A45EE076-334D-5012-9746-A8F828D20FD4\r\n" .
|
||||
"http-method: $method\r\n" .
|
||||
"pathname: $path\r\n";
|
||||
$responseBody = json_encode([
|
||||
"Code" => "error code",
|
||||
"Message" => "error message",
|
||||
"RequestId" => "A45EE076-334D-5012-9746-A8F828D20FD4",
|
||||
"Description" => "error description",
|
||||
"AccessDeniedDetail" => new stdClass(),
|
||||
"accessDeniedDetail" => ["test" => 0]
|
||||
]);
|
||||
break;
|
||||
case 'error2':
|
||||
$responseHeaders = "HTTP/1.1 400 Bad Request\r\n" .
|
||||
"Connection: close\r\n" .
|
||||
"Content-Type: application/json\r\n" .
|
||||
"x-acs-request-id: A45EE076-334D-5012-9746-A8F828D20FD4\r\n" .
|
||||
"http-method: $method\r\n" .
|
||||
"pathname: $path\r\n";
|
||||
$responseBody = json_encode([
|
||||
"Code" => "error code",
|
||||
"Message" => "error message",
|
||||
"RequestId" => "A45EE076-334D-5012-9746-A8F828D20FD4",
|
||||
"Description" => "error description",
|
||||
"accessDeniedDetail" => ["test" => 0]
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
$responseBody = json_encode([
|
||||
"AppId" => "test",
|
||||
"ClassId" => "test",
|
||||
"UserId" => 123
|
||||
]);
|
||||
}
|
||||
|
||||
fwrite($client, $responseHeaders . "\r\n" . $responseBody);
|
||||
}
|
||||
fclose($client);
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose($server);
|
||||
@@ -0,0 +1,512 @@
|
||||
<?php
|
||||
|
||||
namespace Darabonba\OpenApi\Tests;
|
||||
|
||||
use Darabonba\OpenApi\OpenApiClient;
|
||||
use Darabonba\OpenApi\Utils;
|
||||
|
||||
use Darabonba\OpenApi\Models\Config;
|
||||
use Darabonba\OpenApi\Models\Params;
|
||||
use Darabonba\OpenApi\Models\GlobalParameters;
|
||||
use AlibabaCloud\Dara\Models\RuntimeOptions;
|
||||
use AlibabaCloud\Dara\Models\ExtendsParameters;
|
||||
use Darabonba\OpenApi\Models\OpenApiRequest;
|
||||
use AlibabaCloud\Credentials\Credential;
|
||||
use AlibabaCloud\Dara\RetryPolicy\RetryCondition;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use AlibabaCloud\Dara\RetryPolicy\RetryOptions;
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class OpenApiClientTest extends TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $pid = 0;
|
||||
private static $serverStarted = false;
|
||||
private static $serverPid = 0;
|
||||
|
||||
/**
|
||||
* Ensure Mock Server is running (PHP 5.6-8.1 compatible)
|
||||
*/
|
||||
private static function ensureMockServer()
|
||||
{
|
||||
if (self::$serverStarted) {
|
||||
return;
|
||||
}
|
||||
// 启动 Mock 服务器
|
||||
$server = __DIR__ . '/Mock/MockServer.php';
|
||||
$command = "php " . escapeshellarg($server) . " > /dev/null 2>&1 & echo $!";
|
||||
$output = shell_exec($command);
|
||||
self::$serverPid = (int)trim($output);
|
||||
self::$serverStarted = true;
|
||||
// 等待服务器启动并验证
|
||||
sleep(2); // 增加等待时间确保服务器完全启动
|
||||
// 注册关闭钩子
|
||||
register_shutdown_function(array(__CLASS__, 'stopMockServer'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop Mock Server
|
||||
*/
|
||||
public static function stopMockServer()
|
||||
{
|
||||
if (self::$serverStarted && self::$serverPid > 0) {
|
||||
shell_exec('kill ' . self::$serverPid);
|
||||
self::$serverStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @before
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
// Mock 服务器已在 setUpBeforeClass 中启动
|
||||
}
|
||||
|
||||
/**
|
||||
* @after
|
||||
*/
|
||||
protected function cleanup()
|
||||
{
|
||||
// Mock 服务器会在 tearDownAfterClass 中关闭
|
||||
}
|
||||
|
||||
public function testConfig(){
|
||||
$globalParameters = new GlobalParameters([
|
||||
"headers" => [
|
||||
"global-key" => "global-value"
|
||||
],
|
||||
"queries" => [
|
||||
"global-query" => "global-value"
|
||||
]
|
||||
]);
|
||||
$config = new Config([
|
||||
"endpoint" => "config.endpoint",
|
||||
"endpointType" => "regional",
|
||||
"network" => "config.network",
|
||||
"suffix" => "config.suffix",
|
||||
"protocol" => "config.protocol",
|
||||
"method" => "config.method",
|
||||
"regionId" => "config.regionId",
|
||||
"userAgent" => "config.userAgent",
|
||||
"readTimeout" => 3000,
|
||||
"connectTimeout" => 3000,
|
||||
"httpProxy" => "config.httpProxy",
|
||||
"httpsProxy" => "config.httpsProxy",
|
||||
"noProxy" => "config.noProxy",
|
||||
"socks5Proxy" => "config.socks5Proxy",
|
||||
"socks5NetWork" => "config.socks5NetWork",
|
||||
"maxIdleConns" => 128,
|
||||
"signatureVersion" => "config.signatureVersion",
|
||||
"signatureAlgorithm" => "config.signatureAlgorithm",
|
||||
"globalParameters" => $globalParameters
|
||||
]);
|
||||
$creConfig = new \AlibabaCloud\Credentials\Credential\Config([
|
||||
"accessKeyId" => "accessKeyId",
|
||||
"accessKeySecret" => "accessKeySecret",
|
||||
"securityToken" => "securityToken",
|
||||
"type" => "sts"
|
||||
]);
|
||||
$credential = new Credential($creConfig);
|
||||
$config->credential = $credential;
|
||||
$client = new OpenApiClient($config);
|
||||
$this->assertInstanceOf(OpenApiClient::class, $client);
|
||||
|
||||
$config->accessKeyId = "ak";
|
||||
$config->accessKeySecret = "secret";
|
||||
$config->securityToken = "token";
|
||||
$config->type = "sts";
|
||||
$client = new OpenApiClient($config);
|
||||
$this->assertInstanceOf(OpenApiClient::class, $client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Config
|
||||
*/
|
||||
public static function createConfig(){
|
||||
$globalParameters = new GlobalParameters([
|
||||
"headers" => [
|
||||
"global-key" => "global-value"
|
||||
],
|
||||
"queries" => [
|
||||
"global-query" => "global-value"
|
||||
]
|
||||
]);
|
||||
$config = new Config([
|
||||
"accessKeyId" => "ak",
|
||||
"accessKeySecret" => "secret",
|
||||
"securityToken" => "token",
|
||||
"type" => "sts",
|
||||
"userAgent" => "config.userAgent",
|
||||
"readTimeout" => 3000,
|
||||
"connectTimeout" => 3000,
|
||||
"maxIdleConns" => 128,
|
||||
"signatureVersion" => "config.signatureVersion",
|
||||
"signatureAlgorithm" => "ACS3-HMAC-SHA256",
|
||||
"globalParameters" => $globalParameters
|
||||
]);
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RuntimeOptions
|
||||
*/
|
||||
public static function createRuntimeOptions(){
|
||||
$runtime = new RuntimeOptions([
|
||||
"readTimeout" => 4000,
|
||||
"connectTimeout" => 4000,
|
||||
"maxIdleConns" => 100,
|
||||
"autoretry" => true,
|
||||
"backoffPolicy" => "no",
|
||||
"backoffPeriod" => 1,
|
||||
"ignoreSSL" => true,
|
||||
"retryOptions" => new RetryOptions([
|
||||
"retryable" => false,
|
||||
"retryCondition" => [new RetryCondition([
|
||||
"retryOnNonIdempotent" => true,
|
||||
"retryOnThrottling" => true
|
||||
])]
|
||||
]),
|
||||
"extendsParameters" => new ExtendsParameters([
|
||||
"headers" => [
|
||||
"extends-key" => "extends-value"
|
||||
],
|
||||
])
|
||||
]);
|
||||
return $runtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OpenApiRequest
|
||||
*/
|
||||
public static function createOpenApiRequest(){
|
||||
$query = [];
|
||||
$query["key1"] = "value";
|
||||
$query["key2"] = 1;
|
||||
$query["key3"] = true;
|
||||
$body = [];
|
||||
$body["key1"] = "value";
|
||||
$body["key2"] = 1;
|
||||
$body["key3"] = true;
|
||||
$headers = [
|
||||
"for-test" => "sdk"
|
||||
];
|
||||
$req = new OpenApiRequest([
|
||||
"headers" => $headers,
|
||||
"query" => Utils::query($query),
|
||||
"body" => Utils::parseToMap($body)
|
||||
]);
|
||||
return $req;
|
||||
}
|
||||
|
||||
public function testCallApiForRPCWithV2Sign_AK_Form(){
|
||||
self::ensureMockServer();
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->signatureAlgorithm = "v2";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/",
|
||||
"method" => "POST",
|
||||
"authType" => "AK",
|
||||
"style" => "RPC",
|
||||
"reqBodyType" => "formData",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCallApiForRPCWithV2Sign_Anonymous_JSON(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->signatureAlgorithm = "v2";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/",
|
||||
"method" => "POST",
|
||||
"authType" => "Anonymous",
|
||||
"style" => "RPC",
|
||||
"reqBodyType" => "json",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCallApiForROAWithV2Sign_HTTPS_AK_Form(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->signatureAlgorithm = "v2";
|
||||
$config->protocol = "HTTP";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/test",
|
||||
"method" => "POST",
|
||||
"authType" => "AK",
|
||||
"style" => "ROA",
|
||||
"reqBodyType" => "formData",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCallApiForROAWithV2Sign_Anonymous_JSON(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->signatureAlgorithm = "v2";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/test",
|
||||
"method" => "POST",
|
||||
"authType" => "Anonymous",
|
||||
"style" => "ROA",
|
||||
"reqBodyType" => "json",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCallApiForRPCWithV3Sign_AK_Form(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/",
|
||||
"method" => "POST",
|
||||
"authType" => "AK",
|
||||
"style" => "RPC",
|
||||
"reqBodyType" => "formData",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCallApiForRPCWithV3Sign_Anonymous_JSON(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/",
|
||||
"method" => "POST",
|
||||
"authType" => "Anonymous",
|
||||
"style" => "RPC",
|
||||
"reqBodyType" => "json",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCallApiForROAWithV3Sign_AK_Form(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/test",
|
||||
"method" => "POST",
|
||||
"authType" => "AK",
|
||||
"style" => "ROA",
|
||||
"reqBodyType" => "formData",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCallApiForROAWithV3Sign_Anonymous_JSON(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/test",
|
||||
"method" => "POST",
|
||||
"authType" => "Anonymous",
|
||||
"style" => "ROA",
|
||||
"reqBodyType" => "json",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['AppId'])) {
|
||||
$this->assertEquals('test', $response['AppId']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testResponseBodyType(){
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/test",
|
||||
"method" => "POST",
|
||||
"authType" => "AK",
|
||||
"style" => "ROA",
|
||||
"reqBodyType" => "formData",
|
||||
"bodyType" => "json"
|
||||
]);
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertTrue(is_array($response));
|
||||
|
||||
$params->bodyType = "array";
|
||||
$request->headers['bodytype'] = 'array';
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertTrue(is_array($response));
|
||||
// Mock server returns ["AppId", "ClassId", "UserId"] for array type
|
||||
$this->assertNotEmpty($response);
|
||||
|
||||
$params->bodyType = "string";
|
||||
$request->headers['bodytype'] = 'string';
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
// For string type, check if response body exists
|
||||
$this->assertNotEmpty($response);
|
||||
if (is_array($response) && isset($response['body'])) {
|
||||
$this->assertTrue(is_string($response['body']));
|
||||
}
|
||||
|
||||
$params->bodyType = "byte";
|
||||
$request->headers['bodytype'] = 'byte';
|
||||
$response = $client->callApi($params, $request, $runtime);
|
||||
$this->assertNotEmpty($response);
|
||||
}
|
||||
|
||||
public function testCallSSEApiWithSignV3()
|
||||
{
|
||||
self::ensureMockServer();
|
||||
|
||||
// 额外等待确保 Mock 服务器完全启动 (for CI environments)
|
||||
usleep(500000); // 0.5秒
|
||||
|
||||
$config = self::createConfig();
|
||||
$runtime = self::createRuntimeOptions();
|
||||
$config->protocol = "HTTP";
|
||||
$config->endpoint = "127.0.0.1:8000";
|
||||
$client = new OpenApiClient($config);
|
||||
$request = self::createOpenApiRequest();
|
||||
$params = new Params([
|
||||
"action" => "TestAPI",
|
||||
"version" => "2022-06-01",
|
||||
"protocol" => "HTTPS",
|
||||
"pathname" => "/sse",
|
||||
"method" => "POST",
|
||||
"authType" => "AK",
|
||||
"style" => "ROA",
|
||||
"reqBodyType" => "json",
|
||||
"bodyType" => "sse"
|
||||
]);
|
||||
$response = $client->callSSEApi($params, $request, $runtime);
|
||||
|
||||
|
||||
// Add more assertions as needed
|
||||
$events = [];
|
||||
|
||||
// SSE events are typically separated by double newline
|
||||
foreach ($response as $event) {
|
||||
$this->assertEquals(200, $event->statusCode);
|
||||
$headers = $event->headers;
|
||||
$this->assertEquals('text/event-stream;charset=UTF-8', $headers['Content-Type'][0]);
|
||||
$this->assertEquals('sdk', $headers['for-test'][0]);
|
||||
$userAgentArray = explode(' ', $headers['user-agent'][0]);
|
||||
$this->assertEquals('config.userAgent', end($userAgentArray));
|
||||
$this->assertEquals('global-value', $headers['global-key'][0]);
|
||||
$this->assertEquals('extends-value', $headers['extends-key'][0]);
|
||||
$this->assertNotEmpty($headers['x-acs-signature-nonce'][0]);
|
||||
$this->assertNotEmpty($headers['x-acs-date'][0]);
|
||||
$this->assertEquals('application/json', $headers['accept'][0]);
|
||||
$event = $event->event->toArray();
|
||||
// var_dump($event);
|
||||
$events[] = json_decode($event['data'], true);
|
||||
}
|
||||
$expectedEvents = [
|
||||
['count' => 0],
|
||||
['count' => 1],
|
||||
['count' => 2],
|
||||
['count' => 3],
|
||||
['count' => 4],
|
||||
];
|
||||
$this->assertCount(5, $events);
|
||||
$this->assertEquals($expectedEvents, $events);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,586 @@
|
||||
<?php
|
||||
|
||||
namespace Darabonba\OpenApi\Tests;
|
||||
|
||||
use Darabonba\OpenApi\Utils;
|
||||
use Darabonba\OpenApi\Sm3;
|
||||
use AlibabaCloud\Dara\Request;
|
||||
use AlibabaCloud\Dara\Util\BytesUtil;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class UtilsTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Test getEndpoint function
|
||||
*/
|
||||
public function testGetEndpoint()
|
||||
{
|
||||
// Test internal endpoint
|
||||
$endpoint = Utils::getEndpoint('ecs.aliyuncs.com', false, 'internal');
|
||||
$this->assertEquals('ecs-internal.aliyuncs.com', $endpoint);
|
||||
|
||||
// Test accelerate endpoint
|
||||
$endpoint = Utils::getEndpoint('oss.aliyuncs.com', true, 'accelerate');
|
||||
$this->assertEquals('oss-accelerate.aliyuncs.com', $endpoint);
|
||||
|
||||
// Test normal endpoint
|
||||
$endpoint = Utils::getEndpoint('ecs.aliyuncs.com', false, 'public');
|
||||
$this->assertEquals('ecs.aliyuncs.com', $endpoint);
|
||||
|
||||
// Test accelerate without flag
|
||||
$endpoint = Utils::getEndpoint('oss.aliyuncs.com', false, 'accelerate');
|
||||
$this->assertEquals('oss.aliyuncs.com', $endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getThrottlingTimeLeft function
|
||||
*/
|
||||
public function testGetThrottlingTimeLeft()
|
||||
{
|
||||
// Test with both headers
|
||||
$headers = array(
|
||||
'x-ratelimit-user-api' => 'Remaining:10,TimeLeft:5',
|
||||
'x-ratelimit-user' => 'Remaining:20,TimeLeft:3'
|
||||
);
|
||||
$timeLeft = Utils::getThrottlingTimeLeft($headers);
|
||||
$this->assertEquals(5, $timeLeft);
|
||||
|
||||
// Test with empty headers
|
||||
$headers = array();
|
||||
$timeLeft = Utils::getThrottlingTimeLeft($headers);
|
||||
$this->assertEquals(0, $timeLeft);
|
||||
|
||||
// Test with only one header
|
||||
$headers = array('x-ratelimit-user' => 'TimeLeft:10');
|
||||
$timeLeft = Utils::getThrottlingTimeLeft($headers);
|
||||
$this->assertEquals(10, $timeLeft);
|
||||
|
||||
// Test with invalid value
|
||||
$headers = array('x-ratelimit-user-api' => 'Invalid');
|
||||
$timeLeft = Utils::getThrottlingTimeLeft($headers);
|
||||
$this->assertEquals(0, $timeLeft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test hash function
|
||||
*/
|
||||
public function testHash()
|
||||
{
|
||||
// Test SHA256
|
||||
$data = 'test message';
|
||||
$bytes = BytesUtil::from($data);
|
||||
$result = Utils::hash($bytes, 'ACS3-HMAC-SHA256');
|
||||
|
||||
$this->checkInternalType('string', $result);
|
||||
$this->assertEquals(32, strlen($result)); // SHA256 produces 32 bytes
|
||||
|
||||
// Test SM3
|
||||
$result = Utils::hash($bytes, 'ACS3-HMAC-SM3');
|
||||
$this->checkInternalType('string', $result);
|
||||
$this->assertEquals(32, strlen($result)); // SM3 produces 32 bytes
|
||||
|
||||
// Test default case
|
||||
$result = Utils::hash($bytes, 'UNKNOWN');
|
||||
$this->checkInternalType('array', $result);
|
||||
$this->assertEmpty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getNonce function
|
||||
*/
|
||||
public function testGetNonce()
|
||||
{
|
||||
$nonce1 = Utils::getNonce();
|
||||
$nonce2 = Utils::getNonce();
|
||||
|
||||
$this->checkInternalType('string', $nonce1);
|
||||
$this->checkInternalType('string', $nonce2);
|
||||
$this->assertEquals(32, strlen($nonce1));
|
||||
$this->assertEquals(32, strlen($nonce2));
|
||||
$this->assertNotEquals($nonce1, $nonce2); // Should be unique
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getTimestamp function
|
||||
*/
|
||||
public function testGetTimestamp()
|
||||
{
|
||||
$timestamp = Utils::getTimestamp();
|
||||
|
||||
$this->checkInternalType('string', $timestamp);
|
||||
// Format: 2023-12-26T10:30:00Z
|
||||
$this->checkRegExp('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getDateUTCString function
|
||||
*/
|
||||
public function testGetDateUTCString()
|
||||
{
|
||||
$dateString = Utils::getDateUTCString();
|
||||
|
||||
$this->checkInternalType('string', $dateString);
|
||||
// Format: Mon, 26 Dec 2023 10:30:00 GMT
|
||||
$this->checkRegExp('/^\w{3}, \d{2} \w{3} \d{4} \d{2}:\d{2}:\d{2} \w+$/', $dateString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getROASignature function
|
||||
*/
|
||||
public function testGetROASignature()
|
||||
{
|
||||
$stringToSign = "GET\n\n\n\nTue, 26 Dec 2023 10:30:00 GMT\n/test";
|
||||
$secret = "test-secret";
|
||||
|
||||
$signature = Utils::getROASignature($stringToSign, $secret);
|
||||
|
||||
$this->checkInternalType('string', $signature);
|
||||
$this->assertNotEmpty($signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getRPCSignature function
|
||||
*/
|
||||
public function testGetRPCSignature()
|
||||
{
|
||||
$signedParams = array(
|
||||
'Action' => 'DescribeInstances',
|
||||
'Version' => '2014-05-26',
|
||||
'Timestamp' => '2023-12-26T10:30:00Z'
|
||||
);
|
||||
$method = 'GET';
|
||||
$secret = 'test-secret';
|
||||
|
||||
$signature = Utils::getRPCSignature($signedParams, $method, $secret);
|
||||
|
||||
$this->checkInternalType('string', $signature);
|
||||
$this->assertNotEmpty($signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test toForm function
|
||||
*/
|
||||
public function testToForm()
|
||||
{
|
||||
$filter = array(
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'nested' => array('key3' => 'value3')
|
||||
);
|
||||
|
||||
$result = Utils::toForm($filter);
|
||||
|
||||
$this->checkInternalType('string', $result);
|
||||
$this->checkStringContains('key1=value1', $result);
|
||||
$this->checkStringContains('key2=value2', $result);
|
||||
|
||||
// Test with null
|
||||
$result = Utils::toForm(null);
|
||||
$this->assertEquals('', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test query function
|
||||
*/
|
||||
public function testQuery()
|
||||
{
|
||||
$filter = array(
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2',
|
||||
'_private' => 'ignore',
|
||||
'nested' => array('key3' => 'value3')
|
||||
);
|
||||
|
||||
$result = Utils::query($filter);
|
||||
|
||||
$this->checkInternalType('array', $result);
|
||||
$this->assertArrayHasKey('key1', $result);
|
||||
$this->assertArrayHasKey('key2', $result);
|
||||
$this->assertArrayNotHasKey('_private', $result);
|
||||
|
||||
// Test with null
|
||||
$result = Utils::query(null);
|
||||
$this->checkInternalType('array', $result);
|
||||
$this->assertEmpty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test arrayToStringWithSpecifiedStyle function
|
||||
*/
|
||||
public function testArrayToStringWithSpecifiedStyle()
|
||||
{
|
||||
$array = array('a', 'b', 'c');
|
||||
|
||||
// Test simple style (comma-separated)
|
||||
$result = Utils::arrayToStringWithSpecifiedStyle($array, 'prefix', 'simple');
|
||||
$this->assertEquals('a,b,c', $result);
|
||||
|
||||
// Test spaceDelimited style
|
||||
$result = Utils::arrayToStringWithSpecifiedStyle($array, 'prefix', 'spaceDelimited');
|
||||
$this->assertEquals('a b c', $result);
|
||||
|
||||
// Test pipeDelimited style
|
||||
$result = Utils::arrayToStringWithSpecifiedStyle($array, 'prefix', 'pipeDelimited');
|
||||
$this->assertEquals('a|b|c', $result);
|
||||
|
||||
// Test json style
|
||||
$result = Utils::arrayToStringWithSpecifiedStyle($array, 'prefix', 'json');
|
||||
$this->checkStringContains('a', $result);
|
||||
$this->checkStringContains('b', $result);
|
||||
|
||||
// Test with null
|
||||
$result = Utils::arrayToStringWithSpecifiedStyle(null, 'prefix', 'simple');
|
||||
$this->assertEquals('', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parseToMap function
|
||||
*/
|
||||
public function testParseToMap()
|
||||
{
|
||||
$input = array(
|
||||
'key1' => 'value1',
|
||||
'key2' => array('nested' => 'value2')
|
||||
);
|
||||
|
||||
$result = Utils::parseToMap($input);
|
||||
|
||||
$this->checkInternalType('array', $result);
|
||||
$this->assertEquals('value1', $result['key1']);
|
||||
$this->checkInternalType('array', $result['key2']);
|
||||
|
||||
// Test with null
|
||||
$result = Utils::parseToMap(null);
|
||||
$this->checkInternalType('array', $result);
|
||||
// parseToMap(null) returns array() from parse function
|
||||
$this->assertTrue(is_array($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getUserAgent function
|
||||
*/
|
||||
public function testGetUserAgent()
|
||||
{
|
||||
// Test with custom user agent
|
||||
$userAgent = Utils::getUserAgent('MyApp/1.0');
|
||||
|
||||
$this->checkInternalType('string', $userAgent);
|
||||
$this->checkStringContains('AlibabaCloud', $userAgent);
|
||||
$this->checkStringContains('PHP/', $userAgent);
|
||||
$this->checkStringContains('MyApp/1.0', $userAgent);
|
||||
|
||||
// Test with empty user agent
|
||||
$userAgent = Utils::getUserAgent('');
|
||||
$this->checkStringContains('AlibabaCloud', $userAgent);
|
||||
$this->assertFalse(strpos($userAgent, 'MyApp') !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test toArray function
|
||||
*/
|
||||
public function testToArray()
|
||||
{
|
||||
$input = array(
|
||||
'key1' => 'value1',
|
||||
'key2' => array('nested' => 'value2')
|
||||
);
|
||||
|
||||
$result = Utils::toArray($input);
|
||||
|
||||
$this->checkInternalType('array', $result);
|
||||
$this->assertEquals($input, $result);
|
||||
|
||||
// Test with non-array
|
||||
$result = Utils::toArray('string');
|
||||
$this->assertEquals('string', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test stringifyMapValue function
|
||||
*/
|
||||
public function testStringifyMapValue()
|
||||
{
|
||||
$map = array(
|
||||
'int' => 123,
|
||||
'bool' => true,
|
||||
'null' => null,
|
||||
'string' => 'test'
|
||||
);
|
||||
|
||||
$result = Utils::stringifyMapValue($map);
|
||||
|
||||
$this->checkInternalType('array', $result);
|
||||
$this->assertEquals('123', $result['int']);
|
||||
$this->assertEquals('true', $result['bool']);
|
||||
$this->assertEquals('', $result['null']);
|
||||
$this->assertEquals('test', $result['string']);
|
||||
|
||||
// Test with null
|
||||
$result = Utils::stringifyMapValue(null);
|
||||
$this->checkInternalType('array', $result);
|
||||
$this->assertEmpty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getEndpointRules function
|
||||
*/
|
||||
public function testGetEndpointRules()
|
||||
{
|
||||
// Test regional endpoint
|
||||
$result = Utils::getEndpointRules('ecs', 'cn-hangzhou', 'regional', '');
|
||||
$this->assertEquals('ecs.cn-hangzhou.aliyuncs.com', $result);
|
||||
|
||||
// Test non-regional endpoint
|
||||
$result = Utils::getEndpointRules('oss', '', 'public', '');
|
||||
$this->assertEquals('oss.aliyuncs.com', $result);
|
||||
|
||||
// Test with vpc network
|
||||
$result = Utils::getEndpointRules('ecs', 'cn-beijing', 'regional', 'vpc');
|
||||
$this->assertEquals('ecs-vpc.cn-beijing.aliyuncs.com', $result);
|
||||
|
||||
// Test with internal network
|
||||
$result = Utils::getEndpointRules('rds', 'cn-shanghai', 'regional', 'internal');
|
||||
$this->assertEquals('rds-internal.cn-shanghai.aliyuncs.com', $result);
|
||||
|
||||
// Test with public network (should be ignored)
|
||||
$result = Utils::getEndpointRules('ecs', 'cn-hangzhou', 'regional', 'public');
|
||||
$this->assertEquals('ecs.cn-hangzhou.aliyuncs.com', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getEndpointRules with missing regionId
|
||||
*/
|
||||
public function testGetEndpointRulesThrowsException()
|
||||
{
|
||||
try {
|
||||
Utils::getEndpointRules('ecs', '', 'regional', '');
|
||||
$this->fail('Expected RuntimeException was not thrown');
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->checkStringContains('RegionId is empty', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getProductEndpoint function
|
||||
*/
|
||||
public function testGetProductEndpoint()
|
||||
{
|
||||
// Test with provided endpoint
|
||||
$result = Utils::getProductEndpoint('ecs', 'cn-hangzhou', 'regional', '', null, array(), 'custom.endpoint.com');
|
||||
$this->assertEquals('custom.endpoint.com', $result);
|
||||
|
||||
// Test with endpoint map
|
||||
$endpointMap = array('cn-hangzhou' => 'map.endpoint.com');
|
||||
$result = Utils::getProductEndpoint('ecs', 'cn-hangzhou', 'regional', '', null, $endpointMap, null);
|
||||
$this->assertEquals('map.endpoint.com', $result);
|
||||
|
||||
// Test fallback to getEndpointRules
|
||||
$result = Utils::getProductEndpoint('ecs', 'cn-hangzhou', 'regional', '', null, array(), null);
|
||||
$this->assertEquals('ecs.cn-hangzhou.aliyuncs.com', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test sign function
|
||||
*/
|
||||
public function testSign()
|
||||
{
|
||||
$secret = 'test-secret';
|
||||
$str = 'test-string';
|
||||
|
||||
// Test HMAC-SHA256
|
||||
$result = Utils::sign($secret, $str, 'ACS3-HMAC-SHA256');
|
||||
$this->checkInternalType('string', $result);
|
||||
$this->assertEquals(32, strlen($result));
|
||||
|
||||
// Test HMAC-SM3
|
||||
$result = Utils::sign($secret, $str, 'ACS3-HMAC-SM3');
|
||||
$this->checkInternalType('string', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getStringToSign function
|
||||
*/
|
||||
public function testGetStringToSign()
|
||||
{
|
||||
$request = new Request();
|
||||
$request->method = 'GET';
|
||||
$request->pathname = '/test';
|
||||
$request->query = array('key' => 'value');
|
||||
$request->headers = array(
|
||||
'accept' => 'application/json',
|
||||
'content-type' => 'application/json',
|
||||
'date' => 'Tue, 26 Dec 2023 10:30:00 GMT',
|
||||
'x-acs-custom' => 'custom-value'
|
||||
);
|
||||
|
||||
$result = Utils::getStringToSign($request);
|
||||
|
||||
$this->checkInternalType('string', $result);
|
||||
$this->checkStringContains('GET', $result);
|
||||
$this->checkStringContains('/test', $result);
|
||||
$this->checkStringContains('x-acs-custom', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getAuthorization function
|
||||
*/
|
||||
public function testGetAuthorization()
|
||||
{
|
||||
$request = new Request();
|
||||
$request->method = 'GET';
|
||||
$request->pathname = '/test';
|
||||
$request->query = array('key' => 'value');
|
||||
$request->headers = array(
|
||||
'host' => 'test.aliyuncs.com',
|
||||
'content-type' => 'application/json',
|
||||
'x-acs-custom' => 'custom-value'
|
||||
);
|
||||
|
||||
$result = Utils::getAuthorization(
|
||||
$request,
|
||||
'ACS3-HMAC-SHA256',
|
||||
'payload-hash',
|
||||
'test-ak',
|
||||
'test-sk'
|
||||
);
|
||||
|
||||
$this->checkInternalType('string', $result);
|
||||
$this->checkStringContains('ACS3-HMAC-SHA256', $result);
|
||||
$this->checkStringContains('Credential=test-ak', $result);
|
||||
$this->checkStringContains('SignedHeaders=', $result);
|
||||
$this->checkStringContains('Signature=', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Sm3 class
|
||||
*/
|
||||
public function testSm3()
|
||||
{
|
||||
$sm3 = new Sm3();
|
||||
|
||||
// Test known value
|
||||
$result = $sm3->sign('abc');
|
||||
$this->assertEquals('66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0', $result);
|
||||
|
||||
// Test another value
|
||||
$result = $sm3->sign('test');
|
||||
$this->checkInternalType('string', $result);
|
||||
$this->assertEquals(64, strlen($result)); // Hex string of 32 bytes
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for string contains assertion (cross-version compatibility)
|
||||
*/
|
||||
private function checkStringContains($needle, $haystack, $message = '')
|
||||
{
|
||||
if (method_exists($this, 'assertStringContainsString')) {
|
||||
$this->assertStringContainsString($needle, $haystack, $message);
|
||||
} else {
|
||||
// Fallback for older PHPUnit
|
||||
$this->assertContains($needle, $haystack, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for PHP 5.5 compatibility
|
||||
* assertInternalType was deprecated in PHPUnit 8
|
||||
*/
|
||||
private function checkInternalType($type, $value, $message = '')
|
||||
{
|
||||
if (method_exists($this, 'assertIsString') && $type === 'string') {
|
||||
$this->assertIsString($value, $message);
|
||||
} elseif (method_exists($this, 'assertIsArray') && $type === 'array') {
|
||||
$this->assertIsArray($value, $message);
|
||||
} elseif (method_exists($this, 'assertIsInt') && $type === 'int') {
|
||||
$this->assertIsInt($value, $message);
|
||||
} else {
|
||||
// Fallback for older PHPUnit - use parent method or assertTrue
|
||||
if (method_exists('PHPUnit_Framework_Assert', 'assertInternalType')) {
|
||||
parent::assertInternalType($type, $value, $message);
|
||||
} else {
|
||||
$typeMap = array(
|
||||
'string' => 'is_string',
|
||||
'array' => 'is_array',
|
||||
'int' => 'is_int',
|
||||
'integer' => 'is_int',
|
||||
'bool' => 'is_bool',
|
||||
'boolean' => 'is_bool'
|
||||
);
|
||||
if (isset($typeMap[$type])) {
|
||||
$this->assertTrue(call_user_func($typeMap[$type], $value), $message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for PHP 5.5 compatibility
|
||||
* assertRegExp was deprecated in PHPUnit 9
|
||||
*/
|
||||
private function checkRegExp($pattern, $string, $message = '')
|
||||
{
|
||||
if (method_exists($this, 'assertMatchesRegularExpression')) {
|
||||
$this->assertMatchesRegularExpression($pattern, $string, $message);
|
||||
} else {
|
||||
// Fallback for older PHPUnit - use assertTrue with preg_match
|
||||
$this->assertTrue((bool) preg_match($pattern, $string), $message);
|
||||
}
|
||||
}
|
||||
|
||||
public function testMapToFlatStyle()
|
||||
{
|
||||
// Test null
|
||||
$this->assertNull(Utils::mapToFlatStyle(null));
|
||||
|
||||
// Test primitive values
|
||||
$this->assertEquals('test', Utils::mapToFlatStyle('test'));
|
||||
$this->assertEquals(123, Utils::mapToFlatStyle(123));
|
||||
$this->assertEquals(true, Utils::mapToFlatStyle(true));
|
||||
|
||||
// Test plain array (associative array)
|
||||
$plainMap = [
|
||||
'key1' => 'value1',
|
||||
'key2' => 'value2'
|
||||
];
|
||||
$flatMap = Utils::mapToFlatStyle($plainMap);
|
||||
$this->assertEquals('value1', $flatMap['#4#key1']);
|
||||
$this->assertEquals('value2', $flatMap['#4#key2']);
|
||||
|
||||
// Test nested array
|
||||
$nestedMap = [
|
||||
'outerKey' => [
|
||||
'innerKey' => 'innerValue'
|
||||
]
|
||||
];
|
||||
$flatNestedMap = Utils::mapToFlatStyle($nestedMap);
|
||||
$this->assertEquals('innerValue', $flatNestedMap['#8#outerKey']['#8#innerKey']);
|
||||
|
||||
// Test indexed array (list)
|
||||
$arr = ['item1', 'item2'];
|
||||
$flatArr = Utils::mapToFlatStyle($arr);
|
||||
$this->assertEquals('item1', $flatArr[0]);
|
||||
$this->assertEquals('item2', $flatArr[1]);
|
||||
|
||||
// Test indexed array with associative array elements
|
||||
$arrWithDict = [
|
||||
['key' => 'value']
|
||||
];
|
||||
$flatArrWithDict = Utils::mapToFlatStyle($arrWithDict);
|
||||
$this->assertEquals('value', $flatArrWithDict[0]['#3#key']);
|
||||
|
||||
// Test with nested structures
|
||||
$complexMap = [
|
||||
'name' => 'testName',
|
||||
'tags' => [
|
||||
'tagKey' => 'tagValue'
|
||||
]
|
||||
];
|
||||
$flatComplexMap = Utils::mapToFlatStyle($complexMap);
|
||||
$this->assertEquals('testName', $flatComplexMap['#4#name']);
|
||||
$this->assertEquals('tagValue', $flatComplexMap['#4#tags']['#6#tagKey']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
require dirname(__DIR__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||
Reference in New Issue
Block a user