Skip to content

NQuads parser doesn't pass test suite #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
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
21 changes: 19 additions & 2 deletions src/JsonLD/Core/JsonLdProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,25 @@ public static JArray Expand(JToken input, JsonLdOptions opts)
{
// 1)
// TODO: look into java futures/promises
// 2) TODO: better verification of DOMString IRI
if (input.Type == JTokenType.String && ((string)input).Contains(":"))

// 2) verification of DOMString IRI
bool isIriString = input.Type == JTokenType.String;
if (isIriString)
{
bool hasColon = false;
foreach (var c in ((string) input))
{
if (c == ':')
hasColon = true;
if (!hasColon && (c == '{' || c == '['))
{
isIriString = false;
break;
}
}
}

if (isIriString)
{
try
{
Expand Down
2 changes: 1 addition & 1 deletion src/JsonLD/Core/JsonLdUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ internal static void MergeCompactedValue(JObject obj, string
public static bool IsAbsoluteIri(string value)
{
// TODO: this is a bit simplistic!
return value.Contains(":");
return value != null && value.Contains(":");
}

/// <summary>Returns true if the given value is a subject with properties.</summary>
Expand Down
48 changes: 33 additions & 15 deletions src/JsonLD/Core/RDFDatasetUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -544,14 +544,19 @@ public static string Escape(string str)

private class Regex
{
public static readonly Pattern Iri = Pattern.Compile("(?:<([^>]*)>)");
public static readonly Pattern HEX = Pattern.Compile("[0-9A-Fa-f]");

public static readonly Pattern Bnode = Pattern.Compile("(_:(?:[A-Za-z][A-Za-z0-9]*))"
);
public static readonly Pattern UCHAR = Pattern.Compile("\\\\u" + HEX + "{4}|\\\\U" + HEX + "{8}");

public static readonly Pattern Iri = Pattern.Compile("(?:<((?:[^\\x00-\\x20<>\"{}|^`\\\\]|" + UCHAR + ")*)>)");

public static readonly Pattern Plain = Pattern.Compile("\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\""
public static readonly Pattern Bnode = Pattern.Compile("(_:(?:[A-Za-z0-9](?:[A-Za-z0-9\\-\\.]*[A-Za-z0-9])?))"
);

public static readonly Pattern ECHAR = Pattern.Compile("\\\\[tbnrf\"'\\\\]");

public static readonly Pattern Plain = Pattern.Compile("\"((?:[^\\x22\\x5C\\x0A\\x0D]|" + ECHAR + "|" + UCHAR + ")*)\"");

public static readonly Pattern Datatype = Pattern.Compile("(?:\\^\\^" + Iri + ")"
);

Expand All @@ -561,19 +566,16 @@ private class Regex
public static readonly Pattern Literal = Pattern.Compile("(?:" + Plain + "(?:" +
Datatype + "|" + Language + ")?)");

public static readonly Pattern Ws = Pattern.Compile("[ \\t]+");

public static readonly Pattern Wso = Pattern.Compile("[ \\t]*");

public static readonly Pattern Eoln = Pattern.Compile("(?:\r\n)|(?:\n)|(?:\r)");

public static readonly Pattern Empty = Pattern.Compile("^" + Wso + "$");
public static readonly Pattern EmptyOrComment = Pattern.Compile("^" + Wso + "(#.*)?$");

public static readonly Pattern Subject = Pattern.Compile("(?:" + Iri + "|" + Bnode
+ ")" + Ws);
+ ")" + Wso);

public static readonly Pattern Property = Pattern.Compile(Iri.GetPattern() + Ws.GetPattern
());
public static readonly Pattern Property = Pattern.Compile(Iri.GetPattern() + Wso);

public static readonly Pattern Object = Pattern.Compile("(?:" + Iri + "|" + Bnode
+ "|" + Literal + ")" + Wso);
Expand All @@ -582,7 +584,7 @@ private class Regex
+ Bnode + ")" + Wso + "\\.))");

public static readonly Pattern Quad = Pattern.Compile("^" + Wso + Subject + Property
+ Object + Graph + Wso + "$");
+ Object + Graph + Wso + "(#.*)?$");
// define partial regexes
// final public static Pattern IRI =
// Pattern.compile("(?:<([^:]+:[^>]*)>)");
Expand All @@ -606,7 +608,7 @@ public static RDFDataset ParseNQuads(string input)
{
lineNumber++;
// skip empty lines
if (RDFDatasetUtils.Regex.Empty.Matcher(line).Matches())
if (RDFDatasetUtils.Regex.EmptyOrComment.Matcher(line).Matches())
{
continue;
}
Expand All @@ -621,19 +623,25 @@ public static RDFDataset ParseNQuads(string input)
RDFDataset.Node subject;
if (match.Group(1) != null)
{
subject = new RDFDataset.IRI(Unescape(match.Group(1)));
var subjectIri = Unescape(match.Group(1));
AssertAbsoluteIri(subjectIri);
subject = new RDFDataset.IRI(subjectIri);
}
else
{
subject = new RDFDataset.BlankNode(Unescape(match.Group(2)));
}
// get predicate
RDFDataset.Node predicate = new RDFDataset.IRI(Unescape(match.Group(3)));
var predicateIri = Unescape(match.Group(3));
AssertAbsoluteIri(predicateIri);
RDFDataset.Node predicate = new RDFDataset.IRI(predicateIri);
// get object
RDFDataset.Node @object;
if (match.Group(4) != null)
{
@object = new RDFDataset.IRI(Unescape(match.Group(4)));
var objectIri = Unescape(match.Group(4));
AssertAbsoluteIri(objectIri);
@object = new RDFDataset.IRI(objectIri);
}
else
{
Expand All @@ -646,6 +654,7 @@ public static RDFDataset ParseNQuads(string input)
string language = Unescape(match.Group(8));
string datatype = match.Group(7) != null ? Unescape(match.Group(7)) : match.Group
(8) != null ? JSONLDConsts.RdfLangstring : JSONLDConsts.XsdString;
AssertAbsoluteIri(datatype);
string unescaped = Unescape(match.Group(6));
@object = new RDFDataset.Literal(unescaped, datatype, language);
}
Expand All @@ -655,6 +664,7 @@ public static RDFDataset ParseNQuads(string input)
if (match.Group(9) != null)
{
name = Unescape(match.Group(9));
AssertAbsoluteIri(name);
}
else
{
Expand Down Expand Up @@ -683,5 +693,13 @@ public static RDFDataset ParseNQuads(string input)
}
return dataset;
}

private static void AssertAbsoluteIri(string iri)
{
if (Uri.IsWellFormedUriString(Uri.EscapeUriString(iri), UriKind.Absolute) == false)
{
throw new JsonLdError(JsonLdError.Error.SyntaxError, "Invalid absolute URI <" + iri + ">");
}
}
}
}
2 changes: 1 addition & 1 deletion src/JsonLD/Util/JavaCompat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static bool SafeCompare<T>(this JToken token, T val)
{
try
{
return token.Value<T>().Equals(val);
return token == null ? val == null : token.Value<T>().Equals(val);
}
catch
{
Expand Down
7 changes: 7 additions & 0 deletions tests/JsonLD.Test/JsonLD.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,14 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ConformanceTests.cs" />
<Compile Include="NQuadsParserTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="NQuads\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="W3C\compact-0001-context.jsonld">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down Expand Up @@ -3005,6 +3011,7 @@
<Name>JsonLD</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
Expand Down
25 changes: 25 additions & 0 deletions tests/JsonLD.Test/NQuads/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
This README is for the W3C RDF Working Group's N-Quads test suite.
This test suite contains two kinds of tests:

Positive syntax (rdft:TestNQuadsPositiveSyntax) - an input N-Quads
file with no syntax errors.

Negative syntax (rdft:TestNQuadsNegativeSyntax) - an input N-Quads
file with at least one syntax error.

The manifest.ttl file in this directory lists tests in the
RDF WG's N-Quads test suite. All
tests have a name (mf:name) and an input (mf:action).

• An implementation passes a positive syntax test if it parses the
input.

• An implementation passes a negative syntax test if it fails to parse
the input.

The home of the test suite is <http://www.w3.org/2013/NQuadsTests/>.

See http://www.w3.org/2011/rdf-wg/wiki/RDF_Test_Suites for more details.

Eric Prud'hommeaux <[email protected]> - 11 June 2013.
Gregg Kellogg <[email protected]> - 26 June 2013.
5 changes: 5 additions & 0 deletions tests/JsonLD.Test/NQuads/comment_following_triple.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<http://example/s> <http://example/p> <http://example/o> . # comment
<http://example/s> <http://example/p> _:o . # comment
<http://example/s> <http://example/p> "o" . # comment
<http://example/s> <http://example/p> "o"^^<http://example/dt> . # comment
<http://example/s> <http://example/p> "o"@en . # comment
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/langtagged_string.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "chat"@en .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/lantag_with_subtag.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://example.org/ex#a> <http://example.org/ex#b> "Cheers"@en-UK .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "x" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_all_controls.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\t\u000B\u000C\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_all_punctuation.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> " !\"#$%&():;<=>?@[]^_`{|}~" .
Binary file not shown.
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_false.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "false"^^<http://www.w3.org/2001/XMLSchema#boolean> .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_true.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "true"^^<http://www.w3.org/2001/XMLSchema#boolean> .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_2_dquotes.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "x\"\"y" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_2_squotes.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "x''y" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_BACKSPACE.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\b" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_CARRIAGE_RETURN.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\r" .
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\t" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_FORM_FEED.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\f" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_LINE_FEED.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\n" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_REVERSE_SOLIDUS.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\\" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_REVERSE_SOLIDUS2.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://example.org/ns#s> <http://example.org/ns#p1> "test-\\" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_UTF8_boundaries.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "€߿ࠀ࿿က쿿퀀퟿�𐀀𿿽񀀀󿿽􀀀􏿽" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_dquote.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "x\"y" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_numeric_escape4.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\u006F" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_numeric_escape8.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "\U0000006F" .
1 change: 1 addition & 0 deletions tests/JsonLD.Test/NQuads/literal_with_squote.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://a.example/s> <http://a.example/p> "x'y" .
Loading