From db22c1f9ca4992b653ec310b1bceb392a1e9e8ac Mon Sep 17 00:00:00 2001 From: Marco Hutter Date: Sat, 7 Oct 2023 23:38:36 +0200 Subject: [PATCH] Add validation for metadata entity value ranges --- .../metadata/MetadataEntityValidator.ts | 121 +++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/src/validation/metadata/MetadataEntityValidator.ts b/src/validation/metadata/MetadataEntityValidator.ts index 9cd8bd30..1801b694 100644 --- a/src/validation/metadata/MetadataEntityValidator.ts +++ b/src/validation/metadata/MetadataEntityValidator.ts @@ -1,5 +1,11 @@ import { defined } from "3d-tiles-tools"; import { defaultValue } from "3d-tiles-tools"; +import { ArrayValues } from "3d-tiles-tools"; +import { ClassProperties } from "3d-tiles-tools"; +import { ClassProperty } from "3d-tiles-tools"; +import { MetadataValues } from "3d-tiles-tools"; +import { Schema } from "3d-tiles-tools"; +import { MetadataEntity } from "3d-tiles-tools"; import { ValidationContext } from "../ValidationContext"; import { BasicValidator } from "../BasicValidator"; @@ -8,9 +14,9 @@ import { ExtendedObjectsValidators } from "../ExtendedObjectsValidators"; import { MetadataStructureValidator } from "./MetadataStructureValidator"; import { MetadataValueValidator } from "./MetadataValueValidator"; +import { MetadataValuesValidationMessages } from "./MetadataValueValidationMessages"; -import { Schema } from "3d-tiles-tools"; -import { MetadataEntity } from "3d-tiles-tools"; +import { MetadataValidationIssues } from "../../issues/MetadataValidationIssues"; /** * A class for validations related to `metadataEntity` objects. @@ -129,6 +135,117 @@ export class MetadataEntityValidator { } } } + + // If everything seemed to be valid until now, validate + // the metadata entity values + if (result) { + // Validate each property + for (const propertyName of validPropertyNames) { + const propertyPath = path + "/" + propertyName; + const classProperty = classProperties[propertyName]; + const rawPropertyValue = validProperties[propertyName]; + if (defined(rawPropertyValue)) { + if ( + !MetadataEntityValidator.validateMetadataEntityPropertyValue( + propertyPath, + propertyName, + rawPropertyValue, + classProperty, + context + ) + ) { + result = false; + } + } + } + } + + return result; + } + + /** + * Ensure that the given value is valid for the given class property. + * + * This checks whether the value obeys the min/max that have been + * defined in the class property. + * + * @param path - The path for the `ValidationIssue` instances + * @param propertyName - The property name + * @param rawPropertyValue - The raw property value from the JSON, + * without normalization, offset, or scale + * @param classProperty - The class property that describes the + * structure of the property + * @param context - The `ValidationContext` that any issues will be added to + * @returns Whether the given value was valid + */ + private static validateMetadataEntityPropertyValue( + path: string, + propertyName: string, + rawPropertyValue: any, + classProperty: ClassProperty, + context: ValidationContext + ): boolean { + let result = true; + if (ClassProperties.hasNumericType(classProperty)) { + const propertyValue = MetadataValues.processValue( + classProperty, + undefined, + undefined, + rawPropertyValue + ); + + // When the ClassProperty defines a minimum, then the metadata + // values MUST not be smaller than this minimum + if (defined(classProperty.min)) { + const definedMin = classProperty.min; + if (ArrayValues.anyDeepLessThan(propertyValue, definedMin)) { + const valueMessagePart = + MetadataValuesValidationMessages.createValueMessagePart( + rawPropertyValue, + classProperty, + {}, + propertyValue + ); + + const message = + `For property '${propertyName}', the class property ` + + `defines a minimum of ${definedMin}, but the value ` + + `in the metadata entity is ${valueMessagePart}`; + const issue = MetadataValidationIssues.METADATA_VALUE_NOT_IN_RANGE( + path, + message + ); + context.addIssue(issue); + result = false; + } + } + + // When the ClassProperty defines a maximum, then the metadata + // values MUST not be greater than this maximum + if (defined(classProperty.max)) { + const definedMax = classProperty.max; + if (ArrayValues.anyDeepGreaterThan(propertyValue, definedMax)) { + const valueMessagePart = + MetadataValuesValidationMessages.createValueMessagePart( + rawPropertyValue, + classProperty, + {}, + propertyValue + ); + + const message = + `For property '${propertyName}', the class property ` + + `defines a maximum of ${definedMax}, but the value ` + + `in the metadata entity is ${valueMessagePart}`; + const issue = MetadataValidationIssues.METADATA_VALUE_NOT_IN_RANGE( + path, + message + ); + context.addIssue(issue); + result = false; + } + } + } return result; } }