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
|
||||
included empty descriptions, which lead to inconsistent behaviour
|
||||
(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)
|
||||
|
|
|
@ -22,14 +22,6 @@ defmodule RDF.Triple.InvalidPredicateError do
|
|||
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
|
||||
defexception [:graph_context]
|
||||
|
||||
|
@ -38,6 +30,31 @@ defmodule RDF.Quad.InvalidGraphContextError do
|
|||
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
|
||||
defexception [:message]
|
||||
end
|
||||
|
|
|
@ -232,11 +232,15 @@ defmodule RDF.Turtle.Encoder do
|
|||
defp description_order(%{subject: s1}, %{subject: s2}), do: to_string(s1) < to_string(s2)
|
||||
|
||||
defp description_statements(description, state, nesting) do
|
||||
with %BlankNode{} <- description.subject,
|
||||
ref_count when ref_count < 2 <- State.bnode_ref_counter(state, description.subject) do
|
||||
unrefed_bnode_subject_term(description, ref_count, state, nesting)
|
||||
if Description.empty?(description) do
|
||||
raise Graph.EmptyDescriptionError, subject: description.subject
|
||||
else
|
||||
_ -> full_description_statements(description, state, nesting)
|
||||
with %BlankNode{} <- description.subject,
|
||||
ref_count when ref_count < 2 <- State.bnode_ref_counter(state, description.subject) do
|
||||
unrefed_bnode_subject_term(description, ref_count, state, nesting)
|
||||
else
|
||||
_ -> full_description_statements(description, state, nesting)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -416,13 +416,36 @@ defmodule RDF.Turtle.EncoderTest do
|
|||
] .
|
||||
"""
|
||||
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
|
||||
|
||||
test "serializing a description" do
|
||||
description = EX.S |> EX.p(EX.O)
|
||||
describe "serializing a description" do
|
||||
test "a non-empty description" do
|
||||
description = EX.S |> EX.p(EX.O)
|
||||
|
||||
assert Turtle.Encoder.encode!(description) ==
|
||||
description |> Graph.new() |> Turtle.Encoder.encode!()
|
||||
assert Turtle.Encoder.encode!(description) ==
|
||||
description |> Graph.new() |> Turtle.Encoder.encode!()
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue