test(namespace): 添加命名空间相关功能的测试用例

- 添加匿名类在命名空间中的测试
- 添加跨命名空间类常量引用的测试
- 添加跨命名空间继承的测试
- 添加完全限定名与相对名的测试
- 添加组合use导入的测试
- 添加跨命名空间接口实现的测试
- 添加混合use类和函数导入的测试
- 添加命名空间常量定义的测试
- 添加多层嵌套命名空间的测试
- 添加self/static跨命名空间解析的测试
- 添加跨命名空间trait使用的测试
- 添加use别名的测试
- 添加use const导入常量的测试
pull/1/head
韩天峰 3 months ago
parent 928f9050d6
commit 192bba3454
  1. 35
      tests/aot/namespace/anonymous-class-ns.phpt
  2. 61
      tests/aot/namespace/class-const-ref.phpt
  3. 80
      tests/aot/namespace/cross-ns-inheritance.phpt
  4. 41
      tests/aot/namespace/fully-qualified.phpt
  5. 46
      tests/aot/namespace/group-use.phpt
  6. 58
      tests/aot/namespace/interface-across-ns.phpt
  7. 51
      tests/aot/namespace/mixed-use-imports.phpt
  8. 43
      tests/aot/namespace/namespace-constants.phpt
  9. 38
      tests/aot/namespace/nested-namespace.phpt
  10. 52
      tests/aot/namespace/self-static-cross-ns.phpt
  11. 67
      tests/aot/namespace/trait-across-ns.phpt
  12. 35
      tests/aot/namespace/use-alias.phpt
  13. 39
      tests/aot/namespace/use-const.phpt

@ -0,0 +1,35 @@
--TEST--
Anonymous class inside namespace
--FILE--
<?php
namespace App\Factory {
interface Greeter {
public function greet(string $name): string;
}
function createGreeter(string $prefix): Greeter {
return new class($prefix) implements Greeter {
private string $prefix;
public function __construct(string $prefix) {
$this->prefix = $prefix;
}
public function greet(string $name): string {
return $this->prefix . " " . $name;
}
};
}
}
namespace {
use function App\Factory\createGreeter;
function main() {
$g = createGreeter("Hello");
var_dump($g->greet("World"));
echo "done\n";
}
}
?>
--EXPECT--
string(11) "Hello World"
done

@ -0,0 +1,61 @@
--TEST--
Class constant references across namespaces
--FILE--
<?php
namespace Core\Status {
class HttpStatus {
public const OK = 200;
public const NOT_FOUND = 404;
public const SERVER_ERROR = 500;
}
class AppConfig {
public const MAX_CONNECTIONS = 100;
public const TIMEOUT = 30;
}
}
namespace Services {
use Core\Status\HttpStatus;
use Core\Status\AppConfig;
class ApiClient {
public static function check(int $code): string {
switch ($code) {
case HttpStatus::OK:
return "success";
case HttpStatus::NOT_FOUND:
return "not found";
case HttpStatus::SERVER_ERROR:
return "error";
default:
return "unknown";
}
}
public static function getMaxConnections(): int {
return AppConfig::MAX_CONNECTIONS;
}
}
}
namespace {
use Services\ApiClient;
function main() {
var_dump(ApiClient::check(200));
var_dump(ApiClient::check(404));
var_dump(ApiClient::check(500));
var_dump(ApiClient::getMaxConnections());
var_dump(\Core\Status\AppConfig::TIMEOUT);
echo "done\n";
}
}
?>
--EXPECT--
string(7) "success"
string(9) "not found"
string(5) "error"
int(100)
int(30)
done

@ -0,0 +1,80 @@
--TEST--
Namespace with class inheritance across namespaces
--FILE--
<?php
namespace Base\Entity {
abstract class Model {
protected string $table;
public function __construct(string $table) {
$this->table = $table;
}
public function getTable(): string {
return $this->table;
}
abstract public function fields(): array;
}
}
namespace App\Models {
use Base\Entity\Model;
class User extends Model {
public function __construct() {
parent::__construct("users");
}
public function fields(): array {
return ["id", "name", "email"];
}
}
class Product extends Model {
public function __construct() {
parent::__construct("products");
}
public function fields(): array {
return ["id", "title", "price"];
}
}
}
namespace {
use App\Models\User;
use App\Models\Product;
function main() {
$user = new User();
$product = new Product();
var_dump($user->getTable());
var_dump($user->fields());
var_dump($product->getTable());
var_dump($product->fields());
echo "done\n";
}
}
?>
--EXPECT--
string(5) "users"
array(3) {
[0]=>
string(2) "id"
[1]=>
string(4) "name"
[2]=>
string(5) "email"
}
string(8) "products"
array(3) {
[0]=>
string(2) "id"
[1]=>
string(5) "title"
[2]=>
string(5) "price"
}
done

@ -0,0 +1,41 @@
--TEST--
Fully qualified names vs relative names in namespace
--FILE--
<?php
namespace Foo\Bar {
class Helper {
public static function version(): string {
return "1.0.0";
}
}
function baz(): string {
return "baz-in-foo-bar";
}
}
namespace Foo {
class Runner {
// Relative: Bar\Helper resolves to Foo\Bar\Helper
public static function run(): string {
return Bar\Helper::version();
}
}
}
namespace {
function main() {
// Fully qualified calls
var_dump(\Foo\Bar\Helper::version());
var_dump(\Foo\Bar\baz());
// Call into Foo namespace class
var_dump(\Foo\Runner::run());
echo "done\n";
}
}
?>
--EXPECT--
string(5) "1.0.0"
string(14) "baz-in-foo-bar"
string(5) "1.0.0"
done

@ -0,0 +1,46 @@
--TEST--
Group use imports for classes, functions, and constants
--FILE--
<?php
namespace Vendor\Package {
class ClassA {
public static function name(): string { return "ClassA"; }
}
class ClassB {
public static function name(): string { return "ClassB"; }
}
class ClassC {
public static function name(): string { return "ClassC"; }
}
function funcA(): string { return "funcA"; }
function funcB(): string { return "funcB"; }
const CONST_A = "constA";
const CONST_B = "constB";
}
namespace {
use Vendor\Package\{ClassA, ClassB, ClassC};
use function Vendor\Package\{funcA, funcB};
use const Vendor\Package\{CONST_A, CONST_B};
function main() {
var_dump(ClassA::name());
var_dump(ClassB::name());
var_dump(ClassC::name());
var_dump(funcA());
var_dump(funcB());
var_dump(CONST_A);
var_dump(CONST_B);
echo "done\n";
}
}
?>
--EXPECT--
string(6) "ClassA"
string(6) "ClassB"
string(6) "ClassC"
string(5) "funcA"
string(5) "funcB"
string(6) "constA"
string(6) "constB"
done

@ -0,0 +1,58 @@
--TEST--
Namespace with interface and implementation across namespaces
--FILE--
<?php
namespace Contracts\Payment {
interface PaymentProcessor {
public function pay(float $amount): bool;
public function refund(float $amount): bool;
}
}
namespace Services\Payment {
use Contracts\Payment\PaymentProcessor;
class StripeProcessor implements PaymentProcessor {
private array $log = [];
public function pay(float $amount): bool {
$this->log[] = "paid:{$amount}";
return true;
}
public function refund(float $amount): bool {
$this->log[] = "refunded:{$amount}";
return true;
}
public function getLog(): array {
return $this->log;
}
}
}
namespace {
use Services\Payment\StripeProcessor;
use Contracts\Payment\PaymentProcessor;
function main() {
$p = new StripeProcessor();
var_dump($p->pay(100.0));
var_dump($p->refund(50.0));
var_dump($p->getLog());
var_dump($p instanceof PaymentProcessor);
echo "done\n";
}
}
?>
--EXPECT--
bool(true)
bool(true)
array(2) {
[0]=>
string(8) "paid:100"
[1]=>
string(11) "refunded:50"
}
bool(true)
done

@ -0,0 +1,51 @@
--TEST--
Mixed use class and use function imports
--FILE--
<?php
namespace Utils\Str {
function slug(string $s): string {
return str_replace(" ", "-", strtolower($s));
}
function prefix(string $s, string $p): string {
return "{$p}:{$s}";
}
}
namespace Utils\Math {
function double(int $x): int {
return $x * 2;
}
}
namespace App {
use Utils\Str\slug;
use Utils\Str\prefix;
use function Utils\Math\double;
class TextHelper {
public static function normalize(string $text): string {
return slug(prefix($text, "msg"));
}
}
function compute(int $v): int {
return double($v);
}
}
namespace {
use App\TextHelper;
use function App\compute;
function main() {
var_dump(TextHelper::normalize("Hello World"));
var_dump(compute(21));
echo "done\n";
}
}
?>
--EXPECT--
string(15) "msg:hello-world"
int(42)
done

@ -0,0 +1,43 @@
--TEST--
Namespace with constants defined via const keyword
--FILE--
<?php
namespace Config\App {
const APP_NAME = "MyApp";
const VERSION = "2.0.0";
const DEBUG = true;
function getConfig(): array {
return [
"name" => APP_NAME,
"version" => VERSION,
"debug" => DEBUG,
];
}
}
namespace {
use function Config\App\getConfig;
function main() {
var_dump(\Config\App\APP_NAME);
var_dump(\Config\App\VERSION);
var_dump(\Config\App\DEBUG);
var_dump(getConfig());
echo "done\n";
}
}
?>
--EXPECT--
string(5) "MyApp"
string(5) "2.0.0"
bool(true)
array(3) {
["name"]=>
string(5) "MyApp"
["version"]=>
string(5) "2.0.0"
["debug"]=>
bool(true)
}
done

@ -0,0 +1,38 @@
--TEST--
Multi-level nested namespaces with classes and functions
--FILE--
<?php
namespace App\Services\Payment {
class Gateway {
public static function process(string $type): string {
return "processed:{$type}";
}
}
function fee(int $amount): int {
return (int)($amount * 5 / 100);
}
}
namespace App\Controllers {
class OrderController {
public static function create(): string {
return \App\Services\Payment\Gateway::process("order");
}
}
}
namespace {
function main() {
var_dump(\App\Services\Payment\Gateway::process("sale"));
var_dump(\App\Services\Payment\fee(100));
var_dump(\App\Controllers\OrderController::create());
echo "done\n";
}
}
?>
--EXPECT--
string(14) "processed:sale"
int(5)
string(15) "processed:order"
done

@ -0,0 +1,52 @@
--TEST--
self/static resolution with inheritance across namespaces
--FILE--
<?php
namespace Base\Core {
class BaseController {
protected static string $prefix = "base";
public static function whoAmI(): string {
return static::$prefix;
}
public static function selfWhoAmI(): string {
return self::$prefix;
}
}
}
namespace App\Http {
use Base\Core\BaseController;
class UserController extends BaseController {
protected static string $prefix = "user";
}
class AdminController extends BaseController {
protected static string $prefix = "admin";
}
}
namespace {
use App\Http\UserController;
use App\Http\AdminController;
use Base\Core\BaseController;
function main() {
// static:: should resolve to the calling class
var_dump(UserController::whoAmI());
var_dump(AdminController::whoAmI());
// self:: should always resolve to BaseController
var_dump(BaseController::selfWhoAmI());
var_dump(UserController::selfWhoAmI());
echo "done\n";
}
}
?>
--EXPECT--
string(4) "user"
string(5) "admin"
string(4) "base"
string(4) "base"
done

@ -0,0 +1,67 @@
--TEST--
Trait used across namespaces
--FILE--
<?php
namespace Base\Traits {
trait Logger {
private array $log = [];
public function log(string $msg): void {
$this->log[] = $msg;
}
public function getLog(): array {
return $this->log;
}
}
}
namespace App\Services {
use Base\Traits\Logger;
class OrderService {
use Logger;
public function createOrder(int $id): string {
$this->log("order:{$id}");
return "ok";
}
}
class UserService {
use Logger;
public function createUser(string $name): string {
$this->log("user:{$name}");
return "ok";
}
}
}
namespace {
use App\Services\OrderService;
use App\Services\UserService;
function main() {
$os = new OrderService();
$us = new UserService();
$os->createOrder(42);
$us->createUser("alice");
var_dump($os->getLog());
var_dump($us->getLog());
echo "done\n";
}
}
?>
--EXPECT--
array(1) {
[0]=>
string(8) "order:42"
}
array(1) {
[0]=>
string(10) "user:alice"
}
done

@ -0,0 +1,35 @@
--TEST--
use alias for class names
--FILE--
<?php
namespace Library\Storage\Drivers {
class FileDriver {
public function read(): string {
return "file:data";
}
}
class MemoryDriver {
public function read(): string {
return "memory:data";
}
}
}
namespace {
use Library\Storage\Drivers\FileDriver as FS;
use Library\Storage\Drivers\MemoryDriver as Mem;
function main() {
$fs = new FS();
$mem = new Mem();
var_dump($fs->read());
var_dump($mem->read());
echo "done\n";
}
}
?>
--EXPECT--
string(9) "file:data"
string(11) "memory:data"
done

@ -0,0 +1,39 @@
--TEST--
use const for importing namespace constants
--FILE--
<?php
namespace Lib\Config {
const HOST = "localhost";
const PORT = 8080;
const DEBUG = true;
}
namespace App {
use const Lib\Config\HOST;
use const Lib\Config\PORT;
use const Lib\Config\DEBUG;
function getServer(): string {
return HOST . ":" . PORT;
}
function isDebug(): bool {
return DEBUG;
}
}
namespace {
use function App\getServer;
use function App\isDebug;
function main() {
var_dump(getServer());
var_dump(isDebug());
echo "done\n";
}
}
?>
--EXPECT--
string(14) "localhost:8080"
bool(true)
done
Loading…
Cancel
Save