Skip to content

Refactor test code to use new reflection library #170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/main/php/lang/ast/emit/PHP.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,15 @@ protected function emitLambda($result, $lambda) {
}

protected function emitEnumCase($result, $case) {
$result->codegen->scope[0]->meta[self::CONSTANT][$case->name]= [
DETAIL_RETURNS => 'self',
DETAIL_ANNOTATIONS => $case->annotations,
DETAIL_COMMENT => $case->comment,
DETAIL_TARGET_ANNO => [],
DETAIL_ARGUMENTS => []
];

$case->annotations && $this->emitOne($result, $case->annotations);
$result->out->write('case '.$case->name);
if ($case->expression) {
$result->out->write('=');
Expand Down
43 changes: 9 additions & 34 deletions src/test/php/lang/ast/unittest/emit/AnnotationSupport.class.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php namespace lang\ast\unittest\emit;

use lang\{Reflection, IllegalArgumentException};
use lang\IllegalArgumentException;
use test\{Assert, Expect, Test, Values};

/**
Expand All @@ -10,32 +10,7 @@
* - AttributesTest - emits PHP 8 attributes
*/
abstract class AnnotationSupport extends EmittingTest {

/**
* Declares annotations, optionally including a type
*
* @param string $declaration
* @return lang.reflection.Type
*/
private function declare($declaration) {
return Reflection::type($this->type(
$declaration.(strstr($declaration, '<T>') ? '' : ' class <T> { }')
));
}

/**
* Returns annotations present in the given type
*
* @param lang.reflection.Annotated $annotated
* @return [:var[]]
*/
private function annotations($annotated) {
$r= [];
foreach ($annotated->annotations() as $name => $annotation) {
$r[$name]= $annotation->arguments();
}
return $r;
}
use AnnotationsOf;

#[Test]
public function without_value() {
Expand Down Expand Up @@ -127,13 +102,13 @@ public function single_quoted_string_inside_non_constant_expression() {
public function has_access_to_class() {
Assert::equals(
['Expect' => [true]],
$this->annotations($this->declare('#[Expect(self::SUCCESS)] class <T> { const SUCCESS = true; }'))
$this->annotations($this->declare('#[Expect(self::SUCCESS)] class %T { const SUCCESS = true; }'))
);
}

#[Test]
public function method() {
$t= $this->declare('class <T> { #[Test] public function fixture() { } }');
$t= $this->declare('class %T { #[Test] public function fixture() { } }');
Assert::equals(
['Test' => []],
$this->annotations($t->method('fixture'))
Expand All @@ -142,7 +117,7 @@ public function method() {

#[Test]
public function field() {
$t= $this->declare('class <T> { #[Test] public $fixture; }');
$t= $this->declare('class %T { #[Test] public $fixture; }');
Assert::equals(
['Test' => []],
$this->annotations($t->property('fixture'))
Expand All @@ -151,7 +126,7 @@ public function field() {

#[Test]
public function param() {
$t= $this->declare('class <T> { public function fixture(#[Test] $param) { } }');
$t= $this->declare('class %T { public function fixture(#[Test] $param) { } }');
Assert::equals(
['Test' => []],
$this->annotations($t->method('fixture')->parameter(0))
Expand All @@ -160,7 +135,7 @@ public function param() {

#[Test]
public function params() {
$t= $this->declare('class <T> { public function fixture(#[Inject(["name" => "a"])] $a, #[Inject] $b) { } }');
$t= $this->declare('class %T { public function fixture(#[Inject(["name" => "a"])] $a, #[Inject] $b) { } }');
Assert::equals(
['Inject' => [['name' => 'a']]],
$this->annotations($t->method('fixture')->parameter(0))
Expand All @@ -181,7 +156,7 @@ public function multiple_class_annotations() {

#[Test]
public function multiple_member_annotations() {
$t= $this->declare('class <T> { #[Test, Values([1, 2, 3])] public function fixture() { } }');
$t= $this->declare('class %T { #[Test, Values([1, 2, 3])] public function fixture() { } }');
Assert::equals(
['Test' => [], 'Values' => [[1, 2, 3]]],
$this->annotations($t->method('fixture'))
Expand All @@ -195,7 +170,7 @@ public function multiline_annotations() {
"Timm",
"Mr. Midori",
])]
class <T> { }'
class %T { }'
));
Assert::equals(['Authors' => [['Timm', 'Mr. Midori']]], $annotations);
}
Expand Down
18 changes: 18 additions & 0 deletions src/test/php/lang/ast/unittest/emit/AnnotationsOf.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php namespace lang\ast\unittest\emit;

trait AnnotationsOf {

/**
* Returns annotations present in the given type
*
* @param lang.reflection.Annotated $annotated
* @return [:var[]]
*/
private function annotations($annotated) {
$r= [];
foreach ($annotated->annotations() as $name => $annotation) {
$r[$name]= $annotation->arguments();
}
return $r;
}
}
16 changes: 8 additions & 8 deletions src/test/php/lang/ast/unittest/emit/AnonymousClassTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class AnonymousClassTest extends EmittingTest {

#[Test]
public function parentless() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function run() {
return new class() {
public function id() { return "test"; }
Expand All @@ -26,7 +26,7 @@ public function id() { return "test"; }

#[Test]
public function extending_base_class() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function run() {
return new class() extends \\util\\AbstractDeferredInvokationHandler {
public function initialize() {
Expand All @@ -40,7 +40,7 @@ public function initialize() {

#[Test]
public function implementing_interface() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function run() {
return new class() implements \\lang\\Runnable {
public function run() {
Expand All @@ -54,7 +54,7 @@ public function run() {

#[Test]
public function method_annotations() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function run() {
return new class() {

Expand All @@ -69,22 +69,22 @@ public function fixture() { }

#[Test]
public function extending_enclosing_class() {
$t= $this->type('class <T> {
$t= $this->declare('class %T {
public static function run() {
return new class() extends self { };
}
}');
Assert::instance($t, Reflection::type($t)->method('run')->invoke(null));
Assert::instance($t->class(), $t->method('run')->invoke(null));
}

#[Test]
public function referencing_enclosing_class() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
const ID= 6100;

public static function run() {
return new class() extends self {
public static $id= <T>::ID;
public static $id= %T::ID;
};
}
}');
Expand Down
32 changes: 19 additions & 13 deletions src/test/php/lang/ast/unittest/emit/ArgumentPromotionTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ArgumentPromotionTest extends EmittingTest {

#[Test]
public function in_constructor() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function __construct(private $id= "test") {
// Empty
}
Expand All @@ -30,7 +30,7 @@ public function run() {

#[Test]
public function can_be_used_in_constructor() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function __construct(private $id= "test") {
$this->id.= "ed";
}
Expand All @@ -44,7 +44,7 @@ public function run() {

#[Test]
public function parameter_accessible() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function __construct(private $id= "test") {
if (null === $id) {
throw new \\lang\\IllegalArgumentException("ID not set");
Expand All @@ -60,7 +60,7 @@ public function run() {

#[Test]
public function in_method() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function withId(private $id) {
return $this;
}
Expand All @@ -74,36 +74,42 @@ public function run() {

#[Test]
public function type_information() {
$t= $this->type('class <T> {
$t= $this->declare('class %T {
public function __construct(private int $id, private string $name) { }
}');
Assert::equals(
[Primitive::$INT, Primitive::$STRING],
[$t->getField('id')->getType(), $t->getField('name')->getType()]
[$t->property('id')->constraint()->type(), $t->property('name')->constraint()->type()]
);
}

#[Test, Expect(class: Errors::class, message: '/Variadic parameters cannot be promoted/')]
public function variadic_parameters_cannot_be_promoted() {
$this->type('class <T> {
$this->declare('class %T {
public function __construct(private string... $in) { }
}');
}

#[Test]
public function can_be_mixed_with_normal_arguments() {
$t= $this->type('class <T> {
$t= $this->declare('class %T {
public function __construct(public string $name, string $initial= null) {
if (null !== $initial) $this->name.= " ".$initial.".";
}
}');
Assert::equals(['name'], array_map(function($f) { return $f->getName(); }, $t->getFields()));

$names= [];
foreach ($t->properties() as $property) {
$names[]= $property->name();
}

Assert::equals(['name'], $names);
Assert::equals('Timm J.', $t->newInstance('Timm', 'J')->name);
}

#[Test]
public function promoted_by_reference_argument() {
$t= $this->type('class <T> {
$t= $this->declare('class %T {
public function __construct(public array &$list) { }

public static function test() {
Expand All @@ -114,12 +120,12 @@ public static function test() {
}
}');

Assert::equals([1, 2, 3, 4], $t->getMethod('test')->invoke(null, []));
Assert::equals([1, 2, 3, 4], $t->method('test')->invoke(null, []));
}

#[Test]
public function allows_trailing_comma() {
$this->type('class <T> {
$this->declare('class %T {
public function __construct(
public float $x = 0.0,
public float $y = 0.0,
Expand All @@ -130,7 +136,7 @@ public function __construct(

#[Test]
public function initializations_have_access() {
$t= $this->type('class <T> {
$t= $this->declare('class %T {
public $first= $this->list[0] ?? null;
public function __construct(private array $list) { }
}');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ArgumentUnpackingTest extends EmittingTest {

#[Test]
public function invoking_method() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function fixture(... $args) { return $args; }

public function run() {
Expand All @@ -25,7 +25,7 @@ public function run() {

#[Test]
public function in_array_initialization_with_variable() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function run() {
$args= [3, 4];
return [1, 2, ...$args];
Expand All @@ -36,7 +36,7 @@ public function run() {

#[Test]
public function in_array_initialization_with_literal() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function run() {
return [1, 2, ...[3, 4]];
}
Expand All @@ -46,7 +46,7 @@ public function run() {

#[Test]
public function in_map_initialization() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
public function run() {
$args= ["type" => "car"];
return ["color" => "red", ...$args, "year" => 2002];
Expand All @@ -57,7 +57,7 @@ public function run() {

#[Test]
public function from_generator() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
private function items() {
yield 1;
yield 2;
Expand All @@ -72,7 +72,7 @@ public function run() {

#[Test]
public function from_iterator() {
$r= $this->run('class <T> {
$r= $this->run('class %T {
private function items() {
return new \ArrayIterator([1, 2]);
}
Expand Down
Loading