Skip to content

Commit

Permalink
Improved value tests for attributes and properties.
Browse files Browse the repository at this point in the history
  • Loading branch information
CBenghi committed May 5, 2024
1 parent 850abe5 commit 39e1d7f
Show file tree
Hide file tree
Showing 24 changed files with 288 additions and 107 deletions.
1 change: 1 addition & 0 deletions SolutionTooling/BuildingSmartRepoFiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public static IEnumerable<object[]> GetIdsRepositoryTestCaseIdsFiles()
var d = new DirectoryInfo(IdsRepositoryTestcasesPath);
return GetFilesOrEmpty(d, "*.ids");
}

public static IEnumerable<object[]> GetIdsRepositoryTestCaseIfcFiles()
{
// start from current directory and look in relative position for the bs IDS repository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static bool IsValid(string valueString, BaseTypes @base)

## Return Value

TRUE if compatible, false otherwise
TRUE if compatible, FALSE otherwise

## See Also

Expand Down
1 change: 1 addition & 0 deletions ids-lib-documentation/IdsLib.IfcSchema/SchemaInfo.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class SchemaInfo : IEnumerable<ClassInfo>
| [GetAttributeNames](SchemaInfo/GetAttributeNames.md)() | Returns all attribute names in the schema |
| [GetAttributeRelations](SchemaInfo/GetAttributeRelations.md)(…) | Provides information of classes that have an attribute and the form of the relation to it. See for similar function with different return type. |
| [GetAttributesTypes](SchemaInfo/GetAttributesTypes.md)(…) | Returns a distinct enumerable of the backing types of the required attributes, given a set of attribut names |
| [GetAttributesXmlTypes](SchemaInfo/GetAttributesXmlTypes.md)(…) | Returns a distinct enumerable of the backing types of the required attributes, given a set of attribut names |
| [GetEnumerator](SchemaInfo/GetEnumerator.md)() | The default enumerator for the schema returns the classes defined within |
| static [AllAttributes](SchemaInfo/AllAttributes.md) { get; } | The names of all attributes across all schemas. |
| static [AllConcreteClasses](SchemaInfo/AllConcreteClasses.md) { get; } | The names of all concrete classes across known IFC schemas. |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SchemaInfo.GetAttributesXmlTypes method

Returns a distinct enumerable of the backing types of the required attributes, given a set of attribut names

```csharp
public IEnumerable<BaseTypes> GetAttributesXmlTypes(IEnumerable<string> attributeNames)
```

| parameter | description |
| --- | --- |
| attributeNames | The names of the attributes to evaluate |

## Return Value

string names of the types found in the evaluation of the attributes

## See Also

* enum [BaseTypes](../../IdsLib.IdsSchema.XsNodes/XsTypes.BaseTypes.md)
* class [SchemaInfo](../SchemaInfo.md)
* namespace [IdsLib.IfcSchema](../../ids-lib.md)

<!-- DO NOT EDIT: generated by xmldocmd for ids-lib.dll -->
18 changes: 12 additions & 6 deletions ids-lib.codegen/IfcSchema_DocumentationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@ internal static string Execute(Dictionary<string, typeMetadata> dataTypeDictiona
{
var schemas = new string[] { "Ifc2x3", "Ifc4", "Ifc4x3" };

StringBuilder sbDataTypes = new StringBuilder();
var sbDataTypes = new StringBuilder();
foreach (var dataType in dataTypeDictionary.Values.OrderBy(x=>x.Name))
{
var checks = schemas.Select(x => dataType.Schemas.Contains(x) ? "✔️ " : "");
sbDataTypes.AppendLine($"| {dataType.Name,-45} | {string.Join(" | ", checks),-24} | {dataType.XmlBackingType,-21} |");
}


StringBuilder sbXmlTypes = new StringBuilder();
var sbXmlTypes = new StringBuilder();
var xmlTypes = dataTypeDictionary.Values.Select(x => x.XmlBackingType).Where(str => !string.IsNullOrWhiteSpace(str)).Distinct();
foreach (var dataType in xmlTypes.OrderBy(x => x))
{
sbXmlTypes.AppendLine($"| {dataType,-11} |");
var t = XmlSchema_XsTypesGenerator.GetRegexString(dataType).Replace("|", "&#124;");
sbXmlTypes.AppendLine($"| {dataType,-11} | {t,-72} |");
}

var source = stub;
Expand All @@ -49,12 +50,17 @@ Property dataTypes can be set to any values according to the following table.
## XML base types
The list of valid XML base types for the `base` attribute of `xs:restriction` is:
The list of valid XML base types for the `base` attribute of `xs:restriction`, and the associated regex expression to check for the validity of string representation is as follows:
| Base type |
| ----------- |
| Base type | string regex constraint |
| ----------- | ------------------------------------------------------------------------ |
<PlaceHolderXmlTypes>
For example:
- To specify numbers: you must use a dot as the decimal separator, and not use a thousands separator (e.g. `4.2` is valid, but `1.234,5` is invalid). Scientific notation is allowed (e.g. `1e3` to represent `1000`).
- To specify boolean: valid values are `true` or `false`, `0`, or `1`.
## Notes
Please note, this document has been automatically generated via the IDS Audit Tool repository, any changes should be initiated there.
Expand Down
4 changes: 4 additions & 0 deletions ids-lib.codegen/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ static void Main()
IfcSchema_DocumentationGenerator.Execute(dataTypeDictionary),
@"ids-lib.codegen\buildingSMART\DataTypes.md") | GeneratedContentChanged;

GeneratedContentChanged = EvaluateContentChanged(
XmlSchema_XsTypesGenerator.Execute(dataTypeDictionary),
@"ids-lib\IdsSchema\XsNodes\XsTypes.g.cs") | GeneratedContentChanged;

GeneratedContentChanged = EvaluateContentChanged(
IfcSchema_ClassGenerator.Execute(),
@"ids-lib\IfcSchema\SchemaInfo.Schemas.g.cs") | GeneratedContentChanged;
Expand Down
61 changes: 61 additions & 0 deletions ids-lib.codegen/XmlSchema_XsTypesGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IdsLib.codegen
{
internal class XmlSchema_XsTypesGenerator
{
internal static string Execute(Dictionary<string, typeMetadata> dataTypeDictionary)
{
var sbXmlTypes = new StringBuilder();
var xmlTypes = dataTypeDictionary.Values.Select(x => x.XmlBackingType).Where(str => !string.IsNullOrWhiteSpace(str)).Distinct();
foreach (var dataType in xmlTypes.OrderBy(x => x))
{
var t = XmlSchema_XsTypesGenerator.GetRegexString(dataType);
if (string.IsNullOrWhiteSpace(t))
continue;
var name = dataType.Replace("xs:", "");
name = name[..1].ToUpper() + name[1..];
sbXmlTypes.AppendLine($"\t\tprivate readonly static Regex regex{name} = new(@\"{t}\", RegexOptions.Compiled);");
}

var source = stub;
source = source.Replace($"<PlaceHolderXmlRegexes>", sbXmlTypes.ToString().TrimEnd('\r', '\n'));
return source;
}

internal static string GetRegexString(string dataType)
{
return dataType switch
{
"xs:boolean" => @"^(true|false|0|1)$",
"xs:date" => @"^\d{4}-\d{2}-\d{2}(Z|([+-]\d{2}:\d{2}))?$",
"xs:dateTime" => @"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|([+-]\d{2}:\d{2}))?$",
"xs:double" => @"^([-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?|NaN|\+INF|-INF)$",
"xs:duration" => @"^[-+]?P(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$",
"xs:integer" => @"^[+-]?(\d+)$",
"xs:string" => @"^.?$",
"xs:time" => @"^\d{2}:\d{2}:\d{2}(\.\d+)?(Z|([+-]\d{2}:\d{2}))?$",
_ => ""
};
}

private const string stub = @"// <auto-generated/>
// This code was automatically generated.
// Any changes made to this file will be lost.
using System.Text.RegularExpressions;
namespace IdsLib.IdsSchema.XsNodes
{
public static partial class XsTypes
{
<PlaceHolderXmlRegexes>
}
}
";
}
}
27 changes: 16 additions & 11 deletions ids-lib.codegen/buildingSMART/DataTypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,18 +403,23 @@ Columns of the table determine the validity of the type depending on the schema

## XML base types

The list of valid XML base types for the `base` attribute of `xs:restriction` is:
The list of valid XML base types for the `base` attribute of `xs:restriction`, and the associated regex expression to check for the validity of string representation is as follows:

| Base type |
| ----------- |
| xs:boolean |
| xs:date |
| xs:dateTime |
| xs:double |
| xs:duration |
| xs:integer |
| xs:string |
| xs:time |
| Base type | string regex constraint |
| ----------- | ------------------------------------------------------------------------ |
| xs:boolean | ^(true&#124;false&#124;0&#124;1)$ |
| xs:date | ^\d{4}-\d{2}-\d{2}(Z&#124;([+-]\d{2}:\d{2}))?$ |
| xs:dateTime | ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z&#124;([+-]\d{2}:\d{2}))?$ |
| xs:double | ^([-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?&#124;NaN&#124;\+INF&#124;-INF)$ |
| xs:duration | ^[-+]?P(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$ |
| xs:integer | ^[+-]?(\d+)$ |
| xs:string | ^.?$ |
| xs:time | ^\d{2}:\d{2}:\d{2}(\.\d+)?(Z&#124;([+-]\d{2}:\d{2}))?$ |

For example:

- To specify numbers: you must use a dot as the decimal separator, and not use a thousands separator (e.g. `4.2` is valid, but `1.234,5` is invalid). Scientific notation is allowed (e.g. `1e3` to represent `1000`).
- To specify boolean: valid values are `true` or `false`, `0`, or `1`.

## Notes

Expand Down
1 change: 1 addition & 0 deletions ids-lib/ErrorCodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
| 305 | Invalid Constraint Value |
| 306 | Schema validation error |
| 307 | Schema validation warning |
| 308 | Invalid facet type for xs:restriction |
| 400 | Ifc errors |
| 401 | Reserved prefix |
| 500 | Application errors |
Expand Down
21 changes: 13 additions & 8 deletions ids-lib/IdsSchema/IdsNodes/Facets/IdsAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using IdsLib.IdsSchema.Cardinality;
using IdsLib.IdsSchema.XsNodes;
using IdsLib.IfcSchema;
using IdsLib.IfcSchema.TypeFilters;
using IdsLib.Messages;
Expand Down Expand Up @@ -78,32 +79,36 @@ internal protected override Audit.Status PerformAudit(AuditStateInformation stat
{
// if a value is defined then the type must be value type
// we can also check that any value constraint matches the expected type
var possibleTypes = schema.GetAttributesTypes(matchingAttributeNames).ToList();
if (!possibleTypes.Any())
var possibleAttributeTypes = schema.GetAttributesTypes(matchingAttributeNames).ToList();
if (!possibleAttributeTypes.Any())
{
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"no valid base type exists", schema);
}
else if (possibleTypes.Count == 1)
else if (possibleAttributeTypes.Count == 1)
{
var expected = possibleTypes.First();
if (value.HasXmlBaseType(out var baseType))
var expected = possibleAttributeTypes.First();
if (value.HasXmlBaseType(out var baseType)) // this is an xml constraint
{
if (!possibleTypes.Contains(baseType))
if (!possibleAttributeTypes.Contains(baseType))
{
if (string.IsNullOrEmpty(baseType))
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"found empty but expected `{expected}`", schema);
else
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"found `{baseType}` but expected `{expected}`", schema);
}
}
else if (value.HasSimpleValue(out var simpleValueString))
{
ret |= XsTypes.AuditStringValue(logger, XsTypes.GetBaseFrom(expected), simpleValueString, value);
}
}
else
{
if (value.HasXmlBaseType(out var baseType))
{
if (!possibleTypes.Contains(baseType))
if (!possibleAttributeTypes.Contains(baseType))
{
string expected = string.Join(", ", possibleTypes);
string expected = string.Join(", ", possibleAttributeTypes);
if (string.IsNullOrEmpty(baseType))
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"found empty but expected a close list ({expected})", schema);
else
Expand Down
23 changes: 16 additions & 7 deletions ids-lib/IdsSchema/IdsNodes/Facets/IdsProperty.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using IdsLib.IdsSchema.Cardinality;
using IdsLib.IdsSchema.XsNodes;
using IdsLib.IfcSchema;
using IdsLib.IfcSchema.TypeFilters;
using IdsLib.Messages;
Expand Down Expand Up @@ -157,16 +158,24 @@ internal protected override Audit.Status PerformAudit(AuditStateInformation stat
{
if (SchemaInfo.TryParseIfcDataType(dtMatch, out var fnd, false))
{
if (!string.IsNullOrEmpty(fnd.BackingType) && value is not null && value.HasXmlBaseType(out var baseType))
if (!string.IsNullOrEmpty(fnd.BackingType) && value is not null)
{
if (fnd.BackingType != baseType)
if (value.HasXmlBaseType(out var baseType))
{
if (string.IsNullOrEmpty(baseType))
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"found empty but expected `{fnd.BackingType}` for `{fnd.IfcDataTypeClassName}`", schema);
else
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"found `{baseType}` but expected `{fnd.BackingType}` for `{fnd.IfcDataTypeClassName}`", schema);
if (fnd.BackingType != baseType)
{
if (string.IsNullOrEmpty(baseType))
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"found empty but expected `{fnd.BackingType}` for `{fnd.IfcDataTypeClassName}`", schema);
else
ret |= IdsErrorMessages.Report303RestrictionBadType(logger, value, $"found `{baseType}` but expected `{fnd.BackingType}` for `{fnd.IfcDataTypeClassName}`", schema);
}
}
else if (value.HasSimpleValue(out var simpleValueString))
{
ret |= XsTypes.AuditStringValue(logger, XsTypes.GetBaseFrom(fnd.BackingType!), simpleValueString, value);
}
}

}
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions ids-lib/IdsSchema/IdsXmlNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,16 @@ internal bool HasXmlBaseType([NotNullWhen(true)]out string? baseType)
baseType = rest.BaseAsString;
return true;
}

internal bool HasSimpleValue([NotNullWhen(true)] out string? simpleValueString)
{
var rest = GetChildNode<IdsSimpleValue>("simpleValue");
if (rest is null)
{
simpleValueString = null;
return false;
}
simpleValueString = rest.Value;
return true;
}
}
40 changes: 2 additions & 38 deletions ids-lib/IdsSchema/XsNodes/XsEnumeration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,50 +43,14 @@ public bool TryMatch(IEnumerable<string> candidateStrings, bool ignoreCase, out
return matches.Any();
}



public string Value => value;

protected internal override Audit.Status PerformAudit(AuditStateInformation stateInfo, ILogger? logger)
{
Audit.Status ret = Audit.Status.Ok;
if (!TryGetUpperNode<XsRestriction>(logger, this, XsRestriction.RestrictionIdentificationArray, out var restriction, out var retStatus))
return retStatus;

switch (restriction.Base)
{
case XsTypes.BaseTypes.XsAnyUri: // todo: implement Uri value filter
case XsTypes.BaseTypes.Invalid: // notified in the the restriction already, do nothing here
case XsTypes.BaseTypes.Undefined: // todo: to be discussed in group
case XsTypes.BaseTypes.XsString: // nothing
break;
case XsTypes.BaseTypes.XsBoolean:
if (value != "false" && value != "true")
ret |= IdsErrorMessages.Report305BadConstraintValue(logger, this, value, restriction.Base);
break;
case XsTypes.BaseTypes.XsInteger:
if (!XsTypes.IsValid(value, restriction.Base))
ret |= IdsErrorMessages.Report305BadConstraintValue(logger, this, value, restriction.Base);
break;
case XsTypes.BaseTypes.XsDouble:
case XsTypes.BaseTypes.XsFloat:
case XsTypes.BaseTypes.XsDecimal:
if (!XsTypes.IsValid(value, restriction.Base))
ret |= IdsErrorMessages.Report305BadConstraintValue(logger, this, value, restriction.Base);
break;
case XsTypes.BaseTypes.XsDuration:
case XsTypes.BaseTypes.XsDateTime:
case XsTypes.BaseTypes.XsDate:
case XsTypes.BaseTypes.XsTime:
if (!XsTypes.IsValid(value, restriction.Base))
ret |= IdsErrorMessages.Report305BadConstraintValue(logger, this, value, restriction.Base);
break;


default:
ret |= IdsErrorMessages.Report501UnexpectedScenario(logger, $"type evaluation not implemented for `{restriction.Base}`", this);
break;
}
return ret;
ret |= XsTypes.AuditStringValue(logger, restriction.Base, value, this);
return ret;
}
}
Loading

0 comments on commit 39e1d7f

Please sign in to comment.