Parse and validate AT Protocol Lexicons with DTO generation for Laravel
at dev 244 lines 7.9 kB view raw
1<?php 2 3namespace SocialDept\AtpSchema\Tests\Unit\Generator; 4 5use Orchestra\Testbench\TestCase; 6use SocialDept\AtpSchema\Generator\ConstructorGenerator; 7 8class ConstructorGeneratorTest extends TestCase 9{ 10 protected ConstructorGenerator $generator; 11 12 protected function setUp(): void 13 { 14 parent::setUp(); 15 16 $this->generator = new ConstructorGenerator(); 17 } 18 19 public function test_it_generates_constructor_with_promoted_properties(): void 20 { 21 $constructor = $this->generator->generate( 22 [ 23 'name' => ['type' => 'string'], 24 'age' => ['type' => 'integer'], 25 ], 26 ['name', 'age'] 27 ); 28 29 $this->assertStringContainsString('public function __construct(', $constructor); 30 $this->assertStringContainsString('public readonly string $name', $constructor); 31 $this->assertStringContainsString('public readonly int $age', $constructor); 32 } 33 34 public function test_it_handles_optional_parameters(): void 35 { 36 $constructor = $this->generator->generate( 37 [ 38 'name' => ['type' => 'string'], 39 'nickname' => ['type' => 'string'], 40 ], 41 ['name'] 42 ); 43 44 $this->assertStringContainsString('public readonly string $name', $constructor); 45 $this->assertStringContainsString('public readonly ?string $nickname', $constructor); 46 } 47 48 public function test_it_returns_empty_for_no_properties(): void 49 { 50 $constructor = $this->generator->generate([], []); 51 52 $this->assertEmpty($constructor); 53 } 54 55 public function test_it_generates_docblock(): void 56 { 57 $constructor = $this->generator->generate( 58 [ 59 'name' => ['type' => 'string'], 60 ], 61 ['name'] 62 ); 63 64 $this->assertStringContainsString('/**', $constructor); 65 $this->assertStringContainsString('* Create a new instance.', $constructor); 66 $this->assertStringContainsString('* @param string $name', $constructor); 67 } 68 69 public function test_it_includes_descriptions_in_docblock(): void 70 { 71 $constructor = $this->generator->generate( 72 [ 73 'name' => [ 74 'type' => 'string', 75 'description' => 'The user name', 76 ], 77 ], 78 ['name'] 79 ); 80 81 $this->assertStringContainsString('The user name', $constructor); 82 } 83 84 public function test_it_handles_multiple_properties(): void 85 { 86 $constructor = $this->generator->generate( 87 [ 88 'id' => ['type' => 'string'], 89 'name' => ['type' => 'string'], 90 'email' => ['type' => 'string'], 91 'age' => ['type' => 'integer'], 92 'active' => ['type' => 'boolean'], 93 ], 94 ['id', 'name', 'email'] 95 ); 96 97 $this->assertStringContainsString('$id', $constructor); 98 $this->assertStringContainsString('$name', $constructor); 99 $this->assertStringContainsString('$email', $constructor); 100 $this->assertStringContainsString('$age', $constructor); 101 $this->assertStringContainsString('$active', $constructor); 102 } 103 104 public function test_it_generates_with_assignments(): void 105 { 106 $constructor = $this->generator->generateWithAssignments( 107 [ 108 'name' => ['type' => 'string'], 109 'age' => ['type' => 'integer'], 110 ], 111 ['name', 'age'] 112 ); 113 114 $this->assertStringContainsString('public function __construct(', $constructor); 115 $this->assertStringContainsString('string $name,', $constructor); 116 $this->assertStringContainsString('int $age', $constructor); 117 $this->assertStringContainsString('$this->name = $name;', $constructor); 118 $this->assertStringContainsString('$this->age = $age;', $constructor); 119 } 120 121 public function test_it_checks_if_constructor_should_be_generated(): void 122 { 123 $this->assertTrue($this->generator->shouldGenerate(['name' => ['type' => 'string']])); 124 $this->assertFalse($this->generator->shouldGenerate([])); 125 } 126 127 public function test_it_handles_default_values(): void 128 { 129 $constructor = $this->generator->generate( 130 [ 131 'status' => [ 132 'type' => 'string', 133 'default' => 'active', 134 ], 135 ], 136 [] 137 ); 138 139 $this->assertStringContainsString("= 'active'", $constructor); 140 } 141 142 public function test_it_handles_nullable_with_null_default(): void 143 { 144 $constructor = $this->generator->generate( 145 [ 146 'middleName' => [ 147 'type' => 'string', 148 'default' => null, 149 ], 150 ], 151 [] 152 ); 153 154 $this->assertStringContainsString('?string $middleName = null', $constructor); 155 } 156 157 public function test_it_handles_all_primitive_types(): void 158 { 159 $constructor = $this->generator->generate( 160 [ 161 'name' => ['type' => 'string'], 162 'age' => ['type' => 'integer'], 163 'price' => ['type' => 'number'], 164 'active' => ['type' => 'boolean'], 165 'tags' => ['type' => 'array'], 166 ], 167 ['name', 'age', 'price', 'active', 'tags'] 168 ); 169 170 $this->assertStringContainsString('string $name', $constructor); 171 $this->assertStringContainsString('int $age', $constructor); 172 $this->assertStringContainsString('float $price', $constructor); 173 $this->assertStringContainsString('bool $active', $constructor); 174 $this->assertStringContainsString('array $tags', $constructor); 175 } 176 177 public function test_it_does_not_add_trailing_comma_to_last_parameter(): void 178 { 179 $constructor = $this->generator->generate( 180 [ 181 'first' => ['type' => 'string'], 182 'last' => ['type' => 'string'], 183 ], 184 ['first', 'last'] 185 ); 186 187 // Last parameter should not have a trailing comma 188 $this->assertStringNotContainsString('$last,', $constructor); 189 $this->assertStringContainsString('$last', $constructor); 190 } 191 192 public function test_it_formats_parameters_with_proper_indentation(): void 193 { 194 $constructor = $this->generator->generate( 195 [ 196 'name' => ['type' => 'string'], 197 ], 198 ['name'] 199 ); 200 201 // Check for proper indentation (8 spaces for parameters) 202 $this->assertStringContainsString(' public readonly string $name', $constructor); 203 } 204 205 public function test_it_generates_empty_body_for_promoted_properties(): void 206 { 207 $constructor = $this->generator->generate( 208 [ 209 'name' => ['type' => 'string'], 210 ], 211 ['name'] 212 ); 213 214 // Constructor body should be empty for promoted properties 215 $this->assertMatchesRegularExpression('/\) \{\s+\}/', $constructor); 216 } 217 218 public function test_it_handles_blob_type(): void 219 { 220 $constructor = $this->generator->generate( 221 [ 222 'image' => ['type' => 'blob'], 223 ], 224 [] 225 ); 226 227 $this->assertStringContainsString('BlobReference', $constructor); 228 } 229 230 public function test_it_handles_ref_type(): void 231 { 232 $constructor = $this->generator->generate( 233 [ 234 'author' => [ 235 'type' => 'ref', 236 'ref' => 'app.test.author', 237 ], 238 ], 239 ['author'] 240 ); 241 242 $this->assertStringContainsString('public readonly Author $author', $constructor); 243 } 244}