blob: 476f10b1f302c5fa34f83ca07a3dd8dd4c60055f [file]
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
declare(strict_types=1);
namespace Test\Thrift\Unit\Lib\Protocol;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Protocol\TCompactProtocol;
use Thrift\Protocol\TJSONProtocol;
use Thrift\Transport\TMemoryBuffer;
use Thrift\Type\TType;
class BoundaryValuesTest extends TestCase
{
private static $WRITE_TYPE_MAP = [
'writeByte' => TType::BYTE,
'writeI16' => TType::I16,
'writeI32' => TType::I32,
'writeI64' => TType::I64,
'writeDouble' => TType::DOUBLE,
'writeString' => TType::STRING,
'writeBool' => TType::BOOL,
];
#[DataProvider('boundaryProvider')]
public function testBoundaryValues($protocolClass, $writeMethod, $readMethod, $value)
{
$this->assertRoundtrip($protocolClass, $writeMethod, $readMethod, $value);
}
public static function boundaryProvider(): array
{
$cases = [
// integers
'byte min' => ['writeMethod' => 'writeByte', 'readMethod' => 'readByte', 'value' => -128],
'byte max' => ['writeMethod' => 'writeByte', 'readMethod' => 'readByte', 'value' => 127],
'byte zero' => ['writeMethod' => 'writeByte', 'readMethod' => 'readByte', 'value' => 0],
'i16 min' => ['writeMethod' => 'writeI16', 'readMethod' => 'readI16', 'value' => -32768],
'i16 max' => ['writeMethod' => 'writeI16', 'readMethod' => 'readI16', 'value' => 32767],
'i16 zero' => ['writeMethod' => 'writeI16', 'readMethod' => 'readI16', 'value' => 0],
'i32 min' => ['writeMethod' => 'writeI32', 'readMethod' => 'readI32', 'value' => -2147483648],
'i32 max' => ['writeMethod' => 'writeI32', 'readMethod' => 'readI32', 'value' => 2147483647],
'i32 zero' => ['writeMethod' => 'writeI32', 'readMethod' => 'readI32', 'value' => 0],
'i64 min' => ['writeMethod' => 'writeI64', 'readMethod' => 'readI64', 'value' => PHP_INT_MIN],
'i64 max' => ['writeMethod' => 'writeI64', 'readMethod' => 'readI64', 'value' => PHP_INT_MAX],
'i64 zero' => ['writeMethod' => 'writeI64', 'readMethod' => 'readI64', 'value' => 0],
// doubles
'double zero' => ['writeMethod' => 'writeDouble', 'readMethod' => 'readDouble', 'value' => 0.0],
'double negative zero' => ['writeMethod' => 'writeDouble', 'readMethod' => 'readDouble', 'value' => -0.0],
'double max' => ['writeMethod' => 'writeDouble', 'readMethod' => 'readDouble', 'value' => PHP_FLOAT_MAX],
'double min' => ['writeMethod' => 'writeDouble', 'readMethod' => 'readDouble', 'value' => PHP_FLOAT_MIN],
'double epsilon' => ['writeMethod' => 'writeDouble', 'readMethod' => 'readDouble', 'value' => PHP_FLOAT_EPSILON],
'double very small' => ['writeMethod' => 'writeDouble', 'readMethod' => 'readDouble', 'value' => 1e-300],
// strings
'empty string' => ['writeMethod' => 'writeString', 'readMethod' => 'readString', 'value' => ''],
'null byte' => ['writeMethod' => 'writeString', 'readMethod' => 'readString', 'value' => "\x00"],
'unicode' => ['writeMethod' => 'writeString', 'readMethod' => 'readString', 'value' => "Привіт 🌍"],
'long string' => ['writeMethod' => 'writeString', 'readMethod' => 'readString', 'value' => str_repeat('a', 1024)],
// booleans
'bool true' => ['writeMethod' => 'writeBool', 'readMethod' => 'readBool', 'value' => true],
'bool false' => ['writeMethod' => 'writeBool', 'readMethod' => 'readBool', 'value' => false],
];
return self::expandWithProtocols($cases);
}
private static function expandWithProtocols(array $cases): array
{
$protocols = [
'Binary' => TBinaryProtocol::class,
'Compact' => TCompactProtocol::class,
'JSON' => TJSONProtocol::class,
];
$expanded = [];
foreach ($protocols as $protoName => $protoClass) {
foreach ($cases as $caseName => $case) {
$expanded[$protoName . ' ' . $caseName] = [
'protocolClass' => $protoClass,
'writeMethod' => $case['writeMethod'],
'readMethod' => $case['readMethod'],
'value' => $case['value'],
];
}
}
return $expanded;
}
private function assertRoundtrip($protocolClass, $writeMethod, $readMethod, $value)
{
$fieldType = self::$WRITE_TYPE_MAP[$writeMethod];
$transport = new TMemoryBuffer();
$protocol = new $protocolClass($transport);
$protocol->writeStructBegin('Test');
$protocol->writeFieldBegin('field', $fieldType, 1);
$protocol->$writeMethod($value);
$protocol->writeFieldEnd();
$protocol->writeFieldStop();
$protocol->writeStructEnd();
$transport2 = new TMemoryBuffer($transport->getBuffer());
$protocol2 = new $protocolClass($transport2);
$protocol2->readStructBegin($name);
$protocol2->readFieldBegin($fname, $ftype, $fid);
$protocol2->$readMethod($result);
$protocol2->readFieldEnd();
$protocol2->readStructEnd();
$this->assertEquals($value, $result);
}
}