Parse and validate AT Protocol Lexicons with DTO generation for Laravel
1<?php
2
3namespace SocialDept\AtpSchema\Tests\Unit\Parser;
4
5use Orchestra\Testbench\TestCase;
6use SocialDept\AtpSchema\Data\Types\ArrayType;
7use SocialDept\AtpSchema\Data\Types\BlobType;
8use SocialDept\AtpSchema\Data\Types\ObjectType;
9use SocialDept\AtpSchema\Data\Types\RefType;
10use SocialDept\AtpSchema\Data\Types\StringType;
11use SocialDept\AtpSchema\Data\Types\UnionType;
12use SocialDept\AtpSchema\Exceptions\TypeResolutionException;
13use SocialDept\AtpSchema\Parser\ComplexTypeParser;
14
15class ComplexTypeParserTest extends TestCase
16{
17 protected ComplexTypeParser $parser;
18
19 protected function setUp(): void
20 {
21 parent::setUp();
22
23 $this->parser = new ComplexTypeParser();
24 }
25
26 public function test_it_parses_object_type(): void
27 {
28 $type = $this->parser->parse(['type' => 'object']);
29
30 $this->assertInstanceOf(ObjectType::class, $type);
31 }
32
33 public function test_it_parses_object_with_properties(): void
34 {
35 $type = $this->parser->parse([
36 'type' => 'object',
37 'properties' => [
38 'name' => ['type' => 'string'],
39 'age' => ['type' => 'integer'],
40 ],
41 ]);
42
43 $this->assertInstanceOf(ObjectType::class, $type);
44 $this->assertCount(2, $type->properties);
45 $this->assertInstanceOf(StringType::class, $type->properties['name']);
46 }
47
48 public function test_it_parses_array_type(): void
49 {
50 $type = $this->parser->parse(['type' => 'array']);
51
52 $this->assertInstanceOf(ArrayType::class, $type);
53 }
54
55 public function test_it_parses_array_with_items(): void
56 {
57 $type = $this->parser->parse([
58 'type' => 'array',
59 'items' => ['type' => 'string'],
60 ]);
61
62 $this->assertInstanceOf(ArrayType::class, $type);
63 $this->assertInstanceOf(StringType::class, $type->items);
64 }
65
66 public function test_it_parses_nested_complex_types(): void
67 {
68 $type = $this->parser->parse([
69 'type' => 'object',
70 'properties' => [
71 'items' => [
72 'type' => 'array',
73 'items' => ['type' => 'string'],
74 ],
75 ],
76 ]);
77
78 $this->assertInstanceOf(ObjectType::class, $type);
79 $this->assertInstanceOf(ArrayType::class, $type->properties['items']);
80 $this->assertInstanceOf(StringType::class, $type->properties['items']->items);
81 }
82
83 public function test_it_parses_union_type(): void
84 {
85 $type = $this->parser->parse([
86 'type' => 'union',
87 'refs' => ['#typeA', '#typeB'],
88 ]);
89
90 $this->assertInstanceOf(UnionType::class, $type);
91 }
92
93 public function test_it_parses_ref_type(): void
94 {
95 $type = $this->parser->parse([
96 'type' => 'ref',
97 'ref' => '#main',
98 ]);
99
100 $this->assertInstanceOf(RefType::class, $type);
101 }
102
103 public function test_it_parses_blob_type(): void
104 {
105 $type = $this->parser->parse([
106 'type' => 'blob',
107 'accept' => ['image/*'],
108 ]);
109
110 $this->assertInstanceOf(BlobType::class, $type);
111 }
112
113 public function test_it_throws_on_missing_type(): void
114 {
115 $this->expectException(TypeResolutionException::class);
116 $this->expectExceptionMessage('Unknown Lexicon type: (missing type field)');
117
118 $this->parser->parse([]);
119 }
120
121 public function test_it_throws_on_unknown_type(): void
122 {
123 $this->expectException(TypeResolutionException::class);
124 $this->expectExceptionMessage('Unknown Lexicon type: nonexistent');
125
126 $this->parser->parse(['type' => 'nonexistent']);
127 }
128
129 public function test_it_checks_if_type_is_complex(): void
130 {
131 $this->assertTrue($this->parser->isComplex('object'));
132 $this->assertTrue($this->parser->isComplex('array'));
133 $this->assertTrue($this->parser->isComplex('union'));
134 $this->assertTrue($this->parser->isComplex('ref'));
135 $this->assertTrue($this->parser->isComplex('blob'));
136
137 $this->assertFalse($this->parser->isComplex('string'));
138 $this->assertFalse($this->parser->isComplex('integer'));
139 }
140
141 public function test_it_returns_supported_types(): void
142 {
143 $types = $this->parser->getSupportedTypes();
144
145 $this->assertCount(5, $types);
146 $this->assertContains('object', $types);
147 $this->assertContains('array', $types);
148 $this->assertContains('union', $types);
149 $this->assertContains('ref', $types);
150 $this->assertContains('blob', $types);
151 }
152}