defmodule RDF.XSD.ComparisonTest do use ExUnit.Case alias RDF.XSD alias RDF.TestDatatypes.{ Initials, Age, DecimalUnitInterval, CustomTime, DateWithoutTz, DateTimeWithTz } describe "XSD.String" do @ordered_strings [ {"a", "b"}, {"0", "1"} ] test "valid comparisons between string literals" do Enum.each(@ordered_strings, fn {left, right} -> assert_order({XSD.string(left), XSD.string(right)}) end) assert_equal({XSD.string("foo"), XSD.string("foo")}) end test "valid comparisons between derived string literals" do assert_equal({Initials.new("fo"), XSD.string("fo")}) assert_order({Initials.new("ba"), Initials.new("fo")}) assert_order({Initials.new("ba"), XSD.string("foo")}) assert_order({XSD.string("bar"), Initials.new("fo")}) end test "invalid comparison between string and langString literals" do assert_incomparable({XSD.string("foo"), RDF.langString("foo", :en)}) end end describe "XSD.Boolean" do test "when unequal" do assert_order({XSD.false(), XSD.true()}) end test "when equal" do assert_equal({XSD.false(), XSD.false()}) assert_equal({XSD.true(), XSD.true()}) end end describe "XSD.Numeric" do test "when unequal" do Enum.each( [ {XSD.integer(0), XSD.integer(1)}, {XSD.integer("3"), XSD.integer("007")}, {XSD.double(1.1), XSD.double(2.2)}, {XSD.float(1.1), XSD.float(2.2)}, {XSD.decimal(1.1), XSD.decimal(2.2)}, {XSD.decimal(1.1), XSD.double(2.2)}, {XSD.float(1.1), XSD.decimal(2.2)}, {XSD.double(3.14), XSD.integer(42)}, {XSD.float(3.14), XSD.integer(42)}, {XSD.decimal(3.14), XSD.integer(42)}, {XSD.non_negative_integer(0), XSD.integer(1)}, {XSD.integer(0), XSD.positive_integer(1)}, {XSD.non_negative_integer(0), XSD.positive_integer(1)}, {XSD.positive_integer(1), XSD.non_negative_integer(2)}, {XSD.positive_integer(1), XSD.non_negative_integer(2)}, {Age.new(1), Age.new(2)}, {Age.new(1), XSD.integer(2)}, {XSD.non_negative_integer(1), Age.new(2)}, {Age.new(1), XSD.decimal(2.1)}, {XSD.decimal(0.1), DecimalUnitInterval.new(0.2)}, {DecimalUnitInterval.new(0.3), Age.new(2)} ], &assert_order/1 ) end test "when equal" do Enum.each( [ {XSD.integer(42), XSD.integer(42)}, {XSD.integer("42"), XSD.integer("042")}, {XSD.integer("42"), XSD.double("42")}, {XSD.integer(42), XSD.double(42.0)}, {XSD.integer(42), XSD.float(42.0)}, {XSD.integer("42"), XSD.decimal("42")}, {XSD.integer(42), XSD.decimal(42.0)}, {XSD.double(3.14), XSD.decimal(3.14)}, {XSD.float(3.14), XSD.decimal(3.14)}, {XSD.double("+0"), XSD.double("-0")}, {XSD.decimal("+0"), XSD.decimal("-0")}, {XSD.non_negative_integer(0), XSD.integer(0)}, {XSD.integer(1), XSD.positive_integer(1)}, {XSD.non_negative_integer(1), XSD.positive_integer(1)}, {XSD.positive_integer(1), XSD.non_negative_integer(1)} ], &assert_equal/1 ) end end describe "XSD.DateTime" do test "when unequal" do assert_order({XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T17:00:00")}) assert_order( {XSD.datetime("2002-04-02T12:00:00+01:00"), XSD.datetime("2002-04-02T12:00:00+00:00")} ) assert_order({XSD.datetime("2000-01-15T12:00:00"), XSD.datetime("2000-01-16T12:00:00Z")}) assert_order( {XSD.datetime("2000-01-15T12:00:00"), DateTimeWithTz.new("2000-01-16T12:00:00Z")} ) end test "when unequal due to missing time zone" do assert_order({XSD.datetime("2000-01-15T00:00:00"), XSD.datetime("2000-02-15T00:00:00")}) end test "when equal" do assert_equal( {XSD.datetime("2002-04-02T12:00:00-01:00"), XSD.datetime("2002-04-02T12:00:00-01:00")} ) assert_equal({XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T12:00:00")}) assert_equal( {XSD.datetime("2002-04-02T12:00:00-01:00"), XSD.datetime("2002-04-02T17:00:00+04:00")} ) assert_equal( {XSD.datetime("2002-04-02T23:00:00-04:00"), XSD.datetime("2002-04-03T02:00:00-01:00")} ) assert_equal( {DateTimeWithTz.new("2002-04-02T23:00:00-04:00"), XSD.datetime("2002-04-03T02:00:00-01:00")} ) assert_equal({XSD.datetime("1999-12-31T24:00:00"), XSD.datetime("2000-01-01T00:00:00")}) # TODO: Assume that the dynamic context provides an implicit timezone value of -05:00 # assert_equal {XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T23:00:00+06:00")} end test "when indeterminate" do assert_indeterminate( {XSD.datetime("2000-01-01T12:00:00"), XSD.datetime("1999-12-31T23:00:00Z")} ) assert_indeterminate( {XSD.datetime("2000-01-16T12:00:00"), XSD.datetime("2000-01-16T12:00:00Z")} ) assert_indeterminate( {XSD.datetime("2000-01-16T00:00:00"), XSD.datetime("2000-01-16T12:00:00Z")} ) assert_indeterminate( {XSD.datetime("2000-01-16T00:00:00"), DateTimeWithTz.new("2000-01-16T12:00:00Z")} ) end end describe "XSD.Date" do test "when unequal" do assert_order({XSD.date("2002-04-02"), XSD.date("2002-04-03")}) assert_order({XSD.date("2002-04-02+01:00"), XSD.date("2002-04-03+00:00")}) assert_order({XSD.date("2002-04-02"), XSD.date("2002-04-03Z")}) assert_order({DateWithoutTz.new("2002-04-02"), XSD.date("2002-04-03Z")}) assert_order({DateWithoutTz.new("2002-04-02"), DateWithoutTz.new("2002-04-03")}) end test "when equal" do assert_equal({XSD.date("2002-04-02-01:00"), XSD.date("2002-04-02-01:00")}) assert_equal({XSD.date("2002-04-02"), XSD.date("2002-04-02")}) assert_equal({XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02+00:00")}) assert_equal({XSD.date("2002-04-02Z"), XSD.date("2002-04-02+00:00")}) assert_equal({XSD.date("2002-04-02Z"), XSD.date("2002-04-02-00:00")}) assert_equal({XSD.date("2002-04-02"), DateWithoutTz.new("2002-04-02")}) end test "when indeterminate" do assert_indeterminate({XSD.date("2002-04-02Z"), XSD.date("2002-04-02")}) assert_indeterminate({XSD.date("2002-04-02+00:00"), XSD.date("2002-04-02")}) assert_indeterminate({XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02")}) assert_indeterminate({XSD.date("2002-04-02Z"), DateWithoutTz.new("2002-04-02")}) end end # It seems quite strange that open-world test date-2 from the SPARQL 1.0 test suite # allows for equality comparisons between dates and datetimes, but disallows # ordering comparisons in the date-3 test. # # describe "comparisons XSD.DateTime between XSD.Date and XSD.DateTime" do # test "when unequal" do # # without timezone # assert_order({XSD.datetime("2000-01-14T00:00:00"), XSD.date("2000-02-15")}) # assert_order({XSD.date("2000-01-15"), XSD.datetime("2000-01-15T00:00:01")}) # # with timezone # assert_order({XSD.datetime("2000-01-14T00:00:00"), XSD.date("2000-02-15")}) # assert_order({XSD.datetime("2000-01-14T00:00:00"), XSD.date("2000-02-15Z")}) # assert_order({XSD.datetime("2000-01-14T00:00:00"), XSD.date("2000-02-15+01:00")}) # assert_order({XSD.datetime("2000-01-14T00:00:00Z"), XSD.date("2000-02-15")}) # assert_order({XSD.datetime("2000-01-14T00:00:00Z"), XSD.date("2000-02-15Z")}) # assert_order({XSD.datetime("2000-01-14T00:00:00Z"), XSD.date("2000-02-15+01:00")}) # end # # test "when equal" do # assert_equal({XSD.datetime("2000-01-15T00:00:00"), XSD.date("2000-01-15")}) # assert_equal({XSD.datetime("2000-01-15T00:00:00Z"), XSD.date("2000-01-15Z")}) # assert_equal({XSD.datetime("2000-01-15T00:00:00Z"), XSD.date("2000-01-15+00:00")}) # assert_equal({XSD.datetime("2000-01-15T00:00:00Z"), XSD.date("2000-01-15-00:00")}) # end # # test "when indeterminate" do # assert_indeterminate({XSD.datetime("2000-01-15T00:00:00"), XSD.date("2000-01-15Z")}) # assert_indeterminate({XSD.datetime("2000-01-15T00:00:00Z"), XSD.date("2000-01-15")}) # end # end describe "XSD.Time" do test "when unequal" do assert_order({XSD.time("12:00:00+01:00"), XSD.time("13:00:00+01:00")}) assert_order({XSD.time("12:00:00"), XSD.time("13:00:00")}) assert_order({CustomTime.new("12:00:00"), CustomTime.new("13:00:00")}) end test "when equal" do assert_equal({XSD.time("12:00:00+01:00"), XSD.time("12:00:00+01:00")}) assert_equal({XSD.time("12:00:00"), XSD.time("12:00:00")}) assert_equal({CustomTime.new("12:00:00+01:00"), XSD.time("12:00:00+01:00")}) end # TODO: # test "when indeterminate" do # assert_indeterminate({XSD.time("12:00:00Z"), XSD.time("12:00:00")}) # assert_indeterminate({XSD.time("12:00:00+00:00"), XSD.time("12:00:00")}) # assert_indeterminate({XSD.time("12:00:00-00:00"), XSD.time("12:00:00")}) # end end describe "incomparable" do test "when comparing incomparable types" do Enum.each( [ {XSD.string("true"), XSD.true()}, {XSD.string("42"), XSD.integer(42)}, {XSD.string("3.14"), XSD.decimal(3.14)}, {XSD.string("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T12:00:00")}, {XSD.string("2002-04-02"), XSD.date("2002-04-02")}, {XSD.string("12:00:00"), XSD.time("12:00:00")}, {XSD.true(), XSD.integer(42)}, {XSD.true(), XSD.decimal(3.14)}, {XSD.datetime("2002-04-02T12:00:00"), XSD.true()}, {XSD.datetime("2002-04-02T12:00:00"), XSD.integer(42)}, {XSD.datetime("2002-04-02T12:00:00"), XSD.decimal(3.14)}, {XSD.date("2002-04-02"), XSD.true()}, {XSD.date("2002-04-02"), XSD.integer(42)}, {XSD.date("2002-04-02"), XSD.decimal(3.14)}, {XSD.time("12:00:00"), XSD.true()}, {XSD.time("12:00:00"), XSD.integer(42)}, {XSD.time("12:00:00"), XSD.decimal(3.14)} ], &assert_incomparable/1 ) end test "when comparing invalid literals" do Enum.each( [ {XSD.true(), XSD.boolean(42)}, {XSD.false(), Age.new(242)}, {XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002.04.02 12:00")}, {XSD.date("2002-04-02"), XSD.date("2002.04.02")}, {XSD.time("12:00:00"), XSD.time("12-00-00")} ], &assert_incomparable/1 ) end end defp assert_order({left, right}) do assert_compare_result({left, right}, :lt) assert_compare_result({right, left}, :gt) assert_less_than({left, right}, true) assert_less_than({right, left}, false) assert_greater_than({left, right}, false) assert_greater_than({right, left}, true) end defp assert_equal({left, right}) do assert_compare_result({left, right}, :eq) assert_compare_result({right, left}, :eq) assert_less_than({left, right}, false) assert_less_than({right, left}, false) assert_greater_than({left, right}, false) assert_greater_than({right, left}, false) end defp assert_incomparable({left, right}) do assert_compare_result({left, right}, nil) assert_compare_result({right, left}, nil) assert_greater_than({left, right}, false) assert_greater_than({right, left}, false) assert_less_than({left, right}, false) assert_less_than({right, left}, false) end defp assert_indeterminate({left, right}) do assert_compare_result({left, right}, :indeterminate) assert_compare_result({right, left}, :indeterminate) assert_greater_than({left, right}, false) assert_greater_than({right, left}, false) assert_less_than({left, right}, false) assert_less_than({right, left}, false) end defp assert_compare_result({left, right}, expected) do result = RDF.Literal.compare(left, right) assert result == expected, """ expected RDF.Literal.compare( #{inspect(left)}, #{inspect(right)}) to be: #{inspect(expected)} but got: #{inspect(result)} """ end defp assert_less_than({left, right}, expected) do result = RDF.Literal.less_than?(left, right) assert result == expected, """ expected RDF.Literal.less_than?( #{inspect(left)}, #{inspect(right)}) to be: #{inspect(expected)} but got: #{inspect(result)} """ end defp assert_greater_than({left, right}, expected) do result = RDF.Literal.greater_than?(left, right) assert result == expected, """ expected RDF.Literal.greater_than?( #{inspect(left)}, #{inspect(right)}) to be: #{inspect(expected)} but got: #{inspect(result)} """ end end