From b3c559403fccf41406e44f04e05cb04c98d2c238 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 23 May 2026 19:54:43 +0000 Subject: [PATCH 1/3] =?UTF-8?q?test:=20integer=20enum,=20$ref-to-enum,=20v?= =?UTF-8?q?2=20allOf=20collapse,=20v2=20string=20enum=20(+9=20tests,=20459?= =?UTF-8?q?=E2=86=92468)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - V3: integer enum compiles to named IsEnum type with correct member count - V3: required property referencing a string enum uses enum type directly - V2: allOf with single $ref collapses (no wrapper type emitted) - V2: top-level string enum compiles to named IsEnum type Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Schema.V2SchemaCompilationTests.fs | 61 ++++++++++++++ .../Schema.V3SchemaCompilationTests.fs | 82 +++++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs b/tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs index e904912b..3b798e42 100644 --- a/tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.V2SchemaCompilationTests.fs @@ -289,6 +289,67 @@ let ``v2 allOf inheritance derived type has its own property``() = let dogType = types |> List.find(fun t -> t.Name = "Dog") dogType.GetDeclaredProperty("Breed") |> isNull |> shouldEqual false +// ── V2 allOf single $ref collapse ───────────────────────────────────────────── + +/// Swagger 2.0 schema where Alias wraps Pet via allOf with a single $ref and no +/// own properties. The compiler should collapse Alias into Pet. +let private v2AllOfSingleRefSchema = + """{ + "swagger": "2.0", + "info": { "title": "AliasTest", "version": "1.0.0" }, + "basePath": "/", + "paths": {}, + "definitions": { + "Pet": { + "type": "object", + "properties": { + "id": { "type": "integer" } + } + }, + "Alias": { + "allOf": [ { "$ref": "#/definitions/Pet" } ] + } + } +}""" + +[] +let ``v2 allOf single ref collapses to the referenced type``() = + let types = compileV2Schema v2AllOfSingleRefSchema + types |> List.exists(fun t -> t.Name = "Pet") |> shouldEqual true + +[] +let ``v2 allOf single ref does not produce a separate wrapper type``() = + let types = compileV2Schema v2AllOfSingleRefSchema + types |> List.exists(fun t -> t.Name = "Alias") |> shouldEqual false + +// ── V2 top-level string enum ────────────────────────────────────────────────── + +/// Swagger 2.0 schema with a top-level string enum definition. +let private v2StringEnumSchema = + """{ + "swagger": "2.0", + "info": { "title": "EnumTest", "version": "1.0.0" }, + "basePath": "/", + "paths": {}, + "definitions": { + "Color": { + "type": "string", + "enum": ["red", "green", "blue"] + } + } +}""" + +[] +let ``v2 top-level string enum compiles to a named enum type``() = + let types = compileV2Schema v2StringEnumSchema + types |> List.exists(fun t -> t.Name = "Color") |> shouldEqual true + +[] +let ``v2 top-level string enum type is an enum``() = + let types = compileV2Schema v2StringEnumSchema + let colorType = types |> List.find(fun t -> t.Name = "Color") + colorType.IsEnum |> shouldEqual true + // ── ToString tests ─────────────────────────────────────────────────────────── [] diff --git a/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs b/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs index df8f4f82..b67e566f 100644 --- a/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs @@ -452,6 +452,88 @@ let ``anyOf with multiple refs emits the referenced component types``() = types |> List.exists(fun t -> t.Name = "Fish") |> shouldEqual true types |> List.exists(fun t -> t.Name = "Bird") |> shouldEqual true +// ── Integer enum compilation ────────────────────────────────────────────────── + +/// OpenAPI 3.0 schema with a top-level integer enum named Priority. +let private integerEnumSchema = + """{ + "openapi": "3.0.0", + "info": { "title": "Test", "version": "1.0.0" }, + "paths": {}, + "components": { + "schemas": { + "Priority": { + "type": "integer", + "enum": [1, 2, 3] + } + } + } +}""" + +[] +let ``integer enum schema compiles to a named enum type``() = + let types = compileV3Schema integerEnumSchema false + types |> List.exists(fun t -> t.Name = "Priority") |> shouldEqual true + +[] +let ``integer enum type is an enum``() = + let types = compileV3Schema integerEnumSchema false + let priorityType = types |> List.find(fun t -> t.Name = "Priority") + priorityType.IsEnum |> shouldEqual true + +[] +let ``integer enum has the correct number of members``() = + let types = compileV3Schema integerEnumSchema false + let priorityType = types |> List.find(fun t -> t.Name = "Priority") + // Only literal fields (the enum members), not the internal __value field + let memberCount = + priorityType.GetFields() + |> Array.filter(fun f -> f.IsLiteral) + |> Array.length + + memberCount |> shouldEqual 3 + +// ── $ref to enum type → property uses the named enum type ──────────────────── + +/// OpenAPI 3.0 schema where Task.status references Status (a string enum) via $ref. +let private refToEnumSchema = + """{ + "openapi": "3.0.0", + "info": { "title": "Test", "version": "1.0.0" }, + "paths": {}, + "components": { + "schemas": { + "Status": { + "type": "string", + "enum": ["open", "closed"] + }, + "Task": { + "type": "object", + "required": ["status"], + "properties": { + "status": { "$ref": "#/components/schemas/Status" } + } + } + } + } +}""" + +[] +let ``required property referencing a string enum uses the named enum type``() = + let types = compileV3Schema refToEnumSchema false + let taskType = types |> List.find(fun t -> t.Name = "Task") + let statusProp = taskType.GetDeclaredProperty("Status") + statusProp |> isNull |> shouldEqual false + statusProp.PropertyType.IsEnum |> shouldEqual true + +[] +let ``required property referencing a string enum is not wrapped in option``() = + // Required $ref to enum: the property should use the enum type directly (not Option). + let types = compileV3Schema refToEnumSchema false + let taskType = types |> List.find(fun t -> t.Name = "Task") + let statusProp = taskType.GetDeclaredProperty("Status") + statusProp.PropertyType.IsGenericType |> shouldEqual false + // ── allOf single $ref with extra wrapper properties → new object type ───────── /// OpenAPI 3.0 schema where Extended wraps Base via allOf with a single $ref, From 28a8336177dca4b8d459966415df06876d28f3cc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 23 May 2026 19:54:46 +0000 Subject: [PATCH 2/3] ci: trigger checks From 22fe96f9a36cebf96ac5031d0f530496e73d3cd0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 20:15:06 +0000 Subject: [PATCH 3/3] test: remove duplicate V3 integer enum tests and tighten ref enum assertions Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/faaae8f3-8672-45ac-b7da-4e504f49d63d Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- .../Schema.V3SchemaCompilationTests.fs | 46 ++----------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs b/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs index b67e566f..a63e1ed9 100644 --- a/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.V3SchemaCompilationTests.fs @@ -452,47 +452,6 @@ let ``anyOf with multiple refs emits the referenced component types``() = types |> List.exists(fun t -> t.Name = "Fish") |> shouldEqual true types |> List.exists(fun t -> t.Name = "Bird") |> shouldEqual true -// ── Integer enum compilation ────────────────────────────────────────────────── - -/// OpenAPI 3.0 schema with a top-level integer enum named Priority. -let private integerEnumSchema = - """{ - "openapi": "3.0.0", - "info": { "title": "Test", "version": "1.0.0" }, - "paths": {}, - "components": { - "schemas": { - "Priority": { - "type": "integer", - "enum": [1, 2, 3] - } - } - } -}""" - -[] -let ``integer enum schema compiles to a named enum type``() = - let types = compileV3Schema integerEnumSchema false - types |> List.exists(fun t -> t.Name = "Priority") |> shouldEqual true - -[] -let ``integer enum type is an enum``() = - let types = compileV3Schema integerEnumSchema false - let priorityType = types |> List.find(fun t -> t.Name = "Priority") - priorityType.IsEnum |> shouldEqual true - -[] -let ``integer enum has the correct number of members``() = - let types = compileV3Schema integerEnumSchema false - let priorityType = types |> List.find(fun t -> t.Name = "Priority") - // Only literal fields (the enum members), not the internal __value field - let memberCount = - priorityType.GetFields() - |> Array.filter(fun f -> f.IsLiteral) - |> Array.length - - memberCount |> shouldEqual 3 - // ── $ref to enum type → property uses the named enum type ──────────────────── /// OpenAPI 3.0 schema where Task.status references Status (a string enum) via $ref. @@ -521,17 +480,20 @@ let private refToEnumSchema = [] let ``required property referencing a string enum uses the named enum type``() = let types = compileV3Schema refToEnumSchema false + let statusType = types |> List.find(fun t -> t.Name = "Status") let taskType = types |> List.find(fun t -> t.Name = "Task") let statusProp = taskType.GetDeclaredProperty("Status") statusProp |> isNull |> shouldEqual false - statusProp.PropertyType.IsEnum |> shouldEqual true + statusProp.PropertyType |> shouldEqual statusType [] let ``required property referencing a string enum is not wrapped in option``() = // Required $ref to enum: the property should use the enum type directly (not Option). let types = compileV3Schema refToEnumSchema false + let statusType = types |> List.find(fun t -> t.Name = "Status") let taskType = types |> List.find(fun t -> t.Name = "Task") let statusProp = taskType.GetDeclaredProperty("Status") + statusProp.PropertyType |> shouldEqual statusType statusProp.PropertyType.IsGenericType |> shouldEqual false // ── allOf single $ref with extra wrapper properties → new object type ─────────