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']); } }