From c1a030f79f3aa5d3dbd7de10634739d4eafb680c Mon Sep 17 00:00:00 2001 From: Dan Church Date: Tue, 12 Jul 2022 11:47:00 -0500 Subject: [PATCH 1/3] Remove tag ordering restriction Let the document specify the tags immediately under in any order. --- drafts/v2.1/ComicInfo.xsd | 4 ++-- schema/v1.0/ComicInfo.xsd | 4 ++-- schema/v2.0/ComicInfo.xsd | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drafts/v2.1/ComicInfo.xsd b/drafts/v2.1/ComicInfo.xsd index c44a561..261f117 100644 --- a/drafts/v2.1/ComicInfo.xsd +++ b/drafts/v2.1/ComicInfo.xsd @@ -2,7 +2,7 @@ - + @@ -44,7 +44,7 @@ - + diff --git a/schema/v1.0/ComicInfo.xsd b/schema/v1.0/ComicInfo.xsd index 556c3a0..c4e2319 100644 --- a/schema/v1.0/ComicInfo.xsd +++ b/schema/v1.0/ComicInfo.xsd @@ -2,7 +2,7 @@ - + @@ -32,7 +32,7 @@ - + diff --git a/schema/v2.0/ComicInfo.xsd b/schema/v2.0/ComicInfo.xsd index 244a989..0fa3a10 100644 --- a/schema/v2.0/ComicInfo.xsd +++ b/schema/v2.0/ComicInfo.xsd @@ -2,7 +2,7 @@ - + @@ -41,7 +41,7 @@ - + From f90f78b504d52edd78cf6d3535d45a5b9d3c43d4 Mon Sep 17 00:00:00 2001 From: Dan Church Date: Tue, 12 Jul 2022 15:44:43 -0500 Subject: [PATCH 2/3] CI: Add pass-fail validation testing for documents --- .github/workflows/documents.yml | 23 ++ tests/README-tests.md | 35 +++ tests/all/invalid/invalid-minimal.xml | 6 + .../valid-minimal-with-strict-ordering.xml | 5 + tests/run-tests.sh | 257 ++++++++++++++++++ 5 files changed, 326 insertions(+) create mode 100644 .github/workflows/documents.yml create mode 100644 tests/README-tests.md create mode 100644 tests/all/invalid/invalid-minimal.xml create mode 100644 tests/all/valid/valid-minimal-with-strict-ordering.xml create mode 100755 tests/run-tests.sh diff --git a/.github/workflows/documents.yml b/.github/workflows/documents.yml new file mode 100644 index 0000000..4fb04ae --- /dev/null +++ b/.github/workflows/documents.yml @@ -0,0 +1,23 @@ +name: XML Document Validation Tests + +on: + push: + paths: + - '**.xsd' + - '**.xml' + pull_request: + paths: + - '**.xsd' + - '**.xml' + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: apt-get update + run: sudo apt-get update -y + - name: Install xmllint + run: sudo apt-get install -y libxml2-utils + - name: Run tests + run: ./tests/run-tests.sh --color=never diff --git a/tests/README-tests.md b/tests/README-tests.md new file mode 100644 index 0000000..c99982c --- /dev/null +++ b/tests/README-tests.md @@ -0,0 +1,35 @@ +Put XML files here that should either pass or fail validation against the +XSD schema. + +## Testing All Versions + +For files that should validate against every version of the schema, use the +`all` directory. + +- `tests/all/valid/` +- `tests/all/invalid/` + +For example: + +- `tests/all/valid/foo.xml` should **PASS** validation. It will be validated + against every version of the schema, and the tests will fail if it does not + validate. +- `tests/all/invalid/bar.xml` should **FAIL** validation. It will be validated + against every version of the schema, and the tests will fail if it validates + as error-free. + +## Testing Individual Versions + +For individual versions of the XSD, use the following structure: + +- `tests//valid/` +- `tests//invalid/` + +For example: + +- `tests/v2.1/valid/foo.xml` should **PASS** validation. It will be validated + against version 2.1 of the schema, and the tests will fail if it does not + validate. +- `tests/v2.1/invalid/bar.xml` should **FAIL** validation. It will be validated + against version 2.1 of the schema, and the tests will fail if it validates as + error-free. diff --git a/tests/all/invalid/invalid-minimal.xml b/tests/all/invalid/invalid-minimal.xml new file mode 100644 index 0000000..68bed26 --- /dev/null +++ b/tests/all/invalid/invalid-minimal.xml @@ -0,0 +1,6 @@ + + Title 1 + Series 1 + Number 1 + Title 1 + diff --git a/tests/all/valid/valid-minimal-with-strict-ordering.xml b/tests/all/valid/valid-minimal-with-strict-ordering.xml new file mode 100644 index 0000000..9ded032 --- /dev/null +++ b/tests/all/valid/valid-minimal-with-strict-ordering.xml @@ -0,0 +1,5 @@ + + Title 1 + Series 1 + Number 1 + diff --git a/tests/run-tests.sh b/tests/run-tests.sh new file mode 100755 index 0000000..67e48ce --- /dev/null +++ b/tests/run-tests.sh @@ -0,0 +1,257 @@ +#!/bin/bash +# vi: et sts=4 sw=4 ts=4 + +REPO_ROOT=${0%/*}/.. +SCHEMA_ROOT_DIRS=( + "$REPO_ROOT/schema" + "$REPO_ROOT/drafts" +) +TESTS_DIR=${0%/*} + +GREEN=$'\e[1;32m' +RED=$'\e[1;31m' +YELLOW=$'\e[1;33m' +RESET=$'\e[0m' +COLOR=auto +FAIL_ON_WARNINGS=1 + +parse_args() { + ARGS=() + local NO_MORE_FLAGS + NO_MORE_FLAGS=0 + for ARG; do + # Assume arguments that don't begin with a - are supposed to be files + # or other operands + # (currently ignored) + if [[ $NO_MORE_FLAGS -eq 0 && $ARG = -* ]]; then + case "$ARG" in + --color=*) + case "${ARG#*=}" in + [0NnFf]*|never) + COLOR=0 + ;; + [1YyTt]*|always) + COLOR=1 + ;; + auto) + COLOR=auto + ;; + *) + printf 'Unrecognized value: %s\n' \ + "$ARG" \ + >&2 + exit 2 + ;; + esac + ;; + --ignore-warnings) + FAIL_ON_WARNINGS=0 + ;; + --) + NO_MORE_FLAGS=1 + ;; + *) + printf 'Unrecognized flag: %s\n' \ + "$ARG" \ + >&2 + exit 2 + ;; + esac + else + ARGS+=("$ARG") + fi + done + + if [[ $COLOR = 'auto' ]]; then + if [[ -t 1 ]]; then + COLOR=1 + else + COLOR=0 + fi + fi +} + +main() { + parse_args "$@" + assert_has_program xmllint + assert_directory_exists "${SCHEMA_ROOT_DIRS[@]}" + + FAILURES=() + WARNINGS=() + TEST_COUNT=0 + test_version 'all' + + VERSIONS=() + for SCHEMA_ROOT_DIR in "${SCHEMA_ROOT_DIRS[@]}"; do + for VERSION_DIR in "$SCHEMA_ROOT_DIR"/*; do + if [[ -d $VERSION_DIR ]]; then + VERSIONS+=("${VERSION_DIR##*/}") + fi + done + done + for VERSION in "${VERSIONS[@]}"; do + test_version "$VERSION" + done + + printf '\n------------- Results -------------\n' + printf '%d/%d tests passed\n' \ + "$(( TEST_COUNT - ${#FAILURES[@]} ))" \ + "$TEST_COUNT" + + FAILED=0 + if [[ ${#FAILURES[@]} -gt 0 ]]; then + printf_error '\nError: Validation errors occurred:\n' + for MSG in "${FAILURES[@]}"; do + printf_error -- '- %s\n' "$MSG" + done + FAILED=1 + else + printf_success 'All tests passed\n' + fi + + if [[ ${#WARNINGS[@]} -gt 0 ]]; then + printf_warning '\nWarning:\n' + for MSG in "${WARNINGS[@]}"; do + printf_warning -- '- %s\n' "$MSG" + done + if [[ $FAIL_ON_WARNINGS -ne 0 ]]; then + FAILED=1 + fi + fi + return "$FAILED" +} + +assert_directory_exists() { + local \ + DIR \ + MISSING=() + for DIR; do + if [[ ! -d $DIR ]]; then + MISSING+=("$DIR") + fi + done + if [[ ${#MISSING[@]} -gt 0 ]]; then + printf 'Error: Directories do not exist:\n' >&2 + for DIR in "${MISSING[@]}"; do + printf -- '- %s\n' "$DIR" >&2 + done + exit 2 + fi +} + +assert_has_program() { + local \ + BIN \ + MISSING=() + for BIN; do + if ! type -t "$BIN" &>/dev/null; then + MISSING+=("$BIN") + fi + done + if [[ ${#MISSING[@]} -gt 0 ]]; then + printf 'Error: You are missing required programs:\n' >&2 + for BIN in "${MISSING[@]}"; do + printf -- '- %s\n' "$BIN" >&2 + done + exit 2 + fi +} + +colorize() { + local PAINT=$1 + shift + if [[ $COLOR -ne 0 ]]; then + printf '%s' "$PAINT" + "$@" + printf '%s' "$RESET" + else + "$@" + fi +} + +invalidate_against() { + local OUT XML XSD=$1 + shift 1 + for XML; do + ((++TEST_COUNT)) + if OUT=$(lint_xml "$XSD" "$XML" 2>&1); then + # Passes validation --> error, print the message from xmllint + printf '%s\n' "$OUT" >&2 + FAILURES+=("Errors in $XML weren't caught by $XSD") + fi + done +} + +lint_xml() { + local XSD=$1 XML=$2 + xmllint \ + --noout \ + --schema "$XSD" \ + "$XML" +} + +printf_error() { + colorize "$RED" printf "$@" +} + +printf_success() { + colorize "$GREEN" printf "$@" +} + +printf_warning() { + colorize "$YELLOW" printf "$@" +} + +test_version() { + local INVALID_DIR TEST VALID_DIR VERSION VERSION_DIR XSD XSD_DIRS + VERSION=$1 + XSD_DIRS=() + for SCHEMA_ROOT_DIR in "${SCHEMA_ROOT_DIRS[@]}"; do + for VERSION_DIR in "$SCHEMA_ROOT_DIR"/*; do + if [[ -d $VERSION_DIR ]]; then + if [[ $VERSION = 'all' || ${VERSION_DIR##*/} = $VERSION ]]; then + XSD_DIRS+=("$VERSION_DIR") + fi + fi + done + done + + FOUND_VERSION_XSD=0 + for VERSION_DIR in "${XSD_DIRS[@]}"; do + for XSD in "$VERSION_DIR"/*.xsd; do + if [[ ! -f $XSD ]]; then + WARNINGS+=("XSD '$XSD' cannot be located, or isn't a file") + continue + fi + FOUND_VERSION_XSD=1 + + VALID_DIR=$TESTS_DIR/$VERSION/valid + INVALID_DIR=$TESTS_DIR/$VERSION/invalid + if [[ -d $VALID_DIR ]]; then + validate_against "$XSD" \ + "$VALID_DIR"/* + fi + if [[ -d $INVALID_DIR ]]; then + invalidate_against "$XSD" \ + "$INVALID_DIR"/* + fi + done + done + + if [[ $FOUND_VERSION_XSD -eq 0 ]]; then + WARNINGS+=("XSD version $VERSION cannot be located") + fi +} + +validate_against() { + local XML XSD=$1 + shift 1 + for XML; do + ((++TEST_COUNT)) + if ! lint_xml "$XSD" "$XML"; then + FAILURES+=("$XML fails validation against $XSD") + fi + done +} + +main "$@" From 04da24492bbdd2fd147fb606527aa381c6daff72 Mon Sep 17 00:00:00 2001 From: Dan Church Date: Wed, 13 Jul 2022 11:56:58 -0500 Subject: [PATCH 3/3] CI: Add test document --- tests/all/valid/valid-minimal.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/all/valid/valid-minimal.xml diff --git a/tests/all/valid/valid-minimal.xml b/tests/all/valid/valid-minimal.xml new file mode 100644 index 0000000..cc0c9bd --- /dev/null +++ b/tests/all/valid/valid-minimal.xml @@ -0,0 +1,5 @@ + + Series 1 + Number 1 + Title 1 +