Skip to content

Commit 9424e24

Browse files
authored
Merge pull request #276 from Microsoft/dm/vnext/fix272
Fixes to syntax related reading errors
2 parents 0fb9f1d + f3c693a commit 9424e24

File tree

11 files changed

+97
-81
lines changed

11 files changed

+97
-81
lines changed

src/Microsoft.OpenApi.Readers/Exceptions/OpenApiReaderException.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
// Licensed under the MIT license.
33

44
using System;
5+
using Microsoft.OpenApi.Exceptions;
6+
using SharpYaml.Serialization;
57

68
namespace Microsoft.OpenApi.Readers.Exceptions
79
{
810
/// <summary>
911
/// Defines an exception indicating OpenAPI Reader encountered an issue while reading.
1012
/// </summary>
1113
[Serializable]
12-
public class OpenApiReaderException : Exception
14+
public class OpenApiReaderException : OpenApiException
1315
{
1416
/// <summary>
1517
/// Initializes the <see cref="OpenApiReaderException"/> class.
@@ -22,6 +24,18 @@ public OpenApiReaderException() { }
2224
/// <param name="message">Plain text error message for this exception.</param>
2325
public OpenApiReaderException(string message) : base(message) { }
2426

27+
/// <summary>
28+
/// Initializes the <see cref="OpenApiReaderException"/> class with a message and line, column location of error.
29+
/// </summary>
30+
/// <param name="message">Plain text error message for this exception.</param>
31+
/// <param name="node">Parsing node where error occured</param>
32+
public OpenApiReaderException(string message, YamlNode node) : base(message)
33+
{
34+
// This only includes line because using a char range causes tests to break due to CR/LF & LF differences
35+
// See https://tools.ietf.org/html/rfc5147 for syntax
36+
Pointer = $"#line={node.Start.Line}";
37+
}
38+
2539
/// <summary>
2640
/// Initializes the <see cref="OpenApiReaderException"/> class with a custom message and inner exception.
2741
/// </summary>

src/Microsoft.OpenApi.Readers/OpenApiReaderError.cs

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/Microsoft.OpenApi.Readers/OpenApiStreamReader.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ public OpenApiDocument Read(Stream input, out OpenApiDiagnostic diagnostic)
4949
{
5050
yamlDocument = LoadYamlDocument(input);
5151
}
52-
catch (SyntaxErrorException ex)
52+
catch (YamlException ex)
5353
{
54-
diagnostic.Errors.Add(new OpenApiReaderError(ex));
54+
diagnostic.Errors.Add(new OpenApiError($"#char={ex.Start.Line}", ex.Message));
5555
return new OpenApiDocument();
5656
}
5757

@@ -122,9 +122,9 @@ public T ReadFragment<T>(Stream input, OpenApiSpecVersion version, out OpenApiDi
122122
{
123123
yamlDocument = LoadYamlDocument(input);
124124
}
125-
catch (SyntaxErrorException ex)
125+
catch (YamlException ex)
126126
{
127-
diagnostic.Errors.Add(new OpenApiReaderError(ex));
127+
diagnostic.Errors.Add(new OpenApiError($"#line={ex.Start.Line}", ex.Message));
128128
return default(T);
129129
}
130130

@@ -158,7 +158,6 @@ public T ReadFragment<T>(Stream input, OpenApiSpecVersion version, out OpenApiDi
158158
return (T)element;
159159
}
160160

161-
162161
/// <summary>
163162
/// Helper method to turn streams into YamlDocument
164163
/// </summary>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public override List<T> CreateSimpleList<T>(Func<ValueNode, T> map)
5252
$"Expected list at line {_nodeList.Start.Line} while parsing {typeof(T).Name}");
5353
}
5454

55-
return _nodeList.Select(n => map(new ValueNode(Context, Diagnostic, (YamlScalarNode)n))).ToList();
55+
return _nodeList.Select(n => map(new ValueNode(Context, Diagnostic, n))).ToList();
5656
}
5757

5858
public IEnumerator<ParseNode> GetEnumerator()

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.OpenApi.Exceptions;
1010
using Microsoft.OpenApi.Interfaces;
1111
using Microsoft.OpenApi.Models;
12+
using Microsoft.OpenApi.Readers.Exceptions;
1213
using SharpYaml.Schemas;
1314
using SharpYaml.Serialization;
1415

@@ -27,16 +28,16 @@ public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, string yaml
2728
{
2829
}
2930

30-
public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlMappingNode node) : base(
31+
public MapNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode node) : base(
3132
context,
3233
diagnostic)
3334
{
34-
if (node == null)
35+
if (!(node is YamlMappingNode mapNode))
3536
{
36-
throw new OpenApiException("Expected map");
37+
throw new OpenApiReaderException("Expected map.", node);
3738
}
3839

39-
this._node = node;
40+
this._node = mapNode;
4041

4142
_nodes = this._node.Children
4243
.Select(kvp => new PropertyNode(Context, Diagnostic, kvp.Key.GetScalarValue(), kvp.Value))

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

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.OpenApi.Exceptions;
99
using Microsoft.OpenApi.Interfaces;
1010
using Microsoft.OpenApi.Models;
11+
using Microsoft.OpenApi.Readers.Exceptions;
1112
using SharpYaml.Serialization;
1213

1314
namespace Microsoft.OpenApi.Readers.ParseNodes
@@ -26,26 +27,23 @@ protected ParseNode(ParsingContext parsingContext, OpenApiDiagnostic diagnostic)
2627

2728
public MapNode CheckMapNode(string nodeName)
2829
{
29-
var mapNode = this as MapNode;
30-
if (mapNode == null)
30+
if (!(this is MapNode mapNode))
3131
{
32-
throw new OpenApiException($"{nodeName} must be a map/object");
32+
throw new OpenApiReaderException($"{nodeName} must be a map/object");
3333
}
3434

3535
return mapNode;
3636
}
3737

3838
public static ParseNode Create(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode node)
3939
{
40-
var listNode = node as YamlSequenceNode;
4140

42-
if (listNode != null)
41+
if (node is YamlSequenceNode listNode)
4342
{
4443
return new ListNode(context, diagnostic, listNode);
4544
}
4645

47-
var mapNode = node as YamlMappingNode;
48-
if (mapNode != null)
46+
if (node is YamlMappingNode mapNode)
4947
{
5048
return new MapNode(context, diagnostic, mapNode);
5149
}
@@ -55,50 +53,50 @@ public static ParseNode Create(ParsingContext context, OpenApiDiagnostic diagnos
5553

5654
public virtual List<T> CreateList<T>(Func<MapNode, T> map)
5755
{
58-
throw new OpenApiException("Cannot create list from this type of node.");
56+
throw new OpenApiReaderException("Cannot create list from this type of node.");
5957
}
6058

6159
public virtual Dictionary<string, T> CreateMap<T>(Func<MapNode, T> map)
6260
{
63-
throw new OpenApiException("Cannot create map from this type of node.");
61+
throw new OpenApiReaderException("Cannot create map from this type of node.");
6462
}
6563

6664
public virtual Dictionary<string, T> CreateMapWithReference<T>(
6765
ReferenceType referenceType,
6866
Func<MapNode, T> map)
6967
where T : class, IOpenApiReferenceable
7068
{
71-
throw new OpenApiException("Cannot create map from this reference.");
69+
throw new OpenApiReaderException("Cannot create map from this reference.");
7270
}
7371

7472
public virtual List<T> CreateSimpleList<T>(Func<ValueNode, T> map)
7573
{
76-
throw new OpenApiException("Cannot create simple list from this type of node.");
74+
throw new OpenApiReaderException("Cannot create simple list from this type of node.");
7775
}
7876

7977
public virtual Dictionary<string, T> CreateSimpleMap<T>(Func<ValueNode, T> map)
8078
{
81-
throw new OpenApiException("Cannot create simple map from this type of node.");
79+
throw new OpenApiReaderException("Cannot create simple map from this type of node.");
8280
}
8381

8482
public virtual IOpenApiAny CreateAny()
8583
{
86-
throw new OpenApiException("Cannot create an Any object this type of node.");
84+
throw new OpenApiReaderException("Cannot create an Any object this type of node.");
8785
}
8886

8987
public virtual string GetRaw()
9088
{
91-
throw new OpenApiException("Cannot get raw value from this type of node.");
89+
throw new OpenApiReaderException("Cannot get raw value from this type of node.");
9290
}
9391

9492
public virtual string GetScalarValue()
9593
{
96-
throw new OpenApiException("Cannot create a scalar value from this type of node.");
94+
throw new OpenApiReaderException("Cannot create a scalar value from this type of node.");
9795
}
9896

9997
public virtual List<IOpenApiAny> CreateListOfAny()
10098
{
101-
throw new OpenApiException("Cannot create a list from this type of node.");
99+
throw new OpenApiReaderException("Cannot create a list from this type of node.");
102100
}
103101

104102
}

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.OpenApi.Any;
88
using Microsoft.OpenApi.Exceptions;
99
using Microsoft.OpenApi.Models;
10+
using Microsoft.OpenApi.Readers.Exceptions;
1011
using SharpYaml.Serialization;
1112

1213
namespace Microsoft.OpenApi.Readers.ParseNodes
@@ -40,10 +41,14 @@ public void ParseField<T>(
4041
Context.StartObject(Name);
4142
fixedFieldMap(parentInstance, Value);
4243
}
44+
catch (OpenApiReaderException ex)
45+
{
46+
Diagnostic.Errors.Add(new OpenApiError(ex));
47+
}
4348
catch (OpenApiException ex)
4449
{
4550
ex.Pointer = Context.GetLocation();
46-
Diagnostic.Errors.Add(new OpenApiReaderError(ex));
51+
Diagnostic.Errors.Add(new OpenApiError(ex));
4752
}
4853
finally
4954
{
@@ -60,10 +65,14 @@ public void ParseField<T>(
6065
Context.StartObject(Name);
6166
map(parentInstance, Name, Value);
6267
}
68+
catch (OpenApiReaderException ex)
69+
{
70+
Diagnostic.Errors.Add(new OpenApiError(ex));
71+
}
6372
catch (OpenApiException ex)
6473
{
6574
ex.Pointer = Context.GetLocation();
66-
Diagnostic.Errors.Add(new OpenApiReaderError(ex));
75+
Diagnostic.Errors.Add(new OpenApiError(ex));
6776
}
6877
finally
6978
{

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using Microsoft.OpenApi.Any;
66
using Microsoft.OpenApi.Exceptions;
7+
using Microsoft.OpenApi.Readers.Exceptions;
78
using SharpYaml.Serialization;
89

910
namespace Microsoft.OpenApi.Readers.ParseNodes
@@ -12,23 +13,20 @@ internal class ValueNode : ParseNode
1213
{
1314
private readonly YamlScalarNode _node;
1415

15-
public ValueNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlScalarNode scalarNode) : base(
16+
public ValueNode(ParsingContext context, OpenApiDiagnostic diagnostic, YamlNode node) : base(
1617
context,
1718
diagnostic)
1819
{
20+
if (!(node is YamlScalarNode scalarNode))
21+
{
22+
throw new OpenApiReaderException("Expected a value.", node);
23+
}
1924
_node = scalarNode;
2025
}
2126

2227
public override string GetScalarValue()
2328
{
24-
var scalarNode = _node;
25-
26-
if (scalarNode == null)
27-
{
28-
throw new OpenApiException($"Expected scalar at line {_node.Start.Line}");
29-
}
30-
31-
return scalarNode.Value;
29+
return _node.Value;
3230
}
3331

3432
/// <summary>

src/Microsoft.OpenApi/Models/OpenApiError.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public OpenApiError(string pointer, string message)
4141
/// </summary>
4242
public override string ToString()
4343
{
44-
return Message + (!string.IsNullOrEmpty(Pointer) ? " at " + Pointer : "");
44+
return Message + (!string.IsNullOrEmpty(Pointer) ? " [" + Pointer + "]" : "" );
4545
}
4646
}
4747
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System.Collections.Generic;
5+
using FluentAssertions;
6+
using Microsoft.OpenApi.Models;
7+
using Microsoft.OpenApi.Readers;
8+
using Microsoft.OpenApi.Readers.Exceptions;
9+
using Xunit;
10+
11+
namespace Microsoft.OpenApi.Tests
12+
{
13+
public class ParseNodeTests
14+
{
15+
[Fact]
16+
public void BrokenSimpleList()
17+
{
18+
var input = @"swagger: 2.0
19+
info:
20+
title: hey
21+
version: 1.0.0
22+
schemes: [ { ""hello"" }]
23+
paths: { }";
24+
25+
var reader = new OpenApiStringReader();
26+
reader.Read(input, out var diagnostic);
27+
28+
diagnostic.Errors.ShouldBeEquivalentTo(new List<OpenApiError>() {
29+
new OpenApiError(new OpenApiReaderException("Expected a value.") {
30+
Pointer = "#line=4"
31+
})
32+
});
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)