From 9f7c45f9268be50ccd79587a7580f9817794a673 Mon Sep 17 00:00:00 2001 From: Marco De Salvo Date: Mon, 27 May 2024 10:43:55 +0200 Subject: [PATCH] Added RDFMinExclusiveFacet --- .../Model/Facets/RDFMinExclusiveFacetTest.cs | 72 +++++++++++++++++++ RDFSharp.Test/Model/RDFGraphTest.cs | 6 ++ RDFSharp/Model/Facets/RDFMaxExclusiveFacet.cs | 2 +- RDFSharp/Model/Facets/RDFMaxInclusiveFacet.cs | 2 +- RDFSharp/Model/Facets/RDFMinExclusiveFacet.cs | 62 ++++++++++++++++ RDFSharp/Model/RDFModelUtilities.cs | 25 ++++--- 6 files changed, 158 insertions(+), 11 deletions(-) create mode 100644 RDFSharp.Test/Model/Facets/RDFMinExclusiveFacetTest.cs create mode 100644 RDFSharp/Model/Facets/RDFMinExclusiveFacet.cs diff --git a/RDFSharp.Test/Model/Facets/RDFMinExclusiveFacetTest.cs b/RDFSharp.Test/Model/Facets/RDFMinExclusiveFacetTest.cs new file mode 100644 index 00000000..6b8e533d --- /dev/null +++ b/RDFSharp.Test/Model/Facets/RDFMinExclusiveFacetTest.cs @@ -0,0 +1,72 @@ +/* + Copyright 2012-2024 Marco De Salvo + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using RDFSharp.Model; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Linq; + +namespace RDFSharp.Test.Model +{ + [TestClass] + public class RDFMinExclusiveFacetTest + { + #region Tests + [TestMethod] + + public void ShouldCreateMinExclusiveFacet() + { + RDFMinExclusiveFacet facet = new RDFMinExclusiveFacet(6.145); + + Assert.IsNotNull(facet); + Assert.IsTrue(facet.ExclusiveLowerBound == 6.145d); + Assert.IsTrue(facet.URI.IsBlank); + } + + [TestMethod] + + public void ShouldValidateMinExclusiveFacet() + { + RDFMinExclusiveFacet facet = new RDFMinExclusiveFacet(6); + + Assert.IsFalse(facet.Validate("-2.0089")); + Assert.IsFalse(facet.Validate("2.047")); + Assert.IsFalse(facet.Validate(null)); + Assert.IsFalse(facet.Validate(string.Empty)); + Assert.IsTrue(facet.Validate("14.5773")); + Assert.IsFalse(facet.Validate("6")); + Assert.IsFalse(facet.Validate("abcdefgh")); + + RDFMinExclusiveFacet facet0 = new RDFMinExclusiveFacet(-12.45); + Assert.IsFalse(facet0.Validate("-16.2442")); + Assert.IsFalse(facet0.Validate("-12.45")); + Assert.IsTrue(facet0.Validate("-12")); + } + + [TestMethod] + + public void ShouldConvertMinExclusiveFacetToGraph() + { + RDFMinExclusiveFacet facet = new RDFMinExclusiveFacet(6); + RDFGraph graph = facet.ToRDFGraph(); + + Assert.IsNotNull(graph); + Assert.IsTrue(graph.TriplesCount == 1); + Assert.IsTrue(graph.Single().Predicate.Equals(RDFVocabulary.XSD.MIN_EXCLUSIVE)); + Assert.IsTrue(graph.Single().Object.Equals(new RDFTypedLiteral("6", RDFDatatypeRegister.GetDatatype(RDFVocabulary.XSD.DOUBLE.ToString())))); + } + #endregion + } +} \ No newline at end of file diff --git a/RDFSharp.Test/Model/RDFGraphTest.cs b/RDFSharp.Test/Model/RDFGraphTest.cs index 916d2780..6b51f66f 100644 --- a/RDFSharp.Test/Model/RDFGraphTest.cs +++ b/RDFSharp.Test/Model/RDFGraphTest.cs @@ -1832,6 +1832,7 @@ public void ShouldExtractDatatypeDefinitionsFromGraph() RDFDatatype exMaxLength6 = new RDFDatatype(new Uri("ex:maxlength6"), RDFModelEnums.RDFDatatypes.XSD_STRING, [ new RDFMaxLengthFacet(6) ]); RDFDatatype exMaxInclusive6 = new RDFDatatype(new Uri("ex:maxinclusive6"), RDFModelEnums.RDFDatatypes.XSD_DOUBLE, [new RDFMaxInclusiveFacet(6)]); RDFDatatype exMaxExclusive6 = new RDFDatatype(new Uri("ex:maxexclusive6"), RDFModelEnums.RDFDatatypes.XSD_DOUBLE, [new RDFMaxExclusiveFacet(6)]); + RDFDatatype exMinExclusive6 = new RDFDatatype(new Uri("ex:minexclusive6"), RDFModelEnums.RDFDatatypes.XSD_DOUBLE, [new RDFMinExclusiveFacet(6)]); RDFDatatype exPatternEx = new RDFDatatype(new Uri("ex:patternex"), RDFModelEnums.RDFDatatypes.XSD_STRING, [ new RDFPatternFacet("^ex") ]); RDFDatatype exInteger = new RDFDatatype(new Uri("ex:integer"), RDFModelEnums.RDFDatatypes.XSD_INTEGER, null); RDFGraph graph = new RDFGraph() @@ -1840,6 +1841,7 @@ public void ShouldExtractDatatypeDefinitionsFromGraph() .AddDatatype(exMaxLength6) .AddDatatype(exMaxInclusive6) .AddDatatype(exMaxExclusive6) + .AddDatatype(exMinExclusive6) .AddDatatype(exPatternEx) .AddDatatype(exInteger); List datatypes = graph.ExtractDatatypeDefinitions(); @@ -1864,6 +1866,10 @@ public void ShouldExtractDatatypeDefinitionsFromGraph() && dt.TargetDatatype == RDFModelEnums.RDFDatatypes.XSD_DOUBLE && dt.Facets.Single() is RDFMaxExclusiveFacet maxexclusiveFacet && maxexclusiveFacet.ExclusiveUpperBound == 6)); + Assert.IsTrue(datatypes.Any(dt => string.Equals(dt.URI.ToString(), "ex:minexclusive6") + && dt.TargetDatatype == RDFModelEnums.RDFDatatypes.XSD_DOUBLE + && dt.Facets.Single() is RDFMinExclusiveFacet minexclusiveFacet + && minexclusiveFacet.ExclusiveLowerBound == 6)); Assert.IsTrue(datatypes.Any(dt => string.Equals(dt.URI.ToString(), "ex:patternex") && dt.TargetDatatype == RDFModelEnums.RDFDatatypes.XSD_STRING && dt.Facets.Single() is RDFPatternFacet patternFacet diff --git a/RDFSharp/Model/Facets/RDFMaxExclusiveFacet.cs b/RDFSharp/Model/Facets/RDFMaxExclusiveFacet.cs index 497da868..5bfd2cb4 100644 --- a/RDFSharp/Model/Facets/RDFMaxExclusiveFacet.cs +++ b/RDFSharp/Model/Facets/RDFMaxExclusiveFacet.cs @@ -34,7 +34,7 @@ public class RDFMaxExclusiveFacet : RDFFacet #region Ctors /// - /// Builds a facet requiring the given exact MaxExclusive + /// Builds a facet requiring the given exclusive upper bound /// public RDFMaxExclusiveFacet(double exclusiveUpperBound) => ExclusiveUpperBound = exclusiveUpperBound; diff --git a/RDFSharp/Model/Facets/RDFMaxInclusiveFacet.cs b/RDFSharp/Model/Facets/RDFMaxInclusiveFacet.cs index 9ec0ae04..11d21cf0 100644 --- a/RDFSharp/Model/Facets/RDFMaxInclusiveFacet.cs +++ b/RDFSharp/Model/Facets/RDFMaxInclusiveFacet.cs @@ -34,7 +34,7 @@ public class RDFMaxInclusiveFacet : RDFFacet #region Ctors /// - /// Builds a facet requiring the given exact MaxInclusive + /// Builds a facet requiring the given inclusive upper bound /// public RDFMaxInclusiveFacet(double inclusiveUpperBound) => InclusiveUpperBound = inclusiveUpperBound; diff --git a/RDFSharp/Model/Facets/RDFMinExclusiveFacet.cs b/RDFSharp/Model/Facets/RDFMinExclusiveFacet.cs new file mode 100644 index 00000000..2d28eadc --- /dev/null +++ b/RDFSharp/Model/Facets/RDFMinExclusiveFacet.cs @@ -0,0 +1,62 @@ +/* + Copyright 2012-2024 Marco De Salvo + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace RDFSharp.Model +{ + /// + /// RDFMinExclusiveFacet represents a constraint requiring the values of a literal to have a minimum numeric lower bound (excluded) + /// + public class RDFMinExclusiveFacet : RDFFacet + { + #region Properties + /// + /// Minimum numeric lower bound (excluded) required by the facet + /// + public double ExclusiveLowerBound { get; internal set; } + #endregion + + #region Ctors + /// + /// Builds a facet requiring the given exclusive lower bound + /// + public RDFMinExclusiveFacet(double exclusiveLowerBound) + => ExclusiveLowerBound = exclusiveLowerBound; + #endregion + + #region Methods + /// + /// Gives a graph representation of the MinExclusive facet + /// + public override RDFGraph ToRDFGraph() + => new RDFGraph(new List() { + new RDFTriple(URI, RDFVocabulary.XSD.MIN_EXCLUSIVE, new RDFTypedLiteral(Convert.ToString(ExclusiveLowerBound, CultureInfo.InvariantCulture), RDFModelEnums.RDFDatatypes.XSD_DOUBLE)) }); + + /// + /// Validates the given literal value against the MinExclusive facet + /// + public override bool Validate(string literalValue) + { + if (double.TryParse(literalValue, NumberStyles.Integer | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double parseLiteralValue)) + return parseLiteralValue > ExclusiveLowerBound; + return false; + } + #endregion + } +} \ No newline at end of file diff --git a/RDFSharp/Model/RDFModelUtilities.cs b/RDFSharp/Model/RDFModelUtilities.cs index df677ab4..00d88bd5 100644 --- a/RDFSharp/Model/RDFModelUtilities.cs +++ b/RDFSharp/Model/RDFModelUtilities.cs @@ -342,13 +342,6 @@ public static List ExtractDatatypeDefinitions(this RDFGraph graph) targetFacets.Add(new RDFLengthFacet(facetLengthValue)); continue; } - //xsd:maxInclusive - if (graph[facet, RDFVocabulary.XSD.MAX_INCLUSIVE, null, null].FirstOrDefault()?.Object is RDFTypedLiteral facetMaxInclusive - && facetMaxInclusive.HasDecimalDatatype() && double.TryParse(facetMaxInclusive.Value, NumberStyles.Integer | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double facetMaxInclusiveValue)) - { - targetFacets.Add(new RDFMaxInclusiveFacet(facetMaxInclusiveValue)); - continue; - } //xsd:maxExclusive if (graph[facet, RDFVocabulary.XSD.MAX_EXCLUSIVE, null, null].FirstOrDefault()?.Object is RDFTypedLiteral facetMaxExclusive && facetMaxExclusive.HasDecimalDatatype() && double.TryParse(facetMaxExclusive.Value, NumberStyles.Integer | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double facetMaxExclusiveValue)) @@ -356,6 +349,13 @@ public static List ExtractDatatypeDefinitions(this RDFGraph graph) targetFacets.Add(new RDFMaxExclusiveFacet(facetMaxExclusiveValue)); continue; } + //xsd:maxInclusive + if (graph[facet, RDFVocabulary.XSD.MAX_INCLUSIVE, null, null].FirstOrDefault()?.Object is RDFTypedLiteral facetMaxInclusive + && facetMaxInclusive.HasDecimalDatatype() && double.TryParse(facetMaxInclusive.Value, NumberStyles.Integer | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double facetMaxInclusiveValue)) + { + targetFacets.Add(new RDFMaxInclusiveFacet(facetMaxInclusiveValue)); + continue; + } //xsd:maxLength if (graph[facet, RDFVocabulary.XSD.MAX_LENGTH, null, null].FirstOrDefault()?.Object is RDFTypedLiteral facetMaxLength && facetMaxLength.HasDecimalDatatype() && uint.TryParse(facetMaxLength.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint facetMaxLengthValue)) @@ -363,8 +363,15 @@ public static List ExtractDatatypeDefinitions(this RDFGraph graph) targetFacets.Add(new RDFMaxLengthFacet(facetMaxLengthValue)); continue; } - //xsd:minLength - if (graph[facet, RDFVocabulary.XSD.MIN_LENGTH, null, null].FirstOrDefault()?.Object is RDFTypedLiteral facetMinLength + //xsd:minExclusive + if (graph[facet, RDFVocabulary.XSD.MIN_EXCLUSIVE, null, null].FirstOrDefault()?.Object is RDFTypedLiteral facetMinExclusive + && facetMinExclusive.HasDecimalDatatype() && double.TryParse(facetMinExclusive.Value, NumberStyles.Integer | NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out double facetMinExclusiveValue)) + { + targetFacets.Add(new RDFMinExclusiveFacet(facetMinExclusiveValue)); + continue; + } + //xsd:minLength + if (graph[facet, RDFVocabulary.XSD.MIN_LENGTH, null, null].FirstOrDefault()?.Object is RDFTypedLiteral facetMinLength && facetMinLength.HasDecimalDatatype() && uint.TryParse(facetMinLength.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out uint facetMinLengthValue)) { targetFacets.Add(new RDFMinLengthFacet(facetMinLengthValue));