Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal static partial class OpenApiV3Deserializer
private static readonly PatternFieldMap<OpenApiCallback> _callbackPatternFields =
new PatternFieldMap<OpenApiCallback>
{
{s => s.StartsWith("$"), (o, p, n) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n))},
{s => !s.StartsWith("x-"), (o, p, n) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n))},
{s => s.StartsWith("x-"), (o, p, n) => o.AddExtension(p, LoadExtension(p,n))},
};

Expand Down
6 changes: 2 additions & 4 deletions src/Microsoft.OpenApi/Expressions/CompositeExpression.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Microsoft.OpenApi.Expressions
{
Expand All @@ -16,7 +13,8 @@ namespace Microsoft.OpenApi.Expressions
public class CompositeExpression : RuntimeExpression
{
private readonly string template;
private Regex expressionPattern = new Regex("{(?<exp>[^}]+)");
private Regex expressionPattern = new Regex(@"{(?<exp>\$[^}]*)");

/// <summary>
/// Expressions embedded into string literal
/// </summary>
Expand Down
7 changes: 1 addition & 6 deletions src/Microsoft.OpenApi/Expressions/MethodExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,10 @@ public sealed class MethodExpression : RuntimeExpression
/// </summary>
public override string Expression { get; } = Method;

/// <summary>
/// Gets the singleton.
/// </summary>
public static MethodExpression Instance = new MethodExpression();

/// <summary>
/// Private constructor.
/// </summary>
private MethodExpression()
public MethodExpression()
{
}
}
Expand Down
17 changes: 6 additions & 11 deletions src/Microsoft.OpenApi/Expressions/RuntimeExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,27 @@ public static RuntimeExpression Build(string expression)
throw Error.ArgumentNullOrWhiteSpace(nameof(expression));
}

if (expression.Contains("{$"))
if ( !expression.StartsWith( Prefix ) )
{
return new CompositeExpression(expression);
}

if (!expression.StartsWith(Prefix))
{
throw new OpenApiException(string.Format(SRResource.RuntimeExpressionMustBeginWithDollar, expression));
return new CompositeExpression( expression );
}

// $url
if (expression == UrlExpression.Url)
{
return UrlExpression.Instance;
return new UrlExpression();
}

// $method
if (expression == MethodExpression.Method)
{
return MethodExpression.Instance;
return new MethodExpression();
}

// $statusCode
if (expression == StatusCodeExpression.StatusCode)
{
return StatusCodeExpression.Instance;
return new StatusCodeExpression();
}

// $request.
Expand All @@ -78,7 +73,7 @@ public static RuntimeExpression Build(string expression)
return new ResponseExpression(source);
}

throw new OpenApiException(string.Format(SRResource.RuntimeExpressionHasInvalidFormat, expression));
throw new OpenApiException( string.Format( SRResource.RuntimeExpressionHasInvalidFormat, expression ) );
}

/// <summary>
Expand Down
7 changes: 1 addition & 6 deletions src/Microsoft.OpenApi/Expressions/StatusCodeExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,10 @@ public sealed class StatusCodeExpression : RuntimeExpression
/// </summary>
public override string Expression { get; } = StatusCode;

/// <summary>
/// Gets the singleton.
/// </summary>
public static StatusCodeExpression Instance = new StatusCodeExpression();

/// <summary>
/// Private constructor.
/// </summary>
private StatusCodeExpression()
public StatusCodeExpression()
{
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/Microsoft.OpenApi/Expressions/UrlExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,10 @@ public sealed class UrlExpression : RuntimeExpression
/// </summary>
public override string Expression { get; } = Url;

/// <summary>
/// Gets the singleton.
/// </summary>
public static UrlExpression Instance = new UrlExpression();

/// <summary>
/// Private constructor.
/// </summary>
private UrlExpression()
public UrlExpression()
{
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\src\Microsoft.OpenApi.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<None Remove="V3Tests\Samples\OpenApiDocument\securedApi.yaml" />
<None Remove="V3Tests\Samples\OpenApiOperation\securedOperation.yaml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="OpenApiReaderTests\Samples\unsupported.v1.yaml">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
Expand Down Expand Up @@ -74,6 +70,9 @@
<EmbeddedResource Include="V2Tests\Samples\OpenApiSecurityScheme\oauth2PasswordSecurityScheme.yaml">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="V3Tests\Samples\OpenApiCallback\multipleCallbacksWithReference.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="V3Tests\Samples\OpenApiCallback\basicCallback.yaml">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
Expand Down Expand Up @@ -161,9 +160,9 @@
</PackageReference>
<PackageReference Include="SharpYaml" Version="1.6.1">
</PackageReference>
<PackageReference Include="xunit" Version="2.3.0">
<PackageReference Include="xunit" Version="2.3.1">
</PackageReference>
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0">
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1">
</PackageReference>
</ItemGroup>

Expand Down Expand Up @@ -205,7 +204,7 @@
<EmbeddedResource Include="V2Tests\Samples\OpenApiSecurityScheme\oauth2ImplicitSecurityScheme.yaml">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="V3Tests\Samples\OpenApiCallback\advancedCallbackWithReference.yaml">
<EmbeddedResource Include="V3Tests\Samples\OpenApiCallback\callbackWithReference.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="V3Tests\Samples\OpenApiInfo\advancedInfo.yaml">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void ParseBodyParameterShouldSucceed()
// Assert
// Body parameter is currently not translated via LoadParameter.
// This design may be revisited and this unit test may likely change.
parameter.ShouldBeEquivalentTo(null);
parameter.Should().BeNull();
}

[Fact]
Expand Down Expand Up @@ -114,7 +114,7 @@ public void ParseFormDataParameterShouldSucceed()
// Assert
// Form data parameter is currently not translated via LoadParameter.
// This design may be revisited and this unit test may likely change.
parameter.ShouldBeEquivalentTo(null);
parameter.Should().BeNull();
}

[Fact]
Expand Down
141 changes: 139 additions & 2 deletions test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiCallbackTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ public void ParseBasicCallbackShouldSucceed()
}

[Fact]
public void ParseAdvancedCallbackWithReferenceShouldSucceed()
public void ParseCallbackWithReferenceShouldSucceed()
{
using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "advancedCallbackWithReference.yaml")))
using (var stream = Resources.GetStream(Path.Combine(SampleFolderPath, "callbackWithReference.yaml")))
{
// Act
var openApiDoc = new OpenApiStreamReader().Read(stream, out var diagnostic);
Expand Down Expand Up @@ -131,5 +131,142 @@ public void ParseAdvancedCallbackWithReferenceShouldSucceed()
});
}
}

[Fact]
public void ParseMultipleCallbacksWithReferenceShouldSucceed()
{
using ( var stream = Resources.GetStream( Path.Combine( SampleFolderPath, "multipleCallbacksWithReference.yaml" ) ) )
{
// Act
var openApiDoc = new OpenApiStreamReader().Read( stream, out var diagnostic );

// Assert
var path = openApiDoc.Paths.First().Value;
var subscribeOperation = path.Operations[OperationType.Post];

diagnostic.ShouldBeEquivalentTo(
new OpenApiDiagnostic() { SpecificationVersion = OpenApiSpecVersion.OpenApi3_0 } );

var callback1 = subscribeOperation.Callbacks["simpleHook"];

callback1.ShouldBeEquivalentTo(
new OpenApiCallback
{
PathItems =
{
[RuntimeExpression.Build("$request.body#/url")]= new OpenApiPathItem {
Operations = {
[OperationType.Post] = new OpenApiOperation()
{
RequestBody = new OpenApiRequestBody
{
Content =
{
["application/json"] = new OpenApiMediaType
{
Schema = new OpenApiSchema()
{
Type = "object"
}
}
}
},
Responses = {
["200"]= new OpenApiResponse
{
Description = "Success"
}
}
}
}
}
},
Reference = new OpenApiReference
{
Type = ReferenceType.Callback,
Id = "simpleHook",
}
} );

var callback2 = subscribeOperation.Callbacks["callback2"];
callback2.ShouldBeEquivalentTo(
new OpenApiCallback
{
PathItems =
{
[RuntimeExpression.Build("/simplePath")]= new OpenApiPathItem {
Operations = {
[OperationType.Post] = new OpenApiOperation()
{
RequestBody = new OpenApiRequestBody
{
Description = "Callback 2",
Content =
{
["application/json"] = new OpenApiMediaType
{
Schema = new OpenApiSchema()
{
Type = "string"
}
}
}
},
Responses = {
["400"]= new OpenApiResponse
{
Description = "Callback Response"
}
}
}
},
}
}
} );

var callback3 = subscribeOperation.Callbacks["callback3"];
callback3.ShouldBeEquivalentTo(
new OpenApiCallback
{
PathItems =
{
[RuntimeExpression.Build(@"http://example.com?transactionId={$request.body#/id}&email={$request.body#/email}")] = new OpenApiPathItem {
Operations = {
[OperationType.Post] = new OpenApiOperation()
{
RequestBody = new OpenApiRequestBody
{
Content =
{
["application/xml"] = new OpenApiMediaType
{
Schema = new OpenApiSchema()
{
Type = "object"
}
}
}
},
Responses = {
["200"]= new OpenApiResponse
{
Description = "Success"
},
["401"]= new OpenApiResponse
{
Description = "Unauthorized"
},
["404"]= new OpenApiResponse
{
Description = "Not Found"
}
}
}
}
}
}
} );
}
}
}
}
Loading