From a51e2a0dec6d1d8b15fda56678809abd0e2a2aef Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Fri, 14 Sep 2018 17:02:04 +0200 Subject: [PATCH] Fix RDF.Datatype.cast/1 implementations when casting from strings --- lib/rdf/datatype.ex | 8 ++++++++ lib/rdf/datatypes/boolean.ex | 1 + lib/rdf/datatypes/date_time.ex | 1 + lib/rdf/datatypes/decimal.ex | 1 + lib/rdf/datatypes/double.ex | 1 + lib/rdf/datatypes/integer.ex | 8 ++++---- test/unit/datatypes/boolean_test.exs | 6 +++++- test/unit/datatypes/date_time_test.exs | 11 ++++++++--- test/unit/datatypes/decimal_test.exs | 6 +++++- test/unit/datatypes/double_test.exs | 6 +++++- test/unit/datatypes/integer_test.exs | 8 ++++++-- test/unit/datatypes/string_test.exs | 13 +++++++------ 12 files changed, 52 insertions(+), 18 deletions(-) diff --git a/lib/rdf/datatype.ex b/lib/rdf/datatype.ex index 6f3146f..11b7d0c 100644 --- a/lib/rdf/datatype.ex +++ b/lib/rdf/datatype.ex @@ -210,6 +210,14 @@ defmodule RDF.Datatype do def equal_value?(_, _), do: nil + + def validate_cast(%Literal{} = literal) do + if valid?(literal), do: literal + end + + def validate_cast(_), do: nil + + defoverridable [ build_literal_by_value: 2, build_literal_by_lexical: 2, diff --git a/lib/rdf/datatypes/boolean.ex b/lib/rdf/datatypes/boolean.ex index dbb4fc5..34b79c5 100644 --- a/lib/rdf/datatypes/boolean.ex +++ b/lib/rdf/datatypes/boolean.ex @@ -39,6 +39,7 @@ defmodule RDF.Boolean do literal.value |> new() |> canonical() + |> validate_cast() is_xsd_decimal(datatype) -> !Decimal.equal?(literal.value, 0) diff --git a/lib/rdf/datatypes/date_time.ex b/lib/rdf/datatypes/date_time.ex index 6b6dbd8..31cd3ad 100644 --- a/lib/rdf/datatypes/date_time.ex +++ b/lib/rdf/datatypes/date_time.ex @@ -81,6 +81,7 @@ defmodule RDF.DateTime do is_xsd_string(datatype) -> literal.value |> new() + |> validate_cast() true -> nil diff --git a/lib/rdf/datatypes/decimal.ex b/lib/rdf/datatypes/decimal.ex index 8b4e3d8..efeac0f 100644 --- a/lib/rdf/datatypes/decimal.ex +++ b/lib/rdf/datatypes/decimal.ex @@ -85,6 +85,7 @@ defmodule RDF.Decimal do literal.value |> new() |> canonical() + |> validate_cast() is_number(literal.value) and (is_xsd_integer(datatype) or is_xsd_double(datatype) or is_xsd_float(datatype)) -> diff --git a/lib/rdf/datatypes/double.ex b/lib/rdf/datatypes/double.ex index 4df1f82..12a50a6 100644 --- a/lib/rdf/datatypes/double.ex +++ b/lib/rdf/datatypes/double.ex @@ -113,6 +113,7 @@ defmodule RDF.Double do literal.value |> new() |> canonical() + |> validate_cast() is_xsd_decimal(datatype) -> literal.value diff --git a/lib/rdf/datatypes/integer.ex b/lib/rdf/datatypes/integer.ex index 75b6561..7508465 100644 --- a/lib/rdf/datatypes/integer.ex +++ b/lib/rdf/datatypes/integer.ex @@ -36,10 +36,10 @@ defmodule RDF.Integer do new(1) is_xsd_string(datatype) -> - case Integer.parse(literal.value) do - {value, _} -> new(value) - _ -> nil - end + literal.value + |> new() + |> canonical() + |> validate_cast() is_xsd_decimal(datatype) -> literal.value diff --git a/test/unit/datatypes/boolean_test.exs b/test/unit/datatypes/boolean_test.exs index 3832e50..355d8fa 100644 --- a/test/unit/datatypes/boolean_test.exs +++ b/test/unit/datatypes/boolean_test.exs @@ -51,7 +51,7 @@ defmodule RDF.BooleanTest do assert RDF.false |> RDF.Boolean.cast() == RDF.false end - test "casting a string" do + test "casting a string with a value from the lexical value space of xsd:boolean" do assert RDF.string("true") |> RDF.Boolean.cast() == RDF.true assert RDF.string("tRuE") |> RDF.Boolean.cast() == RDF.true assert RDF.string("1") |> RDF.Boolean.cast() == RDF.true @@ -61,6 +61,10 @@ defmodule RDF.BooleanTest do assert RDF.string("0") |> RDF.Boolean.cast() == RDF.false end + test "casting a string with a value not in the lexical value space of xsd:boolean" do + assert RDF.string("foo") |> RDF.Boolean.cast() == nil + end + test "casting an integer" do assert RDF.integer(0) |> RDF.Boolean.cast() == RDF.false assert RDF.integer(1) |> RDF.Boolean.cast() == RDF.true diff --git a/test/unit/datatypes/date_time_test.exs b/test/unit/datatypes/date_time_test.exs index 21cbdec..d6ff8dd 100644 --- a/test/unit/datatypes/date_time_test.exs +++ b/test/unit/datatypes/date_time_test.exs @@ -129,7 +129,7 @@ defmodule RDF.DateTimeTest do RDF.date_time("2010-01-01T12:34:56") end - test "casting a string" do + test "casting a string with a value from the lexical value space of xsd:dateTime" do assert RDF.string("2010-01-01T12:34:56") |> RDF.DateTime.cast() == RDF.date_time("2010-01-01T12:34:56") assert RDF.string("2010-01-01T12:34:56Z") |> RDF.DateTime.cast() == @@ -138,6 +138,11 @@ defmodule RDF.DateTimeTest do RDF.date_time("2010-01-01T12:34:56+01:00") end + test "casting a string with a value not in the lexical value space of xsd:dateTime" do + assert RDF.string("string") |> RDF.DateTime.cast() == nil + assert RDF.string("02010-01-01T00:00:00") |> RDF.DateTime.cast() == nil + end + test "casting a date" do assert RDF.date("2010-01-01") |> RDF.DateTime.cast() == RDF.date_time("2010-01-01T00:00:00") @@ -154,8 +159,8 @@ defmodule RDF.DateTimeTest do end test "with literals of unsupported datatypes" do - assert RDF.false |> RDF.DateTime.cast() == nil - assert RDF.integer(1) |> RDF.DateTime.cast() == nil + assert RDF.false |> RDF.DateTime.cast() == nil + assert RDF.integer(1) |> RDF.DateTime.cast() == nil assert RDF.decimal(3.14) |> RDF.DateTime.cast() == nil end end diff --git a/test/unit/datatypes/decimal_test.exs b/test/unit/datatypes/decimal_test.exs index 5d50bac..cfce14f 100644 --- a/test/unit/datatypes/decimal_test.exs +++ b/test/unit/datatypes/decimal_test.exs @@ -78,11 +78,15 @@ defmodule RDF.DecimalTest do assert RDF.false |> RDF.Decimal.cast() == RDF.decimal(0.0) end - test "casting a string" do + test "casting a string with a value from the lexical value space of xsd:decimal" do assert RDF.string("0") |> RDF.Decimal.cast() == RDF.decimal(0) assert RDF.string("3.14") |> RDF.Decimal.cast() == RDF.decimal(3.14) end + test "casting a string with a value not in the lexical value space of xsd:decimal" do + assert RDF.string("foo") |> RDF.Decimal.cast() == nil + end + test "casting an integer" do assert RDF.integer(0) |> RDF.Decimal.cast() == RDF.decimal(0.0) assert RDF.integer(42) |> RDF.Decimal.cast() == RDF.decimal(42.0) diff --git a/test/unit/datatypes/double_test.exs b/test/unit/datatypes/double_test.exs index 3792a2b..cf0910b 100644 --- a/test/unit/datatypes/double_test.exs +++ b/test/unit/datatypes/double_test.exs @@ -71,12 +71,16 @@ defmodule RDF.DoubleTest do assert RDF.false |> RDF.Double.cast() == RDF.double(0.0) end - test "casting a string" do + test "casting a string with a value from the lexical value space of xsd:double" do assert RDF.string("1.0") |> RDF.Double.cast() == RDF.double("1.0E0") assert RDF.string("3.14") |> RDF.Double.cast() == RDF.double("3.14E0") assert RDF.string("3.14E0") |> RDF.Double.cast() == RDF.double("3.14E0") end + test "casting a string with a value not in the lexical value space of xsd:double" do + assert RDF.string("foo") |> RDF.Double.cast() == nil + end + test "casting an integer" do assert RDF.integer(0) |> RDF.Double.cast() == RDF.double(0.0) assert RDF.integer(42) |> RDF.Double.cast() == RDF.double(42.0) diff --git a/test/unit/datatypes/integer_test.exs b/test/unit/datatypes/integer_test.exs index 5f57b80..a90a99b 100644 --- a/test/unit/datatypes/integer_test.exs +++ b/test/unit/datatypes/integer_test.exs @@ -27,10 +27,14 @@ defmodule RDF.IntegerTest do assert RDF.true |> RDF.Integer.cast() == RDF.integer(1) end - test "casting a string" do + test "casting a string with a value from the lexical value space of xsd:integer" do assert RDF.string("0") |> RDF.Integer.cast() == RDF.integer(0) assert RDF.string("042") |> RDF.Integer.cast() == RDF.integer(42) - assert RDF.string("3.14") |> RDF.Integer.cast() == RDF.integer(3) + end + + test "casting a string with a value not in the lexical value space of xsd:integer" do + assert RDF.string("foo") |> RDF.Integer.cast() == nil + assert RDF.string("3.14") |> RDF.Integer.cast() == nil end test "casting an decimal" do diff --git a/test/unit/datatypes/string_test.exs b/test/unit/datatypes/string_test.exs index cc6f1b9..fd395f2 100644 --- a/test/unit/datatypes/string_test.exs +++ b/test/unit/datatypes/string_test.exs @@ -95,11 +95,11 @@ defmodule RDF.StringTest do end test "casting a date" do - assert RDF.date(~D[2000-01-01]) |> RDF.String.cast() == RDF.string("2000-01-01") - assert RDF.date("2000-01-01") |> RDF.String.cast() == RDF.string("2000-01-01") + assert RDF.date(~D[2000-01-01]) |> RDF.String.cast() == RDF.string("2000-01-01") + assert RDF.date("2000-01-01") |> RDF.String.cast() == RDF.string("2000-01-01") assert RDF.date("2000-01-01+00:00") |> RDF.String.cast() == RDF.string("2000-01-01Z") assert RDF.date("2000-01-01+01:00") |> RDF.String.cast() == RDF.string("2000-01-01+01:00") - assert RDF.date("0001-01-01") |> RDF.String.cast() == RDF.string("0001-01-01") + assert RDF.date("0001-01-01") |> RDF.String.cast() == RDF.string("0001-01-01") unless Version.compare(System.version(), "1.7.2") == :lt do assert RDF.date("-0001-01-01") |> RDF.String.cast() == RDF.string("-0001-01-01") end @@ -118,9 +118,10 @@ defmodule RDF.StringTest do end test "with invalid literals" do - assert RDF.integer(3.14) |> RDF.Integer.cast() == nil - assert RDF.decimal("NAN") |> RDF.Integer.cast() == nil - assert RDF.double(true) |> RDF.Integer.cast() == nil + assert RDF.integer(3.14) |> RDF.String.cast() == nil + assert RDF.decimal("NAN") |> RDF.String.cast() == nil + assert RDF.double(true) |> RDF.String.cast() == nil + end end end