Parse and validate AT Protocol Lexicons with DTO generation for Laravel
at dev 157 lines 4.5 kB view raw
1<?php 2 3namespace SocialDept\AtpSchema\Tests\Unit\Generator; 4 5use Orchestra\Testbench\TestCase; 6use SocialDept\AtpSchema\Data\LexiconDocument; 7use SocialDept\AtpSchema\Generator\DTOGenerator; 8use SocialDept\AtpSchema\Parser\SchemaLoader; 9 10class DTOGeneratorTest extends TestCase 11{ 12 protected DTOGenerator $generator; 13 14 protected string $tempDir; 15 16 protected function setUp(): void 17 { 18 parent::setUp(); 19 20 $fixturesPath = __DIR__.'/../../fixtures'; 21 $loader = new SchemaLoader([$fixturesPath], false); 22 23 $this->tempDir = sys_get_temp_dir().'/schema-gen-test-'.uniqid(); 24 25 $this->generator = new DTOGenerator( 26 schemaLoader: $loader, 27 baseNamespace: 'Test\\Generated', 28 outputDirectory: $this->tempDir 29 ); 30 } 31 32 protected function tearDown(): void 33 { 34 if (is_dir($this->tempDir)) { 35 $this->deleteDirectory($this->tempDir); 36 } 37 38 parent::tearDown(); 39 } 40 41 protected function deleteDirectory(string $dir): void 42 { 43 if (! is_dir($dir)) { 44 return; 45 } 46 47 $items = scandir($dir); 48 49 foreach ($items as $item) { 50 if ($item === '.' || $item === '..') { 51 continue; 52 } 53 54 $path = $dir.'/'.$item; 55 56 if (is_dir($path)) { 57 $this->deleteDirectory($path); 58 } else { 59 unlink($path); 60 } 61 } 62 63 rmdir($dir); 64 } 65 66 public function test_it_generates_from_nsid(): void 67 { 68 $files = $this->generator->generateByNsid('app.bsky.feed.post', ['dryRun' => true]); 69 70 $this->assertNotEmpty($files); 71 $this->assertIsArray($files); 72 } 73 74 public function test_it_generates_code_from_document(): void 75 { 76 $document = LexiconDocument::fromArray([ 77 'lexicon' => 1, 78 'id' => 'test.example.record', 79 'defs' => [ 80 'main' => [ 81 'type' => 'record', 82 'record' => [ 83 'type' => 'object', 84 'required' => ['name'], 85 'properties' => [ 86 'name' => ['type' => 'string'], 87 ], 88 ], 89 ], 90 ], 91 ]); 92 93 $code = $this->generator->generate($document); 94 95 $this->assertIsString($code); 96 $this->assertStringContainsString('class Record', $code); 97 } 98 99 public function test_it_previews_generated_code(): void 100 { 101 $document = LexiconDocument::fromArray([ 102 'lexicon' => 1, 103 'id' => 'test.example.record', 104 'defs' => [ 105 'main' => [ 106 'type' => 'record', 107 'record' => [ 108 'type' => 'object', 109 'required' => ['name'], 110 'properties' => [ 111 'name' => ['type' => 'string'], 112 ], 113 ], 114 ], 115 ], 116 ]); 117 118 $code = $this->generator->preview($document); 119 120 $this->assertIsString($code); 121 $this->assertStringContainsString('<?php', $code); 122 } 123 124 public function test_it_gets_metadata(): void 125 { 126 $metadata = $this->generator->getMetadata('app.bsky.feed.post'); 127 128 $this->assertArrayHasKey('nsid', $metadata); 129 $this->assertArrayHasKey('namespace', $metadata); 130 $this->assertArrayHasKey('className', $metadata); 131 $this->assertArrayHasKey('fullyQualifiedName', $metadata); 132 $this->assertArrayHasKey('type', $metadata); 133 134 $this->assertSame('app.bsky.feed.post', $metadata['nsid']); 135 $this->assertSame('Test\\Generated\\App\\Bsky\\Feed', $metadata['namespace']); 136 $this->assertSame('Post', $metadata['className']); 137 } 138 139 public function test_it_validates_generated_code(): void 140 { 141 $validCode = '<?php class Test {}'; 142 143 $this->assertTrue($this->generator->validate($validCode)); 144 } 145 146 public function test_it_sets_options(): void 147 { 148 $this->generator->setOptions([ 149 'baseNamespace' => 'Custom\\Namespace', 150 'outputDirectory' => '/custom/path', 151 ]); 152 153 $metadata = $this->generator->getMetadata('app.bsky.feed.post'); 154 155 $this->assertStringStartsWith('Custom\\Namespace', $metadata['namespace']); 156 } 157}