Fix handling of empty descriptions in Turtle encoder
This commit is contained in:
parent
5bb1264249
commit
c143272f50
4 changed files with 65 additions and 16 deletions
|
@ -31,6 +31,11 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
|
||||||
- When triples with an empty object list where added to an `RDF.Graph`, it
|
- When triples with an empty object list where added to an `RDF.Graph`, it
|
||||||
included empty descriptions, which lead to inconsistent behaviour
|
included empty descriptions, which lead to inconsistent behaviour
|
||||||
(for example it would be counted in `RDF.Graph.subject_count/1`).
|
(for example it would be counted in `RDF.Graph.subject_count/1`).
|
||||||
|
- When an `RDF.Graph` contained empty descriptions these were rendered by
|
||||||
|
the `RDF.Turtle.Encoder` to a subject without predicates and objects, i.e.
|
||||||
|
invalid Turtle. This actually shouldn't happen and is either caused by
|
||||||
|
misuse or a bug. So instead, a `RDF.Graph.EmptyDescriptionError` with a
|
||||||
|
detailed message will be raised now when this case is detected.
|
||||||
|
|
||||||
|
|
||||||
[Compare v0.11.0...HEAD](https://github.com/rdf-elixir/rdf-ex/compare/v0.11.0...HEAD)
|
[Compare v0.11.0...HEAD](https://github.com/rdf-elixir/rdf-ex/compare/v0.11.0...HEAD)
|
||||||
|
|
|
@ -22,14 +22,6 @@ defmodule RDF.Triple.InvalidPredicateError do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defmodule RDF.XSD.Datatype.Mismatch do
|
|
||||||
defexception [:value, :expected_type]
|
|
||||||
|
|
||||||
def message(%{value: value, expected_type: expected_type}) do
|
|
||||||
"'#{inspect(value)}' is not a #{expected_type}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defmodule RDF.Quad.InvalidGraphContextError do
|
defmodule RDF.Quad.InvalidGraphContextError do
|
||||||
defexception [:graph_context]
|
defexception [:graph_context]
|
||||||
|
|
||||||
|
@ -38,6 +30,31 @@ defmodule RDF.Quad.InvalidGraphContextError do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defmodule RDF.Graph.EmptyDescriptionError do
|
||||||
|
defexception [:subject]
|
||||||
|
|
||||||
|
def message(%{subject: subject}) do
|
||||||
|
"""
|
||||||
|
RDF.Graph with empty description about '#{inspect(subject)}' detected.
|
||||||
|
Empty descriptions in a graph lead to inconsistent behaviour. The RDF.Graph API
|
||||||
|
should ensure that this never happens. So this probably happened by changing the
|
||||||
|
contents of the RDF.Graph struct directly, which is strongly discouraged.
|
||||||
|
You should always use the RDF.Graph API to change the content of a graph.
|
||||||
|
If this happened while using the RDF.Graph API, this is a bug.
|
||||||
|
Please report this at https://github.com/rdf-elixir/rdf-ex/issues and describe the
|
||||||
|
circumstances how this happened.
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defmodule RDF.XSD.Datatype.Mismatch do
|
||||||
|
defexception [:value, :expected_type]
|
||||||
|
|
||||||
|
def message(%{value: value, expected_type: expected_type}) do
|
||||||
|
"'#{inspect(value)}' is not a #{expected_type}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defmodule RDF.Namespace.InvalidVocabBaseIRIError do
|
defmodule RDF.Namespace.InvalidVocabBaseIRIError do
|
||||||
defexception [:message]
|
defexception [:message]
|
||||||
end
|
end
|
||||||
|
|
|
@ -232,6 +232,9 @@ defmodule RDF.Turtle.Encoder do
|
||||||
defp description_order(%{subject: s1}, %{subject: s2}), do: to_string(s1) < to_string(s2)
|
defp description_order(%{subject: s1}, %{subject: s2}), do: to_string(s1) < to_string(s2)
|
||||||
|
|
||||||
defp description_statements(description, state, nesting) do
|
defp description_statements(description, state, nesting) do
|
||||||
|
if Description.empty?(description) do
|
||||||
|
raise Graph.EmptyDescriptionError, subject: description.subject
|
||||||
|
else
|
||||||
with %BlankNode{} <- description.subject,
|
with %BlankNode{} <- description.subject,
|
||||||
ref_count when ref_count < 2 <- State.bnode_ref_counter(state, description.subject) do
|
ref_count when ref_count < 2 <- State.bnode_ref_counter(state, description.subject) do
|
||||||
unrefed_bnode_subject_term(description, ref_count, state, nesting)
|
unrefed_bnode_subject_term(description, ref_count, state, nesting)
|
||||||
|
@ -239,6 +242,7 @@ defmodule RDF.Turtle.Encoder do
|
||||||
_ -> full_description_statements(description, state, nesting)
|
_ -> full_description_statements(description, state, nesting)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp full_description_statements(subject, description, state, nesting) do
|
defp full_description_statements(subject, description, state, nesting) do
|
||||||
nesting = nesting + @indentation
|
nesting = nesting + @indentation
|
||||||
|
|
|
@ -416,15 +416,38 @@ defmodule RDF.Turtle.EncoderTest do
|
||||||
] .
|
] .
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "serializing a pathological graph with an empty description" do
|
||||||
|
description = RDF.description(EX.S)
|
||||||
|
graph = %Graph{Graph.new() | descriptions: %{description.subject => description}}
|
||||||
|
|
||||||
|
assert_raise Graph.EmptyDescriptionError, fn ->
|
||||||
|
Turtle.Encoder.encode!(graph)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "serializing a description" do
|
describe "serializing a description" do
|
||||||
|
test "a non-empty description" do
|
||||||
description = EX.S |> EX.p(EX.O)
|
description = EX.S |> EX.p(EX.O)
|
||||||
|
|
||||||
assert Turtle.Encoder.encode!(description) ==
|
assert Turtle.Encoder.encode!(description) ==
|
||||||
description |> Graph.new() |> Turtle.Encoder.encode!()
|
description |> Graph.new() |> Turtle.Encoder.encode!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "an empty description" do
|
||||||
|
description = RDF.description(EX.S)
|
||||||
|
|
||||||
|
assert Turtle.Encoder.encode!(description) |> String.trim() ==
|
||||||
|
"""
|
||||||
|
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||||
|
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||||
|
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
||||||
|
"""
|
||||||
|
|> String.trim()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "prefixed_name/2" do
|
describe "prefixed_name/2" do
|
||||||
setup do
|
setup do
|
||||||
{:ok,
|
{:ok,
|
||||||
|
|
Loading…
Reference in a new issue