From ab2e92266382243081f4d4a8382eaa2626717960 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 29 Nov 2024 13:35:09 +0100 Subject: [PATCH 01/43] Inital commit of application profile validation --- .github/workflows/tests.yml | 29 ++ .gitignore | 2 + Build/Test/UnitTests.xml | 31 ++ Build/Test/docker-compose.yml | 162 ++++++++ Build/Test/runTests.sh | 349 ++++++++++++++++++ .../AdministrativeMetadataValidator.php | 67 ++++ .../ApplicationProfileBaseValidator.php | 26 ++ .../ApplicationProfileValidationStack.php | 18 + .../Validation/LogicalStructureValidator.php | 87 +++++ .../Validation/PhysicalStructureValidator.php | 43 +++ Tests/Fixtures/mets.xml | 122 ++++++ .../ApplicationProfileValidatorTest.php | 44 +++ .../LogicalStructureValidatorTest.php | 30 ++ composer.json | 16 + 14 files changed, 1026 insertions(+) create mode 100644 .github/workflows/tests.yml create mode 100644 Build/Test/UnitTests.xml create mode 100644 Build/Test/docker-compose.yml create mode 100644 Build/Test/runTests.sh create mode 100644 Classes/Validation/AdministrativeMetadataValidator.php create mode 100644 Classes/Validation/ApplicationProfileBaseValidator.php create mode 100644 Classes/Validation/ApplicationProfileValidationStack.php create mode 100644 Classes/Validation/LogicalStructureValidator.php create mode 100644 Classes/Validation/PhysicalStructureValidator.php create mode 100644 Tests/Fixtures/mets.xml create mode 100644 Tests/Unit/Validation/ApplicationProfileValidatorTest.php create mode 100644 Tests/Unit/Validation/LogicalStructureValidatorTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..c859552c0 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,29 @@ +name: Unit Testing + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + test: + name: TYPO3 + runs-on: ubuntu-latest + strategy: + matrix: + typo3: [ 10.4, 11.5 ] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: Build/Test/runTests.sh -s composerInstall -t ${{ matrix.typo3 }} + + - name: Run unit tests + run: Build/Test/runTests.sh -s unit + + - name: Upload coverage reports + uses: codecov/codecov-action@v4 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 4c5f4df22..2714fd7d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ +.cache .idea/ .vscode/ .DS_Store node_modules *.css.map +Build/Test/.env Documentation-GENERATED-temp/ public/ vendor/ diff --git a/Build/Test/UnitTests.xml b/Build/Test/UnitTests.xml new file mode 100644 index 000000000..e9811e4a5 --- /dev/null +++ b/Build/Test/UnitTests.xml @@ -0,0 +1,31 @@ + + + + + ../../Tests/Unit/ + + + + + + + diff --git a/Build/Test/docker-compose.yml b/Build/Test/docker-compose.yml new file mode 100644 index 000000000..706f471b1 --- /dev/null +++ b/Build/Test/docker-compose.yml @@ -0,0 +1,162 @@ +# Adopted/reduced from https://github.com/TYPO3/typo3/blob/608f238a8b7696a49a47e1e73ce8e2845455f0f5/Build/testing-docker/local/docker-compose.yml + +services: + mysql: + image: docker.io/mysql:${MYSQL_VERSION} + environment: + MYSQL_ROOT_PASSWORD: funcp + tmpfs: + - /var/lib/mysql/:rw,noexec,nosuid + + mariadb: + image: docker.io/mariadb:${MARIADB_VERSION} + environment: + MYSQL_ROOT_PASSWORD: funcp + tmpfs: + - /var/lib/mysql/:rw,noexec,nosuid + + web: + image: docker.io/typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}:${HOST_GID}" + stop_grace_period: 1s + volumes: + - ${EXTENSIONS_ROOT}:/var/www/extensions/ + - ${DFGVIEWER_ROOT}:${DFGVIEWER_ROOT} + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "${SERVER_PORT}:${SERVER_PORT}" + # NOTE: For testing PageViewProxy, we need another web server web:8001 that + # can be requested from TYPO3 running on web:${SERVER_PORT}. + # Setting PHP_CLI_SERVER_WORKERS wouldn't seem to work consistently. + command: > + /bin/sh -c " + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + php -S web:${SERVER_PORT} -t ${DFGVIEWER_ROOT} ${DFGVIEWER_ROOT}/Tests/routeFunctionalInstance.php & + php -S web:8001 -t ${DFGVIEWER_ROOT} + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + php -S web:${SERVER_PORT} -t ${DFGVIEWER_ROOT} ${DFGVIEWER_ROOT}/Tests/routeFunctionalInstance.php & + php -S web:8001 -t ${DFGVIEWER_ROOT} + fi + " + solr: + image: docker.io/solr:9 + volumes: + - ${DFGVIEWER_ROOT}/Configuration/ApacheSolr/configsets:/var/solr/data/configsets + - ./solr/modules/ocrsearch:/opt/solr/modules/ocrsearch + ports: + - 8983:8983 + user: root # run as root to change the permissions of the solr folder + # Change permissions of the solr folder, create a default core and start solr as solr user + command: /bin/sh -c " + chown -R 8983:8983 /var/solr + && runuser -u solr -- solr-precreate default-core + " + composer_install: + image: docker.io/typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}:${HOST_GID}" + volumes: + - ${EXTENSIONS_ROOT}:/var/www/extensions/ + - ${DFGVIEWER_ROOT}:${DFGVIEWER_ROOT} + working_dir: ${DFGVIEWER_ROOT} + environment: + COMPOSER_CACHE_DIR: ".cache/composer" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + composer require "kitodo/presentation:@dev" + if [ -z ${TYPO3_VERSION} ]; then + composer install --no-progress --no-interaction; + else + composer update --with=typo3/cms-core:^${TYPO3_VERSION} --no-progress --no-interaction; + fi + " + functional: + image: docker.io/typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + links: + - ${DBMS} + - web + - solr + user: "${HOST_UID}:${HOST_GID}" + volumes: + - ${EXTENSIONS_ROOT}:/var/www/extensions/ + - ${DFGVIEWER_ROOT}:${DFGVIEWER_ROOT} + environment: + typo3DatabaseDriver: "${DATABASE_DRIVER}" + typo3DatabaseName: func_test + typo3DatabaseUsername: root + typo3DatabasePassword: funcp + typo3DatabaseHost: ${DBMS} + working_dir: ${DFGVIEWER_ROOT} + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + echo Waiting for database start...; + while ! nc -z ${DBMS} 3306; do + sleep 1; + done; + echo Database is up; + echo Waiting for Solr start...; + while ! nc -z solr 8983; do + sleep 1; + done; + echo Solr is up; + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP' + if [ ${PHPUNIT_WATCH} -eq 0 ]; then + PHPUNIT_BIN=\"vendor/bin/phpunit\" + else + PHPUNIT_BIN=\"vendor/bin/phpunit-watcher watch\" + fi + COMMAND=\"$${PHPUNIT_BIN} -c Build/Test/FunctionalTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}\" + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" $${COMMAND}; + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + $${COMMAND}; + fi + " + unit: + image: docker.io/typo3/core-testing-${DOCKER_PHP_IMAGE}:latest + user: "${HOST_UID}:${HOST_GID}" + volumes: + - ${EXTENSIONS_ROOT}:/var/www/extensions/ + - ${DFGVIEWER_ROOT}:${DFGVIEWER_ROOT} + working_dir: ${DFGVIEWER_ROOT} + extra_hosts: + - "host.docker.internal:host-gateway" + command: > + /bin/sh -c " + if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x + fi + php -v | grep '^PHP' + if [ ${PHPUNIT_WATCH} -eq 0 ]; then + PHPUNIT_BIN=\"vendor/bin/phpunit\" + else + PHPUNIT_BIN=\"vendor/bin/phpunit-watcher watch\" + fi + if [ ${PHP_XDEBUG_ON} -eq 0 ]; then + XDEBUG_MODE=\"off\" \ + $${PHPUNIT_BIN} -c Build/Test/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + else + XDEBUG_MODE=\"debug,develop\" \ + XDEBUG_TRIGGER=\"foo\" \ + XDEBUG_CONFIG=\"client_port=${PHP_XDEBUG_PORT} client_host=host.docker.internal\" \ + $${PHPUNIT_BIN} -c Build/Test/UnitTests.xml ${EXTRA_TEST_OPTIONS} ${TEST_FILE}; + fi + " diff --git a/Build/Test/runTests.sh b/Build/Test/runTests.sh new file mode 100644 index 000000000..4ef03e685 --- /dev/null +++ b/Build/Test/runTests.sh @@ -0,0 +1,349 @@ +#!/usr/bin/env bash + +# Adopted/reduced from https://github.com/TYPO3/typo3/blob/f6d73fea5a8f3a5cd8537e29308f18bec65a0c92/Build/Scripts/runTests.sh + +# Function to write a .env file in Build/Test +# This is read by docker compose and vars defined here are +# used in Build/Test/docker-compose.yml +setUpDockerComposeDotEnv() { + # Delete possibly existing local .env file if exists + [ -e .env ] && rm .env + # Set up a new .env file for docker compose + { + echo "COMPOSE_PROJECT_NAME=dfgviewer_testing" + # To prevent access rights of files created by the testing, the docker image later + # runs with the same user that is currently executing the script. docker compose can't + # use $UID directly itself since it is a shell variable and not an env variable, so + # we have to set it explicitly here. + echo "HOST_UID=$(id -u)" + echo "HOST_GID=$(id -g)" + # Your local user + echo "DFGVIEWER_ROOT=${DFGVIEWER_ROOT}" + echo "EXTENSIONS_ROOT=$(dirname "$DFGVIEWER_ROOT")" + echo "HOST_USER=${USER}" + echo "TYPO3_VERSION=${TYPO3_VERSION}" + echo "TEST_FILE=${TEST_FILE}" + echo "PHP_XDEBUG_ON=${PHP_XDEBUG_ON}" + echo "PHP_XDEBUG_PORT=${PHP_XDEBUG_PORT}" + echo "SERVER_PORT=${SERVER_PORT}" + echo "DOCKER_PHP_IMAGE=${DOCKER_PHP_IMAGE}" + echo "EXTRA_TEST_OPTIONS=${EXTRA_TEST_OPTIONS}" + echo "SCRIPT_VERBOSE=${SCRIPT_VERBOSE}" + echo "PHPUNIT_WATCH=${PHPUNIT_WATCH}" + echo "DBMS=${DBMS}" + echo "DATABASE_DRIVER=${DATABASE_DRIVER}" + echo "MARIADB_VERSION=${MARIADB_VERSION}" + echo "MYSQL_VERSION=${MYSQL_VERSION}" + echo "PHP_VERSION=${PHP_VERSION}" + } > .env +} + +# Options -a and -d depend on each other. The function +# validates input combinations and sets defaults. +handleDbmsAndDriverOptions() { + case ${DBMS} in + mysql|mariadb) + [ -z "${DATABASE_DRIVER}" ] && DATABASE_DRIVER="mysqli" + if [ "${DATABASE_DRIVER}" != "mysqli" ] && [ "${DATABASE_DRIVER}" != "pdo_mysql" ]; then + echo "Invalid option -a ${DATABASE_DRIVER} with -d ${DBMS}" >&2 + echo >&2 + echo "call \".Build/Test/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + fi + ;; + esac +} + +# Load help text into $HELP +read -r -d '' HELP <=20.10 for xdebug break pointing to work reliably, and +a recent docker compose (tested >=2.27.1) is needed. +Usage: $0 [options] [file] +No arguments: Run all unit tests with PHP 7.4 +Options: + -s <...> + Specifies which test suite to run + - composerInstall: "composer install" + - functional: PHP functional tests + - unit (default): PHP unit tests + -t <|10.4|11.5> + Only with -s composerInstall + Specifies which TYPO3 version to install. When unset, installs either the packages from + composer.lock, or the latest version otherwise (default behavior of "composer install"). + - 10.4 + - 11.5 + -a + Only with -s functional + Specifies to use another driver, following combinations are available: + - mysql + - mysqli (default) + - pdo_mysql + - mariadb + - mysqli (default) + - pdo_mysql + -d + Only with -s functional + Specifies on which DBMS tests are performed + - mariadb (default): use mariadb + - mysql: use MySQL server + -i <10.1|10.2|10.3|10.4|10.5|10.6|10.7|10.8|10.9|10.10> + Only with -d mariadb + Specifies on which version of mariadb tests are performed + - 10.1 + - 10.2 + - 10.3 (default) + - 10.4 + - 10.5 + - 10.6 + - 10.7 + - 10.8 + - 10.9 + - 10.10 + -j <5.5|5.6|5.7|8.0> + Only with -d mysql + Specifies on which version of mysql tests are performed + - 5.5 (default) + - 5.6 + - 5.7 + - 8.0 + -p <7.4|8.0|8.1|8.2> + Specifies the PHP minor version to be used + - 7.4: (default) use PHP 7.4 + - 8.0: use PHP 8.0 + - 8.1: use PHP 8.1 + - 8.2: use PHP 8.2 (note that xdebug is currently not available for PHP8.2) + -e "" + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance + Additional options to send to phpunit (unit & functional tests) or codeception (acceptance + tests). For phpunit, options starting with "--" must be added after options starting with "-". + Example -e "-v --filter canRetrieveValueWithGP" to enable verbose output AND filter tests + named "canRetrieveValueWithGP" + -x + Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance|acceptanceInstall + Send information to host instance for test or system under test break points. This is especially + useful if a local PhpStorm instance is listening on default xdebug port 9003. A different port + can be selected with -y + -y + Send xdebug information to a different port than default 9003 if an IDE like PhpStorm + is not listening on default port. + -w + Only with -s functional|unit + Run tests in watch mode. + -u + Update existing typo3/core-testing-*:latest docker images and remove dangling local docker volumes. + Maintenance call to docker pull latest versions of the main php images. The images are updated once + in a while and only the latest ones are supported by core testing. Use this if weird test errors occur. + Also removes obsolete image versions of typo3/core-testing-*. + -v + Enable verbose script output. Shows variables and docker commands. + -h + Show this help. +EOF + +# Go to the directory this script is located, so everything else is relative +# to this dir, no matter from where this script is called. +THIS_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)" +cd "$THIS_SCRIPT_DIR" || exit 1 + +# Go to directory that contains the local docker-compose.yml file +# cd ../testing-docker/local || exit 1 + +# Set root path by checking whether realpath exists +if ! command -v realpath &> /dev/null; then + echo "Consider installing realpath for properly resolving symlinks" >&2 + DFGVIEWER_ROOT="${PWD}/../../" +else + DFGVIEWER_ROOT=$(realpath "${PWD}/../../") +fi + +# Option defaults +TEST_SUITE="unit" +TYPO3_VERSION="" +DBMS="mariadb" +PHP_VERSION="7.4" +PHP_XDEBUG_ON=0 +PHP_XDEBUG_PORT=9003 +SERVER_PORT=8000 +EXTRA_TEST_OPTIONS="" +SCRIPT_VERBOSE=0 +PHPUNIT_WATCH=0 +DATABASE_DRIVER="" +MARIADB_VERSION="10.3" +MYSQL_VERSION="5.5" + +# Option parsing +# Reset in case getopts has been used previously in the shell +OPTIND=1 +# Array for invalid options +INVALID_OPTIONS=(); +# Simple option parsing based on getopts (! not getopt) +while getopts ":a:s:t:d:i:j:p:e:xy:whuv" OPT; do + case ${OPT} in + s) + TEST_SUITE=${OPTARG} + ;; + t) + TYPO3_VERSION=${OPTARG} + ;; + a) + DATABASE_DRIVER=${OPTARG} + ;; + d) + DBMS=${OPTARG} + ;; + i) + MARIADB_VERSION=${OPTARG} + if ! [[ ${MARIADB_VERSION} =~ ^(10.2|10.3|10.4|10.5|10.6|10.11)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + j) + MYSQL_VERSION=${OPTARG} + if ! [[ ${MYSQL_VERSION} =~ ^(5.7|8.0)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + p) + PHP_VERSION=${OPTARG} + if ! [[ ${PHP_VERSION} =~ ^(7.4|8.0|8.1|8.2|8.3)$ ]]; then + INVALID_OPTIONS+=("${OPTARG}") + fi + ;; + e) + EXTRA_TEST_OPTIONS=${OPTARG} + ;; + x) + PHP_XDEBUG_ON=1 + ;; + y) + PHP_XDEBUG_PORT=${OPTARG} + ;; + w) + PHPUNIT_WATCH=1 + ;; + h) + echo "${HELP}" + exit 0 + ;; + u) + TEST_SUITE=update + ;; + v) + SCRIPT_VERBOSE=1 + ;; + \?) + INVALID_OPTIONS+=("${OPTARG}") + ;; + :) + INVALID_OPTIONS+=("${OPTARG}") + ;; + esac +done + +# Exit on invalid options +if [ ${#INVALID_OPTIONS[@]} -ne 0 ]; then + echo "Invalid option(s):" >&2 + for I in "${INVALID_OPTIONS[@]}"; do + echo "-"${I} >&2 + done + echo >&2 + echo "call \".Build/Test/runTests.sh -h\" to display help and valid options" + exit 1 +fi + +# Move "7.4" to "php74", the latter is the docker container name +DOCKER_PHP_IMAGE=$(echo "php${PHP_VERSION}" | sed -e 's/\.//') + +# Set $1 to first mass argument, this is the optional test file or test directory to execute +shift $((OPTIND - 1)) +TEST_FILE=${1} + +if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + set -x +fi + +# Suite execution +case ${TEST_SUITE} in + composerInstall) + setUpDockerComposeDotEnv + docker compose run composer_install + SUITE_EXIT_CODE=$? + docker compose down + ;; + functional) + handleDbmsAndDriverOptions + setUpDockerComposeDotEnv + case ${DBMS} in + mariadb|mysql) + echo "Using driver: ${DATABASE_DRIVER}" + docker compose run functional + SUITE_EXIT_CODE=$? + ;; + *) + echo "Functional tests don't run with DBMS ${DBMS}" >&2 + echo >&2 + echo "call \".Build/Test/runTests.sh -h\" to display help and valid options" >&2 + exit 1 + esac + docker compose down + ;; + unit) + setUpDockerComposeDotEnv + docker compose run unit + SUITE_EXIT_CODE=$? + docker compose down + ;; + update) + # pull typo3/core-testing-*:latest versions of those ones that exist locally + docker images typo3/core-testing-*:latest --format "{{.Repository}}:latest" | xargs -I {} docker pull {} + # remove "dangling" typo3/core-testing-* images (those tagged as ) + docker images typo3/core-testing-* --filter "dangling=true" --format "{{.ID}}" | xargs -I {} docker rmi {} + ;; + *) + echo "Invalid -s option argument ${TEST_SUITE}" >&2 + echo >&2 + echo "${HELP}" >&2 + exit 1 +esac + +case ${DBMS} in + mariadb) + DBMS_OUTPUT="DBMS: ${DBMS} version ${MARIADB_VERSION} driver ${DATABASE_DRIVER}" + ;; + mysql) + DBMS_OUTPUT="DBMS: ${DBMS} version ${MYSQL_VERSION} driver ${DATABASE_DRIVER}" + ;; + *) + DBMS_OUTPUT="DBMS not recognized: $DBMS" + exit 1 +esac + +# Print summary +if [ ${SCRIPT_VERBOSE} -eq 1 ]; then + # Turn off verbose mode for the script summary + set +x +fi +echo "" >&2 +echo "###########################################################################" >&2 +if [[ ${TEST_SUITE} =~ ^(functional)$ ]]; then + echo "Result of ${TEST_SUITE}" >&2 + echo "PHP: ${PHP_VERSION}" >&2 + echo "${DBMS_OUTPUT}" >&2 +else + echo "Result of ${TEST_SUITE}" >&2 + echo "PHP: ${PHP_VERSION}" >&2 +fi + +if [[ ${SUITE_EXIT_CODE} -eq 0 ]]; then + echo "SUCCESS" >&2 +else + echo "FAILURE" >&2 +fi +echo "###########################################################################" >&2 +echo "" >&2 + +# Exit with code of test suite - This script return non-zero if the executed test failed. +exit $SUITE_EXIT_CODE diff --git a/Classes/Validation/AdministrativeMetadataValidator.php b/Classes/Validation/AdministrativeMetadataValidator.php new file mode 100644 index 000000000..6673f88c6 --- /dev/null +++ b/Classes/Validation/AdministrativeMetadataValidator.php @@ -0,0 +1,67 @@ +xpath->query('//mets:structMap[@TYPE="LOGICAL"]')->length == 0) { + $this->addError('Every METS file has to have at least one logical structural element.', 1723727164447); + } + + $this->validateStructuralElements(); + + $this->validateExternalReference(); + } + + /** + * @return void + */ + private function validateStructuralElements(): void + { + $structuralElements = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); + if ($structuralElements->length == 0) { + $this->addError('Every logical structure has to consist of at least on mets:div.', 1724234607); + } else { + foreach ($structuralElements as $structuralElement) { + if (!$structuralElement->hasAttribute("ID")) { + $this->addError('Mandatory "ID" attribute of mets:div in the logical structure is missing.', 1724234607); + } + + if (!$structuralElement->hasAttribute("TYPE")) { + $this->addError('Mandatory "TYPE" attribute of mets:div in the logical structure is missing.', 1724234607); + } else { + if (!in_array($structuralElement->getAttribute("TYPE"), self::STRUCTURE_DATASET)) { + $this->addError('Value "' . $structuralElement->getAttribute("TYPE") . '" of "TYPE" attribute of mets:div in the logical structure is not permissible.', 1724234607); + } + } + } + } + } + + /** + * @return void + */ + private function validateExternalReference(): void + { + $externalReference = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr'); + if ($externalReference->length > 1) { + $this->addError('Every mets:div in the logical structure may only contain one mets:mptr.', 1724234607); + } else if ($externalReference->length == 1) { + if (!$externalReference->hasAttribute("LOCTYPE")) { + $this->addError('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', 1724234607); + } else { + if (!in_array($externalReference->getAttribute("LOCTYPE"), array("URL", "PURL"))) { + $this->addError('Value "' . $externalReference->getAttribute("LOCTYPE") . '" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.', 1724234607); + } + } + + if (!$externalReference->hasAttribute("xlink:href")) { + $this->addError('Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.', 1724234607); + } + } + } +} diff --git a/Classes/Validation/ApplicationProfileBaseValidator.php b/Classes/Validation/ApplicationProfileBaseValidator.php new file mode 100644 index 000000000..5b729191e --- /dev/null +++ b/Classes/Validation/ApplicationProfileBaseValidator.php @@ -0,0 +1,26 @@ +xpath = new DOMXPath($value); + } +} diff --git a/Classes/Validation/ApplicationProfileValidationStack.php b/Classes/Validation/ApplicationProfileValidationStack.php new file mode 100644 index 000000000..377f4a395 --- /dev/null +++ b/Classes/Validation/ApplicationProfileValidationStack.php @@ -0,0 +1,18 @@ +addValidator(LogicalStructureValidator::class, "Specifications for the logical document structure", false); + $this->addValidator(PhysicalStructureValidator::class, "Specifications for the physical document structure", false); + + } +} diff --git a/Classes/Validation/LogicalStructureValidator.php b/Classes/Validation/LogicalStructureValidator.php new file mode 100644 index 000000000..53f6b6ce5 --- /dev/null +++ b/Classes/Validation/LogicalStructureValidator.php @@ -0,0 +1,87 @@ +setUpIsValid($value); + + // Validates against the rules of chapter "2.1.1 Logical structure - mets:structMap" + if ($this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]')->length == 0) { + $this->addError('Every METS file has to have at least one logical structural element.', 1723727164447); + } + + $this->validateStructuralElements(); + + $this->validateExternalReference(); + } + + /** + * Validates the structural elements. + * + * Validates against the rules of chapter "2.1.2.1 Structural element - mets:div" + * + * @return void + */ + private function validateStructuralElements(): void + { + $structuralElements = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); + if ($structuralElements->length == 0) { + $this->addError('Every logical structure has to consist of at least one mets:div.', 1724234607); + } else { + foreach ($structuralElements as $structuralElement) { + if (!$structuralElement->hasAttribute("ID")) { + $this->addError('Mandatory "ID" attribute of mets:div in the logical structure is missing.', 1724234607); + } + if (!$structuralElement->hasAttribute("TYPE")) { + $this->addError('Mandatory "TYPE" attribute of mets:div in the logical structure is missing.', 1724234607); + } else { + if (!in_array($structuralElement->getAttribute("TYPE"), self::STRUCTURE_DATASET)) { + $this->addError('Value "' . $structuralElement->getAttribute("TYPE") . '" of "TYPE" attribute of mets:div in the logical structure is not permissible.', 1724234607); + } + } + } + } + } + + /** + * Validates the external references. + * + * Validates against the rules of chapter "2.1.2.2 Reference to external METS-files - mets:div / mets:mptr" + * + * @return void + */ + private function validateExternalReference(): void + { + $externalReference = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr'); + if ($externalReference->length > 1) { + $this->addError('Every mets:div in the logical structure may only contain one mets:mptr.', 1724234607); + } else if ($externalReference->length == 1) { + if (!$externalReference->hasAttribute("LOCTYPE")) { + $this->addError('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', 1724234607); + } else { + if (!in_array($externalReference->getAttribute("LOCTYPE"), array("URL", "PURL"))) { + $this->addError('Value "' . $externalReference->getAttribute("LOCTYPE") . '" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.', 1724234607); + } + } + if (!$externalReference->hasAttribute("xlink:href")) { + $this->addError('Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.', 1724234607); + } else { + if (!filter_var($externalReference->getAttribute("xlink:href"), FILTER_VALIDATE_URL)) { + $this->addError('URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.', 1727792902); + } + } + + } + } +} diff --git a/Classes/Validation/PhysicalStructureValidator.php b/Classes/Validation/PhysicalStructureValidator.php new file mode 100644 index 000000000..93ee6c8c8 --- /dev/null +++ b/Classes/Validation/PhysicalStructureValidator.php @@ -0,0 +1,43 @@ +xpath->query('//mets:structMap[@TYPE="PHYSICAL"]')->length > 1) { + $this->addError('Every METS file has to have no or one physical structural element.', 1723727164447); + } + + $this->validateStructuralElements(); + } + + + /** + * @return void + */ + private function validateStructuralElements(): void + { + if ($this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="“physSequence"]')->length == 0) { + $this->addError('Every physical structure has to consist one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', 1724234607); + } + + $subordinateStructuralElements = $this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="“physSequence"]/mets:div'); + if ($subordinateStructuralElements->length == 0) { + $this->addError('Every physical structure has to consist one mets:div for the sequence and at least one subordinate mets:div.', 1724234607); + } else { + foreach ($subordinateStructuralElements as $subordinateStructuralElement) { + if (!$subordinateStructuralElement->hasAttribute("TYPE")) { + $this->addError('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', 1724234607); + } else { + if (!in_array($subordinateStructuralElement->getAttribute("TYPE"), array("page", "doublepage", "track"))) { + $this->addError('Value "' . $subordinateStructuralElement->getAttribute("TYPE") . '" of "TYPE" attribute of mets:div in physical structure is not permissible.', 1724234607); + } + } + } + } + } +} diff --git a/Tests/Fixtures/mets.xml b/Tests/Fixtures/mets.xml new file mode 100644 index 000000000..f68332267 --- /dev/null +++ b/Tests/Fixtures/mets.xml @@ -0,0 +1,122 @@ + + + + + + + + "INDIA" + + + none + + + "tecnoarcadia" + + aut + + + + none + + + https://zenodo.org/api/files/df31cc16-0a54-4599-89e9-0dd4ada4016d/b5df7cd550f64e818943ad96fff7e902.glb + + prv + + + + + + + + + + + + + + none + + + + + + + + cre + + + + 0 + 0 + + + + "not available" + none + none + none + + + none + CC-BY + + + INDIA + + + + + + + + + + + 3D Repository + http://dfg-viewer.de/fileadmin/_processed_/a/8/csm_HSM_Logo_T_schwarz_klein_bold_regular_d61a371993.jpg + https://3d-repository.hs-mainz.de/ + https://3d-repository.hs-mainz.de/contact + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php new file mode 100644 index 000000000..b96d9823b --- /dev/null +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -0,0 +1,44 @@ +resetSingletonInstances = true; + } + + protected function initValidator($validator): void + { + $this->validator = $validator; + } + + protected function getDOMDocument(): DOMDocument + { + $doc = new DOMDocument(); + $doc->load(__DIR__ . '/../../Fixtures/mets.xml'); + self::assertNotFalse($doc); + return $doc; + } + + /** + * @param DOMDocument $doc + * @param string $expression + * @return void + */ + protected function removeNodes(DOMDocument $doc, string $expression): void + { + $xpath = new DOMXPath($doc); + foreach ($xpath->evaluate($expression) as $node) { + $node->parentNode->removeChild($node); + } + } +} diff --git a/Tests/Unit/Validation/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/LogicalStructureValidatorTest.php new file mode 100644 index 000000000..5f7c75f7d --- /dev/null +++ b/Tests/Unit/Validation/LogicalStructureValidatorTest.php @@ -0,0 +1,30 @@ +initValidator(new LogicalStructureValidator()); + } + + /** + * @test + */ + public function testLogicalStructure() + { + $doc = $this->getDOMDocument(); + $result = $this->validator->validate($doc); + self::assertFalse($result->hasErrors()); + + $this->removeNodes($doc, '//mets:structMap[@TYPE="LOGICAL"]'); + $result = $this->validator->validate($doc); + self::assertTrue($result->hasErrors()); + } + +} diff --git a/composer.json b/composer.json index 8236b5d41..9c9740207 100644 --- a/composer.json +++ b/composer.json @@ -46,11 +46,21 @@ "kitodo/presentation": "^5.0|dev-master", "slub/slub-digitalcollections": "^4.0|dev-master" }, + "require-dev": { + "phpunit/phpunit": "^9.6.20", + "spatie/phpunit-watcher": "^1.23.6", + "typo3/testing-framework": "^7.1.0" + }, "autoload": { "psr-4": { "Slub\\Dfgviewer\\": "Classes/" } }, + "autoload-dev": { + "psr-4": { + "Kitodo\\Dlf\\Tests\\": "Tests/" + } + }, "extra": { "typo3/cms": { "extension-key": "dfgviewer" @@ -72,6 +82,12 @@ "@composer docs:stop", "@composer docs:build", "@composer docs:start" + ], + "test:unit:local": [ + "phpunit -c Build/Test/UnitTests.xml" + ], + "test:unit:watch": [ + "phpunit-watcher watch -c Build/Test/UnitTests.xml" ] }, "config": { From 770da06188934744cb4f36197dbb6ad5d3010dc2 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 6 Dec 2024 17:42:08 +0100 Subject: [PATCH 02/43] Test logical structure validator and fix some bugs --- Build/Test/UnitTests.xml | 2 +- Build/Test/runTests.sh | 18 ++++ .../Validation/LogicalStructureValidator.php | 7 +- Tests/Fixtures/mets.xml | 2 +- .../ApplicationProfileValidatorTest.php | 89 +++++++++++++++++-- .../LogicalStructureValidatorTest.php | 83 ++++++++++++++--- 6 files changed, 178 insertions(+), 23 deletions(-) diff --git a/Build/Test/UnitTests.xml b/Build/Test/UnitTests.xml index e9811e4a5..3f6bfeceb 100644 --- a/Build/Test/UnitTests.xml +++ b/Build/Test/UnitTests.xml @@ -21,7 +21,7 @@ > - ../../Tests/Unit/ + ../../Tests/Unit diff --git a/Build/Test/runTests.sh b/Build/Test/runTests.sh index 4ef03e685..1d739c9f2 100644 --- a/Build/Test/runTests.sh +++ b/Build/Test/runTests.sh @@ -57,24 +57,31 @@ handleDbmsAndDriverOptions() { # Load help text into $HELP read -r -d '' HELP <=20.10 for xdebug break pointing to work reliably, and a recent docker compose (tested >=2.27.1) is needed. + Usage: $0 [options] [file] + No arguments: Run all unit tests with PHP 7.4 + Options: -s <...> Specifies which test suite to run - composerInstall: "composer install" - functional: PHP functional tests - unit (default): PHP unit tests + -t <|10.4|11.5> Only with -s composerInstall Specifies which TYPO3 version to install. When unset, installs either the packages from composer.lock, or the latest version otherwise (default behavior of "composer install"). - 10.4 - 11.5 + -a Only with -s functional Specifies to use another driver, following combinations are available: @@ -84,11 +91,13 @@ Options: - mariadb - mysqli (default) - pdo_mysql + -d Only with -s functional Specifies on which DBMS tests are performed - mariadb (default): use mariadb - mysql: use MySQL server + -i <10.1|10.2|10.3|10.4|10.5|10.6|10.7|10.8|10.9|10.10> Only with -d mariadb Specifies on which version of mariadb tests are performed @@ -102,6 +111,7 @@ Options: - 10.8 - 10.9 - 10.10 + -j <5.5|5.6|5.7|8.0> Only with -d mysql Specifies on which version of mysql tests are performed @@ -109,36 +119,44 @@ Options: - 5.6 - 5.7 - 8.0 + -p <7.4|8.0|8.1|8.2> Specifies the PHP minor version to be used - 7.4: (default) use PHP 7.4 - 8.0: use PHP 8.0 - 8.1: use PHP 8.1 - 8.2: use PHP 8.2 (note that xdebug is currently not available for PHP8.2) + -e "" Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance Additional options to send to phpunit (unit & functional tests) or codeception (acceptance tests). For phpunit, options starting with "--" must be added after options starting with "-". Example -e "-v --filter canRetrieveValueWithGP" to enable verbose output AND filter tests named "canRetrieveValueWithGP" + -x Only with -s functional|functionalDeprecated|unit|unitDeprecated|unitRandom|acceptance|acceptanceInstall Send information to host instance for test or system under test break points. This is especially useful if a local PhpStorm instance is listening on default xdebug port 9003. A different port can be selected with -y + -y Send xdebug information to a different port than default 9003 if an IDE like PhpStorm is not listening on default port. + -w Only with -s functional|unit Run tests in watch mode. + -u Update existing typo3/core-testing-*:latest docker images and remove dangling local docker volumes. Maintenance call to docker pull latest versions of the main php images. The images are updated once in a while and only the latest ones are supported by core testing. Use this if weird test errors occur. Also removes obsolete image versions of typo3/core-testing-*. + -v Enable verbose script output. Shows variables and docker commands. + -h Show this help. EOF diff --git a/Classes/Validation/LogicalStructureValidator.php b/Classes/Validation/LogicalStructureValidator.php index 53f6b6ce5..fc00d0c4b 100644 --- a/Classes/Validation/LogicalStructureValidator.php +++ b/Classes/Validation/LogicalStructureValidator.php @@ -63,10 +63,11 @@ private function validateStructuralElements(): void */ private function validateExternalReference(): void { - $externalReference = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr'); - if ($externalReference->length > 1) { + $externalReferences = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr'); + if ($externalReferences->length > 1) { $this->addError('Every mets:div in the logical structure may only contain one mets:mptr.', 1724234607); - } else if ($externalReference->length == 1) { + } else if ($externalReferences->length == 1) { + $externalReference = $externalReferences->item(0); if (!$externalReference->hasAttribute("LOCTYPE")) { $this->addError('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', 1724234607); } else { diff --git a/Tests/Fixtures/mets.xml b/Tests/Fixtures/mets.xml index f68332267..91af04e66 100644 --- a/Tests/Fixtures/mets.xml +++ b/Tests/Fixtures/mets.xml @@ -106,7 +106,7 @@ - + diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index b96d9823b..c0badc2e6 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -4,32 +4,66 @@ use DOMDocument; use DOMXPath; +use Kitodo\Dlf\Validation\AbstractDlfValidator; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; abstract class ApplicationProfileValidatorTest extends UnitTestCase { protected $validator; + protected $doc; + + private $originalDoc; + + abstract protected function createValidator(): AbstractDlfValidator; + public function setUp(): void { parent::setUp(); $this->resetSingletonInstances = true; + $this->doc = $this->getDOMDocument(); + $this->originalDoc = $this->doc; + $this->validator = $this->createValidator(); } - protected function initValidator($validator): void + /** + * Validates the document using the validator. + * + * @return void + */ + public function testDocument() { - $this->validator = $validator; + $result = $this->validator->validate($this->doc); + self::assertFalse($result->hasErrors()); } - protected function getDOMDocument(): DOMDocument + protected function resetDoc(): void { - $doc = new DOMDocument(); - $doc->load(__DIR__ . '/../../Fixtures/mets.xml'); - self::assertNotFalse($doc); - return $doc; + $this->doc = $this->getDOMDocument(); } /** + * Remove notes found by node expression in document. + * + * @param DOMDocument $doc + * @param string $expression + * @param string $namespace + * @param string $name + * @return void + * @throws \DOMException + */ + protected function addChildNode(DOMDocument $doc, string $expression, string $namespace, string $name): void + { + $xpath = new DOMXPath($doc); + $newNode = $doc->createElementNS($namespace, $name); + foreach ($xpath->evaluate($expression) as $node) { + $node->appendChild($newNode); + } + } + + /** + * Remove notes found by node expression in document. + * * @param DOMDocument $doc * @param string $expression * @return void @@ -41,4 +75,45 @@ protected function removeNodes(DOMDocument $doc, string $expression): void $node->parentNode->removeChild($node); } } + + /** + * Set value of attribute found by node expression in document. + * + * @param DOMDocument $doc + * @param string $expression + * @param string $attribute + * @param string $value + * @return void + */ + protected function setAttributeValue(DOMDocument $doc, string $expression, string $attribute, string $value): void + { + $xpath = new DOMXPath($doc); + foreach ($xpath->evaluate($expression) as $node) { + $node->setAttribute($attribute, $value); + } + } + + /** + * Remove attribute found by node expression in document. + * + * @param DOMDocument $doc + * @param string $expression + * @param string $attribute + * @return void + */ + protected function removeAttribute(DOMDocument $doc, string $expression, string $attribute): void + { + $xpath = new DOMXPath($doc); + foreach ($xpath->evaluate($expression) as $node) { + $node->removeAttribute($attribute); + } + } + + private function getDOMDocument(): DOMDocument + { + $doc = new DOMDocument(); + $doc->load(__DIR__ . '/../../Fixtures/mets.xml'); + self::assertNotFalse($doc); + return $doc; + } } diff --git a/Tests/Unit/Validation/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/LogicalStructureValidatorTest.php index 5f7c75f7d..71167363e 100644 --- a/Tests/Unit/Validation/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/LogicalStructureValidatorTest.php @@ -2,29 +2,90 @@ namespace Slub\Dfgviewer\Tests\Unit\Validation; +use Kitodo\Dlf\Validation\AbstractDlfValidator; use Slub\Dfgviewer\Validation\LogicalStructureValidator; class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest { - public function setUp(): void + /** + * Test validation against the rules of chapter "2.1.1 Logical structure - mets:structMap" + * + * @return void + */ + public function testNotExistingLogicalStructureElement(): void { - parent::setUp(); - $this->initValidator(new LogicalStructureValidator()); + $this->removeNodes($this->doc, '//mets:structMap[@TYPE="LOGICAL"]'); + $result = $this->validator->validate($this->doc); + self::assertEquals('Every METS file has to have at least one logical structural element.', $result->getFirstError()->getMessage()); } /** - * @test + * Test validation against the rules of chapter "2.1.2.1 Structural element - mets:div" + * @return void */ - public function testLogicalStructure() + public function testStructuralElements(): void { - $doc = $this->getDOMDocument(); - $result = $this->validator->validate($doc); - self::assertFalse($result->hasErrors()); + $this->removeNodes($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div'); + $result = $this->validator->validate($this->doc); + self::assertEquals('Every logical structure has to consist of at least one mets:div.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->removeAttribute($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'ID'); + $result = $this->validator->validate($this->doc); + self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "ID" attribute of mets:div in the logical structure is missing.'); + + $this->resetDoc(); - $this->removeNodes($doc, '//mets:structMap[@TYPE="LOGICAL"]'); - $result = $this->validator->validate($doc); - self::assertTrue($result->hasErrors()); + $this->removeAttribute($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); + $result = $this->validator->validate($this->doc); + self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "TYPE" attribute of mets:div in the logical structure is missing.'); + + $this->resetDoc(); + + $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE', 'Test'); + $result = $this->validator->validate($this->doc); + self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "TYPE" attribute of mets:div in the logical structure is not permissible.'); } + + /** + * Test validation against the rules of chapter "2.1.2.2 Reference to external METS-files - mets:div / mets:mptr" + * @return void + */ + public function testExternalReference(): void + { + $this->addChildNode($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'http://www.loc.gov/METS/', 'mets:mptr'); + $this->addChildNode($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'http://www.loc.gov/METS/', 'mets:mptr'); + $result = $this->validator->validate($this->doc); + self::assertEquals('Every mets:div in the logical structure may only contain one mets:mptr.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->addChildNode($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'http://www.loc.gov/METS/', 'mets:mptr'); + $result = $this->validator->validate($this->doc); + self::assertEquals('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', $result->getFirstError()->getMessage()); + + $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); + $result = $this->validator->validate($this->doc); + self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.'); + + $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'URL'); + $result = $this->validator->validate($this->doc); + self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.'); + + $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'Test'); + $result = $this->validator->validate($this->doc); + self::assertEquals($result->getFirstError()->getMessage(), 'URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.'); + + $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'http://example.com/periodical.xml'); + $result = $this->validator->validate($this->doc); + self::assertFalse($result->hasErrors()); + } + + protected function createValidator(): AbstractDlfValidator + { + return new LogicalStructureValidator(); + } } From d89531f8f66083fbcd7512a532fb603f38477294 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Mon, 9 Dec 2024 16:08:29 +0100 Subject: [PATCH 03/43] Improvements test --- .../ApplicationProfileBaseValidator.php | 2 +- .../Validation/LogicalStructureValidator.php | 16 ++++- .../Validation/PhysicalStructureValidator.php | 17 +++-- Tests/Fixtures/mets.xml | 2 +- .../ApplicationProfileValidatorTest.php | 61 +++++++++++------ .../LogicalStructureValidatorTest.php | 47 ++++++------- .../PhysicalStructureValidatorTest.php | 66 +++++++++++++++++++ 7 files changed, 158 insertions(+), 53 deletions(-) create mode 100644 Tests/Unit/Validation/PhysicalStructureValidatorTest.php diff --git a/Classes/Validation/ApplicationProfileBaseValidator.php b/Classes/Validation/ApplicationProfileBaseValidator.php index 5b729191e..cf6ef72df 100644 --- a/Classes/Validation/ApplicationProfileBaseValidator.php +++ b/Classes/Validation/ApplicationProfileBaseValidator.php @@ -19,7 +19,7 @@ public function __construct() parent::__construct(DOMDocument::class); } - protected function setUpIsValid($value): void + protected function setupIsValid($value): void { $this->xpath = new DOMXPath($value); } diff --git a/Classes/Validation/LogicalStructureValidator.php b/Classes/Validation/LogicalStructureValidator.php index fc00d0c4b..2af49a3ac 100644 --- a/Classes/Validation/LogicalStructureValidator.php +++ b/Classes/Validation/LogicalStructureValidator.php @@ -14,7 +14,7 @@ class LogicalStructureValidator extends ApplicationProfileBaseValidator { protected function isValid($value): void { - $this->setUpIsValid($value); + $this->setupIsValid($value); // Validates against the rules of chapter "2.1.1 Logical structure - mets:structMap" if ($this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]')->length == 0) { @@ -24,6 +24,8 @@ protected function isValid($value): void $this->validateStructuralElements(); $this->validateExternalReference(); + + $this->validatePeriodicPublishingSequences(); } /** @@ -85,4 +87,16 @@ private function validateExternalReference(): void } } + + /** + * Validates the periodic publishing sequences. + * + * Validates against the rules of chapter "2.1.3 Periodic publishing sequences" + * + * @return void + */ + private function validatePeriodicPublishingSequences(): void + { + // TODO + } } diff --git a/Classes/Validation/PhysicalStructureValidator.php b/Classes/Validation/PhysicalStructureValidator.php index 93ee6c8c8..b11d92e7c 100644 --- a/Classes/Validation/PhysicalStructureValidator.php +++ b/Classes/Validation/PhysicalStructureValidator.php @@ -6,28 +6,33 @@ class PhysicalStructureValidator extends ApplicationProfileBaseValidator { protected function isValid($value): void { - parent::setValue($value); + $this->setupIsValid($value); + // Validates against the rules of chapter "2.2.1 Physical structure - mets:structMap" if ($this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]')->length > 1) { $this->addError('Every METS file has to have no or one physical structural element.', 1723727164447); } - $this->validateStructuralElements(); } /** + * + * Validates the structural elements. + * + * Validates against the rules of chapter "2.2.2.1 Structural element - mets:div" + * * @return void */ private function validateStructuralElements(): void { - if ($this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="“physSequence"]')->length == 0) { - $this->addError('Every physical structure has to consist one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', 1724234607); + if ($this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]')->length == 0) { + $this->addError('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', 1724234607); } - $subordinateStructuralElements = $this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="“physSequence"]/mets:div'); + $subordinateStructuralElements = $this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]/mets:div'); if ($subordinateStructuralElements->length == 0) { - $this->addError('Every physical structure has to consist one mets:div for the sequence and at least one subordinate mets:div.', 1724234607); + $this->addError('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', 1724234607); } else { foreach ($subordinateStructuralElements as $subordinateStructuralElement) { if (!$subordinateStructuralElement->hasAttribute("TYPE")) { diff --git a/Tests/Fixtures/mets.xml b/Tests/Fixtures/mets.xml index 91af04e66..4270234de 100644 --- a/Tests/Fixtures/mets.xml +++ b/Tests/Fixtures/mets.xml @@ -110,7 +110,7 @@ - + diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index c0badc2e6..bd3ed2046 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -3,18 +3,20 @@ namespace Slub\Dfgviewer\Tests\Unit\Validation; use DOMDocument; +use DOMElement; use DOMXPath; use Kitodo\Dlf\Validation\AbstractDlfValidator; +use TYPO3\CMS\Extbase\Error\Result; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; abstract class ApplicationProfileValidatorTest extends UnitTestCase { + const NAMESPACE_METS = 'http://www.loc.gov/METS/'; + protected $validator; protected $doc; - private $originalDoc; - abstract protected function createValidator(): AbstractDlfValidator; public function setUp(): void @@ -22,7 +24,6 @@ public function setUp(): void parent::setUp(); $this->resetSingletonInstances = true; $this->doc = $this->getDOMDocument(); - $this->originalDoc = $this->doc; $this->validator = $this->createValidator(); } @@ -33,77 +34,95 @@ public function setUp(): void */ public function testDocument() { - $result = $this->validator->validate($this->doc); + $result = $this->validate(); self::assertFalse($result->hasErrors()); } + /** + * Validates using validator and DOMDocument + * + * @return mixed|Result + */ + public function validate(): Result + { + return $this->validator->validate($this->doc); + } + + protected function resetDoc(): void { $this->doc = $this->getDOMDocument(); } /** - * Remove notes found by node expression in document. + * Add child node with name and namespace to DOMDocument. * - * @param DOMDocument $doc * @param string $expression * @param string $namespace * @param string $name * @return void * @throws \DOMException */ - protected function addChildNode(DOMDocument $doc, string $expression, string $namespace, string $name): void + protected function addChildNodeNS(string $expression, string $namespace, string $name): void + { + $this->addChildNode($expression, $this->doc->createElementNS($namespace, $name)); + } + + /** + * Add node as child node to DOMDocument. + * + * @param string $expression + * @param DOMElement $newNode + * @return void + */ + protected function addChildNode(string $expression, DOMElement $newNode): void { - $xpath = new DOMXPath($doc); - $newNode = $doc->createElementNS($namespace, $name); + $xpath = new DOMXPath($this->doc); foreach ($xpath->evaluate($expression) as $node) { $node->appendChild($newNode); } } /** - * Remove notes found by node expression in document. + * Remove notes found by node expression in DOMDocument. * - * @param DOMDocument $doc * @param string $expression * @return void */ - protected function removeNodes(DOMDocument $doc, string $expression): void + protected function removeNodes(string $expression): void { - $xpath = new DOMXPath($doc); + $xpath = new DOMXPath($this->doc); foreach ($xpath->evaluate($expression) as $node) { $node->parentNode->removeChild($node); } } /** - * Set value of attribute found by node expression in document. + * Set value of attribute found by node expression in DOMDocument. * - * @param DOMDocument $doc * @param string $expression * @param string $attribute * @param string $value * @return void */ - protected function setAttributeValue(DOMDocument $doc, string $expression, string $attribute, string $value): void + protected function setAttributeValue(string $expression, string $attribute, string $value): void { - $xpath = new DOMXPath($doc); + $xpath = new DOMXPath($this->doc); foreach ($xpath->evaluate($expression) as $node) { $node->setAttribute($attribute, $value); } } /** - * Remove attribute found by node expression in document. + * Remove attribute found by node expression in DOMDocument. * - * @param DOMDocument $doc * @param string $expression * @param string $attribute * @return void */ - protected function removeAttribute(DOMDocument $doc, string $expression, string $attribute): void + protected function removeAttribute(string $expression, string $attribute): void { - $xpath = new DOMXPath($doc); + $xpath = new DOMXPath($this->doc); foreach ($xpath->evaluate($expression) as $node) { $node->removeAttribute($attribute); } diff --git a/Tests/Unit/Validation/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/LogicalStructureValidatorTest.php index 71167363e..c91af411f 100644 --- a/Tests/Unit/Validation/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/LogicalStructureValidatorTest.php @@ -15,8 +15,8 @@ class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest */ public function testNotExistingLogicalStructureElement(): void { - $this->removeNodes($this->doc, '//mets:structMap[@TYPE="LOGICAL"]'); - $result = $this->validator->validate($this->doc); + $this->removeNodes( '//mets:structMap[@TYPE="LOGICAL"]'); + $result = $this->validate(); self::assertEquals('Every METS file has to have at least one logical structural element.', $result->getFirstError()->getMessage()); } @@ -26,61 +26,62 @@ public function testNotExistingLogicalStructureElement(): void */ public function testStructuralElements(): void { - $this->removeNodes($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div'); - $result = $this->validator->validate($this->doc); + $this->removeNodes('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); + $result = $this->validate(); self::assertEquals('Every logical structure has to consist of at least one mets:div.', $result->getFirstError()->getMessage()); $this->resetDoc(); - $this->removeAttribute($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'ID'); - $result = $this->validator->validate($this->doc); + $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'ID'); + $result = $this->validate(); self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "ID" attribute of mets:div in the logical structure is missing.'); $this->resetDoc(); - $this->removeAttribute($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); - $result = $this->validator->validate($this->doc); + $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); + $result = $this->validate(); self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "TYPE" attribute of mets:div in the logical structure is missing.'); $this->resetDoc(); - $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE', 'Test'); - $result = $this->validator->validate($this->doc); + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE', 'Test'); + $result = $this->validate(); self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "TYPE" attribute of mets:div in the logical structure is not permissible.'); } + /** * Test validation against the rules of chapter "2.1.2.2 Reference to external METS-files - mets:div / mets:mptr" * @return void */ public function testExternalReference(): void { - $this->addChildNode($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'http://www.loc.gov/METS/', 'mets:mptr'); - $this->addChildNode($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'http://www.loc.gov/METS/', 'mets:mptr'); - $result = $this->validator->validate($this->doc); + $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); + $result = $this->validate(); self::assertEquals('Every mets:div in the logical structure may only contain one mets:mptr.', $result->getFirstError()->getMessage()); $this->resetDoc(); - $this->addChildNode($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'http://www.loc.gov/METS/', 'mets:mptr'); - $result = $this->validator->validate($this->doc); + $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); + $result = $this->validate(); self::assertEquals('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', $result->getFirstError()->getMessage()); - $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); - $result = $this->validator->validate($this->doc); + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); + $result = $this->validate(); self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.'); - $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'URL'); - $result = $this->validator->validate($this->doc); + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'URL'); + $result = $this->validate(); self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.'); - $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'Test'); - $result = $this->validator->validate($this->doc); + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'Test'); + $result = $this->validate(); self::assertEquals($result->getFirstError()->getMessage(), 'URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.'); - $this->setAttributeValue($this->doc, '//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'http://example.com/periodical.xml'); - $result = $this->validator->validate($this->doc); + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'http://example.com/periodical.xml'); + $result = $this->validate(); self::assertFalse($result->hasErrors()); } diff --git a/Tests/Unit/Validation/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/PhysicalStructureValidatorTest.php new file mode 100644 index 000000000..4f426b066 --- /dev/null +++ b/Tests/Unit/Validation/PhysicalStructureValidatorTest.php @@ -0,0 +1,66 @@ +doc->createElementNS(self::NAMESPACE_METS, 'mets:structMap'); + $node->setAttribute('TYPE', 'PHYSICAL'); + $this->addChildNode('/mets:mets', $node); + $result = $this->validate(); + self::assertEquals('Every METS file has to have no or one physical structural element.', $result->getFirstError()->getMessage()); + } + + /** + * Test validation against the rules of chapter "2.2.2.1 Structural element - mets:div" + * + * @return void + */ + public function testStructuralElements(): void + { + $this->removeNodes('//mets:structMap[@TYPE="PHYSICAL"]/mets:div'); + $result = $this->validate(); + self::assertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', 'TYPE'); + $result = $this->validate(); + self::assertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->removeNodes('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div'); + $result = $this->validate(); + self::assertEquals('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE'); + $result = $this->validate(); + self::assertEquals('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->setAttributeValue('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE', 'Test'); + $result = $this->validate(); + self::assertEquals('Value "Test" of "TYPE" attribute of mets:div in physical structure is not permissible.', $result->getFirstError()->getMessage()); + } + + protected function createValidator(): AbstractDlfValidator + { + return new PhysicalStructureValidator(); + } +} From 378a776a700570e6a6e97c209d50b05637bb5078 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Mon, 9 Dec 2024 17:54:09 +0100 Subject: [PATCH 04/43] Add link validation and add unique check for ids --- ...nkingLogicalPhysicalStructureValidator.php | 66 +++++++++++++++++++ .../Validation/LogicalStructureValidator.php | 7 ++ .../Validation/PhysicalStructureValidator.php | 8 +++ 3 files changed, 81 insertions(+) create mode 100644 Classes/Validation/LinkingLogicalPhysicalStructureValidator.php diff --git a/Classes/Validation/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/LinkingLogicalPhysicalStructureValidator.php new file mode 100644 index 000000000..f7c195cb8 --- /dev/null +++ b/Classes/Validation/LinkingLogicalPhysicalStructureValidator.php @@ -0,0 +1,66 @@ +setupIsValid($value); + + // Validates against the rules of chapter "2.3.1 Structure links - mets:structLink" + if ($this->xpath->query('//mets:structLink')->length > 1) { + $this->addError('Every METS file has to have no or one struct link element.', 1723727164447); + } + + $this->validateLinkingElements(); + } + + /** + * Validates the linking elements. + * + * Validates against the rules of chapter "2.3.2.1 Linking – mets:smLink" + * + * @return void + */ + private function validateLinkingElements(): void + { + $linkingElements = $this->xpath->query('//mets:structLink/mets:smLink'); + + foreach ($linkingElements as $linkingElement) { + $this->validateLinkingElement($linkingElement, "xlink:from", "LOGICAL"); + $this->validateLinkingElement($linkingElement, "xlink:to", "PHYSICAL"); + } + } + + /** + * Validate linking element. + * + * @param DOMNode $linkingElement + * @param string $attribute + * @param string $structMapType + * @return void + */ + private function validateLinkingElement(DOMNode $linkingElement, string $attribute, string $structMapType): void + { + if (!$linkingElement->hasAttribute($attribute)) { + $this->addError('Mandatory "' . $attribute . ' attribute of mets:div in the logical structure is missing.', 1724234607); + } else { + $id = $linkingElement->getAttribute($attribute); + if ($this->xpath->query('//mets:structMap[@TYPE="' . $structMapType . '"]/mets:div/mets:div[@ID = \'' . $id . '\']')->length !== 1) { + $this->addError('None or multiple ids found for "' . $id . '" in struct map type "' . $structMapType . '".', 1724234607); + } + } + } +} diff --git a/Classes/Validation/LogicalStructureValidator.php b/Classes/Validation/LogicalStructureValidator.php index 2af49a3ac..d5f696df7 100644 --- a/Classes/Validation/LogicalStructureValidator.php +++ b/Classes/Validation/LogicalStructureValidator.php @@ -44,6 +44,11 @@ private function validateStructuralElements(): void foreach ($structuralElements as $structuralElement) { if (!$structuralElement->hasAttribute("ID")) { $this->addError('Mandatory "ID" attribute of mets:div in the logical structure is missing.', 1724234607); + } else { + $id = $structuralElement->getAttribute("ID"); + if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { + $this->addError('Logical structure "ID" "' . $id . '" already exists in document.', 1724234607); + } } if (!$structuralElement->hasAttribute("TYPE")) { $this->addError('Mandatory "TYPE" attribute of mets:div in the logical structure is missing.', 1724234607); @@ -85,6 +90,8 @@ private function validateExternalReference(): void } } + //*[@id="button"] + } } diff --git a/Classes/Validation/PhysicalStructureValidator.php b/Classes/Validation/PhysicalStructureValidator.php index b11d92e7c..00a61e07e 100644 --- a/Classes/Validation/PhysicalStructureValidator.php +++ b/Classes/Validation/PhysicalStructureValidator.php @@ -35,6 +35,14 @@ private function validateStructuralElements(): void $this->addError('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', 1724234607); } else { foreach ($subordinateStructuralElements as $subordinateStructuralElement) { + if (!$subordinateStructuralElements->hasAttribute("ID")) { + $this->addError('Mandatory "ID" attribute of mets:div in the physical structure is missing.', 1724234607); + } else { + $id = $subordinateStructuralElements->getAttribute("ID"); + if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { + $this->addError('Physical structure "ID" "' . $id . '" already exists in document.', 1724234607); + } + } if (!$subordinateStructuralElement->hasAttribute("TYPE")) { $this->addError('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', 1724234607); } else { From 242ac8f086f5d7dece6f6420375c8c44b258284d Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Mon, 9 Dec 2024 17:55:35 +0100 Subject: [PATCH 05/43] Fix tiny bug --- Classes/Validation/PhysicalStructureValidator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Validation/PhysicalStructureValidator.php b/Classes/Validation/PhysicalStructureValidator.php index 00a61e07e..5b4431559 100644 --- a/Classes/Validation/PhysicalStructureValidator.php +++ b/Classes/Validation/PhysicalStructureValidator.php @@ -35,10 +35,10 @@ private function validateStructuralElements(): void $this->addError('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', 1724234607); } else { foreach ($subordinateStructuralElements as $subordinateStructuralElement) { - if (!$subordinateStructuralElements->hasAttribute("ID")) { + if (!$subordinateStructuralElement->hasAttribute("ID")) { $this->addError('Mandatory "ID" attribute of mets:div in the physical structure is missing.', 1724234607); } else { - $id = $subordinateStructuralElements->getAttribute("ID"); + $id = $subordinateStructuralElement->getAttribute("ID"); if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { $this->addError('Physical structure "ID" "' . $id . '" already exists in document.', 1724234607); } From cede8b75ba67387c1f3ae8a91f536a33c068995e Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Tue, 10 Dec 2024 12:12:44 +0100 Subject: [PATCH 06/43] Add license comment and improve validation --- .../ApplicationProfileBaseValidator.php | 23 ++++ .../ApplicationProfileValidationStack.php | 18 ---- .../AdministrativeMetadataValidator.php | 27 ++++- ...nkingLogicalPhysicalStructureValidator.php | 28 ++++- .../{ => Mets}/LogicalStructureValidator.php | 29 ++++- .../{ => Mets}/PhysicalStructureValidator.php | 35 +++++- .../MetsApplicationProfileValidationStack.php | 45 ++++++++ .../ApplicationProfileValidatorTest.php | 23 ++++ ...gLogicalPhysicalStructureValidatorTest.php | 100 ++++++++++++++++++ .../LogicalStructureValidatorTest.php | 33 +++++- .../PhysicalStructureValidatorTest.php | 40 ++++++- 11 files changed, 374 insertions(+), 27 deletions(-) delete mode 100644 Classes/Validation/ApplicationProfileValidationStack.php rename Classes/Validation/{ => Mets}/AdministrativeMetadataValidator.php (75%) rename Classes/Validation/{ => Mets}/LinkingLogicalPhysicalStructureValidator.php (67%) rename Classes/Validation/{ => Mets}/LogicalStructureValidator.php (81%) rename Classes/Validation/{ => Mets}/PhysicalStructureValidator.php (70%) create mode 100644 Classes/Validation/MetsApplicationProfileValidationStack.php create mode 100644 Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php rename Tests/Unit/Validation/{ => Mets}/LogicalStructureValidatorTest.php (76%) rename Tests/Unit/Validation/{ => Mets}/PhysicalStructureValidatorTest.php (62%) diff --git a/Classes/Validation/ApplicationProfileBaseValidator.php b/Classes/Validation/ApplicationProfileBaseValidator.php index cf6ef72df..2f509b770 100644 --- a/Classes/Validation/ApplicationProfileBaseValidator.php +++ b/Classes/Validation/ApplicationProfileBaseValidator.php @@ -2,6 +2,29 @@ namespace Slub\Dfgviewer\Validation; +/** + * Copyright notice + * + * (c) Saxon State and University Library Dresden + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + use DOMDocument; use DOMXPath; use Kitodo\Dlf\Validation\AbstractDlfValidator; diff --git a/Classes/Validation/ApplicationProfileValidationStack.php b/Classes/Validation/ApplicationProfileValidationStack.php deleted file mode 100644 index 377f4a395..000000000 --- a/Classes/Validation/ApplicationProfileValidationStack.php +++ /dev/null @@ -1,18 +0,0 @@ -addValidator(LogicalStructureValidator::class, "Specifications for the logical document structure", false); - $this->addValidator(PhysicalStructureValidator::class, "Specifications for the physical document structure", false); - - } -} diff --git a/Classes/Validation/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php similarity index 75% rename from Classes/Validation/AdministrativeMetadataValidator.php rename to Classes/Validation/Mets/AdministrativeMetadataValidator.php index 6673f88c6..e15349a77 100644 --- a/Classes/Validation/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -1,6 +1,31 @@ + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ class AdministrativeMetadataValidator extends ApplicationProfileBaseValidator { diff --git a/Classes/Validation/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php similarity index 67% rename from Classes/Validation/LinkingLogicalPhysicalStructureValidator.php rename to Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index f7c195cb8..436cbe397 100644 --- a/Classes/Validation/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -1,11 +1,35 @@ + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ use DOMNode; +use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; /** - * The validator validates against the rules outlined in chapter 2.1 of the application profile 2.3.1. + * The validator validates against the rules outlined in chapter 2.3 of the METS application profile 2.3.1. * * @package TYPO3 * @subpackage dfg-viewer diff --git a/Classes/Validation/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php similarity index 81% rename from Classes/Validation/LogicalStructureValidator.php rename to Classes/Validation/Mets/LogicalStructureValidator.php index d5f696df7..30b5e6172 100644 --- a/Classes/Validation/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -1,9 +1,34 @@ + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ /** - * The validator validates against the rules outlined in chapter 2.1 of the application profile 2.3.1. + * The validator validates against the rules outlined in chapter 2.1 of the METS application profile 2.3.1. * * @package TYPO3 * @subpackage dfg-viewer diff --git a/Classes/Validation/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php similarity index 70% rename from Classes/Validation/PhysicalStructureValidator.php rename to Classes/Validation/Mets/PhysicalStructureValidator.php index 5b4431559..90f50b9cc 100644 --- a/Classes/Validation/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -1,7 +1,40 @@ + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +/** + * The validator validates against the rules outlined in chapter 2.2 of the METS application profile 2.3.1. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ class PhysicalStructureValidator extends ApplicationProfileBaseValidator { protected function isValid($value): void diff --git a/Classes/Validation/MetsApplicationProfileValidationStack.php b/Classes/Validation/MetsApplicationProfileValidationStack.php new file mode 100644 index 000000000..2ea42e4d4 --- /dev/null +++ b/Classes/Validation/MetsApplicationProfileValidationStack.php @@ -0,0 +1,45 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidationStack; +use Slub\Dfgviewer\Validation\Mets\LinkingLogicalPhysicalStructureValidator; +use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; +use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; + +class MetsApplicationProfileValidationStack extends AbstractDlfValidationStack { + public function __construct(array $options = []) + { + parent::__construct(\DOMDocument::class, $options); + + $this->addValidator(LogicalStructureValidator::class, "Specifications for the logical document structure", false); + $this->addValidator(PhysicalStructureValidator::class, "Specifications for the physical document structure", false); + $this->addValidator(LinkingLogicalPhysicalStructureValidator::class, "Specifications for the physical document structure", false); + + } +} diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index bd3ed2046..5775ed93e 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -2,6 +2,29 @@ namespace Slub\Dfgviewer\Tests\Unit\Validation; +/** + * Copyright notice + * + * (c) Saxon State and University Library Dresden + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + use DOMDocument; use DOMElement; use DOMXPath; diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php new file mode 100644 index 000000000..428e1c35e --- /dev/null +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -0,0 +1,100 @@ +removeNodes( '//mets:structMap[@TYPE="LOGICAL"]'); + $result = $this->validate(); + self::assertEquals('Every METS file has to have at least one logical structural element.', $result->getFirstError()->getMessage()); + } + + /** + * Test validation against the rules of chapter "2.1.2.1 Structural element - mets:div" + * @return void + */ + public function testStructuralElements(): void + { + $this->removeNodes('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); + $result = $this->validate(); + self::assertEquals('Every logical structure has to consist of at least one mets:div.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'ID'); + $result = $this->validate(); + self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "ID" attribute of mets:div in the logical structure is missing.'); + + $this->resetDoc(); + + $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); + $node->setAttribute('ID', 'LOG_0001'); + $this->addChildNode('//mets:structMap[@TYPE="LOGICAL"]/mets:div', $node); + $result = $this->validate(); + self::assertEquals('Logical structure "ID" "LOG_0001" already exists in document.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); + $result = $this->validate(); + self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "TYPE" attribute of mets:div in the logical structure is missing.'); + + $this->resetDoc(); + + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE', 'Test'); + $result = $this->validate(); + self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "TYPE" attribute of mets:div in the logical structure is not permissible.'); + } + + + + /** + * Test validation against the rules of chapter "2.1.2.2 Reference to external METS-files - mets:div / mets:mptr" + * @return void + */ + public function testExternalReference(): void + { + $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); + $result = $this->validate(); + self::assertEquals('Every mets:div in the logical structure may only contain one mets:mptr.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + + $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); + $result = $this->validate(); + self::assertEquals('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', $result->getFirstError()->getMessage()); + + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); + $result = $this->validate(); + self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.'); + + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'URL'); + $result = $this->validate(); + self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.'); + + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'Test'); + $result = $this->validate(); + self::assertEquals($result->getFirstError()->getMessage(), 'URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.'); + + $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'http://example.com/periodical.xml'); + $result = $this->validate(); + self::assertFalse($result->hasErrors()); + } + + protected function createValidator(): AbstractDlfValidator + { + return new LogicalStructureValidator(); + } +} diff --git a/Tests/Unit/Validation/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php similarity index 76% rename from Tests/Unit/Validation/LogicalStructureValidatorTest.php rename to Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index c91af411f..8e77b6bb5 100644 --- a/Tests/Unit/Validation/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -2,8 +2,31 @@ namespace Slub\Dfgviewer\Tests\Unit\Validation; +/** + * Copyright notice + * + * (c) Saxon State and University Library Dresden + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Validation\LogicalStructureValidator; +use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest { @@ -38,6 +61,14 @@ public function testStructuralElements(): void $this->resetDoc(); + $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); + $node->setAttribute('ID', 'LOG_0001'); + $this->addChildNode('//mets:structMap[@TYPE="LOGICAL"]/mets:div', $node); + $result = $this->validate(); + self::assertEquals('Logical structure "ID" "LOG_0001" already exists in document.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); $result = $this->validate(); self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "TYPE" attribute of mets:div in the logical structure is missing.'); diff --git a/Tests/Unit/Validation/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php similarity index 62% rename from Tests/Unit/Validation/PhysicalStructureValidatorTest.php rename to Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index 4f426b066..f6bb25140 100644 --- a/Tests/Unit/Validation/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -2,9 +2,31 @@ namespace Slub\Dfgviewer\Tests\Unit\Validation; +/** + * Copyright notice + * + * (c) Saxon State and University Library Dresden + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Validation\LogicalStructureValidator; -use Slub\Dfgviewer\Validation\PhysicalStructureValidator; +use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; class PhysicalStructureValidatorTest extends ApplicationProfileValidatorTest { @@ -48,6 +70,20 @@ public function testStructuralElements(): void $this->resetDoc(); + $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'ID'); + $result = $this->validate(); + self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "ID" attribute of mets:div in the physical structure is missing.'); + + $this->resetDoc(); + + $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); + $node->setAttribute('ID', 'PHYS_0001'); + $this->addChildNode('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', $node); + $result = $this->validate(); + self::assertEquals('Physical structure "ID" "PHYS_0001" already exists in document.', $result->getFirstError()->getMessage()); + + $this->resetDoc(); + $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE'); $result = $this->validate(); self::assertEquals('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', $result->getFirstError()->getMessage()); From 9f87f0c8b2f2c00dbdd7d1bd0600c27d5706d0df Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Tue, 10 Dec 2024 12:56:44 +0100 Subject: [PATCH 07/43] Tiny refactoring to reduce duplicate code --- .../ApplicationProfileValidatorTest.php | 17 +++ ...gLogicalPhysicalStructureValidatorTest.php | 110 +++++------------- .../Mets/LogicalStructureValidatorTest.php | 43 ++----- .../Mets/PhysicalStructureValidatorTest.php | 36 ++---- 4 files changed, 66 insertions(+), 140 deletions(-) diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index 5775ed93e..483c3eaac 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -71,6 +71,23 @@ public function validate(): Result return $this->validator->validate($this->doc); } + /** + * Validates using validator and DOMDocument and assert result error message for equality. + * + * Validates using a validator and DOMDocument, then asserts that the resulting error message matches the expected value. + * + * @param $message + * @param $resetDoc + * @return void + */ + public function validateAndAssertEquals(string $message, bool $resetDoc = false): void + { + $result = $this->validator->validate($this->doc); + self::assertEquals($message, $result->getFirstError()->getMessage()); + if ($resetDoc) { + $this->resetDoc(); + } + } protected function resetDoc(): void { diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index 428e1c35e..aa4f4c131 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -2,99 +2,49 @@ namespace Slub\Dfgviewer\Tests\Unit\Validation; +/** + * Copyright notice + * + * (c) Saxon State and University Library Dresden + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + + use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; +use Slub\Dfgviewer\Validation\Mets\LinkingLogicalPhysicalStructureValidator; class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileValidatorTest { /** - * Test validation against the rules of chapter "2.1.1 Logical structure - mets:structMap" + * Test validation against the rules of chapter "2.3.1 Structure links - mets:structLink" * * @return void */ - public function testNotExistingLogicalStructureElement(): void - { - $this->removeNodes( '//mets:structMap[@TYPE="LOGICAL"]'); - $result = $this->validate(); - self::assertEquals('Every METS file has to have at least one logical structural element.', $result->getFirstError()->getMessage()); - } - - /** - * Test validation against the rules of chapter "2.1.2.1 Structural element - mets:div" - * @return void - */ - public function testStructuralElements(): void - { - $this->removeNodes('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); - $result = $this->validate(); - self::assertEquals('Every logical structure has to consist of at least one mets:div.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); - - $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'ID'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "ID" attribute of mets:div in the logical structure is missing.'); - - $this->resetDoc(); - - $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); - $node->setAttribute('ID', 'LOG_0001'); - $this->addChildNode('//mets:structMap[@TYPE="LOGICAL"]/mets:div', $node); - $result = $this->validate(); - self::assertEquals('Logical structure "ID" "LOG_0001" already exists in document.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); - - $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "TYPE" attribute of mets:div in the logical structure is missing.'); - - $this->resetDoc(); - - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE', 'Test'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "TYPE" attribute of mets:div in the logical structure is not permissible.'); - } - - - - /** - * Test validation against the rules of chapter "2.1.2.2 Reference to external METS-files - mets:div / mets:mptr" - * @return void - */ - public function testExternalReference(): void + public function testMultipleStructLinks(): void { - $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $result = $this->validate(); - self::assertEquals('Every mets:div in the logical structure may only contain one mets:mptr.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); - - $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $result = $this->validate(); - self::assertEquals('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', $result->getFirstError()->getMessage()); - - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.'); - - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'URL'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.'); - - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'Test'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.'); - - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'http://example.com/periodical.xml'); - $result = $this->validate(); - self::assertFalse($result->hasErrors()); + $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:structLink'); + $this->validateAndAssertEquals('Every METS file has to have no or one struct link element.'); } protected function createValidator(): AbstractDlfValidator { - return new LogicalStructureValidator(); + return new LinkingLogicalPhysicalStructureValidator(); } } diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index 8e77b6bb5..210690f23 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -39,8 +39,7 @@ class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest public function testNotExistingLogicalStructureElement(): void { $this->removeNodes( '//mets:structMap[@TYPE="LOGICAL"]'); - $result = $this->validate(); - self::assertEquals('Every METS file has to have at least one logical structural element.', $result->getFirstError()->getMessage()); + $this->validateAndAssertEquals('Every METS file has to have at least one logical structural element.'); } /** @@ -50,34 +49,21 @@ public function testNotExistingLogicalStructureElement(): void public function testStructuralElements(): void { $this->removeNodes('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); - $result = $this->validate(); - self::assertEquals('Every logical structure has to consist of at least one mets:div.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Every logical structure has to consist of at least one mets:div.', true); $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'ID'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "ID" attribute of mets:div in the logical structure is missing.'); - - $this->resetDoc(); + $this->validateAndAssertEquals('Mandatory "ID" attribute of mets:div in the logical structure is missing.', true); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); $this->addChildNode('//mets:structMap[@TYPE="LOGICAL"]/mets:div', $node); - $result = $this->validate(); - self::assertEquals('Logical structure "ID" "LOG_0001" already exists in document.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Logical structure "ID" "LOG_0001" already exists in document.', true); $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "TYPE" attribute of mets:div in the logical structure is missing.'); - - $this->resetDoc(); + $this->validateAndAssertEquals('Mandatory "TYPE" attribute of mets:div in the logical structure is missing.', true); $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE', 'Test'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "TYPE" attribute of mets:div in the logical structure is not permissible.'); + $this->validateAndAssertEquals('Value "Test" of "TYPE" attribute of mets:div in the logical structure is not permissible.', true); } @@ -90,26 +76,19 @@ public function testExternalReference(): void { $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $result = $this->validate(); - self::assertEquals('Every mets:div in the logical structure may only contain one mets:mptr.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Every mets:div in the logical structure may only contain one mets:mptr.', true); $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $result = $this->validate(); - self::assertEquals('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', $result->getFirstError()->getMessage()); + $this->validateAndAssertEquals('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.'); $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Value "Test" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.'); + $this->validateAndAssertEquals('Value "Test" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.'); $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'URL'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.'); + $this->validateAndAssertEquals('Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.'); $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'Test'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.'); + $this->validateAndAssertEquals('URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.'); $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'http://example.com/periodical.xml'); $result = $this->validate(); diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index f6bb25140..68b16d993 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -41,8 +41,7 @@ public function testMultiplePhysicalDivisions(): void $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:structMap'); $node->setAttribute('TYPE', 'PHYSICAL'); $this->addChildNode('/mets:mets', $node); - $result = $this->validate(); - self::assertEquals('Every METS file has to have no or one physical structural element.', $result->getFirstError()->getMessage()); + $this->validateAndAssertEquals('Every METS file has to have no or one physical structural element.'); } /** @@ -53,46 +52,27 @@ public function testMultiplePhysicalDivisions(): void public function testStructuralElements(): void { $this->removeNodes('//mets:structMap[@TYPE="PHYSICAL"]/mets:div'); - $result = $this->validate(); - self::assertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', true); $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', 'TYPE'); - $result = $this->validate(); - self::assertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', true); $this->removeNodes('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div'); - $result = $this->validate(); - self::assertEquals('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', true); $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'ID'); - $result = $this->validate(); - self::assertEquals($result->getFirstError()->getMessage(), 'Mandatory "ID" attribute of mets:div in the physical structure is missing.'); - - $this->resetDoc(); + $this->validateAndAssertEquals('Mandatory "ID" attribute of mets:div in the physical structure is missing.', true); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'PHYS_0001'); $this->addChildNode('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', $node); - $result = $this->validate(); - self::assertEquals('Physical structure "ID" "PHYS_0001" already exists in document.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Physical structure "ID" "PHYS_0001" already exists in document.', true); $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE'); - $result = $this->validate(); - self::assertEquals('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', $result->getFirstError()->getMessage()); - - $this->resetDoc(); + $this->validateAndAssertEquals('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', true); $this->setAttributeValue('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE', 'Test'); - $result = $this->validate(); - self::assertEquals('Value "Test" of "TYPE" attribute of mets:div in physical structure is not permissible.', $result->getFirstError()->getMessage()); + $this->validateAndAssertEquals('Value "Test" of "TYPE" attribute of mets:div in physical structure is not permissible.'); } protected function createValidator(): AbstractDlfValidator From ee3682f3a39b8d69d416cf5546dafd950f4d69ad Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Tue, 10 Dec 2024 15:46:33 +0100 Subject: [PATCH 08/43] Improvements regarding linking validation --- ...nkingLogicalPhysicalStructureValidator.php | 21 ++++++++++++++----- .../ApplicationProfileValidatorTest.php | 13 +++++++----- ...gLogicalPhysicalStructureValidatorTest.php | 12 +++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index 436cbe397..3a04dc1ac 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -43,12 +43,13 @@ protected function isValid($value): void { $this->setupIsValid($value); + $structLinks = $this->xpath->query('//mets:structLink'); // Validates against the rules of chapter "2.3.1 Structure links - mets:structLink" - if ($this->xpath->query('//mets:structLink')->length > 1) { + if ($structLinks === false || $structLinks->length > 1) { $this->addError('Every METS file has to have no or one struct link element.', 1723727164447); + } elseif ($structLinks->length == 1) { + $this->validateLinkElements(); } - - $this->validateLinkingElements(); } /** @@ -58,14 +59,19 @@ protected function isValid($value): void * * @return void */ - private function validateLinkingElements(): void + private function validateLinkElements(): void { $linkingElements = $this->xpath->query('//mets:structLink/mets:smLink'); + if ($linkingElements->length === 0) { + $this->addError('There should be at least one "mets:smLink" under "mets:structLink".', 1723727164447); + } + foreach ($linkingElements as $linkingElement) { $this->validateLinkingElement($linkingElement, "xlink:from", "LOGICAL"); $this->validateLinkingElement($linkingElement, "xlink:to", "PHYSICAL"); } + } /** @@ -82,7 +88,12 @@ private function validateLinkingElement(DOMNode $linkingElement, string $attribu $this->addError('Mandatory "' . $attribute . ' attribute of mets:div in the logical structure is missing.', 1724234607); } else { $id = $linkingElement->getAttribute($attribute); - if ($this->xpath->query('//mets:structMap[@TYPE="' . $structMapType . '"]/mets:div/mets:div[@ID = \'' . $id . '\']')->length !== 1) { + $structMaps = $this->xpath->query('//mets:structMap[@TYPE="' . $structMapType . '"]'); + $foundElements = 0; + foreach ($structMaps as $structMap) { + $foundElements += $this->xpath->query('//mets:div[@ID = \'' . $id . '\']', $structMap)->length; + } + if ($foundElements !== 1) { $this->addError('None or multiple ids found for "' . $id . '" in struct map type "' . $structMapType . '".', 1724234607); } } diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index 483c3eaac..aaf39dfe3 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -58,6 +58,9 @@ public function setUp(): void public function testDocument() { $result = $this->validate(); + if($result->hasErrors()){ + self::assertEquals('',$result->getFirstError()->getMessage()); + } self::assertFalse($result->hasErrors()); } @@ -77,19 +80,19 @@ public function validate(): Result * Validates using a validator and DOMDocument, then asserts that the resulting error message matches the expected value. * * @param $message - * @param $resetDoc + * @param $resetDocument bool True if the document is to be reset at the end of the function. * @return void */ - public function validateAndAssertEquals(string $message, bool $resetDoc = false): void + public function validateAndAssertEquals(string $message, bool $resetDocument = false): void { $result = $this->validator->validate($this->doc); self::assertEquals($message, $result->getFirstError()->getMessage()); - if ($resetDoc) { - $this->resetDoc(); + if ($resetDocument) { + $this->resetDocument(); } } - protected function resetDoc(): void + protected function resetDocument(): void { $this->doc = $this->getDOMDocument(); } diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index aa4f4c131..2c8e15add 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -43,6 +43,18 @@ public function testMultipleStructLinks(): void $this->validateAndAssertEquals('Every METS file has to have no or one struct link element.'); } + public function testLinkElements(): void + { + $this->removeNodes('//mets:structLink/mets:smLink'); + $this->validateAndAssertEquals('There should be at least one "mets:smLink" under "mets:structLink".', true); + + $this->setAttributeValue('//mets:structLink/mets:smLink', 'xlink:from', 'Test'); + $this->validateAndAssertEquals('None or multiple ids found for "Test" in struct map type "LOGICAL".', true); + + $this->setAttributeValue('//mets:structLink/mets:smLink', 'xlink:to', 'Test'); + $this->validateAndAssertEquals('None or multiple ids found for "Test" in struct map type "PHYSICAL".', true); + } + protected function createValidator(): AbstractDlfValidator { return new LinkingLogicalPhysicalStructureValidator(); From 83c0408cb7cec12b8f61174691375ef77918f991 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Tue, 10 Dec 2024 17:49:37 +0100 Subject: [PATCH 09/43] Tiny refactoring to reduce complexity --- .../Validation/ApplicationProfileBaseValidator.php | 5 ++++- .../Mets/AdministrativeMetadataValidator.php | 14 ++++++++++---- .../LinkingLogicalPhysicalStructureValidator.php | 4 +--- .../Validation/Mets/LogicalStructureValidator.php | 4 +--- .../Validation/Mets/PhysicalStructureValidator.php | 4 +--- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Classes/Validation/ApplicationProfileBaseValidator.php b/Classes/Validation/ApplicationProfileBaseValidator.php index 2f509b770..03924b694 100644 --- a/Classes/Validation/ApplicationProfileBaseValidator.php +++ b/Classes/Validation/ApplicationProfileBaseValidator.php @@ -42,8 +42,11 @@ public function __construct() parent::__construct(DOMDocument::class); } - protected function setupIsValid($value): void + protected function isValid($value): void { $this->xpath = new DOMXPath($value); + $this->isValidDocument(); } + + protected abstract function isValidDocument(); } diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index e15349a77..aad1df5c3 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -27,13 +27,19 @@ * This copyright notice MUST APPEAR in all copies of the script! */ +/** + * The validator validates against the rules outlined in chapter 2.6 of the METS application profile 2.3.1. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ class AdministrativeMetadataValidator extends ApplicationProfileBaseValidator { - protected function isValid($value): void + protected function isValidDocument(): void { - parent::setValue($value); - - if ($this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]')->length == 0) { + if ($this->xpath->query('//mets:amdSec[@TYPE="LOGICAL"]')->length == 0) { $this->addError('Every METS file has to have at least one logical structural element.', 1723727164447); } diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index 3a04dc1ac..599890cbf 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -39,10 +39,8 @@ class LinkingLogicalPhysicalStructureValidator extends ApplicationProfileBaseValidator { - protected function isValid($value): void + protected function isValidDocument(): void { - $this->setupIsValid($value); - $structLinks = $this->xpath->query('//mets:structLink'); // Validates against the rules of chapter "2.3.1 Structure links - mets:structLink" if ($structLinks === false || $structLinks->length > 1) { diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index 30b5e6172..6392ba32d 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -37,10 +37,8 @@ */ class LogicalStructureValidator extends ApplicationProfileBaseValidator { - protected function isValid($value): void + protected function isValidDocument(): void { - $this->setupIsValid($value); - // Validates against the rules of chapter "2.1.1 Logical structure - mets:structMap" if ($this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]')->length == 0) { $this->addError('Every METS file has to have at least one logical structural element.', 1723727164447); diff --git a/Classes/Validation/Mets/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php index 90f50b9cc..8e2ec902f 100644 --- a/Classes/Validation/Mets/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -37,10 +37,8 @@ */ class PhysicalStructureValidator extends ApplicationProfileBaseValidator { - protected function isValid($value): void + protected function isValidDocument(): void { - $this->setupIsValid($value); - // Validates against the rules of chapter "2.2.1 Physical structure - mets:structMap" if ($this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]')->length > 1) { $this->addError('Every METS file has to have no or one physical structural element.', 1723727164447); From edb42774c13ad1a196c706f12b808fc94501348c Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 13 Dec 2024 17:12:22 +0100 Subject: [PATCH 10/43] Refactore validation structure and test for standardized error messages and clarity --- .../ApplicationProfileBaseValidator.php | 21 +--- Classes/Validation/DOMDocumentValidator.php | 118 ++++++++++++++++++ .../Mets/AdministrativeMetadataValidator.php | 72 +++++------ .../Mets/LogicalStructureValidator.php | 82 +++++------- .../ApplicationProfileValidatorTest.php | 43 ++++++- ...gLogicalPhysicalStructureValidatorTest.php | 4 +- .../Mets/LogicalStructureValidatorTest.php | 55 ++++---- .../Mets/PhysicalStructureValidatorTest.php | 8 +- 8 files changed, 255 insertions(+), 148 deletions(-) create mode 100644 Classes/Validation/DOMDocumentValidator.php diff --git a/Classes/Validation/ApplicationProfileBaseValidator.php b/Classes/Validation/ApplicationProfileBaseValidator.php index 03924b694..878cfb85e 100644 --- a/Classes/Validation/ApplicationProfileBaseValidator.php +++ b/Classes/Validation/ApplicationProfileBaseValidator.php @@ -25,28 +25,9 @@ * This copyright notice MUST APPEAR in all copies of the script! */ -use DOMDocument; -use DOMXPath; -use Kitodo\Dlf\Validation\AbstractDlfValidator; - -abstract class ApplicationProfileBaseValidator extends AbstractDlfValidator +abstract class ApplicationProfileBaseValidator extends DOMDocumentValidator { const STRUCTURE_DATASET = array( 'section', 'file', 'album', 'register', 'annotation', 'address', 'article', 'atlas', 'issue', 'bachelor_thesis', 'volume', 'contained_work', 'additional', 'report', 'official_notification', 'provenance', 'inventory', 'image', 'collation', 'ornament', 'letter', 'cover', 'cover_front', 'cover_back', 'diploma_thesis', 'doctoral_thesis', 'document', 'printers_mark', 'printed_archives', 'binding', 'entry', 'corrigenda', 'bookplate', 'fascicle', 'leaflet', 'research_paper', 'photograph', 'fragment', 'land_register', 'ground_plan', 'habilitation_thesis', 'manuscript', 'illustration', 'imprint', 'contents', 'initial_decoration', 'year', 'chapter', 'map', 'cartulary', 'colophon', 'ephemera', 'engraved_titlepage', 'magister_thesis', 'folder', 'master_thesis', 'multivolume_work', 'month', 'monograph', 'musical_notation', 'periodical', 'poster', 'plan', 'privileges', 'index', 'spine', 'scheme', 'edge', 'seal', 'paste down', 'stamp', 'study', 'table', 'day', 'proceeding', 'text', 'title_page', 'subinventory', 'act', 'judgement', 'verse', 'note', 'preprint', 'dossier', 'lecture', 'endsheet', 'paper', 'preface', 'dedication', 'newspaper' ); - - protected DOMXpath $xpath; - - public function __construct() - { - parent::__construct(DOMDocument::class); - } - - protected function isValid($value): void - { - $this->xpath = new DOMXPath($value); - $this->isValidDocument(); - } - - protected abstract function isValidDocument(); } diff --git a/Classes/Validation/DOMDocumentValidator.php b/Classes/Validation/DOMDocumentValidator.php new file mode 100644 index 000000000..74092b30e --- /dev/null +++ b/Classes/Validation/DOMDocumentValidator.php @@ -0,0 +1,118 @@ +expression = $expression; + $this->nodeList = $this->xpath->query($this->expression); + return $this; + } + + public function iterate(callable $callback) + { + foreach ($this->nodeList as $node) { + call_user_func_array($callback, array($node)); + } + return $this; + } + + public function validateHasAny() + { + if (!$this->nodeList->length > 0) { + $this->addError('There must be at least one element that matches the XPath expression "' . $this->expression . '"', 1723727164447); + } + return $this; + } + + public function validateHasOne() + { + if ($this->nodeList->length != 1) { + $this->addError('There must be an element that matches the XPath expression "' . $this->expression . '"', 1723727164447); + } + return $this; + } + + public function validateHasNoneOrOne() + { + if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { + $this->addError('There must be no more than one element that matches the XPath expression "' . $this->expression . '"', 1723727164447); + } + return $this; + } + + public function validateHasAttributeWithUrl(\DOMNode $node, string $name) + { + if ($node->hasAttribute($name)) { + $value = $node->getAttribute($name); + if (!filter_var($value, FILTER_VALIDATE_URL)) { + $this->addError('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->expression . '" is not valid.', 1724234607); + } + } else { + $this->validateHasAttribute($node, $name); + } + } + + public function validateHasAttributeWithValue(\DOMNode $node, string $name, array $values) + { + if ($node->hasAttribute($name)) { + $value = $node->getAttribute($name); + if (!in_array($value, $values)) { + $this->addError('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->expression . '" is not permissible.', 1724234607); + } + } else { + $this->validateHasAttribute($node, $name); + } + } + + public function validateHasUniqueId(\DOMNode $node) + { + if ($node->hasAttribute("ID")) { + $id = $node->getAttribute("ID"); + if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { + $this->addError('"ID" attribute "' . $id . '" of "' . $this->expression . '" already exists.', 1724234607); + } + } else { + $this->validateHasAttribute($node, "ID"); + } + } + + /** + * @param \DOMNode $node + * @param string $name + * @return void + */ + public function validateHasAttribute(\DOMNode $node, string $name): void + { + if (!$node->hasAttribute($name)) { + $this->addError('Mandatory "' . $name . '" attribute of "' . $this->expression . '" is missing.', 1724234607); + } + } + + protected function isValid($value): void + { + $this->xpath = new DOMXPath($value); + $this->isValidDocument(); + } + + protected abstract function isValidDocument(); + +} diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index aad1df5c3..d60052225 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -39,59 +39,55 @@ class AdministrativeMetadataValidator extends ApplicationProfileBaseValidator { protected function isValidDocument(): void { - if ($this->xpath->query('//mets:amdSec[@TYPE="LOGICAL"]')->length == 0) { - $this->addError('Every METS file has to have at least one logical structural element.', 1723727164447); + // Validates against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" + $admSections = $this->xpath->query('//mets:amdSec'); + if ($admSections === false || $admSections->length == 0) { + $this->addError('Every METS file has to have at least one administrative metadata section.', 1723727164447); } - $this->validateStructuralElements(); + $hasDFGViewerSpecifics = false; + foreach ($admSections as $admSection) { + $this->validateTechnicalMetadata($admSection); + $hasDFGViewerSpecifics = ($this->xpath->query('/mets:rightsMD', $admSection)->length != 0 || + $this->xpath->query('/mets:digiprovMD', $admSection)->length != 0); + } - $this->validateExternalReference(); + if ($hasDFGViewerSpecifics) { + $this->addError('Every METS file must include at least one administrative metadata section containing "mets:rightsMD" and "mets:digiprovMD" as child elements.', 1723727164447); + } } /** + * Validates the technical metadata. + * + * Validates against the rules of chapters "2.6.2.1 Technische Metadaten – mets:techMD" and "2.6.2.2 Eingebettete technische Daten – mets:techMD/mets:mdWrap" + * * @return void */ - private function validateStructuralElements(): void + private function validateTechnicalMetadata(\DOMNode $amdSection): void { - $structuralElements = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); - if ($structuralElements->length == 0) { - $this->addError('Every logical structure has to consist of at least on mets:div.', 1724234607); - } else { - foreach ($structuralElements as $structuralElement) { - if (!$structuralElement->hasAttribute("ID")) { - $this->addError('Mandatory "ID" attribute of mets:div in the logical structure is missing.', 1724234607); - } + $technicalElements = $this->xpath->query('/mets:techMD', $amdSection); + if ($technicalElements === false || $technicalElements->length == 0) { + return; + } - if (!$structuralElement->hasAttribute("TYPE")) { - $this->addError('Mandatory "TYPE" attribute of mets:div in the logical structure is missing.', 1724234607); - } else { - if (!in_array($structuralElement->getAttribute("TYPE"), self::STRUCTURE_DATASET)) { - $this->addError('Value "' . $structuralElement->getAttribute("TYPE") . '" of "TYPE" attribute of mets:div in the logical structure is not permissible.', 1724234607); - } - } - } + if ($technicalElements->length > 1) { + $this->addError('Every "mets:amdSec" has to consist none or one "mets:techMD".', 1724234607); } - } - /** - * @return void - */ - private function validateExternalReference(): void - { - $externalReference = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr'); - if ($externalReference->length > 1) { - $this->addError('Every mets:div in the logical structure may only contain one mets:mptr.', 1724234607); - } else if ($externalReference->length == 1) { - if (!$externalReference->hasAttribute("LOCTYPE")) { - $this->addError('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', 1724234607); + if ($technicalElements->length == 1) { + $mdWrap = $this->xpath->query('/mets:mdWrap', $technicalElements->item(0)); + if( $mdWrap === false || $mdWrap->length != 1 ) { + $this->addError('Every "mets:techMD" has to consist one "mets:mdWrap".', 1724234607); } else { - if (!in_array($externalReference->getAttribute("LOCTYPE"), array("URL", "PURL"))) { - $this->addError('Value "' . $externalReference->getAttribute("LOCTYPE") . '" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.', 1724234607); + if (!$mdWrap->hasAttribute("MDTYPE") || $mdWrap->hasAttribute("OTHERMDTYPE")) { + $this->addError('Mandatory attribute "MDTYPE" or "OTHERMDTYPE" of "mets:techMD/mets:mdWrap" is missing', 1724234607); } - } - if (!$externalReference->hasAttribute("xlink:href")) { - $this->addError('Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.', 1724234607); + $xmlData = $this->xpath->query('/mets:xmlData', $mdWrap); + if ($xmlData === false || $xmlData->length == 0) { + $this->addError('Every "mets:techMD/mets:mdWrap" has to consist one "mets:xmlData"', 1724234607); + } } } } diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index 6392ba32d..a44961850 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -37,17 +37,20 @@ */ class LogicalStructureValidator extends ApplicationProfileBaseValidator { + + const XPATH_LOGICAL_STRUCTURES = '//mets:mets/mets:structMap[@TYPE="LOGICAL"]'; + + const XPATH_STRUCTURAL_ELEMENTS = self::XPATH_LOGICAL_STRUCTURES . '/mets:div'; + + const XPATH_EXTERNAL_REFERENCES = self::XPATH_STRUCTURAL_ELEMENTS . '/mets:mptr'; + protected function isValidDocument(): void { // Validates against the rules of chapter "2.1.1 Logical structure - mets:structMap" - if ($this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]')->length == 0) { - $this->addError('Every METS file has to have at least one logical structural element.', 1723727164447); - } + $this->query(self::XPATH_LOGICAL_STRUCTURES)->validateHasAny(); $this->validateStructuralElements(); - - $this->validateExternalReference(); - + $this->validateExternalReferences(); $this->validatePeriodicPublishingSequences(); } @@ -58,30 +61,17 @@ protected function isValidDocument(): void * * @return void */ - private function validateStructuralElements(): void + protected function validateStructuralElements(): void { - $structuralElements = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); - if ($structuralElements->length == 0) { - $this->addError('Every logical structure has to consist of at least one mets:div.', 1724234607); - } else { - foreach ($structuralElements as $structuralElement) { - if (!$structuralElement->hasAttribute("ID")) { - $this->addError('Mandatory "ID" attribute of mets:div in the logical structure is missing.', 1724234607); - } else { - $id = $structuralElement->getAttribute("ID"); - if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { - $this->addError('Logical structure "ID" "' . $id . '" already exists in document.', 1724234607); - } - } - if (!$structuralElement->hasAttribute("TYPE")) { - $this->addError('Mandatory "TYPE" attribute of mets:div in the logical structure is missing.', 1724234607); - } else { - if (!in_array($structuralElement->getAttribute("TYPE"), self::STRUCTURE_DATASET)) { - $this->addError('Value "' . $structuralElement->getAttribute("TYPE") . '" of "TYPE" attribute of mets:div in the logical structure is not permissible.', 1724234607); - } - } - } - } + $this->query(self::XPATH_STRUCTURAL_ELEMENTS) + ->validateHasAny() + ->iterate(array($this, "validateStructuralElement")); + } + + protected function validateStructuralElement(\DOMNode $structureElement): void + { + $this->validateHasUniqueId($structureElement); + $this->validateHasAttributeWithValue($structureElement, "TYPE", self::STRUCTURE_DATASET); } /** @@ -91,31 +81,17 @@ private function validateStructuralElements(): void * * @return void */ - private function validateExternalReference(): void + protected function validateExternalReferences(): void { - $externalReferences = $this->xpath->query('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr'); - if ($externalReferences->length > 1) { - $this->addError('Every mets:div in the logical structure may only contain one mets:mptr.', 1724234607); - } else if ($externalReferences->length == 1) { - $externalReference = $externalReferences->item(0); - if (!$externalReference->hasAttribute("LOCTYPE")) { - $this->addError('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.', 1724234607); - } else { - if (!in_array($externalReference->getAttribute("LOCTYPE"), array("URL", "PURL"))) { - $this->addError('Value "' . $externalReference->getAttribute("LOCTYPE") . '" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.', 1724234607); - } - } - if (!$externalReference->hasAttribute("xlink:href")) { - $this->addError('Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.', 1724234607); - } else { - if (!filter_var($externalReference->getAttribute("xlink:href"), FILTER_VALIDATE_URL)) { - $this->addError('URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.', 1727792902); - } - } - - //*[@id="button"] + $this->query(self::XPATH_EXTERNAL_REFERENCES) + ->validateHasNoneOrOne() + ->iterate(array($this, "validateExternalReference")); + } - } + protected function validateExternalReference(\DOMNode $externalReference): void + { + $this->validateHasAttributeWithValue($externalReference, "LOCTYPE", array("URL", "PURL")); + $this->validateHasAttributeWithUrl($externalReference, "xlink:href"); } /** @@ -125,7 +101,7 @@ private function validateExternalReference(): void * * @return void */ - private function validatePeriodicPublishingSequences(): void + protected function validatePeriodicPublishingSequences(): void { // TODO } diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index aaf39dfe3..5718fa527 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -80,16 +80,12 @@ public function validate(): Result * Validates using a validator and DOMDocument, then asserts that the resulting error message matches the expected value. * * @param $message - * @param $resetDocument bool True if the document is to be reset at the end of the function. * @return void */ - public function validateAndAssertEquals(string $message, bool $resetDocument = false): void + public function validateAndAssertEquals(string $message): void { $result = $this->validator->validate($this->doc); self::assertEquals($message, $result->getFirstError()->getMessage()); - if ($resetDocument) { - $this->resetDocument(); - } } protected function resetDocument(): void @@ -178,4 +174,41 @@ private function getDOMDocument(): DOMDocument self::assertNotFalse($doc); return $doc; } + + + public function assertHasAny(string $expression): void + { + $this->validateAndAssertEquals('There must be at least one element that matches the XPath expression "' . $expression . '"'); + } + + public function assertHasOne(string $expression): void + { + $this->validateAndAssertEquals('There must be an element that matches the XPath expression "' . $expression . '"'); + } + + public function assertHasNoneOrOne(string $expression): void + { + $this->validateAndAssertEquals('There must be no more than one element that matches the XPath expression "' . $expression . '"'); + } + + public function assertHasAttribute(string $expression, string $name): void + { + $this->validateAndAssertEquals('Mandatory "' . $name . '" attribute of "' . $expression . '" is missing.'); + } + + public function assertHasAttributeWithValue(string $expression, string $name, string $value): void + { + $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not permissible.'); + } + + public function assertHasAttributeWithUrl(string $expression, string $name, string $value): void + { + $this->validateAndAssertEquals('URL "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not valid.'); + } + + public function assertHasUniqueId(string $expression, string $value): void + { + $this->validateAndAssertEquals('"ID" attribute "' . $value . '" of "' . $expression . '" already exists.'); + } + } diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index 2c8e15add..d4e314ee4 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -37,7 +37,7 @@ class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileVal * * @return void */ - public function testMultipleStructLinks(): void + /* public function testMultipleStructLinks(): void { $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:structLink'); $this->validateAndAssertEquals('Every METS file has to have no or one struct link element.'); @@ -54,7 +54,7 @@ public function testLinkElements(): void $this->setAttributeValue('//mets:structLink/mets:smLink', 'xlink:to', 'Test'); $this->validateAndAssertEquals('None or multiple ids found for "Test" in struct map type "PHYSICAL".', true); } - +*/ protected function createValidator(): AbstractDlfValidator { return new LinkingLogicalPhysicalStructureValidator(); diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index 210690f23..c8f787eef 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -38,8 +38,8 @@ class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest */ public function testNotExistingLogicalStructureElement(): void { - $this->removeNodes( '//mets:structMap[@TYPE="LOGICAL"]'); - $this->validateAndAssertEquals('Every METS file has to have at least one logical structural element.'); + $this->removeNodes(LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); + $this->assertHasAny(LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); } /** @@ -48,49 +48,52 @@ public function testNotExistingLogicalStructureElement(): void */ public function testStructuralElements(): void { - $this->removeNodes('//mets:structMap[@TYPE="LOGICAL"]/mets:div'); - $this->validateAndAssertEquals('Every logical structure has to consist of at least one mets:div.', true); + $this->removeNodes(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->assertHasAny(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->resetDocument(); - $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'ID'); - $this->validateAndAssertEquals('Mandatory "ID" attribute of mets:div in the logical structure is missing.', true); + $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->assertHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->resetDocument(); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); - $this->addChildNode('//mets:structMap[@TYPE="LOGICAL"]/mets:div', $node); - $this->validateAndAssertEquals('Logical structure "ID" "LOG_0001" already exists in document.', true); + $this->addChildNode(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, $node); + $this->assertHasUniqueId(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'LOG_0001'); + $this->resetDocument(); - $this->removeAttribute('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE'); - $this->validateAndAssertEquals('Mandatory "TYPE" attribute of mets:div in the logical structure is missing.', true); + $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->assertHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div', 'TYPE', 'Test'); - $this->validateAndAssertEquals('Value "Test" of "TYPE" attribute of mets:div in the logical structure is not permissible.', true); + $this->setAttributeValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->assertHasAttributeWithValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); } - - /** * Test validation against the rules of chapter "2.1.2.2 Reference to external METS-files - mets:div / mets:mptr" * @return void + * @throws \DOMException */ public function testExternalReference(): void { - $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $this->validateAndAssertEquals('Every mets:div in the logical structure may only contain one mets:mptr.', true); + $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->assertHasNoneOrOne(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES); + $this->resetDocument(); - $this->addChildNodeNS('//mets:structMap[@TYPE="LOGICAL"]/mets:div', self::NAMESPACE_METS, 'mets:mptr'); - $this->validateAndAssertEquals('Mandatory "LOCTYPE" attribute of mets:mptr in the logical structure is missing.'); + $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->assertHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE'); - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); - $this->validateAndAssertEquals('Value "Test" of "LOCTYPE" attribute of mets:mptr in the logical structure is not permissible.'); + $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); + $this->assertHasAttributeWithValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'LOCTYPE', 'URL'); - $this->validateAndAssertEquals('Mandatory "xlink:href" attribute of mets:mptr in the logical structure is missing.'); + $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); + $this->assertHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href'); - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'Test'); - $this->validateAndAssertEquals('URL of attribute value "xlink:href" of mets:mptr in the logical structure is not valid.'); + $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); + $this->assertHasAttributeWithUrl(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); - $this->setAttributeValue('//mets:structMap[@TYPE="LOGICAL"]/mets:div/mets:mptr', 'xlink:href', 'http://example.com/periodical.xml'); + $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); $result = $this->validate(); self::assertFalse($result->hasErrors()); } diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index 68b16d993..5da59625d 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -36,20 +36,20 @@ class PhysicalStructureValidatorTest extends ApplicationProfileValidatorTest * * @return void */ - public function testMultiplePhysicalDivisions(): void + /*public function testMultiplePhysicalDivisions(): void { $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:structMap'); $node->setAttribute('TYPE', 'PHYSICAL'); $this->addChildNode('/mets:mets', $node); $this->validateAndAssertEquals('Every METS file has to have no or one physical structural element.'); - } + }*/ /** * Test validation against the rules of chapter "2.2.2.1 Structural element - mets:div" * * @return void */ - public function testStructuralElements(): void + /* public function testStructuralElements(): void { $this->removeNodes('//mets:structMap[@TYPE="PHYSICAL"]/mets:div'); $this->validateAndAssertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', true); @@ -74,7 +74,7 @@ public function testStructuralElements(): void $this->setAttributeValue('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE', 'Test'); $this->validateAndAssertEquals('Value "Test" of "TYPE" attribute of mets:div in physical structure is not permissible.'); } - +*/ protected function createValidator(): AbstractDlfValidator { return new PhysicalStructureValidator(); From bf64b50dffcddfa8947a75ae8e9ad32d412b4e11 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 13 Dec 2024 17:27:48 +0100 Subject: [PATCH 11/43] Rename assert function to a more suitable name --- .../ApplicationProfileValidatorTest.php | 15 ++++++------- .../Mets/LogicalStructureValidatorTest.php | 22 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index 5718fa527..36908fa43 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -175,38 +175,37 @@ private function getDOMDocument(): DOMDocument return $doc; } - - public function assertHasAny(string $expression): void + public function assertErrorHasAny(string $expression): void { $this->validateAndAssertEquals('There must be at least one element that matches the XPath expression "' . $expression . '"'); } - public function assertHasOne(string $expression): void + public function assertErrorHasOne(string $expression): void { $this->validateAndAssertEquals('There must be an element that matches the XPath expression "' . $expression . '"'); } - public function assertHasNoneOrOne(string $expression): void + public function assertErrorHasNoneOrOne(string $expression): void { $this->validateAndAssertEquals('There must be no more than one element that matches the XPath expression "' . $expression . '"'); } - public function assertHasAttribute(string $expression, string $name): void + public function assertErrorHasAttribute(string $expression, string $name): void { $this->validateAndAssertEquals('Mandatory "' . $name . '" attribute of "' . $expression . '" is missing.'); } - public function assertHasAttributeWithValue(string $expression, string $name, string $value): void + public function assertErrorHasAttributeWithValue(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not permissible.'); } - public function assertHasAttributeWithUrl(string $expression, string $name, string $value): void + public function assertErrorHasAttributeWithUrl(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('URL "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not valid.'); } - public function assertHasUniqueId(string $expression, string $value): void + public function validateErrorHasUniqueId(string $expression, string $value): void { $this->validateAndAssertEquals('"ID" attribute "' . $value . '" of "' . $expression . '" already exists.'); } diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index c8f787eef..5feae6a1b 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -39,7 +39,7 @@ class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest public function testNotExistingLogicalStructureElement(): void { $this->removeNodes(LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); - $this->assertHasAny(LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); + $this->assertErrorHasAny(LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); } /** @@ -49,24 +49,24 @@ public function testNotExistingLogicalStructureElement(): void public function testStructuralElements(): void { $this->removeNodes(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); - $this->assertHasAny(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->assertErrorHasAny(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); $this->resetDocument(); $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); - $this->assertHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); $this->resetDocument(); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); $this->addChildNode(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, $node); - $this->assertHasUniqueId(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'LOG_0001'); + $this->validateErrorHasUniqueId(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'LOG_0001'); $this->resetDocument(); $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); - $this->assertHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); $this->setAttributeValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); - $this->assertHasAttributeWithValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); } /** @@ -78,20 +78,20 @@ public function testExternalReference(): void { $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->assertHasNoneOrOne(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES); + $this->assertErrorHasNoneOrOne(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES); $this->resetDocument(); $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->assertHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE'); + $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); - $this->assertHasAttributeWithValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); - $this->assertHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href'); + $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); - $this->assertHasAttributeWithUrl(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); + $this->assertErrorHasAttributeWithUrl(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); $result = $this->validate(); From 9324cf3d820c554002b504125d5b93a01cff4046 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Mon, 16 Dec 2024 12:18:18 +0100 Subject: [PATCH 12/43] Refactor PhysicalStructureValidator including test --- Classes/Validation/DOMDocumentValidator.php | 86 +++++++++++++------ .../Mets/LogicalStructureValidator.php | 10 ++- .../Mets/PhysicalStructureValidator.php | 52 +++++------ .../Mets/PhysicalStructureValidatorTest.php | 44 ++++++---- 4 files changed, 117 insertions(+), 75 deletions(-) diff --git a/Classes/Validation/DOMDocumentValidator.php b/Classes/Validation/DOMDocumentValidator.php index 74092b30e..1723fe1eb 100644 --- a/Classes/Validation/DOMDocumentValidator.php +++ b/Classes/Validation/DOMDocumentValidator.php @@ -3,6 +3,7 @@ namespace Slub\Dfgviewer\Validation; use DOMDocument; +use DOMNode; use DOMNodeList; use DOMXPath; use Kitodo\Dlf\Validation\AbstractDlfValidator; @@ -13,6 +14,8 @@ abstract class DOMDocumentValidator extends AbstractDlfValidator private string $expression; + private DOMNode $node; + private DOMNodeList $nodeList; public function __construct() @@ -20,14 +23,14 @@ public function __construct() parent::__construct(DOMDocument::class); } - public function query(string $expression) + public function query(string $expression): DOMDocumentValidator { $this->expression = $expression; $this->nodeList = $this->xpath->query($this->expression); return $this; } - public function iterate(callable $callback) + public function iterate(callable $callback): DOMDocumentValidator { foreach ($this->nodeList as $node) { call_user_func_array($callback, array($node)); @@ -35,7 +38,27 @@ public function iterate(callable $callback) return $this; } - public function validateHasAny() + public function setNode(DOMNode $node): DOMDocumentValidator + { + $this->node = $node; + return $this; + } + + public function getFirst(): DOMDocumentValidator + { + $this->selectNode(0); + return $this; + } + + public function selectNode(int $index): DOMDocumentValidator + { + if($this->nodeList->count() > $index) { + $this->node = $this->nodeList->item($index); + } + return $this; + } + + public function validateHasAny(): DOMDocumentValidator { if (!$this->nodeList->length > 0) { $this->addError('There must be at least one element that matches the XPath expression "' . $this->expression . '"', 1723727164447); @@ -43,7 +66,7 @@ public function validateHasAny() return $this; } - public function validateHasOne() + public function validateHasOne(): DOMDocumentValidator { if ($this->nodeList->length != 1) { $this->addError('There must be an element that matches the XPath expression "' . $this->expression . '"', 1723727164447); @@ -51,7 +74,7 @@ public function validateHasOne() return $this; } - public function validateHasNoneOrOne() + public function validateHasNoneOrOne(): DOMDocumentValidator { if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { $this->addError('There must be no more than one element that matches the XPath expression "' . $this->expression . '"', 1723727164447); @@ -59,52 +82,67 @@ public function validateHasNoneOrOne() return $this; } - public function validateHasAttributeWithUrl(\DOMNode $node, string $name) + public function validateHasAttributeWithUrl(string $name): DOMDocumentValidator { - if ($node->hasAttribute($name)) { - $value = $node->getAttribute($name); + if(!isset($this->node)) { + return $this; + } + + if ($this->node->hasAttribute($name)) { + $value = $this->node->getAttribute($name); if (!filter_var($value, FILTER_VALIDATE_URL)) { $this->addError('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->expression . '" is not valid.', 1724234607); } } else { - $this->validateHasAttribute($node, $name); + $this->validateHasAttribute($name); } + return $this; } - public function validateHasAttributeWithValue(\DOMNode $node, string $name, array $values) + public function validateHasAttributeWithValue(string $name, array $values): DOMDocumentValidator { - if ($node->hasAttribute($name)) { - $value = $node->getAttribute($name); + if(!isset($this->node)) { + return $this; + } + + if ($this->node->hasAttribute($name)) { + $value = $this->node->getAttribute($name); if (!in_array($value, $values)) { $this->addError('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->expression . '" is not permissible.', 1724234607); } } else { - $this->validateHasAttribute($node, $name); + $this->validateHasAttribute($name); } + return $this; } - public function validateHasUniqueId(\DOMNode $node) + public function validateHasUniqueId(): DOMDocumentValidator { - if ($node->hasAttribute("ID")) { - $id = $node->getAttribute("ID"); + if(!isset($this->node)) { + return $this; + } + + if ($this->node->hasAttribute("ID")) { + $id = $this->node->getAttribute("ID"); if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { $this->addError('"ID" attribute "' . $id . '" of "' . $this->expression . '" already exists.', 1724234607); } } else { - $this->validateHasAttribute($node, "ID"); + $this->validateHasAttribute("ID"); } + return $this; } - /** - * @param \DOMNode $node - * @param string $name - * @return void - */ - public function validateHasAttribute(\DOMNode $node, string $name): void + public function validateHasAttribute(string $name): DOMDocumentValidator { - if (!$node->hasAttribute($name)) { + if(!isset($this->node)) { + return $this; + } + + if (!$this->node->hasAttribute($name)) { $this->addError('Mandatory "' . $name . '" attribute of "' . $this->expression . '" is missing.', 1724234607); } + return $this; } protected function isValid($value): void diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index a44961850..59dac8f5a 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -70,8 +70,9 @@ protected function validateStructuralElements(): void protected function validateStructuralElement(\DOMNode $structureElement): void { - $this->validateHasUniqueId($structureElement); - $this->validateHasAttributeWithValue($structureElement, "TYPE", self::STRUCTURE_DATASET); + $this->setNode($structureElement) + ->validateHasUniqueId() + ->validateHasAttributeWithValue("TYPE", self::STRUCTURE_DATASET); } /** @@ -90,8 +91,9 @@ protected function validateExternalReferences(): void protected function validateExternalReference(\DOMNode $externalReference): void { - $this->validateHasAttributeWithValue($externalReference, "LOCTYPE", array("URL", "PURL")); - $this->validateHasAttributeWithUrl($externalReference, "xlink:href"); + $this->setNode($externalReference) + ->validateHasAttributeWithValue("LOCTYPE", array("URL", "PURL")) + ->validateHasAttributeWithUrl("xlink:href"); } /** diff --git a/Classes/Validation/Mets/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php index 8e2ec902f..170d77a19 100644 --- a/Classes/Validation/Mets/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -37,16 +37,20 @@ */ class PhysicalStructureValidator extends ApplicationProfileBaseValidator { + const XPATH_PHYSICAL_STRUCTURES = '//mets:mets/mets:structMap[@TYPE="PHYSICAL"]'; + + const XPATH_STRUCTURAL_ELEMENT_SEQUENCE = self::XPATH_PHYSICAL_STRUCTURES . '/mets:div'; + + const XPATH_STRUCTURAL_ELEMENTS = self::XPATH_STRUCTURAL_ELEMENT_SEQUENCE . '/mets:div'; + protected function isValidDocument(): void { // Validates against the rules of chapter "2.2.1 Physical structure - mets:structMap" - if ($this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]')->length > 1) { - $this->addError('Every METS file has to have no or one physical structural element.', 1723727164447); - } + $this->query(self::XPATH_PHYSICAL_STRUCTURES)->validateHasNoneOrOne(); + $this->validateStructuralElements(); } - /** * * Validates the structural elements. @@ -57,31 +61,21 @@ protected function isValidDocument(): void */ private function validateStructuralElements(): void { - if ($this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]')->length == 0) { - $this->addError('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', 1724234607); - } + $this->query(self::XPATH_STRUCTURAL_ELEMENT_SEQUENCE ) + ->validateHasOne() + ->getFirst() + ->validateHasAttributeWithValue('TYPE', array('physSequence')); - $subordinateStructuralElements = $this->xpath->query('//mets:structMap[@TYPE="PHYSICAL"]/mets:div[@TYPE="physSequence"]/mets:div'); - if ($subordinateStructuralElements->length == 0) { - $this->addError('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', 1724234607); - } else { - foreach ($subordinateStructuralElements as $subordinateStructuralElement) { - if (!$subordinateStructuralElement->hasAttribute("ID")) { - $this->addError('Mandatory "ID" attribute of mets:div in the physical structure is missing.', 1724234607); - } else { - $id = $subordinateStructuralElement->getAttribute("ID"); - if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { - $this->addError('Physical structure "ID" "' . $id . '" already exists in document.', 1724234607); - } - } - if (!$subordinateStructuralElement->hasAttribute("TYPE")) { - $this->addError('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', 1724234607); - } else { - if (!in_array($subordinateStructuralElement->getAttribute("TYPE"), array("page", "doublepage", "track"))) { - $this->addError('Value "' . $subordinateStructuralElement->getAttribute("TYPE") . '" of "TYPE" attribute of mets:div in physical structure is not permissible.', 1724234607); - } - } - } - } + $this->query(self::XPATH_STRUCTURAL_ELEMENTS) + ->validateHasAny() + ->iterate(array($this, "validateStructuralElement")); } + + protected function validateStructuralElement(\DOMNode $structureElement): void + { + $this->setNode($structureElement) + ->validateHasUniqueId() + ->validateHasAttributeWithValue("TYPE", array("page", "doublepage", "track")); + } + } diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index 5da59625d..e7e647c5d 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -36,45 +36,53 @@ class PhysicalStructureValidatorTest extends ApplicationProfileValidatorTest * * @return void */ - /*public function testMultiplePhysicalDivisions(): void + public function testMultiplePhysicalDivisions(): void { $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:structMap'); $node->setAttribute('TYPE', 'PHYSICAL'); $this->addChildNode('/mets:mets', $node); - $this->validateAndAssertEquals('Every METS file has to have no or one physical structural element.'); - }*/ + $this->assertErrorHasNoneOrOne(PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); + } /** * Test validation against the rules of chapter "2.2.2.1 Structural element - mets:div" * * @return void */ - /* public function testStructuralElements(): void + public function testStructuralElements(): void { - $this->removeNodes('//mets:structMap[@TYPE="PHYSICAL"]/mets:div'); - $this->validateAndAssertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', true); + $this->removeNodes(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE); + $this->assertErrorHasOne(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE); + $this->resetDocument(); + + $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); + $this->assertErrorHasAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); - $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', 'TYPE'); - $this->validateAndAssertEquals('Every physical structure has to consist of one mets:div with "TYPE" attribute and value "physSequence" for the sequence.', true); + $this->setAttributeValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); + $this->resetDocument(); - $this->removeNodes('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div'); - $this->validateAndAssertEquals('Every physical structure has to consist of one mets:div for the sequence and at least of one subordinate mets:div.', true); + $this->removeNodes(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->assertErrorHasAny(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->resetDocument(); - $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'ID'); - $this->validateAndAssertEquals('Mandatory "ID" attribute of mets:div in the physical structure is missing.', true); + $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->assertErrorHasAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->resetDocument(); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'PHYS_0001'); $this->addChildNode('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', $node); - $this->validateAndAssertEquals('Physical structure "ID" "PHYS_0001" already exists in document.', true); + $this->validateErrorHasUniqueId(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'PHYS_0001'); + $this->resetDocument(); - $this->removeAttribute('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE'); - $this->validateAndAssertEquals('Mandatory "TYPE" attribute of subordinate mets:div in physical structure is missing.', true); + $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->assertErrorHasAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); - $this->setAttributeValue('//mets:structMap[@TYPE="PHYSICAL"]/mets:div/mets:div', 'TYPE', 'Test'); - $this->validateAndAssertEquals('Value "Test" of "TYPE" attribute of mets:div in physical structure is not permissible.'); + $this->setAttributeValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); } -*/ + protected function createValidator(): AbstractDlfValidator { return new PhysicalStructureValidator(); From da52ae919ee22e4295926298848ffde99569a52e Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Mon, 16 Dec 2024 14:55:54 +0100 Subject: [PATCH 13/43] Update struct link validation and tests --- Classes/Validation/DOMDocumentValidator.php | 21 +++++++ ...nkingLogicalPhysicalStructureValidator.php | 55 ++++++------------- .../ApplicationProfileValidatorTest.php | 21 ++++--- ...gLogicalPhysicalStructureValidatorTest.php | 25 +++++---- 4 files changed, 65 insertions(+), 57 deletions(-) diff --git a/Classes/Validation/DOMDocumentValidator.php b/Classes/Validation/DOMDocumentValidator.php index 1723fe1eb..046e1cd93 100644 --- a/Classes/Validation/DOMDocumentValidator.php +++ b/Classes/Validation/DOMDocumentValidator.php @@ -145,6 +145,27 @@ public function validateHasAttribute(string $name): DOMDocumentValidator return $this; } + public function validateHasRefToOne(string $name, string $targetContextExpression): DOMDocumentValidator + { + if (!isset($this->node)) { + return $this; + } + + $targetNodes = $this->xpath->query($targetContextExpression); + $id = $this->node->getAttribute($name); + + $foundElements = 0; + foreach ($targetNodes as $targetNode) { + $foundElements += $this->xpath->query('//*[@ID="' . $id . '"]', $targetNode)->length; + } + + if ($foundElements !== 1) { + $this->addError('Value "' . $id . '" in the "' . $name . '" attribute of "' . $this->expression . '" must reference one element under XPath expression "' . $targetContextExpression, 1724234607); + } + + return $this; + } + protected function isValid($value): void { $this->xpath = new DOMXPath($value); diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index 599890cbf..5769a4232 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -39,15 +39,17 @@ class LinkingLogicalPhysicalStructureValidator extends ApplicationProfileBaseValidator { + const XPATH_STRUCT_LINK = '//mets:mets/mets:structLink'; + + const XPATH_LINK_ELEMENTS = self::XPATH_STRUCT_LINK . '/mets:smLink' ; + protected function isValidDocument(): void { - $structLinks = $this->xpath->query('//mets:structLink'); // Validates against the rules of chapter "2.3.1 Structure links - mets:structLink" - if ($structLinks === false || $structLinks->length > 1) { - $this->addError('Every METS file has to have no or one struct link element.', 1723727164447); - } elseif ($structLinks->length == 1) { - $this->validateLinkElements(); - } + $this->query(self::XPATH_STRUCT_LINK) + ->validateHasNoneOrOne(); + + $this->validateLinkElements(); } /** @@ -59,41 +61,16 @@ protected function isValidDocument(): void */ private function validateLinkElements(): void { - $linkingElements = $this->xpath->query('//mets:structLink/mets:smLink'); - - if ($linkingElements->length === 0) { - $this->addError('There should be at least one "mets:smLink" under "mets:structLink".', 1723727164447); - } - - foreach ($linkingElements as $linkingElement) { - $this->validateLinkingElement($linkingElement, "xlink:from", "LOGICAL"); - $this->validateLinkingElement($linkingElement, "xlink:to", "PHYSICAL"); - } - + $this->query(self::XPATH_LINK_ELEMENTS) + ->validateHasAny() + ->iterate(array($this, "validateLinkElement")); } - /** - * Validate linking element. - * - * @param DOMNode $linkingElement - * @param string $attribute - * @param string $structMapType - * @return void - */ - private function validateLinkingElement(DOMNode $linkingElement, string $attribute, string $structMapType): void + protected function validateLinkElement(\DOMNode $linkElement): void { - if (!$linkingElement->hasAttribute($attribute)) { - $this->addError('Mandatory "' . $attribute . ' attribute of mets:div in the logical structure is missing.', 1724234607); - } else { - $id = $linkingElement->getAttribute($attribute); - $structMaps = $this->xpath->query('//mets:structMap[@TYPE="' . $structMapType . '"]'); - $foundElements = 0; - foreach ($structMaps as $structMap) { - $foundElements += $this->xpath->query('//mets:div[@ID = \'' . $id . '\']', $structMap)->length; - } - if ($foundElements !== 1) { - $this->addError('None or multiple ids found for "' . $id . '" in struct map type "' . $structMapType . '".', 1724234607); - } - } + $this->setNode($linkElement) + ->validateHasRefToOne("xlink:from", LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES) + ->validateHasRefToOne("xlink:to", PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); } + } diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index 36908fa43..e1601bfac 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -167,7 +167,7 @@ protected function removeAttribute(string $expression, string $attribute): void } } - private function getDOMDocument(): DOMDocument + protected function getDOMDocument(): DOMDocument { $doc = new DOMDocument(); $doc->load(__DIR__ . '/../../Fixtures/mets.xml'); @@ -175,37 +175,42 @@ private function getDOMDocument(): DOMDocument return $doc; } - public function assertErrorHasAny(string $expression): void + protected function assertErrorHasAny(string $expression): void { $this->validateAndAssertEquals('There must be at least one element that matches the XPath expression "' . $expression . '"'); } - public function assertErrorHasOne(string $expression): void + protected function assertErrorHasOne(string $expression): void { $this->validateAndAssertEquals('There must be an element that matches the XPath expression "' . $expression . '"'); } - public function assertErrorHasNoneOrOne(string $expression): void + protected function assertErrorHasNoneOrOne(string $expression): void { $this->validateAndAssertEquals('There must be no more than one element that matches the XPath expression "' . $expression . '"'); } - public function assertErrorHasAttribute(string $expression, string $name): void + protected function assertErrorHasAttribute(string $expression, string $name): void { $this->validateAndAssertEquals('Mandatory "' . $name . '" attribute of "' . $expression . '" is missing.'); } - public function assertErrorHasAttributeWithValue(string $expression, string $name, string $value): void + protected function assertErrorHasAttributeWithValue(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not permissible.'); } - public function assertErrorHasAttributeWithUrl(string $expression, string $name, string $value): void + protected function assertErrorHasAttributeWithUrl(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('URL "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not valid.'); } - public function validateErrorHasUniqueId(string $expression, string $value): void + protected function assertErrorHasRefToOne(string $expression, string $name, string $value, string $targetContextExpression) + { + $this->validateAndAssertEquals( 'Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); + } + + protected function validateErrorHasUniqueId(string $expression, string $value): void { $this->validateAndAssertEquals('"ID" attribute "' . $value . '" of "' . $expression . '" already exists.'); } diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index d4e314ee4..f18cd6daa 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -25,9 +25,10 @@ * This copyright notice MUST APPEAR in all copies of the script! */ - use Kitodo\Dlf\Validation\AbstractDlfValidator; use Slub\Dfgviewer\Validation\Mets\LinkingLogicalPhysicalStructureValidator; +use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; +use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileValidatorTest { @@ -37,26 +38,30 @@ class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileVal * * @return void */ - /* public function testMultipleStructLinks(): void + public function testMultipleStructLinks(): void { $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:structLink'); - $this->validateAndAssertEquals('Every METS file has to have no or one struct link element.'); + $this->assertErrorHasNoneOrOne(LinkingLogicalPhysicalStructureValidator::XPATH_STRUCT_LINK); } public function testLinkElements(): void { - $this->removeNodes('//mets:structLink/mets:smLink'); - $this->validateAndAssertEquals('There should be at least one "mets:smLink" under "mets:structLink".', true); + $this->removeNodes(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS); + $this->assertErrorHasAny(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS); + $this->resetDocument(); - $this->setAttributeValue('//mets:structLink/mets:smLink', 'xlink:from', 'Test'); - $this->validateAndAssertEquals('None or multiple ids found for "Test" in struct map type "LOGICAL".', true); + $this->setAttributeValue(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:from', 'Test'); + $this->assertErrorHasRefToOne(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:from', 'Test', LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); + $this->resetDocument(); - $this->setAttributeValue('//mets:structLink/mets:smLink', 'xlink:to', 'Test'); - $this->validateAndAssertEquals('None or multiple ids found for "Test" in struct map type "PHYSICAL".', true); + $this->setAttributeValue(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:to', 'Test'); + $this->assertErrorHasRefToOne(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:to', 'Test', PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); } -*/ + protected function createValidator(): AbstractDlfValidator { return new LinkingLogicalPhysicalStructureValidator(); } + + } From da925b11de70f4d173cec6fb4b71376a50715ff6 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 19 Dec 2024 13:05:24 +0100 Subject: [PATCH 14/43] Improve validation architecture --- Classes/Validation/DOMDocumentValidator.php | 154 +----------------- Classes/Validation/DOMNodeListValidator.php | 68 ++++++++ Classes/Validation/DOMNodeValidator.php | 105 ++++++++++++ .../Mets/AdministrativeMetadataValidator.php | 108 +++++++----- ...nkingLogicalPhysicalStructureValidator.php | 11 +- .../Mets/LogicalStructureValidator.php | 15 +- .../Mets/PhysicalStructureValidator.php | 18 +- .../ApplicationProfileValidatorTest.php | 6 +- ...gLogicalPhysicalStructureValidatorTest.php | 5 +- .../Mets/LogicalStructureValidatorTest.php | 16 +- .../Mets/PhysicalStructureValidatorTest.php | 12 +- 11 files changed, 292 insertions(+), 226 deletions(-) create mode 100644 Classes/Validation/DOMNodeListValidator.php create mode 100644 Classes/Validation/DOMNodeValidator.php diff --git a/Classes/Validation/DOMDocumentValidator.php b/Classes/Validation/DOMDocumentValidator.php index 046e1cd93..374aad85a 100644 --- a/Classes/Validation/DOMDocumentValidator.php +++ b/Classes/Validation/DOMDocumentValidator.php @@ -4,7 +4,6 @@ use DOMDocument; use DOMNode; -use DOMNodeList; use DOMXPath; use Kitodo\Dlf\Validation\AbstractDlfValidator; @@ -12,166 +11,29 @@ abstract class DOMDocumentValidator extends AbstractDlfValidator { protected DOMXpath $xpath; - private string $expression; - - private DOMNode $node; - - private DOMNodeList $nodeList; - public function __construct() { parent::__construct(DOMDocument::class); } - public function query(string $expression): DOMDocumentValidator - { - $this->expression = $expression; - $this->nodeList = $this->xpath->query($this->expression); - return $this; - } - - public function iterate(callable $callback): DOMDocumentValidator - { - foreach ($this->nodeList as $node) { - call_user_func_array($callback, array($node)); - } - return $this; - } - - public function setNode(DOMNode $node): DOMDocumentValidator - { - $this->node = $node; - return $this; - } - - public function getFirst(): DOMDocumentValidator - { - $this->selectNode(0); - return $this; - } - - public function selectNode(int $index): DOMDocumentValidator - { - if($this->nodeList->count() > $index) { - $this->node = $this->nodeList->item($index); - } - return $this; - } - - public function validateHasAny(): DOMDocumentValidator - { - if (!$this->nodeList->length > 0) { - $this->addError('There must be at least one element that matches the XPath expression "' . $this->expression . '"', 1723727164447); - } - return $this; - } - - public function validateHasOne(): DOMDocumentValidator - { - if ($this->nodeList->length != 1) { - $this->addError('There must be an element that matches the XPath expression "' . $this->expression . '"', 1723727164447); - } - return $this; - } - - public function validateHasNoneOrOne(): DOMDocumentValidator - { - if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { - $this->addError('There must be no more than one element that matches the XPath expression "' . $this->expression . '"', 1723727164447); - } - return $this; - } - - public function validateHasAttributeWithUrl(string $name): DOMDocumentValidator - { - if(!isset($this->node)) { - return $this; - } - - if ($this->node->hasAttribute($name)) { - $value = $this->node->getAttribute($name); - if (!filter_var($value, FILTER_VALIDATE_URL)) { - $this->addError('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->expression . '" is not valid.', 1724234607); - } - } else { - $this->validateHasAttribute($name); - } - return $this; - } - - public function validateHasAttributeWithValue(string $name, array $values): DOMDocumentValidator + protected function isValid($value): void { - if(!isset($this->node)) { - return $this; - } - - if ($this->node->hasAttribute($name)) { - $value = $this->node->getAttribute($name); - if (!in_array($value, $values)) { - $this->addError('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->expression . '" is not permissible.', 1724234607); - } - } else { - $this->validateHasAttribute($name); - } - return $this; + $this->xpath = new DOMXPath($value); + $this->isValidDocument(); } - public function validateHasUniqueId(): DOMDocumentValidator + protected function createNodeListValidator(string $expression, ?DOMNode $contextNode = null): DOMNodeListValidator { - if(!isset($this->node)) { - return $this; - } - - if ($this->node->hasAttribute("ID")) { - $id = $this->node->getAttribute("ID"); - if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { - $this->addError('"ID" attribute "' . $id . '" of "' . $this->expression . '" already exists.', 1724234607); - } - } else { - $this->validateHasAttribute("ID"); - } - return $this; + return new DOMNodeListValidator($this->xpath, $this->result, $expression, $contextNode); } - public function validateHasAttribute(string $name): DOMDocumentValidator + protected function createNodeValidator(?DOMNode $node): DOMNodeValidator { - if(!isset($this->node)) { - return $this; - } - - if (!$this->node->hasAttribute($name)) { - $this->addError('Mandatory "' . $name . '" attribute of "' . $this->expression . '" is missing.', 1724234607); - } - return $this; + return new DOMNodeValidator($this->xpath, $this->result, $node); } - public function validateHasRefToOne(string $name, string $targetContextExpression): DOMDocumentValidator - { - if (!isset($this->node)) { - return $this; - } - - $targetNodes = $this->xpath->query($targetContextExpression); - $id = $this->node->getAttribute($name); - - $foundElements = 0; - foreach ($targetNodes as $targetNode) { - $foundElements += $this->xpath->query('//*[@ID="' . $id . '"]', $targetNode)->length; - } - - if ($foundElements !== 1) { - $this->addError('Value "' . $id . '" in the "' . $name . '" attribute of "' . $this->expression . '" must reference one element under XPath expression "' . $targetContextExpression, 1724234607); - } - - return $this; - } + protected abstract function isValidDocument(); - protected function isValid($value): void - { - $this->xpath = new DOMXPath($value); - $this->isValidDocument(); - } - protected abstract function isValidDocument(); } diff --git a/Classes/Validation/DOMNodeListValidator.php b/Classes/Validation/DOMNodeListValidator.php new file mode 100644 index 000000000..1d98ed037 --- /dev/null +++ b/Classes/Validation/DOMNodeListValidator.php @@ -0,0 +1,68 @@ +expression = $expression; + $this->nodeList = $xpath->query($expression, $contextNode); + $this->result = $result; + } + + public function iterate(callable $callback): DOMNodeListValidator + { + foreach ($this->nodeList as $node) { + call_user_func_array($callback, array($node)); + } + return $this; + } + + public function getFirstNode(): ?DOMNode + { + return $this->getNode(0); + } + + public function getNode(int $index): ?DOMNode + { + return $this->nodeList->item($index); + } + + public function validateHasAny(): DOMNodeListValidator + { + if (!$this->nodeList->length > 0) { + $this->result->addError(new Error('There must be at least one element that matches the XPath expression "' . $this->expression . '"', 23)); + } + return $this; + } + + public function validateHasOne(): DOMNodeListValidator + { + if ($this->nodeList->length != 1) { + $this->result->addError(new Error('There must be an element that matches the XPath expression "' . $this->expression . '"', 434)); + } + return $this; + } + + public function validateHasNoneOrOne(): DOMNodeListValidator + { + if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { + $this->result->addError(new Error('There must be no more than one element that matches the XPath expression "' . $this->expression . '"', 43)); + } + return $this; + } + +} diff --git a/Classes/Validation/DOMNodeValidator.php b/Classes/Validation/DOMNodeValidator.php new file mode 100644 index 000000000..355b20b95 --- /dev/null +++ b/Classes/Validation/DOMNodeValidator.php @@ -0,0 +1,105 @@ +xpath = $xpath; + $this->result = $result; + $this->node = $node; + } + + public function validateHasAttributeWithUrl(string $name): DOMNodeValidator + { + if (!isset($this->node)) { + return $this; + } + + if ($this->node->hasAttribute($name)) { + $value = $this->node->getAttribute($name); + if (!filter_var($value, FILTER_VALIDATE_URL)) { + $this->result->addError(new Error('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); + } + } else { + $this->validateHasAttribute($name); + } + return $this; + } + + public function validateHasAttributeWithValue(string $name, array $values): DOMNodeValidator + { + if (!isset($this->node)) { + return $this; + } + + if ($this->node->hasAttribute($name)) { + $value = $this->node->getAttribute($name); + if (!in_array($value, $values)) { + $this->result->addError(new Error('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not permissible.', 1724234607)); + } + } else { + $this->validateHasAttribute($name); + } + return $this; + } + + public function validateHasUniqueId(): DOMNodeValidator + { + if (!isset($this->node)) { + return $this; + } + + if ($this->node->hasAttribute("ID")) { + $id = $this->node->getAttribute("ID"); + if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { + $this->result->addError(new Error('"ID" attribute "' . $id . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); + } + } else { + $this->validateHasAttribute("ID"); + } + return $this; + } + + public function validateHasAttribute(string $name): DOMNodeValidator + { + if (!isset($this->node)) { + return $this; + } + + if (!$this->node->hasAttribute($name)) { + $this->result->addError(new Error('Mandatory "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is missing.', 1724234607)); + } + return $this; + } + + public function validateHasRefToOne(string $name, string $targetContextExpression): DOMNodeValidator + { + if (!isset($this->node)) { + return $this; + } + + $targetNodes = $this->xpath->query($targetContextExpression); + $id = $this->node->getAttribute($name); + + $foundElements = 0; + foreach ($targetNodes as $targetNode) { + $foundElements += $this->xpath->query('//*[@ID="' . $id . '"]', $targetNode)->length; + } + + if ($foundElements !== 1) { + $this->result->addError(new Error('Value "' . $id . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" must reference one element under XPath expression "' . $targetContextExpression, 1724234607)); + } + + return $this; + } + +} diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index d60052225..cfe2aeec2 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -37,24 +37,55 @@ */ class AdministrativeMetadataValidator extends ApplicationProfileBaseValidator { + + const XPATH_ADMINISTRATIV_METADATA = '//mets:mets/mets:amdSec'; + + const XPATH_TECHNICAL_METADATA = self::XPATH_ADMINISTRATIV_METADATA . '/mets:techMD'; + + const XPATH_RIGHTS_METADATA = self::XPATH_ADMINISTRATIV_METADATA . '/mets:rightsMD'; + protected function isValidDocument(): void { // Validates against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" - $admSections = $this->xpath->query('//mets:amdSec'); - if ($admSections === false || $admSections->length == 0) { - $this->addError('Every METS file has to have at least one administrative metadata section.', 1723727164447); - } - - $hasDFGViewerSpecifics = false; - foreach ($admSections as $admSection) { - $this->validateTechnicalMetadata($admSection); - $hasDFGViewerSpecifics = ($this->xpath->query('/mets:rightsMD', $admSection)->length != 0 || - $this->xpath->query('/mets:digiprovMD', $admSection)->length != 0); - } - - if ($hasDFGViewerSpecifics) { - $this->addError('Every METS file must include at least one administrative metadata section containing "mets:rightsMD" and "mets:digiprovMD" as child elements.', 1723727164447); - } + $this->createNodeListValidator(self::XPATH_ADMINISTRATIV_METADATA) + ->validateHasAny() + ->iterate(array($this, "validateAdministrativMetadata")); + + // Check if one administrativ metadata exist with "mets:rightsMD" and "mets:digiprovMD" as children + $this->createNodeListValidator(self::XPATH_ADMINISTRATIV_METADATA . '[mets:rightsMD and mets:digiprovMD]') + ->validateHasOne(); + + $this->validateTechnicalMetadataStructure(); + $this->validateRightsMetadataStructure(); + } + + protected function validateAdministrativMetadata(\DOMNode $administrativeMetadata): void + { + $this->createNodeValidator($administrativeMetadata) + ->validateHasUniqueId(); + } + + protected function validateRightsMetadataStructure(): void + { + $this->createNodeListValidator(self::XPATH_RIGHTS_METADATA) + ->iterate(array($this, "validateRightsMetadata")); + } + + protected function validateRightsMetadata(\DOMNode $rightsMetadata): void + { + $this->createNodeValidator($rightsMetadata) + ->validateHasUniqueId(); + + $node = $this->createNodeListValidator('/mets:mdWrap', $rightsMetadata) + ->validateHasOne() + ->getFirstNode(); + + $this->createNodeValidator($node) + ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) + ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVRIGHTS')); + + $this->createNodeListValidator('/mets:xmlData', $rightsMetadata) + ->validateHasOne(); } /** @@ -64,31 +95,28 @@ protected function isValidDocument(): void * * @return void */ - private function validateTechnicalMetadata(\DOMNode $amdSection): void + protected function validateTechnicalMetadataStructure(): void { - $technicalElements = $this->xpath->query('/mets:techMD', $amdSection); - if ($technicalElements === false || $technicalElements->length == 0) { - return; - } - - if ($technicalElements->length > 1) { - $this->addError('Every "mets:amdSec" has to consist none or one "mets:techMD".', 1724234607); - } - - if ($technicalElements->length == 1) { - $mdWrap = $this->xpath->query('/mets:mdWrap', $technicalElements->item(0)); - if( $mdWrap === false || $mdWrap->length != 1 ) { - $this->addError('Every "mets:techMD" has to consist one "mets:mdWrap".', 1724234607); - } else { - if (!$mdWrap->hasAttribute("MDTYPE") || $mdWrap->hasAttribute("OTHERMDTYPE")) { - $this->addError('Mandatory attribute "MDTYPE" or "OTHERMDTYPE" of "mets:techMD/mets:mdWrap" is missing', 1724234607); - } - - $xmlData = $this->xpath->query('/mets:xmlData', $mdWrap); - if ($xmlData === false || $xmlData->length == 0) { - $this->addError('Every "mets:techMD/mets:mdWrap" has to consist one "mets:xmlData"', 1724234607); - } - } - } + $this->createNodeListValidator(self::XPATH_TECHNICAL_METADATA) + ->iterate(array($this, "validateTechnicalMetadata")); } + + + protected function validateTechnicalMetadata(\DOMNode $technicalMetadata): void + { + $this->createNodeValidator($technicalMetadata) + ->validateHasUniqueId(); + + $mdWrap = $this->createNodeListValidator('/mets:mdWrap', $technicalMetadata) + ->validateHasOne() + ->getFirstNode(); + + $this->createNodeValidator($mdWrap) + ->validateHasAttribute("MDTYPE") + ->validateHasAttribute("OTHERMDTYPE"); + + $this->createNodeListValidator('/mets:xmlData', $mdWrap) + ->validateHasOne(); + } + } diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index 5769a4232..e11848ee5 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -25,7 +25,6 @@ * This copyright notice MUST APPEAR in all copies of the script! */ -use DOMNode; use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; /** @@ -46,7 +45,7 @@ class LinkingLogicalPhysicalStructureValidator extends ApplicationProfileBaseVal protected function isValidDocument(): void { // Validates against the rules of chapter "2.3.1 Structure links - mets:structLink" - $this->query(self::XPATH_STRUCT_LINK) + $this->createNodeListValidator(self::XPATH_STRUCT_LINK) ->validateHasNoneOrOne(); $this->validateLinkElements(); @@ -59,16 +58,16 @@ protected function isValidDocument(): void * * @return void */ - private function validateLinkElements(): void + protected function validateLinkElements(): void { - $this->query(self::XPATH_LINK_ELEMENTS) + $this->createNodeListValidator(self::XPATH_LINK_ELEMENTS) ->validateHasAny() ->iterate(array($this, "validateLinkElement")); } - protected function validateLinkElement(\DOMNode $linkElement): void + public function validateLinkElement(\DOMNode $linkElement): void { - $this->setNode($linkElement) + $this->createNodeValidator($linkElement) ->validateHasRefToOne("xlink:from", LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES) ->validateHasRefToOne("xlink:to", PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); } diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index 59dac8f5a..e6c254b00 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -47,7 +47,8 @@ class LogicalStructureValidator extends ApplicationProfileBaseValidator protected function isValidDocument(): void { // Validates against the rules of chapter "2.1.1 Logical structure - mets:structMap" - $this->query(self::XPATH_LOGICAL_STRUCTURES)->validateHasAny(); + $this->createNodeListValidator(self::XPATH_LOGICAL_STRUCTURES) + ->validateHasAny(); $this->validateStructuralElements(); $this->validateExternalReferences(); @@ -63,14 +64,14 @@ protected function isValidDocument(): void */ protected function validateStructuralElements(): void { - $this->query(self::XPATH_STRUCTURAL_ELEMENTS) + $this->createNodeListValidator(self::XPATH_STRUCTURAL_ELEMENTS) ->validateHasAny() ->iterate(array($this, "validateStructuralElement")); } - protected function validateStructuralElement(\DOMNode $structureElement): void + public function validateStructuralElement(\DOMNode $structureElement): void { - $this->setNode($structureElement) + $this->createNodeValidator($structureElement) ->validateHasUniqueId() ->validateHasAttributeWithValue("TYPE", self::STRUCTURE_DATASET); } @@ -84,14 +85,14 @@ protected function validateStructuralElement(\DOMNode $structureElement): void */ protected function validateExternalReferences(): void { - $this->query(self::XPATH_EXTERNAL_REFERENCES) + $this->createNodeListValidator(self::XPATH_EXTERNAL_REFERENCES) ->validateHasNoneOrOne() ->iterate(array($this, "validateExternalReference")); } - protected function validateExternalReference(\DOMNode $externalReference): void + public function validateExternalReference(\DOMNode $externalReference): void { - $this->setNode($externalReference) + $this->createNodeValidator($externalReference) ->validateHasAttributeWithValue("LOCTYPE", array("URL", "PURL")) ->validateHasAttributeWithUrl("xlink:href"); } diff --git a/Classes/Validation/Mets/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php index 170d77a19..cc8e02465 100644 --- a/Classes/Validation/Mets/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -3,6 +3,7 @@ namespace Slub\Dfgviewer\Validation\Mets; use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; +use function PHPUnit\Framework\callback; /** * Copyright notice @@ -46,7 +47,8 @@ class PhysicalStructureValidator extends ApplicationProfileBaseValidator protected function isValidDocument(): void { // Validates against the rules of chapter "2.2.1 Physical structure - mets:structMap" - $this->query(self::XPATH_PHYSICAL_STRUCTURES)->validateHasNoneOrOne(); + $this->createNodeListValidator(self::XPATH_PHYSICAL_STRUCTURES) + ->validateHasNoneOrOne(); $this->validateStructuralElements(); } @@ -59,21 +61,23 @@ protected function isValidDocument(): void * * @return void */ - private function validateStructuralElements(): void + protected function validateStructuralElements(): void { - $this->query(self::XPATH_STRUCTURAL_ELEMENT_SEQUENCE ) + $node = $this->createNodeListValidator(self::XPATH_STRUCTURAL_ELEMENT_SEQUENCE) ->validateHasOne() - ->getFirst() + ->getFirstNode(); + + $this->createNodeValidator($node) ->validateHasAttributeWithValue('TYPE', array('physSequence')); - $this->query(self::XPATH_STRUCTURAL_ELEMENTS) + $this->createNodeListValidator(self::XPATH_STRUCTURAL_ELEMENTS) ->validateHasAny() ->iterate(array($this, "validateStructuralElement")); } - protected function validateStructuralElement(\DOMNode $structureElement): void + public function validateStructuralElement(\DOMNode $structureElement): void { - $this->setNode($structureElement) + $this->createNodeValidator($structureElement) ->validateHasUniqueId() ->validateHasAttributeWithValue("TYPE", array("page", "doublepage", "track")); } diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index e1601bfac..34c26ed6b 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -58,8 +58,8 @@ public function setUp(): void public function testDocument() { $result = $this->validate(); - if($result->hasErrors()){ - self::assertEquals('',$result->getFirstError()->getMessage()); + if ($result->hasErrors()) { + self::assertEquals('', $result->getFirstError()->getMessage()); } self::assertFalse($result->hasErrors()); } @@ -207,7 +207,7 @@ protected function assertErrorHasAttributeWithUrl(string $expression, string $na protected function assertErrorHasRefToOne(string $expression, string $name, string $value, string $targetContextExpression) { - $this->validateAndAssertEquals( 'Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); + $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); } protected function validateErrorHasUniqueId(string $expression, string $value): void diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index f18cd6daa..e89baccbd 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -51,11 +51,11 @@ public function testLinkElements(): void $this->resetDocument(); $this->setAttributeValue(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:from', 'Test'); - $this->assertErrorHasRefToOne(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:from', 'Test', LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); + $this->assertErrorHasRefToOne('/mets:mets/mets:structLink/mets:smLink', 'xlink:from', 'Test', LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); $this->resetDocument(); $this->setAttributeValue(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:to', 'Test'); - $this->assertErrorHasRefToOne(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:to', 'Test', PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); + $this->assertErrorHasRefToOne('/mets:mets/mets:structLink/mets:smLink', 'xlink:to', 'Test', PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); } protected function createValidator(): AbstractDlfValidator @@ -63,5 +63,4 @@ protected function createValidator(): AbstractDlfValidator return new LinkingLogicalPhysicalStructureValidator(); } - } diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index 5feae6a1b..83bb46d88 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -53,20 +53,20 @@ public function testStructuralElements(): void $this->resetDocument(); $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); - $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'ID'); $this->resetDocument(); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); $this->addChildNode(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, $node); - $this->validateErrorHasUniqueId(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'LOG_0001'); + $this->validateErrorHasUniqueId('/mets:mets/mets:structMap[1]/mets:div', 'LOG_0001'); $this->resetDocument(); $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); - $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'TYPE'); $this->setAttributeValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div', 'TYPE', 'Test'); } /** @@ -82,16 +82,16 @@ public function testExternalReference(): void $this->resetDocument(); $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); - $this->assertErrorHasAttribute(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href'); + $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); - $this->assertErrorHasAttributeWithUrl(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); + $this->assertErrorHasAttributeWithUrl('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href', 'Test'); $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); $result = $this->validate(); diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index e7e647c5d..56fd2628d 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -56,10 +56,10 @@ public function testStructuralElements(): void $this->resetDocument(); $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); - $this->assertErrorHasAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div', 'TYPE'); $this->setAttributeValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div', 'TYPE', 'Test'); $this->resetDocument(); $this->removeNodes(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); @@ -67,20 +67,20 @@ public function testStructuralElements(): void $this->resetDocument(); $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); - $this->assertErrorHasAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'ID'); $this->resetDocument(); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'PHYS_0001'); $this->addChildNode('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', $node); - $this->validateErrorHasUniqueId(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'PHYS_0001'); + $this->validateErrorHasUniqueId('/mets:mets/mets:structMap[2]/mets:div/mets:div[1]', 'PHYS_0001'); $this->resetDocument(); $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); - $this->assertErrorHasAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE'); $this->setAttributeValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE', 'Test'); } protected function createValidator(): AbstractDlfValidator From 03702729cb01a63f86026f92e3e7a64251ca6064 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 19 Dec 2024 17:43:59 +0100 Subject: [PATCH 15/43] Add validation for digital representation --- Classes/Validation/DOMNodeValidator.php | 18 ++- .../Mets/AdministrativeMetadataValidator.php | 48 +++++++- .../Mets/DigitalRepresentationValidator.php | 106 ++++++++++++++++++ 3 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 Classes/Validation/Mets/DigitalRepresentationValidator.php diff --git a/Classes/Validation/DOMNodeValidator.php b/Classes/Validation/DOMNodeValidator.php index 355b20b95..15d2d25c1 100644 --- a/Classes/Validation/DOMNodeValidator.php +++ b/Classes/Validation/DOMNodeValidator.php @@ -52,23 +52,29 @@ public function validateHasAttributeWithValue(string $name, array $values): DOMN return $this; } - public function validateHasUniqueId(): DOMNodeValidator + public function validateHasUniqueAttribute(string $name, string $contextExpression): DOMNodeValidator { if (!isset($this->node)) { return $this; } - if ($this->node->hasAttribute("ID")) { - $id = $this->node->getAttribute("ID"); - if ($this->xpath->query('//*[@ID="' . $id . '"]')->length > 1) { - $this->result->addError(new Error('"ID" attribute "' . $id . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); + if ($this->node->hasAttribute($name)) { + $value = $this->node->getAttribute($name); + if ($this->xpath->query($contextExpression . '[@' . $name . '="' . $value . '"]')->length > 1) { + $this->result->addError(new Error('"' . $name . '" attribute "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); } } else { - $this->validateHasAttribute("ID"); + $this->validateHasAttribute($name); } return $this; } + public function validateHasUniqueId(): DOMNodeValidator + { + $this->validateHasUniqueAttribute("ID", "//*"); + return $this; + } + public function validateHasAttribute(string $name): DOMNodeValidator { if (!isset($this->node)) { diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index cfe2aeec2..b45612560 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -44,6 +44,8 @@ class AdministrativeMetadataValidator extends ApplicationProfileBaseValidator const XPATH_RIGHTS_METADATA = self::XPATH_ADMINISTRATIV_METADATA . '/mets:rightsMD'; + const XPATH_DIGIPROV_METADATA = self::XPATH_ADMINISTRATIV_METADATA . '/mets:digiprovMD'; + protected function isValidDocument(): void { // Validates against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" @@ -51,27 +53,65 @@ protected function isValidDocument(): void ->validateHasAny() ->iterate(array($this, "validateAdministrativMetadata")); - // Check if one administrativ metadata exist with "mets:rightsMD" and "mets:digiprovMD" as children + // Check if one administrative metadata exist with "mets:rightsMD" and "mets:digiprovMD" as children $this->createNodeListValidator(self::XPATH_ADMINISTRATIV_METADATA . '[mets:rightsMD and mets:digiprovMD]') ->validateHasOne(); $this->validateTechnicalMetadataStructure(); $this->validateRightsMetadataStructure(); + $this->validateDigitalProvenanceMetadataStructure(); } - protected function validateAdministrativMetadata(\DOMNode $administrativeMetadata): void + public function validateAdministrativMetadata(\DOMNode $administrativeMetadata): void { $this->createNodeValidator($administrativeMetadata) ->validateHasUniqueId(); } + /** + * Validates the digital provenance metadata. + * + * Validates against the rules of chapters "2.6.2.5 Herstellung – mets:digiprovMD" and "2.6.2.6 Eingebettete Verweise – mets:digiprovMD/mets:mdWrap" + * + * @return void + */ + protected function validateDigitalProvenanceMetadataStructure(): void + { + $this->createNodeListValidator(self::XPATH_DIGIPROV_METADATA) + ->iterate(array($this, "validateDigitalProvenanceMetadata")); + } + + public function validateDigitalProvenanceMetadata(\DOMNode $digitalProvenanceMetadata): void + { + $this->createNodeValidator($digitalProvenanceMetadata) + ->validateHasUniqueId(); + + $mdWrAP = $this->createNodeListValidator('/mets:mdWrap', $digitalProvenanceMetadata) + ->validateHasOne() + ->getFirstNode(); + + $this->createNodeValidator($mdWrAP) + ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) + ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVLINKS')); + + $this->createNodeListValidator('/mets:xmlData', $digitalProvenanceMetadata) + ->validateHasOne(); + } + + /** + * Validates the rights metadata. + * + * Validates against the rules of chapters "2.6.2.4 Rechtedeklaration – mets:rightsMD" and "2.6.2.4 Eingebettete Rechteangaben – mets:rightsMD/mets:mdWrap" + * + * @return void + */ protected function validateRightsMetadataStructure(): void { $this->createNodeListValidator(self::XPATH_RIGHTS_METADATA) ->iterate(array($this, "validateRightsMetadata")); } - protected function validateRightsMetadata(\DOMNode $rightsMetadata): void + public function validateRightsMetadata(\DOMNode $rightsMetadata): void { $this->createNodeValidator($rightsMetadata) ->validateHasUniqueId(); @@ -102,7 +142,7 @@ protected function validateTechnicalMetadataStructure(): void } - protected function validateTechnicalMetadata(\DOMNode $technicalMetadata): void + public function validateTechnicalMetadata(\DOMNode $technicalMetadata): void { $this->createNodeValidator($technicalMetadata) ->validateHasUniqueId(); diff --git a/Classes/Validation/Mets/DigitalRepresentationValidator.php b/Classes/Validation/Mets/DigitalRepresentationValidator.php new file mode 100644 index 000000000..b1bc8b232 --- /dev/null +++ b/Classes/Validation/Mets/DigitalRepresentationValidator.php @@ -0,0 +1,106 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +/** + * The validator validates against the rules outlined in chapter 2.4 of the METS application profile 2.3.1. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ +class DigitalRepresentationValidator extends ApplicationProfileBaseValidator +{ + + const XPATH_FILE_SECTIONS = '//mets:mets/mets:fileSec'; + + const XPATH_FILE_GROUPS = self::XPATH_FILE_SECTIONS . '/mets:fileGroup'; + + const XPATH_FILES = self::XPATH_FILE_GROUPS . '/mets:file'; + + protected function isValidDocument(): void + { + // Validates against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" + $this->createNodeListValidator(self::XPATH_FILE_SECTIONS) + ->validateHasNoneOrOne(); + + // If a physical structure is present, there must be one file section. + if($this->xpath->query(PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES)->length > 0){ + $this->createNodeListValidator(self::XPATH_FILE_SECTIONS) + ->validateHasOne(); + } + + $this->validateFileGroups(); + $this->validateFiles(); + } + + /** + * Validates the digital provenance metadata. + * + * Validates against the rules of chapters "2.6.2.5 Herstellung – mets:digiprovMD" and "2.6.2.6 Eingebettete Verweise – mets:digiprovMD/mets:mdWrap" + * + * @return void + */ + protected function validateFileGroups(): void + { + $this->createNodeListValidator(self::XPATH_FILE_GROUPS) + ->validateHasAny() + ->iterate(array($this, "validateFileGroup")); + + $this->createNodeListValidator(self::XPATH_FILE_GROUPS . '[@USE="DEFAULT"]') + ->validateHasOne(); + } + + public function validateFileGroup(\DOMNode $fileGroup): void + { + $this->createNodeValidator($fileGroup) + ->validateHasUniqueAttribute("USE", self::XPATH_FILE_GROUPS); + } + + protected function validateFiles(): void + { + $this->createNodeListValidator(self::XPATH_FILES) + ->validateHasAny() + ->iterate(array($this, "validateFile")); + } + + public function validateFile(\DOMNode $file): void + { + $this->createNodeValidator($file) + ->validateHasUniqueId(); + + $fLocat = $this->createNodeListValidator('/mets:FLocat', $file) + ->validateHasOne() + ->getFirstNode(); + + $this->createNodeValidator($fLocat) + ->validateHasAttribute("xlink:href") + ->validateHasAttributeWithValue("LOCTYPE", array("URL", "PURL")); + } +} From d667674089a1d1d42420b78c8446ddf80298f473 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 20 Dec 2024 10:59:20 +0100 Subject: [PATCH 16/43] Adding descriptive metadata validation and improve other validations --- Classes/Validation/DOMNodeValidator.php | 51 +++++++----- .../Mets/AdministrativeMetadataValidator.php | 4 +- .../Mets/DeskriptiveMetadataValidator.php | 82 +++++++++++++++++++ .../Mets/DigitalRepresentationValidator.php | 18 ++-- ...nkingLogicalPhysicalStructureValidator.php | 4 +- 5 files changed, 128 insertions(+), 31 deletions(-) create mode 100644 Classes/Validation/Mets/DeskriptiveMetadataValidator.php diff --git a/Classes/Validation/DOMNodeValidator.php b/Classes/Validation/DOMNodeValidator.php index 15d2d25c1..ddcd9587e 100644 --- a/Classes/Validation/DOMNodeValidator.php +++ b/Classes/Validation/DOMNodeValidator.php @@ -24,14 +24,15 @@ public function validateHasAttributeWithUrl(string $name): DOMNodeValidator return $this; } - if ($this->node->hasAttribute($name)) { - $value = $this->node->getAttribute($name); - if (!filter_var($value, FILTER_VALIDATE_URL)) { - $this->result->addError(new Error('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); - } - } else { - $this->validateHasAttribute($name); + if (!$this->node->hasAttribute($name)) { + return $this->validateHasAttribute($name); + } + + $value = $this->node->getAttribute($name); + if (!filter_var($value, FILTER_VALIDATE_URL)) { + $this->result->addError(new Error('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); } + return $this; } @@ -41,14 +42,15 @@ public function validateHasAttributeWithValue(string $name, array $values): DOMN return $this; } - if ($this->node->hasAttribute($name)) { - $value = $this->node->getAttribute($name); - if (!in_array($value, $values)) { - $this->result->addError(new Error('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not permissible.', 1724234607)); - } - } else { - $this->validateHasAttribute($name); + if (!$this->node->hasAttribute($name)) { + return $this->validateHasAttribute($name); + } + + $value = $this->node->getAttribute($name); + if (!in_array($value, $values)) { + $this->result->addError(new Error('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not permissible.', 1724234607)); } + return $this; } @@ -58,14 +60,15 @@ public function validateHasUniqueAttribute(string $name, string $contextExpressi return $this; } - if ($this->node->hasAttribute($name)) { - $value = $this->node->getAttribute($name); - if ($this->xpath->query($contextExpression . '[@' . $name . '="' . $value . '"]')->length > 1) { - $this->result->addError(new Error('"' . $name . '" attribute "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); - } - } else { - $this->validateHasAttribute($name); + if (!$this->node->hasAttribute($name)) { + return $this->validateHasAttribute($name); + } + + $value = $this->node->getAttribute($name); + if ($this->xpath->query($contextExpression . '[@' . $name . '="' . $value . '"]')->length > 1) { + $this->result->addError(new Error('"' . $name . '" attribute "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); } + return $this; } @@ -87,12 +90,16 @@ public function validateHasAttribute(string $name): DOMNodeValidator return $this; } - public function validateHasRefToOne(string $name, string $targetContextExpression): DOMNodeValidator + public function validateHasReferenceToId(string $name, string $targetContextExpression): DOMNodeValidator { if (!isset($this->node)) { return $this; } + if (!$this->node->hasAttribute($name)) { + return $this->validateHasAttribute($name); + } + $targetNodes = $this->xpath->query($targetContextExpression); $id = $this->node->getAttribute($name); diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index b45612560..f7c38e6c5 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -94,7 +94,7 @@ public function validateDigitalProvenanceMetadata(\DOMNode $digitalProvenanceMet ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVLINKS')); - $this->createNodeListValidator('/mets:xmlData', $digitalProvenanceMetadata) + $this->createNodeListValidator('/mets:xmlData[dv:links]', $digitalProvenanceMetadata) ->validateHasOne(); } @@ -124,7 +124,7 @@ public function validateRightsMetadata(\DOMNode $rightsMetadata): void ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVRIGHTS')); - $this->createNodeListValidator('/mets:xmlData', $rightsMetadata) + $this->createNodeListValidator('/mets:xmlData[dv:rights]', $rightsMetadata) ->validateHasOne(); } diff --git a/Classes/Validation/Mets/DeskriptiveMetadataValidator.php b/Classes/Validation/Mets/DeskriptiveMetadataValidator.php new file mode 100644 index 000000000..7b46adb0f --- /dev/null +++ b/Classes/Validation/Mets/DeskriptiveMetadataValidator.php @@ -0,0 +1,82 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +/** + * The validator validates against the rules outlined in chapter 2.5 of the METS application profile 2.3.1. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ +class DeskriptiveMetadataValidator extends ApplicationProfileBaseValidator +{ + + const XPATH_DESCRIPTIVE_METADATA_SECTIONS = '//mets:mets/mets:dmdSec'; + + protected function isValidDocument(): void + { + // Validates against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" + $this->createNodeListValidator(self::XPATH_DESCRIPTIVE_METADATA_SECTIONS) + ->validateHasAny() + ->iterate(array($this, 'validateDescriptiveMetadataSection')); + + // If a physical structure is present, there must be one file section. + $logicalStructureElement = $this->createNodeListValidator(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS) + ->validateHasOne() + ->getFirstNode(); + + $this->createNodeValidator($logicalStructureElement) + ->validateHasReferenceToId('DMDID', self::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + } + + /** + * Validates the embedded metadata. + * + * Validates against the rules of chapter "2.5.2.1 Eingebettete Metadaten – mets:mdWrap" + * + * @return void + */ + public function validateDescriptiveMetadataSection(\DOMNode $descriptiveMetadataSection): void + { + $mdWrap = $this->createNodeListValidator('/mets:mdWrap', $descriptiveMetadataSection) + ->validateHasOne() + ->getFirstNode(); + + $this->createNodeValidator($mdWrap) + ->validateHasAttributeWithValue('MDTYPE', array('MODS', 'TEIHDR')); + + $mdType = $mdWrap->getAttribute('MDTYPE'); + if ($mdType == 'TEIHDR' || $mdType == 'MODS') { + $childNode = $mdType == 'TEIHDR' ? 'tei:teiHeader' : 'mods:mods'; + $this->createNodeListValidator('/mets:xmlData[' . $childNode . ']', $mdWrap) + ->validateHasOne(); + } + } +} diff --git a/Classes/Validation/Mets/DigitalRepresentationValidator.php b/Classes/Validation/Mets/DigitalRepresentationValidator.php index b1bc8b232..b593d6813 100644 --- a/Classes/Validation/Mets/DigitalRepresentationValidator.php +++ b/Classes/Validation/Mets/DigitalRepresentationValidator.php @@ -61,9 +61,9 @@ protected function isValidDocument(): void } /** - * Validates the digital provenance metadata. + * Validates the file groups. * - * Validates against the rules of chapters "2.6.2.5 Herstellung – mets:digiprovMD" and "2.6.2.6 Eingebettete Verweise – mets:digiprovMD/mets:mdWrap" + * Validates against the rules of chapter "2.4.2.1 Dateigruppen – mets:fileGrp" * * @return void */ @@ -83,6 +83,13 @@ public function validateFileGroup(\DOMNode $fileGroup): void ->validateHasUniqueAttribute("USE", self::XPATH_FILE_GROUPS); } + /** + * Validates the files. + * + * Validates against the rules of chapters "2.4.2.2 Datei – mets:fileGrp/mets:file" and "2.4.2.3 Dateilink – mets:fileGrp/mets:file/mets:FLocat" + * + * @return void + */ protected function validateFiles(): void { $this->createNodeListValidator(self::XPATH_FILES) @@ -93,14 +100,15 @@ protected function validateFiles(): void public function validateFile(\DOMNode $file): void { $this->createNodeValidator($file) - ->validateHasUniqueId(); + ->validateHasUniqueId() + ->validateHasAttribute('MIMETYPE'); $fLocat = $this->createNodeListValidator('/mets:FLocat', $file) ->validateHasOne() ->getFirstNode(); $this->createNodeValidator($fLocat) - ->validateHasAttribute("xlink:href") - ->validateHasAttributeWithValue("LOCTYPE", array("URL", "PURL")); + ->validateHasAttributeWithValue('LOCTYPE', array('URL', 'PURL')) + ->validateHasAttributeWithUrl('xlink:href'); } } diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index e11848ee5..a34d00e5c 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -68,8 +68,8 @@ protected function validateLinkElements(): void public function validateLinkElement(\DOMNode $linkElement): void { $this->createNodeValidator($linkElement) - ->validateHasRefToOne("xlink:from", LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES) - ->validateHasRefToOne("xlink:to", PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); + ->validateHasReferenceToId("xlink:from", LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES) + ->validateHasReferenceToId("xlink:to", PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); } } From cedcf8e9984cf566350b40a445d21e443642b118 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 20 Dec 2024 15:50:25 +0100 Subject: [PATCH 17/43] Add tests for deskriptive metadata validator --- Classes/Validation/DOMNodeListValidator.php | 18 ++++- .../Mets/DeskriptiveMetadataValidator.php | 14 ++-- .../ApplicationProfileValidatorTest.php | 26 +++++-- .../Mets/DeskriptiveMetadataValidatorTest.php | 78 +++++++++++++++++++ 4 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 Tests/Unit/Validation/Mets/DeskriptiveMetadataValidatorTest.php diff --git a/Classes/Validation/DOMNodeListValidator.php b/Classes/Validation/DOMNodeListValidator.php index 1d98ed037..43fb59d43 100644 --- a/Classes/Validation/DOMNodeListValidator.php +++ b/Classes/Validation/DOMNodeListValidator.php @@ -12,6 +12,8 @@ class DOMNodeListValidator { private string $expression; + private ?DOMNode $contextNode; + private DOMNodeList $nodeList; private Result $result; @@ -19,6 +21,7 @@ class DOMNodeListValidator public function __construct(DOMXPath $xpath, Result $result, string $expression, ?DOMNode $contextNode = null) { $this->expression = $expression; + $this->contextNode = $contextNode; $this->nodeList = $xpath->query($expression, $contextNode); $this->result = $result; } @@ -44,7 +47,7 @@ public function getNode(int $index): ?DOMNode public function validateHasAny(): DOMNodeListValidator { if (!$this->nodeList->length > 0) { - $this->result->addError(new Error('There must be at least one element that matches the XPath expression "' . $this->expression . '"', 23)); + $this->addError('There must be at least one element'); } return $this; } @@ -52,7 +55,7 @@ public function validateHasAny(): DOMNodeListValidator public function validateHasOne(): DOMNodeListValidator { if ($this->nodeList->length != 1) { - $this->result->addError(new Error('There must be an element that matches the XPath expression "' . $this->expression . '"', 434)); + $this->addError('There must be an element'); } return $this; } @@ -60,9 +63,18 @@ public function validateHasOne(): DOMNodeListValidator public function validateHasNoneOrOne(): DOMNodeListValidator { if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { - $this->result->addError(new Error('There must be no more than one element that matches the XPath expression "' . $this->expression . '"', 43)); + $this->addError('There must be no more than one element'); } return $this; } + private function addError(string $prefix): void + { + $message = $prefix . ' that matches the XPath expression "' . $this->expression . '"'; + if($this->contextNode) { + $message .= ' under "' . $this->contextNode->getNodePath() . '"'; + } + $this->result->addError(new Error($message, 23)); + } + } diff --git a/Classes/Validation/Mets/DeskriptiveMetadataValidator.php b/Classes/Validation/Mets/DeskriptiveMetadataValidator.php index 7b46adb0f..3137aa4a3 100644 --- a/Classes/Validation/Mets/DeskriptiveMetadataValidator.php +++ b/Classes/Validation/Mets/DeskriptiveMetadataValidator.php @@ -45,9 +45,9 @@ protected function isValidDocument(): void // Validates against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" $this->createNodeListValidator(self::XPATH_DESCRIPTIVE_METADATA_SECTIONS) ->validateHasAny() - ->iterate(array($this, 'validateDescriptiveMetadataSection')); + ->iterate(array($this, 'validateDescriptiveMetadataSections')); - // If a physical structure is present, there must be one file section. + // there must be one primary structural element $logicalStructureElement = $this->createNodeListValidator(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS) ->validateHasOne() ->getFirstNode(); @@ -63,19 +63,23 @@ protected function isValidDocument(): void * * @return void */ - public function validateDescriptiveMetadataSection(\DOMNode $descriptiveMetadataSection): void + public function validateDescriptiveMetadataSections(\DOMNode $descriptiveMetadataSection): void { - $mdWrap = $this->createNodeListValidator('/mets:mdWrap', $descriptiveMetadataSection) + $mdWrap = $this->createNodeListValidator('mets:mdWrap', $descriptiveMetadataSection) ->validateHasOne() ->getFirstNode(); $this->createNodeValidator($mdWrap) ->validateHasAttributeWithValue('MDTYPE', array('MODS', 'TEIHDR')); + if(!$mdWrap) { + return; + } + $mdType = $mdWrap->getAttribute('MDTYPE'); if ($mdType == 'TEIHDR' || $mdType == 'MODS') { $childNode = $mdType == 'TEIHDR' ? 'tei:teiHeader' : 'mods:mods'; - $this->createNodeListValidator('/mets:xmlData[' . $childNode . ']', $mdWrap) + $this->createNodeListValidator('mets:xmlData[' . $childNode . ']', $mdWrap) ->validateHasOne(); } } diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index 34c26ed6b..54e8637be 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -131,7 +131,7 @@ protected function addChildNode(string $expression, DOMElement $newNode): void protected function removeNodes(string $expression): void { $xpath = new DOMXPath($this->doc); - foreach ($xpath->evaluate($expression) as $node) { + foreach ($xpath->query($expression) as $node) { $node->parentNode->removeChild($node); } } @@ -175,19 +175,31 @@ protected function getDOMDocument(): DOMDocument return $doc; } - protected function assertErrorHasAny(string $expression): void + protected function assertErrorHasAny(string $expression, string $context = ''): void { - $this->validateAndAssertEquals('There must be at least one element that matches the XPath expression "' . $expression . '"'); + $message = 'There must be at least one element that matches the XPath expression "' . $expression . '"'; + if ($context != '') { + $message .= ' under "' . $context . '"'; + } + $this->validateAndAssertEquals($message); } - protected function assertErrorHasOne(string $expression): void + protected function assertErrorHasOne(string $expression, string $context = ''): void { - $this->validateAndAssertEquals('There must be an element that matches the XPath expression "' . $expression . '"'); + $message = 'There must be an element that matches the XPath expression "' . $expression . '"'; + if ($context != '') { + $message .= ' under "' . $context . '"'; + } + $this->validateAndAssertEquals($message); } - protected function assertErrorHasNoneOrOne(string $expression): void + protected function assertErrorHasNoneOrOne(string $expression, string $context = ''): void { - $this->validateAndAssertEquals('There must be no more than one element that matches the XPath expression "' . $expression . '"'); + $message = 'There must be no more than one element that matches the XPath expression "' . $expression . '"'; + if ($context != '') { + $message .= ' under "' . $context . '"'; + } + $this->validateAndAssertEquals($message); } protected function assertErrorHasAttribute(string $expression, string $name): void diff --git a/Tests/Unit/Validation/Mets/DeskriptiveMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/DeskriptiveMetadataValidatorTest.php new file mode 100644 index 000000000..2f615e2e6 --- /dev/null +++ b/Tests/Unit/Validation/Mets/DeskriptiveMetadataValidatorTest.php @@ -0,0 +1,78 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Validation\Mets\DeskriptiveMetadataValidator; +use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; + +class DeskriptiveMetadataValidatorTest extends ApplicationProfileValidatorTest +{ + + /** + * Test validation against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" + * + * @return void + */ + public function testDescriptiveMetadata(): void + { + $this->removeNodes(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->assertErrorHasAny(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->resetDocument(); + + $this->removeNodes(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->assertErrorHasOne(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->resetDocument(); + + $this->setAttributeValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'DMDID', 'Test'); + $this->assertErrorHasRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + } + + /** + * Test validation against the rules of chapter "2.5.2.1 Eingebettete Metadaten – mets:mdWrap" + * + * @return void + */ + public function testEmbeddedMetadata(): void + { + $this->removeNodes(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', '/mets:mets/mets:dmdSec'); + $this->resetDocument(); + + $this->setAttributeValue(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:dmdSec/mets:mdWrap', 'MDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeNodes(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap/mets:xmlData/mods:mods'); + $this->assertErrorHasOne('mets:xmlData[mods:mods]', '/mets:mets/mets:dmdSec/mets:mdWrap'); + } + + + protected function createValidator(): AbstractDlfValidator + { + return new DeskriptiveMetadataValidator(); + } +} From 6420bef490b6136265240f528558695d39fd5388 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 20 Dec 2024 16:27:20 +0100 Subject: [PATCH 18/43] Add administrativ metadata validator test --- .../Mets/AdministrativeMetadataValidator.php | 28 ++--- .../ApplicationProfileValidatorTest.php | 2 +- .../AdministrativeMetadataValidatorTest.php | 108 ++++++++++++++++++ .../Mets/LogicalStructureValidatorTest.php | 2 +- .../Mets/PhysicalStructureValidatorTest.php | 2 +- 5 files changed, 125 insertions(+), 17 deletions(-) create mode 100644 Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index f7c38e6c5..9c63f78b1 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -38,23 +38,23 @@ class AdministrativeMetadataValidator extends ApplicationProfileBaseValidator { - const XPATH_ADMINISTRATIV_METADATA = '//mets:mets/mets:amdSec'; + const XPATH_ADMINISTRATIVE_METADATA = '//mets:mets/mets:amdSec'; - const XPATH_TECHNICAL_METADATA = self::XPATH_ADMINISTRATIV_METADATA . '/mets:techMD'; + const XPATH_TECHNICAL_METADATA = self::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD'; - const XPATH_RIGHTS_METADATA = self::XPATH_ADMINISTRATIV_METADATA . '/mets:rightsMD'; + const XPATH_RIGHTS_METADATA = self::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'; - const XPATH_DIGIPROV_METADATA = self::XPATH_ADMINISTRATIV_METADATA . '/mets:digiprovMD'; + const XPATH_DIGIPROV_METADATA = self::XPATH_ADMINISTRATIVE_METADATA . '/mets:digiprovMD'; protected function isValidDocument(): void { // Validates against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" - $this->createNodeListValidator(self::XPATH_ADMINISTRATIV_METADATA) + $this->createNodeListValidator(self::XPATH_ADMINISTRATIVE_METADATA) ->validateHasAny() ->iterate(array($this, "validateAdministrativMetadata")); // Check if one administrative metadata exist with "mets:rightsMD" and "mets:digiprovMD" as children - $this->createNodeListValidator(self::XPATH_ADMINISTRATIV_METADATA . '[mets:rightsMD and mets:digiprovMD]') + $this->createNodeListValidator(self::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]') ->validateHasOne(); $this->validateTechnicalMetadataStructure(); @@ -86,15 +86,15 @@ public function validateDigitalProvenanceMetadata(\DOMNode $digitalProvenanceMet $this->createNodeValidator($digitalProvenanceMetadata) ->validateHasUniqueId(); - $mdWrAP = $this->createNodeListValidator('/mets:mdWrap', $digitalProvenanceMetadata) + $mdWrap = $this->createNodeListValidator('mets:mdWrap', $digitalProvenanceMetadata) ->validateHasOne() ->getFirstNode(); - $this->createNodeValidator($mdWrAP) + $this->createNodeValidator($mdWrap) ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVLINKS')); - $this->createNodeListValidator('/mets:xmlData[dv:links]', $digitalProvenanceMetadata) + $this->createNodeListValidator('mets:xmlData[dv:links]', $mdWrap) ->validateHasOne(); } @@ -116,15 +116,15 @@ public function validateRightsMetadata(\DOMNode $rightsMetadata): void $this->createNodeValidator($rightsMetadata) ->validateHasUniqueId(); - $node = $this->createNodeListValidator('/mets:mdWrap', $rightsMetadata) + $mpWrap = $this->createNodeListValidator('mets:mdWrap', $rightsMetadata) ->validateHasOne() ->getFirstNode(); - $this->createNodeValidator($node) + $this->createNodeValidator($mpWrap) ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVRIGHTS')); - $this->createNodeListValidator('/mets:xmlData[dv:rights]', $rightsMetadata) + $this->createNodeListValidator('mets:xmlData[dv:rights]', $mpWrap) ->validateHasOne(); } @@ -147,7 +147,7 @@ public function validateTechnicalMetadata(\DOMNode $technicalMetadata): void $this->createNodeValidator($technicalMetadata) ->validateHasUniqueId(); - $mdWrap = $this->createNodeListValidator('/mets:mdWrap', $technicalMetadata) + $mdWrap = $this->createNodeListValidator('mets:mdWrap', $technicalMetadata) ->validateHasOne() ->getFirstNode(); @@ -155,7 +155,7 @@ public function validateTechnicalMetadata(\DOMNode $technicalMetadata): void ->validateHasAttribute("MDTYPE") ->validateHasAttribute("OTHERMDTYPE"); - $this->createNodeListValidator('/mets:xmlData', $mdWrap) + $this->createNodeListValidator('mets:xmlData', $mdWrap) ->validateHasOne(); } diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index 54e8637be..a72fccba9 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -222,7 +222,7 @@ protected function assertErrorHasRefToOne(string $expression, string $name, stri $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); } - protected function validateErrorHasUniqueId(string $expression, string $value): void + protected function assertErrorHasUniqueId(string $expression, string $value): void { $this->validateAndAssertEquals('"ID" attribute "' . $value . '" of "' . $expression . '" already exists.'); } diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php new file mode 100644 index 000000000..4e009db25 --- /dev/null +++ b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php @@ -0,0 +1,108 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; +use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; + +class AdministrativeMetadataValidatorTest extends ApplicationProfileValidatorTest +{ + + /** + * Test validation against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" + * + * @return void + */ + public function testAdministrativeMetadata(): void + { + $this->removeNodes(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA); + $this->assertErrorHasAny(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA); + $this->resetDocument(); + + $this->removeNodes(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'); + $this->assertErrorHasOne(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]'); + $this->resetDocument(); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec', 'DMDLOG_0001'); + + $this->removeAttribute(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA, 'ID'); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec', 'ID'); + } + + /** + * Test validation against the rules of chapters "2.6.2.5 Herstellung – mets:digiprovMD" and "2.6.2.6 Eingebettete Verweise – mets:digiprovMD/mets:mdWrap" + * + * @return void + */ + public function testDigitalProvenanceMetadataStructure(): void + { + + } + + /** + * Test validation against the rules of chapters "2.6.2.4 Rechtedeklaration – mets:rightsMD" and "2.6.2.4 Eingebettete Rechteangaben – mets:rightsMD/mets:mdWrap" + * + * @return void + */ + public function testRightsMetadataStructure(): void + { + + } + + /** + * Test validation against the rules of chapters "2.6.2.1 Technische Metadaten – mets:techMD" and "2.6.2.2 Eingebettete technische Daten – mets:techMD/mets:mdWrap" + * + * @return void + */ + public function testTechnicalMetadataStructure(): void + { + $this->addChildNodeNS(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA, self::NAMESPACE_METS, 'mets:techMD'); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD','ID'); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD', 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec/mets:techMD','DMDLOG_0001'); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD', 'ID', 'TECH_0001'); + $this->assertErrorHasOne('mets:mdWrap','/mets:mets/mets:amdSec/mets:techMD'); + + $this->addChildNodeNS(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA. '/mets:techMD', self::NAMESPACE_METS, 'mets:mdWrap'); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap','MDTYPE'); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD/mets:mdWrap', 'MDTYPE', ''); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap','OTHERMDTYPE'); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD/mets:mdWrap', 'OTHERMDTYPE', ''); + $this->assertErrorHasOne('mets:xmlData','/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap'); + } + + + protected function createValidator(): AbstractDlfValidator + { + return new AdministrativeMetadataValidator(); + } +} diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index 83bb46d88..24314ab8c 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -59,7 +59,7 @@ public function testStructuralElements(): void $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); $this->addChildNode(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, $node); - $this->validateErrorHasUniqueId('/mets:mets/mets:structMap[1]/mets:div', 'LOG_0001'); + $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[1]/mets:div', 'LOG_0001'); $this->resetDocument(); $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index 56fd2628d..b5379a0db 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -73,7 +73,7 @@ public function testStructuralElements(): void $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'PHYS_0001'); $this->addChildNode('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', $node); - $this->validateErrorHasUniqueId('/mets:mets/mets:structMap[2]/mets:div/mets:div[1]', 'PHYS_0001'); + $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[2]/mets:div/mets:div[1]', 'PHYS_0001'); $this->resetDocument(); $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); From d564f4579541df31c9004ad85d7fcae07a78229f Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 20 Dec 2024 16:52:17 +0100 Subject: [PATCH 19/43] Improve tests for administrative metadata validator --- .../AdministrativeMetadataValidatorTest.php | 58 +++++++++++++++++-- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php index 4e009db25..51bcff7b7 100644 --- a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php @@ -27,7 +27,6 @@ use Kitodo\Dlf\Validation\AbstractDlfValidator; use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; -use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; class AdministrativeMetadataValidatorTest extends ApplicationProfileValidatorTest { @@ -61,9 +60,33 @@ public function testAdministrativeMetadata(): void */ public function testDigitalProvenanceMetadataStructure(): void { + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec/mets:digiprovMD', 'DMDLOG_0001'); + $this->resetDocument(); + + $this->removeNodes(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', '/mets:mets/mets:amdSec/mets:digiprovMD'); + $this->resetDocument(); + + $this->removeAttribute(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'MDTYPE'); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'MDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeAttribute(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'OTHERMDTYPE'); + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeNodes(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap/mets:xmlData/dv:links'); + $this->assertErrorHasOne('mets:xmlData[dv:links]', '/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap'); } + /** * Test validation against the rules of chapters "2.6.2.4 Rechtedeklaration – mets:rightsMD" and "2.6.2.4 Eingebettete Rechteangaben – mets:rightsMD/mets:mdWrap" * @@ -71,7 +94,30 @@ public function testDigitalProvenanceMetadataStructure(): void */ public function testRightsMetadataStructure(): void { + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec/mets:rightsMD', 'DMDLOG_0001'); + $this->resetDocument(); + + $this->removeNodes(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', '/mets:mets/mets:amdSec/mets:rightsMD'); + $this->resetDocument(); + + $this->removeAttribute(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'MDTYPE'); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'MDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeAttribute(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'OTHERMDTYPE'); + + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->resetDocument(); + $this->removeNodes(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap/mets:xmlData/dv:rights'); + $this->assertErrorHasOne('mets:xmlData[dv:rights]', '/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap'); } /** @@ -84,19 +130,19 @@ public function testTechnicalMetadataStructure(): void $this->addChildNodeNS(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA, self::NAMESPACE_METS, 'mets:techMD'); $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD','ID'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD', 'ID', 'DMDLOG_0001'); + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA, 'ID', 'DMDLOG_0001'); $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec/mets:techMD','DMDLOG_0001'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD', 'ID', 'TECH_0001'); + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA, 'ID', 'TECH_0001'); $this->assertErrorHasOne('mets:mdWrap','/mets:mets/mets:amdSec/mets:techMD'); - $this->addChildNodeNS(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA. '/mets:techMD', self::NAMESPACE_METS, 'mets:mdWrap'); + $this->addChildNodeNS(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA, self::NAMESPACE_METS, 'mets:mdWrap'); $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap','MDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD/mets:mdWrap', 'MDTYPE', ''); + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA . '/mets:mdWrap', 'MDTYPE', ''); $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap','OTHERMDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD/mets:mdWrap', 'OTHERMDTYPE', ''); + $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', ''); $this->assertErrorHasOne('mets:xmlData','/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap'); } From 3e1d41be34069a4874192b816665fbb04a013531 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 20 Dec 2024 17:46:31 +0100 Subject: [PATCH 20/43] Adding digital representation validator test --- Classes/Validation/DOMNodeValidator.php | 2 +- .../Mets/DigitalRepresentationValidator.php | 10 +- .../ApplicationProfileValidatorTest.php | 20 ++- .../DigitalRepresentationValidatorTest.php | 116 ++++++++++++++++++ 4 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php diff --git a/Classes/Validation/DOMNodeValidator.php b/Classes/Validation/DOMNodeValidator.php index ddcd9587e..4c2703ed2 100644 --- a/Classes/Validation/DOMNodeValidator.php +++ b/Classes/Validation/DOMNodeValidator.php @@ -66,7 +66,7 @@ public function validateHasUniqueAttribute(string $name, string $contextExpressi $value = $this->node->getAttribute($name); if ($this->xpath->query($contextExpression . '[@' . $name . '="' . $value . '"]')->length > 1) { - $this->result->addError(new Error('"' . $name . '" attribute "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); + $this->result->addError(new Error('"' . $name . '" attribute with value "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); } return $this; diff --git a/Classes/Validation/Mets/DigitalRepresentationValidator.php b/Classes/Validation/Mets/DigitalRepresentationValidator.php index b593d6813..b1b6b2c1f 100644 --- a/Classes/Validation/Mets/DigitalRepresentationValidator.php +++ b/Classes/Validation/Mets/DigitalRepresentationValidator.php @@ -40,7 +40,7 @@ class DigitalRepresentationValidator extends ApplicationProfileBaseValidator const XPATH_FILE_SECTIONS = '//mets:mets/mets:fileSec'; - const XPATH_FILE_GROUPS = self::XPATH_FILE_SECTIONS . '/mets:fileGroup'; + const XPATH_FILE_GROUPS = self::XPATH_FILE_SECTIONS . '/mets:fileGrp'; const XPATH_FILES = self::XPATH_FILE_GROUPS . '/mets:file'; @@ -56,8 +56,10 @@ protected function isValidDocument(): void ->validateHasOne(); } - $this->validateFileGroups(); - $this->validateFiles(); + if($this->xpath->query(DigitalRepresentationValidator::XPATH_FILE_SECTIONS)->length > 0) { + $this->validateFileGroups(); + $this->validateFiles(); + } } /** @@ -103,7 +105,7 @@ public function validateFile(\DOMNode $file): void ->validateHasUniqueId() ->validateHasAttribute('MIMETYPE'); - $fLocat = $this->createNodeListValidator('/mets:FLocat', $file) + $fLocat = $this->createNodeListValidator('mets:FLocat', $file) ->validateHasOne() ->getFirstNode(); diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index a72fccba9..f7b8335c3 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -57,11 +57,7 @@ public function setUp(): void */ public function testDocument() { - $result = $this->validate(); - if ($result->hasErrors()) { - self::assertEquals('', $result->getFirstError()->getMessage()); - } - self::assertFalse($result->hasErrors()); + $this->assertNoError(); } /** @@ -74,6 +70,7 @@ public function validate(): Result return $this->validator->validate($this->doc); } + /** * Validates using validator and DOMDocument and assert result error message for equality. * @@ -175,6 +172,12 @@ protected function getDOMDocument(): DOMDocument return $doc; } + protected function assertNoError(): void + { + $result = $this->validate(); + $this->assertFalse($result->hasErrors()); + } + protected function assertErrorHasAny(string $expression, string $context = ''): void { $message = 'There must be at least one element that matches the XPath expression "' . $expression . '"'; @@ -224,7 +227,12 @@ protected function assertErrorHasRefToOne(string $expression, string $name, stri protected function assertErrorHasUniqueId(string $expression, string $value): void { - $this->validateAndAssertEquals('"ID" attribute "' . $value . '" of "' . $expression . '" already exists.'); + $this->assertErrorHasUniqueAttribute($expression, 'ID', $value); + } + + protected function assertErrorHasUniqueAttribute(string $expression, string $name, string $value): void + { + $this->validateAndAssertEquals('"' . $name . '" attribute with value "' . $value . '" of "' . $expression . '" already exists.'); } } diff --git a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php new file mode 100644 index 000000000..9871d74c4 --- /dev/null +++ b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php @@ -0,0 +1,116 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Validation\Mets\DigitalRepresentationValidator; +use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; + +class DigitalRepresentationValidatorTest extends ApplicationProfileValidatorTest +{ + + /** + * Test validation against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" + * + * @return void + */ + public function testFileSections(): void + { + $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:fileSec'); + $this->assertErrorHasNoneOrOne(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); + $this->resetDocument(); + + $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); + $this->assertErrorHasOne(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); + $this->resetDocument(); + + $this->removeNodes(PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); + $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); + $this->assertNoError(); + } + + /** + * Test validation against the rules of chapter "2.4.2.1 Dateigruppen – mets:fileGrp" + * + * @return void + */ + public function testFileGroups(): void + { + $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_GROUPS); + $this->assertErrorHasAny(DigitalRepresentationValidator::XPATH_FILE_GROUPS); + $this->resetDocument(); + + $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_GROUPS . '[@USE="DEFAULT"]'); + $this->assertErrorHasOne(DigitalRepresentationValidator::XPATH_FILE_GROUPS . '[@USE="DEFAULT"]'); + $this->resetDocument(); + + $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILE_GROUPS . '[@USE="THUMBS"]', 'USE', 'DEFAULT'); + $this->assertErrorHasUniqueAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]', 'USE', 'DEFAULT'); + } + + /** + * Test validation against the rules of chapter "2.4.2.2 Datei – mets:fileGrp/mets:file" and "2.4.2.3 Dateilink – mets:fileGrp/mets:file/mets:FLocat" + * + * @return void + */ + public function testFiles(): void + { + $this->removeNodes(DigitalRepresentationValidator::XPATH_FILES); + $this->assertErrorHasAny(DigitalRepresentationValidator::XPATH_FILES); + $this->resetDocument(); + + $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILES, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file', 'DMDLOG_0001'); + $this->resetDocument(); + + $this->removeAttribute(DigitalRepresentationValidator::XPATH_FILES, 'MIMETYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file', 'MIMETYPE'); + $this->resetDocument(); + + $this->removeNodes(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat'); + $this->assertErrorHasOne('mets:FLocat', '/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file'); + $this->resetDocument(); + + $this->removeAttribute(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'LOCTYPE'); + $this->assertErrorHasAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'LOCTYPE'); + $this->resetDocument(); + + $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'LOCTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'LOCTYPE','Test'); + $this->resetDocument(); + + $this->removeAttribute(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'xlink:href'); + $this->assertErrorHasAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'xlink:href'); + + $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'xlink:href', 'Test'); + $this->assertErrorHasAttributeWithUrl('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'xlink:href','Test'); + } + + protected function createValidator(): AbstractDlfValidator + { + return new DigitalRepresentationValidator(); + } +} From fc2536dc7aff4ff05412928a87b6f624e4ec4723 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Mon, 23 Dec 2024 12:12:16 +0100 Subject: [PATCH 21/43] Add validator --- Classes/Validation/DOMNodeValidator.php | 32 +++++ Classes/Validation/DVMetadataValidator.php | 150 +++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 Classes/Validation/DVMetadataValidator.php diff --git a/Classes/Validation/DOMNodeValidator.php b/Classes/Validation/DOMNodeValidator.php index 4c2703ed2..d67499a37 100644 --- a/Classes/Validation/DOMNodeValidator.php +++ b/Classes/Validation/DOMNodeValidator.php @@ -18,6 +18,38 @@ public function __construct(DOMXPath $xpath, Result $result, ?DOMNode $node) $this->node = $node; } + public function validateHasContentWithEmail(): DOMNodeValidator + { + if (!isset($this->node) && !$this->node->nodeValue) { + return $this; + } + + $email = $this->node->nodeValue; + + if (str_starts_with(strtolower($email), 'mailto:')) { + $email = substr($email, 7); + } + + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + $this->result->addError(new Error('Email "' . $this->node->nodeValue . '" in the content of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); + } + + return $this; + } + + public function validateHasContentWithUrl(): DOMNodeValidator + { + if (!isset($this->node) && !$this->node->nodeValue) { + return $this; + } + + if (!filter_var($this->node->nodeValue, FILTER_VALIDATE_URL)) { + $this->result->addError(new Error('URL "' . $this->node->nodeValue . '" in the content of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); + } + + return $this; + } + public function validateHasAttributeWithUrl(string $name): DOMNodeValidator { if (!isset($this->node)) { diff --git a/Classes/Validation/DVMetadataValidator.php b/Classes/Validation/DVMetadataValidator.php new file mode 100644 index 000000000..d8abd89f8 --- /dev/null +++ b/Classes/Validation/DVMetadataValidator.php @@ -0,0 +1,150 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +/** + * The validator validates against the rules outlined in chapter 2.7 of the METS application profile 2.3.1. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ +class DVMetadataValidator extends ApplicationProfileBaseValidator +{ + const XPATH_DV_RIGHTS = AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap[@MDTYPE="OTHER" and @OTHERMDTYPE="DVRIGHTS"]/mets:xmlData/dv:rights'; + + const XPATH_DV_LINKS = AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap[@MDTYPE="OTHER" and @OTHERMDTYPE="DVLINKS"]/mets:xmlData/dv:links'; + + protected function isValidDocument(): void + { + // Validates against the rules of chapter "2.7.1 Rechteangaben – dv:rights" + $this->createNodeListValidator(self::XPATH_DV_RIGHTS) + ->validateHasOne(); + + $this->validateDvRights(); + + $this->createNodeListValidator(self::XPATH_DV_LINKS) + ->validateHasOne(); + + $this->validateDvLinks(); + } + + /** + * Validates the DFG-Viewer links. + * + * Validates against the rules of chapter "2.7.4 Unterelemente zu dv:links" + * + * @return void + */ + public function validateDvLinks(): void + { + $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:reference') + ->validateHasAny() + ->iterate(array($this, "validateReferences")); + + $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:presentation') + ->validateHasNoneOrOne(); + + $sruNode = $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:sru') + ->validateHasNoneOrOne()->getFirstNode(); + $this->createNodeValidator($sruNode)->validateHasContentWithUrl(); + + $iiifNode = $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:iiif') + ->validateHasNoneOrOne()->getFirstNode(); + $this->createNodeValidator($iiifNode)->validateHasContentWithUrl(); + } + + /** + * Validates the DFG-Viewer rights. + * + * Validates against the rules of chapter "2.7.2 Unterelemente zu dv:rights" + * + * @return void + */ + public function validateDvRights(): void + { + $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:owner') + ->validateHasOne(); + + $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:ownerLogo'); + $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:ownerSiteURL'); + $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:ownerContact'); + + $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:aggregator')->validateHasNoneOrOne(); + $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:aggregatorLogo', true); + $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:aggregatorSiteURL', true); + + $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:sponsor')->validateHasNoneOrOne(); + $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:sponsorLogo', true); + $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:sponsorSiteURL', true); + + $licenseNode = $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:license') + ->validateHasNoneOrOne() + ->getFirstNode(); + if ($licenseNode && !in_array($licenseNode->nodeValue, array('pdm', 'cc0', 'cc-by', 'cc-by-sa', 'cc-by-nd', 'cc-by-nc', 'cc-by-nc-sa', 'cc-by-nc-nd', 'reserved'))) { + $this->createNodeValidator($licenseNode)->validateHasContentWithUrl(); + } + } + + /** + * Validates the references. + * + * Validates against the rules of chapter "2.7.4.1 Katalog- bzw. Findbuchnachweis – dv:reference" + * + * @return void + */ + public function validateReferences(\DOMNode $reference): void + { + if ($this->xpath->query('dv:reference', $reference->parentNode)->length > 1) { + $this->createNodeValidator($reference) + ->validateHasAttribute('linktext'); + } + } + + private function validateNodeContent(string $expression, bool $optional = false): void + { + $nodeListValidator = $this->createNodeListValidator($expression); + + if ($optional) { + $nodeListValidator + ->validateHasNoneOrOne(); + } else { + $nodeListValidator + ->validateHasOne(); + } + + $node = $nodeListValidator->getFirstNode(); + $nodeValidator = $this->createNodeValidator($node); + if (str_starts_with(strtolower($node->nodeValue), 'mailto:')) { + $nodeValidator->validateHasContentWithEmail(); + } else { + $nodeValidator->validateHasContentWithUrl(); + } + } +} From 39dad3502dea32fd83a01a69f25ad0423a4956b1 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Mon, 6 Jan 2025 17:48:27 +0100 Subject: [PATCH 22/43] Refactoring validation --- .../ValidationHelper.php} | 44 ++++++++- Classes/Validation/DVMetadataValidator.php | 43 ++++---- .../Mets/AdministrativeMetadataValidator.php | 33 +++---- ...r.php => DescriptiveMetadataValidator.php} | 16 ++- .../Mets/DigitalRepresentationValidator.php | 34 +++---- ...nkingLogicalPhysicalStructureValidator.php | 23 ++--- .../Mets/LogicalStructureValidator.php | 28 +++--- .../Mets/PhysicalStructureValidator.php | 21 ++-- .../MetsApplicationProfileValidationStack.php | 10 +- .../ApplicationProfileValidatorTest.php | 7 ++ .../AdministrativeMetadataValidatorTest.php | 99 +++++++++---------- ...p => DescriptiveMetadataValidatorTest.php} | 34 +++---- .../DigitalRepresentationValidatorTest.php | 57 ++++++----- ...gLogicalPhysicalStructureValidatorTest.php | 19 ++-- .../Mets/LogicalStructureValidatorTest.php | 34 +++---- .../Mets/PhysicalStructureValidatorTest.php | 21 ++-- 16 files changed, 267 insertions(+), 256 deletions(-) rename Classes/{Validation/ApplicationProfileBaseValidator.php => Common/ValidationHelper.php} (52%) rename Classes/Validation/Mets/{DeskriptiveMetadataValidator.php => DescriptiveMetadataValidator.php} (83%) rename Tests/Unit/Validation/Mets/{DeskriptiveMetadataValidatorTest.php => DescriptiveMetadataValidatorTest.php} (51%) diff --git a/Classes/Validation/ApplicationProfileBaseValidator.php b/Classes/Common/ValidationHelper.php similarity index 52% rename from Classes/Validation/ApplicationProfileBaseValidator.php rename to Classes/Common/ValidationHelper.php index 878cfb85e..9b1d98889 100644 --- a/Classes/Validation/ApplicationProfileBaseValidator.php +++ b/Classes/Common/ValidationHelper.php @@ -1,6 +1,6 @@ createNodeListValidator(self::XPATH_DV_RIGHTS) + $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS) ->validateHasOne(); $this->validateDvRights(); - $this->createNodeListValidator(self::XPATH_DV_LINKS) + // Validates against the rules of chapter "2.7.3 Verweise – dv:links" + $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS) ->validateHasOne(); $this->validateDvLinks(); @@ -64,18 +62,18 @@ protected function isValidDocument(): void */ public function validateDvLinks(): void { - $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:reference') + $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:reference') ->validateHasAny() ->iterate(array($this, "validateReferences")); - $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:presentation') + $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:presentation') ->validateHasNoneOrOne(); - $sruNode = $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:sru') + $sruNode = $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:sru') ->validateHasNoneOrOne()->getFirstNode(); $this->createNodeValidator($sruNode)->validateHasContentWithUrl(); - $iiifNode = $this->createNodeListValidator(self::XPATH_DV_LINKS . '/dv:iiif') + $iiifNode = $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:iiif') ->validateHasNoneOrOne()->getFirstNode(); $this->createNodeValidator($iiifNode)->validateHasContentWithUrl(); } @@ -89,22 +87,22 @@ public function validateDvLinks(): void */ public function validateDvRights(): void { - $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:owner') + $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:owner') ->validateHasOne(); - $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:ownerLogo'); - $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:ownerSiteURL'); - $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:ownerContact'); + $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerLogo'); + $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerSiteURL'); + $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerContact'); - $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:aggregator')->validateHasNoneOrOne(); - $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:aggregatorLogo', true); - $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:aggregatorSiteURL', true); + $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregator')->validateHasNoneOrOne(); + $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregatorLogo', true); + $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregatorSiteURL', true); - $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:sponsor')->validateHasNoneOrOne(); - $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:sponsorLogo', true); - $this->validateNodeContent(self::XPATH_DV_RIGHTS . '/dv:sponsorSiteURL', true); + $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsor')->validateHasNoneOrOne(); + $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsorLogo', true); + $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsorSiteURL', true); - $licenseNode = $this->createNodeListValidator(self::XPATH_DV_RIGHTS . '/dv:license') + $licenseNode = $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:license') ->validateHasNoneOrOne() ->getFirstNode(); if ($licenseNode && !in_array($licenseNode->nodeValue, array('pdm', 'cc0', 'cc-by', 'cc-by-sa', 'cc-by-nd', 'cc-by-nc', 'cc-by-nc-sa', 'cc-by-nc-nd', 'reserved'))) { @@ -117,6 +115,7 @@ public function validateDvRights(): void * * Validates against the rules of chapter "2.7.4.1 Katalog- bzw. Findbuchnachweis – dv:reference" * + * @param \DOMNode $reference * @return void */ public function validateReferences(\DOMNode $reference): void diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index 9c63f78b1..2e1b36134 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -2,7 +2,8 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\DOMDocumentValidator; /** * Copyright notice @@ -35,26 +36,17 @@ * * @access public */ -class AdministrativeMetadataValidator extends ApplicationProfileBaseValidator +class AdministrativeMetadataValidator extends DOMDocumentValidator { - - const XPATH_ADMINISTRATIVE_METADATA = '//mets:mets/mets:amdSec'; - - const XPATH_TECHNICAL_METADATA = self::XPATH_ADMINISTRATIVE_METADATA . '/mets:techMD'; - - const XPATH_RIGHTS_METADATA = self::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'; - - const XPATH_DIGIPROV_METADATA = self::XPATH_ADMINISTRATIVE_METADATA . '/mets:digiprovMD'; - - protected function isValidDocument(): void + public function isValidDocument(): void { // Validates against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" - $this->createNodeListValidator(self::XPATH_ADMINISTRATIVE_METADATA) + $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA) ->validateHasAny() ->iterate(array($this, "validateAdministrativMetadata")); // Check if one administrative metadata exist with "mets:rightsMD" and "mets:digiprovMD" as children - $this->createNodeListValidator(self::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]') + $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]') ->validateHasOne(); $this->validateTechnicalMetadataStructure(); @@ -75,9 +67,9 @@ public function validateAdministrativMetadata(\DOMNode $administrativeMetadata): * * @return void */ - protected function validateDigitalProvenanceMetadataStructure(): void + public function validateDigitalProvenanceMetadataStructure(): void { - $this->createNodeListValidator(self::XPATH_DIGIPROV_METADATA) + $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) ->iterate(array($this, "validateDigitalProvenanceMetadata")); } @@ -105,9 +97,9 @@ public function validateDigitalProvenanceMetadata(\DOMNode $digitalProvenanceMet * * @return void */ - protected function validateRightsMetadataStructure(): void + public function validateRightsMetadataStructure(): void { - $this->createNodeListValidator(self::XPATH_RIGHTS_METADATA) + $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) ->iterate(array($this, "validateRightsMetadata")); } @@ -135,9 +127,9 @@ public function validateRightsMetadata(\DOMNode $rightsMetadata): void * * @return void */ - protected function validateTechnicalMetadataStructure(): void + public function validateTechnicalMetadataStructure(): void { - $this->createNodeListValidator(self::XPATH_TECHNICAL_METADATA) + $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) ->iterate(array($this, "validateTechnicalMetadata")); } @@ -158,5 +150,4 @@ public function validateTechnicalMetadata(\DOMNode $technicalMetadata): void $this->createNodeListValidator('mets:xmlData', $mdWrap) ->validateHasOne(); } - } diff --git a/Classes/Validation/Mets/DeskriptiveMetadataValidator.php b/Classes/Validation/Mets/DescriptiveMetadataValidator.php similarity index 83% rename from Classes/Validation/Mets/DeskriptiveMetadataValidator.php rename to Classes/Validation/Mets/DescriptiveMetadataValidator.php index 3137aa4a3..e3ce6248d 100644 --- a/Classes/Validation/Mets/DeskriptiveMetadataValidator.php +++ b/Classes/Validation/Mets/DescriptiveMetadataValidator.php @@ -2,7 +2,8 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\DOMDocumentValidator; /** * Copyright notice @@ -35,25 +36,22 @@ * * @access public */ -class DeskriptiveMetadataValidator extends ApplicationProfileBaseValidator +class DescriptiveMetadataValidator extends DOMDocumentValidator { - - const XPATH_DESCRIPTIVE_METADATA_SECTIONS = '//mets:mets/mets:dmdSec'; - - protected function isValidDocument(): void + public function isValidDocument(): void { // Validates against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" - $this->createNodeListValidator(self::XPATH_DESCRIPTIVE_METADATA_SECTIONS) + $this->createNodeListValidator(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS) ->validateHasAny() ->iterate(array($this, 'validateDescriptiveMetadataSections')); // there must be one primary structural element - $logicalStructureElement = $this->createNodeListValidator(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS) + $logicalStructureElement = $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) ->validateHasOne() ->getFirstNode(); $this->createNodeValidator($logicalStructureElement) - ->validateHasReferenceToId('DMDID', self::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + ->validateHasReferenceToId('DMDID', ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); } /** diff --git a/Classes/Validation/Mets/DigitalRepresentationValidator.php b/Classes/Validation/Mets/DigitalRepresentationValidator.php index b1b6b2c1f..ec070fdb8 100644 --- a/Classes/Validation/Mets/DigitalRepresentationValidator.php +++ b/Classes/Validation/Mets/DigitalRepresentationValidator.php @@ -2,7 +2,8 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\DOMDocumentValidator; /** * Copyright notice @@ -35,28 +36,21 @@ * * @access public */ -class DigitalRepresentationValidator extends ApplicationProfileBaseValidator +class DigitalRepresentationValidator extends DOMDocumentValidator { - - const XPATH_FILE_SECTIONS = '//mets:mets/mets:fileSec'; - - const XPATH_FILE_GROUPS = self::XPATH_FILE_SECTIONS . '/mets:fileGrp'; - - const XPATH_FILES = self::XPATH_FILE_GROUPS . '/mets:file'; - - protected function isValidDocument(): void + public function isValidDocument(): void { // Validates against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" - $this->createNodeListValidator(self::XPATH_FILE_SECTIONS) + $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTIONS) ->validateHasNoneOrOne(); // If a physical structure is present, there must be one file section. - if($this->xpath->query(PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES)->length > 0){ - $this->createNodeListValidator(self::XPATH_FILE_SECTIONS) + if($this->xpath->query(ValidationHelper::XPATH_PHYSICAL_STRUCTURES)->length > 0){ + $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTIONS) ->validateHasOne(); } - if($this->xpath->query(DigitalRepresentationValidator::XPATH_FILE_SECTIONS)->length > 0) { + if ($this->xpath->query(ValidationHelper::XPATH_FILE_SECTIONS)->length > 0) { $this->validateFileGroups(); $this->validateFiles(); } @@ -69,20 +63,20 @@ protected function isValidDocument(): void * * @return void */ - protected function validateFileGroups(): void + public function validateFileGroups(): void { - $this->createNodeListValidator(self::XPATH_FILE_GROUPS) + $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTION_GROUPS) ->validateHasAny() ->iterate(array($this, "validateFileGroup")); - $this->createNodeListValidator(self::XPATH_FILE_GROUPS . '[@USE="DEFAULT"]') + $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]') ->validateHasOne(); } public function validateFileGroup(\DOMNode $fileGroup): void { $this->createNodeValidator($fileGroup) - ->validateHasUniqueAttribute("USE", self::XPATH_FILE_GROUPS); + ->validateHasUniqueAttribute("USE", ValidationHelper::XPATH_FILE_SECTION_GROUPS); } /** @@ -92,9 +86,9 @@ public function validateFileGroup(\DOMNode $fileGroup): void * * @return void */ - protected function validateFiles(): void + public function validateFiles(): void { - $this->createNodeListValidator(self::XPATH_FILES) + $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTION_FILES) ->validateHasAny() ->iterate(array($this, "validateFile")); } diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index a34d00e5c..b39cc6e02 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -25,7 +25,8 @@ * This copyright notice MUST APPEAR in all copies of the script! */ -use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\DOMDocumentValidator; /** * The validator validates against the rules outlined in chapter 2.3 of the METS application profile 2.3.1. @@ -35,17 +36,12 @@ * * @access public */ -class LinkingLogicalPhysicalStructureValidator extends ApplicationProfileBaseValidator +class LinkingLogicalPhysicalStructureValidator extends DOMDocumentValidator { - - const XPATH_STRUCT_LINK = '//mets:mets/mets:structLink'; - - const XPATH_LINK_ELEMENTS = self::XPATH_STRUCT_LINK . '/mets:smLink' ; - - protected function isValidDocument(): void + public function isValidDocument(): void { // Validates against the rules of chapter "2.3.1 Structure links - mets:structLink" - $this->createNodeListValidator(self::XPATH_STRUCT_LINK) + $this->createNodeListValidator(ValidationHelper::XPATH_STRUCT_LINK) ->validateHasNoneOrOne(); $this->validateLinkElements(); @@ -58,9 +54,9 @@ protected function isValidDocument(): void * * @return void */ - protected function validateLinkElements(): void + public function validateLinkElements(): void { - $this->createNodeListValidator(self::XPATH_LINK_ELEMENTS) + $this->createNodeListValidator(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS) ->validateHasAny() ->iterate(array($this, "validateLinkElement")); } @@ -68,8 +64,7 @@ protected function validateLinkElements(): void public function validateLinkElement(\DOMNode $linkElement): void { $this->createNodeValidator($linkElement) - ->validateHasReferenceToId("xlink:from", LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES) - ->validateHasReferenceToId("xlink:to", PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); + ->validateHasReferenceToId("xlink:from", ValidationHelper::XPATH_LOGICAL_STRUCTURES) + ->validateHasReferenceToId("xlink:to", ValidationHelper::XPATH_PHYSICAL_STRUCTURES); } - } diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index e6c254b00..a5db43103 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -2,7 +2,8 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\DOMDocumentValidator; /** * Copyright notice @@ -35,19 +36,12 @@ * * @access public */ -class LogicalStructureValidator extends ApplicationProfileBaseValidator +class LogicalStructureValidator extends DOMDocumentValidator { - - const XPATH_LOGICAL_STRUCTURES = '//mets:mets/mets:structMap[@TYPE="LOGICAL"]'; - - const XPATH_STRUCTURAL_ELEMENTS = self::XPATH_LOGICAL_STRUCTURES . '/mets:div'; - - const XPATH_EXTERNAL_REFERENCES = self::XPATH_STRUCTURAL_ELEMENTS . '/mets:mptr'; - - protected function isValidDocument(): void + public function isValidDocument(): void { // Validates against the rules of chapter "2.1.1 Logical structure - mets:structMap" - $this->createNodeListValidator(self::XPATH_LOGICAL_STRUCTURES) + $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_STRUCTURES) ->validateHasAny(); $this->validateStructuralElements(); @@ -62,9 +56,9 @@ protected function isValidDocument(): void * * @return void */ - protected function validateStructuralElements(): void + public function validateStructuralElements(): void { - $this->createNodeListValidator(self::XPATH_STRUCTURAL_ELEMENTS) + $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) ->validateHasAny() ->iterate(array($this, "validateStructuralElement")); } @@ -73,7 +67,7 @@ public function validateStructuralElement(\DOMNode $structureElement): void { $this->createNodeValidator($structureElement) ->validateHasUniqueId() - ->validateHasAttributeWithValue("TYPE", self::STRUCTURE_DATASET); + ->validateHasAttributeWithValue("TYPE", ValidationHelper::STRUCTURE_DATASET); } /** @@ -83,9 +77,9 @@ public function validateStructuralElement(\DOMNode $structureElement): void * * @return void */ - protected function validateExternalReferences(): void + public function validateExternalReferences(): void { - $this->createNodeListValidator(self::XPATH_EXTERNAL_REFERENCES) + $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES) ->validateHasNoneOrOne() ->iterate(array($this, "validateExternalReference")); } @@ -104,7 +98,7 @@ public function validateExternalReference(\DOMNode $externalReference): void * * @return void */ - protected function validatePeriodicPublishingSequences(): void + public function validatePeriodicPublishingSequences(): void { // TODO } diff --git a/Classes/Validation/Mets/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php index cc8e02465..f07c2641f 100644 --- a/Classes/Validation/Mets/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -2,8 +2,8 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Validation\ApplicationProfileBaseValidator; -use function PHPUnit\Framework\callback; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\DOMDocumentValidator; /** * Copyright notice @@ -36,18 +36,14 @@ * * @access public */ -class PhysicalStructureValidator extends ApplicationProfileBaseValidator +class PhysicalStructureValidator extends DOMDocumentValidator { - const XPATH_PHYSICAL_STRUCTURES = '//mets:mets/mets:structMap[@TYPE="PHYSICAL"]'; - const XPATH_STRUCTURAL_ELEMENT_SEQUENCE = self::XPATH_PHYSICAL_STRUCTURES . '/mets:div'; - const XPATH_STRUCTURAL_ELEMENTS = self::XPATH_STRUCTURAL_ELEMENT_SEQUENCE . '/mets:div'; - - protected function isValidDocument(): void + public function isValidDocument(): void { // Validates against the rules of chapter "2.2.1 Physical structure - mets:structMap" - $this->createNodeListValidator(self::XPATH_PHYSICAL_STRUCTURES) + $this->createNodeListValidator(ValidationHelper::XPATH_PHYSICAL_STRUCTURES) ->validateHasNoneOrOne(); $this->validateStructuralElements(); @@ -61,16 +57,16 @@ protected function isValidDocument(): void * * @return void */ - protected function validateStructuralElements(): void + public function validateStructuralElements(): void { - $node = $this->createNodeListValidator(self::XPATH_STRUCTURAL_ELEMENT_SEQUENCE) + $node = $this->createNodeListValidator(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE) ->validateHasOne() ->getFirstNode(); $this->createNodeValidator($node) ->validateHasAttributeWithValue('TYPE', array('physSequence')); - $this->createNodeListValidator(self::XPATH_STRUCTURAL_ELEMENTS) + $this->createNodeListValidator(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS) ->validateHasAny() ->iterate(array($this, "validateStructuralElement")); } @@ -81,5 +77,4 @@ public function validateStructuralElement(\DOMNode $structureElement): void ->validateHasUniqueId() ->validateHasAttributeWithValue("TYPE", array("page", "doublepage", "track")); } - } diff --git a/Classes/Validation/MetsApplicationProfileValidationStack.php b/Classes/Validation/MetsApplicationProfileValidationStack.php index 2ea42e4d4..a6cb78eb9 100644 --- a/Classes/Validation/MetsApplicationProfileValidationStack.php +++ b/Classes/Validation/MetsApplicationProfileValidationStack.php @@ -28,6 +28,9 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidationStack; +use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; +use Slub\Dfgviewer\Validation\Mets\DescriptiveMetadataValidator; +use Slub\Dfgviewer\Validation\Mets\DigitalRepresentationValidator; use Slub\Dfgviewer\Validation\Mets\LinkingLogicalPhysicalStructureValidator; use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; @@ -35,11 +38,14 @@ class MetsApplicationProfileValidationStack extends AbstractDlfValidationStack { public function __construct(array $options = []) { - parent::__construct(\DOMDocument::class, $options); + parent::__construct(\DOMDocument::class); $this->addValidator(LogicalStructureValidator::class, "Specifications for the logical document structure", false); $this->addValidator(PhysicalStructureValidator::class, "Specifications for the physical document structure", false); $this->addValidator(LinkingLogicalPhysicalStructureValidator::class, "Specifications for the physical document structure", false); - + $this->addValidator(DigitalRepresentationValidator::class, "Specifications for the physical document structure", false); + $this->addValidator(DescriptiveMetadataValidator::class, "Descriptive metadata", false); + $this->addValidator(AdministrativeMetadataValidator::class, "Administrative metadata", false); + $this->addValidator(DVMetadataValidator::class, "DFG-Viewer specific informations", false); } } diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index f7b8335c3..5d1cfed01 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -70,6 +70,13 @@ public function validate(): Result return $this->validator->validate($this->doc); } + public static function trimDoubleSlash(string $value): string + { + if(str_starts_with($value, '//')) { + return substr($value, 1); + } + return $value; + } /** * Validates using validator and DOMDocument and assert result error message for equality. diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php index 51bcff7b7..22bee6373 100644 --- a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php @@ -26,11 +26,11 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper; use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; class AdministrativeMetadataValidatorTest extends ApplicationProfileValidatorTest { - /** * Test validation against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" * @@ -38,19 +38,19 @@ class AdministrativeMetadataValidatorTest extends ApplicationProfileValidatorTes */ public function testAdministrativeMetadata(): void { - $this->removeNodes(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA); - $this->assertErrorHasAny(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA); + $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA); + $this->assertErrorHasAny(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA); $this->resetDocument(); - $this->removeNodes(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'); - $this->assertErrorHasOne(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]'); + $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'); + $this->assertErrorHasOne(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]'); $this->resetDocument(); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec', 'DMDLOG_0001'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA), 'DMDLOG_0001'); - $this->removeAttribute(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA, 'ID'); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec', 'ID'); + $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, 'ID'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA), 'ID'); } /** @@ -60,30 +60,30 @@ public function testAdministrativeMetadata(): void */ public function testDigitalProvenanceMetadataStructure(): void { - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec/mets:digiprovMD', 'DMDLOG_0001'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA), 'DMDLOG_0001'); $this->resetDocument(); - $this->removeNodes(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', '/mets:mets/mets:amdSec/mets:digiprovMD'); + $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA)); $this->resetDocument(); - $this->removeAttribute(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'MDTYPE'); + $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'MDTYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); $this->resetDocument(); - $this->removeAttribute(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'OTHERMDTYPE'); + $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); $this->resetDocument(); - $this->removeNodes(AdministrativeMetadataValidator::XPATH_DIGIPROV_METADATA . '/mets:mdWrap/mets:xmlData/dv:links'); - $this->assertErrorHasOne('mets:xmlData[dv:links]', '/mets:mets/mets:amdSec/mets:digiprovMD/mets:mdWrap'); + $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap/mets:xmlData/dv:links'); + $this->assertErrorHasOne('mets:xmlData[dv:links]', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap'); } @@ -94,30 +94,30 @@ public function testDigitalProvenanceMetadataStructure(): void */ public function testRightsMetadataStructure(): void { - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec/mets:rightsMD', 'DMDLOG_0001'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA), 'DMDLOG_0001'); $this->resetDocument(); - $this->removeNodes(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', '/mets:mets/mets:amdSec/mets:rightsMD'); + $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA)); $this->resetDocument(); - $this->removeAttribute(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'MDTYPE'); + $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'MDTYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); $this->resetDocument(); - $this->removeAttribute(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'OTHERMDTYPE'); + $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); $this->resetDocument(); - $this->removeNodes(AdministrativeMetadataValidator::XPATH_RIGHTS_METADATA . '/mets:mdWrap/mets:xmlData/dv:rights'); - $this->assertErrorHasOne('mets:xmlData[dv:rights]', '/mets:mets/mets:amdSec/mets:rightsMD/mets:mdWrap'); + $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap/mets:xmlData/dv:rights'); + $this->assertErrorHasOne('mets:xmlData[dv:rights]', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap'); } /** @@ -127,26 +127,25 @@ public function testRightsMetadataStructure(): void */ public function testTechnicalMetadataStructure(): void { - $this->addChildNodeNS(AdministrativeMetadataValidator::XPATH_ADMINISTRATIVE_METADATA, self::NAMESPACE_METS, 'mets:techMD'); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD','ID'); + $this->addChildNodeNS(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, self::NAMESPACE_METS, 'mets:techMD'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'ID'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId('/mets:mets/mets:amdSec/mets:techMD','DMDLOG_0001'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'DMDLOG_0001'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA, 'ID', 'TECH_0001'); - $this->assertErrorHasOne('mets:mdWrap','/mets:mets/mets:amdSec/mets:techMD'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'TECH_0001'); + $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA)); - $this->addChildNodeNS(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA, self::NAMESPACE_METS, 'mets:mdWrap'); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap','MDTYPE'); + $this->addChildNodeNS(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, self::NAMESPACE_METS, 'mets:mdWrap'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'MDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA . '/mets:mdWrap', 'MDTYPE', ''); - $this->assertErrorHasAttribute('/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap','OTHERMDTYPE'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'MDTYPE', ''); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->setAttributeValue(AdministrativeMetadataValidator::XPATH_TECHNICAL_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', ''); - $this->assertErrorHasOne('mets:xmlData','/mets:mets/mets:amdSec/mets:techMD/mets:mdWrap'); + $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', ''); + $this->assertErrorHasOne('mets:xmlData', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap'); } - protected function createValidator(): AbstractDlfValidator { return new AdministrativeMetadataValidator(); diff --git a/Tests/Unit/Validation/Mets/DeskriptiveMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php similarity index 51% rename from Tests/Unit/Validation/Mets/DeskriptiveMetadataValidatorTest.php rename to Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php index 2f615e2e6..aca94b8d3 100644 --- a/Tests/Unit/Validation/Mets/DeskriptiveMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php @@ -26,12 +26,11 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Validation\Mets\DeskriptiveMetadataValidator; -use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\Mets\DescriptiveMetadataValidator; -class DeskriptiveMetadataValidatorTest extends ApplicationProfileValidatorTest +class DescriptiveMetadataValidatorTest extends ApplicationProfileValidatorTest { - /** * Test validation against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" * @@ -39,16 +38,16 @@ class DeskriptiveMetadataValidatorTest extends ApplicationProfileValidatorTest */ public function testDescriptiveMetadata(): void { - $this->removeNodes(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS); - $this->assertErrorHasAny(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->removeNodes(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->assertErrorHasAny(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); $this->resetDocument(); - $this->removeNodes(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); - $this->assertErrorHasOne(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->removeNodes(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->assertErrorHasOne(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); - $this->setAttributeValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'DMDID', 'Test'); - $this->assertErrorHasRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'DMDID', 'Test'); + $this->assertErrorHasRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); } /** @@ -58,21 +57,20 @@ public function testDescriptiveMetadata(): void */ public function testEmbeddedMetadata(): void { - $this->removeNodes(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', '/mets:mets/mets:dmdSec'); + $this->removeNodes(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS)); $this->resetDocument(); - $this->setAttributeValue(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:dmdSec/mets:mdWrap', 'MDTYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap', 'MDTYPE', 'Test'); $this->resetDocument(); - $this->removeNodes(DeskriptiveMetadataValidator::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap/mets:xmlData/mods:mods'); - $this->assertErrorHasOne('mets:xmlData[mods:mods]', '/mets:mets/mets:dmdSec/mets:mdWrap'); + $this->removeNodes(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap/mets:xmlData/mods:mods'); + $this->assertErrorHasOne('mets:xmlData[mods:mods]', self::trimDoubleSlash(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap'); } - protected function createValidator(): AbstractDlfValidator { - return new DeskriptiveMetadataValidator(); + return new DescriptiveMetadataValidator(); } } diff --git a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php index 9871d74c4..39cc5f574 100644 --- a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php +++ b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php @@ -26,12 +26,11 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper; use Slub\Dfgviewer\Validation\Mets\DigitalRepresentationValidator; -use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; class DigitalRepresentationValidatorTest extends ApplicationProfileValidatorTest { - /** * Test validation against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" * @@ -40,15 +39,15 @@ class DigitalRepresentationValidatorTest extends ApplicationProfileValidatorTest public function testFileSections(): void { $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:fileSec'); - $this->assertErrorHasNoneOrOne(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_FILE_SECTIONS); $this->resetDocument(); - $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); - $this->assertErrorHasOne(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); + $this->removeNodes(ValidationHelper::XPATH_FILE_SECTIONS); + $this->assertErrorHasOne(ValidationHelper::XPATH_FILE_SECTIONS); $this->resetDocument(); - $this->removeNodes(PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); - $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_SECTIONS); + $this->removeNodes(ValidationHelper::XPATH_PHYSICAL_STRUCTURES); + $this->removeNodes(ValidationHelper::XPATH_FILE_SECTIONS); $this->assertNoError(); } @@ -59,16 +58,16 @@ public function testFileSections(): void */ public function testFileGroups(): void { - $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_GROUPS); - $this->assertErrorHasAny(DigitalRepresentationValidator::XPATH_FILE_GROUPS); + $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_GROUPS); + $this->assertErrorHasAny(ValidationHelper::XPATH_FILE_SECTION_GROUPS); $this->resetDocument(); - $this->removeNodes(DigitalRepresentationValidator::XPATH_FILE_GROUPS . '[@USE="DEFAULT"]'); - $this->assertErrorHasOne(DigitalRepresentationValidator::XPATH_FILE_GROUPS . '[@USE="DEFAULT"]'); + $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); + $this->assertErrorHasOne(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); $this->resetDocument(); - $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILE_GROUPS . '[@USE="THUMBS"]', 'USE', 'DEFAULT'); - $this->assertErrorHasUniqueAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]', 'USE', 'DEFAULT'); + $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="THUMBS"]', 'USE', 'DEFAULT'); + $this->assertErrorHasUniqueAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]', 'USE', 'DEFAULT'); } /** @@ -78,35 +77,35 @@ public function testFileGroups(): void */ public function testFiles(): void { - $this->removeNodes(DigitalRepresentationValidator::XPATH_FILES); - $this->assertErrorHasAny(DigitalRepresentationValidator::XPATH_FILES); + $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_FILES); + $this->assertErrorHasAny(ValidationHelper::XPATH_FILE_SECTION_FILES); $this->resetDocument(); - $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILES, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file', 'DMDLOG_0001'); + $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_FILES, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'DMDLOG_0001'); $this->resetDocument(); - $this->removeAttribute(DigitalRepresentationValidator::XPATH_FILES, 'MIMETYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file', 'MIMETYPE'); + $this->removeAttribute(ValidationHelper::XPATH_FILE_SECTION_FILES, 'MIMETYPE'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'MIMETYPE'); $this->resetDocument(); - $this->removeNodes(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat'); - $this->assertErrorHasOne('mets:FLocat', '/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file'); + $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat'); + $this->assertErrorHasOne('mets:FLocat', self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file'); $this->resetDocument(); - $this->removeAttribute(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'LOCTYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'LOCTYPE'); + $this->removeAttribute(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE'); $this->resetDocument(); - $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'LOCTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'LOCTYPE','Test'); + $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE', 'Test'); $this->resetDocument(); - $this->removeAttribute(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'xlink:href'); - $this->assertErrorHasAttribute('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'xlink:href'); + $this->removeAttribute(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href'); + $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href'); - $this->setAttributeValue(DigitalRepresentationValidator::XPATH_FILES . '/mets:FLocat', 'xlink:href', 'Test'); - $this->assertErrorHasAttributeWithUrl('/mets:mets/mets:fileSec/mets:fileGrp[1]/mets:file/mets:FLocat', 'xlink:href','Test'); + $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href', 'Test'); + $this->assertErrorHasAttributeWithUrl(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href', 'Test'); } protected function createValidator(): AbstractDlfValidator diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index e89baccbd..8f7ba86e9 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -26,13 +26,11 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper; use Slub\Dfgviewer\Validation\Mets\LinkingLogicalPhysicalStructureValidator; -use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; -use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileValidatorTest { - /** * Test validation against the rules of chapter "2.3.1 Structure links - mets:structLink" * @@ -41,26 +39,25 @@ class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileVal public function testMultipleStructLinks(): void { $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:structLink'); - $this->assertErrorHasNoneOrOne(LinkingLogicalPhysicalStructureValidator::XPATH_STRUCT_LINK); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_STRUCT_LINK); } public function testLinkElements(): void { - $this->removeNodes(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS); - $this->assertErrorHasAny(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS); + $this->removeNodes(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS); + $this->assertErrorHasAny(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS); $this->resetDocument(); - $this->setAttributeValue(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:from', 'Test'); - $this->assertErrorHasRefToOne('/mets:mets/mets:structLink/mets:smLink', 'xlink:from', 'Test', LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); + $this->setAttributeValue(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:from', 'Test'); + $this->assertErrorHasRefToOne(self::trimDoubleSlash(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:from', 'Test', ValidationHelper::XPATH_LOGICAL_STRUCTURES); $this->resetDocument(); - $this->setAttributeValue(LinkingLogicalPhysicalStructureValidator::XPATH_LINK_ELEMENTS, 'xlink:to', 'Test'); - $this->assertErrorHasRefToOne('/mets:mets/mets:structLink/mets:smLink', 'xlink:to', 'Test', PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); + $this->setAttributeValue(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:to', 'Test'); + $this->assertErrorHasRefToOne(self::trimDoubleSlash(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:to', 'Test', ValidationHelper::XPATH_PHYSICAL_STRUCTURES); } protected function createValidator(): AbstractDlfValidator { return new LinkingLogicalPhysicalStructureValidator(); } - } diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index 24314ab8c..d283464ac 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -26,11 +26,11 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper; use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest { - /** * Test validation against the rules of chapter "2.1.1 Logical structure - mets:structMap" * @@ -38,8 +38,8 @@ class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest */ public function testNotExistingLogicalStructureElement(): void { - $this->removeNodes(LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); - $this->assertErrorHasAny(LogicalStructureValidator::XPATH_LOGICAL_STRUCTURES); + $this->removeNodes(ValidationHelper::XPATH_LOGICAL_STRUCTURES); + $this->assertErrorHasAny(ValidationHelper::XPATH_LOGICAL_STRUCTURES); } /** @@ -48,24 +48,24 @@ public function testNotExistingLogicalStructureElement(): void */ public function testStructuralElements(): void { - $this->removeNodes(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); - $this->assertErrorHasAny(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->removeNodes(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->assertErrorHasAny(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); - $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->removeAttribute(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'ID'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'ID'); $this->resetDocument(); $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); - $this->addChildNode(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, $node); + $this->addChildNode(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, $node); $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[1]/mets:div', 'LOG_0001'); $this->resetDocument(); - $this->removeAttribute(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->removeAttribute(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'TYPE'); - $this->setAttributeValue(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div', 'TYPE', 'Test'); } @@ -76,24 +76,24 @@ public function testStructuralElements(): void */ public function testExternalReference(): void { - $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->assertErrorHasNoneOrOne(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES); + $this->addChildNodeNS(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeNS(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES); $this->resetDocument(); - $this->addChildNodeNS(LogicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeNS(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE'); - $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); - $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); + $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href'); - $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); $this->assertErrorHasAttributeWithUrl('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href', 'Test'); - $this->setAttributeValue(LogicalStructureValidator::XPATH_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); + $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); $result = $this->validate(); self::assertFalse($result->hasErrors()); } diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index b5379a0db..95eac0d17 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -26,6 +26,7 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper; use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; class PhysicalStructureValidatorTest extends ApplicationProfileValidatorTest @@ -41,7 +42,7 @@ public function testMultiplePhysicalDivisions(): void $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:structMap'); $node->setAttribute('TYPE', 'PHYSICAL'); $this->addChildNode('/mets:mets', $node); - $this->assertErrorHasNoneOrOne(PhysicalStructureValidator::XPATH_PHYSICAL_STRUCTURES); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_PHYSICAL_STRUCTURES); } /** @@ -51,22 +52,22 @@ public function testMultiplePhysicalDivisions(): void */ public function testStructuralElements(): void { - $this->removeNodes(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE); - $this->assertErrorHasOne(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE); + $this->removeNodes(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); + $this->assertErrorHasOne(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); $this->resetDocument(); - $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); + $this->removeAttribute(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div', 'TYPE'); - $this->setAttributeValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div', 'TYPE', 'Test'); $this->resetDocument(); - $this->removeNodes(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); - $this->assertErrorHasAny(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS); + $this->removeNodes(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); + $this->assertErrorHasAny(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); - $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'ID'); + $this->removeAttribute(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'ID'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'ID'); $this->resetDocument(); @@ -76,10 +77,10 @@ public function testStructuralElements(): void $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[2]/mets:div/mets:div[1]', 'PHYS_0001'); $this->resetDocument(); - $this->removeAttribute(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->removeAttribute(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE'); - $this->setAttributeValue(PhysicalStructureValidator::XPATH_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->setAttributeValue(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE', 'Test'); } From 7a50d5ebe187c5aca9b9e0937f1c91cd4de800f9 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Tue, 7 Jan 2025 14:49:10 +0100 Subject: [PATCH 23/43] Add test for DvMetadataValidator --- Classes/Validation/DOMNodeValidator.php | 4 +- ...aValidator.php => DvMetadataValidator.php} | 7 +- .../MetsApplicationProfileValidationStack.php | 2 +- Tests/Fixtures/mets.xml | 13 +- .../ApplicationProfileValidatorTest.php | 33 +++- .../Validation/DvMetadataValidatorTest.php | 152 ++++++++++++++++++ .../AdministrativeMetadataValidatorTest.php | 4 +- .../DigitalRepresentationValidatorTest.php | 2 +- ...gLogicalPhysicalStructureValidatorTest.php | 2 +- .../Mets/LogicalStructureValidatorTest.php | 6 +- 10 files changed, 208 insertions(+), 17 deletions(-) rename Classes/Validation/{DVMetadataValidator.php => DvMetadataValidator.php} (97%) create mode 100644 Tests/Unit/Validation/DvMetadataValidatorTest.php diff --git a/Classes/Validation/DOMNodeValidator.php b/Classes/Validation/DOMNodeValidator.php index d67499a37..45af9c9a9 100644 --- a/Classes/Validation/DOMNodeValidator.php +++ b/Classes/Validation/DOMNodeValidator.php @@ -20,7 +20,7 @@ public function __construct(DOMXPath $xpath, Result $result, ?DOMNode $node) public function validateHasContentWithEmail(): DOMNodeValidator { - if (!isset($this->node) && !$this->node->nodeValue) { + if (!isset($this->node) || !$this->node->nodeValue) { return $this; } @@ -39,7 +39,7 @@ public function validateHasContentWithEmail(): DOMNodeValidator public function validateHasContentWithUrl(): DOMNodeValidator { - if (!isset($this->node) && !$this->node->nodeValue) { + if (!isset($this->node) || !$this->node->nodeValue) { return $this; } diff --git a/Classes/Validation/DVMetadataValidator.php b/Classes/Validation/DvMetadataValidator.php similarity index 97% rename from Classes/Validation/DVMetadataValidator.php rename to Classes/Validation/DvMetadataValidator.php index 49d88c8a2..4b33d4ae2 100644 --- a/Classes/Validation/DVMetadataValidator.php +++ b/Classes/Validation/DvMetadataValidator.php @@ -3,7 +3,6 @@ namespace Slub\Dfgviewer\Validation; use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; /** * Copyright notice @@ -36,7 +35,7 @@ * * @access public */ -class DVMetadataValidator extends DOMDocumentValidator +class DvMetadataValidator extends DOMDocumentValidator { protected function isValidDocument(): void { @@ -139,6 +138,10 @@ private function validateNodeContent(string $expression, bool $optional = false) } $node = $nodeListValidator->getFirstNode(); + if (!isset($node)) { + return; + } + $nodeValidator = $this->createNodeValidator($node); if (str_starts_with(strtolower($node->nodeValue), 'mailto:')) { $nodeValidator->validateHasContentWithEmail(); diff --git a/Classes/Validation/MetsApplicationProfileValidationStack.php b/Classes/Validation/MetsApplicationProfileValidationStack.php index a6cb78eb9..b4a5d6c07 100644 --- a/Classes/Validation/MetsApplicationProfileValidationStack.php +++ b/Classes/Validation/MetsApplicationProfileValidationStack.php @@ -46,6 +46,6 @@ public function __construct(array $options = []) $this->addValidator(DigitalRepresentationValidator::class, "Specifications for the physical document structure", false); $this->addValidator(DescriptiveMetadataValidator::class, "Descriptive metadata", false); $this->addValidator(AdministrativeMetadataValidator::class, "Administrative metadata", false); - $this->addValidator(DVMetadataValidator::class, "DFG-Viewer specific informations", false); + $this->addValidator(DvMetadataValidator::class, "DFG-Viewer specific informations", false); } } diff --git a/Tests/Fixtures/mets.xml b/Tests/Fixtures/mets.xml index 4270234de..2d1193f71 100644 --- a/Tests/Fixtures/mets.xml +++ b/Tests/Fixtures/mets.xml @@ -78,6 +78,13 @@ http://dfg-viewer.de/fileadmin/_processed_/a/8/csm_HSM_Logo_T_schwarz_klein_bold_regular_d61a371993.jpg https://3d-repository.hs-mainz.de/ https://3d-repository.hs-mainz.de/contact + Aggregator + http://dfg-viewer.de/fileadmin/_processed_/a/8/csm_HSM_Logo_T_schwarz_klein_bold_regular_d61a371993.jpg + https://3d-repository.hs-mainz.de/ + Sponsor + http://dfg-viewer.de/fileadmin/_processed_/a/8/csm_HSM_Logo_T_schwarz_klein_bold_regular_d61a371993.jpg + https://3d-repository.hs-mainz.de/ + pdm @@ -86,8 +93,10 @@ - - + http://slub-dresden.de/FOZK.pl?PPN=356448053 + http://slub-dresden.de/356448053 + http://digital.slub-dresden.de/sru/356448053 + http://digital.slub-dresden.de/iiif/356448053.xml diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php index 5d1cfed01..206529ced 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/ApplicationProfileValidatorTest.php @@ -36,6 +36,8 @@ abstract class ApplicationProfileValidatorTest extends UnitTestCase { const NAMESPACE_METS = 'http://www.loc.gov/METS/'; + const NAMESPACE_DV = 'http://dfg-viewer.de/'; + protected $validator; protected $doc; @@ -106,7 +108,7 @@ protected function resetDocument(): void * @return void * @throws \DOMException */ - protected function addChildNodeNS(string $expression, string $namespace, string $name): void + protected function addChildNodeWithNamespace(string $expression, string $namespace, string $name): void { $this->addChildNode($expression, $this->doc->createElementNS($namespace, $name)); } @@ -171,6 +173,22 @@ protected function removeAttribute(string $expression, string $attribute): void } } + /** + * Set value of content found by node expression in DOMDocument. + * + * @param string $expression + * @param string $value + * @return void + */ + protected function setContentValue(string $expression, string $value): void + { + $xpath = new DOMXPath($this->doc); + foreach ($xpath->evaluate($expression) as $node) { + $node->nodeValue = $value; + } + } + + protected function getDOMDocument(): DOMDocument { $doc = new DOMDocument(); @@ -227,7 +245,17 @@ protected function assertErrorHasAttributeWithUrl(string $expression, string $na $this->validateAndAssertEquals('URL "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not valid.'); } - protected function assertErrorHasRefToOne(string $expression, string $name, string $value, string $targetContextExpression) + protected function assertErrorHasContentWithEmail(string $expression, string $value): void + { + $this->validateAndAssertEquals('Email "' . $value . '" in the content of "' . $expression . '" is not valid.'); + } + + protected function assertErrorHasContentWithUrl(string $expression, string $value): void + { + $this->validateAndAssertEquals('URL "' . $value . '" in the content of "' . $expression . '" is not valid.'); + } + + protected function assertErrorHasRefToOne(string $expression, string $name, string $value, string $targetContextExpression): void { $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); } @@ -241,5 +269,4 @@ protected function assertErrorHasUniqueAttribute(string $expression, string $nam { $this->validateAndAssertEquals('"' . $name . '" attribute with value "' . $value . '" of "' . $expression . '" already exists.'); } - } diff --git a/Tests/Unit/Validation/DvMetadataValidatorTest.php b/Tests/Unit/Validation/DvMetadataValidatorTest.php new file mode 100644 index 000000000..121d10638 --- /dev/null +++ b/Tests/Unit/Validation/DvMetadataValidatorTest.php @@ -0,0 +1,152 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Validation\DvMetadataValidator; + +class DvMetadataValidatorTest extends ApplicationProfileValidatorTest +{ + /** + * Test validation against the rules of chapter "2.7.1 Rechteangaben – dv:rights" + * + * @return void + */ + public function testDvRights(): void + { + $this->removeNodes(ValidationHelper::XPATH_DVRIGHTS); + $this->assertErrorHasOne(ValidationHelper::XPATH_DVRIGHTS); + } + + /** + * Test validation against the rules of chapter "2.7.2 Unterelemente zu dv:rights" + * + * @return void + */ + public function testDvRightsSubelements(): void + { + $this->removeNodes(ValidationHelper::XPATH_DVRIGHTS . '/dv:owner'); + $this->assertErrorHasOne(ValidationHelper::XPATH_DVRIGHTS . '/dv:owner'); + $this->resetDocument(); + + $this->assertNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerLogo', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerLogo'); + $this->assertNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerSiteURL', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerSiteURL'); + $this->assertNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerContact', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact'); + $this->setContentValue(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerContact', 'mailto:Test'); + $this->assertErrorHasContentWithEmail($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact', 'mailto:Test'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVRIGHTS, self::NAMESPACE_DV, 'dv:aggregator'); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregator'); + $this->resetDocument(); + $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:aggregatorLogo', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorLogo'); + $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:aggregatorSiteURL', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorSiteURL'); + + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVRIGHTS, self::NAMESPACE_DV, 'dv:sponsor'); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsor'); + $this->resetDocument(); + $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:sponsorLogo', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorLogo'); + $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:sponsorSiteURL', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorSiteURL'); + + $this->setContentValue(ValidationHelper::XPATH_DVRIGHTS . '/dv:license', 'Test'); + $this->assertErrorHasContentWithUrl($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:license', 'Test'); + } + + /** + * Test validation against the rules of chapter "2.7.3 Verweise – dv:links" + * + * @return void + */ + public function testDvLinks(): void + { + $this->removeNodes(ValidationHelper::XPATH_DVLINKS); + $this->assertErrorHasOne(ValidationHelper::XPATH_DVLINKS); + } + + /** + * Test validation against the rules of chapter "2.7.4 Unterelemente zu dv:links" + * + * @return void + */ + public function testDvLinksSubelements(): void + { + $this->removeNodes(ValidationHelper::XPATH_DVLINKS . '/dv:reference'); + $this->assertErrorHasAny(ValidationHelper::XPATH_DVLINKS . '/dv:reference'); + $this->resetDocument(); + + // if there are multiple `dv:references`, the `linktext` attribute must be present. + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:reference'); + $this->assertErrorHasAttribute($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:reference[1]', 'linktext'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:presentation'); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVLINKS . '/dv:presentation'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:sru'); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVLINKS . '/dv:sru'); + $this->resetDocument(); + + $this->setContentValue(ValidationHelper::XPATH_DVLINKS . '/dv:sru', 'Test'); + $this->assertErrorHasContentWithUrl($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:sru', 'Test'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:iiif'); + $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVLINKS . '/dv:iiif'); + $this->resetDocument(); + + $this->setContentValue(ValidationHelper::XPATH_DVLINKS . '/dv:iiif', 'Test'); + $this->assertErrorHasContentWithUrl($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:iiif', 'Test'); + } + + protected function assertNodeContent(string $expression, string $expectedErrorExpression): void + { + $this->removeNodes($expression); + $this->assertErrorHasOne($expression); + $this->resetDocument(); + + $this->setContentValue($expression, 'Test'); + $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); + $this->resetDocument(); + } + + protected function assertOptionalNodeContent(string $expression, string $name, string $expectedErrorExpression): void + { + $this->addChildNodeWithNamespace($expression, self::NAMESPACE_DV, $name); + $this->assertErrorHasNoneOrOne($expression . '/' . $name); + $this->resetDocument(); + + $this->setContentValue($expression . '/' . $name, 'Test'); + $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); + $this->resetDocument(); + } + + protected function createValidator(): AbstractDlfValidator + { + return new DvMetadataValidator(); + } +} diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php index 22bee6373..ac68c6313 100644 --- a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php @@ -127,7 +127,7 @@ public function testRightsMetadataStructure(): void */ public function testTechnicalMetadataStructure(): void { - $this->addChildNodeNS(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, self::NAMESPACE_METS, 'mets:techMD'); + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, self::NAMESPACE_METS, 'mets:techMD'); $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'ID'); $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'DMDLOG_0001'); @@ -136,7 +136,7 @@ public function testTechnicalMetadataStructure(): void $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'TECH_0001'); $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA)); - $this->addChildNodeNS(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, self::NAMESPACE_METS, 'mets:mdWrap'); + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, self::NAMESPACE_METS, 'mets:mdWrap'); $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'MDTYPE'); $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'MDTYPE', ''); diff --git a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php index 39cc5f574..cc48f3bec 100644 --- a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php +++ b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php @@ -38,7 +38,7 @@ class DigitalRepresentationValidatorTest extends ApplicationProfileValidatorTest */ public function testFileSections(): void { - $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:fileSec'); + $this->addChildNodeWithNamespace('/mets:mets', self::NAMESPACE_METS, 'mets:fileSec'); $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_FILE_SECTIONS); $this->resetDocument(); diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index 8f7ba86e9..8e0d0ab24 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -38,7 +38,7 @@ class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileVal */ public function testMultipleStructLinks(): void { - $this->addChildNodeNS('/mets:mets', self::NAMESPACE_METS, 'mets:structLink'); + $this->addChildNodeWithNamespace('/mets:mets', self::NAMESPACE_METS, 'mets:structLink'); $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_STRUCT_LINK); } diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index d283464ac..aea163172 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -76,12 +76,12 @@ public function testStructuralElements(): void */ public function testExternalReference(): void { - $this->addChildNodeNS(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->addChildNodeNS(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES); $this->resetDocument(); - $this->addChildNodeNS(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeWithNamespace(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE'); $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); From 355faf8fa058d2828dad4d6269c3878c3245e863 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Tue, 7 Jan 2025 14:55:27 +0100 Subject: [PATCH 24/43] Improvements --- .../MetsApplicationProfileValidationStack.php | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Classes/Validation/MetsApplicationProfileValidationStack.php b/Classes/Validation/MetsApplicationProfileValidationStack.php index b4a5d6c07..ed6e50896 100644 --- a/Classes/Validation/MetsApplicationProfileValidationStack.php +++ b/Classes/Validation/MetsApplicationProfileValidationStack.php @@ -36,16 +36,15 @@ use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; class MetsApplicationProfileValidationStack extends AbstractDlfValidationStack { - public function __construct(array $options = []) + public function __construct() { parent::__construct(\DOMDocument::class); - - $this->addValidator(LogicalStructureValidator::class, "Specifications for the logical document structure", false); - $this->addValidator(PhysicalStructureValidator::class, "Specifications for the physical document structure", false); - $this->addValidator(LinkingLogicalPhysicalStructureValidator::class, "Specifications for the physical document structure", false); - $this->addValidator(DigitalRepresentationValidator::class, "Specifications for the physical document structure", false); - $this->addValidator(DescriptiveMetadataValidator::class, "Descriptive metadata", false); - $this->addValidator(AdministrativeMetadataValidator::class, "Administrative metadata", false); - $this->addValidator(DvMetadataValidator::class, "DFG-Viewer specific informations", false); + $this->addValidator(LogicalStructureValidator::class, "Validation of the logical document structure", false); + $this->addValidator(PhysicalStructureValidator::class, "Validation of the physical document structure", false); + $this->addValidator(LinkingLogicalPhysicalStructureValidator::class, "Validation of linking between logical and physical structure", false); + $this->addValidator(DigitalRepresentationValidator::class, "Validation of the digital representation", false); + $this->addValidator(DescriptiveMetadataValidator::class, "Validation of the descriptive metadata", false); + $this->addValidator(AdministrativeMetadataValidator::class, "Validation of the administrative metadata", false); + $this->addValidator(DvMetadataValidator::class, "Validation of the DFG-Viewer specific details", false); } } From 559cbc687ecf1f072ceafccf3a5215f49d2fc1f3 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Tue, 7 Jan 2025 15:38:37 +0100 Subject: [PATCH 25/43] Add alias for validation helper and add configuration to typoscript --- Classes/Common/ValidationHelper.php | 11 ++ .../AbstactDomDocumentValidator.php | 60 +++++++ Classes/Validation/DOMDocumentValidator.php | 39 ----- ...Validator.php => DomNodeListValidator.php} | 33 +++- ...NodeValidator.php => DomNodeValidator.php} | 41 ++++- Classes/Validation/DvMetadataValidator.php | 2 +- .../Mets/AdministrativeMetadataValidator.php | 4 +- .../Mets/DescriptiveMetadataValidator.php | 4 +- .../Mets/DigitalRepresentationValidator.php | 4 +- ...nkingLogicalPhysicalStructureValidator.php | 4 +- .../Mets/LogicalStructureValidator.php | 4 +- .../Mets/PhysicalStructureValidator.php | 4 +- .../TypoScript/Plugins/kitodo.typoscript | 32 ++++ ...p => AbstractDomDocumentValidatorTest.php} | 19 +-- .../Validation/DvMetadataValidatorTest.php | 152 ----------------- .../DvMetadataValidatorTestAbstract.php | 154 ++++++++++++++++++ .../AdministrativeMetadataValidatorTest.php | 153 ----------------- ...istrativeMetadataValidatorTestAbstract.php | 154 ++++++++++++++++++ ...criptiveMetadataValidatorTestAbstract.php} | 28 ++-- .../DigitalRepresentationValidatorTest.php | 115 ------------- ...talRepresentationValidatorTestAbstract.php | 116 +++++++++++++ ...hysicalStructureValidatorTestAbstract.php} | 21 +-- ...LogicalStructureValidatorTestAbstract.php} | 38 ++--- ...hysicalStructureValidatorTestAbstract.php} | 31 ++-- 24 files changed, 663 insertions(+), 560 deletions(-) create mode 100644 Classes/Validation/AbstactDomDocumentValidator.php delete mode 100644 Classes/Validation/DOMDocumentValidator.php rename Classes/Validation/{DOMNodeListValidator.php => DomNodeListValidator.php} (61%) rename Classes/Validation/{DOMNodeValidator.php => DomNodeValidator.php} (77%) rename Tests/Unit/Validation/{ApplicationProfileValidatorTest.php => AbstractDomDocumentValidatorTest.php} (95%) delete mode 100644 Tests/Unit/Validation/DvMetadataValidatorTest.php create mode 100644 Tests/Unit/Validation/DvMetadataValidatorTestAbstract.php delete mode 100644 Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php create mode 100644 Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTestAbstract.php rename Tests/Unit/Validation/Mets/{DescriptiveMetadataValidatorTest.php => DescriptiveMetadataValidatorTestAbstract.php} (54%) delete mode 100644 Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php create mode 100644 Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTestAbstract.php rename Tests/Unit/Validation/Mets/{LinkingLogicalPhysicalStructureValidatorTest.php => LinkingLogicalPhysicalStructureValidatorTestAbstract.php} (59%) rename Tests/Unit/Validation/Mets/{LogicalStructureValidatorTest.php => LogicalStructureValidatorTestAbstract.php} (61%) rename Tests/Unit/Validation/Mets/{PhysicalStructureValidatorTest.php => PhysicalStructureValidatorTestAbstract.php} (67%) diff --git a/Classes/Common/ValidationHelper.php b/Classes/Common/ValidationHelper.php index 9b1d98889..38c3481b0 100644 --- a/Classes/Common/ValidationHelper.php +++ b/Classes/Common/ValidationHelper.php @@ -26,6 +26,10 @@ */ class ValidationHelper { + const NAMESPACE_DV = 'http://dfg-viewer.de/'; + + const NAMESPACE_METS = 'http://www.loc.gov/METS/'; + const STRUCTURE_DATASET = array( 'section', 'file', 'album', 'register', 'annotation', 'address', 'article', 'atlas', 'issue', 'bachelor_thesis', 'volume', 'contained_work', 'additional', 'report', 'official_notification', 'provenance', 'inventory', 'image', 'collation', 'ornament', 'letter', 'cover', 'cover_front', 'cover_back', 'diploma_thesis', 'doctoral_thesis', 'document', 'printers_mark', 'printed_archives', 'binding', 'entry', 'corrigenda', 'bookplate', 'fascicle', 'leaflet', 'research_paper', 'photograph', 'fragment', 'land_register', 'ground_plan', 'habilitation_thesis', 'manuscript', 'illustration', 'imprint', 'contents', 'initial_decoration', 'year', 'chapter', 'map', 'cartulary', 'colophon', 'ephemera', 'engraved_titlepage', 'magister_thesis', 'folder', 'master_thesis', 'multivolume_work', 'month', 'monograph', 'musical_notation', 'periodical', 'poster', 'plan', 'privileges', 'index', 'spine', 'scheme', 'edge', 'seal', 'paste down', 'stamp', 'study', 'table', 'day', 'proceeding', 'text', 'title_page', 'subinventory', 'act', 'judgement', 'verse', 'note', 'preprint', 'dossier', 'lecture', 'endsheet', 'paper', 'preface', 'dedication', 'newspaper' ); @@ -68,4 +72,11 @@ class ValidationHelper const XPATH_DVLINKS = self::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap[@MDTYPE="OTHER" and @OTHERMDTYPE="DVLINKS"]/mets:xmlData/dv:links'; + public static function trimDoubleSlash(string $value): string + { + if(str_starts_with($value, '//')) { + return substr($value, 1); + } + return $value; + } } diff --git a/Classes/Validation/AbstactDomDocumentValidator.php b/Classes/Validation/AbstactDomDocumentValidator.php new file mode 100644 index 000000000..45583c099 --- /dev/null +++ b/Classes/Validation/AbstactDomDocumentValidator.php @@ -0,0 +1,60 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use DOMDocument; +use DOMNode; +use DOMXPath; +use Kitodo\Dlf\Validation\AbstractDlfValidator; + +abstract class AbstactDomDocumentValidator extends AbstractDlfValidator +{ + protected DOMXpath $xpath; + + public function __construct() + { + parent::__construct(DOMDocument::class); + } + + protected function isValid($value): void + { + $this->xpath = new DOMXPath($value); + $this->isValidDocument(); + } + + protected function createNodeListValidator(string $expression, ?DOMNode $contextNode = null): DomNodeListValidator + { + return new DomNodeListValidator($this->xpath, $this->result, $expression, $contextNode); + } + + protected function createNodeValidator(?DOMNode $node): DomNodeValidator + { + return new DomNodeValidator($this->xpath, $this->result, $node); + } + + protected abstract function isValidDocument(); + +} diff --git a/Classes/Validation/DOMDocumentValidator.php b/Classes/Validation/DOMDocumentValidator.php deleted file mode 100644 index 374aad85a..000000000 --- a/Classes/Validation/DOMDocumentValidator.php +++ /dev/null @@ -1,39 +0,0 @@ -xpath = new DOMXPath($value); - $this->isValidDocument(); - } - - protected function createNodeListValidator(string $expression, ?DOMNode $contextNode = null): DOMNodeListValidator - { - return new DOMNodeListValidator($this->xpath, $this->result, $expression, $contextNode); - } - - protected function createNodeValidator(?DOMNode $node): DOMNodeValidator - { - return new DOMNodeValidator($this->xpath, $this->result, $node); - } - - protected abstract function isValidDocument(); - - - -} diff --git a/Classes/Validation/DOMNodeListValidator.php b/Classes/Validation/DomNodeListValidator.php similarity index 61% rename from Classes/Validation/DOMNodeListValidator.php rename to Classes/Validation/DomNodeListValidator.php index 43fb59d43..520c308ca 100644 --- a/Classes/Validation/DOMNodeListValidator.php +++ b/Classes/Validation/DomNodeListValidator.php @@ -2,13 +2,36 @@ namespace Slub\Dfgviewer\Validation; +/** + * Copyright notice + * + * (c) Saxon State and University Library Dresden + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + use DOMXPath; use DOMNode; use DOMNodeList; use TYPO3\CMS\Extbase\Error\Error; use TYPO3\CMS\Extbase\Error\Result; -class DOMNodeListValidator +class DomNodeListValidator { private string $expression; @@ -26,7 +49,7 @@ public function __construct(DOMXPath $xpath, Result $result, string $expression, $this->result = $result; } - public function iterate(callable $callback): DOMNodeListValidator + public function iterate(callable $callback): DomNodeListValidator { foreach ($this->nodeList as $node) { call_user_func_array($callback, array($node)); @@ -44,7 +67,7 @@ public function getNode(int $index): ?DOMNode return $this->nodeList->item($index); } - public function validateHasAny(): DOMNodeListValidator + public function validateHasAny(): DomNodeListValidator { if (!$this->nodeList->length > 0) { $this->addError('There must be at least one element'); @@ -52,7 +75,7 @@ public function validateHasAny(): DOMNodeListValidator return $this; } - public function validateHasOne(): DOMNodeListValidator + public function validateHasOne(): DomNodeListValidator { if ($this->nodeList->length != 1) { $this->addError('There must be an element'); @@ -60,7 +83,7 @@ public function validateHasOne(): DOMNodeListValidator return $this; } - public function validateHasNoneOrOne(): DOMNodeListValidator + public function validateHasNoneOrOne(): DomNodeListValidator { if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { $this->addError('There must be no more than one element'); diff --git a/Classes/Validation/DOMNodeValidator.php b/Classes/Validation/DomNodeValidator.php similarity index 77% rename from Classes/Validation/DOMNodeValidator.php rename to Classes/Validation/DomNodeValidator.php index 45af9c9a9..b96c8fcfe 100644 --- a/Classes/Validation/DOMNodeValidator.php +++ b/Classes/Validation/DomNodeValidator.php @@ -2,12 +2,35 @@ namespace Slub\Dfgviewer\Validation; +/** + * Copyright notice + * + * (c) Saxon State and University Library Dresden + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + use DOMNode; use DOMXPath; use TYPO3\CMS\Extbase\Error\Error; use TYPO3\CMS\Extbase\Error\Result; -class DOMNodeValidator +class DomNodeValidator { protected DOMXPath $xpath; @@ -18,7 +41,7 @@ public function __construct(DOMXPath $xpath, Result $result, ?DOMNode $node) $this->node = $node; } - public function validateHasContentWithEmail(): DOMNodeValidator + public function validateHasContentWithEmail(): DomNodeValidator { if (!isset($this->node) || !$this->node->nodeValue) { return $this; @@ -37,7 +60,7 @@ public function validateHasContentWithEmail(): DOMNodeValidator return $this; } - public function validateHasContentWithUrl(): DOMNodeValidator + public function validateHasContentWithUrl(): DomNodeValidator { if (!isset($this->node) || !$this->node->nodeValue) { return $this; @@ -50,7 +73,7 @@ public function validateHasContentWithUrl(): DOMNodeValidator return $this; } - public function validateHasAttributeWithUrl(string $name): DOMNodeValidator + public function validateHasAttributeWithUrl(string $name): DomNodeValidator { if (!isset($this->node)) { return $this; @@ -68,7 +91,7 @@ public function validateHasAttributeWithUrl(string $name): DOMNodeValidator return $this; } - public function validateHasAttributeWithValue(string $name, array $values): DOMNodeValidator + public function validateHasAttributeWithValue(string $name, array $values): DomNodeValidator { if (!isset($this->node)) { return $this; @@ -86,7 +109,7 @@ public function validateHasAttributeWithValue(string $name, array $values): DOMN return $this; } - public function validateHasUniqueAttribute(string $name, string $contextExpression): DOMNodeValidator + public function validateHasUniqueAttribute(string $name, string $contextExpression): DomNodeValidator { if (!isset($this->node)) { return $this; @@ -104,13 +127,13 @@ public function validateHasUniqueAttribute(string $name, string $contextExpressi return $this; } - public function validateHasUniqueId(): DOMNodeValidator + public function validateHasUniqueId(): DomNodeValidator { $this->validateHasUniqueAttribute("ID", "//*"); return $this; } - public function validateHasAttribute(string $name): DOMNodeValidator + public function validateHasAttribute(string $name): DomNodeValidator { if (!isset($this->node)) { return $this; @@ -122,7 +145,7 @@ public function validateHasAttribute(string $name): DOMNodeValidator return $this; } - public function validateHasReferenceToId(string $name, string $targetContextExpression): DOMNodeValidator + public function validateHasReferenceToId(string $name, string $targetContextExpression): DomNodeValidator { if (!isset($this->node)) { return $this; diff --git a/Classes/Validation/DvMetadataValidator.php b/Classes/Validation/DvMetadataValidator.php index 4b33d4ae2..aa18b667f 100644 --- a/Classes/Validation/DvMetadataValidator.php +++ b/Classes/Validation/DvMetadataValidator.php @@ -35,7 +35,7 @@ * * @access public */ -class DvMetadataValidator extends DOMDocumentValidator +class DvMetadataValidator extends AbstactDomDocumentValidator { protected function isValidDocument(): void { diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index 2e1b36134..cef8b1da9 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -3,7 +3,7 @@ namespace Slub\Dfgviewer\Validation\Mets; use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\DOMDocumentValidator; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; /** * Copyright notice @@ -36,7 +36,7 @@ * * @access public */ -class AdministrativeMetadataValidator extends DOMDocumentValidator +class AdministrativeMetadataValidator extends AbstactDomDocumentValidator { public function isValidDocument(): void { diff --git a/Classes/Validation/Mets/DescriptiveMetadataValidator.php b/Classes/Validation/Mets/DescriptiveMetadataValidator.php index e3ce6248d..47e3e430b 100644 --- a/Classes/Validation/Mets/DescriptiveMetadataValidator.php +++ b/Classes/Validation/Mets/DescriptiveMetadataValidator.php @@ -3,7 +3,7 @@ namespace Slub\Dfgviewer\Validation\Mets; use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\DOMDocumentValidator; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; /** * Copyright notice @@ -36,7 +36,7 @@ * * @access public */ -class DescriptiveMetadataValidator extends DOMDocumentValidator +class DescriptiveMetadataValidator extends AbstactDomDocumentValidator { public function isValidDocument(): void { diff --git a/Classes/Validation/Mets/DigitalRepresentationValidator.php b/Classes/Validation/Mets/DigitalRepresentationValidator.php index ec070fdb8..74cdd2541 100644 --- a/Classes/Validation/Mets/DigitalRepresentationValidator.php +++ b/Classes/Validation/Mets/DigitalRepresentationValidator.php @@ -3,7 +3,7 @@ namespace Slub\Dfgviewer\Validation\Mets; use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\DOMDocumentValidator; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; /** * Copyright notice @@ -36,7 +36,7 @@ * * @access public */ -class DigitalRepresentationValidator extends DOMDocumentValidator +class DigitalRepresentationValidator extends AbstactDomDocumentValidator { public function isValidDocument(): void { diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index b39cc6e02..07b6c482c 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -26,7 +26,7 @@ */ use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\DOMDocumentValidator; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; /** * The validator validates against the rules outlined in chapter 2.3 of the METS application profile 2.3.1. @@ -36,7 +36,7 @@ * * @access public */ -class LinkingLogicalPhysicalStructureValidator extends DOMDocumentValidator +class LinkingLogicalPhysicalStructureValidator extends AbstactDomDocumentValidator { public function isValidDocument(): void { diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index a5db43103..fd1fca8a0 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -3,7 +3,7 @@ namespace Slub\Dfgviewer\Validation\Mets; use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\DOMDocumentValidator; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; /** * Copyright notice @@ -36,7 +36,7 @@ * * @access public */ -class LogicalStructureValidator extends DOMDocumentValidator +class LogicalStructureValidator extends AbstactDomDocumentValidator { public function isValidDocument(): void { diff --git a/Classes/Validation/Mets/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php index f07c2641f..7ccc263ff 100644 --- a/Classes/Validation/Mets/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -3,7 +3,7 @@ namespace Slub\Dfgviewer\Validation\Mets; use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\DOMDocumentValidator; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; /** * Copyright notice @@ -36,7 +36,7 @@ * * @access public */ -class PhysicalStructureValidator extends DOMDocumentValidator +class PhysicalStructureValidator extends AbstactDomDocumentValidator { diff --git a/Configuration/TypoScript/Plugins/kitodo.typoscript b/Configuration/TypoScript/Plugins/kitodo.typoscript index bf2b3cf0a..345c13ed9 100644 --- a/Configuration/TypoScript/Plugins/kitodo.typoscript +++ b/Configuration/TypoScript/Plugins/kitodo.typoscript @@ -28,6 +28,38 @@ plugin.tx_dlf { } settings { storagePid = {$plugin.tx_dlf.persistence.storagePid} + domDocumentValidationValidators { + 10 { + title = XML-Schemes Validator + className = Kitodo\Dlf\Validation\XmlSchemesValidator + breakOnError = false + configuration { + oai { + namespace = http://www.openarchives.org/OAI/2.0/ + schemaLocation = https://www.openarchives.org/OAI/2.0/OAI-PMH.xsd + } + + mets { + namespace = http://www.loc.gov/METS/ + schemaLocation = http://www.loc.gov/standards/mets/mets.xsd + } + + mods { + namespace = http://www.loc.gov/mods/v3 + schemaLocation = http://www.loc.gov/standards/mods/mods.xsd + } + + dfgviewer { + namespace = http://dfg-viewer.de/ + schemaLocation = /var/www/html/public/typo3conf/ext/dfgviewer/Resources/Public/Xsd/dfg-viewer.xsd + } + } + } + 20 { + title = METS Application Profile Validation + className = Slub\Dfgviewer\Validation\MetsApplicationProfileValidationStack + } + } } view { partialRootPaths { diff --git a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php similarity index 95% rename from Tests/Unit/Validation/ApplicationProfileValidatorTest.php rename to Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php index 206529ced..70e59c099 100644 --- a/Tests/Unit/Validation/ApplicationProfileValidatorTest.php +++ b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php @@ -32,12 +32,8 @@ use TYPO3\CMS\Extbase\Error\Result; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; -abstract class ApplicationProfileValidatorTest extends UnitTestCase +abstract class AbstractDomDocumentValidatorTest extends UnitTestCase { - const NAMESPACE_METS = 'http://www.loc.gov/METS/'; - - const NAMESPACE_DV = 'http://dfg-viewer.de/'; - protected $validator; protected $doc; @@ -65,27 +61,19 @@ public function testDocument() /** * Validates using validator and DOMDocument * - * @return mixed|Result + * @return Result */ public function validate(): Result { return $this->validator->validate($this->doc); } - public static function trimDoubleSlash(string $value): string - { - if(str_starts_with($value, '//')) { - return substr($value, 1); - } - return $value; - } - /** * Validates using validator and DOMDocument and assert result error message for equality. * * Validates using a validator and DOMDocument, then asserts that the resulting error message matches the expected value. * - * @param $message + * @param $message string * @return void */ public function validateAndAssertEquals(string $message): void @@ -188,7 +176,6 @@ protected function setContentValue(string $expression, string $value): void } } - protected function getDOMDocument(): DOMDocument { $doc = new DOMDocument(); diff --git a/Tests/Unit/Validation/DvMetadataValidatorTest.php b/Tests/Unit/Validation/DvMetadataValidatorTest.php deleted file mode 100644 index 121d10638..000000000 --- a/Tests/Unit/Validation/DvMetadataValidatorTest.php +++ /dev/null @@ -1,152 +0,0 @@ - - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * - * This script is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - */ - -use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\DvMetadataValidator; - -class DvMetadataValidatorTest extends ApplicationProfileValidatorTest -{ - /** - * Test validation against the rules of chapter "2.7.1 Rechteangaben – dv:rights" - * - * @return void - */ - public function testDvRights(): void - { - $this->removeNodes(ValidationHelper::XPATH_DVRIGHTS); - $this->assertErrorHasOne(ValidationHelper::XPATH_DVRIGHTS); - } - - /** - * Test validation against the rules of chapter "2.7.2 Unterelemente zu dv:rights" - * - * @return void - */ - public function testDvRightsSubelements(): void - { - $this->removeNodes(ValidationHelper::XPATH_DVRIGHTS . '/dv:owner'); - $this->assertErrorHasOne(ValidationHelper::XPATH_DVRIGHTS . '/dv:owner'); - $this->resetDocument(); - - $this->assertNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerLogo', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerLogo'); - $this->assertNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerSiteURL', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerSiteURL'); - $this->assertNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerContact', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact'); - $this->setContentValue(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerContact', 'mailto:Test'); - $this->assertErrorHasContentWithEmail($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact', 'mailto:Test'); - $this->resetDocument(); - - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVRIGHTS, self::NAMESPACE_DV, 'dv:aggregator'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregator'); - $this->resetDocument(); - $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:aggregatorLogo', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorLogo'); - $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:aggregatorSiteURL', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorSiteURL'); - - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVRIGHTS, self::NAMESPACE_DV, 'dv:sponsor'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsor'); - $this->resetDocument(); - $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:sponsorLogo', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorLogo'); - $this->assertOptionalNodeContent(ValidationHelper::XPATH_DVRIGHTS, 'dv:sponsorSiteURL', $this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorSiteURL'); - - $this->setContentValue(ValidationHelper::XPATH_DVRIGHTS . '/dv:license', 'Test'); - $this->assertErrorHasContentWithUrl($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:license', 'Test'); - } - - /** - * Test validation against the rules of chapter "2.7.3 Verweise – dv:links" - * - * @return void - */ - public function testDvLinks(): void - { - $this->removeNodes(ValidationHelper::XPATH_DVLINKS); - $this->assertErrorHasOne(ValidationHelper::XPATH_DVLINKS); - } - - /** - * Test validation against the rules of chapter "2.7.4 Unterelemente zu dv:links" - * - * @return void - */ - public function testDvLinksSubelements(): void - { - $this->removeNodes(ValidationHelper::XPATH_DVLINKS . '/dv:reference'); - $this->assertErrorHasAny(ValidationHelper::XPATH_DVLINKS . '/dv:reference'); - $this->resetDocument(); - - // if there are multiple `dv:references`, the `linktext` attribute must be present. - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:reference'); - $this->assertErrorHasAttribute($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:reference[1]', 'linktext'); - $this->resetDocument(); - - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:presentation'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVLINKS . '/dv:presentation'); - $this->resetDocument(); - - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:sru'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVLINKS . '/dv:sru'); - $this->resetDocument(); - - $this->setContentValue(ValidationHelper::XPATH_DVLINKS . '/dv:sru', 'Test'); - $this->assertErrorHasContentWithUrl($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:sru', 'Test'); - $this->resetDocument(); - - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_DVLINKS, self::NAMESPACE_DV, 'dv:iiif'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_DVLINKS . '/dv:iiif'); - $this->resetDocument(); - - $this->setContentValue(ValidationHelper::XPATH_DVLINKS . '/dv:iiif', 'Test'); - $this->assertErrorHasContentWithUrl($this->trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:iiif', 'Test'); - } - - protected function assertNodeContent(string $expression, string $expectedErrorExpression): void - { - $this->removeNodes($expression); - $this->assertErrorHasOne($expression); - $this->resetDocument(); - - $this->setContentValue($expression, 'Test'); - $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); - $this->resetDocument(); - } - - protected function assertOptionalNodeContent(string $expression, string $name, string $expectedErrorExpression): void - { - $this->addChildNodeWithNamespace($expression, self::NAMESPACE_DV, $name); - $this->assertErrorHasNoneOrOne($expression . '/' . $name); - $this->resetDocument(); - - $this->setContentValue($expression . '/' . $name, 'Test'); - $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); - $this->resetDocument(); - } - - protected function createValidator(): AbstractDlfValidator - { - return new DvMetadataValidator(); - } -} diff --git a/Tests/Unit/Validation/DvMetadataValidatorTestAbstract.php b/Tests/Unit/Validation/DvMetadataValidatorTestAbstract.php new file mode 100644 index 000000000..0fe19d91e --- /dev/null +++ b/Tests/Unit/Validation/DvMetadataValidatorTestAbstract.php @@ -0,0 +1,154 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\DvMetadataValidator; + +class DvMetadataValidatorTestAbstract extends AbstractDomDocumentValidatorTest +{ + /** + * Test validation against the rules of chapter "2.7.1 Rechteangaben – dv:rights" + * + * @return void + */ + public function testDvRights(): void + { + $this->removeNodes(VH::XPATH_DVRIGHTS); + $this->assertErrorHasOne(VH::XPATH_DVRIGHTS); + } + + /** + * Test validation against the rules of chapter "2.7.2 Unterelemente zu dv:rights" + * + * @return void + * @throws \DOMException + */ + public function testDvRightsSubelements(): void + { + $this->removeNodes(VH::XPATH_DVRIGHTS . '/dv:owner'); + $this->assertErrorHasOne(VH::XPATH_DVRIGHTS . '/dv:owner'); + $this->resetDocument(); + + $this->assertNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerLogo', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerLogo'); + $this->assertNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerSiteURL', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerSiteURL'); + $this->assertNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerContact', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact'); + $this->setContentValue(VH::XPATH_DVRIGHTS . '/dv:ownerContact', 'mailto:Test'); + $this->assertErrorHasContentWithEmail(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact', 'mailto:Test'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(VH::XPATH_DVRIGHTS, VH::NAMESPACE_DV, 'dv:aggregator'); + $this->assertErrorHasNoneOrOne(VH::XPATH_DVRIGHTS . '/dv:aggregator'); + $this->resetDocument(); + $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:aggregatorLogo', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorLogo'); + $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:aggregatorSiteURL', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorSiteURL'); + + $this->addChildNodeWithNamespace(VH::XPATH_DVRIGHTS, VH::NAMESPACE_DV, 'dv:sponsor'); + $this->assertErrorHasNoneOrOne(VH::XPATH_DVRIGHTS . '/dv:sponsor'); + $this->resetDocument(); + $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:sponsorLogo', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorLogo'); + $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:sponsorSiteURL', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorSiteURL'); + + $this->setContentValue(VH::XPATH_DVRIGHTS . '/dv:license', 'Test'); + $this->assertErrorHasContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:license', 'Test'); + } + + /** + * Test validation against the rules of chapter "2.7.3 Verweise – dv:links" + * + * @return void + */ + public function testDvLinks(): void + { + $this->removeNodes(VH::XPATH_DVLINKS); + $this->assertErrorHasOne(VH::XPATH_DVLINKS); + } + + /** + * Test validation against the rules of chapter "2.7.4 Unterelemente zu dv:links" + * + * @return void + * @throws \DOMException + */ + public function testDvLinksSubelements(): void + { + $this->removeNodes(VH::XPATH_DVLINKS . '/dv:reference'); + $this->assertErrorHasAny(VH::XPATH_DVLINKS . '/dv:reference'); + $this->resetDocument(); + + // if there are multiple `dv:references`, the `linktext` attribute must be present. + $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:reference'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:reference[1]', 'linktext'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:presentation'); + $this->assertErrorHasNoneOrOne(VH::XPATH_DVLINKS . '/dv:presentation'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:sru'); + $this->assertErrorHasNoneOrOne(VH::XPATH_DVLINKS . '/dv:sru'); + $this->resetDocument(); + + $this->setContentValue(VH::XPATH_DVLINKS . '/dv:sru', 'Test'); + $this->assertErrorHasContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:sru', 'Test'); + $this->resetDocument(); + + $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:iiif'); + $this->assertErrorHasNoneOrOne(VH::XPATH_DVLINKS . '/dv:iiif'); + $this->resetDocument(); + + $this->setContentValue(VH::XPATH_DVLINKS . '/dv:iiif', 'Test'); + $this->assertErrorHasContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:iiif', 'Test'); + } + + protected function assertNodeContent(string $expression, string $expectedErrorExpression): void + { + $this->removeNodes($expression); + $this->assertErrorHasOne($expression); + $this->resetDocument(); + + $this->setContentValue($expression, 'Test'); + $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); + $this->resetDocument(); + } + + protected function assertOptionalNodeContent(string $expression, string $name, string $expectedErrorExpression): void + { + $this->addChildNodeWithNamespace($expression, VH::NAMESPACE_DV, $name); + $this->assertErrorHasNoneOrOne($expression . '/' . $name); + $this->resetDocument(); + + $this->setContentValue($expression . '/' . $name, 'Test'); + $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); + $this->resetDocument(); + } + + protected function createValidator(): AbstractDlfValidator + { + return new DvMetadataValidator(); + } +} diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php deleted file mode 100644 index ac68c6313..000000000 --- a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php +++ /dev/null @@ -1,153 +0,0 @@ - - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * - * This script is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - */ - -use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; - -class AdministrativeMetadataValidatorTest extends ApplicationProfileValidatorTest -{ - /** - * Test validation against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" - * - * @return void - */ - public function testAdministrativeMetadata(): void - { - $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA); - $this->assertErrorHasAny(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'); - $this->assertErrorHasOne(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]'); - $this->resetDocument(); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA), 'DMDLOG_0001'); - - $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, 'ID'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA), 'ID'); - } - - /** - * Test validation against the rules of chapters "2.6.2.5 Herstellung – mets:digiprovMD" and "2.6.2.6 Eingebettete Verweise – mets:digiprovMD/mets:mdWrap" - * - * @return void - */ - public function testDigitalProvenanceMetadataStructure(): void - { - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA), 'DMDLOG_0001'); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA)); - $this->resetDocument(); - - $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->resetDocument(); - - $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap/mets:xmlData/dv:links'); - $this->assertErrorHasOne('mets:xmlData[dv:links]', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap'); - } - - - /** - * Test validation against the rules of chapters "2.6.2.4 Rechtedeklaration – mets:rightsMD" and "2.6.2.4 Eingebettete Rechteangaben – mets:rightsMD/mets:mdWrap" - * - * @return void - */ - public function testRightsMetadataStructure(): void - { - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA), 'DMDLOG_0001'); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA)); - $this->resetDocument(); - - $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->resetDocument(); - - $this->removeAttribute(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap/mets:xmlData/dv:rights'); - $this->assertErrorHasOne('mets:xmlData[dv:rights]', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap'); - } - - /** - * Test validation against the rules of chapters "2.6.2.1 Technische Metadaten – mets:techMD" and "2.6.2.2 Eingebettete technische Daten – mets:techMD/mets:mdWrap" - * - * @return void - */ - public function testTechnicalMetadataStructure(): void - { - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA, self::NAMESPACE_METS, 'mets:techMD'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'ID'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'DMDLOG_0001'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'TECH_0001'); - $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA)); - - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, self::NAMESPACE_METS, 'mets:mdWrap'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'MDTYPE'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'MDTYPE', ''); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); - - $this->setAttributeValue(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', ''); - $this->assertErrorHasOne('mets:xmlData', self::trimDoubleSlash(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap'); - } - - protected function createValidator(): AbstractDlfValidator - { - return new AdministrativeMetadataValidator(); - } -} diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTestAbstract.php new file mode 100644 index 000000000..8b5737194 --- /dev/null +++ b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTestAbstract.php @@ -0,0 +1,154 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; + +class AdministrativeMetadataValidatorTestAbstract extends AbstractDomDocumentValidatorTest +{ + /** + * Test validation against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" + * + * @return void + */ + public function testAdministrativeMetadata(): void + { + $this->removeNodes(VH::XPATH_ADMINISTRATIVE_METADATA); + $this->assertErrorHasAny(VH::XPATH_ADMINISTRATIVE_METADATA); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'); + $this->assertErrorHasOne(VH::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]'); + $this->resetDocument(); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_METADATA), 'DMDLOG_0001'); + + $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_METADATA, 'ID'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_METADATA), 'ID'); + } + + /** + * Test validation against the rules of chapters "2.6.2.5 Herstellung – mets:digiprovMD" and "2.6.2.6 Eingebettete Verweise – mets:digiprovMD/mets:mdWrap" + * + * @return void + */ + public function testDigitalProvenanceMetadataStructure(): void + { + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA), 'DMDLOG_0001'); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA)); + $this->resetDocument(); + + $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap/mets:xmlData/dv:links'); + $this->assertErrorHasOne('mets:xmlData[dv:links]', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap'); + } + + + /** + * Test validation against the rules of chapters "2.6.2.4 Rechtedeklaration – mets:rightsMD" and "2.6.2.4 Eingebettete Rechteangaben – mets:rightsMD/mets:mdWrap" + * + * @return void + */ + public function testRightsMetadataStructure(): void + { + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA), 'DMDLOG_0001'); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA)); + $this->resetDocument(); + + $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap/mets:xmlData/dv:rights'); + $this->assertErrorHasOne('mets:xmlData[dv:rights]', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap'); + } + + /** + * Test validation against the rules of chapters "2.6.2.1 Technische Metadaten – mets:techMD" and "2.6.2.2 Eingebettete technische Daten – mets:techMD/mets:mdWrap" + * + * @return void + * @throws \DOMException + */ + public function testTechnicalMetadataStructure(): void + { + $this->addChildNodeWithNamespace(VH::XPATH_ADMINISTRATIVE_METADATA, VH::NAMESPACE_METS, 'mets:techMD'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'ID'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'DMDLOG_0001'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'TECH_0001'); + $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA)); + + $this->addChildNodeWithNamespace(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, VH::NAMESPACE_METS, 'mets:mdWrap'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'MDTYPE'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'MDTYPE', ''); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); + + $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', ''); + $this->assertErrorHasOne('mets:xmlData', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap'); + } + + protected function createValidator(): AbstractDlfValidator + { + return new AdministrativeMetadataValidator(); + } +} diff --git a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTestAbstract.php similarity index 54% rename from Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php rename to Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTestAbstract.php index aca94b8d3..797836b92 100644 --- a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTestAbstract.php @@ -26,10 +26,10 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\DescriptiveMetadataValidator; -class DescriptiveMetadataValidatorTest extends ApplicationProfileValidatorTest +class DescriptiveMetadataValidatorTestAbstract extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" @@ -38,16 +38,16 @@ class DescriptiveMetadataValidatorTest extends ApplicationProfileValidatorTest */ public function testDescriptiveMetadata(): void { - $this->removeNodes(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); - $this->assertErrorHasAny(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->removeNodes(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->assertErrorHasAny(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); $this->resetDocument(); - $this->removeNodes(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); - $this->assertErrorHasOne(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->removeNodes(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->assertErrorHasOne(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); - $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'DMDID', 'Test'); - $this->assertErrorHasRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->setAttributeValue(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'DMDID', 'Test'); + $this->assertErrorHasRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); } /** @@ -57,16 +57,16 @@ public function testDescriptiveMetadata(): void */ public function testEmbeddedMetadata(): void { - $this->removeNodes(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', self::trimDoubleSlash(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS)); + $this->removeNodes(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap'); + $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS)); $this->resetDocument(); - $this->setAttributeValue(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->setAttributeValue(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap', 'MDTYPE', 'Test'); $this->resetDocument(); - $this->removeNodes(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap/mets:xmlData/mods:mods'); - $this->assertErrorHasOne('mets:xmlData[mods:mods]', self::trimDoubleSlash(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap'); + $this->removeNodes(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap/mets:xmlData/mods:mods'); + $this->assertErrorHasOne('mets:xmlData[mods:mods]', VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap'); } protected function createValidator(): AbstractDlfValidator diff --git a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php deleted file mode 100644 index cc48f3bec..000000000 --- a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php +++ /dev/null @@ -1,115 +0,0 @@ - - * All rights reserved - * - * This script is part of the TYPO3 project. The TYPO3 project is - * free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * The GNU General Public License can be found at - * http://www.gnu.org/copyleft/gpl.html. - * - * This script is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * This copyright notice MUST APPEAR in all copies of the script! - */ - -use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\Mets\DigitalRepresentationValidator; - -class DigitalRepresentationValidatorTest extends ApplicationProfileValidatorTest -{ - /** - * Test validation against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" - * - * @return void - */ - public function testFileSections(): void - { - $this->addChildNodeWithNamespace('/mets:mets', self::NAMESPACE_METS, 'mets:fileSec'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_FILE_SECTIONS); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_FILE_SECTIONS); - $this->assertErrorHasOne(ValidationHelper::XPATH_FILE_SECTIONS); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_PHYSICAL_STRUCTURES); - $this->removeNodes(ValidationHelper::XPATH_FILE_SECTIONS); - $this->assertNoError(); - } - - /** - * Test validation against the rules of chapter "2.4.2.1 Dateigruppen – mets:fileGrp" - * - * @return void - */ - public function testFileGroups(): void - { - $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_GROUPS); - $this->assertErrorHasAny(ValidationHelper::XPATH_FILE_SECTION_GROUPS); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); - $this->assertErrorHasOne(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); - $this->resetDocument(); - - $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="THUMBS"]', 'USE', 'DEFAULT'); - $this->assertErrorHasUniqueAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]', 'USE', 'DEFAULT'); - } - - /** - * Test validation against the rules of chapter "2.4.2.2 Datei – mets:fileGrp/mets:file" and "2.4.2.3 Dateilink – mets:fileGrp/mets:file/mets:FLocat" - * - * @return void - */ - public function testFiles(): void - { - $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_FILES); - $this->assertErrorHasAny(ValidationHelper::XPATH_FILE_SECTION_FILES); - $this->resetDocument(); - - $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_FILES, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'DMDLOG_0001'); - $this->resetDocument(); - - $this->removeAttribute(ValidationHelper::XPATH_FILE_SECTION_FILES, 'MIMETYPE'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'MIMETYPE'); - $this->resetDocument(); - - $this->removeNodes(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat'); - $this->assertErrorHasOne('mets:FLocat', self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file'); - $this->resetDocument(); - - $this->removeAttribute(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE'); - $this->resetDocument(); - - $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE', 'Test'); - $this->resetDocument(); - - $this->removeAttribute(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href'); - $this->assertErrorHasAttribute(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href'); - - $this->setAttributeValue(ValidationHelper::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href', 'Test'); - $this->assertErrorHasAttributeWithUrl(self::trimDoubleSlash(ValidationHelper::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href', 'Test'); - } - - protected function createValidator(): AbstractDlfValidator - { - return new DigitalRepresentationValidator(); - } -} diff --git a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTestAbstract.php new file mode 100644 index 000000000..d57e0c67e --- /dev/null +++ b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTestAbstract.php @@ -0,0 +1,116 @@ + + * All rights reserved + * + * This script is part of the TYPO3 project. The TYPO3 project is + * free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * The GNU General Public License can be found at + * http://www.gnu.org/copyleft/gpl.html. + * + * This script is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This copyright notice MUST APPEAR in all copies of the script! + */ + +use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\Mets\DigitalRepresentationValidator; + +class DigitalRepresentationValidatorTestAbstract extends AbstractDomDocumentValidatorTest +{ + /** + * Test validation against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" + * + * @return void + * @throws \DOMException + */ + public function testFileSections(): void + { + $this->addChildNodeWithNamespace('/mets:mets', VH::NAMESPACE_METS, 'mets:fileSec'); + $this->assertErrorHasNoneOrOne(VH::XPATH_FILE_SECTIONS); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_FILE_SECTIONS); + $this->assertErrorHasOne(VH::XPATH_FILE_SECTIONS); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_PHYSICAL_STRUCTURES); + $this->removeNodes(VH::XPATH_FILE_SECTIONS); + $this->assertNoError(); + } + + /** + * Test validation against the rules of chapter "2.4.2.1 Dateigruppen – mets:fileGrp" + * + * @return void + */ + public function testFileGroups(): void + { + $this->removeNodes(VH::XPATH_FILE_SECTION_GROUPS); + $this->assertErrorHasAny(VH::XPATH_FILE_SECTION_GROUPS); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); + $this->assertErrorHasOne(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); + $this->resetDocument(); + + $this->setAttributeValue(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="THUMBS"]', 'USE', 'DEFAULT'); + $this->assertErrorHasUniqueAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]', 'USE', 'DEFAULT'); + } + + /** + * Test validation against the rules of chapter "2.4.2.2 Datei – mets:fileGrp/mets:file" and "2.4.2.3 Dateilink – mets:fileGrp/mets:file/mets:FLocat" + * + * @return void + */ + public function testFiles(): void + { + $this->removeNodes(VH::XPATH_FILE_SECTION_FILES); + $this->assertErrorHasAny(VH::XPATH_FILE_SECTION_FILES); + $this->resetDocument(); + + $this->setAttributeValue(VH::XPATH_FILE_SECTION_FILES, 'ID', 'DMDLOG_0001'); + $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'DMDLOG_0001'); + $this->resetDocument(); + + $this->removeAttribute(VH::XPATH_FILE_SECTION_FILES, 'MIMETYPE'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'MIMETYPE'); + $this->resetDocument(); + + $this->removeNodes(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat'); + $this->assertErrorHasOne('mets:FLocat', VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file'); + $this->resetDocument(); + + $this->removeAttribute(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE'); + $this->resetDocument(); + + $this->setAttributeValue(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE', 'Test'); + $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE', 'Test'); + $this->resetDocument(); + + $this->removeAttribute(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href'); + $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href'); + + $this->setAttributeValue(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href', 'Test'); + $this->assertErrorHasAttributeWithUrl(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href', 'Test'); + } + + protected function createValidator(): AbstractDlfValidator + { + return new DigitalRepresentationValidator(); + } +} diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTestAbstract.php similarity index 59% rename from Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php rename to Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTestAbstract.php index 8e0d0ab24..1f26f7377 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTestAbstract.php @@ -26,34 +26,35 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\LinkingLogicalPhysicalStructureValidator; -class LinkingLogicalPhysicalStructureValidatorTest extends ApplicationProfileValidatorTest +class LinkingLogicalPhysicalStructureValidatorTestAbstract extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.3.1 Structure links - mets:structLink" * * @return void + * @throws \DOMException */ public function testMultipleStructLinks(): void { - $this->addChildNodeWithNamespace('/mets:mets', self::NAMESPACE_METS, 'mets:structLink'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_STRUCT_LINK); + $this->addChildNodeWithNamespace('/mets:mets', VH::NAMESPACE_METS, 'mets:structLink'); + $this->assertErrorHasNoneOrOne(VH::XPATH_STRUCT_LINK); } public function testLinkElements(): void { - $this->removeNodes(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS); - $this->assertErrorHasAny(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS); + $this->removeNodes(VH::XPATH_STRUCT_LINK_ELEMENTS); + $this->assertErrorHasAny(VH::XPATH_STRUCT_LINK_ELEMENTS); $this->resetDocument(); - $this->setAttributeValue(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:from', 'Test'); - $this->assertErrorHasRefToOne(self::trimDoubleSlash(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:from', 'Test', ValidationHelper::XPATH_LOGICAL_STRUCTURES); + $this->setAttributeValue(VH::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:from', 'Test'); + $this->assertErrorHasRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:from', 'Test', VH::XPATH_LOGICAL_STRUCTURES); $this->resetDocument(); - $this->setAttributeValue(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:to', 'Test'); - $this->assertErrorHasRefToOne(self::trimDoubleSlash(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:to', 'Test', ValidationHelper::XPATH_PHYSICAL_STRUCTURES); + $this->setAttributeValue(VH::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:to', 'Test'); + $this->assertErrorHasRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:to', 'Test', VH::XPATH_PHYSICAL_STRUCTURES); } protected function createValidator(): AbstractDlfValidator diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTestAbstract.php similarity index 61% rename from Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php rename to Tests/Unit/Validation/Mets/LogicalStructureValidatorTestAbstract.php index aea163172..442881e5e 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTestAbstract.php @@ -26,10 +26,10 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; -class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest +class LogicalStructureValidatorTestAbstract extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.1.1 Logical structure - mets:structMap" @@ -38,8 +38,8 @@ class LogicalStructureValidatorTest extends ApplicationProfileValidatorTest */ public function testNotExistingLogicalStructureElement(): void { - $this->removeNodes(ValidationHelper::XPATH_LOGICAL_STRUCTURES); - $this->assertErrorHasAny(ValidationHelper::XPATH_LOGICAL_STRUCTURES); + $this->removeNodes(VH::XPATH_LOGICAL_STRUCTURES); + $this->assertErrorHasAny(VH::XPATH_LOGICAL_STRUCTURES); } /** @@ -48,24 +48,24 @@ public function testNotExistingLogicalStructureElement(): void */ public function testStructuralElements(): void { - $this->removeNodes(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); - $this->assertErrorHasAny(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->removeNodes(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->assertErrorHasAny(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); - $this->removeAttribute(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'ID'); + $this->removeAttribute(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'ID'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'ID'); $this->resetDocument(); - $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); + $node = $this->doc->createElementNS(VH::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); - $this->addChildNode(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, $node); + $this->addChildNode(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, $node); $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[1]/mets:div', 'LOG_0001'); $this->resetDocument(); - $this->removeAttribute(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->removeAttribute(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'TYPE'); - $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->setAttributeValue(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div', 'TYPE', 'Test'); } @@ -76,24 +76,24 @@ public function testStructuralElements(): void */ public function testExternalReference(): void { - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES); + $this->addChildNodeWithNamespace(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, VH::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeWithNamespace(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, VH::NAMESPACE_METS, 'mets:mptr'); + $this->assertErrorHasNoneOrOne(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES); $this->resetDocument(); - $this->addChildNodeWithNamespace(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, self::NAMESPACE_METS, 'mets:mptr'); + $this->addChildNodeWithNamespace(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, VH::NAMESPACE_METS, 'mets:mptr'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE'); - $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); + $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); - $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); + $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href'); - $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); + $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); $this->assertErrorHasAttributeWithUrl('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href', 'Test'); - $this->setAttributeValue(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); + $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); $result = $this->validate(); self::assertFalse($result->hasErrors()); } diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTestAbstract.php similarity index 67% rename from Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php rename to Tests/Unit/Validation/Mets/PhysicalStructureValidatorTestAbstract.php index 95eac0d17..f5f1f8f22 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTestAbstract.php @@ -26,61 +26,62 @@ */ use Kitodo\Dlf\Validation\AbstractDlfValidator; -use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; -class PhysicalStructureValidatorTest extends ApplicationProfileValidatorTest +class PhysicalStructureValidatorTestAbstract extends AbstractDomDocumentValidatorTest { - /** * Test validation against the rules of chapter "2.2.1 Physical structure - mets:structMap" * * @return void + * @throws \DOMException */ public function testMultiplePhysicalDivisions(): void { - $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:structMap'); + $node = $this->doc->createElementNS(VH::NAMESPACE_METS, 'mets:structMap'); $node->setAttribute('TYPE', 'PHYSICAL'); $this->addChildNode('/mets:mets', $node); - $this->assertErrorHasNoneOrOne(ValidationHelper::XPATH_PHYSICAL_STRUCTURES); + $this->assertErrorHasNoneOrOne(VH::XPATH_PHYSICAL_STRUCTURES); } /** * Test validation against the rules of chapter "2.2.2.1 Structural element - mets:div" * * @return void + * @throws \DOMException */ public function testStructuralElements(): void { - $this->removeNodes(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); - $this->assertErrorHasOne(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); + $this->removeNodes(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); + $this->assertErrorHasOne(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); $this->resetDocument(); - $this->removeAttribute(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); + $this->removeAttribute(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div', 'TYPE'); - $this->setAttributeValue(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); + $this->setAttributeValue(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div', 'TYPE', 'Test'); $this->resetDocument(); - $this->removeNodes(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); - $this->assertErrorHasAny(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); + $this->removeNodes(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); + $this->assertErrorHasAny(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); - $this->removeAttribute(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'ID'); + $this->removeAttribute(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'ID'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'ID'); $this->resetDocument(); - $node = $this->doc->createElementNS(self::NAMESPACE_METS, 'mets:div'); + $node = $this->doc->createElementNS(VH::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'PHYS_0001'); $this->addChildNode('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', $node); $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[2]/mets:div/mets:div[1]', 'PHYS_0001'); $this->resetDocument(); - $this->removeAttribute(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE'); + $this->removeAttribute(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE'); $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE'); - $this->setAttributeValue(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); + $this->setAttributeValue(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE', 'Test'); } From 9a6965dc14ee4c22c554c55b5a773c8ea24c593b Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Wed, 8 Jan 2025 17:34:51 +0100 Subject: [PATCH 26/43] Reafactoring and renamings --- Classes/Validation/AbstactDomDocumentValidator.php | 2 ++ ...tack.php => ApplicationProfileValidationStack.php} | 2 +- Classes/Validation/{ => Dom}/DomNodeListValidator.php | 5 ++--- Classes/Validation/{ => Dom}/DomNodeValidator.php | 2 +- Configuration/TypoScript/Plugins/kitodo.typoscript | 11 ++--------- .../Validation/AbstractDomDocumentValidatorTest.php | 6 +++--- ...orTestAbstract.php => DvMetadataValidatorTest.php} | 2 +- ...ct.php => AdministrativeMetadataValidatorTest.php} | 3 +-- ...tract.php => DescriptiveMetadataValidatorTest.php} | 2 +- ...act.php => DigitalRepresentationValidatorTest.php} | 2 +- ... LinkingLogicalPhysicalStructureValidatorTest.php} | 2 +- ...Abstract.php => LogicalStructureValidatorTest.php} | 2 +- ...bstract.php => PhysicalStructureValidatorTest.php} | 2 +- 13 files changed, 18 insertions(+), 25 deletions(-) rename Classes/Validation/{MetsApplicationProfileValidationStack.php => ApplicationProfileValidationStack.php} (96%) rename Classes/Validation/{ => Dom}/DomNodeListValidator.php (98%) rename Classes/Validation/{ => Dom}/DomNodeValidator.php (99%) rename Tests/Unit/Validation/{DvMetadataValidatorTestAbstract.php => DvMetadataValidatorTest.php} (98%) rename Tests/Unit/Validation/Mets/{AdministrativeMetadataValidatorTestAbstract.php => AdministrativeMetadataValidatorTest.php} (98%) rename Tests/Unit/Validation/Mets/{DescriptiveMetadataValidatorTestAbstract.php => DescriptiveMetadataValidatorTest.php} (97%) rename Tests/Unit/Validation/Mets/{DigitalRepresentationValidatorTestAbstract.php => DigitalRepresentationValidatorTest.php} (98%) rename Tests/Unit/Validation/Mets/{LinkingLogicalPhysicalStructureValidatorTestAbstract.php => LinkingLogicalPhysicalStructureValidatorTest.php} (95%) rename Tests/Unit/Validation/Mets/{LogicalStructureValidatorTestAbstract.php => LogicalStructureValidatorTest.php} (98%) rename Tests/Unit/Validation/Mets/{PhysicalStructureValidatorTestAbstract.php => PhysicalStructureValidatorTest.php} (97%) diff --git a/Classes/Validation/AbstactDomDocumentValidator.php b/Classes/Validation/AbstactDomDocumentValidator.php index 45583c099..c073d390a 100644 --- a/Classes/Validation/AbstactDomDocumentValidator.php +++ b/Classes/Validation/AbstactDomDocumentValidator.php @@ -29,6 +29,8 @@ use DOMNode; use DOMXPath; use Kitodo\Dlf\Validation\AbstractDlfValidator; +use Slub\Dfgviewer\Validation\Dom\DomNodeListValidator; +use Slub\Dfgviewer\Validation\Dom\DomNodeValidator; abstract class AbstactDomDocumentValidator extends AbstractDlfValidator { diff --git a/Classes/Validation/MetsApplicationProfileValidationStack.php b/Classes/Validation/ApplicationProfileValidationStack.php similarity index 96% rename from Classes/Validation/MetsApplicationProfileValidationStack.php rename to Classes/Validation/ApplicationProfileValidationStack.php index ed6e50896..ec30b9981 100644 --- a/Classes/Validation/MetsApplicationProfileValidationStack.php +++ b/Classes/Validation/ApplicationProfileValidationStack.php @@ -35,7 +35,7 @@ use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; -class MetsApplicationProfileValidationStack extends AbstractDlfValidationStack { +class ApplicationProfileValidationStack extends AbstractDlfValidationStack { public function __construct() { parent::__construct(\DOMDocument::class); diff --git a/Classes/Validation/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php similarity index 98% rename from Classes/Validation/DomNodeListValidator.php rename to Classes/Validation/Dom/DomNodeListValidator.php index 520c308ca..744dafc7b 100644 --- a/Classes/Validation/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -1,6 +1,6 @@ result->addError(new Error($message, 23)); } - } diff --git a/Classes/Validation/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php similarity index 99% rename from Classes/Validation/DomNodeValidator.php rename to Classes/Validation/Dom/DomNodeValidator.php index b96c8fcfe..5ccf629c6 100644 --- a/Classes/Validation/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -1,6 +1,6 @@ resetSingletonInstances = true; - $this->doc = $this->getDOMDocument(); + $this->doc = $this->getDomDocument(); $this->validator = $this->createValidator(); } @@ -84,7 +84,7 @@ public function validateAndAssertEquals(string $message): void protected function resetDocument(): void { - $this->doc = $this->getDOMDocument(); + $this->doc = $this->getDomDocument(); } /** @@ -176,7 +176,7 @@ protected function setContentValue(string $expression, string $value): void } } - protected function getDOMDocument(): DOMDocument + protected function getDomDocument(): DOMDocument { $doc = new DOMDocument(); $doc->load(__DIR__ . '/../../Fixtures/mets.xml'); diff --git a/Tests/Unit/Validation/DvMetadataValidatorTestAbstract.php b/Tests/Unit/Validation/DvMetadataValidatorTest.php similarity index 98% rename from Tests/Unit/Validation/DvMetadataValidatorTestAbstract.php rename to Tests/Unit/Validation/DvMetadataValidatorTest.php index 0fe19d91e..680badf95 100644 --- a/Tests/Unit/Validation/DvMetadataValidatorTestAbstract.php +++ b/Tests/Unit/Validation/DvMetadataValidatorTest.php @@ -29,7 +29,7 @@ use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\DvMetadataValidator; -class DvMetadataValidatorTestAbstract extends AbstractDomDocumentValidatorTest +class DvMetadataValidatorTest extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.7.1 Rechteangaben – dv:rights" diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php similarity index 98% rename from Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTestAbstract.php rename to Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php index 8b5737194..594e976ec 100644 --- a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTestAbstract.php +++ b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php @@ -29,7 +29,7 @@ use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\AdministrativeMetadataValidator; -class AdministrativeMetadataValidatorTestAbstract extends AbstractDomDocumentValidatorTest +class AdministrativeMetadataValidatorTest extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" @@ -86,7 +86,6 @@ public function testDigitalProvenanceMetadataStructure(): void $this->assertErrorHasOne('mets:xmlData[dv:links]', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap'); } - /** * Test validation against the rules of chapters "2.6.2.4 Rechtedeklaration – mets:rightsMD" and "2.6.2.4 Eingebettete Rechteangaben – mets:rightsMD/mets:mdWrap" * diff --git a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php similarity index 97% rename from Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTestAbstract.php rename to Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php index 797836b92..911449c1d 100644 --- a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTestAbstract.php +++ b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php @@ -29,7 +29,7 @@ use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\DescriptiveMetadataValidator; -class DescriptiveMetadataValidatorTestAbstract extends AbstractDomDocumentValidatorTest +class DescriptiveMetadataValidatorTest extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" diff --git a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php similarity index 98% rename from Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTestAbstract.php rename to Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php index d57e0c67e..23efc5582 100644 --- a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTestAbstract.php +++ b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php @@ -29,7 +29,7 @@ use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\DigitalRepresentationValidator; -class DigitalRepresentationValidatorTestAbstract extends AbstractDomDocumentValidatorTest +class DigitalRepresentationValidatorTest extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php similarity index 95% rename from Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTestAbstract.php rename to Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index 1f26f7377..086b350e7 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTestAbstract.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -29,7 +29,7 @@ use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\LinkingLogicalPhysicalStructureValidator; -class LinkingLogicalPhysicalStructureValidatorTestAbstract extends AbstractDomDocumentValidatorTest +class LinkingLogicalPhysicalStructureValidatorTest extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.3.1 Structure links - mets:structLink" diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php similarity index 98% rename from Tests/Unit/Validation/Mets/LogicalStructureValidatorTestAbstract.php rename to Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index 442881e5e..78742a893 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTestAbstract.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -29,7 +29,7 @@ use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; -class LogicalStructureValidatorTestAbstract extends AbstractDomDocumentValidatorTest +class LogicalStructureValidatorTest extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.1.1 Logical structure - mets:structMap" diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTestAbstract.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php similarity index 97% rename from Tests/Unit/Validation/Mets/PhysicalStructureValidatorTestAbstract.php rename to Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index f5f1f8f22..d0fc41af9 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTestAbstract.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -29,7 +29,7 @@ use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; -class PhysicalStructureValidatorTestAbstract extends AbstractDomDocumentValidatorTest +class PhysicalStructureValidatorTest extends AbstractDomDocumentValidatorTest { /** * Test validation against the rules of chapter "2.2.1 Physical structure - mets:structMap" From 43a0d24b86f28386851f56da44a67fdca7faa96b Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 12:50:25 +0100 Subject: [PATCH 27/43] Refactoring and documentation --- Classes/Common/ValidationHelper.php | 9 ++ .../Validation/Dom/DomNodeListValidator.php | 52 ++++++-- Classes/Validation/Dom/DomNodeValidator.php | 57 ++++++++- Classes/Validation/DvMetadataValidator.php | 53 ++++---- .../Mets/AdministrativeMetadataValidator.php | 57 +++++---- .../Mets/DescriptiveMetadataValidator.php | 19 +-- .../Mets/DigitalRepresentationValidator.php | 40 ++++--- ...nkingLogicalPhysicalStructureValidator.php | 19 +-- .../Mets/LogicalStructureValidator.php | 34 +++--- .../Mets/PhysicalStructureValidator.php | 23 ++-- .../AbstractDomDocumentValidatorTest.php | 113 ++++++++++++++++-- .../Mets/DescriptiveMetadataValidatorTest.php | 2 +- ...gLogicalPhysicalStructureValidatorTest.php | 4 +- 13 files changed, 356 insertions(+), 126 deletions(-) diff --git a/Classes/Common/ValidationHelper.php b/Classes/Common/ValidationHelper.php index 38c3481b0..84d1eb72e 100644 --- a/Classes/Common/ValidationHelper.php +++ b/Classes/Common/ValidationHelper.php @@ -24,6 +24,15 @@ * * This copyright notice MUST APPEAR in all copies of the script! */ + +/** + * The validator helper contains constants and functions to support the validation process. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ class ValidationHelper { const NAMESPACE_DV = 'http://dfg-viewer.de/'; diff --git a/Classes/Validation/Dom/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php index 744dafc7b..4edc6414a 100644 --- a/Classes/Validation/Dom/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -31,6 +31,14 @@ use TYPO3\CMS\Extbase\Error\Error; use TYPO3\CMS\Extbase\Error\Result; +/** + * The validator contains functions to validate a DOMNodeList. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ class DomNodeListValidator { private string $expression; @@ -49,24 +57,42 @@ public function __construct(DOMXPath $xpath, Result $result, string $expression, $this->result = $result; } - public function iterate(callable $callback): DomNodeListValidator - { - foreach ($this->nodeList as $node) { - call_user_func_array($callback, array($node)); - } - return $this; - } - + /** + * Get the first node from the node list. + * + * @return DOMNode|null + */ public function getFirstNode(): ?DOMNode { return $this->getNode(0); } + /** + * Get a node from the node list at a specific index. + * + * @param int $index The index to retrieve the node + * @return DOMNode|null + */ public function getNode(int $index): ?DOMNode { return $this->nodeList->item($index); } + /** + * Get the node list. + * + * @return DOMNodeList + */ + public function getNodeList(): DOMNodeList + { + return $this->nodeList; + } + + /** + * Validates the node list has any node. + * + * @return $this + */ public function validateHasAny(): DomNodeListValidator { if (!$this->nodeList->length > 0) { @@ -75,6 +101,11 @@ public function validateHasAny(): DomNodeListValidator return $this; } + /** + * Validates the node list has one node. + * + * @return $this + */ public function validateHasOne(): DomNodeListValidator { if ($this->nodeList->length != 1) { @@ -83,6 +114,11 @@ public function validateHasOne(): DomNodeListValidator return $this; } + /** + * Validates the node list has none or one node. + * + * @return $this + */ public function validateHasNoneOrOne(): DomNodeListValidator { if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index 5ccf629c6..82dd634c1 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -30,6 +30,14 @@ use TYPO3\CMS\Extbase\Error\Error; use TYPO3\CMS\Extbase\Error\Result; +/** + * The validator contains functions to validate a DOMNode. + * + * @package TYPO3 + * @subpackage dfg-viewer + * + * @access public + */ class DomNodeValidator { protected DOMXPath $xpath; @@ -41,6 +49,11 @@ public function __construct(DOMXPath $xpath, Result $result, ?DOMNode $node) $this->node = $node; } + /** + * Validate that the node's content contains an Email. + * + * @return $this + */ public function validateHasContentWithEmail(): DomNodeValidator { if (!isset($this->node) || !$this->node->nodeValue) { @@ -60,6 +73,11 @@ public function validateHasContentWithEmail(): DomNodeValidator return $this; } + /** + * Validate that the node's content contains a URL. + * + * @return $this + */ public function validateHasContentWithUrl(): DomNodeValidator { if (!isset($this->node) || !$this->node->nodeValue) { @@ -73,6 +91,12 @@ public function validateHasContentWithUrl(): DomNodeValidator return $this; } + /** + * Validate that the node has an attribute with a URL value. + * + * @param string $name The attribute name + * @return $this + */ public function validateHasAttributeWithUrl(string $name): DomNodeValidator { if (!isset($this->node)) { @@ -91,6 +115,13 @@ public function validateHasAttributeWithUrl(string $name): DomNodeValidator return $this; } + /** + * Validate that the node has an attribute with a specific value. + * + * @param string $name The attribute name + * @param array $values The allowed values + * @return $this + */ public function validateHasAttributeWithValue(string $name, array $values): DomNodeValidator { if (!isset($this->node)) { @@ -109,6 +140,13 @@ public function validateHasAttributeWithValue(string $name, array $values): DomN return $this; } + /** + * Validate that the node has a unique attribute with name. + * + * @param string $name The attribute name + * @param string $contextExpression The context expression to determine uniqueness. + * @return $this + */ public function validateHasUniqueAttribute(string $name, string $contextExpression): DomNodeValidator { if (!isset($this->node)) { @@ -127,12 +165,23 @@ public function validateHasUniqueAttribute(string $name, string $contextExpressi return $this; } + /** + * Validate that the node has a unique identifier. + * + * @return $this + */ public function validateHasUniqueId(): DomNodeValidator { $this->validateHasUniqueAttribute("ID", "//*"); return $this; } + /** + * Validate that the node has attribute with name. + * + * @param string $name The attribute name + * @return $this + */ public function validateHasAttribute(string $name): DomNodeValidator { if (!isset($this->node)) { @@ -145,6 +194,13 @@ public function validateHasAttribute(string $name): DomNodeValidator return $this; } + /** + * Validate that the node's resolvable identifier attribute points to a target with the specified "ID" attribute. + * + * @param string $name The attribute name containing the reference id as value + * @param string $targetContextExpression The context expression to the target reference + * @return $this + */ public function validateHasReferenceToId(string $name, string $targetContextExpression): DomNodeValidator { if (!isset($this->node)) { @@ -169,5 +225,4 @@ public function validateHasReferenceToId(string $name, string $targetContextExpr return $this; } - } diff --git a/Classes/Validation/DvMetadataValidator.php b/Classes/Validation/DvMetadataValidator.php index aa18b667f..b5e5d016d 100644 --- a/Classes/Validation/DvMetadataValidator.php +++ b/Classes/Validation/DvMetadataValidator.php @@ -2,8 +2,6 @@ namespace Slub\Dfgviewer\Validation; -use Slub\Dfgviewer\Common\ValidationHelper; - /** * Copyright notice * @@ -27,6 +25,8 @@ * This copyright notice MUST APPEAR in all copies of the script! */ +use Slub\Dfgviewer\Common\ValidationHelper as VH; + /** * The validator validates against the rules outlined in chapter 2.7 of the METS application profile 2.3.1. * @@ -37,16 +37,16 @@ */ class DvMetadataValidator extends AbstactDomDocumentValidator { - protected function isValidDocument(): void + public function isValidDocument(): void { // Validates against the rules of chapter "2.7.1 Rechteangaben – dv:rights" - $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS) + $this->createNodeListValidator(VH::XPATH_DVRIGHTS) ->validateHasOne(); $this->validateDvRights(); // Validates against the rules of chapter "2.7.3 Verweise – dv:links" - $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS) + $this->createNodeListValidator(VH::XPATH_DVLINKS) ->validateHasOne(); $this->validateDvLinks(); @@ -59,20 +59,23 @@ protected function isValidDocument(): void * * @return void */ - public function validateDvLinks(): void + protected function validateDvLinks(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:reference') + $references = $this->createNodeListValidator(VH::XPATH_DVLINKS . '/dv:reference') ->validateHasAny() - ->iterate(array($this, "validateReferences")); + ->getNodeList(); + foreach ($references as $reference) { + $this->validateReference($reference); + } - $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:presentation') + $this->createNodeListValidator(VH::XPATH_DVLINKS . '/dv:presentation') ->validateHasNoneOrOne(); - $sruNode = $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:sru') + $sruNode = $this->createNodeListValidator(VH::XPATH_DVLINKS . '/dv:sru') ->validateHasNoneOrOne()->getFirstNode(); $this->createNodeValidator($sruNode)->validateHasContentWithUrl(); - $iiifNode = $this->createNodeListValidator(ValidationHelper::XPATH_DVLINKS . '/dv:iiif') + $iiifNode = $this->createNodeListValidator(VH::XPATH_DVLINKS . '/dv:iiif') ->validateHasNoneOrOne()->getFirstNode(); $this->createNodeValidator($iiifNode)->validateHasContentWithUrl(); } @@ -84,24 +87,24 @@ public function validateDvLinks(): void * * @return void */ - public function validateDvRights(): void + protected function validateDvRights(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:owner') + $this->createNodeListValidator(VH::XPATH_DVRIGHTS . '/dv:owner') ->validateHasOne(); - $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerLogo'); - $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerSiteURL'); - $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:ownerContact'); + $this->validateNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerLogo'); + $this->validateNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerSiteURL'); + $this->validateNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerContact'); - $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregator')->validateHasNoneOrOne(); - $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregatorLogo', true); - $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:aggregatorSiteURL', true); + $this->createNodeListValidator(VH::XPATH_DVRIGHTS . '/dv:aggregator')->validateHasNoneOrOne(); + $this->validateNodeContent(VH::XPATH_DVRIGHTS . '/dv:aggregatorLogo', true); + $this->validateNodeContent(VH::XPATH_DVRIGHTS . '/dv:aggregatorSiteURL', true); - $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsor')->validateHasNoneOrOne(); - $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsorLogo', true); - $this->validateNodeContent(ValidationHelper::XPATH_DVRIGHTS . '/dv:sponsorSiteURL', true); + $this->createNodeListValidator(VH::XPATH_DVRIGHTS . '/dv:sponsor')->validateHasNoneOrOne(); + $this->validateNodeContent(VH::XPATH_DVRIGHTS . '/dv:sponsorLogo', true); + $this->validateNodeContent(VH::XPATH_DVRIGHTS . '/dv:sponsorSiteURL', true); - $licenseNode = $this->createNodeListValidator(ValidationHelper::XPATH_DVRIGHTS . '/dv:license') + $licenseNode = $this->createNodeListValidator(VH::XPATH_DVRIGHTS . '/dv:license') ->validateHasNoneOrOne() ->getFirstNode(); if ($licenseNode && !in_array($licenseNode->nodeValue, array('pdm', 'cc0', 'cc-by', 'cc-by-sa', 'cc-by-nd', 'cc-by-nc', 'cc-by-nc-sa', 'cc-by-nc-nd', 'reserved'))) { @@ -110,14 +113,14 @@ public function validateDvRights(): void } /** - * Validates the references. + * Validates the reference. * * Validates against the rules of chapter "2.7.4.1 Katalog- bzw. Findbuchnachweis – dv:reference" * * @param \DOMNode $reference * @return void */ - public function validateReferences(\DOMNode $reference): void + protected function validateReference(\DOMNode $reference): void { if ($this->xpath->query('dv:reference', $reference->parentNode)->length > 1) { $this->createNodeValidator($reference) diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index cef8b1da9..7c5944bed 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -2,9 +2,6 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; - /** * Copyright notice * @@ -28,6 +25,9 @@ * This copyright notice MUST APPEAR in all copies of the script! */ +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; + /** * The validator validates against the rules outlined in chapter 2.6 of the METS application profile 2.3.1. * @@ -41,20 +41,23 @@ class AdministrativeMetadataValidator extends AbstactDomDocumentValidator public function isValidDocument(): void { // Validates against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" - $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA) + $administrativeMetadata = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_METADATA) ->validateHasAny() - ->iterate(array($this, "validateAdministrativMetadata")); + ->getNodeList(); + foreach ($administrativeMetadata as $administrativeMetadataNode) { + $this->validateAdministrativMetadataNode($administrativeMetadataNode); + } // Check if one administrative metadata exist with "mets:rightsMD" and "mets:digiprovMD" as children - $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]') + $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]') ->validateHasOne(); - $this->validateTechnicalMetadataStructure(); - $this->validateRightsMetadataStructure(); - $this->validateDigitalProvenanceMetadataStructure(); + $this->validateTechnicalMetadata(); + $this->validateRightsMetadata(); + $this->validateDigitalProvenanceMetadata(); } - public function validateAdministrativMetadata(\DOMNode $administrativeMetadata): void + protected function validateAdministrativMetadataNode(\DOMNode $administrativeMetadata): void { $this->createNodeValidator($administrativeMetadata) ->validateHasUniqueId(); @@ -67,13 +70,16 @@ public function validateAdministrativMetadata(\DOMNode $administrativeMetadata): * * @return void */ - public function validateDigitalProvenanceMetadataStructure(): void + protected function validateDigitalProvenanceMetadata(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) - ->iterate(array($this, "validateDigitalProvenanceMetadata")); + $digitalProvenanceMetadata = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) + ->getNodeList(); + foreach ($digitalProvenanceMetadata as $digitalProvenanceMetadataNode) { + $this->validateDigitalProvenanceMetadataNode($digitalProvenanceMetadataNode); + } } - public function validateDigitalProvenanceMetadata(\DOMNode $digitalProvenanceMetadata): void + protected function validateDigitalProvenanceMetadataNode(\DOMNode $digitalProvenanceMetadata): void { $this->createNodeValidator($digitalProvenanceMetadata) ->validateHasUniqueId(); @@ -97,13 +103,16 @@ public function validateDigitalProvenanceMetadata(\DOMNode $digitalProvenanceMet * * @return void */ - public function validateRightsMetadataStructure(): void + protected function validateRightsMetadata(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) - ->iterate(array($this, "validateRightsMetadata")); + $rightsMetadata = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) + ->getNodeList(); + foreach ($rightsMetadata as $rightsMetadataNode) { + $this->validateRightsMetadataNode($rightsMetadataNode); + } } - public function validateRightsMetadata(\DOMNode $rightsMetadata): void + protected function validateRightsMetadataNode(\DOMNode $rightsMetadata): void { $this->createNodeValidator($rightsMetadata) ->validateHasUniqueId(); @@ -127,14 +136,16 @@ public function validateRightsMetadata(\DOMNode $rightsMetadata): void * * @return void */ - public function validateTechnicalMetadataStructure(): void + protected function validateTechnicalMetadata(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) - ->iterate(array($this, "validateTechnicalMetadata")); + $technicalMetadata = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) + ->getNodeList(); + foreach ($technicalMetadata as $technicalMetadataNode) { + $this->validateTechnicalMetadataNode($technicalMetadataNode); + } } - - public function validateTechnicalMetadata(\DOMNode $technicalMetadata): void + protected function validateTechnicalMetadataNode(\DOMNode $technicalMetadata): void { $this->createNodeValidator($technicalMetadata) ->validateHasUniqueId(); diff --git a/Classes/Validation/Mets/DescriptiveMetadataValidator.php b/Classes/Validation/Mets/DescriptiveMetadataValidator.php index 47e3e430b..d7c5b8572 100644 --- a/Classes/Validation/Mets/DescriptiveMetadataValidator.php +++ b/Classes/Validation/Mets/DescriptiveMetadataValidator.php @@ -2,9 +2,6 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; - /** * Copyright notice * @@ -28,6 +25,9 @@ * This copyright notice MUST APPEAR in all copies of the script! */ +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; + /** * The validator validates against the rules outlined in chapter 2.5 of the METS application profile 2.3.1. * @@ -41,17 +41,20 @@ class DescriptiveMetadataValidator extends AbstactDomDocumentValidator public function isValidDocument(): void { // Validates against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" - $this->createNodeListValidator(ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS) + $descriptiveMetadataSections = $this->createNodeListValidator(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) ->validateHasAny() - ->iterate(array($this, 'validateDescriptiveMetadataSections')); + ->getNodeList(); + foreach ($descriptiveMetadataSections as $descriptiveMetadataSection) { + $this->validateDescriptiveMetadataSection($descriptiveMetadataSection); + } // there must be one primary structural element - $logicalStructureElement = $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) + $logicalStructureElement = $this->createNodeListValidator(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) ->validateHasOne() ->getFirstNode(); $this->createNodeValidator($logicalStructureElement) - ->validateHasReferenceToId('DMDID', ValidationHelper::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + ->validateHasReferenceToId('DMDID', VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); } /** @@ -61,7 +64,7 @@ public function isValidDocument(): void * * @return void */ - public function validateDescriptiveMetadataSections(\DOMNode $descriptiveMetadataSection): void + protected function validateDescriptiveMetadataSection(\DOMNode $descriptiveMetadataSection): void { $mdWrap = $this->createNodeListValidator('mets:mdWrap', $descriptiveMetadataSection) ->validateHasOne() diff --git a/Classes/Validation/Mets/DigitalRepresentationValidator.php b/Classes/Validation/Mets/DigitalRepresentationValidator.php index 74cdd2541..2995b3125 100644 --- a/Classes/Validation/Mets/DigitalRepresentationValidator.php +++ b/Classes/Validation/Mets/DigitalRepresentationValidator.php @@ -2,9 +2,6 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; - /** * Copyright notice * @@ -28,6 +25,9 @@ * This copyright notice MUST APPEAR in all copies of the script! */ +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; + /** * The validator validates against the rules outlined in chapter 2.4 of the METS application profile 2.3.1. * @@ -41,16 +41,16 @@ class DigitalRepresentationValidator extends AbstactDomDocumentValidator public function isValidDocument(): void { // Validates against the rules of chapter "2.4.1 Dateisektion – mets:fileSec" - $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTIONS) + $this->createNodeListValidator(VH::XPATH_FILE_SECTIONS) ->validateHasNoneOrOne(); // If a physical structure is present, there must be one file section. - if($this->xpath->query(ValidationHelper::XPATH_PHYSICAL_STRUCTURES)->length > 0){ - $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTIONS) + if($this->xpath->query(VH::XPATH_PHYSICAL_STRUCTURES)->length > 0){ + $this->createNodeListValidator(VH::XPATH_FILE_SECTIONS) ->validateHasOne(); } - if ($this->xpath->query(ValidationHelper::XPATH_FILE_SECTIONS)->length > 0) { + if ($this->xpath->query(VH::XPATH_FILE_SECTIONS)->length > 0) { $this->validateFileGroups(); $this->validateFiles(); } @@ -63,20 +63,23 @@ public function isValidDocument(): void * * @return void */ - public function validateFileGroups(): void + protected function validateFileGroups(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTION_GROUPS) + $fileSectionGroups = $this->createNodeListValidator(VH::XPATH_FILE_SECTION_GROUPS) ->validateHasAny() - ->iterate(array($this, "validateFileGroup")); + ->getNodeList(); + foreach ($fileSectionGroups as $fileSectionGroup) { + $this->validateFileGroup($fileSectionGroup); + } - $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]') + $this->createNodeListValidator(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]') ->validateHasOne(); } - public function validateFileGroup(\DOMNode $fileGroup): void + protected function validateFileGroup(\DOMNode $fileGroup): void { $this->createNodeValidator($fileGroup) - ->validateHasUniqueAttribute("USE", ValidationHelper::XPATH_FILE_SECTION_GROUPS); + ->validateHasUniqueAttribute("USE", VH::XPATH_FILE_SECTION_GROUPS); } /** @@ -86,14 +89,17 @@ public function validateFileGroup(\DOMNode $fileGroup): void * * @return void */ - public function validateFiles(): void + protected function validateFiles(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_FILE_SECTION_FILES) + $files = $this->createNodeListValidator(VH::XPATH_FILE_SECTION_FILES) ->validateHasAny() - ->iterate(array($this, "validateFile")); + ->getNodeList(); + foreach ($files as $file) { + $this->validateFile($file); + } } - public function validateFile(\DOMNode $file): void + protected function validateFile(\DOMNode $file): void { $this->createNodeValidator($file) ->validateHasUniqueId() diff --git a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php index 07b6c482c..ae50de37a 100644 --- a/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php +++ b/Classes/Validation/Mets/LinkingLogicalPhysicalStructureValidator.php @@ -25,7 +25,7 @@ * This copyright notice MUST APPEAR in all copies of the script! */ -use Slub\Dfgviewer\Common\ValidationHelper; +use Slub\Dfgviewer\Common\ValidationHelper as VH; use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; /** @@ -41,7 +41,7 @@ class LinkingLogicalPhysicalStructureValidator extends AbstactDomDocumentValidat public function isValidDocument(): void { // Validates against the rules of chapter "2.3.1 Structure links - mets:structLink" - $this->createNodeListValidator(ValidationHelper::XPATH_STRUCT_LINK) + $this->createNodeListValidator(VH::XPATH_STRUCT_LINK) ->validateHasNoneOrOne(); $this->validateLinkElements(); @@ -54,17 +54,20 @@ public function isValidDocument(): void * * @return void */ - public function validateLinkElements(): void + protected function validateLinkElements(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_STRUCT_LINK_ELEMENTS) + $linkElements = $this->createNodeListValidator(VH::XPATH_STRUCT_LINK_ELEMENTS) ->validateHasAny() - ->iterate(array($this, "validateLinkElement")); + ->getNodeList(); + foreach ($linkElements as $linkElement) { + $this->validateLinkElement($linkElement); + } } - public function validateLinkElement(\DOMNode $linkElement): void + protected function validateLinkElement(\DOMNode $linkElement): void { $this->createNodeValidator($linkElement) - ->validateHasReferenceToId("xlink:from", ValidationHelper::XPATH_LOGICAL_STRUCTURES) - ->validateHasReferenceToId("xlink:to", ValidationHelper::XPATH_PHYSICAL_STRUCTURES); + ->validateHasReferenceToId("xlink:from", VH::XPATH_LOGICAL_STRUCTURES) + ->validateHasReferenceToId("xlink:to", VH::XPATH_PHYSICAL_STRUCTURES); } } diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index fd1fca8a0..6d51ffa42 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -2,9 +2,6 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; - /** * Copyright notice * @@ -28,6 +25,9 @@ * This copyright notice MUST APPEAR in all copies of the script! */ +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; + /** * The validator validates against the rules outlined in chapter 2.1 of the METS application profile 2.3.1. * @@ -41,7 +41,7 @@ class LogicalStructureValidator extends AbstactDomDocumentValidator public function isValidDocument(): void { // Validates against the rules of chapter "2.1.1 Logical structure - mets:structMap" - $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_STRUCTURES) + $this->createNodeListValidator(VH::XPATH_LOGICAL_STRUCTURES) ->validateHasAny(); $this->validateStructuralElements(); @@ -56,18 +56,21 @@ public function isValidDocument(): void * * @return void */ - public function validateStructuralElements(): void + protected function validateStructuralElements(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) + $structuralElements = $this->createNodeListValidator(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) ->validateHasAny() - ->iterate(array($this, "validateStructuralElement")); + ->getNodeList(); + foreach ($structuralElements as $structuralElement) { + $this->validateStructuralElement($structuralElement); + } } - public function validateStructuralElement(\DOMNode $structureElement): void + protected function validateStructuralElement(\DOMNode $structureElement): void { $this->createNodeValidator($structureElement) ->validateHasUniqueId() - ->validateHasAttributeWithValue("TYPE", ValidationHelper::STRUCTURE_DATASET); + ->validateHasAttributeWithValue("TYPE", VH::STRUCTURE_DATASET); } /** @@ -77,14 +80,17 @@ public function validateStructuralElement(\DOMNode $structureElement): void * * @return void */ - public function validateExternalReferences(): void + protected function validateExternalReferences(): void { - $this->createNodeListValidator(ValidationHelper::XPATH_LOGICAL_EXTERNAL_REFERENCES) + $externalReferences = $this->createNodeListValidator(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES) ->validateHasNoneOrOne() - ->iterate(array($this, "validateExternalReference")); + ->getNodeList(); + foreach ($externalReferences as $externalReference) { + $this->validateExternalReference($externalReference); + } } - public function validateExternalReference(\DOMNode $externalReference): void + protected function validateExternalReference(\DOMNode $externalReference): void { $this->createNodeValidator($externalReference) ->validateHasAttributeWithValue("LOCTYPE", array("URL", "PURL")) @@ -98,7 +104,7 @@ public function validateExternalReference(\DOMNode $externalReference): void * * @return void */ - public function validatePeriodicPublishingSequences(): void + protected function validatePeriodicPublishingSequences(): void { // TODO } diff --git a/Classes/Validation/Mets/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php index 7ccc263ff..4878ed496 100644 --- a/Classes/Validation/Mets/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -2,9 +2,6 @@ namespace Slub\Dfgviewer\Validation\Mets; -use Slub\Dfgviewer\Common\ValidationHelper; -use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; - /** * Copyright notice * @@ -28,6 +25,9 @@ * This copyright notice MUST APPEAR in all copies of the script! */ +use Slub\Dfgviewer\Common\ValidationHelper as VH; +use Slub\Dfgviewer\Validation\AbstactDomDocumentValidator; + /** * The validator validates against the rules outlined in chapter 2.2 of the METS application profile 2.3.1. * @@ -38,12 +38,10 @@ */ class PhysicalStructureValidator extends AbstactDomDocumentValidator { - - public function isValidDocument(): void { // Validates against the rules of chapter "2.2.1 Physical structure - mets:structMap" - $this->createNodeListValidator(ValidationHelper::XPATH_PHYSICAL_STRUCTURES) + $this->createNodeListValidator(VH::XPATH_PHYSICAL_STRUCTURES) ->validateHasNoneOrOne(); $this->validateStructuralElements(); @@ -57,21 +55,24 @@ public function isValidDocument(): void * * @return void */ - public function validateStructuralElements(): void + protected function validateStructuralElements(): void { - $node = $this->createNodeListValidator(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE) + $node = $this->createNodeListValidator(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE) ->validateHasOne() ->getFirstNode(); $this->createNodeValidator($node) ->validateHasAttributeWithValue('TYPE', array('physSequence')); - $this->createNodeListValidator(ValidationHelper::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS) + $structuralElements =$this->createNodeListValidator(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS) ->validateHasAny() - ->iterate(array($this, "validateStructuralElement")); + ->getNodeList(); + foreach ($structuralElements as $structuralElement) { + $this->validateStructuralElement($structuralElement); + } } - public function validateStructuralElement(\DOMNode $structureElement): void + protected function validateStructuralElement(\DOMNode $structureElement): void { $this->createNodeValidator($structureElement) ->validateHasUniqueId() diff --git a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php index 8e6ea2677..ec35bf082 100644 --- a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php +++ b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php @@ -49,7 +49,7 @@ public function setUp(): void } /** - * Validates the document using the validator. + * Validates the document using the created validator. * * @return void */ @@ -63,7 +63,7 @@ public function testDocument() * * @return Result */ - public function validate(): Result + protected function validate(): Result { return $this->validator->validate($this->doc); } @@ -76,12 +76,17 @@ public function validate(): Result * @param $message string * @return void */ - public function validateAndAssertEquals(string $message): void + protected function validateAndAssertEquals(string $message): void { $result = $this->validator->validate($this->doc); self::assertEquals($message, $result->getFirstError()->getMessage()); } + /** + * Reset the document. + * + * @return void + */ protected function resetDocument(): void { $this->doc = $this->getDomDocument(); @@ -176,6 +181,11 @@ protected function setContentValue(string $expression, string $value): void } } + /** + * Gets the doc from xml file. + * + * @return DOMDocument + */ protected function getDomDocument(): DOMDocument { $doc = new DOMDocument(); @@ -184,12 +194,24 @@ protected function getDomDocument(): DOMDocument return $doc; } + /** + * Assert validation has no error. + * + * @return void + */ protected function assertNoError(): void { $result = $this->validate(); $this->assertFalse($result->hasErrors()); } + /** + * Assert validation error has any. + * + * @param string $expression The expression in error message + * @param string $context The context in error message + * @return void + */ protected function assertErrorHasAny(string $expression, string $context = ''): void { $message = 'There must be at least one element that matches the XPath expression "' . $expression . '"'; @@ -199,6 +221,13 @@ protected function assertErrorHasAny(string $expression, string $context = ''): $this->validateAndAssertEquals($message); } + /** + * Assert validation error has one. + * + * @param string $expression The expression in error message + * @param string $context The context in error message + * @return void + */ protected function assertErrorHasOne(string $expression, string $context = ''): void { $message = 'There must be an element that matches the XPath expression "' . $expression . '"'; @@ -208,6 +237,13 @@ protected function assertErrorHasOne(string $expression, string $context = ''): $this->validateAndAssertEquals($message); } + /** + * Assert validation error has none or one. + * + * @param string $expression The expression in error message + * @param string $context The context in error message + * @return void + */ protected function assertErrorHasNoneOrOne(string $expression, string $context = ''): void { $message = 'There must be no more than one element that matches the XPath expression "' . $expression . '"'; @@ -217,41 +253,102 @@ protected function assertErrorHasNoneOrOne(string $expression, string $context = $this->validateAndAssertEquals($message); } + /** + * Assert validation error has attribute. + * + * @param string $expression The expression in error message + * @param string $name The attribute name + * @return void + */ protected function assertErrorHasAttribute(string $expression, string $name): void { $this->validateAndAssertEquals('Mandatory "' . $name . '" attribute of "' . $expression . '" is missing.'); } + /** + * Assert validation error has attribute with value. + * + * @param string $expression The expression in error message + * @param string $name The attribute name + * @param string $value The attribute value + * @return void + */ protected function assertErrorHasAttributeWithValue(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not permissible.'); } + /** + * Assert validation error has attribute with URL value. + * + * @param string $expression The expression in error message + * @param string $name The attribute name + * @param string $value The attribute value + * @return void + */ protected function assertErrorHasAttributeWithUrl(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('URL "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not valid.'); } + /** + * Assert validation error has content with Email. + * + * @param string $expression The expression in error message + * @param string $name The attribute name + * @param string $value The attribute value + * @param string $targetContextExpression The target context expression + * @return void + */ + protected function assertErrorHasAttributeRefToOne(string $expression, string $name, string $value, string $targetContextExpression): void + { + $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); + } + + /** + * Assert validation error has content with Email. + * + * @param string $expression The expression in error message + * @param string $value The content value + * @return void + */ protected function assertErrorHasContentWithEmail(string $expression, string $value): void { $this->validateAndAssertEquals('Email "' . $value . '" in the content of "' . $expression . '" is not valid.'); } + /** + * Assert validation error has content with URL. + * + * @param string $expression The expression in error message + * @param string $value The content value + * @return void + */ protected function assertErrorHasContentWithUrl(string $expression, string $value): void { $this->validateAndAssertEquals('URL "' . $value . '" in the content of "' . $expression . '" is not valid.'); } - protected function assertErrorHasRefToOne(string $expression, string $name, string $value, string $targetContextExpression): void - { - $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); - } - + /** + * Assert validation error has unique identifier. + * + * @param string $expression The expression in error message + * @param string $value The attribute value + * @return void + */ protected function assertErrorHasUniqueId(string $expression, string $value): void { $this->assertErrorHasUniqueAttribute($expression, 'ID', $value); } + /** + * Assert validation error has unique attribute with value. + * + * @param string $expression The expression in error message + * @param string $name The attribute name + * @param string $value The attribute value + * @return void + */ protected function assertErrorHasUniqueAttribute(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('"' . $name . '" attribute with value "' . $value . '" of "' . $expression . '" already exists.'); diff --git a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php index 911449c1d..c566d203e 100644 --- a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php @@ -47,7 +47,7 @@ public function testDescriptiveMetadata(): void $this->resetDocument(); $this->setAttributeValue(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'DMDID', 'Test'); - $this->assertErrorHasRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->assertErrorHasAttributeRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); } /** diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index 086b350e7..7342e92b8 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -50,11 +50,11 @@ public function testLinkElements(): void $this->resetDocument(); $this->setAttributeValue(VH::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:from', 'Test'); - $this->assertErrorHasRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:from', 'Test', VH::XPATH_LOGICAL_STRUCTURES); + $this->assertErrorHasAttributeRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:from', 'Test', VH::XPATH_LOGICAL_STRUCTURES); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:to', 'Test'); - $this->assertErrorHasRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:to', 'Test', VH::XPATH_PHYSICAL_STRUCTURES); + $this->assertErrorHasAttributeRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:to', 'Test', VH::XPATH_PHYSICAL_STRUCTURES); } protected function createValidator(): AbstractDlfValidator From 008e0c111dd2b5cf3728d2cbe6a309b3e80f26a8 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 13:26:13 +0100 Subject: [PATCH 28/43] Add missing properties! --- Classes/Validation/Dom/DomNodeValidator.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index 82dd634c1..ea4442e49 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -42,6 +42,10 @@ class DomNodeValidator { protected DOMXPath $xpath; + protected ?DOMNode $node; + + protected Result $result; + public function __construct(DOMXPath $xpath, Result $result, ?DOMNode $node) { $this->xpath = $xpath; From 8793fe8087625edd380c63c2de2d7c0acc796e81 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 13:49:30 +0100 Subject: [PATCH 29/43] Add phpstan ignores --- Classes/Validation/Dom/DomNodeValidator.php | 16 ++++++++++++---- .../Mets/DescriptiveMetadataValidator.php | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index ea4442e49..a3fda9719 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -42,6 +42,9 @@ class DomNodeValidator { protected DOMXPath $xpath; + /** + * @var DOMNode + */ protected ?DOMNode $node; protected Result $result; @@ -107,11 +110,12 @@ public function validateHasAttributeWithUrl(string $name): DomNodeValidator return $this; } + // @phpstan-ignore-next-line if (!$this->node->hasAttribute($name)) { return $this->validateHasAttribute($name); } - $value = $this->node->getAttribute($name); + $value = $this->node->getAttribute($name); // @phpstan-ignore-line if (!filter_var($value, FILTER_VALIDATE_URL)) { $this->result->addError(new Error('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); } @@ -132,11 +136,12 @@ public function validateHasAttributeWithValue(string $name, array $values): DomN return $this; } + // @phpstan-ignore-next-line if (!$this->node->hasAttribute($name)) { return $this->validateHasAttribute($name); } - $value = $this->node->getAttribute($name); + $value = $this->node->getAttribute($name); // @phpstan-ignore-line if (!in_array($value, $values)) { $this->result->addError(new Error('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not permissible.', 1724234607)); } @@ -157,11 +162,12 @@ public function validateHasUniqueAttribute(string $name, string $contextExpressi return $this; } + // @phpstan-ignore-next-line if (!$this->node->hasAttribute($name)) { return $this->validateHasAttribute($name); } - $value = $this->node->getAttribute($name); + $value = $this->node->getAttribute($name); // @phpstan-ignore-line if ($this->xpath->query($contextExpression . '[@' . $name . '="' . $value . '"]')->length > 1) { $this->result->addError(new Error('"' . $name . '" attribute with value "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); } @@ -192,6 +198,7 @@ public function validateHasAttribute(string $name): DomNodeValidator return $this; } + // @phpstan-ignore-next-line if (!$this->node->hasAttribute($name)) { $this->result->addError(new Error('Mandatory "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is missing.', 1724234607)); } @@ -211,12 +218,13 @@ public function validateHasReferenceToId(string $name, string $targetContextExpr return $this; } + // @phpstan-ignore-next-line if (!$this->node->hasAttribute($name)) { return $this->validateHasAttribute($name); } $targetNodes = $this->xpath->query($targetContextExpression); - $id = $this->node->getAttribute($name); + $id = $this->node->getAttribute($name); // @phpstan-ignore-line $foundElements = 0; foreach ($targetNodes as $targetNode) { diff --git a/Classes/Validation/Mets/DescriptiveMetadataValidator.php b/Classes/Validation/Mets/DescriptiveMetadataValidator.php index d7c5b8572..cfe9a08f7 100644 --- a/Classes/Validation/Mets/DescriptiveMetadataValidator.php +++ b/Classes/Validation/Mets/DescriptiveMetadataValidator.php @@ -77,7 +77,7 @@ protected function validateDescriptiveMetadataSection(\DOMNode $descriptiveMetad return; } - $mdType = $mdWrap->getAttribute('MDTYPE'); + $mdType = $mdWrap->getAttribute('MDTYPE'); // @phpstan-ignore-line if ($mdType == 'TEIHDR' || $mdType == 'MODS') { $childNode = $mdType == 'TEIHDR' ? 'tei:teiHeader' : 'mods:mods'; $this->createNodeListValidator('mets:xmlData[' . $childNode . ']', $mdWrap) From fe345406971fc2f6e2afd66ddbf3c77b99f4e3a1 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 13:54:41 +0100 Subject: [PATCH 30/43] Make runTests.sh executable --- Build/Test/runTests.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Build/Test/runTests.sh diff --git a/Build/Test/runTests.sh b/Build/Test/runTests.sh old mode 100644 new mode 100755 From 492487d809f647c01d9d54bb673f6593da7f5d5f Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 14:03:11 +0100 Subject: [PATCH 31/43] Remove code coverage cause it needs a secret --- .github/workflows/tests.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c859552c0..153023ac2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,8 +22,3 @@ jobs: - name: Run unit tests run: Build/Test/runTests.sh -s unit - - - name: Upload coverage reports - uses: codecov/codecov-action@v4 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From 3648c40431c496feebc14078544b9f930feda363 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 14:09:13 +0100 Subject: [PATCH 32/43] Downgrade test framework --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f6005641b..80ada1bc1 100644 --- a/composer.json +++ b/composer.json @@ -49,9 +49,9 @@ }, "require-dev": { "phpstan/phpstan": "^1.12", - "phpunit/phpunit": "^9.6.20", + "phpunit/phpunit": "^9.6.22", "spatie/phpunit-watcher": "^1.23.6", - "typo3/testing-framework": "^7.1.0" + "typo3/testing-framework": "^6.16.10" }, "replace": { "typo3-ter/dfgviewer": "self.version" From e1daa4d9d7fa47e007183fa29a2c82d296348685 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 14:46:01 +0100 Subject: [PATCH 33/43] add solarium dev dependency --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 80ada1bc1..c42fa3b26 100644 --- a/composer.json +++ b/composer.json @@ -50,6 +50,7 @@ "require-dev": { "phpstan/phpstan": "^1.12", "phpunit/phpunit": "^9.6.22", + "solarium/solarium": "5.2 - 6.3", "spatie/phpunit-watcher": "^1.23.6", "typo3/testing-framework": "^6.16.10" }, From 45230a91733078cf0fe2ac4eec4ad6ffdc10cccb Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 16:38:40 +0100 Subject: [PATCH 34/43] Update testing pipeline --- .github/workflows/tests.yml | 5 +---- Build/Test/docker-compose.yml | 15 --------------- composer.json | 8 +------- 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 153023ac2..288ac405c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,15 +10,12 @@ jobs: test: name: TYPO3 runs-on: ubuntu-latest - strategy: - matrix: - typo3: [ 10.4, 11.5 ] steps: - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies - run: Build/Test/runTests.sh -s composerInstall -t ${{ matrix.typo3 }} + run: Build/Test/runTests.sh -s composerInstall -t 11.5 - name: Run unit tests run: Build/Test/runTests.sh -s unit diff --git a/Build/Test/docker-compose.yml b/Build/Test/docker-compose.yml index 706f471b1..43b7a1fd3 100644 --- a/Build/Test/docker-compose.yml +++ b/Build/Test/docker-compose.yml @@ -43,19 +43,6 @@ services: php -S web:8001 -t ${DFGVIEWER_ROOT} fi " - solr: - image: docker.io/solr:9 - volumes: - - ${DFGVIEWER_ROOT}/Configuration/ApacheSolr/configsets:/var/solr/data/configsets - - ./solr/modules/ocrsearch:/opt/solr/modules/ocrsearch - ports: - - 8983:8983 - user: root # run as root to change the permissions of the solr folder - # Change permissions of the solr folder, create a default core and start solr as solr user - command: /bin/sh -c " - chown -R 8983:8983 /var/solr - && runuser -u solr -- solr-precreate default-core - " composer_install: image: docker.io/typo3/core-testing-${DOCKER_PHP_IMAGE}:latest user: "${HOST_UID}:${HOST_GID}" @@ -70,7 +57,6 @@ services: if [ ${SCRIPT_VERBOSE} -eq 1 ]; then set -x fi - composer require "kitodo/presentation:@dev" if [ -z ${TYPO3_VERSION} ]; then composer install --no-progress --no-interaction; else @@ -82,7 +68,6 @@ services: links: - ${DBMS} - web - - solr user: "${HOST_UID}:${HOST_GID}" volumes: - ${EXTENSIONS_ROOT}:/var/www/extensions/ diff --git a/composer.json b/composer.json index c42fa3b26..d1094f82c 100644 --- a/composer.json +++ b/composer.json @@ -50,9 +50,8 @@ "require-dev": { "phpstan/phpstan": "^1.12", "phpunit/phpunit": "^9.6.22", - "solarium/solarium": "5.2 - 6.3", "spatie/phpunit-watcher": "^1.23.6", - "typo3/testing-framework": "^6.16.10" + "typo3/testing-framework": "^7.1.1" }, "replace": { "typo3-ter/dfgviewer": "self.version" @@ -62,11 +61,6 @@ "Slub\\Dfgviewer\\": "Classes/" } }, - "autoload-dev": { - "psr-4": { - "Kitodo\\Dlf\\Tests\\": "Tests/" - } - }, "extra": { "typo3/cms": { "extension-key": "dfgviewer" From 4f8c4efbc0400758f649a64a7e3967b725cfa5c8 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 16:53:37 +0100 Subject: [PATCH 35/43] Fix codacy errors --- Classes/Validation/AbstactDomDocumentValidator.php | 4 ++-- Classes/Validation/ApplicationProfileValidationStack.php | 3 ++- Classes/Validation/Dom/DomNodeListValidator.php | 3 ++- Classes/Validation/Dom/DomNodeValidator.php | 1 + Classes/Validation/Mets/AdministrativeMetadataValidator.php | 4 ++-- Classes/Validation/Mets/DigitalRepresentationValidator.php | 4 ++-- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Classes/Validation/AbstactDomDocumentValidator.php b/Classes/Validation/AbstactDomDocumentValidator.php index c073d390a..1054e9462 100644 --- a/Classes/Validation/AbstactDomDocumentValidator.php +++ b/Classes/Validation/AbstactDomDocumentValidator.php @@ -34,6 +34,7 @@ abstract class AbstactDomDocumentValidator extends AbstractDlfValidator { + protected DOMXpath $xpath; public function __construct() @@ -57,6 +58,5 @@ protected function createNodeValidator(?DOMNode $node): DomNodeValidator return new DomNodeValidator($this->xpath, $this->result, $node); } - protected abstract function isValidDocument(); - + abstract function isValidDocument(); } diff --git a/Classes/Validation/ApplicationProfileValidationStack.php b/Classes/Validation/ApplicationProfileValidationStack.php index ec30b9981..9ab3c46a7 100644 --- a/Classes/Validation/ApplicationProfileValidationStack.php +++ b/Classes/Validation/ApplicationProfileValidationStack.php @@ -35,7 +35,8 @@ use Slub\Dfgviewer\Validation\Mets\LogicalStructureValidator; use Slub\Dfgviewer\Validation\Mets\PhysicalStructureValidator; -class ApplicationProfileValidationStack extends AbstractDlfValidationStack { +class ApplicationProfileValidationStack extends AbstractDlfValidationStack +{ public function __construct() { parent::__construct(\DOMDocument::class); diff --git a/Classes/Validation/Dom/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php index 4edc6414a..cb6fb1d1e 100644 --- a/Classes/Validation/Dom/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -41,6 +41,7 @@ */ class DomNodeListValidator { + private string $expression; private ?DOMNode $contextNode; @@ -130,7 +131,7 @@ public function validateHasNoneOrOne(): DomNodeListValidator private function addError(string $prefix): void { $message = $prefix . ' that matches the XPath expression "' . $this->expression . '"'; - if($this->contextNode) { + if ($this->contextNode) { $message .= ' under "' . $this->contextNode->getNodePath() . '"'; } $this->result->addError(new Error($message, 23)); diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index a3fda9719..392da9feb 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -40,6 +40,7 @@ */ class DomNodeValidator { + protected DOMXPath $xpath; /** diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index 7c5944bed..8626265cd 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -89,8 +89,8 @@ protected function validateDigitalProvenanceMetadataNode(\DOMNode $digitalProven ->getFirstNode(); $this->createNodeValidator($mdWrap) - ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) - ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVLINKS')); + ->validateHasAttributeWithValue('MDTYPE', ['OTHER']) + ->validateHasAttributeWithValue('OTHERMDTYPE', ['DVLINKS']); $this->createNodeListValidator('mets:xmlData[dv:links]', $mdWrap) ->validateHasOne(); diff --git a/Classes/Validation/Mets/DigitalRepresentationValidator.php b/Classes/Validation/Mets/DigitalRepresentationValidator.php index 2995b3125..d8a51934b 100644 --- a/Classes/Validation/Mets/DigitalRepresentationValidator.php +++ b/Classes/Validation/Mets/DigitalRepresentationValidator.php @@ -45,7 +45,7 @@ public function isValidDocument(): void ->validateHasNoneOrOne(); // If a physical structure is present, there must be one file section. - if($this->xpath->query(VH::XPATH_PHYSICAL_STRUCTURES)->length > 0){ + if ($this->xpath->query(VH::XPATH_PHYSICAL_STRUCTURES)->length > 0) { $this->createNodeListValidator(VH::XPATH_FILE_SECTIONS) ->validateHasOne(); } @@ -110,7 +110,7 @@ protected function validateFile(\DOMNode $file): void ->getFirstNode(); $this->createNodeValidator($fLocat) - ->validateHasAttributeWithValue('LOCTYPE', array('URL', 'PURL')) + ->validateHasAttributeWithValue('LOCTYPE', ['URL', 'PURL']) ->validateHasAttributeWithUrl('xlink:href'); } } From 25ee6c1b5f32725462cc724207463392bab1e7ab Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 17:53:56 +0100 Subject: [PATCH 36/43] Changes codacy --- Build/Test/runTests.sh | 4 +-- Classes/Common/ValidationHelper.php | 6 ++-- Classes/Validation/Dom/DomNodeValidator.php | 31 ++++++++++--------- .../Mets/AdministrativeMetadataValidator.php | 22 ++++++------- .../Mets/DescriptiveMetadataValidator.php | 17 +++++----- .../AbstractDomDocumentValidatorTest.php | 6 ++-- .../Validation/DvMetadataValidatorTest.php | 8 ++--- 7 files changed, 48 insertions(+), 46 deletions(-) diff --git a/Build/Test/runTests.sh b/Build/Test/runTests.sh index 1d739c9f2..d3f109f44 100755 --- a/Build/Test/runTests.sh +++ b/Build/Test/runTests.sh @@ -265,7 +265,7 @@ done if [ ${#INVALID_OPTIONS[@]} -ne 0 ]; then echo "Invalid option(s):" >&2 for I in "${INVALID_OPTIONS[@]}"; do - echo "-"${I} >&2 + echo "-${I}" >&2 done echo >&2 echo "call \".Build/Test/runTests.sh -h\" to display help and valid options" @@ -364,4 +364,4 @@ echo "########################################################################## echo "" >&2 # Exit with code of test suite - This script return non-zero if the executed test failed. -exit $SUITE_EXIT_CODE +exit "$SUITE_EXIT_CODE" diff --git a/Classes/Common/ValidationHelper.php b/Classes/Common/ValidationHelper.php index 84d1eb72e..8b4b97f21 100644 --- a/Classes/Common/ValidationHelper.php +++ b/Classes/Common/ValidationHelper.php @@ -39,9 +39,9 @@ class ValidationHelper const NAMESPACE_METS = 'http://www.loc.gov/METS/'; - const STRUCTURE_DATASET = array( + const STRUCTURE_DATASET = [ 'section', 'file', 'album', 'register', 'annotation', 'address', 'article', 'atlas', 'issue', 'bachelor_thesis', 'volume', 'contained_work', 'additional', 'report', 'official_notification', 'provenance', 'inventory', 'image', 'collation', 'ornament', 'letter', 'cover', 'cover_front', 'cover_back', 'diploma_thesis', 'doctoral_thesis', 'document', 'printers_mark', 'printed_archives', 'binding', 'entry', 'corrigenda', 'bookplate', 'fascicle', 'leaflet', 'research_paper', 'photograph', 'fragment', 'land_register', 'ground_plan', 'habilitation_thesis', 'manuscript', 'illustration', 'imprint', 'contents', 'initial_decoration', 'year', 'chapter', 'map', 'cartulary', 'colophon', 'ephemera', 'engraved_titlepage', 'magister_thesis', 'folder', 'master_thesis', 'multivolume_work', 'month', 'monograph', 'musical_notation', 'periodical', 'poster', 'plan', 'privileges', 'index', 'spine', 'scheme', 'edge', 'seal', 'paste down', 'stamp', 'study', 'table', 'day', 'proceeding', 'text', 'title_page', 'subinventory', 'act', 'judgement', 'verse', 'note', 'preprint', 'dossier', 'lecture', 'endsheet', 'paper', 'preface', 'dedication', 'newspaper' - ); + ]; const XPATH_METS = '//mets:mets'; @@ -83,7 +83,7 @@ class ValidationHelper public static function trimDoubleSlash(string $value): string { - if(str_starts_with($value, '//')) { + if (str_starts_with($value, '//')) { return substr($value, 1); } return $value; diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index 392da9feb..1a0c3d597 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -41,14 +41,11 @@ class DomNodeValidator { - protected DOMXPath $xpath; + private DOMXPath $xpath; - /** - * @var DOMNode - */ - protected ?DOMNode $node; + private ?DOMNode $node; - protected Result $result; + private Result $result; public function __construct(DOMXPath $xpath, Result $result, ?DOMNode $node) { @@ -116,7 +113,8 @@ public function validateHasAttributeWithUrl(string $name): DomNodeValidator return $this->validateHasAttribute($name); } - $value = $this->node->getAttribute($name); // @phpstan-ignore-line + // @phpstan-ignore-next-line + $value = $this->node->getAttribute($name); if (!filter_var($value, FILTER_VALIDATE_URL)) { $this->result->addError(new Error('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); } @@ -142,7 +140,8 @@ public function validateHasAttributeWithValue(string $name, array $values): DomN return $this->validateHasAttribute($name); } - $value = $this->node->getAttribute($name); // @phpstan-ignore-line + // @phpstan-ignore-next-line + $value = $this->node->getAttribute($name); if (!in_array($value, $values)) { $this->result->addError(new Error('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not permissible.', 1724234607)); } @@ -168,7 +167,8 @@ public function validateHasUniqueAttribute(string $name, string $contextExpressi return $this->validateHasAttribute($name); } - $value = $this->node->getAttribute($name); // @phpstan-ignore-line + // @phpstan-ignore-next-line + $value = $this->node->getAttribute($name); if ($this->xpath->query($contextExpression . '[@' . $name . '="' . $value . '"]')->length > 1) { $this->result->addError(new Error('"' . $name . '" attribute with value "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); } @@ -210,10 +210,10 @@ public function validateHasAttribute(string $name): DomNodeValidator * Validate that the node's resolvable identifier attribute points to a target with the specified "ID" attribute. * * @param string $name The attribute name containing the reference id as value - * @param string $targetContextExpression The context expression to the target reference + * @param string $targetExpression The context expression to the target reference * @return $this */ - public function validateHasReferenceToId(string $name, string $targetContextExpression): DomNodeValidator + public function validateHasReferenceToId(string $name, string $targetExpression): DomNodeValidator { if (!isset($this->node)) { return $this; @@ -224,16 +224,17 @@ public function validateHasReferenceToId(string $name, string $targetContextExpr return $this->validateHasAttribute($name); } - $targetNodes = $this->xpath->query($targetContextExpression); - $id = $this->node->getAttribute($name); // @phpstan-ignore-line + $targetNodes = $this->xpath->query($targetExpression); + // @phpstan-ignore-next-line + $identifier = $this->node->getAttribute($name); $foundElements = 0; foreach ($targetNodes as $targetNode) { - $foundElements += $this->xpath->query('//*[@ID="' . $id . '"]', $targetNode)->length; + $foundElements += $this->xpath->query('//*[@ID="' . $identifier . '"]', $targetNode)->length; } if ($foundElements !== 1) { - $this->result->addError(new Error('Value "' . $id . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" must reference one element under XPath expression "' . $targetContextExpression, 1724234607)); + $this->result->addError(new Error('Value "' . $identifier . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" must reference one element under XPath expression "' . $targetExpression, 1724234607)); } return $this; diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index 8626265cd..71ef4baf3 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -41,11 +41,11 @@ class AdministrativeMetadataValidator extends AbstactDomDocumentValidator public function isValidDocument(): void { // Validates against the rules of chapter "2.6.1 Metadatensektion – mets:amdSec" - $administrativeMetadata = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_METADATA) + $amdSections = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_METADATA) ->validateHasAny() ->getNodeList(); - foreach ($administrativeMetadata as $administrativeMetadataNode) { - $this->validateAdministrativMetadataNode($administrativeMetadataNode); + foreach ($amdSections as $amdSection) { + $this->validateAdministrativMetadataNode($amdSection); } // Check if one administrative metadata exist with "mets:rightsMD" and "mets:digiprovMD" as children @@ -57,9 +57,9 @@ public function isValidDocument(): void $this->validateDigitalProvenanceMetadata(); } - protected function validateAdministrativMetadataNode(\DOMNode $administrativeMetadata): void + protected function validateAdministrativMetadataNode(\DOMNode $amdSection): void { - $this->createNodeValidator($administrativeMetadata) + $this->createNodeValidator($amdSection) ->validateHasUniqueId(); } @@ -72,19 +72,19 @@ protected function validateAdministrativMetadataNode(\DOMNode $administrativeMet */ protected function validateDigitalProvenanceMetadata(): void { - $digitalProvenanceMetadata = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) + $digiprovs = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) ->getNodeList(); - foreach ($digitalProvenanceMetadata as $digitalProvenanceMetadataNode) { - $this->validateDigitalProvenanceMetadataNode($digitalProvenanceMetadataNode); + foreach ($digiprovs as $digiprov) { + $this->validateDigitalProvenanceMetadataNode($digiprov); } } - protected function validateDigitalProvenanceMetadataNode(\DOMNode $digitalProvenanceMetadata): void + protected function validateDigitalProvenanceMetadataNode(\DOMNode $digiprov): void { - $this->createNodeValidator($digitalProvenanceMetadata) + $this->createNodeValidator($digiprov) ->validateHasUniqueId(); - $mdWrap = $this->createNodeListValidator('mets:mdWrap', $digitalProvenanceMetadata) + $mdWrap = $this->createNodeListValidator('mets:mdWrap', $digiprov) ->validateHasOne() ->getFirstNode(); diff --git a/Classes/Validation/Mets/DescriptiveMetadataValidator.php b/Classes/Validation/Mets/DescriptiveMetadataValidator.php index cfe9a08f7..027c39c1b 100644 --- a/Classes/Validation/Mets/DescriptiveMetadataValidator.php +++ b/Classes/Validation/Mets/DescriptiveMetadataValidator.php @@ -41,19 +41,19 @@ class DescriptiveMetadataValidator extends AbstactDomDocumentValidator public function isValidDocument(): void { // Validates against the rules of chapter "2.5.1 Metadatensektion – mets:dmdSec" - $descriptiveMetadataSections = $this->createNodeListValidator(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) + $descriptiveSections = $this->createNodeListValidator(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) ->validateHasAny() ->getNodeList(); - foreach ($descriptiveMetadataSections as $descriptiveMetadataSection) { - $this->validateDescriptiveMetadataSection($descriptiveMetadataSection); + foreach ($descriptiveSections as $descriptiveSection) { + $this->validateDescriptiveMetadataSection($descriptiveSection); } // there must be one primary structural element - $logicalStructureElement = $this->createNodeListValidator(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) + $structureElement = $this->createNodeListValidator(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS) ->validateHasOne() ->getFirstNode(); - $this->createNodeValidator($logicalStructureElement) + $this->createNodeValidator($structureElement) ->validateHasReferenceToId('DMDID', VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); } @@ -64,9 +64,9 @@ public function isValidDocument(): void * * @return void */ - protected function validateDescriptiveMetadataSection(\DOMNode $descriptiveMetadataSection): void + protected function validateDescriptiveMetadataSection(\DOMNode $descriptiveSection): void { - $mdWrap = $this->createNodeListValidator('mets:mdWrap', $descriptiveMetadataSection) + $mdWrap = $this->createNodeListValidator('mets:mdWrap', $descriptiveSection) ->validateHasOne() ->getFirstNode(); @@ -77,7 +77,8 @@ protected function validateDescriptiveMetadataSection(\DOMNode $descriptiveMetad return; } - $mdType = $mdWrap->getAttribute('MDTYPE'); // @phpstan-ignore-line + // @phpstan-ignore-next-line + $mdType = $mdWrap->getAttribute('MDTYPE'); if ($mdType == 'TEIHDR' || $mdType == 'MODS') { $childNode = $mdType == 'TEIHDR' ? 'tei:teiHeader' : 'mods:mods'; $this->createNodeListValidator('mets:xmlData[' . $childNode . ']', $mdWrap) diff --git a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php index ec35bf082..afda9b1eb 100644 --- a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php +++ b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php @@ -297,12 +297,12 @@ protected function assertErrorHasAttributeWithUrl(string $expression, string $na * @param string $expression The expression in error message * @param string $name The attribute name * @param string $value The attribute value - * @param string $targetContextExpression The target context expression + * @param string $targetExpression The target context expression * @return void */ - protected function assertErrorHasAttributeRefToOne(string $expression, string $name, string $value, string $targetContextExpression): void + protected function assertErrorHasAttributeRefToOne(string $expression, string $name, string $value, string $targetExpression): void { - $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetContextExpression); + $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetExpression); } /** diff --git a/Tests/Unit/Validation/DvMetadataValidatorTest.php b/Tests/Unit/Validation/DvMetadataValidatorTest.php index 680badf95..61d5354fa 100644 --- a/Tests/Unit/Validation/DvMetadataValidatorTest.php +++ b/Tests/Unit/Validation/DvMetadataValidatorTest.php @@ -125,25 +125,25 @@ public function testDvLinksSubelements(): void $this->assertErrorHasContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:iiif', 'Test'); } - protected function assertNodeContent(string $expression, string $expectedErrorExpression): void + protected function assertNodeContent(string $expression, string $expectedExpression): void { $this->removeNodes($expression); $this->assertErrorHasOne($expression); $this->resetDocument(); $this->setContentValue($expression, 'Test'); - $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); + $this->assertErrorHasContentWithUrl($expectedExpression, 'Test'); $this->resetDocument(); } - protected function assertOptionalNodeContent(string $expression, string $name, string $expectedErrorExpression): void + protected function assertOptionalNodeContent(string $expression, string $name, string $expectedExpression): void { $this->addChildNodeWithNamespace($expression, VH::NAMESPACE_DV, $name); $this->assertErrorHasNoneOrOne($expression . '/' . $name); $this->resetDocument(); $this->setContentValue($expression . '/' . $name, 'Test'); - $this->assertErrorHasContentWithUrl($expectedErrorExpression, 'Test'); + $this->assertErrorHasContentWithUrl($expectedExpression, 'Test'); $this->resetDocument(); } From 699a49306e696a4a36a1ce57870e01b23fb88db7 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 18:16:18 +0100 Subject: [PATCH 37/43] Fixes of codacy issues --- .../Validation/AbstactDomDocumentValidator.php | 7 +++++-- Classes/Validation/Dom/DomNodeListValidator.php | 13 ++++++++++++- Classes/Validation/Dom/DomNodeValidator.php | 10 ++++++++++ Classes/Validation/DvMetadataValidator.php | 4 ++-- .../Mets/AdministrativeMetadataValidator.php | 16 ++++++++-------- .../Mets/DescriptiveMetadataValidator.php | 9 ++++++--- .../Mets/LogicalStructureValidator.php | 3 +-- .../Mets/PhysicalStructureValidator.php | 6 +++--- .../AbstractDomDocumentValidatorTest.php | 6 +++--- 9 files changed, 50 insertions(+), 24 deletions(-) diff --git a/Classes/Validation/AbstactDomDocumentValidator.php b/Classes/Validation/AbstactDomDocumentValidator.php index 1054e9462..23466fa05 100644 --- a/Classes/Validation/AbstactDomDocumentValidator.php +++ b/Classes/Validation/AbstactDomDocumentValidator.php @@ -35,6 +35,9 @@ abstract class AbstactDomDocumentValidator extends AbstractDlfValidator { + /** + * @var DOMXPath The XPath of DOMDocument value. + */ protected DOMXpath $xpath; public function __construct() @@ -48,7 +51,7 @@ protected function isValid($value): void $this->isValidDocument(); } - protected function createNodeListValidator(string $expression, ?DOMNode $contextNode = null): DomNodeListValidator + protected function createNodeListValidator(string $expression, ?DOMNode $contextNode=null): DomNodeListValidator { return new DomNodeListValidator($this->xpath, $this->result, $expression, $contextNode); } @@ -58,5 +61,5 @@ protected function createNodeValidator(?DOMNode $node): DomNodeValidator return new DomNodeValidator($this->xpath, $this->result, $node); } - abstract function isValidDocument(); + public abstract function isValidDocument(); } diff --git a/Classes/Validation/Dom/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php index cb6fb1d1e..846ddbcae 100644 --- a/Classes/Validation/Dom/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -41,13 +41,24 @@ */ class DomNodeListValidator { - + /** + * @var string The expression of XPath query + */ private string $expression; + /** + * @var DOMNode|null The context node of XPath query + */ private ?DOMNode $contextNode; + /** + * @var DOMNodeList|false|mixed The node list result of XPath query + */ private DOMNodeList $nodeList; + /** + * @var Result The result containing errors of validation + */ private Result $result; public function __construct(DOMXPath $xpath, Result $result, string $expression, ?DOMNode $contextNode = null) diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index 1a0c3d597..d1dde67a8 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -41,10 +41,20 @@ class DomNodeValidator { + /** + * @var DOMXPath The XPath of document to validate + */ private DOMXPath $xpath; + /** + * @var DOMNode|null The node to validate. + */ private ?DOMNode $node; + + /** + * @var Result The result containing errors of validation + */ private Result $result; public function __construct(DOMXPath $xpath, Result $result, ?DOMNode $node) diff --git a/Classes/Validation/DvMetadataValidator.php b/Classes/Validation/DvMetadataValidator.php index b5e5d016d..f722a7c42 100644 --- a/Classes/Validation/DvMetadataValidator.php +++ b/Classes/Validation/DvMetadataValidator.php @@ -107,7 +107,7 @@ protected function validateDvRights(): void $licenseNode = $this->createNodeListValidator(VH::XPATH_DVRIGHTS . '/dv:license') ->validateHasNoneOrOne() ->getFirstNode(); - if ($licenseNode && !in_array($licenseNode->nodeValue, array('pdm', 'cc0', 'cc-by', 'cc-by-sa', 'cc-by-nd', 'cc-by-nc', 'cc-by-nc-sa', 'cc-by-nc-nd', 'reserved'))) { + if ($licenseNode && !in_array($licenseNode->nodeValue, ['pdm', 'cc0', 'cc-by', 'cc-by-sa', 'cc-by-nd', 'cc-by-nc', 'cc-by-nc-sa', 'cc-by-nc-nd', 'reserved'])) { $this->createNodeValidator($licenseNode)->validateHasContentWithUrl(); } } @@ -128,7 +128,7 @@ protected function validateReference(\DOMNode $reference): void } } - private function validateNodeContent(string $expression, bool $optional = false): void + private function validateNodeContent(string $expression, bool $optional=false): void { $nodeListValidator = $this->createNodeListValidator($expression); diff --git a/Classes/Validation/Mets/AdministrativeMetadataValidator.php b/Classes/Validation/Mets/AdministrativeMetadataValidator.php index 71ef4baf3..9175b90ad 100644 --- a/Classes/Validation/Mets/AdministrativeMetadataValidator.php +++ b/Classes/Validation/Mets/AdministrativeMetadataValidator.php @@ -122,8 +122,8 @@ protected function validateRightsMetadataNode(\DOMNode $rightsMetadata): void ->getFirstNode(); $this->createNodeValidator($mpWrap) - ->validateHasAttributeWithValue('MDTYPE', array('OTHER')) - ->validateHasAttributeWithValue('OTHERMDTYPE', array('DVRIGHTS')); + ->validateHasAttributeWithValue('MDTYPE', ['OTHER']) + ->validateHasAttributeWithValue('OTHERMDTYPE', ['DVRIGHTS']); $this->createNodeListValidator('mets:xmlData[dv:rights]', $mpWrap) ->validateHasOne(); @@ -138,19 +138,19 @@ protected function validateRightsMetadataNode(\DOMNode $rightsMetadata): void */ protected function validateTechnicalMetadata(): void { - $technicalMetadata = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) + $technicalMd = $this->createNodeListValidator(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) ->getNodeList(); - foreach ($technicalMetadata as $technicalMetadataNode) { - $this->validateTechnicalMetadataNode($technicalMetadataNode); + foreach ($technicalMd as $technicalMdNode) { + $this->validateTechnicalMetadataNode($technicalMdNode); } } - protected function validateTechnicalMetadataNode(\DOMNode $technicalMetadata): void + protected function validateTechnicalMetadataNode(\DOMNode $technicalMd): void { - $this->createNodeValidator($technicalMetadata) + $this->createNodeValidator($technicalMd) ->validateHasUniqueId(); - $mdWrap = $this->createNodeListValidator('mets:mdWrap', $technicalMetadata) + $mdWrap = $this->createNodeListValidator('mets:mdWrap', $technicalMd) ->validateHasOne() ->getFirstNode(); diff --git a/Classes/Validation/Mets/DescriptiveMetadataValidator.php b/Classes/Validation/Mets/DescriptiveMetadataValidator.php index 027c39c1b..787a503e7 100644 --- a/Classes/Validation/Mets/DescriptiveMetadataValidator.php +++ b/Classes/Validation/Mets/DescriptiveMetadataValidator.php @@ -71,16 +71,19 @@ protected function validateDescriptiveMetadataSection(\DOMNode $descriptiveSecti ->getFirstNode(); $this->createNodeValidator($mdWrap) - ->validateHasAttributeWithValue('MDTYPE', array('MODS', 'TEIHDR')); + ->validateHasAttributeWithValue('MDTYPE', ['MODS', 'TEIHDR']); - if(!$mdWrap) { + if (!$mdWrap) { return; } // @phpstan-ignore-next-line $mdType = $mdWrap->getAttribute('MDTYPE'); if ($mdType == 'TEIHDR' || $mdType == 'MODS') { - $childNode = $mdType == 'TEIHDR' ? 'tei:teiHeader' : 'mods:mods'; + $childNode = 'mods:mods'; + if ($mdType == 'TEIHDR') { + $childNode = 'tei:teiHeader'; + } $this->createNodeListValidator('mets:xmlData[' . $childNode . ']', $mdWrap) ->validateHasOne(); } diff --git a/Classes/Validation/Mets/LogicalStructureValidator.php b/Classes/Validation/Mets/LogicalStructureValidator.php index 6d51ffa42..e2e5194b4 100644 --- a/Classes/Validation/Mets/LogicalStructureValidator.php +++ b/Classes/Validation/Mets/LogicalStructureValidator.php @@ -93,7 +93,7 @@ protected function validateExternalReferences(): void protected function validateExternalReference(\DOMNode $externalReference): void { $this->createNodeValidator($externalReference) - ->validateHasAttributeWithValue("LOCTYPE", array("URL", "PURL")) + ->validateHasAttributeWithValue("LOCTYPE", ["URL", "PURL"]) ->validateHasAttributeWithUrl("xlink:href"); } @@ -106,6 +106,5 @@ protected function validateExternalReference(\DOMNode $externalReference): void */ protected function validatePeriodicPublishingSequences(): void { - // TODO } } diff --git a/Classes/Validation/Mets/PhysicalStructureValidator.php b/Classes/Validation/Mets/PhysicalStructureValidator.php index 4878ed496..feed4e351 100644 --- a/Classes/Validation/Mets/PhysicalStructureValidator.php +++ b/Classes/Validation/Mets/PhysicalStructureValidator.php @@ -62,9 +62,9 @@ protected function validateStructuralElements(): void ->getFirstNode(); $this->createNodeValidator($node) - ->validateHasAttributeWithValue('TYPE', array('physSequence')); + ->validateHasAttributeWithValue('TYPE', ['physSequence']); - $structuralElements =$this->createNodeListValidator(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS) + $structuralElements = $this->createNodeListValidator(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS) ->validateHasAny() ->getNodeList(); foreach ($structuralElements as $structuralElement) { @@ -76,6 +76,6 @@ protected function validateStructuralElement(\DOMNode $structureElement): void { $this->createNodeValidator($structureElement) ->validateHasUniqueId() - ->validateHasAttributeWithValue("TYPE", array("page", "doublepage", "track")); + ->validateHasAttributeWithValue("TYPE", ["page", "doublepage", "track"]); } } diff --git a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php index afda9b1eb..1eb0d1a3f 100644 --- a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php +++ b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php @@ -212,7 +212,7 @@ protected function assertNoError(): void * @param string $context The context in error message * @return void */ - protected function assertErrorHasAny(string $expression, string $context = ''): void + protected function assertErrorHasAny(string $expression, string $context=''): void { $message = 'There must be at least one element that matches the XPath expression "' . $expression . '"'; if ($context != '') { @@ -228,7 +228,7 @@ protected function assertErrorHasAny(string $expression, string $context = ''): * @param string $context The context in error message * @return void */ - protected function assertErrorHasOne(string $expression, string $context = ''): void + protected function assertErrorHasOne(string $expression, string $context=''): void { $message = 'There must be an element that matches the XPath expression "' . $expression . '"'; if ($context != '') { @@ -244,7 +244,7 @@ protected function assertErrorHasOne(string $expression, string $context = ''): * @param string $context The context in error message * @return void */ - protected function assertErrorHasNoneOrOne(string $expression, string $context = ''): void + protected function assertErrorHasNoneOrOne(string $expression, string $context=''): void { $message = 'There must be no more than one element that matches the XPath expression "' . $expression . '"'; if ($context != '') { From 70cb8d909f67f5d21c032a55842842a5588684ee Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Thu, 9 Jan 2025 19:13:08 +0100 Subject: [PATCH 38/43] Codacy fixes --- Classes/Validation/Dom/DomNodeListValidator.php | 3 ++- Classes/Validation/Dom/DomNodeValidator.php | 2 -- Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php | 6 ++++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Classes/Validation/Dom/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php index 846ddbcae..c69db093f 100644 --- a/Classes/Validation/Dom/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -41,6 +41,7 @@ */ class DomNodeListValidator { + /** * @var string The expression of XPath query */ @@ -61,7 +62,7 @@ class DomNodeListValidator */ private Result $result; - public function __construct(DOMXPath $xpath, Result $result, string $expression, ?DOMNode $contextNode = null) + public function __construct(DOMXPath $xpath, Result $result, string $expression, ?DOMNode $contextNode=null) { $this->expression = $expression; $this->contextNode = $contextNode; diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index d1dde67a8..3d472fa14 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -40,7 +40,6 @@ */ class DomNodeValidator { - /** * @var DOMXPath The XPath of document to validate */ @@ -51,7 +50,6 @@ class DomNodeValidator */ private ?DOMNode $node; - /** * @var Result The result containing errors of validation */ diff --git a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php index 1eb0d1a3f..c4c2bda08 100644 --- a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php +++ b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php @@ -34,8 +34,14 @@ abstract class AbstractDomDocumentValidatorTest extends UnitTestCase { + /** + * @var AbstractDlfValidator + */ protected $validator; + /** + * @var DOMDocument + */ protected $doc; abstract protected function createValidator(): AbstractDlfValidator; From c567307e47b732b2b4206750b98d860f9c3d880c Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 10 Jan 2025 10:18:48 +0100 Subject: [PATCH 39/43] Improvements regarding codacy issues --- Classes/Validation/AbstactDomDocumentValidator.php | 4 ++-- Classes/Validation/Dom/DomNodeListValidator.php | 2 +- Classes/Validation/Dom/DomNodeValidator.php | 1 + Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Classes/Validation/AbstactDomDocumentValidator.php b/Classes/Validation/AbstactDomDocumentValidator.php index 23466fa05..f5c85b993 100644 --- a/Classes/Validation/AbstactDomDocumentValidator.php +++ b/Classes/Validation/AbstactDomDocumentValidator.php @@ -45,6 +45,8 @@ public function __construct() parent::__construct(DOMDocument::class); } + abstract public function isValidDocument(); + protected function isValid($value): void { $this->xpath = new DOMXPath($value); @@ -60,6 +62,4 @@ protected function createNodeValidator(?DOMNode $node): DomNodeValidator { return new DomNodeValidator($this->xpath, $this->result, $node); } - - public abstract function isValidDocument(); } diff --git a/Classes/Validation/Dom/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php index c69db093f..bdbd38b9c 100644 --- a/Classes/Validation/Dom/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -53,7 +53,7 @@ class DomNodeListValidator private ?DOMNode $contextNode; /** - * @var DOMNodeList|false|mixed The node list result of XPath query + * @var DOMNodeList|false The node list result of XPath query */ private DOMNodeList $nodeList; diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index 3d472fa14..e142e4e86 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -40,6 +40,7 @@ */ class DomNodeValidator { + /** * @var DOMXPath The XPath of document to validate */ diff --git a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php index c4c2bda08..991f5555f 100644 --- a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php +++ b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php @@ -34,6 +34,7 @@ abstract class AbstractDomDocumentValidatorTest extends UnitTestCase { + /** * @var AbstractDlfValidator */ From e47f3407495839e3d5b4b928978883b03abda717 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 10 Jan 2025 10:38:05 +0100 Subject: [PATCH 40/43] Improve type in documentation --- Classes/Validation/Dom/DomNodeListValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Validation/Dom/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php index bdbd38b9c..b431de536 100644 --- a/Classes/Validation/Dom/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -53,7 +53,7 @@ class DomNodeListValidator private ?DOMNode $contextNode; /** - * @var DOMNodeList|false The node list result of XPath query + * @var DOMNodeList The node list result of XPath query */ private DOMNodeList $nodeList; From a371c26755e5846f891b2f791801ad139401409e Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 10 Jan 2025 11:01:28 +0100 Subject: [PATCH 41/43] Renaming methods for codacy --- .../AbstractDomDocumentValidatorTest.php | 50 +++++++++---------- .../Validation/DvMetadataValidatorTest.php | 36 ++++++------- .../AdministrativeMetadataValidatorTest.php | 48 +++++++++--------- .../Mets/DescriptiveMetadataValidatorTest.php | 12 ++--- .../DigitalRepresentationValidatorTest.php | 28 +++++------ ...gLogicalPhysicalStructureValidatorTest.php | 8 +-- .../Mets/LogicalStructureValidatorTest.php | 22 ++++---- .../Mets/PhysicalStructureValidatorTest.php | 18 +++---- 8 files changed, 111 insertions(+), 111 deletions(-) diff --git a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php index 991f5555f..db5986431 100644 --- a/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php +++ b/Tests/Unit/Validation/AbstractDomDocumentValidatorTest.php @@ -62,7 +62,7 @@ public function setUp(): void */ public function testDocument() { - $this->assertNoError(); + $this->hasNoError(); } /** @@ -206,20 +206,20 @@ protected function getDomDocument(): DOMDocument * * @return void */ - protected function assertNoError(): void + protected function hasNoError(): void { $result = $this->validate(); $this->assertFalse($result->hasErrors()); } /** - * Assert validation error has any. + * Assert error of has any validation. * * @param string $expression The expression in error message * @param string $context The context in error message * @return void */ - protected function assertErrorHasAny(string $expression, string $context=''): void + protected function hasErrorAny(string $expression, string $context=''): void { $message = 'There must be at least one element that matches the XPath expression "' . $expression . '"'; if ($context != '') { @@ -229,13 +229,13 @@ protected function assertErrorHasAny(string $expression, string $context=''): vo } /** - * Assert validation error has one. + * Assert error of has one validation. * * @param string $expression The expression in error message * @param string $context The context in error message * @return void */ - protected function assertErrorHasOne(string $expression, string $context=''): void + protected function hasErrorOne(string $expression, string $context=''): void { $message = 'There must be an element that matches the XPath expression "' . $expression . '"'; if ($context != '') { @@ -245,13 +245,13 @@ protected function assertErrorHasOne(string $expression, string $context=''): vo } /** - * Assert validation error has none or one. + * Assert error of has none or one validation. * * @param string $expression The expression in error message * @param string $context The context in error message * @return void */ - protected function assertErrorHasNoneOrOne(string $expression, string $context=''): void + protected function hasErrorNoneOrOne(string $expression, string $context=''): void { $message = 'There must be no more than one element that matches the XPath expression "' . $expression . '"'; if ($context != '') { @@ -261,45 +261,45 @@ protected function assertErrorHasNoneOrOne(string $expression, string $context=' } /** - * Assert validation error has attribute. + * Assert error of has attribute validation. * * @param string $expression The expression in error message * @param string $name The attribute name * @return void */ - protected function assertErrorHasAttribute(string $expression, string $name): void + protected function hasErrorAttribute(string $expression, string $name): void { $this->validateAndAssertEquals('Mandatory "' . $name . '" attribute of "' . $expression . '" is missing.'); } /** - * Assert validation error has attribute with value. + * Assert error of has attribute with value validation. * * @param string $expression The expression in error message * @param string $name The attribute name * @param string $value The attribute value * @return void */ - protected function assertErrorHasAttributeWithValue(string $expression, string $name, string $value): void + protected function hasErrorAttributeWithValue(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not permissible.'); } /** - * Assert validation error has attribute with URL value. + * Assert error of has attribute with URL value validation. * * @param string $expression The expression in error message * @param string $name The attribute name * @param string $value The attribute value * @return void */ - protected function assertErrorHasAttributeWithUrl(string $expression, string $name, string $value): void + protected function hasErrorAttributeWithUrl(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('URL "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" is not valid.'); } /** - * Assert validation error has content with Email. + * Assert error of has attribute reference to one validation. * * @param string $expression The expression in error message * @param string $name The attribute name @@ -307,56 +307,56 @@ protected function assertErrorHasAttributeWithUrl(string $expression, string $na * @param string $targetExpression The target context expression * @return void */ - protected function assertErrorHasAttributeRefToOne(string $expression, string $name, string $value, string $targetExpression): void + protected function hasErrorAttributeRefToOne(string $expression, string $name, string $value, string $targetExpression): void { $this->validateAndAssertEquals('Value "' . $value . '" in the "' . $name . '" attribute of "' . $expression . '" must reference one element under XPath expression "' . $targetExpression); } /** - * Assert validation error has content with Email. + * Assert error of has content with Email validation. * * @param string $expression The expression in error message * @param string $value The content value * @return void */ - protected function assertErrorHasContentWithEmail(string $expression, string $value): void + protected function hasErrorContentWithEmail(string $expression, string $value): void { $this->validateAndAssertEquals('Email "' . $value . '" in the content of "' . $expression . '" is not valid.'); } /** - * Assert validation error has content with URL. + * Assert error of has content with URL. * * @param string $expression The expression in error message * @param string $value The content value * @return void */ - protected function assertErrorHasContentWithUrl(string $expression, string $value): void + protected function hasErrorContentWithUrl(string $expression, string $value): void { $this->validateAndAssertEquals('URL "' . $value . '" in the content of "' . $expression . '" is not valid.'); } /** - * Assert validation error has unique identifier. + * Assert error of has unique identifier. * * @param string $expression The expression in error message * @param string $value The attribute value * @return void */ - protected function assertErrorHasUniqueId(string $expression, string $value): void + protected function hasErrorUniqueId(string $expression, string $value): void { - $this->assertErrorHasUniqueAttribute($expression, 'ID', $value); + $this->hasErrorUniqueAttribute($expression, 'ID', $value); } /** - * Assert validation error has unique attribute with value. + * Assert error of has unique attribute with value. * * @param string $expression The expression in error message * @param string $name The attribute name * @param string $value The attribute value * @return void */ - protected function assertErrorHasUniqueAttribute(string $expression, string $name, string $value): void + protected function hasErrorUniqueAttribute(string $expression, string $name, string $value): void { $this->validateAndAssertEquals('"' . $name . '" attribute with value "' . $value . '" of "' . $expression . '" already exists.'); } diff --git a/Tests/Unit/Validation/DvMetadataValidatorTest.php b/Tests/Unit/Validation/DvMetadataValidatorTest.php index 61d5354fa..60afb738f 100644 --- a/Tests/Unit/Validation/DvMetadataValidatorTest.php +++ b/Tests/Unit/Validation/DvMetadataValidatorTest.php @@ -39,7 +39,7 @@ class DvMetadataValidatorTest extends AbstractDomDocumentValidatorTest public function testDvRights(): void { $this->removeNodes(VH::XPATH_DVRIGHTS); - $this->assertErrorHasOne(VH::XPATH_DVRIGHTS); + $this->hasErrorOne(VH::XPATH_DVRIGHTS); } /** @@ -51,30 +51,30 @@ public function testDvRights(): void public function testDvRightsSubelements(): void { $this->removeNodes(VH::XPATH_DVRIGHTS . '/dv:owner'); - $this->assertErrorHasOne(VH::XPATH_DVRIGHTS . '/dv:owner'); + $this->hasErrorOne(VH::XPATH_DVRIGHTS . '/dv:owner'); $this->resetDocument(); $this->assertNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerLogo', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerLogo'); $this->assertNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerSiteURL', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerSiteURL'); $this->assertNodeContent(VH::XPATH_DVRIGHTS . '/dv:ownerContact', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact'); $this->setContentValue(VH::XPATH_DVRIGHTS . '/dv:ownerContact', 'mailto:Test'); - $this->assertErrorHasContentWithEmail(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact', 'mailto:Test'); + $this->hasErrorContentWithEmail(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:ownerContact', 'mailto:Test'); $this->resetDocument(); $this->addChildNodeWithNamespace(VH::XPATH_DVRIGHTS, VH::NAMESPACE_DV, 'dv:aggregator'); - $this->assertErrorHasNoneOrOne(VH::XPATH_DVRIGHTS . '/dv:aggregator'); + $this->hasErrorNoneOrOne(VH::XPATH_DVRIGHTS . '/dv:aggregator'); $this->resetDocument(); $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:aggregatorLogo', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorLogo'); $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:aggregatorSiteURL', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:aggregatorSiteURL'); $this->addChildNodeWithNamespace(VH::XPATH_DVRIGHTS, VH::NAMESPACE_DV, 'dv:sponsor'); - $this->assertErrorHasNoneOrOne(VH::XPATH_DVRIGHTS . '/dv:sponsor'); + $this->hasErrorNoneOrOne(VH::XPATH_DVRIGHTS . '/dv:sponsor'); $this->resetDocument(); $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:sponsorLogo', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorLogo'); $this->assertOptionalNodeContent(VH::XPATH_DVRIGHTS, 'dv:sponsorSiteURL', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:sponsorSiteURL'); $this->setContentValue(VH::XPATH_DVRIGHTS . '/dv:license', 'Test'); - $this->assertErrorHasContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:license', 'Test'); + $this->hasErrorContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap/mets:xmlData/dv:rights/dv:license', 'Test'); } /** @@ -85,7 +85,7 @@ public function testDvRightsSubelements(): void public function testDvLinks(): void { $this->removeNodes(VH::XPATH_DVLINKS); - $this->assertErrorHasOne(VH::XPATH_DVLINKS); + $this->hasErrorOne(VH::XPATH_DVLINKS); } /** @@ -97,53 +97,53 @@ public function testDvLinks(): void public function testDvLinksSubelements(): void { $this->removeNodes(VH::XPATH_DVLINKS . '/dv:reference'); - $this->assertErrorHasAny(VH::XPATH_DVLINKS . '/dv:reference'); + $this->hasErrorAny(VH::XPATH_DVLINKS . '/dv:reference'); $this->resetDocument(); // if there are multiple `dv:references`, the `linktext` attribute must be present. $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:reference'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:reference[1]', 'linktext'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:reference[1]', 'linktext'); $this->resetDocument(); $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:presentation'); - $this->assertErrorHasNoneOrOne(VH::XPATH_DVLINKS . '/dv:presentation'); + $this->hasErrorNoneOrOne(VH::XPATH_DVLINKS . '/dv:presentation'); $this->resetDocument(); $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:sru'); - $this->assertErrorHasNoneOrOne(VH::XPATH_DVLINKS . '/dv:sru'); + $this->hasErrorNoneOrOne(VH::XPATH_DVLINKS . '/dv:sru'); $this->resetDocument(); $this->setContentValue(VH::XPATH_DVLINKS . '/dv:sru', 'Test'); - $this->assertErrorHasContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:sru', 'Test'); + $this->hasErrorContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:sru', 'Test'); $this->resetDocument(); $this->addChildNodeWithNamespace(VH::XPATH_DVLINKS, VH::NAMESPACE_DV, 'dv:iiif'); - $this->assertErrorHasNoneOrOne(VH::XPATH_DVLINKS . '/dv:iiif'); + $this->hasErrorNoneOrOne(VH::XPATH_DVLINKS . '/dv:iiif'); $this->resetDocument(); $this->setContentValue(VH::XPATH_DVLINKS . '/dv:iiif', 'Test'); - $this->assertErrorHasContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:iiif', 'Test'); + $this->hasErrorContentWithUrl(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap/mets:xmlData/dv:links/dv:iiif', 'Test'); } protected function assertNodeContent(string $expression, string $expectedExpression): void { $this->removeNodes($expression); - $this->assertErrorHasOne($expression); + $this->hasErrorOne($expression); $this->resetDocument(); $this->setContentValue($expression, 'Test'); - $this->assertErrorHasContentWithUrl($expectedExpression, 'Test'); + $this->hasErrorContentWithUrl($expectedExpression, 'Test'); $this->resetDocument(); } protected function assertOptionalNodeContent(string $expression, string $name, string $expectedExpression): void { $this->addChildNodeWithNamespace($expression, VH::NAMESPACE_DV, $name); - $this->assertErrorHasNoneOrOne($expression . '/' . $name); + $this->hasErrorNoneOrOne($expression . '/' . $name); $this->resetDocument(); $this->setContentValue($expression . '/' . $name, 'Test'); - $this->assertErrorHasContentWithUrl($expectedExpression, 'Test'); + $this->hasErrorContentWithUrl($expectedExpression, 'Test'); $this->resetDocument(); } diff --git a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php index 594e976ec..e470c09b9 100644 --- a/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/AdministrativeMetadataValidatorTest.php @@ -39,18 +39,18 @@ class AdministrativeMetadataValidatorTest extends AbstractDomDocumentValidatorTe public function testAdministrativeMetadata(): void { $this->removeNodes(VH::XPATH_ADMINISTRATIVE_METADATA); - $this->assertErrorHasAny(VH::XPATH_ADMINISTRATIVE_METADATA); + $this->hasErrorAny(VH::XPATH_ADMINISTRATIVE_METADATA); $this->resetDocument(); $this->removeNodes(VH::XPATH_ADMINISTRATIVE_METADATA . '/mets:rightsMD'); - $this->assertErrorHasOne(VH::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]'); + $this->hasErrorOne(VH::XPATH_ADMINISTRATIVE_METADATA . '[mets:rightsMD and mets:digiprovMD]'); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_METADATA), 'DMDLOG_0001'); + $this->hasErrorUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_METADATA), 'DMDLOG_0001'); $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_METADATA, 'ID'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_METADATA), 'ID'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_METADATA), 'ID'); } /** @@ -61,29 +61,29 @@ public function testAdministrativeMetadata(): void public function testDigitalProvenanceMetadataStructure(): void { $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA), 'DMDLOG_0001'); + $this->hasErrorUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA), 'DMDLOG_0001'); $this->resetDocument(); $this->removeNodes(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA)); + $this->hasErrorOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA)); $this->resetDocument(); $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->hasErrorAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); $this->resetDocument(); $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->hasErrorAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); $this->resetDocument(); $this->removeNodes(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA . '/mets:mdWrap/mets:xmlData/dv:links'); - $this->assertErrorHasOne('mets:xmlData[dv:links]', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap'); + $this->hasErrorOne('mets:xmlData[dv:links]', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_DIGIPROV_METADATA) . '/mets:mdWrap'); } /** @@ -94,29 +94,29 @@ public function testDigitalProvenanceMetadataStructure(): void public function testRightsMetadataStructure(): void { $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA), 'DMDLOG_0001'); + $this->hasErrorUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA), 'DMDLOG_0001'); $this->resetDocument(); $this->removeNodes(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA)); + $this->hasErrorOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA)); $this->resetDocument(); $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->hasErrorAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'MDTYPE', 'Test'); $this->resetDocument(); $this->removeAttribute(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); + $this->hasErrorAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE', 'Test'); $this->resetDocument(); $this->removeNodes(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA . '/mets:mdWrap/mets:xmlData/dv:rights'); - $this->assertErrorHasOne('mets:xmlData[dv:rights]', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap'); + $this->hasErrorOne('mets:xmlData[dv:rights]', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_RIGHTS_METADATA) . '/mets:mdWrap'); } /** @@ -128,22 +128,22 @@ public function testRightsMetadataStructure(): void public function testTechnicalMetadataStructure(): void { $this->addChildNodeWithNamespace(VH::XPATH_ADMINISTRATIVE_METADATA, VH::NAMESPACE_METS, 'mets:techMD'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'ID'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'ID'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'DMDLOG_0001'); + $this->hasErrorUniqueId(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA), 'DMDLOG_0001'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, 'ID', 'TECH_0001'); - $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA)); + $this->hasErrorOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA)); $this->addChildNodeWithNamespace(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA, VH::NAMESPACE_METS, 'mets:mdWrap'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'MDTYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'MDTYPE'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'MDTYPE', ''); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap', 'OTHERMDTYPE'); $this->setAttributeValue(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA . '/mets:mdWrap', 'OTHERMDTYPE', ''); - $this->assertErrorHasOne('mets:xmlData', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap'); + $this->hasErrorOne('mets:xmlData', VH::trimDoubleSlash(VH::XPATH_ADMINISTRATIVE_TECHNICAL_METADATA) . '/mets:mdWrap'); } protected function createValidator(): AbstractDlfValidator diff --git a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php index c566d203e..622983b0a 100644 --- a/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php +++ b/Tests/Unit/Validation/Mets/DescriptiveMetadataValidatorTest.php @@ -39,15 +39,15 @@ class DescriptiveMetadataValidatorTest extends AbstractDomDocumentValidatorTest public function testDescriptiveMetadata(): void { $this->removeNodes(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); - $this->assertErrorHasAny(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->hasErrorAny(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); $this->resetDocument(); $this->removeNodes(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); - $this->assertErrorHasOne(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->hasErrorOne(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'DMDID', 'Test'); - $this->assertErrorHasAttributeRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); + $this->hasErrorAttributeRefToOne('/mets:mets/mets:structMap[1]/mets:div', 'DMDID', 'Test', VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS); } /** @@ -58,15 +58,15 @@ public function testDescriptiveMetadata(): void public function testEmbeddedMetadata(): void { $this->removeNodes(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap'); - $this->assertErrorHasOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS)); + $this->hasErrorOne('mets:mdWrap', VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS)); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap', 'MDTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap', 'MDTYPE', 'Test'); + $this->hasErrorAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap', 'MDTYPE', 'Test'); $this->resetDocument(); $this->removeNodes(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS . '/mets:mdWrap/mets:xmlData/mods:mods'); - $this->assertErrorHasOne('mets:xmlData[mods:mods]', VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap'); + $this->hasErrorOne('mets:xmlData[mods:mods]', VH::trimDoubleSlash(VH::XPATH_DESCRIPTIVE_METADATA_SECTIONS) . '/mets:mdWrap'); } protected function createValidator(): AbstractDlfValidator diff --git a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php index 23efc5582..21198fc43 100644 --- a/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php +++ b/Tests/Unit/Validation/Mets/DigitalRepresentationValidatorTest.php @@ -40,16 +40,16 @@ class DigitalRepresentationValidatorTest extends AbstractDomDocumentValidatorTes public function testFileSections(): void { $this->addChildNodeWithNamespace('/mets:mets', VH::NAMESPACE_METS, 'mets:fileSec'); - $this->assertErrorHasNoneOrOne(VH::XPATH_FILE_SECTIONS); + $this->hasErrorNoneOrOne(VH::XPATH_FILE_SECTIONS); $this->resetDocument(); $this->removeNodes(VH::XPATH_FILE_SECTIONS); - $this->assertErrorHasOne(VH::XPATH_FILE_SECTIONS); + $this->hasErrorOne(VH::XPATH_FILE_SECTIONS); $this->resetDocument(); $this->removeNodes(VH::XPATH_PHYSICAL_STRUCTURES); $this->removeNodes(VH::XPATH_FILE_SECTIONS); - $this->assertNoError(); + $this->hasNoError(); } /** @@ -60,15 +60,15 @@ public function testFileSections(): void public function testFileGroups(): void { $this->removeNodes(VH::XPATH_FILE_SECTION_GROUPS); - $this->assertErrorHasAny(VH::XPATH_FILE_SECTION_GROUPS); + $this->hasErrorAny(VH::XPATH_FILE_SECTION_GROUPS); $this->resetDocument(); $this->removeNodes(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); - $this->assertErrorHasOne(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); + $this->hasErrorOne(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="DEFAULT"]'); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_FILE_SECTION_GROUPS . '[@USE="THUMBS"]', 'USE', 'DEFAULT'); - $this->assertErrorHasUniqueAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]', 'USE', 'DEFAULT'); + $this->hasErrorUniqueAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]', 'USE', 'DEFAULT'); } /** @@ -79,34 +79,34 @@ public function testFileGroups(): void public function testFiles(): void { $this->removeNodes(VH::XPATH_FILE_SECTION_FILES); - $this->assertErrorHasAny(VH::XPATH_FILE_SECTION_FILES); + $this->hasErrorAny(VH::XPATH_FILE_SECTION_FILES); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_FILE_SECTION_FILES, 'ID', 'DMDLOG_0001'); - $this->assertErrorHasUniqueId(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'DMDLOG_0001'); + $this->hasErrorUniqueId(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'DMDLOG_0001'); $this->resetDocument(); $this->removeAttribute(VH::XPATH_FILE_SECTION_FILES, 'MIMETYPE'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'MIMETYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file', 'MIMETYPE'); $this->resetDocument(); $this->removeNodes(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat'); - $this->assertErrorHasOne('mets:FLocat', VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file'); + $this->hasErrorOne('mets:FLocat', VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file'); $this->resetDocument(); $this->removeAttribute(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE'); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'LOCTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE', 'Test'); + $this->hasErrorAttributeWithValue(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'LOCTYPE', 'Test'); $this->resetDocument(); $this->removeAttribute(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href'); - $this->assertErrorHasAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href'); + $this->hasErrorAttribute(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href'); $this->setAttributeValue(VH::XPATH_FILE_SECTION_FILES . '/mets:FLocat', 'xlink:href', 'Test'); - $this->assertErrorHasAttributeWithUrl(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href', 'Test'); + $this->hasErrorAttributeWithUrl(VH::trimDoubleSlash(VH::XPATH_FILE_SECTION_GROUPS) . '[1]/mets:file/mets:FLocat', 'xlink:href', 'Test'); } protected function createValidator(): AbstractDlfValidator diff --git a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php index 7342e92b8..22e4bd273 100644 --- a/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LinkingLogicalPhysicalStructureValidatorTest.php @@ -40,21 +40,21 @@ class LinkingLogicalPhysicalStructureValidatorTest extends AbstractDomDocumentVa public function testMultipleStructLinks(): void { $this->addChildNodeWithNamespace('/mets:mets', VH::NAMESPACE_METS, 'mets:structLink'); - $this->assertErrorHasNoneOrOne(VH::XPATH_STRUCT_LINK); + $this->hasErrorNoneOrOne(VH::XPATH_STRUCT_LINK); } public function testLinkElements(): void { $this->removeNodes(VH::XPATH_STRUCT_LINK_ELEMENTS); - $this->assertErrorHasAny(VH::XPATH_STRUCT_LINK_ELEMENTS); + $this->hasErrorAny(VH::XPATH_STRUCT_LINK_ELEMENTS); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:from', 'Test'); - $this->assertErrorHasAttributeRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:from', 'Test', VH::XPATH_LOGICAL_STRUCTURES); + $this->hasErrorAttributeRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:from', 'Test', VH::XPATH_LOGICAL_STRUCTURES); $this->resetDocument(); $this->setAttributeValue(VH::XPATH_STRUCT_LINK_ELEMENTS, 'xlink:to', 'Test'); - $this->assertErrorHasAttributeRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:to', 'Test', VH::XPATH_PHYSICAL_STRUCTURES); + $this->hasErrorAttributeRefToOne(VH::trimDoubleSlash(VH::XPATH_STRUCT_LINK_ELEMENTS), 'xlink:to', 'Test', VH::XPATH_PHYSICAL_STRUCTURES); } protected function createValidator(): AbstractDlfValidator diff --git a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php index 78742a893..0ba64ce23 100644 --- a/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/LogicalStructureValidatorTest.php @@ -39,7 +39,7 @@ class LogicalStructureValidatorTest extends AbstractDomDocumentValidatorTest public function testNotExistingLogicalStructureElement(): void { $this->removeNodes(VH::XPATH_LOGICAL_STRUCTURES); - $this->assertErrorHasAny(VH::XPATH_LOGICAL_STRUCTURES); + $this->hasErrorAny(VH::XPATH_LOGICAL_STRUCTURES); } /** @@ -49,24 +49,24 @@ public function testNotExistingLogicalStructureElement(): void public function testStructuralElements(): void { $this->removeNodes(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); - $this->assertErrorHasAny(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); + $this->hasErrorAny(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); $this->removeAttribute(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'ID'); - $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'ID'); + $this->hasErrorAttribute('/mets:mets/mets:structMap[1]/mets:div', 'ID'); $this->resetDocument(); $node = $this->doc->createElementNS(VH::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'LOG_0001'); $this->addChildNode(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, $node); - $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[1]/mets:div', 'LOG_0001'); + $this->hasErrorUniqueId('/mets:mets/mets:structMap[1]/mets:div', 'LOG_0001'); $this->resetDocument(); $this->removeAttribute(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div', 'TYPE'); + $this->hasErrorAttribute('/mets:mets/mets:structMap[1]/mets:div', 'TYPE'); $this->setAttributeValue(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div', 'TYPE', 'Test'); + $this->hasErrorAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div', 'TYPE', 'Test'); } /** @@ -78,20 +78,20 @@ public function testExternalReference(): void { $this->addChildNodeWithNamespace(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, VH::NAMESPACE_METS, 'mets:mptr'); $this->addChildNodeWithNamespace(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, VH::NAMESPACE_METS, 'mets:mptr'); - $this->assertErrorHasNoneOrOne(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES); + $this->hasErrorNoneOrOne(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES); $this->resetDocument(); $this->addChildNodeWithNamespace(VH::XPATH_LOGICAL_STRUCTURAL_ELEMENTS, VH::NAMESPACE_METS, 'mets:mptr'); - $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE'); + $this->hasErrorAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE'); $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); + $this->hasErrorAttributeWithValue('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'LOCTYPE', 'Test'); $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'LOCTYPE', 'URL'); - $this->assertErrorHasAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href'); + $this->hasErrorAttribute('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href'); $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'Test'); - $this->assertErrorHasAttributeWithUrl('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href', 'Test'); + $this->hasErrorAttributeWithUrl('/mets:mets/mets:structMap[1]/mets:div/mets:mptr', 'xlink:href', 'Test'); $this->setAttributeValue(VH::XPATH_LOGICAL_EXTERNAL_REFERENCES, 'xlink:href', 'http://example.com/periodical.xml'); $result = $this->validate(); diff --git a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php index d0fc41af9..70878537a 100644 --- a/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php +++ b/Tests/Unit/Validation/Mets/PhysicalStructureValidatorTest.php @@ -42,7 +42,7 @@ public function testMultiplePhysicalDivisions(): void $node = $this->doc->createElementNS(VH::NAMESPACE_METS, 'mets:structMap'); $node->setAttribute('TYPE', 'PHYSICAL'); $this->addChildNode('/mets:mets', $node); - $this->assertErrorHasNoneOrOne(VH::XPATH_PHYSICAL_STRUCTURES); + $this->hasErrorNoneOrOne(VH::XPATH_PHYSICAL_STRUCTURES); } /** @@ -54,35 +54,35 @@ public function testMultiplePhysicalDivisions(): void public function testStructuralElements(): void { $this->removeNodes(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); - $this->assertErrorHasOne(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); + $this->hasErrorOne(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE); $this->resetDocument(); $this->removeAttribute(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div', 'TYPE'); + $this->hasErrorAttribute('/mets:mets/mets:structMap[2]/mets:div', 'TYPE'); $this->setAttributeValue(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENT_SEQUENCE, 'TYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div', 'TYPE', 'Test'); + $this->hasErrorAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div', 'TYPE', 'Test'); $this->resetDocument(); $this->removeNodes(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); - $this->assertErrorHasAny(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); + $this->hasErrorAny(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS); $this->resetDocument(); $this->removeAttribute(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'ID'); - $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'ID'); + $this->hasErrorAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'ID'); $this->resetDocument(); $node = $this->doc->createElementNS(VH::NAMESPACE_METS, 'mets:div'); $node->setAttribute('ID', 'PHYS_0001'); $this->addChildNode('//mets:structMap[@TYPE="PHYSICAL"]/mets:div', $node); - $this->assertErrorHasUniqueId('/mets:mets/mets:structMap[2]/mets:div/mets:div[1]', 'PHYS_0001'); + $this->hasErrorUniqueId('/mets:mets/mets:structMap[2]/mets:div/mets:div[1]', 'PHYS_0001'); $this->resetDocument(); $this->removeAttribute(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE'); - $this->assertErrorHasAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE'); + $this->hasErrorAttribute('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE'); $this->setAttributeValue(VH::XPATH_PHYSICAL_STRUCTURAL_ELEMENTS, 'TYPE', 'Test'); - $this->assertErrorHasAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE', 'Test'); + $this->hasErrorAttributeWithValue('/mets:mets/mets:structMap[2]/mets:div/mets:div', 'TYPE', 'Test'); } protected function createValidator(): AbstractDlfValidator From 9063ba570117a3f0b94a413261d5629921d7043f Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 10 Jan 2025 11:21:17 +0100 Subject: [PATCH 42/43] Set unique error codes --- Classes/Validation/Dom/DomNodeListValidator.php | 10 +++++----- Classes/Validation/Dom/DomNodeValidator.php | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Classes/Validation/Dom/DomNodeListValidator.php b/Classes/Validation/Dom/DomNodeListValidator.php index b431de536..479add2f9 100644 --- a/Classes/Validation/Dom/DomNodeListValidator.php +++ b/Classes/Validation/Dom/DomNodeListValidator.php @@ -109,7 +109,7 @@ public function getNodeList(): DOMNodeList public function validateHasAny(): DomNodeListValidator { if (!$this->nodeList->length > 0) { - $this->addError('There must be at least one element'); + $this->addError('There must be at least one element', 1736504345); } return $this; } @@ -122,7 +122,7 @@ public function validateHasAny(): DomNodeListValidator public function validateHasOne(): DomNodeListValidator { if ($this->nodeList->length != 1) { - $this->addError('There must be an element'); + $this->addError('There must be an element', 1736504354); } return $this; } @@ -135,17 +135,17 @@ public function validateHasOne(): DomNodeListValidator public function validateHasNoneOrOne(): DomNodeListValidator { if (!($this->nodeList->length == 0 || $this->nodeList->length == 1)) { - $this->addError('There must be no more than one element'); + $this->addError('There must be no more than one element', 1736504361); } return $this; } - private function addError(string $prefix): void + private function addError(string $prefix, int $code): void { $message = $prefix . ' that matches the XPath expression "' . $this->expression . '"'; if ($this->contextNode) { $message .= ' under "' . $this->contextNode->getNodePath() . '"'; } - $this->result->addError(new Error($message, 23)); + $this->result->addError(new Error($message, $code)); } } diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index e142e4e86..b77b472df 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -81,7 +81,7 @@ public function validateHasContentWithEmail(): DomNodeValidator } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { - $this->result->addError(new Error('Email "' . $this->node->nodeValue . '" in the content of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); + $this->result->addError(new Error('Email "' . $this->node->nodeValue . '" in the content of "' . $this->node->getNodePath() . '" is not valid.', 1736504169)); } return $this; @@ -99,7 +99,7 @@ public function validateHasContentWithUrl(): DomNodeValidator } if (!filter_var($this->node->nodeValue, FILTER_VALIDATE_URL)) { - $this->result->addError(new Error('URL "' . $this->node->nodeValue . '" in the content of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); + $this->result->addError(new Error('URL "' . $this->node->nodeValue . '" in the content of "' . $this->node->getNodePath() . '" is not valid.', 1736504177)); } return $this; @@ -125,7 +125,7 @@ public function validateHasAttributeWithUrl(string $name): DomNodeValidator // @phpstan-ignore-next-line $value = $this->node->getAttribute($name); if (!filter_var($value, FILTER_VALIDATE_URL)) { - $this->result->addError(new Error('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not valid.', 1724234607)); + $this->result->addError(new Error('URL "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not valid.', 1736504189)); } return $this; @@ -152,7 +152,7 @@ public function validateHasAttributeWithValue(string $name, array $values): DomN // @phpstan-ignore-next-line $value = $this->node->getAttribute($name); if (!in_array($value, $values)) { - $this->result->addError(new Error('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not permissible.', 1724234607)); + $this->result->addError(new Error('Value "' . $value . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is not permissible.', 1736504197)); } return $this; @@ -179,7 +179,7 @@ public function validateHasUniqueAttribute(string $name, string $contextExpressi // @phpstan-ignore-next-line $value = $this->node->getAttribute($name); if ($this->xpath->query($contextExpression . '[@' . $name . '="' . $value . '"]')->length > 1) { - $this->result->addError(new Error('"' . $name . '" attribute with value "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1724234607)); + $this->result->addError(new Error('"' . $name . '" attribute with value "' . $value . '" of "' . $this->node->getNodePath() . '" already exists.', 1736504203)); } return $this; @@ -210,7 +210,7 @@ public function validateHasAttribute(string $name): DomNodeValidator // @phpstan-ignore-next-line if (!$this->node->hasAttribute($name)) { - $this->result->addError(new Error('Mandatory "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is missing.', 1724234607)); + $this->result->addError(new Error('Mandatory "' . $name . '" attribute of "' . $this->node->getNodePath() . '" is missing.', 1736504217)); } return $this; } @@ -243,7 +243,7 @@ public function validateHasReferenceToId(string $name, string $targetExpression) } if ($foundElements !== 1) { - $this->result->addError(new Error('Value "' . $identifier . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" must reference one element under XPath expression "' . $targetExpression, 1724234607)); + $this->result->addError(new Error('Value "' . $identifier . '" in the "' . $name . '" attribute of "' . $this->node->getNodePath() . '" must reference one element under XPath expression "' . $targetExpression, 1736504228)); } return $this; From 1da107a9761b88b346d8f008d15257d3fe5e3b39 Mon Sep 17 00:00:00 2001 From: Markus Weigelt Date: Fri, 10 Jan 2025 11:22:01 +0100 Subject: [PATCH 43/43] Remove dot --- Classes/Validation/Dom/DomNodeValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Validation/Dom/DomNodeValidator.php b/Classes/Validation/Dom/DomNodeValidator.php index b77b472df..7f27d0646 100644 --- a/Classes/Validation/Dom/DomNodeValidator.php +++ b/Classes/Validation/Dom/DomNodeValidator.php @@ -47,7 +47,7 @@ class DomNodeValidator private DOMXPath $xpath; /** - * @var DOMNode|null The node to validate. + * @var DOMNode|null The node to validate */ private ?DOMNode $node;