Skip to content

Commit 791e286

Browse files
committed
Added specialized error classes
1 parent 7c7a32a commit 791e286

File tree

11 files changed

+126
-75
lines changed

11 files changed

+126
-75
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.OpenApi.Exceptions;
10+
using Microsoft.OpenApi.Models;
11+
using SharpYaml;
12+
13+
namespace Microsoft.OpenApi.Readers
14+
{
15+
/// <summary>
16+
/// Error detected during the reading of some input and converting to an OpenApiDocument
17+
/// </summary>
18+
public class OpenApiReaderError : OpenApiError
19+
{
20+
21+
/// <summary>
22+
/// Creates error object from thrown exception
23+
/// </summary>
24+
/// <param name="exception"></param>
25+
public OpenApiReaderError(OpenApiException exception) : base(exception)
26+
{
27+
28+
}
29+
30+
/// <summary>
31+
/// Create error object from YAML SyntaxErrorException
32+
/// </summary>
33+
/// <param name="exception"></param>
34+
public OpenApiReaderError(SyntaxErrorException exception) : base(String.Empty, exception.Message)
35+
{
36+
37+
}
38+
}
39+
}

src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
5050
}
5151
catch (SyntaxErrorException ex)
5252
{
53-
diagnostic.Errors.Add(new OpenApiError(string.Empty, ex.Message));
53+
diagnostic.Errors.Add(new OpenApiReaderError(ex));
5454
return new OpenApiDocument();
5555
}
5656

@@ -83,7 +83,6 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
8383
case ReferenceResolutionSetting.DoNotResolveReferences:
8484
break;
8585
}
86-
8786
}
8887
catch (OpenApiException ex)
8988
{

src/Microsoft.OpenApi.Readers/ParseNodes/ParseNode.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ protected ParseNode(ParsingContext parsingContext, OpenApiDiagnostic diagnostic)
2424

2525
public OpenApiDiagnostic Diagnostic { get; }
2626

27-
public string DomainType { get; internal set; }
28-
2927
public MapNode CheckMapNode(string nodeName)
3028
{
3129
var mapNode = this as MapNode;
@@ -37,17 +35,6 @@ public MapNode CheckMapNode(string nodeName)
3735
return mapNode;
3836
}
3937

40-
internal string CheckRegex(string value, Regex versionRegex, string defaultValue)
41-
{
42-
if (!versionRegex.IsMatch(value))
43-
{
44-
Diagnostic.Errors.Add(new OpenApiError("", "Value does not match regex: " + versionRegex));
45-
return defaultValue;
46-
}
47-
48-
return value;
49-
}
50-
5138
public static ParseNode Create(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode node)
5239
{
5340
var listNode = node as YamlSequenceNode;

src/Microsoft.OpenApi.Readers/ParseNodes/PropertyNode.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public void ParseField<T>(
4343
catch (OpenApiException ex)
4444
{
4545
ex.Pointer = Context.GetLocation();
46-
Diagnostic.Errors.Add(new OpenApiError(ex));
46+
Diagnostic.Errors.Add(new OpenApiReaderError(ex));
4747
}
4848
finally
4949
{
@@ -63,7 +63,7 @@ public void ParseField<T>(
6363
catch (OpenApiException ex)
6464
{
6565
ex.Pointer = Context.GetLocation();
66-
Diagnostic.Errors.Add(new OpenApiError(ex));
66+
Diagnostic.Errors.Add(new OpenApiReaderError(ex));
6767
}
6868
finally
6969
{

src/Microsoft.OpenApi/Models/OpenApiError.cs

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,11 @@
55

66
namespace Microsoft.OpenApi.Models
77
{
8-
/// <summary>
9-
/// Error reason.
10-
/// </summary>
11-
public enum ErrorReason
12-
{
13-
/// <summary>
14-
/// Field is required.
15-
/// </summary>
16-
Required,
17-
18-
/// <summary>
19-
/// Format error.
20-
/// </summary>
21-
Format,
22-
23-
/// <summary>
24-
/// Duplicate Key error.
25-
/// </summary>
26-
DuplicateKey
27-
28-
}
29-
308
/// <summary>
319
/// Error related to the Open API Document.
3210
/// </summary>
3311
public class OpenApiError
3412
{
35-
3613
/// <summary>
3714
/// Initializes the <see cref="OpenApiError"/> class using the message and pointer from the given exception.
3815
/// </summary>
@@ -51,20 +28,6 @@ public OpenApiError(string pointer, string message)
5128
Message = message;
5229
}
5330

54-
/// <summary>
55-
/// Initializes the <see cref="OpenApiError"/> class.
56-
/// </summary>
57-
public OpenApiError(ErrorReason reason, string pointer, string message)
58-
{
59-
Pointer = pointer;
60-
Message = message;
61-
}
62-
63-
/// <summary>
64-
/// Classified Reason for the error.
65-
/// </summary>
66-
public ErrorReason ReasonClass { get; set; }
67-
6831
/// <summary>
6932
/// Message explaining the error.
7033
/// </summary>
@@ -75,11 +38,6 @@ public OpenApiError(ErrorReason reason, string pointer, string message)
7538
/// </summary>
7639
public string Pointer { get; set; }
7740

78-
/// <summary>
79-
/// Name of rule that detected the error.
80-
/// </summary>
81-
public string RuleName { get; set; }
82-
8341
/// <summary>
8442
/// Gets the string representation of <see cref="OpenApiError"/>.
8543
/// </summary>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.OpenApi.Models;
10+
11+
namespace Microsoft.OpenApi.Validations
12+
{
13+
/// <summary>
14+
/// Error reason.
15+
/// </summary>
16+
public enum ErrorReason
17+
{
18+
/// <summary>
19+
/// Field is required.
20+
/// </summary>
21+
Required,
22+
23+
/// <summary>
24+
/// Format error.
25+
/// </summary>
26+
Format,
27+
28+
/// <summary>
29+
/// Duplicate Key error.
30+
/// </summary>
31+
DuplicateKey
32+
33+
}
34+
35+
/// <summary>
36+
/// Errors detected when validating a OpenAPI Element
37+
/// </summary>
38+
public class OpenApiValidationError : OpenApiError
39+
{
40+
/// <summary>
41+
/// Initializes the <see cref="OpenApiError"/> class.
42+
/// </summary>
43+
public OpenApiValidationError(ErrorReason reason, string pointer, string message) : base(pointer, message)
44+
{
45+
Pointer = pointer;
46+
Message = message;
47+
ReasonClass = reason;
48+
}
49+
50+
/// <summary>
51+
/// Initializes the <see cref="OpenApiError"/> class.
52+
/// </summary>
53+
public OpenApiValidationError(string ruleName, string pointer, string message) : base(pointer, message)
54+
{
55+
Pointer = pointer;
56+
Message = message;
57+
RuleName = ruleName;
58+
}
59+
60+
/// <summary>
61+
/// Classified Reason for the error.
62+
/// </summary>
63+
public ErrorReason ReasonClass { get; set; }
64+
65+
/// <summary>
66+
/// Name of rule that detected the error.
67+
/// </summary>
68+
public string RuleName { get; set; }
69+
70+
}
71+
}

src/Microsoft.OpenApi/Validations/Rules/OpenApiResponsesRules.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,11 @@ public static class OpenApiResponsesRules
4040

4141
if (key != "default" && !Regex.IsMatch(key, "^[1-5]([0-9][0-9]|XX)$"))
4242
{
43-
context.AddError(
44-
new OpenApiError(
45-
ErrorReason.Format,
46-
context.PathString,
43+
context.CreateError(nameof(ResponsesMustBeIdentifiedByDefaultOrStatusCode), ErrorReason.Format,
44+
4745
"Responses key must be 'default', an HTTP status code, " +
4846
"or one of the following strings representing a range of HTTP status codes: " +
49-
"'1XX', '2XX', '3XX', '4XX', '5XX'"));
47+
"'1XX', '2XX', '3XX', '4XX', '5XX'");
5048
}
5149

5250
context.Exit();

src/Microsoft.OpenApi/Validations/ValidationExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ namespace Microsoft.OpenApi.Validations
1313
/// <summary>
1414
/// Helper methods to simplify creating validation rules
1515
/// </summary>
16-
public static class ValidationExtensions
16+
public static class ValidationContextExtensions
1717
{
1818
/// <summary>
1919
/// Helper method to simplify validation rules
2020
/// </summary>
2121
public static void CreateError(this IValidationContext context, string ruleName, ErrorReason reason, string message)
2222
{
23-
OpenApiError error = new OpenApiError(reason, context.PathString,message);
23+
OpenApiValidationError error = new OpenApiValidationError(reason, context.PathString, message);
2424
error.RuleName = ruleName;
2525
context.AddError(error);
2626
}

test/Microsoft.OpenApi.Readers.Tests/V3Tests/OpenApiDocumentTests.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
using System.Linq;
88
using FluentAssertions;
99
using Microsoft.OpenApi.Models;
10+
using Microsoft.OpenApi.Validations;
11+
using Microsoft.OpenApi.Validations.Rules;
1012
using Newtonsoft.Json;
1113
using Xunit;
1214
using Xunit.Abstractions;
@@ -107,10 +109,7 @@ public void ParseBrokenMinimalDocumentShouldYieldExpectedDiagnostic()
107109
{
108110
Errors =
109111
{
110-
new OpenApiError("#/info/title", "The field 'title' in 'info' object is REQUIRED.")
111-
{
112-
RuleName = "InfoRequiredFields"
113-
}
112+
new OpenApiValidationError(nameof(OpenApiInfoRules.InfoRequiredFields),"#/info/title", "The field 'title' in 'info' object is REQUIRED.")
114113
},
115114
SpecificationVersion = OpenApiSpecVersion.OpenApi3_0
116115
});

test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void ResponseMustHaveADescription()
5757
validator.Errors.ShouldBeEquivalentTo(
5858
new List<OpenApiError>
5959
{
60-
new OpenApiError(ErrorReason.Required, "#/paths/~1test/get/responses/200/description",
60+
new OpenApiValidationError(ErrorReason.Required, "#/paths/~1test/get/responses/200/description",
6161
String.Format(SRResource.Validation_FieldIsRequired, "description", "response"))
6262
{
6363
RuleName = "ResponseRequiredFields"
@@ -92,7 +92,7 @@ public void ServersShouldBeReferencedByIndex()
9292
validator.Errors.ShouldBeEquivalentTo(
9393
new List<OpenApiError>
9494
{
95-
new OpenApiError(ErrorReason.Required, "#/servers/1/url",
95+
new OpenApiValidationError(ErrorReason.Required, "#/servers/1/url",
9696
String.Format(SRResource.Validation_FieldIsRequired, "url", "server"))
9797
{
9898
RuleName = "ServerRequiredFields"
@@ -112,7 +112,7 @@ public void ValidateCustomExtension()
112112
{
113113
if (item.Bar == "hey")
114114
{
115-
context.AddError(new OpenApiError(ErrorReason.Format, context.PathString, "Don't say hey"));
115+
context.AddError(new OpenApiValidationError(ErrorReason.Format, context.PathString, "Don't say hey"));
116116
}
117117
}));
118118

@@ -138,7 +138,7 @@ public void ValidateCustomExtension()
138138
validator.Errors.ShouldBeEquivalentTo(
139139
new List<OpenApiError>
140140
{
141-
new OpenApiError(ErrorReason.Format, "#/info/x-foo", "Don't say hey")
141+
new OpenApiValidationError(ErrorReason.Format, "#/info/x-foo", "Don't say hey")
142142
});
143143
}
144144

0 commit comments

Comments
 (0)