diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index 96d3cc17d..a76dcf354 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -52,7 +52,8 @@ public override void Visit(OpenApiSchema schema) public override void Visit(OpenApiPathItem pathItem) { - if (pathItem.Operations.TryGetValue(OperationType.Put, out var value)) + if (pathItem.Operations.TryGetValue(OperationType.Put, out var value) && + value.OperationId != null) { var operationId = value.OperationId; pathItem.Operations[OperationType.Put].OperationId = ResolvePutOperationId(operationId); @@ -67,14 +68,14 @@ public override void Visit(OpenApiOperation operation) throw new ArgumentException($"OperationId is required {PathString}", nameof(operation)); var operationId = operation.OperationId; - var operationTypeExtension = operation.Extensions.GetExtension("x-ms-docs-operation-type"); + var operationTypeExtension = operation.Extensions?.GetExtension("x-ms-docs-operation-type"); if (operationTypeExtension.IsEquals("function")) - operation.Parameters = ResolveFunctionParameters(operation.Parameters); + operation.Parameters = ResolveFunctionParameters(operation.Parameters ?? new List()); // Order matters. Resolve operationId. operationId = RemoveHashSuffix(operationId); if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function")) - operationId = RemoveKeyTypeSegment(operationId, operation.Parameters); + operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List()); operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.')); operationId = ResolveODataCastOperationId(operationId); operationId = ResolveByRefOperationId(operationId); diff --git a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs index d3d3fdd8c..014891a42 100644 --- a/src/Microsoft.OpenApi.Hidi/OpenApiService.cs +++ b/src/Microsoft.OpenApi.Hidi/OpenApiService.cs @@ -172,7 +172,7 @@ private static OpenApiDocument ApplyFilters(HidiOptions options, ILogger logger, stopwatch.Start(); document = OpenApiFilterService.CreateFilteredDocument(document, predicate); stopwatch.Stop(); - logger.LogTrace("{Timestamp}ms: Creating filtered OpenApi document with {Paths} paths.", stopwatch.ElapsedMilliseconds, document.Paths.Count); + logger.LogTrace("{Timestamp}ms: Creating filtered OpenApi document with {Paths} paths.", stopwatch.ElapsedMilliseconds, document.Paths?.Count); } return document; @@ -235,7 +235,7 @@ private static async Task GetOpenApi(HidiOptions options, ILogg document = await ConvertCsdlToOpenApi(filteredStream ?? stream, metadataVersion, options.SettingsConfig, cancellationToken).ConfigureAwait(false); stopwatch.Stop(); - logger.LogTrace("{Timestamp}ms: Generated OpenAPI with {Paths} paths.", stopwatch.ElapsedMilliseconds, document.Paths.Count); + logger.LogTrace("{Timestamp}ms: Generated OpenAPI with {Paths} paths.", stopwatch.ElapsedMilliseconds, document.Paths?.Count); } } else if (!string.IsNullOrEmpty(options.OpenApi)) @@ -649,7 +649,7 @@ internal static void WriteTreeDocumentAsMarkdown(string openapiUrl, OpenApiDocum { var rootNode = OpenApiUrlTreeNode.Create(document, "main"); - writer.WriteLine("# " + document.Info.Title); + writer.WriteLine("# " + document.Info?.Title); writer.WriteLine(); writer.WriteLine("API Description: " + openapiUrl); @@ -685,7 +685,7 @@ internal static void WriteTreeDocumentAsHtml(string sourceUrl, OpenApiDocument d """); - writer.WriteLine("

" + document.Info.Title + "

"); + writer.WriteLine("

" + document.Info?.Title + "

"); writer.WriteLine(); writer.WriteLine($"

API Description: {sourceUrl}

"); @@ -755,8 +755,8 @@ internal static async Task PluginManifest(HidiOptions options, ILogger logger, C // Create OpenAIPluginManifest from ApiDependency and OpenAPI document var manifest = new OpenAIPluginManifest { - NameForHuman = document.Info.Title, - DescriptionForHuman = document.Info.Description, + NameForHuman = document.Info?.Title, + DescriptionForHuman = document.Info?.Description, Api = new() { Type = "openapi", diff --git a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs index 52e8cac14..f9828f165 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiComponents.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiComponents.cs @@ -6,6 +6,8 @@ using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; +#nullable enable + namespace Microsoft.OpenApi.Models { /// @@ -16,55 +18,55 @@ public class OpenApiComponents : IOpenApiSerializable, IOpenApiExtensible /// /// An object to hold reusable Objects. /// - public IDictionary Schemas { get; set; } = new Dictionary(); + public IDictionary? Schemas { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary Responses { get; set; } = new Dictionary(); + public IDictionary? Responses { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary Parameters { get; set; } = + public IDictionary? Parameters { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary Examples { get; set; } = new Dictionary(); + public IDictionary? Examples { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary RequestBodies { get; set; } = + public IDictionary? RequestBodies { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary Headers { get; set; } = new Dictionary(); + public IDictionary? Headers { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary SecuritySchemes { get; set; } = + public IDictionary? SecuritySchemes { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary Links { get; set; } = new Dictionary(); + public IDictionary? Links { get; set; } = new Dictionary(); /// /// An object to hold reusable Objects. /// - public IDictionary Callbacks { get; set; } = new Dictionary(); + public IDictionary? Callbacks { get; set; } = new Dictionary(); /// /// This object MAY be extended with Specification Extensions. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// Parameter-less constructor @@ -74,7 +76,7 @@ public OpenApiComponents() { } /// /// Initializes a copy of an object /// - public OpenApiComponents(OpenApiComponents components) + public OpenApiComponents(OpenApiComponents? components) { Schemas = components?.Schemas != null ? new Dictionary(components.Schemas) : null; Responses = components?.Responses != null ? new Dictionary(components.Responses) : null; diff --git a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs index 8d4526a20..daf5aee72 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiDocument.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiDocument.cs @@ -12,6 +12,8 @@ using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Writers; +#nullable enable + namespace Microsoft.OpenApi.Models { /// @@ -22,48 +24,48 @@ public class OpenApiDocument : IOpenApiSerializable, IOpenApiExtensible /// /// Related workspace containing OpenApiDocuments that are referenced in this document /// - public OpenApiWorkspace Workspace { get; set; } + public OpenApiWorkspace? Workspace { get; set; } /// /// REQUIRED. Provides metadata about the API. The metadata MAY be used by tooling as required. /// - public OpenApiInfo Info { get; set; } + public OpenApiInfo? Info { get; set; } /// /// An array of Server Objects, which provide connectivity information to a target server. /// - public IList Servers { get; set; } = new List(); + public IList? Servers { get; set; } = new List(); /// /// REQUIRED. The available paths and operations for the API. /// - public OpenApiPaths Paths { get; set; } + public OpenApiPaths? Paths { get; set; } /// /// An element to hold various schemas for the specification. /// - public OpenApiComponents Components { get; set; } + public OpenApiComponents? Components { get; set; } /// /// A declaration of which security mechanisms can be used across the API. /// - public IList SecurityRequirements { get; set; } = + public IList? SecurityRequirements { get; set; } = new List(); /// /// A list of tags used by the specification with additional metadata. /// - public IList Tags { get; set; } = new List(); + public IList? Tags { get; set; } = new List(); /// /// Additional external documentation. /// - public OpenApiExternalDocs ExternalDocs { get; set; } + public OpenApiExternalDocs? ExternalDocs { get; set; } /// /// This object MAY be extended with Specification Extensions. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// The unique hash code of the generated OpenAPI document @@ -78,7 +80,7 @@ public OpenApiDocument() {} /// /// Initializes a copy of an an object /// - public OpenApiDocument(OpenApiDocument document) + public OpenApiDocument(OpenApiDocument? document) { Workspace = document?.Workspace != null ? new(document?.Workspace) : null; Info = document?.Info != null ? new(document?.Info) : null; @@ -289,7 +291,7 @@ private static string ParseServerUrl(OpenApiServer server) return parsedUrl; } - private static void WriteHostInfoV2(IOpenApiWriter writer, IList servers) + private static void WriteHostInfoV2(IOpenApiWriter writer, IList? servers) { if (servers == null || !servers.Any()) { @@ -373,7 +375,7 @@ public IEnumerable ResolveReferences() /// /// Load the referenced object from a object /// - internal T ResolveReferenceTo(OpenApiReference reference) where T : class, IOpenApiReferenceable + internal T? ResolveReferenceTo(OpenApiReference reference) where T : class, IOpenApiReferenceable { if (reference.IsExternal) { @@ -388,7 +390,7 @@ internal T ResolveReferenceTo(OpenApiReference reference) where T : class, IO /// /// Load the referenced object from a object /// - public IOpenApiReferenceable ResolveReference(OpenApiReference reference) + public IOpenApiReferenceable? ResolveReference(OpenApiReference reference) { return ResolveReference(reference, false); } @@ -430,7 +432,7 @@ private static string ConvertByteArrayToString(byte[] hash) /// /// Load the referenced object from a object /// - internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool useExternal) + internal IOpenApiReferenceable? ResolveReference(OpenApiReference? reference, bool useExternal) { if (reference == null) { @@ -455,7 +457,7 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool // Special case for Tag if (reference.Type == ReferenceType.Tag) { - foreach (var tag in this.Tags) + foreach (var tag in this.Tags ?? Enumerable.Empty()) { if (tag.Name == reference.Id) { @@ -477,34 +479,34 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool switch (reference.Type) { case ReferenceType.Schema: - return this.Components.Schemas[reference.Id]; + return this.Components.Schemas?[reference.Id]; case ReferenceType.Response: - return this.Components.Responses[reference.Id]; + return this.Components.Responses?[reference.Id]; case ReferenceType.Parameter: - return this.Components.Parameters[reference.Id]; + return this.Components.Parameters?[reference.Id]; case ReferenceType.Example: - return this.Components.Examples[reference.Id]; + return this.Components.Examples?[reference.Id]; case ReferenceType.RequestBody: - return this.Components.RequestBodies[reference.Id]; + return this.Components.RequestBodies?[reference.Id]; case ReferenceType.Header: - return this.Components.Headers[reference.Id]; + return this.Components.Headers?[reference.Id]; case ReferenceType.SecurityScheme: - return this.Components.SecuritySchemes[reference.Id]; + return this.Components.SecuritySchemes?[reference.Id]; case ReferenceType.Link: - return this.Components.Links[reference.Id]; + return this.Components.Links?[reference.Id]; case ReferenceType.Callback: - return this.Components.Callbacks[reference.Id]; + return this.Components.Callbacks?[reference.Id]; case ReferenceType.Path: - return this.Paths[reference.Id]; + return this.Paths?[reference.Id]; default: throw new OpenApiException(Properties.SRResource.InvalidReferenceType); @@ -519,9 +521,9 @@ internal IOpenApiReferenceable ResolveReference(OpenApiReference reference, bool internal class FindSchemaReferences : OpenApiVisitorBase { - private Dictionary Schemas; + private Dictionary Schemas = new Dictionary(); - public static void ResolveSchemas(OpenApiComponents components, Dictionary schemas ) + public static void ResolveSchemas(OpenApiComponents? components, Dictionary schemas ) { var visitor = new FindSchemaReferences(); visitor.Schemas = schemas; diff --git a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs index 444f41ba5..5d0b11a1f 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiMediaType.cs @@ -6,6 +6,8 @@ using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; +#nullable enable + namespace Microsoft.OpenApi.Models { /// @@ -16,19 +18,19 @@ public class OpenApiMediaType : IOpenApiSerializable, IOpenApiExtensible /// /// The schema defining the type used for the request body. /// - public OpenApiSchema Schema { get; set; } + public OpenApiSchema? Schema { get; set; } /// /// Example of the media type. /// The example object SHOULD be in the correct format as specified by the media type. /// - public IOpenApiAny Example { get; set; } + public IOpenApiAny? Example { get; set; } /// /// Examples of the media type. /// Each example object SHOULD match the media type and specified schema if present. /// - public IDictionary Examples { get; set; } = new Dictionary(); + public IDictionary? Examples { get; set; } = new Dictionary(); /// /// A map between a property name and its encoding information. @@ -36,12 +38,12 @@ public class OpenApiMediaType : IOpenApiSerializable, IOpenApiExtensible /// The encoding object SHALL only apply to requestBody objects /// when the media type is multipart or application/x-www-form-urlencoded. /// - public IDictionary Encoding { get; set; } = new Dictionary(); + public IDictionary? Encoding { get; set; } = new Dictionary(); /// /// Serialize to Open Api v3.0. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -51,7 +53,7 @@ public OpenApiMediaType() {} /// /// Initializes a copy of an object /// - public OpenApiMediaType(OpenApiMediaType mediaType) + public OpenApiMediaType(OpenApiMediaType? mediaType) { Schema = mediaType?.Schema != null ? new(mediaType?.Schema) : null; Example = OpenApiAnyCloneHelper.CloneFromCopyConstructor(mediaType?.Example); diff --git a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs index 360cfe7c1..4765e929d 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiOperation.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiOperation.cs @@ -7,6 +7,8 @@ using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Writers; +#nullable enable + namespace Microsoft.OpenApi.Models { /// @@ -23,30 +25,30 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// A list of tags for API documentation control. /// Tags can be used for logical grouping of operations by resources or any other qualifier. /// - public IList Tags { get; set; } = new List(); + public IList? Tags { get; set; } = new List(); /// /// A short summary of what the operation does. /// - public string Summary { get; set; } + public string? Summary { get; set; } /// /// A verbose explanation of the operation behavior. /// CommonMark syntax MAY be used for rich text representation. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Additional external documentation for this operation. /// - public OpenApiExternalDocs ExternalDocs { get; set; } + public OpenApiExternalDocs? ExternalDocs { get; set; } /// /// Unique string used to identify the operation. The id MUST be unique among all operations described in the API. /// Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, /// it is RECOMMENDED to follow common programming naming conventions. /// - public string OperationId { get; set; } + public string? OperationId { get; set; } /// /// A list of parameters that are applicable for this operation. @@ -54,7 +56,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// The list MUST NOT include duplicated parameters. A unique parameter is defined by a combination of a name and location. /// The list can use the Reference Object to link to parameters that are defined at the OpenAPI Object's components/parameters. /// - public IList Parameters { get; set; } = new List(); + public IList? Parameters { get; set; } = new List(); /// /// The request body applicable for this operation. @@ -62,12 +64,12 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// has explicitly defined semantics for request bodies. /// In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers. /// - public OpenApiRequestBody RequestBody { get; set; } + public OpenApiRequestBody? RequestBody { get; set; } /// /// REQUIRED. The list of possible responses as they are returned from executing this operation. /// - public OpenApiResponses Responses { get; set; } = new(); + public OpenApiResponses? Responses { get; set; } = new(); /// /// A map of possible out-of band callbacks related to the parent operation. @@ -77,7 +79,7 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// The key value used to identify the callback object is an expression, evaluated at runtime, /// that identifies a URL to use for the callback operation. /// - public IDictionary Callbacks { get; set; } = new Dictionary(); + public IDictionary? Callbacks { get; set; } = new Dictionary(); /// /// Declares this operation to be deprecated. Consumers SHOULD refrain from usage of the declared operation. @@ -91,19 +93,19 @@ public class OpenApiOperation : IOpenApiSerializable, IOpenApiExtensible /// This definition overrides any declared top-level security. /// To remove a top-level security declaration, an empty array can be used. /// - public IList Security { get; set; } = new List(); + public IList? Security { get; set; } = new List(); /// /// An alternative server array to service this operation. /// If an alternative server object is specified at the Path Item Object or Root level, /// it will be overridden by this value. /// - public IList Servers { get; set; } = new List(); + public IList? Servers { get; set; } = new List(); /// /// This object MAY be extended with Specification Extensions. /// - public IDictionary Extensions { get; set; } = new Dictionary(); + public IDictionary? Extensions { get; set; } = new Dictionary(); /// /// Parameterless constructor @@ -113,9 +115,9 @@ public OpenApiOperation() {} /// /// Initializes a copy of an object /// - public OpenApiOperation(OpenApiOperation operation) + public OpenApiOperation(OpenApiOperation? operation) { - Tags = operation?.Tags != null ? new List(operation?.Tags) : null; + Tags = operation?.Tags != null ? new List(operation.Tags) : null; Summary = operation?.Summary ?? Summary; Description = operation?.Description ?? Description; ExternalDocs = operation?.ExternalDocs != null ? new(operation?.ExternalDocs) : null; diff --git a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs index 446663f6b..6a328d68f 100644 --- a/src/Microsoft.OpenApi/Services/OpenApiWalker.cs +++ b/src/Microsoft.OpenApi/Services/OpenApiWalker.cs @@ -87,11 +87,11 @@ internal void Walk(OpenApiExternalDocs externalDocs) _visitor.Visit(externalDocs); } - +#nullable enable /// /// Visits and child objects /// - internal void Walk(OpenApiComponents components) + internal void Walk(OpenApiComponents? components) { if (components == null) { @@ -207,6 +207,8 @@ internal void Walk(OpenApiComponents components) Walk(components as IOpenApiExtensible); } +#nullable restore + /// /// Visits and child objects /// diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs index 7b85dd680..616b156e1 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs @@ -125,6 +125,7 @@ public static void WriteProperty(this IOpenApiWriter writer, string name, T v writer.WriteValue(value); } +#nullable enable /// /// Write the optional Open API object/element. /// @@ -136,7 +137,7 @@ public static void WriteProperty(this IOpenApiWriter writer, string name, T v public static void WriteOptionalObject( this IOpenApiWriter writer, string name, - T value, + T? value, Action action) where T : IOpenApiElement { @@ -162,7 +163,7 @@ public static void WriteOptionalObject( public static void WriteRequiredObject( this IOpenApiWriter writer, string name, - T value, + T? value, Action action) where T : IOpenApiElement { @@ -180,6 +181,7 @@ public static void WriteRequiredObject( } } +#nullable restore /// /// Write the optional of collection string. /// diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index a5bf74219..f375f2cc3 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -57,19 +57,19 @@ public void RemoveAnyOfAndOneOfFromSchema() var walker = new OpenApiWalker(powerShellFormatter); walker.Walk(openApiDocument); - var testSchema = openApiDocument.Components.Schemas["TestSchema"]; - var averageAudioDegradationProperty = testSchema.Properties["averageAudioDegradation"]; - var defaultPriceProperty = testSchema.Properties["defaultPrice"]; + var testSchema = openApiDocument.Components?.Schemas?["TestSchema"]; + var averageAudioDegradationProperty = testSchema?.Properties["averageAudioDegradation"]; + var defaultPriceProperty = testSchema?.Properties["defaultPrice"]; // Assert - Assert.Null(averageAudioDegradationProperty.AnyOf); - Assert.Equal("number", averageAudioDegradationProperty.Type); - Assert.Equal("float", averageAudioDegradationProperty.Format); - Assert.True(averageAudioDegradationProperty.Nullable); - Assert.Null(defaultPriceProperty.OneOf); - Assert.Equal("number", defaultPriceProperty.Type); - Assert.Equal("double", defaultPriceProperty.Format); - Assert.NotNull(testSchema.AdditionalProperties); + Assert.Null(averageAudioDegradationProperty?.AnyOf); + Assert.Equal("number", averageAudioDegradationProperty?.Type); + Assert.Equal("float", averageAudioDegradationProperty?.Format); + Assert.True(averageAudioDegradationProperty?.Nullable); + Assert.Null(defaultPriceProperty?.OneOf); + Assert.Equal("number", defaultPriceProperty?.Type); + Assert.Equal("double", defaultPriceProperty?.Format); + Assert.NotNull(testSchema?.AdditionalProperties); } [Fact] @@ -83,7 +83,7 @@ public void ResolveFunctionParameters() var walker = new OpenApiWalker(powerShellFormatter); walker.Walk(openApiDocument); - var idsParameter = openApiDocument.Paths["/foo"].Operations[OperationType.Get].Parameters.Where(static p => p.Name == "ids").FirstOrDefault(); + var idsParameter = openApiDocument.Paths?["/foo"].Operations[OperationType.Get].Parameters?.Where(static p => p.Name == "ids").FirstOrDefault(); // Assert Assert.Null(idsParameter?.Content); diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs index 5fb1b15f9..02e6cedb0 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiFilterServiceTests.cs @@ -43,6 +43,7 @@ public void ReturnFilteredOpenApiDocumentBasedOnOperationIdsAndTags(string? oper // Assert Assert.NotNull(subsetOpenApiDocument); + Assert.NotNull(subsetOpenApiDocument.Paths); Assert.NotEmpty(subsetOpenApiDocument.Paths); Assert.Equal(expectedPathCount, subsetOpenApiDocument.Paths.Count); } @@ -62,6 +63,7 @@ public void ReturnFilteredOpenApiDocumentBasedOnPostmanCollection() // Assert Assert.NotNull(subsetOpenApiDocument); + Assert.NotNull(subsetOpenApiDocument.Paths); Assert.NotEmpty(subsetOpenApiDocument.Paths); Assert.Equal(3, subsetOpenApiDocument.Paths.Count); } @@ -150,10 +152,11 @@ public void ContinueProcessingWhenUrlsInCollectionAreMissingFromSourceDocument() var pathCount = requestUrls.Count; var predicate = OpenApiFilterService.CreatePredicate(requestUrls: requestUrls, source: _openApiDocumentMock); var subsetOpenApiDocument = OpenApiFilterService.CreateFilteredDocument(_openApiDocumentMock, predicate); - var subsetPathCount = subsetOpenApiDocument.Paths.Count; + var subsetPathCount = subsetOpenApiDocument.Paths?.Count; // Assert Assert.NotNull(subsetOpenApiDocument); + Assert.NotNull(subsetOpenApiDocument.Paths); Assert.NotEmpty(subsetOpenApiDocument.Paths); Assert.Equal(2, subsetPathCount); Assert.NotEqual(pathCount, subsetPathCount); @@ -180,6 +183,7 @@ public void ReturnsPathParametersOnSlicingBasedOnOperationIdsOrTags(string? oper var subsetOpenApiDocument = OpenApiFilterService.CreateFilteredDocument(_openApiDocumentMock, predicate); // Assert + Assert.NotNull(subsetOpenApiDocument.Paths); foreach (var pathItem in subsetOpenApiDocument.Paths) { Assert.True(pathItem.Value.Parameters.Any()); diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiServiceTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiServiceTests.cs index 7314da8ab..544aa7df1 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiServiceTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Services/OpenApiServiceTests.cs @@ -39,6 +39,7 @@ public async Task ReturnConvertedCSDLFile() // Assert Assert.NotNull(openApiDoc); + Assert.NotNull(openApiDoc.Paths); Assert.NotEmpty(openApiDoc.Paths); Assert.Equal(expectedPathCount, openApiDoc.Paths.Count); } @@ -61,6 +62,7 @@ public async Task ReturnFilteredOpenApiDocBasedOnOperationIdsAndInputCsdlDocumen // Assert Assert.NotNull(subsetOpenApiDocument); + Assert.NotNull(subsetOpenApiDocument.Paths); Assert.NotEmpty(subsetOpenApiDocument.Paths); Assert.Equal(expectedPathCount, subsetOpenApiDocument.Paths.Count); } diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 37f40bb11..d0d179ebb 100755 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -426,17 +426,17 @@ namespace Microsoft.OpenApi.Models public class OpenApiComponents : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiComponents() { } - public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents components) { } - public System.Collections.Generic.IDictionary Callbacks { get; set; } - public System.Collections.Generic.IDictionary Examples { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public System.Collections.Generic.IDictionary Headers { get; set; } - public System.Collections.Generic.IDictionary Links { get; set; } - public System.Collections.Generic.IDictionary Parameters { get; set; } - public System.Collections.Generic.IDictionary RequestBodies { get; set; } - public System.Collections.Generic.IDictionary Responses { get; set; } - public System.Collections.Generic.IDictionary Schemas { get; set; } - public System.Collections.Generic.IDictionary SecuritySchemes { get; set; } + public OpenApiComponents(Microsoft.OpenApi.Models.OpenApiComponents? components) { } + public System.Collections.Generic.IDictionary? Callbacks { get; set; } + public System.Collections.Generic.IDictionary? Examples { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public System.Collections.Generic.IDictionary? Headers { get; set; } + public System.Collections.Generic.IDictionary? Links { get; set; } + public System.Collections.Generic.IDictionary? Parameters { get; set; } + public System.Collections.Generic.IDictionary? RequestBodies { get; set; } + public System.Collections.Generic.IDictionary? Responses { get; set; } + public System.Collections.Generic.IDictionary? Schemas { get; set; } + public System.Collections.Generic.IDictionary? SecuritySchemes { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } @@ -592,18 +592,18 @@ namespace Microsoft.OpenApi.Models public class OpenApiDocument : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiDocument() { } - public OpenApiDocument(Microsoft.OpenApi.Models.OpenApiDocument document) { } - public Microsoft.OpenApi.Models.OpenApiComponents Components { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } + public OpenApiDocument(Microsoft.OpenApi.Models.OpenApiDocument? document) { } + public Microsoft.OpenApi.Models.OpenApiComponents? Components { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs? ExternalDocs { get; set; } public string HashCode { get; } - public Microsoft.OpenApi.Models.OpenApiInfo Info { get; set; } - public Microsoft.OpenApi.Models.OpenApiPaths Paths { get; set; } - public System.Collections.Generic.IList SecurityRequirements { get; set; } - public System.Collections.Generic.IList Servers { get; set; } - public System.Collections.Generic.IList Tags { get; set; } - public Microsoft.OpenApi.Services.OpenApiWorkspace Workspace { get; set; } - public Microsoft.OpenApi.Interfaces.IOpenApiReferenceable ResolveReference(Microsoft.OpenApi.Models.OpenApiReference reference) { } + public Microsoft.OpenApi.Models.OpenApiInfo? Info { get; set; } + public Microsoft.OpenApi.Models.OpenApiPaths? Paths { get; set; } + public System.Collections.Generic.IList? SecurityRequirements { get; set; } + public System.Collections.Generic.IList? Servers { get; set; } + public System.Collections.Generic.IList? Tags { get; set; } + public Microsoft.OpenApi.Services.OpenApiWorkspace? Workspace { get; set; } + public Microsoft.OpenApi.Interfaces.IOpenApiReferenceable? ResolveReference(Microsoft.OpenApi.Models.OpenApiReference reference) { } public System.Collections.Generic.IEnumerable ResolveReferences() { } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } @@ -738,12 +738,12 @@ namespace Microsoft.OpenApi.Models public class OpenApiMediaType : Microsoft.OpenApi.Interfaces.IOpenApiElement, Microsoft.OpenApi.Interfaces.IOpenApiExtensible, Microsoft.OpenApi.Interfaces.IOpenApiSerializable { public OpenApiMediaType() { } - public OpenApiMediaType(Microsoft.OpenApi.Models.OpenApiMediaType mediaType) { } - public System.Collections.Generic.IDictionary Encoding { get; set; } - public Microsoft.OpenApi.Any.IOpenApiAny Example { get; set; } - public System.Collections.Generic.IDictionary Examples { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public Microsoft.OpenApi.Models.OpenApiSchema Schema { get; set; } + public OpenApiMediaType(Microsoft.OpenApi.Models.OpenApiMediaType? mediaType) { } + public System.Collections.Generic.IDictionary? Encoding { get; set; } + public Microsoft.OpenApi.Any.IOpenApiAny? Example { get; set; } + public System.Collections.Generic.IDictionary? Examples { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiSchema? Schema { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } @@ -775,20 +775,20 @@ namespace Microsoft.OpenApi.Models { public const bool DeprecatedDefault = false; public OpenApiOperation() { } - public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation operation) { } - public System.Collections.Generic.IDictionary Callbacks { get; set; } + public OpenApiOperation(Microsoft.OpenApi.Models.OpenApiOperation? operation) { } + public System.Collections.Generic.IDictionary? Callbacks { get; set; } public bool Deprecated { get; set; } - public string Description { get; set; } - public System.Collections.Generic.IDictionary Extensions { get; set; } - public Microsoft.OpenApi.Models.OpenApiExternalDocs ExternalDocs { get; set; } - public string OperationId { get; set; } - public System.Collections.Generic.IList Parameters { get; set; } - public Microsoft.OpenApi.Models.OpenApiRequestBody RequestBody { get; set; } - public Microsoft.OpenApi.Models.OpenApiResponses Responses { get; set; } - public System.Collections.Generic.IList Security { get; set; } - public System.Collections.Generic.IList Servers { get; set; } - public string Summary { get; set; } - public System.Collections.Generic.IList Tags { get; set; } + public string? Description { get; set; } + public System.Collections.Generic.IDictionary? Extensions { get; set; } + public Microsoft.OpenApi.Models.OpenApiExternalDocs? ExternalDocs { get; set; } + public string? OperationId { get; set; } + public System.Collections.Generic.IList? Parameters { get; set; } + public Microsoft.OpenApi.Models.OpenApiRequestBody? RequestBody { get; set; } + public Microsoft.OpenApi.Models.OpenApiResponses? Responses { get; set; } + public System.Collections.Generic.IList? Security { get; set; } + public System.Collections.Generic.IList? Servers { get; set; } + public string? Summary { get; set; } + public System.Collections.Generic.IList? Tags { get; set; } public void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } public void SerializeAsV3(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { } } @@ -1575,7 +1575,7 @@ namespace Microsoft.OpenApi.Writers where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } - public static void WriteOptionalObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T value, System.Action action) + public static void WriteOptionalObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T? value, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, string value) { } public static void WriteProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, bool value, bool defaultValue = false) { } @@ -1589,7 +1589,7 @@ namespace Microsoft.OpenApi.Writers public static void WriteRequiredMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { } public static void WriteRequiredMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } - public static void WriteRequiredObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T value, System.Action action) + public static void WriteRequiredObject(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, T? value, System.Action action) where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { } public static void WriteRequiredProperty(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, string value) { } }