microsoft/typespec

Public

mirrored from https://github.com/microsoft/typespecAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
ce9c567e5bfb441bb6415699a6b6fa797bc08f2e

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

packages/json-schema/test/models.test.ts

347lines · modecode

1import assert, { deepStrictEqual } from "assert";
2import { describe, it } from "vitest";
3import { emitSchema } from "./utils.js";
4
5describe("emitting models", () => {
6 it("works", async () => {
7 const schemas = await emitSchema(`
8 model Foo {
9 x: string;
10 }
11 `);
12 const Foo = schemas["Foo.json"];
13
14 assert.strictEqual(Foo.$id, "Foo.json");
15 assert.strictEqual(Foo.$schema, "https://json-schema.org/draft/2020-12/schema");
16 assert.deepStrictEqual(Foo.properties, { x: { type: "string" } });
17 assert.deepStrictEqual(Foo.required, ["x"]);
18 });
19
20 it("works with model property references", async () => {
21 const schemas = await emitSchema(`
22 model Foo {
23 x: Bar.y
24 }
25
26 model Bar {
27 @maxLength(20)
28 y: string;
29 }
30 `);
31
32 assert.deepStrictEqual(schemas["Foo.json"].properties, {
33 x: { type: "string", maxLength: 20 },
34 });
35 });
36
37 it("handles inheritance", async () => {
38 const schemas = await emitSchema(`
39 model Foo {}
40 model Bar extends Foo {}
41 `);
42
43 assert.deepStrictEqual(schemas["Bar.json"].allOf, [{ $ref: "Foo.json" }]);
44 });
45
46 it("handles templates instantiated with declarations", async () => {
47 const schemas = await emitSchema(`
48 model Foo {
49 prop: Template<Foo>
50 }
51
52 model Template<T> {
53 x: T
54 }
55
56 `);
57
58 assert.deepStrictEqual(schemas["Foo.json"].properties.prop, { $ref: "TemplateFoo.json" });
59 assert(schemas["TemplateFoo.json"]);
60 });
61
62 it("works with minProperties and maxProperties", async () => {
63 const { "Foo.json": Foo } = await emitSchema(`
64 @minProperties(1)
65 @maxProperties(2)
66 model Foo is Record<unknown>;
67 `);
68
69 assert.strictEqual(Foo.minProperties, 1);
70 assert.strictEqual(Foo.maxProperties, 2);
71 });
72
73 it("works with @doc, @summary, and @deprecated", async () => {
74 const { "Foo.json": Foo } = await emitSchema(`
75 @doc("a")
76 @summary("a")
77 #deprecated "bad api"
78 model Foo {
79 @doc("b")
80 @summary("b")
81 #deprecated "bad api"
82 b: string;
83 }
84 `);
85
86 assert.strictEqual(Foo.description, "a");
87 assert.strictEqual(Foo.title, "a");
88 assert.strictEqual(Foo.deprecated, true);
89 assert.strictEqual(Foo.properties.b.description, "b");
90 assert.strictEqual(Foo.properties.b.title, "b");
91 assert.strictEqual(Foo.properties.b.deprecated, true);
92 });
93
94 it("handles extensions", async () => {
95 const { "Foo.json": Foo } = await emitSchema(`
96 @extension("x-hi", "bye")
97 model Foo {
98 @extension("x-hi", Json<"hello">)
99 b: string;
100 }
101 `);
102
103 assert.deepStrictEqual(Foo["x-hi"], { type: "string", const: "bye" });
104 assert.deepStrictEqual(Foo.properties.b["x-hi"], "hello");
105 });
106
107 it("handles Record<T>", async () => {
108 const schemas = await emitSchema(
109 `
110 model ExtendsRecord extends Record<string> {};
111 model IsRecord is Record<{ x: int32, y: int32}>;
112 model HasProp {
113 x: Record<string>;
114 }
115 `,
116 { emitAllRefs: true }
117 );
118
119 assert.deepStrictEqual(schemas["ExtendsRecord.json"].allOf[0], { $ref: "RecordString.json" });
120 assert.deepStrictEqual(schemas["RecordString.json"].additionalProperties, { type: "string" });
121 assert.deepStrictEqual(schemas["IsRecord.json"].additionalProperties, {
122 type: "object",
123 properties: {
124 x: {
125 type: "integer",
126 minimum: -2147483648,
127 maximum: 2147483647,
128 },
129 y: {
130 type: "integer",
131 minimum: -2147483648,
132 maximum: 2147483647,
133 },
134 },
135 required: ["x", "y"],
136 });
137 assert.deepStrictEqual(schemas["HasProp.json"].properties.x, { $ref: "RecordString.json" });
138 });
139
140 it("handles instantiations of intrinsics", async () => {
141 const schemas = await emitSchema(
142 `
143 model Test {
144 "never": Record<never>;
145 "unknown": Record<unknown>;
146 "void": Record<void>;
147 "null": Record<null>;
148 }
149 `,
150 { emitAllRefs: true }
151 );
152
153 assert.deepStrictEqual(schemas["RecordNever.json"].additionalProperties, { not: {} });
154 assert.deepStrictEqual(schemas["RecordUnknown.json"].additionalProperties, {});
155 assert.deepStrictEqual(schemas["RecordVoid.json"].additionalProperties, { not: {} });
156 assert.deepStrictEqual(schemas["RecordNull.json"].additionalProperties, { type: "null" });
157 });
158
159 it("handles instantiations of literal types", async () => {
160 const schemas = await emitSchema(
161 `
162 model Test {
163 "string": Record<"hi">;
164 "number": Record<1.2>;
165 "boolean": Record<true>;
166 }
167 `,
168 { emitAllRefs: true }
169 );
170 assert.deepStrictEqual(schemas["Test.json"].properties.string.additionalProperties, {
171 type: "string",
172 const: "hi",
173 });
174 assert.deepStrictEqual(schemas["Test.json"].properties.number.additionalProperties, {
175 type: "number",
176 const: 1.2,
177 });
178 assert.deepStrictEqual(schemas["Test.json"].properties.boolean.additionalProperties, {
179 type: "boolean",
180 const: true,
181 });
182 });
183
184 it("handles instantiations of type expressions", async () => {
185 const schemas = await emitSchema(
186 `
187 model A { x: int32 }
188 model B { y: int32 }
189 model Test {
190 "union": Record<int32 | int16>;
191 "intersection": Record<A & B>;
192 "speakableInstantiation": Record<Record<int32>>;
193 "unspeakableInstantiation": Record<Record<A & B>>;
194 }
195 `,
196 { emitAllRefs: true }
197 );
198
199 assert.deepStrictEqual(schemas["Test.json"].properties.union.additionalProperties, {
200 anyOf: [
201 {
202 type: "integer",
203 minimum: -2147483648,
204 maximum: 2147483647,
205 },
206 {
207 type: "integer",
208 minimum: -32768,
209 maximum: 32767,
210 },
211 ],
212 });
213
214 assert.deepStrictEqual(schemas["Test.json"].properties.intersection.additionalProperties, {
215 type: "object",
216 properties: {
217 x: {
218 type: "integer",
219 minimum: -2147483648,
220 maximum: 2147483647,
221 },
222 y: {
223 type: "integer",
224 minimum: -2147483648,
225 maximum: 2147483647,
226 },
227 },
228 required: ["x", "y"],
229 });
230
231 assert.deepStrictEqual(
232 schemas["Test.json"].properties.unspeakableInstantiation.additionalProperties,
233 {
234 type: "object",
235 properties: {},
236 additionalProperties: {
237 type: "object",
238 properties: {
239 x: {
240 type: "integer",
241 minimum: -2147483648,
242 maximum: 2147483647,
243 },
244 y: {
245 type: "integer",
246 minimum: -2147483648,
247 maximum: 2147483647,
248 },
249 },
250 required: ["x", "y"],
251 },
252 }
253 );
254 assert.deepStrictEqual(schemas["RecordRecordInt32.json"].additionalProperties, {
255 $ref: "RecordInt32.json",
256 });
257 });
258
259 describe("default values", () => {
260 it("specify default value on enum property", async () => {
261 const res = await emitSchema(
262 `
263 model Foo {
264 optionalEnum?: MyEnum = MyEnum.a;
265 };
266
267 enum MyEnum {
268 a: "a-value",
269 b,
270 }
271 `
272 );
273
274 deepStrictEqual(res["Foo.json"].properties.optionalEnum, {
275 $ref: "MyEnum.json",
276 default: "a-value",
277 });
278 });
279
280 it("specify default value on string property", async () => {
281 const res = await emitSchema(
282 `
283 model Foo {
284 optional?: string = "abc";
285 }
286 `
287 );
288
289 deepStrictEqual(res["Foo.json"].properties.optional, {
290 type: "string",
291 default: "abc",
292 });
293 });
294
295 it("specify default value on numeric property", async () => {
296 const res = await emitSchema(
297 `
298 model Foo {
299 optional?: int32 = 123;
300 }
301 `
302 );
303
304 deepStrictEqual(res["Foo.json"].properties.optional, {
305 type: "integer",
306 minimum: -2147483648,
307 maximum: 2147483647,
308 default: 123,
309 });
310 });
311
312 it("specify default value on boolean property", async () => {
313 const res = await emitSchema(
314 `
315 model Foo {
316 optional?: boolean = true;
317 }
318 `
319 );
320
321 deepStrictEqual(res["Foo.json"].properties.optional, {
322 type: "boolean",
323 default: true,
324 });
325 });
326
327 it("specify default value on union with variant", async () => {
328 const res = await emitSchema(
329 `
330 model Foo {
331 optionalUnion?: MyUnion = MyUnion.a;
332 };
333
334 union MyUnion {
335 a: "a-value",
336 b: "b-value",
337 }
338 `
339 );
340
341 deepStrictEqual(res["Foo.json"].properties.optionalUnion, {
342 $ref: "MyUnion.json",
343 default: "a-value",
344 });
345 });
346 });
347});
348