- Add alternative control structure syntax test with if/for/while/foreach/switch - Implement DNF types test covering intersection and union type combinations - Create numeric literal syntax test for binary, octal and separated numbers - Remove outdated test coverage documentation files - Add traditional operator precedence and short-circuiting behavior test - Verify compound assignment operations and bitwise operations - Test negative and positive unary operators with integer and float valuesmaster
parent
6d45c64b4d
commit
23a2bf44d7
6 changed files with 268 additions and 738 deletions
@ -1,282 +0,0 @@ |
||||
# PHP AOT 编译器单元测试覆盖总结 |
||||
|
||||
## 新增测试文件列表 |
||||
|
||||
本次为 PHP AOT 编译器添加了以下单元测试文件,覆盖了 PHP 语言的核心语法特性: |
||||
|
||||
### 1. **trait-basic.phpt** - Traits (特征) |
||||
- 基础 trait 使用 |
||||
- trait 中的抽象方法 |
||||
- 多个 trait 的组合使用 |
||||
- trait 方法继承 |
||||
|
||||
### 2. **generators.phpt** - Generators (生成器) |
||||
- 基础 yield 语法 |
||||
- 带键的生成器 |
||||
- 生成器对象操作 |
||||
- 有限和无限生成器 |
||||
|
||||
### 3. **attributes.phpt** - Attributes (注解/属性) |
||||
- Attribute 定义和使用 |
||||
- 类属性、方法属性、属性属性 |
||||
- Reflection API 读取属性 |
||||
- 属性参数传递 |
||||
|
||||
### 4. **match-expression.phpt** - Match Expression (匹配表达式) |
||||
- 基础 match 语法 |
||||
- 多条件匹配 |
||||
- 严格类型比较 |
||||
- 表达式作为返回值 |
||||
- 嵌套 match |
||||
- UnhandledMatchError 异常处理 |
||||
|
||||
### 5. **named-arguments.phpt** - Named Arguments (命名参数) |
||||
- 基础命名参数调用 |
||||
- 跳过可选参数 |
||||
- 混合位置和命名参数 |
||||
- 参数顺序无关性 |
||||
- 复杂场景应用 |
||||
|
||||
### 6. **union-intersection-types.phpt** - Union and Intersection Types (联合和交集类型) |
||||
- Union 类型声明 |
||||
- Nullable union 类型 |
||||
- mixed 类型 |
||||
- never 返回类型 |
||||
- instanceof 检查 |
||||
|
||||
### 7. **constructor-promotion.phpt** - Constructor Property Promotion (构造函数属性提升) |
||||
- 基础构造函数提升 |
||||
- 可见性修饰符 (public/private/protected) |
||||
- 可空类型和默认值 |
||||
- 混合传统和提升方式 |
||||
- readonly 属性 (PHP 8.1+) |
||||
|
||||
### 8. **null-coalescing.phpt** - Null Coalescing Operators (空合并运算符) |
||||
- 基础 ?? 运算符 |
||||
- 链式 null coalescing |
||||
- ??= 赋值运算符 |
||||
- 数组访问中的 coalescing |
||||
- 嵌套数组 coalescing |
||||
- 表达式中的使用 |
||||
|
||||
### 9. **array-spread.phpt** - Spread Operator in Arrays (数组展开运算符) |
||||
- 基础数组展开 |
||||
- 展开时添加额外元素 |
||||
- 多个展开操作 |
||||
- 带键的数组展开 |
||||
- 字符串键的覆盖行为 |
||||
- 展开空数组 |
||||
|
||||
### 10. **arrow-functions.phpt** - Arrow Functions (箭头函数) |
||||
- 基础箭头函数语法 |
||||
- 多参数箭头函数 |
||||
- 变量捕获 (by value) |
||||
- 嵌套箭头函数 |
||||
- 在 array_map/filter/reduce 中使用 |
||||
- 链式调用 |
||||
|
||||
### 11. **magic-methods.phpt** - Magic Methods (魔术方法) |
||||
- __get / __set |
||||
- __isset / __unset |
||||
- __call / __callStatic |
||||
- __invoke |
||||
- __toString |
||||
- __debugInfo |
||||
- __clone |
||||
- __serialize / __unserialize |
||||
|
||||
### 12. **iterators.phpt** - Iterators (迭代器) |
||||
- Iterator 接口实现 |
||||
- IteratorAggregate 接口实现 |
||||
- Generator-based 迭代器 |
||||
- FilterIterator 实现 |
||||
- 可重复使用的迭代器 |
||||
|
||||
### 13. **anonymous-classes.phpt** - Anonymous Classes (匿名类) |
||||
- 基础匿名类定义 |
||||
- 继承父类的匿名类 |
||||
- 实现接口的匿名类 |
||||
- 带属性的匿名类 |
||||
- 嵌套匿名类 |
||||
- 匿名类数组 |
||||
- 静态方法和属性 |
||||
|
||||
### 14. **type-declarations.phpt** - Type Declarations (类型声明) |
||||
- 标量类型声明 (int/string/float/bool) |
||||
- 可空类型 (?T) |
||||
- callable 类型 |
||||
- array/object/iterable 类型 |
||||
- strict_types 模式 |
||||
- 返回类型声明 |
||||
|
||||
### 15. **late-static-binding.phpt** - Late Static Binding (后期静态绑定) |
||||
- self:: vs static:: |
||||
- 静态属性的后期绑定 |
||||
- 静态方法的后期绑定 |
||||
- 构造函数中的 static:: |
||||
|
||||
### 16. **variadic-functions.phpt** - Variadic Functions (可变参数函数) |
||||
- 基础可变参数 (...$args) |
||||
- 必需参数 + 可变参数 |
||||
- 类方法中的可变参数 |
||||
- 类型化的可变参数 |
||||
- 数组展开到函数调用 |
||||
|
||||
## 现有测试覆盖的主要领域 |
||||
|
||||
### 已覆盖的 PHP 语法特性: |
||||
|
||||
#### 基础语法 |
||||
- ✅ 算术运算符 (arithmetic_operators.phpt) |
||||
- ✅ 比较运算符 (comparison_operators.phpt) |
||||
- ✅ 逻辑运算符 (logical_operators.phpt) |
||||
- ✅ 赋值运算符 (assignment_operators.phpt) |
||||
- ✅ 位运算符 |
||||
- ✅ 递增/递减运算符 (postincdec.phpt) |
||||
|
||||
#### 控制结构 |
||||
- ✅ if/else/elseif (control_structures.phpt) |
||||
- ✅ for/while/do-while (control_structures.phpt) |
||||
- ✅ switch (switch-001.phpt, switch-002.phpt) |
||||
- ✅ break/continue |
||||
- ✅ try-catch-finally (try-catch.phpt, try-catch-2.phpt) |
||||
- ✅ throw (throw-in-php.phpt) |
||||
|
||||
#### 函数 |
||||
- ✅ 函数定义和调用 (functions.phpt) |
||||
- ✅ 参数传递 (class_args.phpt) |
||||
- ✅ 默认参数 (func-default-param.phpt) |
||||
- ✅ 返回类型 (func-return-type.phpt) |
||||
- ✅ 可变参数 (variadic-args.phpt, variadic-functions.phpt) |
||||
- ✅ 命名参数 (named-arguments.phpt) |
||||
- ✅ 闭包 (closure-001.phpt, closure-002.phpt) |
||||
- ✅ 箭头函数 (arrow-func.phpt, arrow-func-2.phpt, arrow-functions.phpt) |
||||
- ✅ 生成器 (generators.phpt) |
||||
|
||||
#### 类与对象 |
||||
- ✅ 类定义 (class-namespace.phpt) |
||||
- ✅ 构造函数 (ctor.phpt) |
||||
- ✅ 析构函数 |
||||
- ✅ 继承 |
||||
- ✅ 访问修饰符 (private-prop-001.phpt, private-prop-002.phpt) |
||||
- ✅ 静态属性和方法 (class-static-001~005.phpt) |
||||
- ✅ 常量 (const-test.phpt) |
||||
- ✅ 抽象类 |
||||
- ✅ 接口 (enum1.phpt, enum2.phpt) |
||||
- ✅ Traits (trait-basic.phpt) |
||||
- ✅ 匿名类 (anonymous-classes.phpt) |
||||
- ✅ 枚举 (enum1.phpt, enum2.phpt) |
||||
|
||||
#### 对象特性 |
||||
- ✅ 属性访问 (prop-001.phpt, prop-002.phpt) |
||||
- ✅ 方法调用 (method-call.phpt) |
||||
- ✅ 静态调用 (static-call.phpt) |
||||
- ✅ 对象引用 (object-link.phpt, object-link-002.phpt, object-link-003.phpt) |
||||
- ✅ 克隆 |
||||
- ✅ 序列化 |
||||
- ✅ 魔术方法 (magic-methods.phpt) |
||||
- ✅ 迭代器 (iterators.phpt) |
||||
|
||||
#### 类型系统 |
||||
- ✅ 标量类型 (native-type.phpt) |
||||
- ✅ 联合类型 (union-intersection-types.phpt) |
||||
- ✅ 可空类型 |
||||
- ✅ mixed 类型 |
||||
- ✅ never 类型 |
||||
- ✅ 类型声明 (type-declarations.phpt) |
||||
- ✅ 类型转换 (to-str.phpt) |
||||
|
||||
#### 数组 |
||||
- ✅ 数组创建 (arrays.phpt, array_001~003.phpt) |
||||
- ✅ 数组访问 |
||||
- ✅ 数组修改 (array_assignment_edge_cases.phpt) |
||||
- ✅ 数组运算符 (array_assignment_operators.phpt) |
||||
- ✅ 多维数组 (complex_array_operations.phpt) |
||||
- ✅ 数组展开 (array-spread.phpt) |
||||
- ✅ list() 解构 (list-test.phpt) |
||||
- ✅ 数组项自增自减 (array-item-dec-inc.phpt) |
||||
|
||||
#### 字符串 |
||||
- ✅ 字符串连接 |
||||
- ✅ 字符串函数 (string_functions.phpt) |
||||
- ✅ 字符串长度 (strlen.phpt) |
||||
- ✅ 字符串偏移量 (str-offset-set.phpt) |
||||
- ✅ 格式化字符串 (fstring.py) |
||||
|
||||
#### 变量 |
||||
- ✅ 变量定义 (basic_variables.phpt) |
||||
- ✅ 变量作用域 (global-vars.phpt, static-vars.phpt) |
||||
- ✅ 引用 (ref.phpt, ref-005.phpt, ref-func-param.phpt, ref-closure-param.phpt, ref-call-arg.phpt) |
||||
- ✅ 可变变量 |
||||
|
||||
#### 运算符 |
||||
- ✅ 算术运算符 (arithmetic_operators.phpt) |
||||
- ✅ 比较运算符 (comparison_operators.phpt) |
||||
- ✅ 逻辑运算符 (logical_operators.phpt) |
||||
- ✅ 赋值运算符 (assignment_operators.phpt) |
||||
- ✅ 三元运算符 (assign-compare.phpt) |
||||
- ✅ 空合并运算符 (assign_coalesce_001.phpt, assign_coalesce_002.phpt, null-coalescing.phpt) |
||||
- ✅ 实例运算符 (instanceof) |
||||
- ✅ 按位运算符 |
||||
|
||||
#### 高级特性 |
||||
- ✅ 命名空间 (class-namespace.phpt, ns-const.phpt) |
||||
- ✅ 自动加载 |
||||
- ✅ 特性 (trait-basic.phpt) |
||||
- ✅ 生成器 (generators.phpt) |
||||
- ✅ 闭包 (closure-001.phpt, closure-002.phpt) |
||||
- ✅ 匿名函数 (arrow-func.phpt, arrow-func-2.phpt) |
||||
- ✅ 匿名类 (anonymous-classes.phpt) |
||||
- ✅ 属性 (attributes.phpt) |
||||
- ✅ 匹配表达式 (match-expression.phpt) |
||||
- ✅ 空船运算符 (null-coalescing.phpt) |
||||
- ✅ 展开运算符 (array-spread.phpt, variadic-functions.phpt) |
||||
- ✅ 类型声明 (type-declarations.phpt) |
||||
- ✅ 后期静态绑定 (late-static-binding.phpt) |
||||
|
||||
#### 错误处理 |
||||
- ✅ 异常处理 (try-catch.phpt, try-catch-2.phpt) |
||||
- ✅ 错误报告 |
||||
- ✅ 自定义错误处理 |
||||
|
||||
#### 内置类 |
||||
- ✅ DateTime (datetime_builtin_class.phpt) |
||||
- ✅ ArrayObject |
||||
- ✅ Exception |
||||
- ✅ Reflection (attributes.phpt) |
||||
|
||||
## 测试覆盖率统计 |
||||
|
||||
- **总测试文件数**: 116 个 phpt 文件 |
||||
- **新增测试文件**: 16 个 |
||||
- **覆盖的 PHP 版本**: PHP 7.4+ ~ PHP 8.x |
||||
|
||||
## 主要覆盖的 PHP 特性类别 |
||||
|
||||
1. **基础语法** (100%) - 运算符、控制结构、变量等 |
||||
2. **函数** (95%) - 定义、调用、闭包、生成器等 |
||||
3. **类与对象** (90%) - 继承、多态、封装等 OOP 特性 |
||||
4. **类型系统** (95%) - 类型声明、类型转换、联合类型等 |
||||
5. **数组处理** (95%) - 创建、访问、修改、遍历等 |
||||
6. **字符串处理** (90%) - 连接、函数、格式化等 |
||||
7. **错误处理** (85%) - 异常、错误报告等 |
||||
8. **高级特性** (85%) - 反射、迭代器、序列化等 |
||||
|
||||
## 测试质量保证 |
||||
|
||||
- 所有测试都遵循标准的 phpt 格式 |
||||
- 包含 --TEST--、--FILE--、--EXPECT-- 三个必要部分 |
||||
- 测试用例覆盖正常情况和边界情况 |
||||
- 包含错误处理和异常情况测试 |
||||
- 符合 PHP AOT 编译器的特殊要求 |
||||
|
||||
## 后续建议 |
||||
|
||||
虽然已经覆盖了大量 PHP 语法,但仍有以下方面可以继续加强: |
||||
|
||||
1. **性能测试**: 添加更多性能基准测试 |
||||
2. **边缘案例**: 更多极端情况和边界条件的测试 |
||||
3. **并发测试**: 多线程/协程相关测试 |
||||
4. **内存管理**: 内存泄漏和垃圾回收测试 |
||||
5. **扩展集成**: 与 PHP 扩展的集成测试 |
||||
6. **兼容性测试**: 不同 PHP 版本的兼容性测试 |
||||
@ -0,0 +1,29 @@ |
||||
--TEST-- |
||||
Binary, explicit octal and separated numeric literals preserve their values |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main(): void |
||||
{ |
||||
var_dump(0b1010); |
||||
var_dump(0B1111); |
||||
var_dump(0o17); |
||||
var_dump(0O20); |
||||
|
||||
var_dump(1_234_567); |
||||
var_dump(0b1010_0101); |
||||
var_dump(0o7_5_5); |
||||
var_dump(0xCA_FE); |
||||
var_dump(1_2.5_0e1); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(10) |
||||
int(15) |
||||
int(15) |
||||
int(16) |
||||
int(1234567) |
||||
int(165) |
||||
int(493) |
||||
int(51966) |
||||
float(125) |
||||
@ -0,0 +1,52 @@ |
||||
--TEST-- |
||||
Alternative control structure syntax shares normal control-flow semantics |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main(): void |
||||
{ |
||||
$events = []; |
||||
$value = 2; |
||||
|
||||
if ($value === 1): |
||||
$events[] = 'if:one'; |
||||
elseif ($value === 2): |
||||
$events[] = 'if:two'; |
||||
else: |
||||
$events[] = 'if:other'; |
||||
endif; |
||||
|
||||
for ($i = 0; $i < 4; $i++): |
||||
if ($i === 1): |
||||
continue; |
||||
endif; |
||||
$events[] = 'for:' . $i; |
||||
endfor; |
||||
|
||||
$i = 0; |
||||
while ($i < 2): |
||||
$events[] = 'while:' . $i; |
||||
$i++; |
||||
endwhile; |
||||
|
||||
foreach (['a' => 1, 'b' => 2] as $key => $item): |
||||
$events[] = 'foreach:' . $key . '=' . $item; |
||||
endforeach; |
||||
|
||||
switch ($value): |
||||
case 1: |
||||
$events[] = 'switch:one'; |
||||
break; |
||||
case 2: |
||||
$events[] = 'switch:two'; |
||||
break; |
||||
default: |
||||
$events[] = 'switch:other'; |
||||
break; |
||||
endswitch; |
||||
|
||||
echo implode('|', $events), "\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
if:two|for:0|for:2|for:3|while:0|while:1|foreach:a=1|foreach:b=2|switch:two |
||||
@ -0,0 +1,74 @@ |
||||
--TEST-- |
||||
Traditional operators preserve precedence, short-circuiting, values and compound writes |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function traditional_record(array &$events, string $label, bool $result): bool |
||||
{ |
||||
$events[] = $label; |
||||
return $result; |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$counter = 3; |
||||
var_dump(--$counter); |
||||
var_dump($counter); |
||||
|
||||
$lowAnd = true and false; |
||||
$highAnd = true && false; |
||||
$lowOr = false or true; |
||||
$highOr = false || true; |
||||
var_dump($lowAnd, $highAnd, $lowOr, $highOr); |
||||
|
||||
$events = []; |
||||
$andResult = traditional_record($events, 'and-left', false) |
||||
and traditional_record($events, 'and-right', true); |
||||
$orResult = traditional_record($events, 'or-left', true) |
||||
or traditional_record($events, 'or-right', false); |
||||
var_dump($andResult, $orResult, $events); |
||||
|
||||
$integer = -7; |
||||
$float = -2.5; |
||||
var_dump(+$integer, +$float); |
||||
|
||||
var_dump(0b1100 ^ 0b1010); |
||||
|
||||
$values = [3, 16, 0b1100]; |
||||
var_dump($values[0] <<= 3); |
||||
var_dump($values[1] >>= 2); |
||||
var_dump($values[2] ^= 0b1010); |
||||
var_dump($values[2] &= 0b0011); |
||||
var_dump($values); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(2) |
||||
int(2) |
||||
bool(true) |
||||
bool(false) |
||||
bool(false) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
array(2) { |
||||
[0]=> |
||||
string(8) "and-left" |
||||
[1]=> |
||||
string(7) "or-left" |
||||
} |
||||
int(-7) |
||||
float(-2.5) |
||||
int(6) |
||||
int(24) |
||||
int(4) |
||||
int(6) |
||||
int(2) |
||||
array(3) { |
||||
[0]=> |
||||
int(24) |
||||
[1]=> |
||||
int(4) |
||||
[2]=> |
||||
int(2) |
||||
} |
||||
@ -0,0 +1,113 @@ |
||||
--TEST-- |
||||
DNF types enforce intersection alternatives on parameters, returns and properties |
||||
--FILE-- |
||||
<?php |
||||
|
||||
interface DnfLeft |
||||
{ |
||||
public function left(): string; |
||||
} |
||||
|
||||
interface DnfRight |
||||
{ |
||||
public function right(): string; |
||||
} |
||||
|
||||
final class DnfBoth implements DnfLeft, DnfRight |
||||
{ |
||||
public function left(): string |
||||
{ |
||||
return 'left'; |
||||
} |
||||
|
||||
public function right(): string |
||||
{ |
||||
return 'right'; |
||||
} |
||||
} |
||||
|
||||
final class DnfFallback |
||||
{ |
||||
public function label(): string |
||||
{ |
||||
return 'fallback'; |
||||
} |
||||
} |
||||
|
||||
final class DnfOnlyLeft implements DnfLeft |
||||
{ |
||||
public function left(): string |
||||
{ |
||||
return 'only-left'; |
||||
} |
||||
} |
||||
|
||||
function dnf_label((DnfLeft&DnfRight)|DnfFallback $value): string |
||||
{ |
||||
if ($value instanceof DnfFallback) { |
||||
return $value->label(); |
||||
} |
||||
return $value->left() . '+' . $value->right(); |
||||
} |
||||
|
||||
function dnf_identity( |
||||
(DnfLeft&DnfRight)|DnfFallback $value, |
||||
): (DnfLeft&DnfRight)|DnfFallback { |
||||
return $value; |
||||
} |
||||
|
||||
function dnf_dynamic_return(mixed $value): (DnfLeft&DnfRight)|DnfFallback |
||||
{ |
||||
return $value; |
||||
} |
||||
|
||||
final class DnfBox |
||||
{ |
||||
public (DnfLeft&DnfRight)|DnfFallback $value; |
||||
|
||||
public function __construct((DnfLeft&DnfRight)|DnfFallback $value) |
||||
{ |
||||
$this->value = $value; |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$both = new DnfBoth(); |
||||
$fallback = new DnfFallback(); |
||||
var_dump(dnf_label($both)); |
||||
var_dump(dnf_label($fallback)); |
||||
var_dump(dnf_identity($both) instanceof DnfBoth); |
||||
|
||||
$box = new DnfBox($fallback); |
||||
var_dump($box->value instanceof DnfFallback); |
||||
$box->value = $both; |
||||
var_dump($box->value instanceof DnfBoth); |
||||
|
||||
$invalid = any(new DnfOnlyLeft()); |
||||
try { |
||||
dnf_label($invalid); |
||||
} catch (TypeError $error) { |
||||
echo "parameter TypeError\n"; |
||||
} |
||||
try { |
||||
dnf_dynamic_return($invalid); |
||||
} catch (TypeError $error) { |
||||
echo "return TypeError\n"; |
||||
} |
||||
try { |
||||
$box->value = $invalid; |
||||
} catch (TypeError $error) { |
||||
echo "property TypeError\n"; |
||||
} |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(10) "left+right" |
||||
string(8) "fallback" |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
parameter TypeError |
||||
return TypeError |
||||
property TypeError |
||||
Loading…
Reference in new issue