From 407cce81d8003cd9065d6693c9e272734ded9965 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 2 Aug 2024 17:00:53 -0500 Subject: [PATCH 01/73] Starter project --- java-accessibility-checker/.gitattributes | 12 + java-accessibility-checker/.gitignore | 5 + .../gradle/libs.versions.toml | 12 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43504 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + java-accessibility-checker/gradlew | 252 ++++++++++++++++++ java-accessibility-checker/gradlew.bat | 94 +++++++ java-accessibility-checker/lib/build.gradle | 43 +++ .../src/main/java/org/example/Library.java | 10 + .../test/java/org/example/LibraryTest.java | 41 +++ java-accessibility-checker/settings.gradle | 14 + 11 files changed, 490 insertions(+) create mode 100644 java-accessibility-checker/.gitattributes create mode 100644 java-accessibility-checker/.gitignore create mode 100644 java-accessibility-checker/gradle/libs.versions.toml create mode 100644 java-accessibility-checker/gradle/wrapper/gradle-wrapper.jar create mode 100644 java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties create mode 100755 java-accessibility-checker/gradlew create mode 100644 java-accessibility-checker/gradlew.bat create mode 100644 java-accessibility-checker/lib/build.gradle create mode 100644 java-accessibility-checker/lib/src/main/java/org/example/Library.java create mode 100644 java-accessibility-checker/lib/src/test/java/org/example/LibraryTest.java create mode 100644 java-accessibility-checker/settings.gradle diff --git a/java-accessibility-checker/.gitattributes b/java-accessibility-checker/.gitattributes new file mode 100644 index 000000000..f91f64602 --- /dev/null +++ b/java-accessibility-checker/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/java-accessibility-checker/.gitignore b/java-accessibility-checker/.gitignore new file mode 100644 index 000000000..1b6985c00 --- /dev/null +++ b/java-accessibility-checker/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/java-accessibility-checker/gradle/libs.versions.toml b/java-accessibility-checker/gradle/libs.versions.toml new file mode 100644 index 000000000..ab0036d1b --- /dev/null +++ b/java-accessibility-checker/gradle/libs.versions.toml @@ -0,0 +1,12 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +commons-math3 = "3.6.1" +guava = "33.1.0-jre" +junit = "4.13.2" + +[libraries] +commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } +junit = { module = "junit:junit", version.ref = "junit" } diff --git a/java-accessibility-checker/gradle/wrapper/gradle-wrapper.jar b/java-accessibility-checker/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2c3521197d7c4586c843d1d3e9090525f1898cde GIT binary patch literal 43504 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 TZiJi*F`$tkWLn) literal 0 HcmV?d00001 diff --git a/java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties b/java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..09523c0e5 --- /dev/null +++ b/java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java-accessibility-checker/gradlew b/java-accessibility-checker/gradlew new file mode 100755 index 000000000..f5feea6d6 --- /dev/null +++ b/java-accessibility-checker/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java-accessibility-checker/gradlew.bat b/java-accessibility-checker/gradlew.bat new file mode 100644 index 000000000..9d21a2183 --- /dev/null +++ b/java-accessibility-checker/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle new file mode 100644 index 000000000..024eb4aa3 --- /dev/null +++ b/java-accessibility-checker/lib/build.gradle @@ -0,0 +1,43 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java library project to get you started. + * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.9/userguide/building_java_projects.html in the Gradle documentation. + */ + +plugins { + // Apply the java-library plugin for API and implementation separation. + id 'java-library' +} + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Use JUnit test framework. + testImplementation libs.junit + + // This dependency is exported to consumers, that is to say found on their compile classpath. + api libs.commons.math3 + + // This dependency is used internally, and not exposed to consumers on their own compile classpath. + implementation libs.guava + + // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java + implementation 'org.seleniumhq.selenium:selenium-java:4.16.1' +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +test { + testLogging { + showStandardStreams = true + } +} \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/main/java/org/example/Library.java b/java-accessibility-checker/lib/src/main/java/org/example/Library.java new file mode 100644 index 000000000..b98461bb7 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/org/example/Library.java @@ -0,0 +1,10 @@ +/* + * This source file was generated by the Gradle 'init' task + */ +package org.example; + +public class Library { + public boolean someLibraryMethod() { + return true; + } +} diff --git a/java-accessibility-checker/lib/src/test/java/org/example/LibraryTest.java b/java-accessibility-checker/lib/src/test/java/org/example/LibraryTest.java new file mode 100644 index 000000000..834cbdfc2 --- /dev/null +++ b/java-accessibility-checker/lib/src/test/java/org/example/LibraryTest.java @@ -0,0 +1,41 @@ +/* + * This source file was generated by the Gradle 'init' task + */ +package org.example; + +import org.junit.Test; +import static org.junit.Assert.*; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +// import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; + +public class LibraryTest { + private static ChromeDriver driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + String workingDir = System.getProperty("user.dir"); + String chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + System.setProperty("webdriver.chrome.driver", chromeDriverDir); + LibraryTest.driver = new ChromeDriver(); + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + LibraryTest.driver.close(); + } + + @Test public void someLibraryMethodReturnsTrue() { + LibraryTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + String pageTitle = driver.getTitle(); + System.out.println("Page Title: " + pageTitle); + Library classUnderTest = new Library(); + assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod()); + } +} diff --git a/java-accessibility-checker/settings.gradle b/java-accessibility-checker/settings.gradle new file mode 100644 index 000000000..60a3ed8fe --- /dev/null +++ b/java-accessibility-checker/settings.gradle @@ -0,0 +1,14 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.9/userguide/multi_project_builds.html in the Gradle documentation. + */ + +plugins { + // Apply the foojay-resolver plugin to allow automatic download of JDKs + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +rootProject.name = 'java-accessibility-checker' +include('lib') From 72530487cfe504e156c3a635aa856a604678386a Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 2 Aug 2024 23:52:59 -0500 Subject: [PATCH 02/73] Basic config files --- .../example => com/ibm/able}/Library.java | 2 +- .../main/java/com/ibm/able/config/Config.java | 95 ++++++++++++++++++ .../com/ibm/able/config/ConfigInternal.java | 96 +++++++++++++++++++ .../example => com/ibm/able}/LibraryTest.java | 4 +- 4 files changed, 195 insertions(+), 2 deletions(-) rename java-accessibility-checker/lib/src/main/java/{org/example => com/ibm/able}/Library.java (87%) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java rename java-accessibility-checker/lib/src/test/java/{org/example => com/ibm/able}/LibraryTest.java (96%) diff --git a/java-accessibility-checker/lib/src/main/java/org/example/Library.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/Library.java similarity index 87% rename from java-accessibility-checker/lib/src/main/java/org/example/Library.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/Library.java index b98461bb7..e1d609b90 100644 --- a/java-accessibility-checker/lib/src/main/java/org/example/Library.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/Library.java @@ -1,7 +1,7 @@ /* * This source file was generated by the Gradle 'init' task */ -package org.example; +package com.ibm.able; public class Library { public boolean someLibraryMethod() { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java new file mode 100644 index 000000000..9802f549a --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java @@ -0,0 +1,95 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.config; + +public class Config { + /** + * (optional) Specify the rule archive + * + * Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids + * Default: "latest" + * Values: "latest" | "preview" | "versioned" | archive id + */ + public String ruleArchive = "latest"; + + /** + * (optional) Specify one or many policies to scan. + * + * Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids + * Default: ["IBM_Accessibility"] + */ + public String[] policies = { "IBM_Accessibility" }; + + /** + * (optional) Specify one or many violation levels on which to fail the test + * + * i.e. If specified violation then the testcase will only fail if + * a violation is found during the scan. + * Default: ["violation", "review"] + */ + public String[] failLevels = { "violation", "potentialviolation" }; + + /** + * (optional) Specify one or many violation levels which should be reported + * + * i.e. If specified violation then in the report it would only contain + * results which are level of violation. + * Default: ["violation", "review"] + */ + public String[] reportLevels = { "violation", "potentialviolation" }; + + /** + * (optional) In which fornats should the results be output + * Default: ["json"] + */ + public String[] outputFormat = { "json" }; + + /** + * (optional) Specify any labels that you would like associated to your scan + * Default: [] + */ + public String[] label; + + /** + * (optional) Where the scan results should be saved. + * Default: "results" + */ + public String outputFolder; + + /** + * (optional) Should the timestamp be included in the filename of the reports? + * Default: true + */ + public boolean outputFilenameTimestamp = true; + + /** + * (optional) Where the baseline results should be loaded from + * Default: "baselines" + */ + public String baselineFolder = "baselines"; + + /** + * (optional) Where the tool can read/write cached files (ace-node.js / archive.json) + * Default: `${os.tmpdir()}/accessibility-checker/` + */ + public String cacheFolder = System.getProperty("java.io.tmpdir")+"/accessibility-checker/"; + + /** + * (optional) For tools that scan files, which extensions should we include + * Default: ["html", "htm", "svg"] + */ + public String[] extensions = { "html", "htm", "svg" }; +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java new file mode 100644 index 000000000..9f7a279d8 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java @@ -0,0 +1,96 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.config; + +import java.nio.file.Paths; + +public class ConfigInternal extends Config { + /** + * Run in debug mode + */ + public boolean DEBUG = "true".equals(System.getenv("DEBUG")); + + /** + * Spot to store parsed archive file + */ + // ruleArchiveSet?: IArchive[] + + /** + * Label to expose to reports + */ + public String ruleArchiveLabel; + + /** + * (optional) Rule server to pull the rules from and to use for help + * Default: "https://able.ibm.com/rules" + */ + public String ruleServer = "https://cdn.jsdelivr.net/npm/accessibility-checker-engine"; + + /** + * Path to the rule pack + */ + public String rulePack; + + /** + * Path within the archive + */ + public String ruleArchivePath; + + /** + * Version number of the selected archive + */ + public String ruleArchiveVersion; + + /** + * (optional) If the tool allows, should we capture screenshots + */ + public boolean captureScreenshots = false; + + /** + * (optional) If the tool allows, should we run headless + */ + public boolean headless = true; + + /** + * (optional) If the tool allows, set the maximum number of tabs to open + */ + public int maxTabs = 1; + + /** + * Configuration filenames to try loading + */ + public String[] configFiles = { + "achecker.json", + "aceconfig.json", + Paths.get(".config", "achecker.json").toString(), + Paths.get(".config", "aceconfig.json").toString() + }; + + public String toolID; + public String toolName; + public String toolVersion; + + public String scanID; + + public boolean ignoreHTTPSErrors = false; + + public boolean perfMetrics = true; + + /** + * "DEFAULT" | "REMOTE" | "INJECT" + */ + public String engineMode = "DEFAULT"; +} diff --git a/java-accessibility-checker/lib/src/test/java/org/example/LibraryTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java similarity index 96% rename from java-accessibility-checker/lib/src/test/java/org/example/LibraryTest.java rename to java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java index 834cbdfc2..48995cf39 100644 --- a/java-accessibility-checker/lib/src/test/java/org/example/LibraryTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java @@ -1,7 +1,7 @@ /* * This source file was generated by the Gradle 'init' task */ -package org.example; +package com.ibm.able; import org.junit.Test; import static org.junit.Assert.*; @@ -11,6 +11,8 @@ // import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; +import com.ibm.able.Library; + public class LibraryTest { private static ChromeDriver driver; From eb86a478277d73c5089d29334f56dab3fb2c3778 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 6 Aug 2024 11:12:58 -0500 Subject: [PATCH 03/73] Config starter --- java-accessibility-checker/lib/build.gradle | 1 + .../com/ibm/able/config/ACConfigManager.java | 375 ++++++++++++++++++ .../java/com/ibm/able/config/Archive.java | 39 ++ .../main/java/com/ibm/able/config/Config.java | 19 +- .../com/ibm/able/config/ConfigInternal.java | 28 +- .../main/java/com/ibm/able/util/Fetch.java | 64 +++ .../src/main/java/com/ibm/able/util/Misc.java | 28 ++ 7 files changed, 542 insertions(+), 12 deletions(-) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Archive.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 024eb4aa3..990aeaf0b 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -27,6 +27,7 @@ dependencies { // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.16.1' + implementation 'com.google.code.gson:gson:2.11.0' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java new file mode 100644 index 000000000..86a969b53 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java @@ -0,0 +1,375 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.config; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.ibm.able.config.Archive; +import com.ibm.able.util.Fetch; +import com.ibm.able.util.Misc; + +public class ACConfigManager { + private static class ConfigError extends Error { + ConfigError(String message) { + super(message); + } + + } + + private static String[] covertPolicies(String policies) { + return policies.split(","); + } + + + /** + * negative if versionA is less than versionB, positive if versionA is greater than versionB, and zero if they are equal. NaN is treated as 0. + * @param versionA + * @param versionB + */ + private static int compareVersions(String versionA, String versionB) { + Pattern versionRE = Pattern.compile("[0-9.]+(-rc.[0-9]+)?"); + versionA = versionA.trim(); + versionB = versionB.trim(); + if (!versionRE.matcher(versionA).matches()) throw new ConfigError("Invalid version"); + if (!versionRE.matcher(versionB).matches()) throw new ConfigError("Invalid version"); + if (versionA.equals(versionB)) return 0; + // Get x.y.z-rc.a into [x.y.z, a] + // Get x.y.z into [x.y.z] + String[] split1A = versionA.split("-rc."); + String[] split1B = versionB.split("-rc."); + // Get x.y.z into [x,y,z] + String[] split2A = split1A[0].split("."); + String[] split2B = split1B[0].split("."); + // For the components of the shortest version - can only compare numbers we have + int minLength = Math.min(split2A.length, split2B.length); + for (int idx=0; idx= 0) { + return archive.id; + } + } + // Something wrong, go with the latest + return "latest"; + } + + /** + * This function is responsible processing the achecker config which was initialized to make sure it contains, + * information which matches what the engine reads. + * + * i.e. + * Need to change reportLevels and failLevels to match with level declerations in the engine. + * replace violation with level.violation + * Need to change array of policies into a string + * ["CI162_5_2_DCP070116","CI162_5_2_DCP070116"] to "CI162_5_2_DCP070116,CI162_5_2_DCP070116" + * + * @param {Object} ACConfig - Provide the config object in which needs to be processed. + * + * @return {Object} ACConfig - return the config object which has been made engine readable + * + * @memberOf this + */ + private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IOException { + String[] validArchiveKeywords = { "latest", "preview", "versioned" }; + String ruleServer = ACConfig.ruleServer; + + // Get and parse the rule archive. + String ruleArchiveFile = String.format("%s%s/archives.json",ruleServer,ruleServer.contains("jsdelivr.net")?"@next":""); + Archive[] ruleArchiveParse; + try { + // if (ACConfig.ignoreHTTPSErrors) { + // process.env.NODE_TLS_REJECT_UNAUTHORIZED="0" + // } + ruleArchiveParse = Fetch.getJSONArr(ruleArchiveFile, Archive[].class); + } catch (Error err) { + System.err.println(err.toString()); + throw err; + } + String ruleArchivePath = null; + if (ruleArchiveParse.length > 0) { + if (ACConfig.DEBUG) System.out.println("Found archiveFile: " + ruleArchiveFile); + ACConfig.ruleArchiveSet = ruleArchiveParse; + String ruleArchive = ACConfig.ruleArchive; + // If the user asked us to sync the rule version with the tool version, we need to figure out what the last rule version was + if ("versioned".equals(ruleArchive)) { + if (ACConfig.toolVersion == null) { + ruleArchive = "latest"; + } else { + ruleArchive = findLatestArchiveId(ACConfig.ruleArchiveSet, ACConfig.toolVersion); + } + } + ACConfig.ruleArchiveLabel = ACConfig.ruleArchive; + for (int i = 0; i < ACConfig.ruleArchiveSet.length; i++) { + if (ruleArchive.equals(ACConfig.ruleArchiveSet[i].id) && !ACConfig.ruleArchiveSet[i].sunset) { + ruleArchivePath = ACConfig.ruleArchiveSet[i].path; + ACConfig.ruleArchiveVersion = ACConfig.ruleArchiveSet[i].version; + ACConfig.ruleArchiveLabel = ruleArchiveParse[i].name + " (" + ruleArchiveParse[i].id + ")"; + break; + } + } + if (ruleArchivePath == null || ACConfig.ruleArchiveVersion == null) { + String errStr = "[ERROR] RuleArchiveInvalid: Make Sure correct rule archive is provided in the configuration file. More information is available in the README.md"; + System.err.println(errStr); + throw new ConfigError(errStr); + } + for (int i = 0; i < ACConfig.ruleArchiveSet.length; i++) { + if (ACConfig.ruleArchiveVersion.equals(ACConfig.ruleArchiveSet[i].version) + && !Arrays.asList(validArchiveKeywords).contains(ACConfig.ruleArchiveSet[i].id)) + { + ACConfig.ruleArchivePath = ACConfig.ruleArchiveSet[i].path; + break; + } + } + //} + } else { + String errStr = "[ERROR] UnableToParseArchive: Archives are unable to be parse. Contact support team."; + System.err.println(errStr); + throw new ConfigError(errStr); + } + + // Build the new rulePack based of the baseA11yServerURL + if (ACConfig.rulePack == null || "".equals(ACConfig.rulePack)) { + if (ruleServer.contains("jsdelivr.net")) { + ACConfig.rulePack = String.format("%s@%s", ruleServer, ACConfig.ruleArchiveVersion); + } else { + ACConfig.rulePack = String.format("%s%s/js", ruleServer, ruleArchivePath); + } + } + ACConfig.ruleServer = ruleServer; + + if (ACConfig.DEBUG) System.err.println("Built new rulePack: " + ACConfig.rulePack); + + if (ACConfig.DEBUG) System.err.println("END 'processACConfig' function"); + + // Return the updated ACConfig object + return ACConfig; + } + + /** + * This function is responsible initializing all the default values for the configurations, in the case any + * of the config options are missing. + * + * @param {Object} config - Provide the config object in which we need to initialize the default values. + * + * @return {Object} config - return the config object which has all the default values, in the case + * some of the options are null or undefined. + * + * @memberOf this + */ + private static void initializeDefaults(ConfigInternal config) { + // Use an unpopulated config as the default values + ConfigInternal ACConstants = new ConfigInternal(); + if (config.DEBUG) System.out.println("START 'initializeDefaults' function"); + + if (config.DEBUG) System.out.println("Config before initialization: "); + if (config.DEBUG) System.out.println(config); + // Make sure all the following options are defined, otherwise reset them to default values. + config.ruleArchiveLabel = Misc.firstNotNull(config.ruleArchiveLabel, config.ruleArchive); + // For capture screenshots need to check for null or undefined and then set default otherwise it will evaluate the + // boolean which causes it to always comply with the default value and not user provided option + config.captureScreenshots = Misc.firstNotNull(config.captureScreenshots, ACConstants.captureScreenshots); + + // Build the toolID based on name and version + config.toolID = "java-accessibility-checker-v1.0.0"; + config.toolName = "java-accessibility-checker"; + config.toolVersion = "1.0.0"; + + // Using the uuid module generate a uuid number which is used to assoiciate to the scans that + // are done for a single run of karma. + config.scanID = java.util.UUID.randomUUID().toString(); + + for (Field field : ACConstants.getClass().getDeclaredFields()) { + try { + field.set(config, field.get(ACConstants)); + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + } + + if (config.DEBUG) System.out.println("Config after initialization: "); + if (config.DEBUG) System.out.println(config); + + if (config.DEBUG) System.out.println("END 'initializeDefaults' function"); + } + + /** + * This function is responsible reading in the .yaml or .yml or .json and set the config options based on this. + * + * @return {Object} config - return the config object that was read in, refer to function initializeDefaults + * to view how the object is to be constructed. + * + * @memberOf this + */ + private static ConfigInternal loadConfigFromJSONFile() { + // Use an unpopulated config as the default values + ConfigInternal ACConstants = new ConfigInternal(); + + if (ACConstants.DEBUG) System.out.println("START 'loadConfigFromYAMLorJSONFile' function"); + + // Get the current working directory, where we will look for the yaml, yml or json file + String workingDir = System.getProperty("user.dir"); + if (ACConstants.DEBUG) System.out.println("Working directory set to: " + workingDir); + + String[] configFiles = ACConstants.configFiles; + + ConfigInternal config = null; + // Loop over all the possible location where the config file can reside, if one is found load it and break out. + for (String configFile: configFiles) { + // Get the full path to the config file we are going to check + String fileToCheck = Paths.get(workingDir, configFile).toString(); + + if (ACConstants.DEBUG) System.out.println("Checking file: " + fileToCheck); + + // Get the extension of the file we are about to scan + String fileExtension = fileToCheck.substring(fileToCheck.lastIndexOf('.') + 1); + + // If this is a yml or yaml file verify that the file exists and then load as such. + if ("json".equals(fileExtension)) { + if (ACConstants.DEBUG) System.out.println("Trying to load as json or js."); + + // Need to use try/catch mech so that in the case the require throws an exception, we can + // catch this and discatd the error, as in the case there is no config file provided then + // we load in default values. + try { + Gson gson = new Gson(); + JsonReader reader = new JsonReader(new FileReader(fileToCheck)); + config = gson.fromJson(reader, ConfigInternal.class); + } catch (FileNotFoundException e) { + if (ACConstants.DEBUG) System.out.println("JSON or JS file ("+fileToCheck+") does not exists, will load default config."); + } + } + } + + if (ACConstants.DEBUG) System.out.println("END 'loadConfigFromYAMLorJSONFile' function"); + + return config; + } + + /** + * This function is responsible for processing the karma configuration for accessibility-checker. + * The ACConfig provided in the Karma configuration will be processed by this + * function and then the config variables will be assoiciated to the global space so that + * they can be accessed from window.__karma__.config + * + * @param {Object} config - All the Karma configuration, we will extract what we need from this over + * all object, we need the entire object so that we can reasign some config + * variables to global scope so that all karma testscases/scripts can access + * them. + * + * @return - N/A - Object will be processed and all the params that are needed for this module will + * be extracted and then the entire object will be added to global space. + * + * @memberOf this + */ + private static ConfigInternal processConfiguration(Config config) { + // Use an unpopulated config as the default values + ConfigInternal ACConstants = new ConfigInternal(); + if (ACConstants.DEBUG) System.out.println("START 'processConfiguration' function"); + + // Variable Decleration + ConfigInternal ACConfig = null; + ConfigInternal configFromFile = null; + + // Read in the .yaml (.yml) or .json file to load in the configuration + configFromFile = loadConfigFromJSONFile(); + + if (ACConstants.DEBUG) System.out.println("Loaded config from file: "); + if (ACConstants.DEBUG) System.out.println(configFromFile); + + // In the case configuration was provided in a yaml, yml or json file, then set this as the configuration + // otherwise load them from the Karma configuration. + if (configFromFile != null) { + if (ACConstants.DEBUG) System.out.println("Using config which was loaded from config file."); + + ACConfig = configFromFile; + } else if (config != null) { + ACConfig = new ConfigInternal(config); + } else { + ACConfig = new ConfigInternal(); + } + + // In the case the ACConfig object is not defined, then define it with default config options so + // it can be set in window.__karma__.config.ACConfig, so that we know even in the testcases, other + // wrapper scripts that there was nothing defined at all, and at the same time to make sure that this + // code was actually executed. + initializeDefaults(ACConfig); + + // Now we process the final accessibility-checker config object that is build to make sure it is valid, also need to perform some + // mapping for provided paremeters to actualy read by the engine. + try { + ACConfig = processACConfig(ACConfig); + } catch (IOException e) { + System.err.println(e); + } + + // In the case the Karma config is set to config.LOG_DEBUG then also enable the accessibility-checker debuging + ACConfig.DEBUG = ACConstants.DEBUG; + + if (ACConstants.DEBUG) System.out.println("END 'processConfiguration' function"); + return ACConfig; + } + + private static ConfigInternal config = null; + static void setConfig(Config inConfig) { + config = ACConfigManager.processConfiguration(inConfig); + // TODO: + // ReporterManager.setConfig(config); + } + + static Config getConfig() { + return ACConfigManager.getConfigUnsupported(); + } + + static ConfigInternal getConfigUnsupported() { + if (ACConfigManager.config == null) { + ACConfigManager.setConfig(null); + } + return config; + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Archive.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Archive.java new file mode 100644 index 000000000..28859bd63 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Archive.java @@ -0,0 +1,39 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.config; + +import java.util.HashMap; +import java.util.Map; + +public class Archive { + public static class Ruleset { + public String id; + public String name; + public String description; + } + + public String id; + public String name; + public String path; + public Ruleset[] policies; + public Map rulesets = new HashMap(); + + public String version; + public boolean latest; + public boolean sunset; + public String helpPath; + public String enginePath; +} \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java index 9802f549a..ea89359fa 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java @@ -16,6 +16,21 @@ package com.ibm.able.config; public class Config { + Config() {} + + Config(Config other) { + this.ruleArchive = other.ruleArchive; + this.policies = other.policies.clone(); + this.failLevels = other.failLevels.clone(); + this.reportLevels = other.reportLevels.clone(); + this.outputFormat = other.outputFormat.clone(); + this.label = other.label.clone(); + this.outputFolder = other.outputFolder; + this.outputFilenameTimestamp = other.outputFilenameTimestamp; + this.baselineFolder = other.baselineFolder; + this.cacheFolder = other.cacheFolder; + this.extensions = other.extensions; + } /** * (optional) Specify the rule archive * @@ -61,13 +76,13 @@ public class Config { * (optional) Specify any labels that you would like associated to your scan * Default: [] */ - public String[] label; + public String[] label = null; /** * (optional) Where the scan results should be saved. * Default: "results" */ - public String outputFolder; + public String outputFolder = null; /** * (optional) Should the timestamp be included in the filename of the reports? diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java index 9f7a279d8..3b4f9af00 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java @@ -18,6 +18,14 @@ import java.nio.file.Paths; public class ConfigInternal extends Config { + ConfigInternal() { + super(); + } + + ConfigInternal(Config config) { + super(config); + } + /** * Run in debug mode */ @@ -26,12 +34,12 @@ public class ConfigInternal extends Config { /** * Spot to store parsed archive file */ - // ruleArchiveSet?: IArchive[] + public Archive[] ruleArchiveSet = null; /** * Label to expose to reports */ - public String ruleArchiveLabel; + public String ruleArchiveLabel = null; /** * (optional) Rule server to pull the rules from and to use for help @@ -42,22 +50,22 @@ public class ConfigInternal extends Config { /** * Path to the rule pack */ - public String rulePack; + public String rulePack = null; /** * Path within the archive */ - public String ruleArchivePath; + public String ruleArchivePath = null; /** * Version number of the selected archive */ - public String ruleArchiveVersion; + public String ruleArchiveVersion = null; /** * (optional) If the tool allows, should we capture screenshots */ - public boolean captureScreenshots = false; + public Boolean captureScreenshots = false; /** * (optional) If the tool allows, should we run headless @@ -79,11 +87,11 @@ public class ConfigInternal extends Config { Paths.get(".config", "aceconfig.json").toString() }; - public String toolID; - public String toolName; - public String toolVersion; + public String toolID = null; + public String toolName = null; + public String toolVersion = null; - public String scanID; + public String scanID = null; public boolean ignoreHTTPSErrors = false; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java new file mode 100644 index 000000000..ab9b1bf5b --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java @@ -0,0 +1,64 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.util; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import com.google.gson.Gson; + +public class Fetch { + private Fetch() {} + + private static Gson gson = new Gson(); + + public static String get(String urlStr) throws IOException { + URL url = new URL(urlStr); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + + con.setDoOutput(true); + DataOutputStream out = new DataOutputStream(con.getOutputStream()); + out.flush(); + out.close(); + return out.toString(); + } + + public static T[] getJSONArr(String urlStr, Class clazz) throws IOException { + URL url = new URL(urlStr); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + + con.setDoOutput(true); + DataOutputStream out = new DataOutputStream(con.getOutputStream()); + out.flush(); + out.close(); + return gson.fromJson(out.toString(), clazz); + } + + public static T getJSONObj(String urlStr, Class clazz) throws IOException { + URL url = new URL(urlStr); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + + con.setDoOutput(true); + DataOutputStream out = new DataOutputStream(con.getOutputStream()); + out.flush(); + out.close(); + return gson.fromJson(out.toString(), clazz); + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java new file mode 100644 index 000000000..46639123e --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java @@ -0,0 +1,28 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.util; + +public class Misc { + private Misc() {} + + public static T firstNotNull(T ... args) { + for (T x : args) { + if (x != null) return x; + } + return null; + } + +} From 2936c7dfdd831fd1ae83c88d018765e96586930e Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 6 Aug 2024 14:00:30 -0500 Subject: [PATCH 04/73] Process config files --- .../com/ibm/able/config/ACConfigManager.java | 59 +++-- .../java/com/ibm/able/config/Archive.java | 2 +- .../main/java/com/ibm/able/config/Config.java | 2 +- .../main/java/com/ibm/able/util/Fetch.java | 40 +-- .../test/java/com/ibm/able/LibraryTest.java | 3 +- .../ibm/able/config/ACConfigManagerTest.java | 245 ++++++++++++++++++ .../java/com/ibm/able/util/FetchTest.java | 23 ++ 7 files changed, 320 insertions(+), 54 deletions(-) create mode 100644 java-accessibility-checker/lib/src/test/java/com/ibm/able/config/ACConfigManagerTest.java create mode 100644 java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java index 86a969b53..2c2329012 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java @@ -22,12 +22,10 @@ import java.lang.reflect.Field; import java.nio.file.Paths; import java.util.Arrays; -import java.util.List; import java.util.regex.Pattern; import com.google.gson.Gson; import com.google.gson.stream.JsonReader; -import com.ibm.able.config.Archive; import com.ibm.able.util.Fetch; import com.ibm.able.util.Misc; @@ -49,8 +47,8 @@ private static String[] covertPolicies(String policies) { * @param versionA * @param versionB */ - private static int compareVersions(String versionA, String versionB) { - Pattern versionRE = Pattern.compile("[0-9.]+(-rc.[0-9]+)?"); + public static int compareVersions(String versionA, String versionB) { + Pattern versionRE = Pattern.compile("[0-9.]+(-rc\\.[0-9]+)?"); versionA = versionA.trim(); versionB = versionB.trim(); if (!versionRE.matcher(versionA).matches()) throw new ConfigError("Invalid version"); @@ -58,15 +56,16 @@ private static int compareVersions(String versionA, String versionB) { if (versionA.equals(versionB)) return 0; // Get x.y.z-rc.a into [x.y.z, a] // Get x.y.z into [x.y.z] - String[] split1A = versionA.split("-rc."); - String[] split1B = versionB.split("-rc."); + String[] split1A = versionA.split("-rc\\."); + String[] split1B = versionB.split("-rc\\."); // Get x.y.z into [x,y,z] - String[] split2A = split1A[0].split("."); - String[] split2B = split1B[0].split("."); + String[] split2A = split1A[0].split("\\."); + String[] split2B = split1B[0].split("\\."); + // For the components of the shortest version - can only compare numbers we have int minLength = Math.min(split2A.length, split2B.length); for (int idx=0; idx rulesets = new HashMap(); + public Map rulesets = new HashMap(); public String version; public boolean latest; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java index ea89359fa..10553a960 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java @@ -82,7 +82,7 @@ public class Config { * (optional) Where the scan results should be saved. * Default: "results" */ - public String outputFolder = null; + public String outputFolder = "results"; /** * (optional) Should the timestamp be included in the filename of the reports? diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java index ab9b1bf5b..74ca68891 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java @@ -15,8 +15,9 @@ *****************************************************************************/ package com.ibm.able.util; -import java.io.DataOutputStream; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import com.google.gson.Gson; @@ -28,37 +29,22 @@ private Fetch() {} public static String get(String urlStr) throws IOException { URL url = new URL(urlStr); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - - con.setDoOutput(true); - DataOutputStream out = new DataOutputStream(con.getOutputStream()); - out.flush(); - out.close(); - return out.toString(); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); + StringBuilder sb = new StringBuilder(); + String output; + while ((output = br.readLine()) != null) { + sb.append(output); + } + return sb.toString(); } public static T[] getJSONArr(String urlStr, Class clazz) throws IOException { - URL url = new URL(urlStr); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - - con.setDoOutput(true); - DataOutputStream out = new DataOutputStream(con.getOutputStream()); - out.flush(); - out.close(); - return gson.fromJson(out.toString(), clazz); + return gson.fromJson(Fetch.get(urlStr), clazz); } public static T getJSONObj(String urlStr, Class clazz) throws IOException { - URL url = new URL(urlStr); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - - con.setDoOutput(true); - DataOutputStream out = new DataOutputStream(con.getOutputStream()); - out.flush(); - out.close(); - return gson.fromJson(out.toString(), clazz); + return gson.fromJson(Fetch.get(urlStr), clazz); } } diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java index 48995cf39..4f6c5ac53 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java @@ -36,7 +36,8 @@ public class LibraryTest { @Test public void someLibraryMethodReturnsTrue() { LibraryTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); String pageTitle = driver.getTitle(); - System.out.println("Page Title: " + pageTitle); + System.out.println("Page Title: " + pageTitle); + System.out.println(System.getProperty("user.dir")); Library classUnderTest = new Library(); assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod()); } diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/config/ACConfigManagerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/config/ACConfigManagerTest.java new file mode 100644 index 000000000..c152c2619 --- /dev/null +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/config/ACConfigManagerTest.java @@ -0,0 +1,245 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.config; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.regex.Pattern; + +import org.junit.Test; + +public class ACConfigManagerTest { + @Test public void getConfigWithNoConfigFile() { + Config config = ACConfigManager.getConfig(); + + // Main properties + assertEquals("latest", config.ruleArchive); + assertArrayEquals(new String[] { "IBM_Accessibility" }, config.policies); + assertArrayEquals(new String[] { "violation", "potentialviolation" }, config.failLevels); + assertArrayEquals(new String[] { "violation", "potentialviolation" }, config.reportLevels); + assertArrayEquals(new String[] { "json" }, config.outputFormat); + assertArrayEquals(null, config.label); + assertEquals("results", config.outputFolder); + assertEquals(true, config.outputFilenameTimestamp); + assertEquals("baselines", config.baselineFolder); + assertEquals(System.getProperty("java.io.tmpdir")+"/accessibility-checker/", config.cacheFolder); + assertArrayEquals(new String[] { "html", "htm", "svg" }, config.extensions); + + // Internal properties + assertTrue(config instanceof ConfigInternal); + ConfigInternal configInternal = (ConfigInternal) config; + + assertEquals(false, configInternal.DEBUG); + assertEquals("latest", configInternal.ruleArchiveSet[0].id); + assertEquals("Latest Deployment (latest)", configInternal.ruleArchiveLabel); + assertEquals("https://cdn.jsdelivr.net/npm/accessibility-checker-engine", configInternal.ruleServer); + assertEquals("https://cdn.jsdelivr.net/npm/accessibility-checker-engine", configInternal.rulePack.split("@")[0]); + assertEquals("/archives/", configInternal.ruleArchivePath.substring(0, "/archives/".length())); + assertEquals(3, configInternal.ruleArchiveVersion.split("\\.").length); + assertEquals(false, configInternal.captureScreenshots); + assertEquals(true, configInternal.headless); + assertEquals(1, configInternal.maxTabs); + assertArrayEquals(new String[] { + "achecker.json", + "aceconfig.json", + Paths.get(".config", "achecker.json").toString(), + Paths.get(".config", "aceconfig.json").toString() + }, configInternal.configFiles); + assertEquals("java-accessibility-checker-v3.1.70", configInternal.toolID); + assertEquals("java-accessibility-checker", configInternal.toolName); + assertEquals("3.1.70", configInternal.toolVersion); + Pattern uuidPattern = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + assertTrue(uuidPattern.matcher(configInternal.scanID).matches()); + assertEquals(false, configInternal.ignoreHTTPSErrors); + assertEquals(true, configInternal.perfMetrics); + assertEquals("DEFAULT", configInternal.engineMode); + } + + @Test public void getConfigWithConfigFile() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "ruleArchive": "17June2024", + "policies": [ "IBM_Accessibility"], + "failLevels": [ "violation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual" + ], + "outputFormat": [ "json", "xlsx" ], + "label": [ + "Java", + "Demo" + ], + "outputFolder": ".aat/results", + "baselineFolder": ".aat/baselines" +} +"""); + myWriter.close(); + + Config config = ACConfigManager.getConfig(); + + // Main properties + assertEquals("17June2024", config.ruleArchive); + assertArrayEquals(new String[] { "IBM_Accessibility" }, config.policies); + assertArrayEquals(new String[] { "violation" }, config.failLevels); + assertArrayEquals(new String[] { "violation", "potentialviolation", "recommendation", "potentialrecommendation", "manual" }, config.reportLevels); + assertArrayEquals(new String[] { "json", "xlsx" }, config.outputFormat); + assertArrayEquals(new String[] { "Java", "Demo" }, config.label); + assertEquals(".aat/results", config.outputFolder); + assertEquals(true, config.outputFilenameTimestamp); + assertEquals(".aat/baselines", config.baselineFolder); + assertEquals(System.getProperty("java.io.tmpdir")+"/accessibility-checker/", config.cacheFolder); + assertArrayEquals(new String[] { "html", "htm", "svg" }, config.extensions); + + // Internal properties + assertTrue(config instanceof ConfigInternal); + ConfigInternal configInternal = (ConfigInternal) config; + + assertEquals(false, configInternal.DEBUG); + assertEquals("latest", configInternal.ruleArchiveSet[0].id); + assertEquals("17 June 2024 Deployment (IBM 7.2, 7.3) (17June2024)", configInternal.ruleArchiveLabel); + assertEquals("https://cdn.jsdelivr.net/npm/accessibility-checker-engine", configInternal.ruleServer); + assertEquals("https://cdn.jsdelivr.net/npm/accessibility-checker-engine", configInternal.rulePack.split("@")[0]); + assertEquals("/archives/", configInternal.ruleArchivePath.substring(0, "/archives/".length())); + assertEquals(3, configInternal.ruleArchiveVersion.split("\\.").length); + assertEquals(false, configInternal.captureScreenshots); + assertEquals(true, configInternal.headless); + assertEquals(1, configInternal.maxTabs); + assertArrayEquals(new String[] { + "achecker.json", + "aceconfig.json", + Paths.get(".config", "achecker.json").toString(), + Paths.get(".config", "aceconfig.json").toString() + }, configInternal.configFiles); + assertEquals("java-accessibility-checker-v3.1.70", configInternal.toolID); + assertEquals("java-accessibility-checker", configInternal.toolName); + assertEquals("3.1.70", configInternal.toolVersion); + Pattern uuidPattern = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + assertTrue(uuidPattern.matcher(configInternal.scanID).matches()); + assertEquals(false, configInternal.ignoreHTTPSErrors); + assertEquals(true, configInternal.perfMetrics); + assertEquals("DEFAULT", configInternal.engineMode); + } finally { + configFile.delete(); + } + } + + @Test public void getConfigWithConfigFileVersioned() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "ruleArchive": "versioned", + "policies": [ "IBM_Accessibility"], + "failLevels": [ "violation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual" + ], + "outputFormat": [ "json", "xlsx" ], + "label": [ + "Java", + "Demo" + ], + "outputFolder": ".aat/results", + "baselineFolder": ".aat/baselines" +} +"""); + myWriter.close(); + + Config config = ACConfigManager.getConfig(); + + // Main properties + assertEquals("versioned", config.ruleArchive); + assertArrayEquals(new String[] { "IBM_Accessibility" }, config.policies); + assertArrayEquals(new String[] { "violation" }, config.failLevels); + assertArrayEquals(new String[] { "violation", "potentialviolation", "recommendation", "potentialrecommendation", "manual" }, config.reportLevels); + assertArrayEquals(new String[] { "json", "xlsx" }, config.outputFormat); + assertArrayEquals(new String[] { "Java", "Demo" }, config.label); + assertEquals(".aat/results", config.outputFolder); + assertEquals(true, config.outputFilenameTimestamp); + assertEquals(".aat/baselines", config.baselineFolder); + assertEquals(System.getProperty("java.io.tmpdir")+"/accessibility-checker/", config.cacheFolder); + assertArrayEquals(new String[] { "html", "htm", "svg" }, config.extensions); + + // Internal properties + assertTrue(config instanceof ConfigInternal); + ConfigInternal configInternal = (ConfigInternal) config; + + assertEquals(false, configInternal.DEBUG); + assertEquals("latest", configInternal.ruleArchiveSet[0].id); + assertEquals("19 April 2024 Deployment (IBM 7.2) (19April2024)", configInternal.ruleArchiveLabel); + assertEquals("https://cdn.jsdelivr.net/npm/accessibility-checker-engine", configInternal.ruleServer); + assertEquals("https://cdn.jsdelivr.net/npm/accessibility-checker-engine", configInternal.rulePack.split("@")[0]); + assertEquals("/archives/", configInternal.ruleArchivePath.substring(0, "/archives/".length())); + assertEquals(3, configInternal.ruleArchiveVersion.split("\\.").length); + assertEquals(false, configInternal.captureScreenshots); + assertEquals(true, configInternal.headless); + assertEquals(1, configInternal.maxTabs); + assertArrayEquals(new String[] { + "achecker.json", + "aceconfig.json", + Paths.get(".config", "achecker.json").toString(), + Paths.get(".config", "aceconfig.json").toString() + }, configInternal.configFiles); + assertEquals("java-accessibility-checker-v3.1.70", configInternal.toolID); + assertEquals("java-accessibility-checker", configInternal.toolName); + assertEquals("3.1.70", configInternal.toolVersion); + Pattern uuidPattern = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + assertTrue(uuidPattern.matcher(configInternal.scanID).matches()); + assertEquals(false, configInternal.ignoreHTTPSErrors); + assertEquals(true, configInternal.perfMetrics); + assertEquals("DEFAULT", configInternal.engineMode); + } finally { + configFile.delete(); + } + } + + @Test public void compareVersions() throws IOException { + assertTrue(ACConfigManager.compareVersions("1.0.0", "1.0.0") == 0); + assertTrue(ACConfigManager.compareVersions("1.0.1", "1.0.0") > 0); + assertTrue(ACConfigManager.compareVersions("1.1.0", "1.0.0") > 0); + assertTrue(ACConfigManager.compareVersions("2.0.0", "1.0.0") > 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "1.0.1") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "1.1.0") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "2.0.0") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0", "1.0.0-rc.0") > 0); + assertTrue(ACConfigManager.compareVersions("1.0.0-rc.1", "1.0.0-rc.0") > 0); + assertTrue(ACConfigManager.compareVersions("1.0.0-rc.0", "1.0.0") < 0); + assertTrue(ACConfigManager.compareVersions("1.0.0-rc.0", "1.0.0-rc.1") < 0); + } +} \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java new file mode 100644 index 000000000..9cb22c9ee --- /dev/null +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java @@ -0,0 +1,23 @@ +/* + * This source file was generated by the Gradle 'init' task + */ +package com.ibm.able.util; + +import org.junit.Test; +import static org.junit.Assert.*; + +import java.io.IOException; + +import com.ibm.able.util.Fetch; + +public class FetchTest { + @Test public void getArr() { + String s = null; + try { + s = Fetch.get("https://cdn.jsdelivr.net/npm/accessibility-checker-engine@next/archives.json"); + } catch (IOException e) { + e.printStackTrace(); + } + assertEquals(String.class, s.getClass()); + } +} From 62c54007a3dd2d29c1c40de64e208b4bc26cc9dd Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Wed, 7 Aug 2024 10:17:38 -0500 Subject: [PATCH 05/73] Report signs of life --- .../com/ibm/able/AccessibilityChecker.java | 246 ++++++++++++++++++ .../com/ibm/able/EngineContextManager.java | 30 +++ .../java/com/ibm/able/IEngineContext.java | 26 ++ .../com/ibm/able/config/ACConfigManager.java | 8 +- .../java/com/ibm/able/engine/ACError.java | 8 + .../java/com/ibm/able/engine/ACReport.java | 47 ++++ .../able/selenium/EngineContextSelenium.java | 193 ++++++++++++++ .../src/main/java/com/ibm/able/util/Misc.java | 9 + .../ibm/able/AccessibilityCheckerTest.java | 53 ++++ .../test/java/com/ibm/able/LibraryTest.java | 44 ---- 10 files changed, 616 insertions(+), 48 deletions(-) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/EngineContextManager.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/IEngineContext.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/selenium/EngineContextSelenium.java create mode 100644 java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java delete mode 100644 java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java new file mode 100644 index 000000000..422366a54 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java @@ -0,0 +1,246 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able; + +import java.io.IOException; +import com.ibm.able.config.ACConfigManager; +import com.ibm.able.config.Config; +import com.ibm.able.engine.ACReport; + +public class AccessibilityChecker { + /** + * This function is responsible performing a scan based on the context that is provided, following are + * the supported context type: + * Single node (HTMLElement) + * Local file path (String) + * URL (String) + * document node + * data stream for html content (String) + * + * Future Items + * Multiple node (Array of HTMLElements) ---> FUTURE + * + * @param {(Webdriver|Puppeteer Page |)} content - Provide the context to scan, which includes the items from above. + * @param {String} label - Provide a label for the scan that is being performed + * @param {Function} callback - (optional) Provide callback function which will be executed once the results are extracted. + * @return Promise with the ICheckerResult + */ + public static ACReport getCompliance(Object content, String label) { + if (content == null) { + System.err.println("aChecker: Unable to get compliance of null or undefined object"); + return null; + } + + AccessibilityChecker.initialize(); + + IEngineContext engineContext = EngineContextManager.getEngineContext(content); + try { + engineContext.loadEngine(); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine due to IOException: "+e.toString()); + e.printStackTrace(); + } + + // Get the Data when the scan is started + // Start time will be in milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now. + return engineContext.getCompliance(label); + } + + public static Config getConfig() { + return ACConfigManager.getConfig(); + } + + public static Config getConfigUnsupported() { + return ACConfigManager.getConfigUnsupported(); + } + + private static void initialize() { + // TODO: + // if (Config) return; + // Config = await ACConfigManager.getConfigUnsupported(); + // await ACEngineManager.loadEngineLocal(); + // let absAPI = new MyFS(); + // let refactorMap : RefactorMap = {} + // let rules = ACEngineManager.getRulesSync(); + // for (const rule of rules) { + // if (rule.refactor) { + // for (const key in rule.refactor) { + // refactorMap[key] = rule; + // } + // } + // } + // ReporterManager.initialize(Config, absAPI, await ACEngineManager.getRulesets()); + // BaselineManager.initialize(Config, absAPI, refactorMap); + } + +// /** +// * This function is responsible for comparing the scan results with baseline or checking that there are +// * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will +// * be used to perform the check, in the case no baseline is provided then we comply with only failing if +// * there is a sinble violation which falls into failLevels. +// * +// * @param {ReportResult} actual - the actual results object provided by the user, this object should follow the +// * same format as outlined in the return of aChecker.buildReport function. +// * +// * @return {int} - return 0 in the case actual matches baseline or no violations fall into failsLevels, +// * return 1 in the case actual results does not match baseline results, +// * return 2 in the case that there is a failure based on failLevels (this means no baseline found). +// * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. +// */ +// export function assertCompliance(report: IBaselineReport) : eAssertResult { +// return BaselineManager.assertCompliance(report) +// } + +// /** +// * This function is responsible for printing the scan results to console. +// * +// * @param {Object} results - Provide the results from the scan. +// * +// * @return {String} resultsString - String representation of the results/violations. +// * +// * PUBLIC API +// * +// * @memberOf this +// */ +// export function stringifyResults(report: ICheckerReport) : string { +// return ReporterManager.stringifyResults(report) +// } + +// export function close() { +// return ACBrowserManager.close(); +// } + +// /** +// * This function is responsible for getting the diff results based on label for a scan that was already performed. +// * +// * @param {String} label - Provide a lable for which to get the diff results for. +// * +// * @return {Object} - return the diff results object from global space based on label provided, the object will be +// * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. +// */ +// export function getDiffResults(label: string) { +// return BaselineManager.getDiffResults(label); +// } + +// /** +// * This function is responsible for getting the baseline object for a label that was provided. +// * +// * @param {String} label - Provide a lable for which to get the baseline for. +// * +// * @return {Object} - return the baseline object from global space based on label provided, the object will be +// * in the same format as outlined in the return of aChecker.buildReport function. +// */ +// export function getBaseline(label: string) { +// return BaselineManager.getBaseline(label); +// } + +// /** +// * This function is responsible for comparing actual with expected and returning all the differences as an array. +// * +// * @param {Object} actual - Provide the actual object to be used for compare +// * @param {Object} expected - Provide the expected object to be used for compare +// * @param {boolean} clean - Provide a boolean if both the actual and expected objects need to be cleaned +// * cleaning refers to converting the objects to match with a basic compliance +// * compare of xpath and ruleId. +// * +// * @return {Object} differences - return an array of diff objects that were found, following is the format of the object: +// * [ +// * { +// * "kind": "E", +// * "path": [ +// * "reports", +// * 0, +// * "issues", +// * 10, +// * "xpath" +// * ], +// * "lhs": "/html[1]/body[1]/div[2]/table[5]", +// * "rhs": "/html[1]/body[1]/div[2]/table[5]d", +// * }, +// * { +// * "kind": "E", +// * "path": [ +// * "label" +// * ], +// * "lhs": "Table-layoutMultiple", +// * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html", +// * } +// * ] +// */ +// export function diffResultsWithExpected(actual, expected, clean) { +// return BaselineManager.diffResultsWithExpected(actual, expected, clean); +// } + +// /** +// * This function is responsible for cleaning up the compliance baseline or actual results, based on +// * a pre-defined set of criterias, such as the following: +// * 1. No need to compare summary object +// * 2. Only need to compare the ruleId and xpath in for each of the issues +// * +// * @param {Object} objectToClean - Provide either an baseline or actual results object which would be in the +// * the same format as outlined in the return of aChecker.buildReport function. +// * +// * @return {Object} objectToClean - return an object that was cleaned to only contain the information that is +// * needed for compare. Following is a sample of how the cleaned object will look like: +// * { +// * "label": "unitTestContent", +// * "reports": [ +// * { +// * "frameIdx": "0", +// * "frameTitle": "Frame 0", +// * "issues": [ +// * { +// * "ruleId": "1", +// * "xpath": "/html[1]/head[1]/style[1]" +// * } +// * .... +// * ] +// * }, +// * { +// * "frameIdx": "1", +// * "frameTitle": "Frame 1", +// * "issues": [ +// * { +// * "ruleId": "471", +// * "xpath": "/html[1]/body[1]/div[2]/table[3]" +// * } +// * .... +// * ] +// * } +// * ] +// * } +// */ +// export function cleanComplianceObjectBeforeCompare(objectToClean) { +// return BaselineManager.cleanComplianceObjectBeforeCompare(objectToClean); +// } + +// export function addRuleset(ruleset) { +// ACEngineManager.addRuleset(ruleset); +// } + +// export async function getRuleset(rsId) { +// return ACEngineManager.getRuleset(rsId); +// }; + +// export async function getRulesets() { +// return ACEngineManager.getRulesets(); +// }; + +// export async function getRules() { +// return ACEngineManager.getRules(); +// } + +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/EngineContextManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/EngineContextManager.java new file mode 100644 index 000000000..b0b935ebc --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/EngineContextManager.java @@ -0,0 +1,30 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able; + +import org.openqa.selenium.WebDriver; + +import com.ibm.able.selenium.EngineContextSelenium; +import com.ibm.able.util.Misc; + +public class EngineContextManager { + public static IEngineContext getEngineContext(Object contentContext) { + if (Misc.classIsAvailable("org.openqa.selenium.WebDriver") && contentContext instanceof org.openqa.selenium.WebDriver) { + return new EngineContextSelenium((WebDriver) contentContext); + } + return null; + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/IEngineContext.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/IEngineContext.java new file mode 100644 index 000000000..1ad11b3a7 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/IEngineContext.java @@ -0,0 +1,26 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able; + +import java.io.IOException; + +import com.ibm.able.engine.ACReport; + +public interface IEngineContext { + void loadEngine() throws IOException; + + ACReport getCompliance(String label); +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java index 2c2329012..03e843937 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java @@ -363,24 +363,24 @@ private static ConfigInternal processConfiguration(Config config) { } private static ConfigInternal config = null; - static void setConfig(Config inConfig) { + public static void setConfig(Config inConfig) { config = ACConfigManager.processConfiguration(inConfig); // TODO: // ReporterManager.setConfig(config); } - static Config getConfig() { + public static Config getConfig() { return ACConfigManager.getConfigUnsupported(); } - static ConfigInternal getConfigUnsupported() { + public static ConfigInternal getConfigUnsupported() { if (ACConfigManager.config == null) { ACConfigManager.setConfig(null); } return config; } - static void resetConfig() { + public static void resetConfig() { config = null; } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java new file mode 100644 index 000000000..0be8b61f1 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java @@ -0,0 +1,8 @@ +package com.ibm.able.engine; + +public class ACError extends Error { + public ACError(String msg) { + super(msg); + } + +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java new file mode 100644 index 000000000..68b1494c9 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java @@ -0,0 +1,47 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.engine; +import java.util.Map; + +public class ACReport { + public static class Bounds { + int top; + int left; + int height; + int width; + } + + public static class Result { + public Object[] apiArgs; + public Bounds bounds; + public String category; + public String message; + public String[] messageArgs; + public Map path; + public String reasonId; + public String ruleId; + public int ruleTime; + public String snippet; + public String[] value; + } + + public int numExecuted; + public int ruleTime; + public int totalTime; + public Map> nls; + public Result[] results; +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/selenium/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/selenium/EngineContextSelenium.java new file mode 100644 index 000000000..0030c94ff --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/selenium/EngineContextSelenium.java @@ -0,0 +1,193 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.selenium; + +import java.io.IOException; +import java.time.Duration; +import java.util.Date; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; + +import com.google.gson.Gson; +import com.ibm.able.IEngineContext; +import com.ibm.able.config.ACConfigManager; +import com.ibm.able.config.Config; +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.engine.ACError; +import com.ibm.able.engine.ACReport; +import com.ibm.able.util.Fetch; + +public class EngineContextSelenium implements IEngineContext { + private WebDriver driver = null; + private String engineContent = null; + + public EngineContextSelenium(WebDriver driver) { + this.driver = driver; + } + + public void loadEngine() throws IOException { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String engineLoadMode = config.engineMode; + if ("DEFAULT".equals(engineLoadMode)) { + engineLoadMode = "INJECT"; + } + if ("INJECT".equals(engineLoadMode) && engineContent == null) { + engineContent = Fetch.get(config.rulePack+"/ace.js"); + } + + if (config.DEBUG) System.out.println("[INFO] aChecker.loadEngine detected Selenium"); + try { + String scriptStr; + if ("REMOTE".equals(engineLoadMode)) { + scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + let script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script.setAttribute('aChecker', 'ACE'); + script.setAttribute('src', '%s/ace.js'); + script.addEventListener('load', function() { + globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + cb(); + }); + let heads = document.getElementsByTagName('head'); + if (heads.length > 0) { heads[0].appendChild(script); } + else { document.body.appendChild(script); } + } else { + cb(); + } +} catch (e) { + cb(e); +} +""", config.rulePack); + } else if ("INJECT".equals(engineLoadMode)) { + Gson gson = new Gson(); + // Selenium + scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + eval(%s) + globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + cb(); + + } else { + cb(); + } +} catch (e) { + cb(e); +} +""", gson.toJson(engineContent)); + } else { + scriptStr = ""; + } + + this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); + + Object result = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr); + if (result != null) { + System.err.println(result); + } + } catch (Error e) { + System.err.println(e); + } + } + + public ACReport getCompliance(String label) { + Config config = ACConfigManager.getConfig(); + Gson gson = new Gson(); + try { + Date startScan = new Date(); + String scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + let policies = %s; + + let checker = new window.ace_ibma.Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + setTimeout(function() { + checker.check(document, policies).then(function(report) { + for (const result of report.results) { + delete result.node; + } + cb(JSON.stringify(report)); + }) + },0) +} catch (e) { + cb(e); +} + """, gson.toJson(config.policies) /* TODO: ${JSON.stringify(ACEngineManager.customRulesets)}; */); + this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); + + String jsonReport = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + if (!jsonReport.startsWith("{\"results\":[")) { + throw new ACError(jsonReport); + } else { + return gson.fromJson(jsonReport, ACReport.class); + } + // TODO: + // String getPolicies = "return new window.ace_ibma.Checker().rulesetIds;"; + // if (curPol != null && !checkPolicy) { + // checkPolicy = true; + // const valPolicies = ACEngineManager.customRulesets.map(rs => rs.id).concat(await browser.executeScript(getPolicies)); + // areValidPolicy(valPolicies, curPol); + // } + + // // If there is something to report... + // let finalReport : IBaselineReport; + // if (report.results) { + // // Add URL to the result object + // const url = await browser.getCurrentUrl(); + // const title = await browser.getTitle(); + // let origReport : IEngineReport = JSON.parse(JSON.stringify(report)); + // if (Config.captureScreenshots && browser.takeScreenshot) { + // const image = await browser.takeScreenshot(); + // origReport.screenshot = image; + // } + // finalReport = ReporterManager.addEngineReport("Selenium", startScan, url, title, label, origReport); + // } + // return { + // "report": finalReport, + // "webdriver": parsed + // } + } catch (Error err) { + System.err.println(err); + throw err; + } + } + +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java index 46639123e..8d6365617 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java @@ -25,4 +25,13 @@ public static T firstNotNull(T ... args) { return null; } + public static boolean classIsAvailable(String className) { + try { + Class.forName(className); + return true; + } catch (Throwable ex) { + // Class or one of its dependencies is not present... + return false; + } + } } diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java new file mode 100644 index 000000000..da5ec64c2 --- /dev/null +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -0,0 +1,53 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able; + +import org.junit.Test; +import static org.junit.Assert.*; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.openqa.selenium.chrome.ChromeDriver; + +import com.ibm.able.engine.ACReport; + +public class AccessibilityCheckerTest { + private static ChromeDriver driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + String workingDir = System.getProperty("user.dir"); + String chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + System.setProperty("webdriver.chrome.driver", chromeDriverDir); + AccessibilityCheckerTest.driver = new ChromeDriver(); + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + AccessibilityCheckerTest.driver.close(); + } + + @Test public void getCompliance() { + AccessibilityCheckerTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); + assertNotNull(report); + assertTrue(report.results.length > 0); + } +} diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java deleted file mode 100644 index 4f6c5ac53..000000000 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/LibraryTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This source file was generated by the Gradle 'init' task - */ -package com.ibm.able; - -import org.junit.Test; -import static org.junit.Assert.*; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -// import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeDriver; - -import com.ibm.able.Library; - -public class LibraryTest { - private static ChromeDriver driver; - - /** - * Setup a Selenium Chrome environment before tests - */ - @BeforeClass public static void setup() { - String workingDir = System.getProperty("user.dir"); - String chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; - System.setProperty("webdriver.chrome.driver", chromeDriverDir); - LibraryTest.driver = new ChromeDriver(); - } - - /** - * Close Selenium Chrome environment after tests - */ - @AfterClass public static void teardown() { - LibraryTest.driver.close(); - } - - @Test public void someLibraryMethodReturnsTrue() { - LibraryTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); - String pageTitle = driver.getTitle(); - System.out.println("Page Title: " + pageTitle); - System.out.println(System.getProperty("user.dir")); - Library classUnderTest = new Library(); - assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod()); - } -} From 5464d6cf6a542a54c251d1253d6b60cbeadf9247 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 8 Aug 2024 14:52:28 -0500 Subject: [PATCH 06/73] First report --- java-accessibility-checker/lib/.gitignore | 1 + java-accessibility-checker/lib/build.gradle | 2 + .../com/ibm/able/AccessibilityChecker.java | 37 +-- .../IAbstractAPI.java} | 9 +- .../src/main/java/com/ibm/able/abs/MyFS.java | 54 +++++ .../main/java/com/ibm/able/config/Config.java | 5 + .../com/ibm/able/config/ConfigInternal.java | 5 - .../java/com/ibm/able/engine/ACEReport.java | 56 +++++ .../java/com/ibm/able/engine/ACError.java | 15 ++ .../java/com/ibm/able/engine/ACReport.java | 174 ++++++++++++-- .../com/ibm/able/engine/ACReportSummary.java | 86 +++++++ .../main/java/com/ibm/able/engine/Bounds.java | 23 ++ .../java/com/ibm/able/engine/Guideline.java | 39 ++++ .../eRuleConfidence.java} | 30 ++- .../java/com/ibm/able/engine/eRuleLevel.java | 42 ++++ .../enginecontext/EngineContextLocal.java | 76 ++++++ .../enginecontext/EngineContextManager.java | 44 ++++ .../EngineContextSelenium.java | 76 +++--- .../able/enginecontext/IEngineContext.java | 30 +++ .../com/ibm/able/report/ACReporterJSON.java | 46 ++++ .../com/ibm/able/report/CompressedReport.java | 133 +++++++++++ .../java/com/ibm/able/report/IReporter.java | 13 ++ .../com/ibm/able/report/ReporterFile.java | 12 + .../com/ibm/able/report/ReporterManager.java | 219 ++++++++++++++++++ .../com/ibm/able/report/ReporterStored.java | 15 ++ .../src/main/java/com/ibm/able/util/Misc.java | 12 + 26 files changed, 1168 insertions(+), 86 deletions(-) create mode 100644 java-accessibility-checker/lib/.gitignore rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{IEngineContext.java => abs/IAbstractAPI.java} (81%) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Bounds.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Guideline.java rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{EngineContextManager.java => engine/eRuleConfidence.java} (60%) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/eRuleLevel.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{selenium => enginecontext}/EngineContextSelenium.java (77%) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java diff --git a/java-accessibility-checker/lib/.gitignore b/java-accessibility-checker/lib/.gitignore new file mode 100644 index 000000000..872aa273a --- /dev/null +++ b/java-accessibility-checker/lib/.gitignore @@ -0,0 +1 @@ +results \ No newline at end of file diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 990aeaf0b..8078eaf36 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -28,6 +28,8 @@ dependencies { // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.16.1' implementation 'com.google.code.gson:gson:2.11.0' + // https://mavenlibs.com/maven/dependency/org.mozilla/rhino + implementation 'org.mozilla:rhino:1.7.14' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java index 422366a54..ab3b746ff 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java @@ -16,11 +16,24 @@ package com.ibm.able; import java.io.IOException; +import java.util.Date; + import com.ibm.able.config.ACConfigManager; import com.ibm.able.config.Config; +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.engine.ACEReport; import com.ibm.able.engine.ACReport; +import com.ibm.able.enginecontext.EngineContextManager; +import com.ibm.able.enginecontext.IEngineContext; +import com.ibm.able.report.ReporterManager; +import com.ibm.able.abs.IAbstractAPI; +import com.ibm.able.abs.MyFS; public class AccessibilityChecker { + private static boolean initialized = false; + private static IAbstractAPI myFS = new MyFS(); + private static IEngineContext localEngine; + /** * This function is responsible performing a scan based on the context that is provided, following are * the supported context type: @@ -47,32 +60,30 @@ public static ACReport getCompliance(Object content, String label) { AccessibilityChecker.initialize(); IEngineContext engineContext = EngineContextManager.getEngineContext(content); - try { - engineContext.loadEngine(); - } catch (IOException e) { - System.err.println("aChecker: Unable to load engine due to IOException: "+e.toString()); - e.printStackTrace(); - } // Get the Data when the scan is started // Start time will be in milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now. - return engineContext.getCompliance(label); + long startScan = new Date().getTime(); + ACEReport origReport = engineContext.getCompliance(label); + String url = engineContext.getUrl(); + String title = engineContext.getTitle(); + ACReport finalReport = ReporterManager.get().addEngineReport("Selenium", startScan, url, title, label, origReport); + return finalReport; } public static Config getConfig() { return ACConfigManager.getConfig(); } - public static Config getConfigUnsupported() { + public static ConfigInternal getConfigUnsupported() { return ACConfigManager.getConfigUnsupported(); } private static void initialize() { + if (initialized) return; + initialized = true; + localEngine = EngineContextManager.getEngineContext(null); // TODO: - // if (Config) return; - // Config = await ACConfigManager.getConfigUnsupported(); - // await ACEngineManager.loadEngineLocal(); - // let absAPI = new MyFS(); // let refactorMap : RefactorMap = {} // let rules = ACEngineManager.getRulesSync(); // for (const rule of rules) { @@ -82,7 +93,7 @@ private static void initialize() { // } // } // } - // ReporterManager.initialize(Config, absAPI, await ACEngineManager.getRulesets()); + ReporterManager.initialize(getConfigUnsupported(), myFS, localEngine.getGuidelines()); // BaselineManager.initialize(Config, absAPI, refactorMap); } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/IEngineContext.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/IAbstractAPI.java similarity index 81% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/IEngineContext.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/IAbstractAPI.java index 1ad11b3a7..021daab86 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/IEngineContext.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/IAbstractAPI.java @@ -13,14 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able; +package com.ibm.able.abs; import java.io.IOException; import com.ibm.able.engine.ACReport; -public interface IEngineContext { - void loadEngine() throws IOException; - - ACReport getCompliance(String label); +public interface IAbstractAPI { + public ACReport loadBaseline(String scanLabel); + public void writeFile(String path, Object contents) throws IOException; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java new file mode 100644 index 000000000..c0cc2c0cb --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java @@ -0,0 +1,54 @@ +package com.ibm.able.abs; + +import com.ibm.able.engine.ACReport; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.ibm.able.config.ACConfigManager; +import com.ibm.able.config.ConfigInternal; + +public class MyFS implements IAbstractAPI { + public static Gson gson = new Gson(); + + @Override + public void writeFile(String filePath, Object contents) throws IOException { + File outFile = this.prepFileSync(filePath); + FileWriter myWriter = new FileWriter(outFile); + myWriter.write(contents.toString()); + myWriter.close(); + } + + private File prepFileSync(String filePath) { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + Path outFile = Paths.get(System.getProperty("user.dir"), config.outputFolder, filePath); + File f = outFile.toFile(); + File dir = f.getParentFile(); + if (!dir.exists()) { + dir.mkdirs(); + } + return f; + } + + @Override + public ACReport loadBaseline(String scanLabel) { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + Path outPath = Paths.get(System.getProperty("user.dir"), config.baselineFolder, scanLabel+".json"); + File outFile = outPath.toFile(); + if (!outFile.exists()) return null; + JsonReader reader; + try { + reader = new JsonReader(new FileReader(outFile)); + } catch (FileNotFoundException e) { + return null; + } + return gson.fromJson(reader, ACReport.class); + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java index 10553a960..159f9e334 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java @@ -107,4 +107,9 @@ public class Config { * Default: ["html", "htm", "svg"] */ public String[] extensions = { "html", "htm", "svg" }; + + /** + * (optional) If the tool allows, should we capture screenshots + */ + public Boolean captureScreenshots = false; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java index 3b4f9af00..c72421e8e 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java @@ -62,11 +62,6 @@ public class ConfigInternal extends Config { */ public String ruleArchiveVersion = null; - /** - * (optional) If the tool allows, should we capture screenshots - */ - public Boolean captureScreenshots = false; - /** * (optional) If the tool allows, should we run headless */ diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java new file mode 100644 index 000000000..7752c72d7 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java @@ -0,0 +1,56 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.engine; +import java.util.Map; + +public class ACEReport { + + public static class Result { + public Result() {} + public Result(Result o) { + apiArgs = o.apiArgs; + bounds = o.bounds; + category = o.category; + message = o.message; + messageArgs = o.messageArgs.clone(); + path = o.path; + reasonId = o.reasonId; + ruleId = o.ruleId; + ruleTime = o.ruleTime; + snippet = o.snippet; + value = o.value.clone(); + } + public Object[] apiArgs; + public Bounds bounds; + public String category; + public String message; + public String[] messageArgs; + public Map path; + public String reasonId; + public String ruleId; + public int ruleTime; + public String snippet; + public String[] value; + } + + public int numExecuted; + public int ruleTime; + public int totalTime; + public Map> nls; + public Result[] results; + public String screenshot=null; +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java index 0be8b61f1..a6eb1f063 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java @@ -1,3 +1,18 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ package com.ibm.able.engine; public class ACError extends Error { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java index 68b1494c9..bc76d7d67 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java @@ -15,33 +15,161 @@ *****************************************************************************/ package com.ibm.able.engine; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import java.util.Map.Entry; + +import com.ibm.able.config.ConfigInternal; public class ACReport { - public static class Bounds { - int top; - int left; - int height; - int width; + public static class SummaryCounts { + public int violation = 0; + public int potentialviolation = 0; + public int recommendation = 0; + public int potentialrecommendation = 0; + public int manual = 0; + public int pass = 0; + public int ignored = 0; + public int elements = 0; + public int elementsViolation = 0; + public int elementsViolationReview = 0; + } + public static class Summary { + public SummaryCounts counts = new SummaryCounts(); + public long scanTime = 0; + public String ruleArchive = ""; + public String[] policies = {}; + public String[] reportLevels = {}; + public long startScan = 0; + public String URL = ""; } + public static class Result extends ACEReport.Result { + public boolean ignored = false; + public String help = ""; + public eRuleLevel level; + + public Result() {} + public Result(ACEReport.Result engineResult) { + super(engineResult); + } + } + public Result[] results = new Result[0]; + public int numExecuted = 0; + public Map> nls = new HashMap<>(); + public Summary summary = new Summary(); + public String scanID = ""; + public String toolID = ""; + public String label = ""; + public String screenshot=null; + public int ruleTime = 0; + + public ACReport() {} + public ACReport(ConfigInternal config, ACEReport engineReport, String label) { + numExecuted = engineReport.numExecuted; + nls = engineReport.nls; + screenshot = engineReport.screenshot; + ruleTime = engineReport.ruleTime; + results = new Result[engineReport.results.length]; + for (int idx=0; idx < results.length; ++idx) { + results[idx] = new Result(engineReport.results[idx]); + } + scanID = config.scanID; + toolID = config.toolID; + this.label = label; + } + + public void updateSummaryCounts() { + SummaryCounts counts = summary.counts; + counts.violation = 0; + counts.potentialviolation = 0; + counts.recommendation = 0; + counts.potentialrecommendation = 0; + counts.manual = 0; + counts.pass = 0; + counts.ignored = 0; + counts.elements = 0; + counts.elementsViolation = 0; + counts.elementsViolationReview = 0; + Set elementSet = new HashSet<>(); + Set elementViolationSet = new HashSet<>(); + Set elementViolationReviewSet = new HashSet<>(); + for (Result issue: results) { + elementSet.add(issue.path.get("dom")); + if (issue.ignored) { + ++counts.ignored; + } else { + if (eRuleLevel.violation.equals(issue.level)) { + ++counts.violation; + } else if (eRuleLevel.potentialviolation.equals(issue.level)) { + ++counts.potentialviolation; + } else if (eRuleLevel.recommendation.equals(issue.level)) { + ++counts.recommendation; + } else if (eRuleLevel.potentialrecommendation.equals(issue.level)) { + ++counts.potentialrecommendation; + } else if (eRuleLevel.manual.equals(issue.level)) { + ++counts.manual; + } else if (eRuleLevel.pass.equals(issue.level)) { + ++counts.pass; + } else if (eRuleLevel.ignored.equals(issue.level)) { + ++counts.ignored; + } + if (eRuleLevel.violation.equals(issue.level)) { + elementViolationSet.add(issue.path.get("dom")); + elementViolationReviewSet.add(issue.path.get("dom")); + } else if (eRuleLevel.potentialviolation.equals(issue.level) || eRuleLevel.manual.equals(issue.level)) { + elementViolationReviewSet.add(issue.path.get("dom")); + } + } + } + counts.elements = elementSet.size(); + counts.elementsViolation = elementViolationSet.size(); + counts.elementsViolationReview = elementViolationReviewSet.size(); + } + + public void filter(String[] reportLevels) { + Map> keepNlsKeys = new HashMap<>(); + List reportLevelsList = Arrays.asList(reportLevels); + Stream filtResults = Arrays.stream(results).filter(pageResult -> { + if (reportLevelsList.contains(pageResult.level.toString())) { + Set keepRuleReasons = keepNlsKeys.get(pageResult.ruleId); + if (keepRuleReasons == null) { + keepNlsKeys.put(pageResult.ruleId, new HashSet()); + keepRuleReasons = keepNlsKeys.get(pageResult.ruleId); + keepRuleReasons.add("0"); + } + keepRuleReasons.add(pageResult.reasonId); + if (pageResult.message.length() > 32000) { + pageResult.message = pageResult.message.substring(0, 32000 - 3) + "..."; + } + if (pageResult.snippet.length() > 32000) { + pageResult.snippet = pageResult.snippet.substring(0, 32000 - 3) + "..."; + } + return true; + } else { + return false; + } + }); + results = filtResults.toArray(size -> new Result[size]); - public static class Result { - public Object[] apiArgs; - public Bounds bounds; - public String category; - public String message; - public String[] messageArgs; - public Map path; - public String reasonId; - public String ruleId; - public int ruleTime; - public String snippet; - public String[] value; + if (nls != null) { + for (String ruleId: nls.keySet().toArray(new String[] {})) { + if (!keepNlsKeys.containsKey(ruleId)) { + nls.remove(ruleId); + } else { + Set keepRuleReasons = keepNlsKeys.get(ruleId); + Map nlsRuleMap = nls.get(ruleId); + for (String reasonId: nls.get(ruleId).values()) { + if (!keepRuleReasons.contains(reasonId)) { + nlsRuleMap.remove(reasonId); + } + } + } + } + } } - - public int numExecuted; - public int ruleTime; - public int totalTime; - public Map> nls; - public Result[] results; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java new file mode 100644 index 000000000..5bc97b4f3 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java @@ -0,0 +1,86 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ + +package com.ibm.able.engine; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.report.CompressedReport; +import com.ibm.able.report.ReporterStored; + +public class ACReportSummary { + public static class SummaryCounts { + public int violation = 0; + public int potentialviolation = 0; + public int recommendation = 0; + public int potentialrecommendation = 0; + public int manual = 0; + public int pass = 0; + public int ignored = 0; + public int elements = 0; + public int elementsViolation = 0; + public int elementsViolationReview = 0; + } + public static class PageSummary { + public String label; + public ACReport.SummaryCounts counts; + } + public SummaryCounts counts = new SummaryCounts(); + + public long startReport = 0; + public long endReport = 0; + public String toolID = ""; + public String[] policies = {}; + public String[] reportLevels = {}; + public String[] labels = {}; + public String[] failLevels = {}; + public String scanID = ""; + public PageSummary[] pageScanSummery = new PageSummary[0]; + + public ACReportSummary() {} + public ACReportSummary(ConfigInternal config, long endReport, CompressedReport[] compressedReports) { + this.startReport = compressedReports[0].getStartScan(); + this.endReport = endReport; + this.toolID = config.toolID; + this.policies = config.policies; + this.reportLevels = config.reportLevels; + this.labels = config.label; + this.failLevels = config.failLevels; + this.scanID = config.scanID; + this.pageScanSummery = new PageSummary[compressedReports.length]; + for (int idx=0; idx", 1, null); + } + + @Override + public ACEReport getCompliance(String label) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getCompliance'"); + } + + @Override + public String getUrl() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getUrl'"); + } + + @Override + public String getTitle() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getTitle'"); + } + + @Override + public Guideline[] getGuidelines() { + String scriptStr = "JSON.stringify(new ace.Checker().getGuidelines())"; + String jsonGuidelines = engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + return gson.fromJson(jsonGuidelines, Guideline[].class); + } + +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java new file mode 100644 index 000000000..3a2188a1a --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java @@ -0,0 +1,44 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.enginecontext; + +import java.io.IOException; + +import org.openqa.selenium.WebDriver; + +import com.ibm.able.util.Misc; + +public class EngineContextManager { + private EngineContextManager() {} + + public static IEngineContext getEngineContext(Object contentContext) { + IEngineContext engineContext = null; + if (contentContext == null) { + engineContext = new EngineContextLocal(); + } else if (Misc.classIsAvailable("org.openqa.selenium.WebDriver") && contentContext instanceof org.openqa.selenium.WebDriver) { + engineContext = new EngineContextSelenium((WebDriver) contentContext); + } + if (engineContext != null) { + try { + engineContext.loadEngine(); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine due to IOException: "+e.toString()); + e.printStackTrace(); + } + } + return engineContext; + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/selenium/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java similarity index 77% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/selenium/EngineContextSelenium.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java index 0030c94ff..bc8f58949 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/selenium/EngineContextSelenium.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java @@ -13,25 +13,28 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.selenium; +package com.ibm.able.enginecontext; import java.io.IOException; import java.time.Duration; import java.util.Date; import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import com.google.gson.Gson; -import com.ibm.able.IEngineContext; import com.ibm.able.config.ACConfigManager; import com.ibm.able.config.Config; import com.ibm.able.config.ConfigInternal; import com.ibm.able.engine.ACError; -import com.ibm.able.engine.ACReport; +import com.ibm.able.engine.Guideline; +import com.ibm.able.engine.ACEReport; import com.ibm.able.util.Fetch; public class EngineContextSelenium implements IEngineContext { + private static Gson gson = new Gson(); private WebDriver driver = null; private String engineContent = null; @@ -39,6 +42,7 @@ public EngineContextSelenium(WebDriver driver) { this.driver = driver; } + @Override public void loadEngine() throws IOException { ConfigInternal config = ACConfigManager.getConfigUnsupported(); String engineLoadMode = config.engineMode; @@ -85,7 +89,6 @@ public void loadEngine() throws IOException { } """, config.rulePack); } else if ("INJECT".equals(engineLoadMode)) { - Gson gson = new Gson(); // Selenium scriptStr = String.format(""" let cb = arguments[arguments.length - 1]; @@ -117,20 +120,16 @@ public void loadEngine() throws IOException { this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); - Object result = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr); - if (result != null) { - System.err.println(result); - } + ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr); } catch (Error e) { System.err.println(e); } } - public ACReport getCompliance(String label) { + @Override + public ACEReport getCompliance(String label) { Config config = ACConfigManager.getConfig(); - Gson gson = new Gson(); try { - Date startScan = new Date(); String scriptStr = String.format(""" let cb = arguments[arguments.length - 1]; try { @@ -154,10 +153,11 @@ public ACReport getCompliance(String label) { this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); String jsonReport = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + ACEReport report; if (!jsonReport.startsWith("{\"results\":[")) { throw new ACError(jsonReport); } else { - return gson.fromJson(jsonReport, ACReport.class); + report = gson.fromJson(jsonReport, ACEReport.class); } // TODO: // String getPolicies = "return new window.ace_ibma.Checker().rulesetIds;"; @@ -167,27 +167,45 @@ public ACReport getCompliance(String label) { // areValidPolicy(valPolicies, curPol); // } - // // If there is something to report... - // let finalReport : IBaselineReport; - // if (report.results) { - // // Add URL to the result object - // const url = await browser.getCurrentUrl(); - // const title = await browser.getTitle(); - // let origReport : IEngineReport = JSON.parse(JSON.stringify(report)); - // if (Config.captureScreenshots && browser.takeScreenshot) { - // const image = await browser.takeScreenshot(); - // origReport.screenshot = image; - // } - // finalReport = ReporterManager.addEngineReport("Selenium", startScan, url, title, label, origReport); - // } - // return { - // "report": finalReport, - // "webdriver": parsed - // } + // If there is something to report... + if (report.results != null) { + if (config.captureScreenshots) { + String image = ((TakesScreenshot)this.driver).getScreenshotAs(OutputType.BASE64); + report.screenshot = image; + } + } + return report; } catch (Error err) { System.err.println(err); throw err; } } + @Override + public String getUrl() { + return this.driver.getCurrentUrl(); + } + + @Override + public String getTitle() { + return this.driver.getTitle(); + } + + @Override + public Guideline[] getGuidelines() { + String scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + let checker = new window.ace_ibma.Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + cb(JSON.stringify(checker.getGuidelines())); +} catch (e) { + cb(e); +} +"""); + String jsonGuidelines = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Guideline[].class); + } + } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java new file mode 100644 index 000000000..4f456dbc2 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java @@ -0,0 +1,30 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.enginecontext; + +import java.io.IOException; + +import com.ibm.able.engine.ACEReport; +import com.ibm.able.engine.Guideline; + +public interface IEngineContext { + public void loadEngine() throws IOException; + + public ACEReport getCompliance(String label); + public String getUrl(); + public String getTitle(); + public Guideline[] getGuidelines(); +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java new file mode 100644 index 000000000..b287a62dd --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java @@ -0,0 +1,46 @@ +package com.ibm.able.report; + +import java.util.Date; + +import com.google.gson.Gson; +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.engine.ACReport; +import com.ibm.able.engine.ACReportSummary; +import com.ibm.able.engine.Guideline; +import com.ibm.able.util.Misc; + +public class ACReporterJSON implements IReporter { + private static Gson gson = new Gson(); + + @Override + public String name() { + return "json"; + } + + @Override + public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored storedReport) { + ACReport outReport = storedReport.engineReport; + return new ReporterFile( + outReport.label.replaceAll("[:?&=]", "_")+".json", + gson.toJson(outReport) + ); + } + + @Override + public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, int endReport, + CompressedReport[] compressedReports) + { + if (compressedReports != null && compressedReports.length > 0) { + ACReportSummary summReport = new ACReportSummary(config, endReport, compressedReports); + if (summReport != null) { + Date startScan = new Date(compressedReports[0].getStartScan()); + String reportFilename = "summary_"+Misc.toISOString(startScan).replaceAll(":","-")+".json"; + if (!config.outputFilenameTimestamp) { + reportFilename = "summary.json"; + } + return new ReporterFile(reportFilename, gson.toJson(summReport)); + } + } + return null; + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java new file mode 100644 index 000000000..371533e96 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java @@ -0,0 +1,133 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.report; + +import java.util.HashMap; +import java.util.Map; + +import com.ibm.able.engine.ACReport; + +public class CompressedReport { + public static String scanID; + public static String toolID; + public static Map> nlsStore = new HashMap<>(); + + public Object[] data = {}; + + public CompressedReport(ReporterStored info) { + ACReport report = info.engineReport; + ACReport.Summary summary = report.summary; + CompressedReport.scanID = report.scanID; + CompressedReport.toolID = report.toolID; + this.data = new Object[] { + summary.startScan, // startScan (0) + summary.URL, // url (1) + info.pageTitle, // pagetitle (2) + report.label, // label (3) + info.scanProfile, // scanProfile (4) + report.numExecuted, // numExecuted (5) + summary.scanTime, // scanTime (6) + summary.ruleArchive, // ruleArchive (7) + summary.policies, // policies (8) + summary.reportLevels, // reportLevels (9) + new Object[report.results.length][] // (10) + }; + for (int idx=0; idx 32000) { + issue[idx2] = ((String) issue[idx2]).substring(0, 32000 - 3) + "..."; + } + } + Map storeRuleMap = nlsStore.getOrDefault(result.ruleId, new HashMap()); + storeRuleMap.put( + result.reasonId, + report.nls.getOrDefault( + result.ruleId, + new HashMap() + ).getOrDefault( + result.reasonId, + result.ruleId+"_"+result.reasonId + ) + ); + } + } + + public ReporterStored uncompress() { + ACReport engineReport = new ACReport(); + engineReport.label = (String)data[3]; + engineReport.numExecuted = (Integer)data[5]; + ACReport.Summary summary = engineReport.summary; + summary.scanTime = (Long)data[6]; + summary.ruleArchive = (String)data[7]; + summary.policies = (String[])data[8]; + summary.reportLevels = (String[])data[9]; + summary.startScan = (Long)data[0]; + summary.URL = (String)data[1]; + engineReport.results = new ACReport.Result[((Object[])data[10]).length]; + for (int idx=0; idx<((Object[][])data[10]).length; ++idx) { + Object[] issue = ((Object[][])data[10])[idx]; + ACReport.Result result = engineReport.results[idx] = new ACReport.Result(); + result.category = (String)issue[0]; + result.ruleId = (String)issue[1]; + result.value = (String[])issue[2]; + result.reasonId = (String)issue[3]; + result.messageArgs = (String[])issue[4]; + result.apiArgs = new Object[] {}; + result.path = (Map)issue[5]; + result.ruleTime = (Integer)issue[6]; + result.message = (String)issue[10]; + result.snippet = (String)issue[7]; + result.help = (String)issue[8]; + result.ignored = (Boolean)issue[9]; + result.level = ReporterManager.valueToLevel((String[])issue[2]); + Map nlsRuleMap = engineReport.nls.getOrDefault(result.ruleId, new HashMap()); + nlsRuleMap.put( + result.reasonId, + nlsStore.getOrDefault( + result.ruleId, + new HashMap() + ).getOrDefault( + result.reasonId, + result.ruleId+"_"+result.reasonId + ) + ); + } + engineReport.updateSummaryCounts(); + return new ReporterStored(data[2].toString(), data[4].toString(), null); + } + + public long getStartScan() { + return (Long)data[0]; + } + + public String getLabel() { + return (String)data[3]; + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java new file mode 100644 index 000000000..2b948c421 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java @@ -0,0 +1,13 @@ +package com.ibm.able.report; + +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.engine.Guideline; + +public interface IReporter { + String name(); + /** + * @return [ reportPath: string, report: string ] + */ + ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored reportData); + ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, int endReport, CompressedReport[] summaryData); +}; \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java new file mode 100644 index 000000000..aeeec3c03 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java @@ -0,0 +1,12 @@ +package com.ibm.able.report; + +public class ReporterFile { + public String path; + // summary: string | Buffer | ((filename?: string) => Promise) + public Object contents; + + public ReporterFile(String path, String contents) { + this.path = path; + this.contents = contents; + } +} \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java new file mode 100644 index 000000000..0eee9db70 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java @@ -0,0 +1,219 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.report; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gson.Gson; +import com.ibm.able.abs.IAbstractAPI; +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.engine.ACEReport; +import com.ibm.able.engine.ACError; +import com.ibm.able.engine.ACReport; +import com.ibm.able.engine.Guideline; +import com.ibm.able.engine.eRuleConfidence; +import com.ibm.able.engine.eRuleLevel; +import com.ibm.able.engine.ACReport.Result; + +public class ReporterManager { + private static Gson gson = new Gson(); + private static ReporterManager singleton = null; + public static ReporterManager get() { + if (singleton == null) throw new ACError("RepoterManager not intialized"); + return singleton; + } + public static ReporterManager initialize(ConfigInternal config, IAbstractAPI absAPI, Guideline[] rulesets) { + return singleton = new ReporterManager(config, absAPI, rulesets); + } + + private ConfigInternal config; + private IAbstractAPI absAPI; + private Guideline[] rulesets; + private List reporters = new ArrayList<>(); + private List reports = new ArrayList<>(); + private IReporter returnReporter = new ACReporterJSON(); + + + private ReporterManager(ConfigInternal config, IAbstractAPI absAPI, Guideline[] rulesets) { + this.config = config; + this.absAPI = absAPI; + this.rulesets = rulesets; + if (config.perfMetrics) { + // TODO: + // reporters.add(new ACReporterMetrics(config.toolName, config.policies)); + } + + if (!Arrays.asList(config.outputFormat).contains("disable")) { + if (Arrays.asList(config.outputFormat).contains("json")) { + reporters.add(new ACReporterJSON()); + } + if (Arrays.asList(config.outputFormat).contains("html")) { + // TODO: + // reporters.push(new ACReporterHTML()) + } + if (Arrays.asList(config.outputFormat).contains("csv")) { + // TODO: + // reporters.add(new ACReporterCSV()); + } + if (Arrays.asList(config.outputFormat).contains("xlsx")) { + // TODO: + // reporters.add(new ACReporterXLSX()); + } + } + } + private Set usedLabels = new HashSet(); + + public ACReport addEngineReport(String scanProfile, long startScan, String url, String pageTitle, String label, ACEReport engineReport) { + verifyLabel(label); + usedLabels.add(label); + ACReport filteredReport = filterReport(engineReport, label); + filteredReport.summary.startScan = startScan; + filteredReport.summary.URL = url; + filteredReport.label = label; + ReporterStored storedReport = new ReporterStored(pageTitle, scanProfile, filteredReport); + for (Result issue: filteredReport.results) { + issue.help = getHelpUrl(issue); + } + CompressedReport compressedReport = new CompressedReport(storedReport); + if (reporters.size() > 0) { + reports.add(compressedReport); + for (IReporter reporter: reporters) { + ReporterFile reportInfo = reporter.generateReport(config, rulesets, storedReport); + if (reportInfo != null) { + try { + absAPI.writeFile(reportInfo.path, reportInfo.contents); + } catch (IOException e) { + System.err.println(e); + e.printStackTrace(); + } + } + } + } + ReporterFile retVal = returnReporter.generateReport(config, rulesets, storedReport); + if (retVal != null) return gson.fromJson(retVal.contents.toString(), ACReport.class); + return null; + } + + private void verifyLabel(String label) { + // In the case that the label is null or undefined, throw an error + if (label == null) { + throw new ACError("labelNotProvided: Label must be provided when calling aChecker.getCompliance."); + } + + // Check to make sure that the label that is provided is unique with all the other ones + // that we have gone through. + boolean labelUnique = isLabelUnique(label); + + // In the case that the label is not unique + if (!labelUnique) { + throw new ACError("Label provided to aChecker.getCompliance ("+label+") should be unique across all testcases in a single accessibility-checker session."); + } + } + + private boolean isLabelUnique(String label) { + return !usedLabels.contains(label); + } + + private ACReport filterReport(ACEReport engineResult, String scanLabel) { + Map>> ignoreLookup = new HashMap>> (); + + ACReport baselineReport = absAPI.loadBaseline(scanLabel); + if (baselineReport != null) { + for (Result issue : baselineReport.results) { + // ignoreLookup[issue.path.dom] = ignoreLookup[issue.path.dom] || {} + Map> a = ignoreLookup.get(issue.path.get("dom")); + if (a == null) { + ignoreLookup.put(issue.path.get("dom"), new HashMap>()); + a = ignoreLookup.get(issue.path.get("dom")); + } + // ignoreLookup[issue.path.dom][issue.ruleId] = ignoreLookup[issue.path.dom][issue.ruleId] || {} + Set b = a.get(issue.ruleId); + if (b == null) { + b = new HashSet(); + } + // ignoreLookup[issue.path.dom][issue.ruleId][issue.reasonId] = true; + b.add(issue.reasonId); + } + } + ACReport retVal = new ACReport(config, engineResult, scanLabel); + + // Set the config level and filter the results. Make note of which NLS keys we need + for (ACReport.Result pageResult: retVal.results) { + eRuleLevel reportLevel = ReporterManager.valueToLevel(pageResult.value); + boolean ignored = false; + if (!eRuleConfidence.PASS.toString().equals(pageResult.value[1]) + && ignoreLookup.containsKey(pageResult.path.get("dom")) + && ignoreLookup.get(pageResult.path.get("dom")).containsKey(pageResult.ruleId) + && ignoreLookup.get(pageResult.path.get("dom")).get(pageResult.ruleId).contains(pageResult.reasonId)) + { + ignored = true; + } + pageResult.ignored = ignored; + pageResult.level = reportLevel; + } + + retVal.updateSummaryCounts(); + retVal.filter(config.reportLevels); + + return retVal; + } + + public static eRuleLevel valueToLevel(String[] reportValue) { + eRuleLevel reportLevel = eRuleLevel.undefined; + if ("PASS".equals(reportValue[1])) { + reportLevel = eRuleLevel.pass; + } else if (("VIOLATION".equals(reportValue[0]) || "RECOMMENDATION".equals(reportValue[0])) && "MANUAL".equals(reportValue[1])) { + reportLevel = eRuleLevel.manual; + } else if ("VIOLATION".equals(reportValue[0])) { + if ("FAIL".equals(reportValue[1])) { + reportLevel = eRuleLevel.violation; + } else if ("POTENTIAL".equals(reportValue[1])) { + reportLevel = eRuleLevel.potentialviolation; + } + } else if ("RECOMMENDATION".equals(reportValue[0])) { + if ("FAIL".equals(reportValue[1])) { + reportLevel = eRuleLevel.recommendation; + } else if ("POTENTIAL".equals(reportValue[1])) { + reportLevel = eRuleLevel.potentialrecommendation; + } + } + return reportLevel; + } + + private String getHelpUrl(ACReport.Result issue) { + if (issue.help != null && issue.help.length() > 0) return issue.help; + return ""; + // TODO: + // let config = ReporterManager.config; + // let helpUrl = ReporterManager.absAPI.getChecker().engine.getHelp(issue.ruleId, issue.reasonId, !config.ruleArchivePath ? config.ruleArchive : config.ruleArchivePath.substring(config.ruleArchivePath.lastIndexOf("/")+1)); + // let minIssue = { + // message: issue.message, + // snippet: issue.snippet, + // value: issue.value, + // reasonId: issue.reasonId, + // ruleId: issue.ruleId, + // msgArgs: issue.messageArgs + // }; + // return `${helpUrl}#${encodeURIComponent(JSON.stringify(minIssue))}` + } +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java new file mode 100644 index 000000000..cf41153a8 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java @@ -0,0 +1,15 @@ +package com.ibm.able.report; + +import com.ibm.able.engine.ACReport; + +public class ReporterStored { + public String pageTitle; + public String scanProfile; + public ACReport engineReport; + + public ReporterStored(String title, String profile, ACReport report) { + pageTitle = title; + scanProfile = profile; + engineReport = report; + } +}; \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java index 8d6365617..e8b59a7ff 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java @@ -15,6 +15,11 @@ *****************************************************************************/ package com.ibm.able.util; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + public class Misc { private Misc() {} @@ -34,4 +39,11 @@ public static boolean classIsAvailable(String className) { return false; } } + + public static String toISOString(Date d) { + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); + df.setTimeZone(tz); + return df.format(d); + } } From fc99aa04a4228d131cbdc314f2c36dcfd1a6ff64 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 9 Aug 2024 00:51:12 -0500 Subject: [PATCH 07/73] Baselines --- .../com/ibm/able/AccessibilityChecker.java | 249 +++++++------- .../com/ibm/able/config/ACConfigManager.java | 4 +- .../java/com/ibm/able/engine/ACEReport.java | 22 +- .../java/com/ibm/able/engine/ACReport.java | 61 +++- .../main/java/com/ibm/able/engine/Bounds.java | 19 +- .../main/java/com/ibm/able/engine/Rule.java | 23 ++ .../enginecontext/EngineContextLocal.java | 12 +- .../enginecontext/EngineContextSelenium.java | 15 + .../able/enginecontext/IEngineContext.java | 2 + .../com/ibm/able/report/BaselineManager.java | 308 ++++++++++++++++++ .../ibm/able/AccessibilityCheckerTest.java | 19 ++ .../com/ibm/able/engine/ACReportTest.java | 49 +++ .../java/com/ibm/able/util/FetchTest.java | 18 +- 13 files changed, 640 insertions(+), 161 deletions(-) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Rule.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java create mode 100644 java-accessibility-checker/lib/src/test/java/com/ibm/able/engine/ACReportTest.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java index ab3b746ff..271791e54 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java @@ -15,17 +15,23 @@ *****************************************************************************/ package com.ibm.able; -import java.io.IOException; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import com.ibm.able.config.ACConfigManager; import com.ibm.able.config.Config; import com.ibm.able.config.ConfigInternal; import com.ibm.able.engine.ACEReport; import com.ibm.able.engine.ACReport; +import com.ibm.able.engine.Guideline; +import com.ibm.able.engine.Rule; import com.ibm.able.enginecontext.EngineContextManager; import com.ibm.able.enginecontext.IEngineContext; +import com.ibm.able.report.BaselineManager; import com.ibm.able.report.ReporterManager; +import com.ibm.able.report.BaselineManager.DiffResult; +import com.ibm.able.report.BaselineManager.eAssertResult; import com.ibm.able.abs.IAbstractAPI; import com.ibm.able.abs.MyFS; @@ -83,37 +89,37 @@ private static void initialize() { if (initialized) return; initialized = true; localEngine = EngineContextManager.getEngineContext(null); - // TODO: - // let refactorMap : RefactorMap = {} - // let rules = ACEngineManager.getRulesSync(); - // for (const rule of rules) { - // if (rule.refactor) { - // for (const key in rule.refactor) { - // refactorMap[key] = rule; - // } - // } - // } - ReporterManager.initialize(getConfigUnsupported(), myFS, localEngine.getGuidelines()); - // BaselineManager.initialize(Config, absAPI, refactorMap); + Map refactorMap = new HashMap<>(); + Rule[] rules = localEngine.getRules(); + for (Rule rule: rules) { + if (rule.refactor != null) { + for (String key: rule.refactor.keySet()) { + refactorMap.put(key, rule); + } + } + } + ConfigInternal config = getConfigUnsupported(); + ReporterManager.initialize(config, myFS, localEngine.getGuidelines()); + BaselineManager.initialize(config, myFS, refactorMap); } -// /** -// * This function is responsible for comparing the scan results with baseline or checking that there are -// * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will -// * be used to perform the check, in the case no baseline is provided then we comply with only failing if -// * there is a sinble violation which falls into failLevels. -// * -// * @param {ReportResult} actual - the actual results object provided by the user, this object should follow the -// * same format as outlined in the return of aChecker.buildReport function. -// * -// * @return {int} - return 0 in the case actual matches baseline or no violations fall into failsLevels, -// * return 1 in the case actual results does not match baseline results, -// * return 2 in the case that there is a failure based on failLevels (this means no baseline found). -// * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. -// */ -// export function assertCompliance(report: IBaselineReport) : eAssertResult { -// return BaselineManager.assertCompliance(report) -// } + /** + * This function is responsible for comparing the scan results with baseline or checking that there are + * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will + * be used to perform the check, in the case no baseline is provided then we comply with only failing if + * there is a sinble violation which falls into failLevels. + * + * @param {ReportResult} actual - the actual results object provided by the user, this object should follow the + * same format as outlined in the return of aChecker.buildReport function. + * + * @return {int} - return 0 in the case actual matches baseline or no violations fall into failsLevels, + * return 1 in the case actual results does not match baseline results, + * return 2 in the case that there is a failure based on failLevels (this means no baseline found). + * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. + */ + public static eAssertResult assertCompliance(ACReport report) { + return BaselineManager.assertCompliance(report); + } // /** // * This function is responsible for printing the scan results to console. @@ -134,124 +140,87 @@ private static void initialize() { // return ACBrowserManager.close(); // } -// /** -// * This function is responsible for getting the diff results based on label for a scan that was already performed. -// * -// * @param {String} label - Provide a lable for which to get the diff results for. -// * -// * @return {Object} - return the diff results object from global space based on label provided, the object will be -// * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. -// */ -// export function getDiffResults(label: string) { -// return BaselineManager.getDiffResults(label); -// } - -// /** -// * This function is responsible for getting the baseline object for a label that was provided. -// * -// * @param {String} label - Provide a lable for which to get the baseline for. -// * -// * @return {Object} - return the baseline object from global space based on label provided, the object will be -// * in the same format as outlined in the return of aChecker.buildReport function. -// */ -// export function getBaseline(label: string) { -// return BaselineManager.getBaseline(label); -// } + /** + * This function is responsible for getting the diff results based on label for a scan that was already performed. + * + * @param {String} label - Provide a lable for which to get the diff results for. + * + * @return {Object} - return the diff results object from global space based on label provided, the object will be + * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. + */ + public static DiffResult[] getDiffResults(String label) { + return BaselineManager.getDiffResults(label); + } -// /** -// * This function is responsible for comparing actual with expected and returning all the differences as an array. -// * -// * @param {Object} actual - Provide the actual object to be used for compare -// * @param {Object} expected - Provide the expected object to be used for compare -// * @param {boolean} clean - Provide a boolean if both the actual and expected objects need to be cleaned -// * cleaning refers to converting the objects to match with a basic compliance -// * compare of xpath and ruleId. -// * -// * @return {Object} differences - return an array of diff objects that were found, following is the format of the object: -// * [ -// * { -// * "kind": "E", -// * "path": [ -// * "reports", -// * 0, -// * "issues", -// * 10, -// * "xpath" -// * ], -// * "lhs": "/html[1]/body[1]/div[2]/table[5]", -// * "rhs": "/html[1]/body[1]/div[2]/table[5]d", -// * }, -// * { -// * "kind": "E", -// * "path": [ -// * "label" -// * ], -// * "lhs": "Table-layoutMultiple", -// * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html", -// * } -// * ] -// */ -// export function diffResultsWithExpected(actual, expected, clean) { -// return BaselineManager.diffResultsWithExpected(actual, expected, clean); -// } + /** + * This function is responsible for getting the baseline object for a label that was provided. + * + * @param {String} label - Provide a lable for which to get the baseline for. + * + * @return {Object} - return the baseline object from global space based on label provided, the object will be + * in the same format as outlined in the return of aChecker.buildReport function. + */ + public static ACReport getBaseline(String label) { + return BaselineManager.getBaseline(label); + } -// /** -// * This function is responsible for cleaning up the compliance baseline or actual results, based on -// * a pre-defined set of criterias, such as the following: -// * 1. No need to compare summary object -// * 2. Only need to compare the ruleId and xpath in for each of the issues -// * -// * @param {Object} objectToClean - Provide either an baseline or actual results object which would be in the -// * the same format as outlined in the return of aChecker.buildReport function. -// * -// * @return {Object} objectToClean - return an object that was cleaned to only contain the information that is -// * needed for compare. Following is a sample of how the cleaned object will look like: -// * { -// * "label": "unitTestContent", -// * "reports": [ -// * { -// * "frameIdx": "0", -// * "frameTitle": "Frame 0", -// * "issues": [ -// * { -// * "ruleId": "1", -// * "xpath": "/html[1]/head[1]/style[1]" -// * } -// * .... -// * ] -// * }, -// * { -// * "frameIdx": "1", -// * "frameTitle": "Frame 1", -// * "issues": [ -// * { -// * "ruleId": "471", -// * "xpath": "/html[1]/body[1]/div[2]/table[3]" -// * } -// * .... -// * ] -// * } -// * ] -// * } -// */ -// export function cleanComplianceObjectBeforeCompare(objectToClean) { -// return BaselineManager.cleanComplianceObjectBeforeCompare(objectToClean); -// } + /** + * This function is responsible for comparing actual with expected and returning all the differences as an array. + * + * @param {Object} actual - Provide the actual object to be used for compare + * @param {Object} expected - Provide the expected object to be used for compare + * @param {boolean} clean - Provide a boolean if both the actual and expected objects need to be cleaned + * cleaning refers to converting the objects to match with a basic compliance + * compare of xpath and ruleId. + * + * @return {Object} differences - return an array of diff objects that were found, following is the format of the object: + * [ + * { + * "kind": "E", + * "path": [ + * "reports", + * 0, + * "issues", + * 10, + * "xpath" + * ], + * "lhs": "/html[1]/body[1]/div[2]/table[5]", + * "rhs": "/html[1]/body[1]/div[2]/table[5]d", + * }, + * { + * "kind": "E", + * "path": [ + * "label" + * ], + * "lhs": "Table-layoutMultiple", + * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html", + * } + * ] + */ + public static DiffResult[] diffResultsWithExpected(ACReport actual, ACReport expected) { + return BaselineManager.diffResultsWithExpected(actual, expected); + } // export function addRuleset(ruleset) { // ACEngineManager.addRuleset(ruleset); // } -// export async function getRuleset(rsId) { -// return ACEngineManager.getRuleset(rsId); -// }; + public static Guideline getGuideline(String rsId) { + Guideline[] gs = getGuidelines(); + for (int i=0; i { + int cc = b.category.compareTo(a.category); + if (cc != 0) return cc; + int pc = b.path.get("dom").compareTo(a.path.get("dom")); + if (pc != 0) return pc; + return b.ruleId.compareTo(a.ruleId); + }); + } + + @Override + public Object clone() { + // Shallow copy + ACReport ret = null; + try { + ret = (ACReport)super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + ret.summary = (Summary)summary.clone(); + ret.results = new ACReport.Result[results.length]; + for (int idx=0; idx> refactor = null; +} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java index 2a0a9aca2..f3aed0446 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java @@ -21,6 +21,7 @@ import com.ibm.able.config.ConfigInternal; import com.ibm.able.engine.ACEReport; import com.ibm.able.engine.Guideline; +import com.ibm.able.engine.Rule; import com.ibm.able.util.Fetch; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; @@ -33,7 +34,7 @@ public class EngineContextLocal implements IEngineContext { @Override public void loadEngine() throws IOException { ConfigInternal config = ACConfigManager.getConfigUnsupported(); - String engineContent = Fetch.get(config.rulePack+"/ace.js"); + String engineContent = Fetch.get(config.rulePack+"/ace.js")+";var ace_checker = new ace.Checker();"; // Creates and enters a Context. The Context stores information // about the execution environment of a script. @@ -68,9 +69,16 @@ public String getTitle() { @Override public Guideline[] getGuidelines() { - String scriptStr = "JSON.stringify(new ace.Checker().getGuidelines())"; + String scriptStr = "JSON.stringify(ace_checker.getGuidelines())"; String jsonGuidelines = engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); return gson.fromJson(jsonGuidelines, Guideline[].class); + } + + @Override + public Rule[] getRules() { + String scriptStr = "JSON.stringify(Object.keys(ace_checker.engine.ruleMap).map(key => ace_checker.engine.ruleMap[key]))"; + String jsonGuidelines = engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + return gson.fromJson(jsonGuidelines, Rule[].class); } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java index bc8f58949..6a0cf0f8f 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java @@ -30,6 +30,7 @@ import com.ibm.able.config.ConfigInternal; import com.ibm.able.engine.ACError; import com.ibm.able.engine.Guideline; +import com.ibm.able.engine.Rule; import com.ibm.able.engine.ACEReport; import com.ibm.able.util.Fetch; @@ -208,4 +209,18 @@ public Guideline[] getGuidelines() { return gson.fromJson(jsonGuidelines, Guideline[].class); } + @Override + public Rule[] getRules() { + String scriptStr = String.format(""" +let cb = arguments[arguments.length - 1]; +try { + let checker = new window.ace_ibma.Checker(); + cb(JSON.stringify(checker.getRules())); +} catch (e) { + cb(e); +} +"""); + String jsonGuidelines = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Rule[].class); + } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java index 4f456dbc2..9fb7e67f3 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java @@ -19,6 +19,7 @@ import com.ibm.able.engine.ACEReport; import com.ibm.able.engine.Guideline; +import com.ibm.able.engine.Rule; public interface IEngineContext { public void loadEngine() throws IOException; @@ -27,4 +28,5 @@ public interface IEngineContext { public String getUrl(); public String getTitle(); public Guideline[] getGuidelines(); + public Rule[] getRules(); } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java new file mode 100644 index 000000000..1415b92d0 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java @@ -0,0 +1,308 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*****************************************************************************/ + +package com.ibm.able.report; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import com.google.gson.Gson; +import com.ibm.able.abs.IAbstractAPI; +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.engine.ACReport; +import com.ibm.able.engine.ACReport.Result; +import com.ibm.able.engine.Rule; + +/** + * This interface is responsible for aChecker baselines and comparing scans to baselines + */ +public class BaselineManager { + private static Gson gson = new Gson(); + public static enum eAssertResult { + ERROR(-1), + PASS(0), + BASELINE_MISMATCH(1), + FAIL(2) + ; + + private final int val; + + eAssertResult(final int val) { + this.val = val; + } + + int intValue() { + return this.val; + } + } + + public static class DiffResult { + public String kind = null; + public Object[] path = new Object[]{}; + public Object lhs = null; + public Object rhs = null; + public Integer index = null; + public DiffResult item = null; + + public DiffResult(String kind, Object[] path, Object lhs, Object rhs) { + this.kind = kind; + this.path = path; + this.lhs = lhs; + this.rhs = rhs; + } + + public DiffResult(String kind, int index, Object lhs, Object rhs) { + this.kind = kind; + this.index = index; + if (lhs != null && rhs != null) throw new RuntimeException("Cannot have index with lhs and rhs"); + this.item = new DiffResult(lhs != null ? "D" : "N", null, lhs, rhs); + } + } + + private static ConfigInternal config; + private static Map diffResults = new HashMap<>(); + private static IAbstractAPI absAPI; + private static Map refactorMap; + + public static void initialize(ConfigInternal config, IAbstractAPI absAPI, Map refactorMap) { + BaselineManager.config = config; + BaselineManager.absAPI = absAPI; + BaselineManager.refactorMap = refactorMap; + } + + public static ACReport getBaseline(String label) { + try { + ACReport retVal = BaselineManager.absAPI.loadBaseline(label); + if (retVal != null && retVal.results != null) { + for (ACReport.Result result: retVal.results) { + if (refactorMap.containsKey(result.ruleId)) { + Rule rule = refactorMap.get(result.ruleId); + Map mapping = rule.refactor.get(result.ruleId); + result.ruleId = rule.id; + result.reasonId = mapping.get(result.reasonId); + } + } + } + return retVal; + } catch (Error e) { + // console.error("getBaseline Error:", e); + return null; + } + } + + /** + * This function is responsible for comparing the scan results with baseline or checking that there are + * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will + * be used to perform the check, in the case no baseline is provided then we comply with only failing if + * there is a sinble violation which falls into failLevels. + * + * @param {Object} actual - the actual results object provided by the user, this object should follow the + * same format as outlined in the return of aChecker.buildReport function. + * + * @return {int} - return 0 in the case actual matches baseline or no violations fall into failsLevels, + * return 1 in the case actual results does not match baseline results, + * return 2 in the case that there is a failure based on failLevels (this means no baseline found). + * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. + * + * PUBLIC API + * + * @memberOf this + */ + public static eAssertResult assertCompliance(ACReport actualResults) { + // Get the label directly from the results object, the same label has to match + // the baseline object which is available in the global space. + String label = actualResults.label; + + // Fetch the baseline object based on the label provided + ACReport expected = BaselineManager.getBaseline(label); + + // In the case there are no baseline found then run a different assertion algo, + // when there is baseline compare the baselines in the case there is no baseline then + // check to make sure there are no violations that are listed in the fails on. + if (expected != null) { + // Run the diff algo to get the list of differences + DiffResult[] differences = BaselineManager.diffResultsWithExpected(actualResults, expected); + + // console.log("difference=" + JSON.stringify(differences, null, ' ')); + + // In the case that there are no differences then that means it passed + if (differences == null || differences.length == 0) { + return eAssertResult.PASS; + } else { + // Re-sort results and check again + ACReport modActual = (ACReport) actualResults.clone(); + modActual.sortResults(); + ACReport modExpected = (ACReport) expected.clone(); + modExpected.sortResults(); + DiffResult[] differences2 = BaselineManager.diffResultsWithExpected(modActual, modExpected); + if (differences2 == null || differences2.length == 0) { + return eAssertResult.PASS; + } else { + // In the case that there are failures add the whole diff array to + // global space indexed by the label so that user can access it. + BaselineManager.diffResults.put(label, differences); + + return eAssertResult.BASELINE_MISMATCH; + } + } + } else { + // In the case that there was no baseline data found compare the results based on + // the failLevels array, which was defined by the user. + int returnCode = BaselineManager.compareBasedOnFailLevels(actualResults); + + // In the case there are no violations that match the fail on then return as success + if (returnCode == 0) { + return eAssertResult.PASS; + } else { + // In the case there are some violation that match in the fail on then return 2 + // to identify that there was a failure, and we used a 2nd method for compare. + return eAssertResult.FAIL; + } + } + }; + + + /** + * This function is responsible for comparing actual with expected and returning all the differences as an array. + * + * @param {Object} actual - Provide the actual object to be used for compare + * @param {Object} expected - Provide the expected object to be used for compare + * @param {boolean} clean - Provide a boolean if both the actual and expected objects need to be cleaned + * cleaning refers to converting the objects to match with a basic compliance + * compare of xpath and ruleId. + * + * @return {Object} differences - return an array of diff objects that were found, following is the format of the object: + * [ + * { + * "kind": "E", + * "path": [ + * "reports", + * 0, + * "issues", + * 10, + * "xpath" + * ], + * "lhs": "/html[1]/body[1]/div[2]/table[5]", + * "rhs": "/html[1]/body[1]/div[2]/table[5]d", + * }, + * { + * "kind": "E", + * "path": [ + * "label" + * ], + * "lhs": "Table-layoutMultiple", + * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html", + * } + * ] + * + * PUBLIC API + * + * @memberOf this + */ + public static DiffResult[] diffResultsWithExpected(ACReport actual, ACReport expected) { + // Run Deep diff function to compare the actual and expected values. + DiffResult[] differences = diff(actual, expected); + if (differences != null && differences.length > 0) { + differences = Arrays.stream(differences).filter(difference -> { + return "E".equals(difference.kind) + && difference.path.length == 4 + && difference.path.length > 2 && "bounds".equals(difference.path[2]) + && Math.abs((Integer)difference.lhs-(Integer)difference.rhs) <= 1; + }).toArray(size -> new DiffResult[size]); + if (differences.length == 0) return null; + } + + // Return the results of the diff, which will include the differences between the objects + return differences; + } + + /** + * This function is responsible for checking if any of the issues reported have any level that falls + * into the failsLevel array. + * + * @param {Object} results - Provide the scan results, object which would be in the + * the same format as outlined in the return of aChecker.buildReport function. + * + * @return {int} - return 1 in the case a single issue was found which is in the failsLevel array. + * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. + * + * PRIVATE METHOD + * + * @memberOf this + */ + public static int compareBasedOnFailLevels(ACReport report) { + // Variable Declaration + String[] failLevels = BaselineManager.config.failLevels; + + // Loop over all the issues to check for any level that is in failLevels + // console.log(report); + for (ACReport.Result issue: report.results) { + // In the case current level is in the failsLevel array them fail, with out checking further + // currently we are not saving exactly which results failed, as all the issues are going to be saved to + // results file. + if (Arrays.asList(failLevels).indexOf(issue.level.toString()) > -1) { + // return 1 as there was a fialure + return 1; + } + } + + // return 0 as there were no levels that fall into the failLevels + return 0; + } + + /** + * This function is responsible for getting the diff results based on label for a scan that was already performed. + * + * @param {String} label - Provide a lable for which to get the diff results for. + * + * @return {Object} - return the diff results object from global space based on label provided, the object will be + * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. + * + * PUBLIC API + * + * @memberOf this + */ + public static DiffResult[] getDiffResults(String label) { + return diffResults.get(label); + } + + private static DiffResult[] diff(ACReport actual, ACReport expected) { + Result[] actualRs = actual.results; + Result[] expectedRs = expected.results; + ArrayList retVal = new ArrayList<>(); + for (int idx=actualRs.length; idx < expectedRs.length; ++idx) { + retVal.add(new DiffResult("A", idx, null, gson.toJson(expectedRs[idx]))); + } + for (int idx=expectedRs.length; idx < actualRs.length; ++idx) { + retVal.add(new DiffResult("A", idx, gson.toJson(expectedRs[idx]), null)); + } + for (int idx=0; idx 0); } + + @Test public void baselines() throws IOException { + Paths.get("baselines", "getComplianceTest3.json").toFile().delete(); + AccessibilityCheckerTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest2"); + assertEquals(eAssertResult.FAIL, AccessibilityChecker.assertCompliance(report)); + new File("baselines").mkdirs(); + Files.copy(Paths.get("results", "getComplianceTest2.json").toFile(), Paths.get("baselines", "getComplianceTest3.json").toFile()); + + report = AccessibilityChecker.getCompliance(driver, "getComplianceTest3"); + assertEquals(eAssertResult.PASS, AccessibilityChecker.assertCompliance(report)); + Paths.get("baselines", "getComplianceTest3.json").toFile().delete(); + } } diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/engine/ACReportTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/engine/ACReportTest.java new file mode 100644 index 000000000..371a12422 --- /dev/null +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/engine/ACReportTest.java @@ -0,0 +1,49 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.engine; + +import org.junit.Test; +import static org.junit.Assert.*; + +import com.ibm.able.engine.ACReport; + +public class ACReportTest { + + @Test public void cloneTest() { + ACReport one = new ACReport(); + one.results = new ACReport.Result[1]; + one.results[0] = new ACReport.Result(); + ACReport two = (ACReport) one.clone(); + assertNotSame(one, two); + + two.label="ASDF"; + assertNotEquals(one.label, two.label); + + two.summary.URL="Hi"; + assertNotEquals(one.summary.URL, two.summary.URL); + + two.summary.counts.elements = 5; + assertNotEquals(one.summary.counts.elements, two.summary.counts.elements); + + assertNotSame(one.results[0], two.results[0]); + + two.results[0].category = "Test"; + assertNotEquals(one.results[0].category, two.results[0].category); + + two.results[0].bounds.top = 5; + assertNotEquals(one.results[0].bounds.top, two.results[0].bounds.top); + } +} diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java index 9cb22c9ee..3929d6e57 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java @@ -1,6 +1,18 @@ -/* - * This source file was generated by the Gradle 'init' task - */ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ package com.ibm.able.util; import org.junit.Test; From 603b3a0af9a2d030c3b6bfb6dc606b76c146b64b Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 9 Aug 2024 01:24:26 -0500 Subject: [PATCH 08/73] Scan summaries --- .../com/ibm/able/AccessibilityChecker.java | 8 +++++--- .../com/ibm/able/engine/ACReportSummary.java | 9 +++++---- .../com/ibm/able/report/ACReporterJSON.java | 5 +++-- .../com/ibm/able/report/CompressedReport.java | 2 +- .../java/com/ibm/able/report/IReporter.java | 2 +- .../com/ibm/able/report/ReporterManager.java | 20 ++++++++++++++++++- .../ibm/able/AccessibilityCheckerTest.java | 1 + 7 files changed, 35 insertions(+), 12 deletions(-) diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java index 271791e54..6343f976b 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java @@ -101,6 +101,8 @@ private static void initialize() { ConfigInternal config = getConfigUnsupported(); ReporterManager.initialize(config, myFS, localEngine.getGuidelines()); BaselineManager.initialize(config, myFS, refactorMap); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> AccessibilityChecker.close() )); } /** @@ -136,9 +138,9 @@ public static eAssertResult assertCompliance(ACReport report) { // return ReporterManager.stringifyResults(report) // } -// export function close() { -// return ACBrowserManager.close(); -// } + public static void close() { + ReporterManager.get().generateSummaries(); + } /** * This function is responsible for getting the diff results based on label for a scan that was already performed. diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java index 5bc97b4f3..18ac21235 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java @@ -53,7 +53,7 @@ public static class PageSummary { public String[] labels = {}; public String[] failLevels = {}; public String scanID = ""; - public PageSummary[] pageScanSummery = new PageSummary[0]; + public PageSummary[] pageScanSummary = new PageSummary[0]; public ACReportSummary() {} public ACReportSummary(ConfigInternal config, long endReport, CompressedReport[] compressedReports) { @@ -65,11 +65,12 @@ public ACReportSummary(ConfigInternal config, long endReport, CompressedReport[] this.labels = config.label; this.failLevels = config.failLevels; this.scanID = config.scanID; - this.pageScanSummery = new PageSummary[compressedReports.length]; + this.pageScanSummary = new PageSummary[compressedReports.length]; for (int idx=0; idx 0) { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java index 371533e96..0c36b19a1 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java @@ -120,7 +120,7 @@ public ReporterStored uncompress() { ); } engineReport.updateSummaryCounts(); - return new ReporterStored(data[2].toString(), data[4].toString(), null); + return new ReporterStored(data[2].toString(), data[4].toString(), engineReport); } public long getStartScan() { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java index 2b948c421..24f28f17d 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java @@ -9,5 +9,5 @@ public interface IReporter { * @return [ reportPath: string, report: string ] */ ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored reportData); - ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, int endReport, CompressedReport[] summaryData); + ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, CompressedReport[] summaryData); }; \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java index 0eee9db70..c827fb3ce 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -53,7 +54,6 @@ public static ReporterManager initialize(ConfigInternal config, IAbstractAPI abs private List reports = new ArrayList<>(); private IReporter returnReporter = new ACReporterJSON(); - private ReporterManager(ConfigInternal config, IAbstractAPI absAPI, Guideline[] rulesets) { this.config = config; this.absAPI = absAPI; @@ -216,4 +216,22 @@ private String getHelpUrl(ACReport.Result issue) { // }; // return `${helpUrl}#${encodeURIComponent(JSON.stringify(minIssue))}` } + + public void generateSummaries() { + long endReport = new Date().getTime(); + // If no scans, don't generate summaries + if (reports.isEmpty()) return; + for (IReporter reporter: reporters) { + CompressedReport[] cReports = reports.toArray(new CompressedReport[reports.size()]); + ReporterFile summaryInfo = reporter.generateSummary(config, rulesets, endReport, cReports); + if (summaryInfo != null) { + try { + absAPI.writeFile(summaryInfo.path, summaryInfo.contents); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + reports.clear(); + } } diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 167756c06..d062fda8c 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -48,6 +48,7 @@ public class AccessibilityCheckerTest { */ @AfterClass public static void teardown() { AccessibilityCheckerTest.driver.close(); + AccessibilityChecker.close(); } @Test public void getCompliance() { From 3cf03d4ca0cfcbf142ec1e7d9392b0c51364cff8 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 9 Aug 2024 08:53:04 -0500 Subject: [PATCH 09/73] Add jar build --- java-accessibility-checker/README-DEV.md | 21 +++++++++++++++++++++ java-accessibility-checker/lib/build.gradle | 16 ++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 java-accessibility-checker/README-DEV.md diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md new file mode 100644 index 000000000..0432971e3 --- /dev/null +++ b/java-accessibility-checker/README-DEV.md @@ -0,0 +1,21 @@ +## Example gradle commands + +Run a specific testcase: +``` +./gradlew test --tests com.ibm.able.AccessibilityCheckerTest +``` + +Run all tests: +``` +./gradlew test +``` + +Create jar (result in lib/build/libs): +``` +./gradlew jar +``` + +Generate javadoc +``` +./gradlew javadoc +``` diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 8078eaf36..96d44cfdf 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -10,6 +10,10 @@ plugins { id 'java-library' } +group 'com.ibm.able' +version '1.0.0-beta-1' +archivesBaseName = 'accessibility-checker' + repositories { // Use Maven Central for resolving dependencies. mavenCentral() @@ -43,4 +47,16 @@ test { testLogging { showStandardStreams = true } +} + +jar { + // manifest { + // attributes "Main-Class": "com.baeldung.fatjar.Application" + // } + + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } + + duplicatesStrategy = DuplicatesStrategy.INCLUDE } \ No newline at end of file From 6ef30e8f00d561bed5fca3ef1c3a90ce4a4bcd18 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 15:27:40 -0500 Subject: [PATCH 10/73] Java test suite --- java-accessibility-checker/lib/build.gradle | 2 +- .../com/ibm/able/config/ACConfigManager.java | 5 +- .../enginecontext/EngineContextLocal.java | 2 +- .../enginecontext/EngineContextSelenium.java | 24 +-- .../com/ibm/able/report/ReporterManager.java | 2 +- .../main/java/com/ibm/able/util/Fetch.java | 63 +++++++- .../ibm/able/AccessibilityCheckerTest.java | 141 ++++++++++++++++++ 7 files changed, 220 insertions(+), 19 deletions(-) diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 96d44cfdf..109a47227 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -30,7 +30,7 @@ dependencies { implementation libs.guava // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java - implementation 'org.seleniumhq.selenium:selenium-java:4.16.1' + implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' implementation 'com.google.code.gson:gson:2.11.0' // https://mavenlibs.com/maven/dependency/org.mozilla/rhino implementation 'org.mozilla:rhino:1.7.14' diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java index e4be11154..713870b1d 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java @@ -126,10 +126,7 @@ private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IO Archive[] ruleArchiveParse; try { - // if (ACConfig.ignoreHTTPSErrors) { - // process.env.NODE_TLS_REJECT_UNAUTHORIZED="0" - // } - ruleArchiveParse = Fetch.getJSONArr(ruleArchiveFile, Archive[].class); + ruleArchiveParse = Fetch.getJSONArr(ruleArchiveFile, Archive[].class, ACConfig.ignoreHTTPSErrors); } catch (Error err) { System.err.println(ruleArchiveFile); System.err.println(err.toString()); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java index f3aed0446..bb07b434c 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java @@ -34,7 +34,7 @@ public class EngineContextLocal implements IEngineContext { @Override public void loadEngine() throws IOException { ConfigInternal config = ACConfigManager.getConfigUnsupported(); - String engineContent = Fetch.get(config.rulePack+"/ace.js")+";var ace_checker = new ace.Checker();"; + String engineContent = Fetch.get(config.rulePack+"/ace.js", config.ignoreHTTPSErrors)+";var ace_checker = new ace.Checker();"; // Creates and enters a Context. The Context stores information // about the execution environment of a script. diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java index 6a0cf0f8f..2962ff982 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java @@ -17,11 +17,11 @@ import java.io.IOException; import java.time.Duration; -import java.util.Date; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; +import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import com.google.gson.Gson; @@ -51,7 +51,7 @@ public void loadEngine() throws IOException { engineLoadMode = "INJECT"; } if ("INJECT".equals(engineLoadMode) && engineContent == null) { - engineContent = Fetch.get(config.rulePack+"/ace.js"); + engineContent = Fetch.get(config.rulePack+"/ace.js", config.ignoreHTTPSErrors); } if (config.DEBUG) System.out.println("[INFO] aChecker.loadEngine detected Selenium"); @@ -151,15 +151,21 @@ public ACEReport getCompliance(String label) { cb(e); } """, gson.toJson(config.policies) /* TODO: ${JSON.stringify(ACEngineManager.customRulesets)}; */); - this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); - - String jsonReport = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); ACEReport report; - if (!jsonReport.startsWith("{\"results\":[")) { - throw new ACError(jsonReport); - } else { - report = gson.fromJson(jsonReport, ACEReport.class); + try { + this.driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(60)); + this.driver.manage().timeouts().setScriptTimeout(Duration.ofMinutes(60)); + String jsonReport = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); + if (!jsonReport.startsWith("{\"results\":[")) { + throw new ACError(jsonReport); + } else { + report = gson.fromJson(jsonReport, ACEReport.class); + } + } catch (TimeoutException err) { + System.err.println("TIMEOUT?!"); + throw err; } + // TODO: // String getPolicies = "return new window.ace_ibma.Checker().rulesetIds;"; // if (curPol != null && !checkPolicy) { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java index c827fb3ce..fed0a304a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java @@ -40,7 +40,7 @@ public class ReporterManager { private static Gson gson = new Gson(); private static ReporterManager singleton = null; public static ReporterManager get() { - if (singleton == null) throw new ACError("RepoterManager not intialized"); + if (singleton == null) throw new ACError("ReporterManager not intialized"); return singleton; } public static ReporterManager initialize(ConfigInternal config, IAbstractAPI absAPI, Guideline[] rulesets) { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java index 74ca68891..45b7ed982 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java @@ -22,12 +22,57 @@ import java.net.URL; import com.google.gson.Gson; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.X509TrustManager; + public class Fetch { private Fetch() {} private static Gson gson = new Gson(); - + public static String get(String urlStr) throws IOException { + return get(urlStr, false); + } + + public static String get(String urlStr, boolean ignoreSSL) throws IOException { + SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory(); + HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier(); + + if (ignoreSSL) { + try { + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, new TrustManager[] { new X509TrustManager() { + + public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[0]; + } + }}, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + } catch (Error err) { + System.err.println("Ignoring SSL Err! "+err); + } catch (Exception err2) { + System.err.println("Ignoring SSL Err! "+err2); + } + } URL url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); @@ -37,14 +82,26 @@ public static String get(String urlStr) throws IOException { while ((output = br.readLine()) != null) { sb.append(output); } + if (ignoreSSL) { + HttpsURLConnection.setDefaultSSLSocketFactory(factory); + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + } return sb.toString(); } public static T[] getJSONArr(String urlStr, Class clazz) throws IOException { - return gson.fromJson(Fetch.get(urlStr), clazz); + return getJSONArr(urlStr, clazz, false); + } + + public static T[] getJSONArr(String urlStr, Class clazz, boolean ignoreHTTPSErrors) throws IOException { + return gson.fromJson(Fetch.get(urlStr, ignoreHTTPSErrors), clazz); } public static T getJSONObj(String urlStr, Class clazz) throws IOException { - return gson.fromJson(Fetch.get(urlStr), clazz); + return getJSONObj(urlStr, clazz, false); + } + + public static T getJSONObj(String urlStr, Class clazz, boolean ignoreHTTPSErrors) throws IOException { + return gson.fromJson(Fetch.get(urlStr, ignoreHTTPSErrors), clazz); } } diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index d062fda8c..8a2983f30 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -19,18 +19,52 @@ import static org.junit.Assert.*; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Arrays; +import java.util.Map; +import java.util.List; +import java.util.HashSet; +import java.util.Set; import org.junit.AfterClass; import org.junit.BeforeClass; import org.openqa.selenium.chrome.ChromeDriver; import com.google.common.io.Files; +import com.google.gson.Gson; +import com.ibm.able.config.ACConfigManager; import com.ibm.able.engine.ACReport; +import com.ibm.able.engine.ACReport.Result; import com.ibm.able.report.BaselineManager.eAssertResult; public class AccessibilityCheckerTest { + public static class UnitTestInfoResult { + public String ruleId; + public String reasonId; + public String category; + public String message; + public String[] messageArgs; + public String[] value; + public Map path; + + public boolean matches(Result result) { + return ruleId.equals(result.ruleId) + && reasonId.equals(result.reasonId) + && category.equals(result.category) + && message.equals(result.message) + && value[1].equals(result.value[1]) + && path.get("dom").equals(result.path.get("dom")) + && path.get("aria").equals(result.path.get("aria")); + } + } + public static class UnitTestInfo { + public String[] ruleIds; + public UnitTestInfoResult[] results; + } private static ChromeDriver driver; /** @@ -70,4 +104,111 @@ public class AccessibilityCheckerTest { assertEquals(eAssertResult.PASS, AccessibilityChecker.assertCompliance(report)); Paths.get("baselines", "getComplianceTest3.json").toFile().delete(); } + + // @Test public void getComplianceLong() { + // AccessibilityCheckerTest.driver.get("https://openliberty.io/docs/latest/reference/javadoc/liberty-jakartaee8-javadoc.html?path=liberty-javaee8-javadoc/index-all.html"); + // ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceLong"); + // assertNotNull(report); + // assertTrue(report.results.length > 0); + // } + + private void listFiles(File f, java.util.List retFiles) { + if (f.isFile() && f.exists() && (f.getName().endsWith("html") || f.getName().endsWith("htm"))) { + retFiles.add(f); + } else if (f.isDirectory()) { + for (File subF: f.listFiles((testFile, name) -> testFile.isDirectory() || name.endsWith(".htm") || name.endsWith(".html"))) { + listFiles(subF, retFiles); + } + } + + } + @Test public void getComplianceTestsuite() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "customRuleServer": true, + "rulePack": "https://localhost:9445/rules/archives/preview/js", + "ruleArchive": "preview", + "ignoreHTTPSErrors": true, + "policies": [ "IBM_Accessibility", "IBM_Accessibility_next"], + "failLevels": [ "violation", "potentialviolation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual", + "pass" + ], + "outputFormat": [ "json" ], + "label": [ + "IBMa-Node-TeSt" + ] +} +"""); + myWriter.close(); + ACConfigManager.getConfig(); + + Gson gson = new Gson(); + File testRootDir = Paths.get(System.getProperty("user.dir"), "..","..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); + ArrayList testFiles = new ArrayList<>(); + listFiles(testRootDir, testFiles); + + + // Skip test cases that don't work in this environment (e.g., can't disable meta refresh in chrome) + Set skipList = new HashSet<>(Arrays.asList(new File[] { + //not in karma conf file + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-hasTextEmbedded.html").toFile(), + // path.join(testRootDir, "a_text_purpose_ruleunit", "A-nonTabable.html"), + + // Meta refresh + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-invalidRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-validRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_redirect_optional_ruleunit", "Meta-RefreshZero.html").toFile(), + + // CSS test issues + Paths.get(testRootDir.getAbsolutePath(), "style_color_misuse_ruleunit","D543.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_before_after_review_ruleunit","D100.html").toFile(), + + // Misc + // path.join(testRootDir, "aria_banner_label_unique_ruleunit", "validLandMarks-testCaseFromAnn.html"), + })); + + for (File testFile: testFiles) { + if (skipList.contains(testFile)) continue; + AccessibilityCheckerTest.driver.get("file://"+testFile.getAbsolutePath()); + ACReport report = AccessibilityChecker.getCompliance(driver, testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); + String unitTestInfoStr = AccessibilityCheckerTest.driver.executeScript("return JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); + if (!"false".equals(unitTestInfoStr)) { + System.out.print("."); + UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); + List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); + if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { + List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); + List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); + for (int idxActual=0; idxActual Date: Mon, 12 Aug 2024 15:50:58 -0500 Subject: [PATCH 11/73] Add java test to PRs --- .github/workflows/test.yml | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e7af5a6a4..508d822a7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -360,6 +360,45 @@ jobs: - run: npm run wdio working-directory: accessibility-checker/test/webdriverio +############################################################################### +# Java test +#### + java-accessibility-checker-test: + runs-on: ubuntu-22.04 + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v4 + with: + distribution: 'semeru' # See 'Supported distributions' for available options + java-version: '17' + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + cache-dependency-path: '**/package-lock.json' + - name: Latest Chrome + uses: browser-actions/setup-chrome@v1 + with: + chrome-version: latest + id: setup-chrome + - run: npm install + working-directory: rule-server + - run: npm run build + working-directory: rule-server + - run: node main.js & + working-directory: rule-server/dist + - run: sleep 10 + working-directory: rule-server/dist + + - run: ./gradlew test + working-directory: java-accessibility-checker + ############################################################################### # Karma Tests #### From 105622d5306aeaf0c339dcd47eff867572086405 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 15:51:11 -0500 Subject: [PATCH 12/73] Make headless --- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 8a2983f30..c552f1aa6 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -33,6 +33,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; import com.google.common.io.Files; import com.google.gson.Gson; @@ -74,7 +75,9 @@ public static class UnitTestInfo { String workingDir = System.getProperty("user.dir"); String chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; System.setProperty("webdriver.chrome.driver", chromeDriverDir); - AccessibilityCheckerTest.driver = new ChromeDriver(); + ChromeOptions options = new ChromeOptions(); + options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); + AccessibilityCheckerTest.driver = new ChromeDriver(options); } /** From f7f0e3ec76ece34a70cc0747f2b984672766b98e Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 16:01:24 -0500 Subject: [PATCH 13/73] Git chromedriver --- .github/workflows/test.yml | 1 + .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 508d822a7..3e7172942 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -386,6 +386,7 @@ jobs: uses: browser-actions/setup-chrome@v1 with: chrome-version: latest + install-chromedriver: true id: setup-chrome - run: npm install working-directory: rule-server diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index c552f1aa6..fdeca62ab 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -73,7 +73,10 @@ public static class UnitTestInfo { */ @BeforeClass public static void setup() { String workingDir = System.getProperty("user.dir"); - String chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + String chromeDriverDir = System.getenv("chromedriver-path"); + if (chromeDriverDir == null) { + chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + } System.setProperty("webdriver.chrome.driver", chromeDriverDir); ChromeOptions options = new ChromeOptions(); options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); From 1fc3cd566f9008c512173325a5643fbaebd2d290 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 16:30:12 -0500 Subject: [PATCH 14/73] debug --- .../lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index fdeca62ab..760874a7d 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -77,6 +77,7 @@ public static class UnitTestInfo { if (chromeDriverDir == null) { chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; } + System.out.println("Chrome driver: "+chromeDriverDir); System.setProperty("webdriver.chrome.driver", chromeDriverDir); ChromeOptions options = new ChromeOptions(); options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); From 72538c9d735751a37b4210c9742a3b797f7846f7 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 16:39:56 -0500 Subject: [PATCH 15/73] Add env --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e7172942..942a428ca 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -399,6 +399,8 @@ jobs: - run: ./gradlew test working-directory: java-accessibility-checker + env: + chromedriver-path: ${{ steps.setup-chrome.outputs.chromedriver-path }} ############################################################################### # Karma Tests From b796bc734a707db1fa92c5e42068cabf0cdd2b66 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 17:06:19 -0500 Subject: [PATCH 16/73] Chrome driver dir --- .github/workflows/test.yml | 2 +- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 942a428ca..eac8f320e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -400,7 +400,7 @@ jobs: - run: ./gradlew test working-directory: java-accessibility-checker env: - chromedriver-path: ${{ steps.setup-chrome.outputs.chromedriver-path }} + chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} ############################################################################### # Karma Tests diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 760874a7d..505641ff4 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -73,7 +73,7 @@ public static class UnitTestInfo { */ @BeforeClass public static void setup() { String workingDir = System.getProperty("user.dir"); - String chromeDriverDir = System.getenv("chromedriver-path"); + String chromeDriverDir = System.getenv("chromedriverpath"); if (chromeDriverDir == null) { chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; } From cf70577f7fe3bcb2ae90df29a1eeb59d3e55767b Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 17:25:48 -0500 Subject: [PATCH 17/73] headless new --- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 505641ff4..0b58953e0 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -80,7 +80,9 @@ public static class UnitTestInfo { System.out.println("Chrome driver: "+chromeDriverDir); System.setProperty("webdriver.chrome.driver", chromeDriverDir); ChromeOptions options = new ChromeOptions(); - options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); + options.addArguments("--headless=new"); + // options.setImplicitWaitTimeout + // options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); AccessibilityCheckerTest.driver = new ChromeDriver(options); } From c744a8fe2c8ea142e39da288fbe7a6ca2619cadd Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 17:39:39 -0500 Subject: [PATCH 18/73] debug --- .github/workflows/test.yml | 4 ++++ .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eac8f320e..097de5692 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -397,6 +397,10 @@ jobs: - run: sleep 10 working-directory: rule-server/dist + - run: | + echo "${{ steps.setup-chrome.outputs.chrome-version }}" + - run: | + echo "${{ steps.setup-chrome.outputs.chromedriver-version }}" - run: ./gradlew test working-directory: java-accessibility-checker env: diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 0b58953e0..16fa57f18 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -77,7 +77,6 @@ public static class UnitTestInfo { if (chromeDriverDir == null) { chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; } - System.out.println("Chrome driver: "+chromeDriverDir); System.setProperty("webdriver.chrome.driver", chromeDriverDir); ChromeOptions options = new ChromeOptions(); options.addArguments("--headless=new"); From 71c19bf153bdd53ecd3460a502882749fc7e55fe Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 17:43:48 -0500 Subject: [PATCH 19/73] debug --- .github/workflows/test.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 097de5692..00c49f1cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -397,10 +397,8 @@ jobs: - run: sleep 10 working-directory: rule-server/dist - - run: | - echo "${{ steps.setup-chrome.outputs.chrome-version }}" - - run: | - echo "${{ steps.setup-chrome.outputs.chromedriver-version }}" + - run: echo "${{ steps.setup-chrome.outputs.chrome-version }}" + - run: echo "${{ steps.setup-chrome.outputs.chromedriver-version }}" - run: ./gradlew test working-directory: java-accessibility-checker env: From 3dd70777cad49b33902a458439690aad24ea43c8 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 19:44:24 -0500 Subject: [PATCH 20/73] Debug --- .../test/java/com/ibm/able/AccessibilityCheckerTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 16fa57f18..ecf176d05 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -32,6 +32,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; +import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; @@ -82,7 +83,13 @@ public static class UnitTestInfo { options.addArguments("--headless=new"); // options.setImplicitWaitTimeout // options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); - AccessibilityCheckerTest.driver = new ChromeDriver(options); + try { + AccessibilityCheckerTest.driver = new ChromeDriver(options); + } catch (SessionNotCreatedException e) { + System.out.println(e.getMessage()); + System.out.println(e.getAdditionalInformation()); + throw e; + } } /** From a18ad318d8670301193c477f9e4b5f350243b864 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 20:03:30 -0500 Subject: [PATCH 21/73] Set bin path --- .github/workflows/test.yml | 2 +- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 00c49f1cd..ed4659b0f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -403,7 +403,7 @@ jobs: working-directory: java-accessibility-checker env: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} - + chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} ############################################################################### # Karma Tests #### diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index ecf176d05..7db801037 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -75,11 +75,13 @@ public static class UnitTestInfo { @BeforeClass public static void setup() { String workingDir = System.getProperty("user.dir"); String chromeDriverDir = System.getenv("chromedriverpath"); + ChromeOptions options = new ChromeOptions(); if (chromeDriverDir == null) { chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + } else { + options.setBinary(System.getenv("chromebinpath")); } System.setProperty("webdriver.chrome.driver", chromeDriverDir); - ChromeOptions options = new ChromeOptions(); options.addArguments("--headless=new"); // options.setImplicitWaitTimeout // options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1200","--ignore-certificate-errors"); From ab3921541579aaefd0a3517f3b2ff67347cd7fb1 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 20:29:39 -0500 Subject: [PATCH 22/73] Fix test --- .github/workflows/test.yml | 3 --- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ed4659b0f..60e945a14 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -396,9 +396,6 @@ jobs: working-directory: rule-server/dist - run: sleep 10 working-directory: rule-server/dist - - - run: echo "${{ steps.setup-chrome.outputs.chrome-version }}" - - run: echo "${{ steps.setup-chrome.outputs.chromedriver-version }}" - run: ./gradlew test working-directory: java-accessibility-checker env: diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 7db801037..e30e18718 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -225,6 +225,7 @@ private void listFiles(File f, java.util.List retFiles) { System.out.println(); } finally { configFile.delete(); + ACConfigManager.resetConfig(); } } From e70ef31702e1165465ab7f1528d4fa7dde61be04 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Mon, 12 Aug 2024 20:45:05 -0500 Subject: [PATCH 23/73] Output progress --- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index e30e18718..e5f6294a2 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -201,10 +201,11 @@ private void listFiles(File f, java.util.List retFiles) { ACReport report = AccessibilityChecker.getCompliance(driver, testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); String unitTestInfoStr = AccessibilityCheckerTest.driver.executeScript("return JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); if (!"false".equals(unitTestInfoStr)) { - System.out.print("."); UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { + System.out.println(testFile.getAbsolutePath()); + System.out.flush(); List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); for (int idxActual=0; idxActual Date: Mon, 12 Aug 2024 20:54:15 -0500 Subject: [PATCH 24/73] change path --- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index e5f6294a2..18fbf8196 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -204,7 +204,7 @@ private void listFiles(File f, java.util.List retFiles) { UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { - System.out.println(testFile.getAbsolutePath()); + System.out.println(testFile.getCanonicalPath()); System.out.flush(); List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); From b03f45f8fc1ce66a43bc2f0ef8365d574e13706b Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 10:12:11 -0500 Subject: [PATCH 25/73] Metrics and copyright --- .../src/main/java/com/ibm/able/Library.java | 10 -- .../src/main/java/com/ibm/able/abs/MyFS.java | 15 ++ .../enginecontext/EngineContextLocal.java | 15 ++ .../enginecontext/EngineContextManager.java | 4 + .../com/ibm/able/report/ACReporterJSON.java | 15 ++ .../ibm/able/report/ACReporterMetrics.java | 144 ++++++++++++++++++ .../java/com/ibm/able/report/IReporter.java | 15 ++ .../com/ibm/able/report/ReporterFile.java | 15 ++ .../com/ibm/able/report/ReporterManager.java | 3 +- .../com/ibm/able/report/ReporterStored.java | 15 ++ .../ibm/able/AccessibilityCheckerTest.java | 2 +- 11 files changed, 240 insertions(+), 13 deletions(-) delete mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/Library.java create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/Library.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/Library.java deleted file mode 100644 index e1d609b90..000000000 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/Library.java +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This source file was generated by the Gradle 'init' task - */ -package com.ibm.able; - -public class Library { - public boolean someLibraryMethod() { - return true; - } -} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java index c0cc2c0cb..0bea28638 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java @@ -1,3 +1,18 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ package com.ibm.able.abs; import com.ibm.able.engine.ACReport; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java index bb07b434c..443c06d24 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java @@ -81,4 +81,19 @@ public Rule[] getRules() { return gson.fromJson(jsonGuidelines, Rule[].class); } + public String encodeURIComponent(String s) { + if (engine == null) { + // Creates and enters a Context. The Context stores information + // about the execution environment of a script. + engine = Context.enter(); + + // Initialize the standard objects (Object, Function, etc.) + // This must be done before scripts can be executed. Returns + // a scope object that we use in later calls. + engineScope = engine.initStandardObjects(); + } + String scriptStr = String.format("encodeURIComponent(`%s`)", s); + String result = engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + return result; + } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java index 3a2188a1a..e824eaedd 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java @@ -23,6 +23,10 @@ public class EngineContextManager { private EngineContextManager() {} + + public static String encodeURIComponent(String s) { + return new EngineContextLocal().encodeURIComponent(s); + } public static IEngineContext getEngineContext(Object contentContext) { IEngineContext engineContext = null; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java index 484705f63..9da2aa017 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java @@ -1,3 +1,18 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ package com.ibm.able.report; import java.util.Date; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java new file mode 100644 index 000000000..a930cc539 --- /dev/null +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java @@ -0,0 +1,144 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.report; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import com.ibm.able.config.ConfigInternal; +import com.ibm.able.engine.Guideline; +import com.ibm.able.enginecontext.EngineContextManager; +import com.ibm.able.util.Fetch; + +/******************************************************************************* + * NAME: ACMetricsLogger.js + * DESCRIPTION: Common Metrics logger object which can be shared between tools + * to upload metrics of the tool to the metrics server. + *******************************************************************************/ + +public class ACReporterMetrics implements IReporter { + private String policies; + private String metricsURLV2 = "https://able.ibm.com/tools"; + private String toolName; + private Map> scanTimesV2 = new HashMap<>(); + + public ACReporterMetrics(String toolName, String[] policies) { + this.policies = String.join(",", policies); + // Init all the local object variables + this.toolName = toolName; + } + + @Override + public String name() { + return "metrics"; + } + + /** + * This function is responsible for profiling the testcases and adding the scan time to the global + * array which will be sent to the metrics server to log the number of scans that were performed. + * This function profiles scanTimes for the V2 metric server: + * https://aat.w3ibm.mybluemix.net + * + * In the case that user provides any url that is https://aat* it will upload based on accountId + * + * @param {String} scanTime - Provide the time it took for the testcase to run + * @param {String} profile - The type of profile the scan time is for: + * i.e. browser information, features, etc... + * + * @return N/A - Global scanTimesV2 object is updated with the time + * + * @memberOf this + */ + @Override + public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored storedReport) { + if (config.label == null || Arrays.asList(config.label).contains("IBMa-Java-TeSt")) { + // URI encode the profile text provided + String profile = EngineContextManager.encodeURIComponent(storedReport.scanProfile); + if (!scanTimesV2.containsKey(profile)) { + scanTimesV2.put(profile, new ArrayList()); + } + // Add the time it took for the testcase to run to the global array, indexed by the profile + scanTimesV2.get(profile).add(""+storedReport.engineReport.summary.scanTime); + } + return null; + }; + + /** + * This function is responsible for uploading scan results to the metrics server: + * https://aat.w3ibm.mybluemix.net + * + * @param {Function} done - The browser on which the testcases were run on + * + * @return N/A - performs the upload of the metrics to the server + * + * @memberOf this + */ + @Override + public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, + CompressedReport[] compressedReports) + { + try { + // Variable Declaration + String accountId = ""; + + // Loop over all the profiles with in the scanTime Object + for (Entry> entry: scanTimesV2.entrySet()) { + // Loop over all the V2 Scan Times until it reaches 0 + if (!entry.getValue().isEmpty()) { + String preQS = "?t=" + this.toolName + "&tag=" + entry.getKey() + "&a=" + accountId + "&pol=" + this.policies + "&st="; + StringBuilder qsBuilder = new StringBuilder(); + ArrayList times = entry.getValue(); + for (int idx=0; idx < times.size(); ++idx) { + qsBuilder.append(times.get(idx)); + qsBuilder.append(","); + + if ((idx % 150) == 0) { + String qs = preQS + qsBuilder.substring(0, qsBuilder.length()-1); + + // Dispatch the call to the metrics server + try { + System.out.println(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); + Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); + } catch (Throwable t) { + System.err.println(t); + } + } + qsBuilder = new StringBuilder(); + } + if (qsBuilder.length() > 0) { + String qs = preQS + qsBuilder.substring(0, qsBuilder.length()-1); + + // Dispatch the call to the metrics server + try { + System.out.println(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); + Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); + } catch (Throwable t) { + System.err.println(t); + } + } + } + } + } catch (Throwable t) { + System.err.println(t); + t.printStackTrace(); + } + return null; + }; +}; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java index 24f28f17d..cda60734c 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java @@ -1,3 +1,18 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ package com.ibm.able.report; import com.ibm.able.config.ConfigInternal; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java index aeeec3c03..bc5895324 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java @@ -1,3 +1,18 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ package com.ibm.able.report; public class ReporterFile { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java index fed0a304a..e53c08f1b 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java @@ -59,8 +59,7 @@ private ReporterManager(ConfigInternal config, IAbstractAPI absAPI, Guideline[] this.absAPI = absAPI; this.rulesets = rulesets; if (config.perfMetrics) { - // TODO: - // reporters.add(new ACReporterMetrics(config.toolName, config.policies)); + reporters.add(new ACReporterMetrics(config.toolName, config.policies)); } if (!Arrays.asList(config.outputFormat).contains("disable")) { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java index cf41153a8..c093c05df 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java @@ -1,3 +1,18 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ package com.ibm.able.report; import com.ibm.able.engine.ACReport; diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 18fbf8196..24941604e 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -163,7 +163,7 @@ private void listFiles(File f, java.util.List retFiles) { ], "outputFormat": [ "json" ], "label": [ - "IBMa-Node-TeSt" + "IBMa-Java-TeSt2" ] } """); From f332d653004f1557925c0216ff7d6fcea2699dfd Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 11:22:41 -0500 Subject: [PATCH 26/73] Don't record our own tests --- .../src/main/java/com/ibm/able/report/ACReporterMetrics.java | 2 +- .../src/test/java/com/ibm/able/AccessibilityCheckerTest.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java index a930cc539..b7aba6acf 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java @@ -68,7 +68,7 @@ public String name() { */ @Override public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored storedReport) { - if (config.label == null || Arrays.asList(config.label).contains("IBMa-Java-TeSt")) { + if (config.label == null || !Arrays.asList(config.label).contains("IBMa-Java-TeSt")) { // URI encode the profile text provided String profile = EngineContextManager.encodeURIComponent(storedReport.scanProfile); if (!scanTimesV2.containsKey(profile)) { diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java index 24941604e..5a730da9e 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java @@ -103,6 +103,7 @@ public static class UnitTestInfo { } @Test public void getCompliance() { + ACConfigManager.getConfig().label = new String[] { "IBMa-Java-TeSt" }; AccessibilityCheckerTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); assertNotNull(report); @@ -163,7 +164,7 @@ private void listFiles(File f, java.util.List retFiles) { ], "outputFormat": [ "json" ], "label": [ - "IBMa-Java-TeSt2" + "IBMa-Java-TeSt" ] } """); From 7d14a3ae66e6210563d5de850981f25a81919f8b Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 12:08:14 -0500 Subject: [PATCH 27/73] Javadoc updates --- .../com/ibm/able/AccessibilityChecker.java | 62 +++++++++---------- .../com/ibm/able/config/ACConfigManager.java | 23 ++----- .../ibm/able/report/ACReporterMetrics.java | 26 -------- .../com/ibm/able/report/BaselineManager.java | 37 +++-------- 4 files changed, 44 insertions(+), 104 deletions(-) diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java index 6343f976b..b26d990b1 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java @@ -40,23 +40,13 @@ public class AccessibilityChecker { private static IAbstractAPI myFS = new MyFS(); private static IEngineContext localEngine; - /** - * This function is responsible performing a scan based on the context that is provided, following are - * the supported context type: - * Single node (HTMLElement) - * Local file path (String) - * URL (String) - * document node - * data stream for html content (String) - * - * Future Items - * Multiple node (Array of HTMLElements) ---> FUTURE - * - * @param {(Webdriver|Puppeteer Page |)} content - Provide the context to scan, which includes the items from above. - * @param {String} label - Provide a label for the scan that is being performed - * @param {Function} callback - (optional) Provide callback function which will be executed once the results are extracted. - * @return Promise with the ICheckerResult - */ + /** + * This function is responsible performing a scan based on the context that is provided, following are + * the supported context type: WebDriver + * @param content The WebDriver with the content to scan + * @param label Provide a label for the scan that is being performed + * @return Resulting report + */ public static ACReport getCompliance(Object content, String label) { if (content == null) { System.err.println("aChecker: Unable to get compliance of null or undefined object"); @@ -111,14 +101,27 @@ private static void initialize() { * be used to perform the check, in the case no baseline is provided then we comply with only failing if * there is a sinble violation which falls into failLevels. * - * @param {ReportResult} actual - the actual results object provided by the user, this object should follow the + * @param actual the actual results object provided by the user, this object should follow the * same format as outlined in the return of aChecker.buildReport function. * - * @return {int} - return 0 in the case actual matches baseline or no violations fall into failsLevels, + * @return return 0 in the case actual matches baseline or no violations fall into failsLevels, * return 1 in the case actual results does not match baseline results, * return 2 in the case that there is a failure based on failLevels (this means no baseline found). * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. */ + + /** + * This function is responsible for comparing the scan results with baseline or checking that there are + * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will + * be used to perform the check, in the case no baseline is provided then we comply with only failing if + * there is a sinble violation which falls into failLevels. + * @param report the actual results object provided by the user, this object should follow the + * same format as outlined in the return of aChecker.buildReport function. + * @return return 0 in the case actual matches baseline or no violations fall into failsLevels, + * return 1 in the case actual results does not match baseline results, + * return 2 in the case that there is a failure based on failLevels (this means no baseline found). + * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. + */ public static eAssertResult assertCompliance(ACReport report) { return BaselineManager.assertCompliance(report); } @@ -129,10 +132,6 @@ public static eAssertResult assertCompliance(ACReport report) { // * @param {Object} results - Provide the results from the scan. // * // * @return {String} resultsString - String representation of the results/violations. -// * -// * PUBLIC API -// * -// * @memberOf this // */ // export function stringifyResults(report: ICheckerReport) : string { // return ReporterManager.stringifyResults(report) @@ -145,9 +144,9 @@ public static void close() { /** * This function is responsible for getting the diff results based on label for a scan that was already performed. * - * @param {String} label - Provide a lable for which to get the diff results for. + * @param label Provide a label for which to get the diff results for. * - * @return {Object} - return the diff results object from global space based on label provided, the object will be + * @return return the diff results object from global space based on label provided, the object will be * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. */ public static DiffResult[] getDiffResults(String label) { @@ -157,9 +156,9 @@ public static DiffResult[] getDiffResults(String label) { /** * This function is responsible for getting the baseline object for a label that was provided. * - * @param {String} label - Provide a lable for which to get the baseline for. + * @param label Provide a label for which to get the baseline for. * - * @return {Object} - return the baseline object from global space based on label provided, the object will be + * @return return the baseline object from global space based on label provided, the object will be * in the same format as outlined in the return of aChecker.buildReport function. */ public static ACReport getBaseline(String label) { @@ -169,13 +168,10 @@ public static ACReport getBaseline(String label) { /** * This function is responsible for comparing actual with expected and returning all the differences as an array. * - * @param {Object} actual - Provide the actual object to be used for compare - * @param {Object} expected - Provide the expected object to be used for compare - * @param {boolean} clean - Provide a boolean if both the actual and expected objects need to be cleaned - * cleaning refers to converting the objects to match with a basic compliance - * compare of xpath and ruleId. + * @param actual Provide the actual object to be used for compare + * @param expected Provide the expected object to be used for compare * - * @return {Object} differences - return an array of diff objects that were found, following is the format of the object: + * @return differences - return an array of diff objects that were found, following is the format of the object: * [ * { * "kind": "E", diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java index 713870b1d..7d116ad00 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java @@ -111,11 +111,9 @@ private static String findLatestArchiveId(Archive[] archives, String toolVersion * Need to change array of policies into a string * ["CI162_5_2_DCP070116","CI162_5_2_DCP070116"] to "CI162_5_2_DCP070116,CI162_5_2_DCP070116" * - * @param {Object} ACConfig - Provide the config object in which needs to be processed. + * @param ACConfig Provide the config object in which needs to be processed. * - * @return {Object} ACConfig - return the config object which has been made engine readable - * - * @memberOf this + * @return ConfigInternal - return the config object which has been made engine readable */ private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IOException { String[] validArchiveKeywords = { "latest", "preview", "versioned" }; @@ -197,12 +195,7 @@ private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IO * This function is responsible initializing all the default values for the configurations, in the case any * of the config options are missing. * - * @param {Object} config - Provide the config object in which we need to initialize the default values. - * - * @return {Object} config - return the config object which has all the default values, in the case - * some of the options are null or undefined. - * - * @memberOf this + * @param config Provide the config object in which we need to initialize the default values. */ private static void initializeDefaults(ConfigInternal config) { // Use an unpopulated config as the default values @@ -247,8 +240,6 @@ private static void initializeDefaults(ConfigInternal config) { * * @return {Object} config - return the config object that was read in, refer to function initializeDefaults * to view how the object is to be constructed. - * - * @memberOf this */ private static ConfigInternal loadConfigFromJSONFile() { // Use an unpopulated config as the default values @@ -300,15 +291,13 @@ private static ConfigInternal loadConfigFromJSONFile() { * function and then the config variables will be assoiciated to the global space so that * they can be accessed from window.__karma__.config * - * @param {Object} config - All the Karma configuration, we will extract what we need from this over + * @param config All the Karma configuration, we will extract what we need from this over * all object, we need the entire object so that we can reasign some config * variables to global scope so that all karma testscases/scripts can access * them. * - * @return - N/A - Object will be processed and all the params that are needed for this module will - * be extracted and then the entire object will be added to global space. - * - * @memberOf this + * @return Object will be processed and all the params that are needed for this module will + * be extracted */ private static ConfigInternal processConfiguration(Config config) { // Use an unpopulated config as the default values diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java index b7aba6acf..00f2a32f1 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java @@ -50,22 +50,6 @@ public String name() { return "metrics"; } - /** - * This function is responsible for profiling the testcases and adding the scan time to the global - * array which will be sent to the metrics server to log the number of scans that were performed. - * This function profiles scanTimes for the V2 metric server: - * https://aat.w3ibm.mybluemix.net - * - * In the case that user provides any url that is https://aat* it will upload based on accountId - * - * @param {String} scanTime - Provide the time it took for the testcase to run - * @param {String} profile - The type of profile the scan time is for: - * i.e. browser information, features, etc... - * - * @return N/A - Global scanTimesV2 object is updated with the time - * - * @memberOf this - */ @Override public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored storedReport) { if (config.label == null || !Arrays.asList(config.label).contains("IBMa-Java-TeSt")) { @@ -80,16 +64,6 @@ public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, return null; }; - /** - * This function is responsible for uploading scan results to the metrics server: - * https://aat.w3ibm.mybluemix.net - * - * @param {Function} done - The browser on which the testcases were run on - * - * @return N/A - performs the upload of the metrics to the server - * - * @memberOf this - */ @Override public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, CompressedReport[] compressedReports) diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java index 1415b92d0..179547ee8 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java @@ -112,17 +112,13 @@ public static ACReport getBaseline(String label) { * be used to perform the check, in the case no baseline is provided then we comply with only failing if * there is a sinble violation which falls into failLevels. * - * @param {Object} actual - the actual results object provided by the user, this object should follow the + * @param actualResults the actual results object provided by the user, this object should follow the * same format as outlined in the return of aChecker.buildReport function. * - * @return {int} - return 0 in the case actual matches baseline or no violations fall into failsLevels, + * @return return 0 in the case actual matches baseline or no violations fall into failsLevels, * return 1 in the case actual results does not match baseline results, * return 2 in the case that there is a failure based on failLevels (this means no baseline found). * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. - * - * PUBLIC API - * - * @memberOf this */ public static eAssertResult assertCompliance(ACReport actualResults) { // Get the label directly from the results object, the same label has to match @@ -181,13 +177,10 @@ public static eAssertResult assertCompliance(ACReport actualResults) { /** * This function is responsible for comparing actual with expected and returning all the differences as an array. * - * @param {Object} actual - Provide the actual object to be used for compare - * @param {Object} expected - Provide the expected object to be used for compare - * @param {boolean} clean - Provide a boolean if both the actual and expected objects need to be cleaned - * cleaning refers to converting the objects to match with a basic compliance - * compare of xpath and ruleId. + * @param actual Provide the actual object to be used for compare + * @param expected Provide the expected object to be used for compare * - * @return {Object} differences - return an array of diff objects that were found, following is the format of the object: + * @return differences - return an array of diff objects that were found, following is the format of the object: * [ * { * "kind": "E", @@ -210,10 +203,6 @@ public static eAssertResult assertCompliance(ACReport actualResults) { * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html", * } * ] - * - * PUBLIC API - * - * @memberOf this */ public static DiffResult[] diffResultsWithExpected(ACReport actual, ACReport expected) { // Run Deep diff function to compare the actual and expected values. @@ -236,15 +225,11 @@ public static DiffResult[] diffResultsWithExpected(ACReport actual, ACReport exp * This function is responsible for checking if any of the issues reported have any level that falls * into the failsLevel array. * - * @param {Object} results - Provide the scan results, object which would be in the + * @param report Provide the scan results, object which would be in the * the same format as outlined in the return of aChecker.buildReport function. * - * @return {int} - return 1 in the case a single issue was found which is in the failsLevel array. + * @return return 1 in the case a single issue was found which is in the failsLevel array. * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. - * - * PRIVATE METHOD - * - * @memberOf this */ public static int compareBasedOnFailLevels(ACReport report) { // Variable Declaration @@ -269,14 +254,10 @@ public static int compareBasedOnFailLevels(ACReport report) { /** * This function is responsible for getting the diff results based on label for a scan that was already performed. * - * @param {String} label - Provide a lable for which to get the diff results for. + * @param label Provide a label for which to get the diff results for. * - * @return {Object} - return the diff results object from global space based on label provided, the object will be + * @return return the diff results object from global space based on label provided, the object will be * in the same format as outlined in the return of aChecker.diffResultsWithExpected function. - * - * PUBLIC API - * - * @memberOf this */ public static DiffResult[] getDiffResults(String label) { return diffResults.get(label); From 0af9784c8e8c4969460caba099678a417a9f696a Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 12:42:11 -0500 Subject: [PATCH 28/73] Basic javadoc cleanup --- .../com/ibm/able/AccessibilityChecker.java | 106 ++++++++---------- .../java/com/ibm/able/engine/ACEReport.java | 12 +- .../java/com/ibm/able/engine/ACReport.java | 15 +++ 3 files changed, 73 insertions(+), 60 deletions(-) diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java index b26d990b1..5a3bdae7b 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java @@ -36,14 +36,27 @@ import com.ibm.able.abs.MyFS; public class AccessibilityChecker { + private AccessibilityChecker() {} + private static boolean initialized = false; private static IAbstractAPI myFS = new MyFS(); private static IEngineContext localEngine; + /** + * Get the processed configuration object + * @return + */ + public static Config getConfig() { + return ACConfigManager.getConfig(); + } + + public static ConfigInternal getConfigUnsupported() { + return ACConfigManager.getConfigUnsupported(); + } + /** - * This function is responsible performing a scan based on the context that is provided, following are - * the supported context type: WebDriver - * @param content The WebDriver with the content to scan + * Perform a scan of the provided context. Currently supported contexts: WebDriver. + * @param content The content to scan. * @param label Provide a label for the scan that is being performed * @return Resulting report */ @@ -67,65 +80,24 @@ public static ACReport getCompliance(Object content, String label) { return finalReport; } - public static Config getConfig() { - return ACConfigManager.getConfig(); - } - - public static ConfigInternal getConfigUnsupported() { - return ACConfigManager.getConfigUnsupported(); - } - - private static void initialize() { - if (initialized) return; - initialized = true; - localEngine = EngineContextManager.getEngineContext(null); - Map refactorMap = new HashMap<>(); - Rule[] rules = localEngine.getRules(); - for (Rule rule: rules) { - if (rule.refactor != null) { - for (String key: rule.refactor.keySet()) { - refactorMap.put(key, rule); - } - } - } - ConfigInternal config = getConfigUnsupported(); - ReporterManager.initialize(config, myFS, localEngine.getGuidelines()); - BaselineManager.initialize(config, myFS, refactorMap); - - Runtime.getRuntime().addShutdownHook(new Thread(() -> AccessibilityChecker.close() )); - } - /** - * This function is responsible for comparing the scan results with baseline or checking that there are - * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will - * be used to perform the check, in the case no baseline is provided then we comply with only failing if - * there is a sinble violation which falls into failLevels. - * - * @param actual the actual results object provided by the user, this object should follow the - * same format as outlined in the return of aChecker.buildReport function. - * - * @return return 0 in the case actual matches baseline or no violations fall into failsLevels, - * return 1 in the case actual results does not match baseline results, - * return 2 in the case that there is a failure based on failLevels (this means no baseline found). - * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. + * Check the scan results against configured failLevels or against a previously set baseline. + * @param report Report generated by getCompliance + * @return - 0 if report matches baseline, or no issues match failLevels + * - 1 results do not match baseline results + * - 2 failure based on failLevels (this means no baseline found) */ - - /** - * This function is responsible for comparing the scan results with baseline or checking that there are - * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will - * be used to perform the check, in the case no baseline is provided then we comply with only failing if - * there is a sinble violation which falls into failLevels. - * @param report the actual results object provided by the user, this object should follow the - * same format as outlined in the return of aChecker.buildReport function. - * @return return 0 in the case actual matches baseline or no violations fall into failsLevels, - * return 1 in the case actual results does not match baseline results, - * return 2 in the case that there is a failure based on failLevels (this means no baseline found). - * return -1 in the case that there is an exception that occured in the results object which came from the scan engine. - */ public static eAssertResult assertCompliance(ACReport report) { return BaselineManager.assertCompliance(report); } + /** + * Close the checker and ensure all summary reports are generated + */ + public static void close() { + ReporterManager.get().generateSummaries(); + } + // /** // * This function is responsible for printing the scan results to console. // * @@ -137,9 +109,6 @@ public static eAssertResult assertCompliance(ACReport report) { // return ReporterManager.stringifyResults(report) // } - public static void close() { - ReporterManager.get().generateSummaries(); - } /** * This function is responsible for getting the diff results based on label for a scan that was already performed. @@ -221,4 +190,23 @@ public static Rule[] getRules() { return localEngine.getRules(); } + private static void initialize() { + if (initialized) return; + initialized = true; + localEngine = EngineContextManager.getEngineContext(null); + Map refactorMap = new HashMap<>(); + Rule[] rules = localEngine.getRules(); + for (Rule rule: rules) { + if (rule.refactor != null) { + for (String key: rule.refactor.keySet()) { + refactorMap.put(key, rule); + } + } + } + ConfigInternal config = getConfigUnsupported(); + ReporterManager.initialize(config, myFS, localEngine.getGuidelines()); + BaselineManager.initialize(config, myFS, refactorMap); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> AccessibilityChecker.close() )); + } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java index f153558ef..8c071bd2c 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java @@ -35,15 +35,25 @@ public Result(Result o) { value = o.value.clone(); } public Object[] apiArgs = new Object[]{}; + /** Bounds of the result as would be found in the viewport */ public Bounds bounds = new Bounds(); + /** Category of the result (e.g., accessibility) */ public String category; + /** Result message describing what was found */ public String message; + /** Parameter parts used to construct the message */ public String[] messageArgs; + /** Mapping of "dom", "aria", etc to identify the location of the result */ public Map path; - public String reasonId; + /** Identifier of the rule that triggered the result */ public String ruleId; + /** Identifier indicating the specific reason this issue triggered within the rule */ + public String reasonId; + /** How long this rule took to run */ public int ruleTime; + /** HTML snippet that this result triggered on */ public String snippet; + /** Combination of the level of the result (e.g., ["VIOLATION", "FAIL"]) */ public String[] value; @Override diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java index 33e737bc6..c9258e5ab 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java @@ -69,8 +69,11 @@ public Object clone() { } } public static class Result extends ACEReport.Result implements Cloneable { + /** Did this issue match a baseline */ public boolean ignored = false; + /** Help url for this item */ public String help = ""; + /** Level of the issue (violation, potentialviolation, etc) */ public eRuleLevel level; public Result() {} @@ -82,14 +85,23 @@ public Object clone() { return super.clone(); } } + /** List of items detected by the getCompliance scan */ public Result[] results = new Result[0]; + /** Number of rules executed */ public int numExecuted = 0; + /** Mapping of ruleId to reasonId to a parameterized message */ public Map> nls = new HashMap<>(); + /** Summary of the scan */ public Summary summary = new Summary(); + /** Identifier of the scan (same id used for each scan of the session) */ public String scanID = ""; + /** Identifier for the accessibility-checker tool used to perform the scan */ public String toolID = ""; + /** Label as specified in the getCompliance call that generated the report */ public String label = ""; + /** base64 screenshot, if one was taken */ public String screenshot=null; + /** Amount of time in ms that rules were running */ public int ruleTime = 0; public ACReport() {} @@ -107,6 +119,9 @@ public ACReport(ConfigInternal config, ACEReport engineReport, String label) { this.label = label; } + /** + * Update the summary counts to match the included results + */ public void updateSummaryCounts() { SummaryCounts counts = summary.counts; counts.violation = 0; From 9464e4ca7964c99240afa1fcfd6e3c6182c1a746 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 13:30:14 -0500 Subject: [PATCH 29/73] Test build --- .github/workflows/test.yml | 34 ++++++++++++--- java-accessibility-checker/README-DEV.md | 5 +++ java-accessibility-checker/lib/build.gradle | 46 ++++++++++++++++++++- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 60e945a14..b8744d426 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -376,12 +376,6 @@ jobs: with: distribution: 'semeru' # See 'Supported distributions' for available options java-version: '17' - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - cache-dependency-path: '**/package-lock.json' - name: Latest Chrome uses: browser-actions/setup-chrome@v1 with: @@ -401,6 +395,34 @@ jobs: env: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} + +############################################################################### +# Java test +#### + java-accessibility-checker-buildtest: + runs-on: ubuntu-22.04 + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v4 + with: + distribution: 'semeru' # See 'Supported distributions' for available options + java-version: '17' + - run: ./gradlew jar + working-directory: java-accessibility-checker + env: + chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} + chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} + - name: Publish to GitHub Packages + run: gradle publish + env: + USERNAME: ${{ github.actor }} + PASSWORD: ${{ secrets.GITHUB_TOKEN }} + ############################################################################### # Karma Tests #### diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index 0432971e3..2c235c24c 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -19,3 +19,8 @@ Generate javadoc ``` ./gradlew javadoc ``` + +Create maven POM file: +``` +./gradlew generatePomFileForMavenJavaPublication +``` \ No newline at end of file diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 109a47227..aab643d36 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -8,10 +8,12 @@ plugins { // Apply the java-library plugin for API and implementation separation. id 'java-library' + id 'maven-publish' + // id 'signing' } group 'com.ibm.able' -version '1.0.0-beta-1' +version '1.0.0-beta-2' archivesBaseName = 'accessibility-checker' repositories { @@ -59,4 +61,44 @@ jar { } duplicatesStrategy = DuplicatesStrategy.INCLUDE -} \ No newline at end of file +} + +publishing { + repositories { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/IBMa/equal-access") + credentials { + username = project.findProperty("gpr.user") ?: System.getenv("USERNAME") + password = project.findProperty("gpr.key") ?: System.getenv("TOKEN") + } + } + } + publications { + githubJava(MavenPublication) { + from components.java + artifactId = 'accessibility-checker' + + pom { + name = 'accessibility-checker' + description = 'A module that allows you to perform integrated accessibility testing for environments such as JUnit and Selenium' + url = 'https://www.ibm.com/able/toolkit/tools/' + licenses { + license { + name = 'The Apache License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + scm { + connection = 'scm:git:git://github.com/IBMa/equal-access.git' + developerConnection = 'scm:git:ssh://github.com/IBMa/equal-access.git' + url = 'https://github.com/IBMa/equal-access' + } + } + } + } +} + +// signing { +// sign publishing.publications.githubJava +// } \ No newline at end of file From 92e73abab845d8a967f7e0e20523f8159f4ca0f5 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 13:44:51 -0500 Subject: [PATCH 30/73] yaml syntax --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8744d426..6295bf7bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -418,10 +418,10 @@ jobs: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} - name: Publish to GitHub Packages - run: gradle publish - env: - USERNAME: ${{ github.actor }} - PASSWORD: ${{ secrets.GITHUB_TOKEN }} + run: gradle publish + env: + USERNAME: ${{ github.actor }} + PASSWORD: ${{ secrets.GITHUB_TOKEN }} ############################################################################### # Karma Tests From cdaa7e3c82165dc4300659683bb7faaf05f2b9ea Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 13:46:50 -0500 Subject: [PATCH 31/73] working directory --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6295bf7bb..3897052d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -419,6 +419,7 @@ jobs: chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} - name: Publish to GitHub Packages run: gradle publish + working-directory: java-accessibility-checker env: USERNAME: ${{ github.actor }} PASSWORD: ${{ secrets.GITHUB_TOKEN }} From 577b31c5390e4b043a44553834ed397519aa8600 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 14:06:39 -0500 Subject: [PATCH 32/73] Generate pom --- .github/workflows/test.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3897052d1..04b0cf068 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -414,9 +414,8 @@ jobs: java-version: '17' - run: ./gradlew jar working-directory: java-accessibility-checker - env: - chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} - chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} + - run: ./gradlew generatePomFileForMavenJavaPublication + working-directory: java-accessibility-checker - name: Publish to GitHub Packages run: gradle publish working-directory: java-accessibility-checker From f7b122bfd7c1433323b9db530da0c56dcf146b95 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 14:10:23 -0500 Subject: [PATCH 33/73] package write --- .github/workflows/test.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 04b0cf068..187dc3d29 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -401,7 +401,8 @@ jobs: #### java-accessibility-checker-buildtest: runs-on: ubuntu-22.04 - + permissions: + packages: write strategy: matrix: node-version: [18.x] @@ -414,8 +415,6 @@ jobs: java-version: '17' - run: ./gradlew jar working-directory: java-accessibility-checker - - run: ./gradlew generatePomFileForMavenJavaPublication - working-directory: java-accessibility-checker - name: Publish to GitHub Packages run: gradle publish working-directory: java-accessibility-checker From 2f96ca1ed2729643874098d27ef2049aa7004f4a Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 14:19:48 -0500 Subject: [PATCH 34/73] switch token --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 187dc3d29..f06a38d06 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -419,8 +419,8 @@ jobs: run: gradle publish working-directory: java-accessibility-checker env: - USERNAME: ${{ github.actor }} - PASSWORD: ${{ secrets.GITHUB_TOKEN }} + USERNAME: ${{ secrets.MVN_GITHUB_USER }} + PASSWORD: ${{ secrets.MVN_GITHUB_TOKEN }} ############################################################################### # Karma Tests From 33622449b8dd5a04a0663780d2dd5055422efb49 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 14:21:46 -0500 Subject: [PATCH 35/73] Generate pom --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f06a38d06..7f8490ab3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -415,6 +415,8 @@ jobs: java-version: '17' - run: ./gradlew jar working-directory: java-accessibility-checker + - run: ./gradlew generatePomFileForGithubJavaPublication + working-directory: java-accessibility-checker - name: Publish to GitHub Packages run: gradle publish working-directory: java-accessibility-checker From d4e666f8aab597261098b810ed8b6af80ded7076 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 14:25:18 -0500 Subject: [PATCH 36/73] Wrong gradle? --- .github/workflows/test.yml | 2 +- java-accessibility-checker/lib/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f8490ab3..1fe5d3acb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -418,7 +418,7 @@ jobs: - run: ./gradlew generatePomFileForGithubJavaPublication working-directory: java-accessibility-checker - name: Publish to GitHub Packages - run: gradle publish + run: ./gradlew publish working-directory: java-accessibility-checker env: USERNAME: ${{ secrets.MVN_GITHUB_USER }} diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index aab643d36..6b807ac27 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -13,7 +13,7 @@ plugins { } group 'com.ibm.able' -version '1.0.0-beta-2' +version '1.0.0-beta-3' archivesBaseName = 'accessibility-checker' repositories { From b798cccbc226dda3d9416360f4f304afcf2151f9 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 14:31:51 -0500 Subject: [PATCH 37/73] creds --- java-accessibility-checker/lib/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 6b807ac27..2e1d66719 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -69,8 +69,8 @@ publishing { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/IBMa/equal-access") credentials { - username = project.findProperty("gpr.user") ?: System.getenv("USERNAME") - password = project.findProperty("gpr.key") ?: System.getenv("TOKEN") + username = project.findProperty("githubJava.user") ?: System.getenv("USERNAME") + password = project.findProperty("githubJava.key") ?: System.getenv("TOKEN") } } } From eafb554232e9dc63a4fe7a623eed640608075cfa Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 14:48:26 -0500 Subject: [PATCH 38/73] Add boilerplate --- .../junit-selenium/.gitattributes | 12 + .../boilerplates/junit-selenium/.gitignore | 5 + .../junit-selenium/gradle/libs.versions.toml | 12 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43504 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../boilerplates/junit-selenium/gradlew | 252 ++++++++++++++++++ .../boilerplates/junit-selenium/gradlew.bat | 94 +++++++ .../junit-selenium/lib/.gitignore | 1 + .../junit-selenium/lib/build.gradle | 56 ++++ .../lib/src/main/java/com/foo/SomeClass.java | 23 ++ .../src/test/java/com/foo/SomeClassTest.java | 72 +++++ .../junit-selenium/settings.gradle | 14 + .../ibm/able/report/ACReporterMetrics.java | 1 - 13 files changed, 548 insertions(+), 1 deletion(-) create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/.gitattributes create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/.gitignore create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/gradle/libs.versions.toml create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.jar create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.properties create mode 100755 java-accessibility-checker/boilerplates/junit-selenium/gradlew create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/gradlew.bat create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/lib/.gitignore create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClass.java create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java create mode 100644 java-accessibility-checker/boilerplates/junit-selenium/settings.gradle diff --git a/java-accessibility-checker/boilerplates/junit-selenium/.gitattributes b/java-accessibility-checker/boilerplates/junit-selenium/.gitattributes new file mode 100644 index 000000000..f91f64602 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/java-accessibility-checker/boilerplates/junit-selenium/.gitignore b/java-accessibility-checker/boilerplates/junit-selenium/.gitignore new file mode 100644 index 000000000..1b6985c00 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradle/libs.versions.toml b/java-accessibility-checker/boilerplates/junit-selenium/gradle/libs.versions.toml new file mode 100644 index 000000000..ab0036d1b --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradle/libs.versions.toml @@ -0,0 +1,12 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +commons-math3 = "3.6.1" +guava = "33.1.0-jre" +junit = "4.13.2" + +[libraries] +commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } +junit = { module = "junit:junit", version.ref = "junit" } diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.jar b/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2c3521197d7c4586c843d1d3e9090525f1898cde GIT binary patch literal 43504 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 TZiJi*F`$tkWLn) literal 0 HcmV?d00001 diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.properties b/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..09523c0e5 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradlew b/java-accessibility-checker/boilerplates/junit-selenium/gradlew new file mode 100755 index 000000000..f5feea6d6 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java-accessibility-checker/boilerplates/junit-selenium/gradlew.bat b/java-accessibility-checker/boilerplates/junit-selenium/gradlew.bat new file mode 100644 index 000000000..9d21a2183 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/.gitignore b/java-accessibility-checker/boilerplates/junit-selenium/lib/.gitignore new file mode 100644 index 000000000..872aa273a --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/.gitignore @@ -0,0 +1 @@ +results \ No newline at end of file diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle new file mode 100644 index 000000000..b3fde3520 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -0,0 +1,56 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java library project to get you started. + * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.9/userguide/building_java_projects.html in the Gradle documentation. + */ + +plugins { + id 'java-library' +} + +group 'com.foo' +version '1.0.0' + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() + maven { + url = uri("https://maven.pkg.github.com/IBMa/equal-access") + credentials { + username = project.findProperty("gpr.user") ?: System.getenv("USERNAME") + password = project.findProperty("gpr.key") ?: System.getenv("TOKEN") + } + } +} + +dependencies { + // Use JUnit test framework. + testImplementation libs.junit + + // This dependency is exported to consumers, that is to say found on their compile classpath. + api libs.commons.math3 + + // This dependency is used internally, and not exposed to consumers on their own compile classpath. + implementation libs.guava + + // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java + implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' + implementation 'com.google.code.gson:gson:2.11.0' + // https://mavenlibs.com/maven/dependency/org.mozilla/rhino + implementation 'org.mozilla:rhino:1.7.14' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-2' +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +test { + testLogging { + showStandardStreams = true + } +} diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClass.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClass.java new file mode 100644 index 000000000..e6fae59ed --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClass.java @@ -0,0 +1,23 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.foo; + +public class SomeClass { + + public boolean someFunction() { + return true; + } +} diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java new file mode 100644 index 000000000..33101e998 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java @@ -0,0 +1,72 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able; + +import org.junit.Test; +import static org.junit.Assert.*; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.openqa.selenium.SessionNotCreatedException; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; + +import com.ibm.able.engine.ACReport; +import com.ibm.able.engine.ACReport.Result; +import com.ibm.able.report.BaselineManager.eAssertResult; + +public class SomeClassTest { + private static ChromeDriver driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + String workingDir = System.getProperty("user.dir"); + String chromeDriverDir = System.getenv("chromedriverpath"); + ChromeOptions options = new ChromeOptions(); + if (chromeDriverDir == null) { + chromeDriverDir = workingDir+"/src/test/resources/chromedriver-mac-arm64/chromedriver"; + } else { + options.setBinary(System.getenv("chromebinpath")); + } + System.setProperty("webdriver.chrome.driver", chromeDriverDir); + options.addArguments("--headless=new"); + try { + SomeClassTest.driver = new ChromeDriver(options); + } catch (SessionNotCreatedException e) { + System.out.println(e.getMessage()); + System.out.println(e.getAdditionalInformation()); + throw e; + } + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + SomeClassTest.driver.close(); + AccessibilityChecker.close(); + } + + @Test public void getCompliance() { + SomeClassTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + + ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); + eAssertResult resultCode = AccessibilityChecker.assertCompliance(report); + assertEquals(resultCode, eAssertResult.PASS); + } +} diff --git a/java-accessibility-checker/boilerplates/junit-selenium/settings.gradle b/java-accessibility-checker/boilerplates/junit-selenium/settings.gradle new file mode 100644 index 000000000..9e57c289e --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-selenium/settings.gradle @@ -0,0 +1,14 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.9/userguide/multi_project_builds.html in the Gradle documentation. + */ + +plugins { + // Apply the foojay-resolver plugin to allow automatic download of JDKs + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +rootProject.name = 'java-accessibility-checker-boilerplate-selenium' +include('lib') diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java index 00f2a32f1..7aad2dd3a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java @@ -88,7 +88,6 @@ public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, // Dispatch the call to the metrics server try { - System.out.println(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); } catch (Throwable t) { System.err.println(t); From e9fe1d1e43f6c8f0cd1de97fa98d1a936a64fc73 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 15:26:29 -0500 Subject: [PATCH 39/73] Move files into equalaccess sub namespace --- java-accessibility-checker/README-DEV.md | 2 +- .../junit-selenium/lib/build.gradle | 2 +- .../src/test/java/com/foo/SomeClassTest.java | 8 ++--- java-accessibility-checker/lib/build.gradle | 2 +- .../AccessibilityChecker.java | 32 +++++++++---------- .../{ => equalaccess}/abs/IAbstractAPI.java | 4 +-- .../ibm/able/{ => equalaccess}/abs/MyFS.java | 8 ++--- .../config/ACConfigManager.java | 6 ++-- .../{ => equalaccess}/config/Archive.java | 2 +- .../able/{ => equalaccess}/config/Config.java | 2 +- .../config/ConfigInternal.java | 2 +- .../{ => equalaccess}/engine/ACEReport.java | 2 +- .../{ => equalaccess}/engine/ACError.java | 2 +- .../{ => equalaccess}/engine/ACReport.java | 4 +-- .../engine/ACReportSummary.java | 8 ++--- .../able/{ => equalaccess}/engine/Bounds.java | 2 +- .../{ => equalaccess}/engine/Guideline.java | 2 +- .../able/{ => equalaccess}/engine/Rule.java | 2 +- .../engine/eRuleConfidence.java | 2 +- .../{ => equalaccess}/engine/eRuleLevel.java | 2 +- .../enginecontext/EngineContextLocal.java | 14 ++++---- .../enginecontext/EngineContextManager.java | 4 +-- .../enginecontext/EngineContextSelenium.java | 18 +++++------ .../enginecontext/IEngineContext.java | 8 ++--- .../report/ACReporterJSON.java | 12 +++---- .../report/ACReporterMetrics.java | 10 +++--- .../report/BaselineManager.java | 12 +++---- .../report/CompressedReport.java | 4 +-- .../{ => equalaccess}/report/IReporter.java | 6 ++-- .../report/ReporterFile.java | 2 +- .../report/ReporterManager.java | 20 ++++++------ .../report/ReporterStored.java | 4 +-- .../able/{ => equalaccess}/util/Fetch.java | 2 +- .../ibm/able/{ => equalaccess}/util/Misc.java | 2 +- .../AccessibilityCheckerTest.java | 10 +++--- .../config/ACConfigManagerTest.java | 2 +- .../engine/ACReportTest.java | 4 +-- .../{ => equalaccess}/util/FetchTest.java | 4 +-- 38 files changed, 117 insertions(+), 117 deletions(-) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/AccessibilityChecker.java (89%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/abs/IAbstractAPI.java (91%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/abs/MyFS.java (92%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/config/ACConfigManager.java (99%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/config/Archive.java (96%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/config/Config.java (98%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/config/ConfigInternal.java (98%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/ACEReport.java (98%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/ACError.java (95%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/ACReport.java (99%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/ACReportSummary.java (94%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/Bounds.java (96%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/Guideline.java (96%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/Rule.java (95%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/eRuleConfidence.java (96%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/engine/eRuleLevel.java (96%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/enginecontext/EngineContextLocal.java (91%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/enginecontext/EngineContextManager.java (95%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/enginecontext/EngineContextSelenium.java (94%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/enginecontext/IEngineContext.java (84%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/ACReporterJSON.java (88%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/ACReporterMetrics.java (94%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/BaselineManager.java (97%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/CompressedReport.java (98%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/IReporter.java (88%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/ReporterFile.java (96%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/ReporterManager.java (95%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/report/ReporterStored.java (92%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/util/Fetch.java (99%) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/{ => equalaccess}/util/Misc.java (97%) rename java-accessibility-checker/lib/src/test/java/com/ibm/able/{ => equalaccess}/AccessibilityCheckerTest.java (97%) rename java-accessibility-checker/lib/src/test/java/com/ibm/able/{ => equalaccess}/config/ACConfigManagerTest.java (99%) rename java-accessibility-checker/lib/src/test/java/com/ibm/able/{ => equalaccess}/engine/ACReportTest.java (94%) rename java-accessibility-checker/lib/src/test/java/com/ibm/able/{ => equalaccess}/util/FetchTest.java (93%) diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index 2c235c24c..ef76cd2a9 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -2,7 +2,7 @@ Run a specific testcase: ``` -./gradlew test --tests com.ibm.able.AccessibilityCheckerTest +./gradlew test --tests com.ibm.able.equalaccess.AccessibilityCheckerTest ``` Run all tests: diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index b3fde3520..b5dcf0d33 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -39,7 +39,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.11.0' // https://mavenlibs.com/maven/dependency/org.mozilla/rhino implementation 'org.mozilla:rhino:1.7.14' - implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-2' + implementation 'com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-2' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java index 33101e998..af0dadd78 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able; +package com.foo; import org.junit.Test; import static org.junit.Assert.*; @@ -24,9 +24,9 @@ import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; -import com.ibm.able.engine.ACReport; -import com.ibm.able.engine.ACReport.Result; -import com.ibm.able.report.BaselineManager.eAssertResult; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; public class SomeClassTest { private static ChromeDriver driver; diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 2e1d66719..5aff8a1f0 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -12,7 +12,7 @@ plugins { // id 'signing' } -group 'com.ibm.able' +group 'com.ibm.able.equalaccess' version '1.0.0-beta-3' archivesBaseName = 'accessibility-checker' diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java similarity index 89% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java index 5a3bdae7b..aabeee5ef 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/AccessibilityChecker.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java @@ -13,27 +13,27 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able; +package com.ibm.able.equalaccess; import java.util.Date; import java.util.HashMap; import java.util.Map; -import com.ibm.able.config.ACConfigManager; -import com.ibm.able.config.Config; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.ACEReport; -import com.ibm.able.engine.ACReport; -import com.ibm.able.engine.Guideline; -import com.ibm.able.engine.Rule; -import com.ibm.able.enginecontext.EngineContextManager; -import com.ibm.able.enginecontext.IEngineContext; -import com.ibm.able.report.BaselineManager; -import com.ibm.able.report.ReporterManager; -import com.ibm.able.report.BaselineManager.DiffResult; -import com.ibm.able.report.BaselineManager.eAssertResult; -import com.ibm.able.abs.IAbstractAPI; -import com.ibm.able.abs.MyFS; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.Config; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.enginecontext.EngineContextManager; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; +import com.ibm.able.equalaccess.report.BaselineManager; +import com.ibm.able.equalaccess.report.ReporterManager; +import com.ibm.able.equalaccess.report.BaselineManager.DiffResult; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; +import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.abs.MyFS; public class AccessibilityChecker { private AccessibilityChecker() {} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/IAbstractAPI.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java similarity index 91% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/IAbstractAPI.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java index 021daab86..0808d5ea8 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/IAbstractAPI.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java @@ -13,11 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.abs; +package com.ibm.able.equalaccess.abs; import java.io.IOException; -import com.ibm.able.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport; public interface IAbstractAPI { public ACReport loadBaseline(String scanLabel); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java similarity index 92% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java index 0bea28638..a0237e697 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/abs/MyFS.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.abs; +package com.ibm.able.equalaccess.abs; -import com.ibm.able.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport; import java.io.File; import java.io.FileNotFoundException; @@ -27,8 +27,8 @@ import com.google.gson.Gson; import com.google.gson.stream.JsonReader; -import com.ibm.able.config.ACConfigManager; -import com.ibm.able.config.ConfigInternal; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.ConfigInternal; public class MyFS implements IAbstractAPI { public static Gson gson = new Gson(); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java similarity index 99% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java index 7d116ad00..5b4d1aafb 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ACConfigManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java @@ -14,7 +14,7 @@ limitations under the License. *****************************************************************************/ -package com.ibm.able.config; +package com.ibm.able.equalaccess.config; import java.io.FileNotFoundException; import java.io.FileReader; @@ -26,8 +26,8 @@ import com.google.gson.Gson; import com.google.gson.stream.JsonReader; -import com.ibm.able.util.Fetch; -import com.ibm.able.util.Misc; +import com.ibm.able.equalaccess.util.Fetch; +import com.ibm.able.equalaccess.util.Misc; public class ACConfigManager { private static class ConfigError extends Error { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Archive.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Archive.java similarity index 96% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Archive.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Archive.java index 95243730a..9d44348f1 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Archive.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Archive.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.config; +package com.ibm.able.equalaccess.config; import java.util.HashMap; import java.util.Map; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Config.java similarity index 98% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Config.java index 159f9e334..7747d03fb 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/Config.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Config.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.config; +package com.ibm.able.equalaccess.config; public class Config { Config() {} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java similarity index 98% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java index c72421e8e..02adcaadf 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/config/ConfigInternal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.config; +package com.ibm.able.equalaccess.config; import java.nio.file.Paths; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java similarity index 98% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java index 8c071bd2c..77eddea40 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACEReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java @@ -14,7 +14,7 @@ limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; import java.util.Map; public class ACEReport { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACError.java similarity index 95% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACError.java index a6eb1f063..004773357 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACError.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACError.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; public class ACError extends Error { public ACError(String msg) { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java similarity index 99% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java index c9258e5ab..555aa880f 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java @@ -14,7 +14,7 @@ limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -23,7 +23,7 @@ import java.util.Set; import java.util.stream.Stream; -import com.ibm.able.config.ConfigInternal; +import com.ibm.able.equalaccess.config.ConfigInternal; public class ACReport implements Cloneable { public static class SummaryCounts implements Cloneable { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java similarity index 94% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java index 18ac21235..412e8517a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/ACReportSummary.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java @@ -14,7 +14,7 @@ limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -22,9 +22,9 @@ import java.util.Set; import java.util.Map.Entry; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.report.CompressedReport; -import com.ibm.able.report.ReporterStored; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.report.CompressedReport; +import com.ibm.able.equalaccess.report.ReporterStored; public class ACReportSummary { public static class SummaryCounts { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Bounds.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java similarity index 96% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Bounds.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java index 79517a88a..9f41fac6f 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Bounds.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; public class Bounds implements Cloneable { int top = -1; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Guideline.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java similarity index 96% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Guideline.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java index 76f1fa0e4..06e581717 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Guideline.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; public class Guideline { public static class Rule { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Rule.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Rule.java similarity index 95% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Rule.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Rule.java index 3d0c482e6..0620d2f57 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/Rule.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Rule.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; import java.util.Map; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/eRuleConfidence.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java similarity index 96% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/eRuleConfidence.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java index f376b73d2..c19ed4aa4 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/eRuleConfidence.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; public enum eRuleConfidence { PASS("PASS"), diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/eRuleLevel.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java similarity index 96% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/eRuleLevel.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java index 2e5435020..2d022db39 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/engine/eRuleLevel.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; public enum eRuleLevel { violation("violation"), diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java similarity index 91% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java index 443c06d24..5e3582ed6 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextLocal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java @@ -13,16 +13,16 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.enginecontext; +package com.ibm.able.equalaccess.enginecontext; import java.io.IOException; import com.google.gson.Gson; -import com.ibm.able.config.ACConfigManager; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.ACEReport; -import com.ibm.able.engine.Guideline; -import com.ibm.able.engine.Rule; -import com.ibm.able.util.Fetch; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.util.Fetch; import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java similarity index 95% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java index e824eaedd..8f949f314 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java @@ -13,13 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.enginecontext; +package com.ibm.able.equalaccess.enginecontext; import java.io.IOException; import org.openqa.selenium.WebDriver; -import com.ibm.able.util.Misc; +import com.ibm.able.equalaccess.util.Misc; public class EngineContextManager { private EngineContextManager() {} diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextSelenium.java similarity index 94% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextSelenium.java index 2962ff982..608db3a46 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/EngineContextSelenium.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextSelenium.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.enginecontext; +package com.ibm.able.equalaccess.enginecontext; import java.io.IOException; import java.time.Duration; @@ -25,14 +25,14 @@ import org.openqa.selenium.WebDriver; import com.google.gson.Gson; -import com.ibm.able.config.ACConfigManager; -import com.ibm.able.config.Config; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.ACError; -import com.ibm.able.engine.Guideline; -import com.ibm.able.engine.Rule; -import com.ibm.able.engine.ACEReport; -import com.ibm.able.util.Fetch; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.Config; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACError; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.util.Fetch; public class EngineContextSelenium implements IEngineContext { private static Gson gson = new Gson(); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java similarity index 84% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java index 9fb7e67f3..dac3d8e2a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/enginecontext/IEngineContext.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java @@ -13,13 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.enginecontext; +package com.ibm.able.equalaccess.enginecontext; import java.io.IOException; -import com.ibm.able.engine.ACEReport; -import com.ibm.able.engine.Guideline; -import com.ibm.able.engine.Rule; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; public interface IEngineContext { public void loadEngine() throws IOException; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java similarity index 88% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java index 9da2aa017..c4597f6eb 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterJSON.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java @@ -13,17 +13,17 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; import java.util.Date; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.ACReport; -import com.ibm.able.engine.ACReportSummary; -import com.ibm.able.engine.Guideline; -import com.ibm.able.util.Misc; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReportSummary; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.util.Misc; public class ACReporterJSON implements IReporter { private static Gson gson = new GsonBuilder().setPrettyPrinting().create(); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java similarity index 94% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java index 7aad2dd3a..d5a664155 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ACReporterMetrics.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; import java.util.Arrays; import java.util.HashMap; @@ -22,10 +22,10 @@ import java.util.Map; import java.util.Map.Entry; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.Guideline; -import com.ibm.able.enginecontext.EngineContextManager; -import com.ibm.able.util.Fetch; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.enginecontext.EngineContextManager; +import com.ibm.able.equalaccess.util.Fetch; /******************************************************************************* * NAME: ACMetricsLogger.js diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java similarity index 97% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java index 179547ee8..0b2f7673f 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/BaselineManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java @@ -14,7 +14,7 @@ limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; import java.util.ArrayList; import java.util.Arrays; @@ -23,11 +23,11 @@ import java.util.stream.Stream; import com.google.gson.Gson; -import com.ibm.able.abs.IAbstractAPI; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.ACReport; -import com.ibm.able.engine.ACReport.Result; -import com.ibm.able.engine.Rule; +import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.engine.Rule; /** * This interface is responsible for aChecker baselines and comparing scans to baselines diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java similarity index 98% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java index 0c36b19a1..b65fb0136 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/CompressedReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java @@ -13,12 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; import java.util.HashMap; import java.util.Map; -import com.ibm.able.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport; public class CompressedReport { public static String scanID; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java similarity index 88% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java index cda60734c..95c5ed20a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/IReporter.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java @@ -13,10 +13,10 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.Guideline; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.Guideline; public interface IReporter { String name(); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java similarity index 96% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java index bc5895324..755138527 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterFile.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; public class ReporterFile { public String path; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java similarity index 95% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java index e53c08f1b..683008c5a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; import java.io.IOException; import java.util.ArrayList; @@ -26,15 +26,15 @@ import java.util.Set; import com.google.gson.Gson; -import com.ibm.able.abs.IAbstractAPI; -import com.ibm.able.config.ConfigInternal; -import com.ibm.able.engine.ACEReport; -import com.ibm.able.engine.ACError; -import com.ibm.able.engine.ACReport; -import com.ibm.able.engine.Guideline; -import com.ibm.able.engine.eRuleConfidence; -import com.ibm.able.engine.eRuleLevel; -import com.ibm.able.engine.ACReport.Result; +import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.engine.ACError; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.eRuleConfidence; +import com.ibm.able.equalaccess.engine.eRuleLevel; +import com.ibm.able.equalaccess.engine.ACReport.Result; public class ReporterManager { private static Gson gson = new Gson(); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java similarity index 92% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java index c093c05df..e95e29316 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/report/ReporterStored.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.report; +package com.ibm.able.equalaccess.report; -import com.ibm.able.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport; public class ReporterStored { public String pageTitle; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Fetch.java similarity index 99% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Fetch.java index 45b7ed982..c8b8f002a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Fetch.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Fetch.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.util; +package com.ibm.able.equalaccess.util; import java.io.BufferedReader; import java.io.IOException; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Misc.java similarity index 97% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Misc.java index e8b59a7ff..6f479c7c9 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/util/Misc.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Misc.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.util; +package com.ibm.able.equalaccess.util; import java.text.DateFormat; import java.text.SimpleDateFormat; diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java similarity index 97% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java rename to java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java index 5a730da9e..e882adb59 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able; +package com.ibm.able.equalaccess; import org.junit.Test; import static org.junit.Assert.*; @@ -38,10 +38,10 @@ import com.google.common.io.Files; import com.google.gson.Gson; -import com.ibm.able.config.ACConfigManager; -import com.ibm.able.engine.ACReport; -import com.ibm.able.engine.ACReport.Result; -import com.ibm.able.report.BaselineManager.eAssertResult; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; public class AccessibilityCheckerTest { public static class UnitTestInfoResult { diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/config/ACConfigManagerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java similarity index 99% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/config/ACConfigManagerTest.java rename to java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java index c152c2619..c22d8b7e2 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/config/ACConfigManagerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java @@ -14,7 +14,7 @@ limitations under the License. *****************************************************************************/ -package com.ibm.able.config; +package com.ibm.able.equalaccess.config; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/engine/ACReportTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java similarity index 94% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/engine/ACReportTest.java rename to java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java index 371a12422..3d7d8f100 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/engine/ACReportTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java @@ -13,12 +13,12 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.engine; +package com.ibm.able.equalaccess.engine; import org.junit.Test; import static org.junit.Assert.*; -import com.ibm.able.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport; public class ACReportTest { diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java similarity index 93% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java rename to java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java index 3929d6e57..c9882d5bf 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/util/FetchTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java @@ -13,14 +13,14 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.util; +package com.ibm.able.equalaccess.util; import org.junit.Test; import static org.junit.Assert.*; import java.io.IOException; -import com.ibm.able.util.Fetch; +import com.ibm.able.equalaccess.util.Fetch; public class FetchTest { @Test public void getArr() { From d4488175c615ed01bdd182d50e4fd2f8caf46005 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 15:28:14 -0500 Subject: [PATCH 40/73] Change boilerplate dependency version --- .../boilerplates/junit-selenium/lib/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index b5dcf0d33..9fead409a 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -39,7 +39,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.11.0' // https://mavenlibs.com/maven/dependency/org.mozilla/rhino implementation 'org.mozilla:rhino:1.7.14' - implementation 'com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-2' + implementation 'com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-3' } // Apply a specific Java toolchain to ease working on different environments. From ef779d9395da5f44792470114e836b9f32c6ef7b Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 13 Aug 2024 15:34:04 -0500 Subject: [PATCH 41/73] Flip expected, actual --- .../lib/src/test/java/com/foo/SomeClassTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java index af0dadd78..c04b93aca 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java @@ -24,6 +24,7 @@ import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; +import com.ibm.able.equalaccess.AccessibilityChecker; import com.ibm.able.equalaccess.engine.ACReport; import com.ibm.able.equalaccess.engine.ACReport.Result; import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; @@ -67,6 +68,6 @@ public class SomeClassTest { ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); eAssertResult resultCode = AccessibilityChecker.assertCompliance(report); - assertEquals(resultCode, eAssertResult.PASS); + assertEquals(eAssertResult.PASS, resultCode); } } From 8ab315791ff30149930c101c6c24df043e694c57 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Wed, 14 Aug 2024 15:31:13 -0500 Subject: [PATCH 42/73] More isolation of selenium dependency --- .../junit-selenium/lib/build.gradle | 9 +- java-accessibility-checker/lib/build.gradle | 33 +++++- .../equalaccess/AccessibilityChecker.java | 2 +- .../equalaccess/config/ACConfigManager.java | 106 +++++++++--------- .../ibm/able/equalaccess/engine/ACReport.java | 3 +- .../equalaccess/engine/ACReportSummary.java | 6 - .../enginecontext/EngineContextLocal.java | 26 +++-- .../enginecontext/EngineContextManager.java | 32 +++++- .../enginecontext/IEngineContext.java | 7 ++ .../{ => selenium}/EngineContextSelenium.java | 21 +++- .../equalaccess/report/ACReporterMetrics.java | 8 +- .../equalaccess/report/BaselineManager.java | 1 - .../equalaccess/report/ReporterManager.java | 9 +- .../equalaccess/AccessibilityCheckerTest.java | 6 + .../config/ACConfigManagerTest.java | 14 ++- .../ibm/able/equalaccess/util/FetchTest.java | 2 - 16 files changed, 192 insertions(+), 93 deletions(-) rename java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/{ => selenium}/EngineContextSelenium.java (92%) diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index 9fead409a..1a6a4d2fb 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -36,11 +36,12 @@ dependencies { // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - implementation 'com.google.code.gson:gson:2.11.0' - // https://mavenlibs.com/maven/dependency/org.mozilla/rhino - implementation 'org.mozilla:rhino:1.7.14' implementation 'com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-3' -} + implementation('com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-3') { + capabilities { + requireCapability("com.ibm.able.equalaccess:selenium") + } + }} // Apply a specific Java toolchain to ease working on different environments. java { diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 5aff8a1f0..44437ba39 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -16,6 +16,31 @@ group 'com.ibm.able.equalaccess' version '1.0.0-beta-3' archivesBaseName = 'accessibility-checker' +sourceSets { + selenium { + java { + srcDir 'src/main/java' + } + } + main { + java { + srcDir 'src/main/java' + exclude '**/enginecontext/selenium/**' + } + } + test { + java { + srcDir 'src/main/java' + } + } +} + +java { + registerFeature('selenium') { + usingSourceSet(sourceSets.selenium) + } +} + repositories { // Use Maven Central for resolving dependencies. mavenCentral() @@ -31,11 +56,14 @@ dependencies { // This dependency is used internally, and not exposed to consumers on their own compile classpath. implementation libs.guava - // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java - implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' implementation 'com.google.code.gson:gson:2.11.0' // https://mavenlibs.com/maven/dependency/org.mozilla/rhino implementation 'org.mozilla:rhino:1.7.14' + + // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java + seleniumImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' + testImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' + // implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' } // Apply a specific Java toolchain to ease working on different environments. @@ -48,6 +76,7 @@ java { test { testLogging { showStandardStreams = true + showStackTraces = true } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java index aabeee5ef..b7c0f2ea4 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java @@ -76,7 +76,7 @@ public static ACReport getCompliance(Object content, String label) { ACEReport origReport = engineContext.getCompliance(label); String url = engineContext.getUrl(); String title = engineContext.getTitle(); - ACReport finalReport = ReporterManager.get().addEngineReport("Selenium", startScan, url, title, label, origReport); + ACReport finalReport = ReporterManager.get().addEngineReport(engineContext.getProfile(), startScan, url, title, label, origReport); return finalReport; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java index 5b4d1aafb..102e1f5ac 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java @@ -30,6 +30,12 @@ import com.ibm.able.equalaccess.util.Misc; public class ACConfigManager { + public static final String ARCHIVE_LATEST = "latest"; + public static final String ARCHIVE_PREVIEW = "preview"; + public static final String ARCHIVE_VERSIONED = "versioned"; + + private ACConfigManager() {} + private static class ConfigError extends Error { ConfigError(String message) { super(message); @@ -37,18 +43,13 @@ private static class ConfigError extends Error { } - private static String[] covertPolicies(String policies) { - return policies.split(","); - } - - /** * negative if versionA is less than versionB, positive if versionA is greater than versionB, and zero if they are equal. NaN is treated as 0. * @param versionA * @param versionB */ public static int compareVersions(String versionA, String versionB) { - Pattern versionRE = Pattern.compile("[0-9.]+(-rc\\.[0-9]+)?"); + Pattern versionRE = Pattern.compile("[0-9.]+(-rc\\.[\\d]+)?"); versionA = versionA.trim(); versionB = versionB.trim(); if (!versionRE.matcher(versionA).matches()) throw new ConfigError("Invalid version"); @@ -89,7 +90,7 @@ public static int compareVersions(String versionA, String versionB) { * @param toolVersion */ private static String findLatestArchiveId(Archive[] archives, String toolVersion) { - String[] validArchiveKeywords = { "latest", "preview", "versioned" }; + String[] validArchiveKeywords = { ARCHIVE_LATEST, ARCHIVE_PREVIEW, ARCHIVE_VERSIONED }; for (Archive archive : archives) { if (Arrays.asList(validArchiveKeywords).contains(archive.id)) continue; // If the toolVersion is greater than or equal to the archive version we've found it @@ -98,7 +99,7 @@ private static String findLatestArchiveId(Archive[] archives, String toolVersion } } // Something wrong, go with the latest - return "latest"; + return ARCHIVE_LATEST; } /** @@ -111,20 +112,20 @@ private static String findLatestArchiveId(Archive[] archives, String toolVersion * Need to change array of policies into a string * ["CI162_5_2_DCP070116","CI162_5_2_DCP070116"] to "CI162_5_2_DCP070116,CI162_5_2_DCP070116" * - * @param ACConfig Provide the config object in which needs to be processed. + * @param acConfig Provide the config object in which needs to be processed. * * @return ConfigInternal - return the config object which has been made engine readable */ - private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IOException { - String[] validArchiveKeywords = { "latest", "preview", "versioned" }; - String ruleServer = ACConfig.ruleServer; + private static ConfigInternal processACConfig(ConfigInternal acConfig) throws IOException { + String[] validArchiveKeywords = { ARCHIVE_LATEST, ARCHIVE_PREVIEW, ARCHIVE_VERSIONED }; + String ruleServer = acConfig.ruleServer; // Get and parse the rule archive. String ruleArchiveFile = String.format("%s%s/archives.json",ruleServer,ruleServer.contains("jsdelivr.net")?"@next":""); Archive[] ruleArchiveParse; try { - ruleArchiveParse = Fetch.getJSONArr(ruleArchiveFile, Archive[].class, ACConfig.ignoreHTTPSErrors); + ruleArchiveParse = Fetch.getJSONArr(ruleArchiveFile, Archive[].class, acConfig.ignoreHTTPSErrors); } catch (Error err) { System.err.println(ruleArchiveFile); System.err.println(err.toString()); @@ -133,40 +134,39 @@ private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IO } String ruleArchivePath = null; if (ruleArchiveParse.length > 0) { - if (ACConfig.DEBUG) System.out.println("Found archiveFile: " + ruleArchiveFile); - ACConfig.ruleArchiveSet = ruleArchiveParse; - String ruleArchive = ACConfig.ruleArchive; + if (acConfig.DEBUG) System.out.println("Found archiveFile: " + ruleArchiveFile); + acConfig.ruleArchiveSet = ruleArchiveParse; + String ruleArchive = acConfig.ruleArchive; // If the user asked us to sync the rule version with the tool version, we need to figure out what the last rule version was - if ("versioned".equals(ruleArchive)) { - if (ACConfig.toolVersion == null) { - ruleArchive = "latest"; + if (ARCHIVE_VERSIONED.equals(ruleArchive)) { + if (acConfig.toolVersion == null) { + ruleArchive = ARCHIVE_LATEST; } else { - ruleArchive = findLatestArchiveId(ACConfig.ruleArchiveSet, ACConfig.toolVersion); + ruleArchive = findLatestArchiveId(acConfig.ruleArchiveSet, acConfig.toolVersion); } } - ACConfig.ruleArchiveLabel = ACConfig.ruleArchive; - for (int i = 0; i < ACConfig.ruleArchiveSet.length; i++) { - if (ruleArchive.equals(ACConfig.ruleArchiveSet[i].id) && !ACConfig.ruleArchiveSet[i].sunset) { - ruleArchivePath = ACConfig.ruleArchiveSet[i].path; - ACConfig.ruleArchiveVersion = ACConfig.ruleArchiveSet[i].version; - ACConfig.ruleArchiveLabel = ruleArchiveParse[i].name + " (" + ruleArchiveParse[i].id + ")"; + acConfig.ruleArchiveLabel = acConfig.ruleArchive; + for (int i = 0; i < acConfig.ruleArchiveSet.length; i++) { + if (ruleArchive.equals(acConfig.ruleArchiveSet[i].id) && !acConfig.ruleArchiveSet[i].sunset) { + ruleArchivePath = acConfig.ruleArchiveSet[i].path; + acConfig.ruleArchiveVersion = acConfig.ruleArchiveSet[i].version; + acConfig.ruleArchiveLabel = ruleArchiveParse[i].name + " (" + ruleArchiveParse[i].id + ")"; break; } } - if (ruleArchivePath == null || ACConfig.ruleArchiveVersion == null) { + if (ruleArchivePath == null || acConfig.ruleArchiveVersion == null) { String errStr = "[ERROR] RuleArchiveInvalid: Make Sure correct rule archive is provided in the configuration file. More information is available in the README.md"; System.err.println(errStr); throw new ConfigError(errStr); } - for (int i = 0; i < ACConfig.ruleArchiveSet.length; i++) { - if (ACConfig.ruleArchiveVersion.equals(ACConfig.ruleArchiveSet[i].version) - && !Arrays.asList(validArchiveKeywords).contains(ACConfig.ruleArchiveSet[i].id)) + for (int i = 0; i < acConfig.ruleArchiveSet.length; i++) { + if (acConfig.ruleArchiveVersion.equals(acConfig.ruleArchiveSet[i].version) + && !Arrays.asList(validArchiveKeywords).contains(acConfig.ruleArchiveSet[i].id)) { - ACConfig.ruleArchivePath = ACConfig.ruleArchiveSet[i].path; + acConfig.ruleArchivePath = acConfig.ruleArchiveSet[i].path; break; } } - //} } else { String errStr = "[ERROR] UnableToParseArchive: Archives are unable to be parse. Contact support team."; System.err.println(errStr); @@ -174,21 +174,21 @@ private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IO } // Build the new rulePack based of the baseA11yServerURL - if (ACConfig.rulePack == null || "".equals(ACConfig.rulePack)) { + if (acConfig.rulePack == null || "".equals(acConfig.rulePack)) { if (ruleServer.contains("jsdelivr.net")) { - ACConfig.rulePack = String.format("%s@%s", ruleServer, ACConfig.ruleArchiveVersion); + acConfig.rulePack = String.format("%s@%s", ruleServer, acConfig.ruleArchiveVersion); } else { - ACConfig.rulePack = String.format("%s%s/js", ruleServer, ruleArchivePath); + acConfig.rulePack = String.format("%s%s/js", ruleServer, ruleArchivePath); } } - ACConfig.ruleServer = ruleServer; + acConfig.ruleServer = ruleServer; - if (ACConfig.DEBUG) System.err.println("Built new rulePack: " + ACConfig.rulePack); + if (acConfig.DEBUG) System.err.println("Built new rulePack: " + acConfig.rulePack); - if (ACConfig.DEBUG) System.err.println("END 'processACConfig' function"); + if (acConfig.DEBUG) System.err.println("END 'processACConfig' function"); // Return the updated ACConfig object - return ACConfig; + return acConfig; } /** @@ -199,7 +199,7 @@ private static ConfigInternal processACConfig(ConfigInternal ACConfig) throws IO */ private static void initializeDefaults(ConfigInternal config) { // Use an unpopulated config as the default values - ConfigInternal ACConstants = new ConfigInternal(); + ConfigInternal acConstants = new ConfigInternal(); if (config.DEBUG) System.out.println("START 'initializeDefaults' function"); if (config.DEBUG) System.out.println("Config before initialization: "); @@ -208,7 +208,7 @@ private static void initializeDefaults(ConfigInternal config) { config.ruleArchiveLabel = Misc.firstNotNull(config.ruleArchiveLabel, config.ruleArchive); // For capture screenshots need to check for null or undefined and then set default otherwise it will evaluate the // boolean which causes it to always comply with the default value and not user provided option - config.captureScreenshots = Misc.firstNotNull(config.captureScreenshots, ACConstants.captureScreenshots); + config.captureScreenshots = Misc.firstNotNull(config.captureScreenshots, acConstants.captureScreenshots); // Build the toolID based on name and version config.toolID = "java-accessibility-checker-v3.1.70"; @@ -219,13 +219,13 @@ private static void initializeDefaults(ConfigInternal config) { // are done for a single run of karma. config.scanID = java.util.UUID.randomUUID().toString(); - for (Field field : ACConstants.getClass().getDeclaredFields()) { + for (Field field : acConstants.getClass().getDeclaredFields()) { try { if (field.get(config) == null) { - field.set(config, field.get(ACConstants)); + field.set(config, field.get(acConstants)); } - } catch (IllegalArgumentException e) { - } catch (IllegalAccessException e) { + } catch (IllegalArgumentException | IllegalAccessException e) { + // Skip if we can't access the field } } @@ -243,15 +243,15 @@ private static void initializeDefaults(ConfigInternal config) { */ private static ConfigInternal loadConfigFromJSONFile() { // Use an unpopulated config as the default values - ConfigInternal ACConstants = new ConfigInternal(); + ConfigInternal acConstants = new ConfigInternal(); - if (ACConstants.DEBUG) System.out.println("START 'loadConfigFromJSONFile' function"); + if (acConstants.DEBUG) System.out.println("START 'loadConfigFromJSONFile' function"); // Get the current working directory, where we will look for the yaml, yml or json file String workingDir = System.getProperty("user.dir"); - if (ACConstants.DEBUG) System.out.println("Working directory set to: " + workingDir); + if (acConstants.DEBUG) System.out.println("Working directory set to: " + workingDir); - String[] configFiles = ACConstants.configFiles; + String[] configFiles = acConstants.configFiles; ConfigInternal config = null; // Loop over all the possible location where the config file can reside, if one is found load it and break out. @@ -264,7 +264,7 @@ private static ConfigInternal loadConfigFromJSONFile() { // If this is a yml or yaml file verify that the file exists and then load as such. if ("json".equals(fileExtension)) { - if (ACConstants.DEBUG) System.out.println(fileToCheck+": Trying to load as json or js."); + if (acConstants.DEBUG) System.out.println(fileToCheck+": Trying to load as json or js."); // Need to use try/catch mech so that in the case the require throws an exception, we can // catch this and discatd the error, as in the case there is no config file provided then @@ -273,15 +273,15 @@ private static ConfigInternal loadConfigFromJSONFile() { Gson gson = new Gson(); JsonReader reader = new JsonReader(new FileReader(fileToCheck)); config = gson.fromJson(reader, ConfigInternal.class); - if (ACConstants.DEBUG) System.out.println(fileToCheck+": LOADED"); + if (acConstants.DEBUG) System.out.println(fileToCheck+": LOADED"); return config; } catch (FileNotFoundException e) { - if (ACConstants.DEBUG) System.out.println(fileToCheck+": Skipping, JSON file does not exist."); + if (acConstants.DEBUG) System.out.println(fileToCheck+": Skipping, JSON file does not exist."); } } } - if (ACConstants.DEBUG) System.out.println("END 'loadConfigFromJSONFile' function"); + if (acConstants.DEBUG) System.out.println("END 'loadConfigFromJSONFile' function"); return config; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java index 555aa880f..c2161abcd 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java @@ -68,7 +68,7 @@ public Object clone() { return ret; } } - public static class Result extends ACEReport.Result implements Cloneable { + public static class Result extends ACEReport.Result { /** Did this issue match a baseline */ public boolean ignored = false; /** Help url for this item */ @@ -81,6 +81,7 @@ public Result(ACEReport.Result engineResult) { super(engineResult); } + @Override public Object clone() { return super.clone(); } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java index 412e8517a..85d08e118 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java @@ -15,12 +15,6 @@ *****************************************************************************/ package com.ibm.able.equalaccess.engine; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; import com.ibm.able.equalaccess.config.ConfigInternal; import com.ibm.able.equalaccess.report.CompressedReport; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java index 5e3582ed6..b7e2d7109 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java @@ -51,20 +51,20 @@ public void loadEngine() throws IOException { @Override public ACEReport getCompliance(String label) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getCompliance'"); + // Can't getCompliance with no content model + throw new UnsupportedOperationException("Cannot 'getCompliance' with EngineContextLocal"); } @Override public String getUrl() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getUrl'"); + // Can't getUrl with no content model + throw new UnsupportedOperationException("Cannot 'getUrl' with EngineContextLocal"); } @Override public String getTitle() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getTitle'"); + // Can't getTitle with no content model + throw new UnsupportedOperationException("Cannot 'getTitle' with EngineContextLocal"); } @Override @@ -93,7 +93,17 @@ public String encodeURIComponent(String s) { engineScope = engine.initStandardObjects(); } String scriptStr = String.format("encodeURIComponent(`%s`)", s); - String result = engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); - return result; + return engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); + } + + @Override + public String getProfile() { + return "Local"; + } + + @Override + public String getHelp(String ruleId, String reasonId, String helpRoot) { + String scriptStr = String.format("ace_checker.engine.getHelp(`%s`,`%s`,`%s`)", ruleId, reasonId, helpRoot); + return engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java index 8f949f314..795c0b34a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java @@ -16,9 +16,9 @@ package com.ibm.able.equalaccess.enginecontext; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; -import org.openqa.selenium.WebDriver; - +import com.ibm.able.equalaccess.engine.ACError; import com.ibm.able.equalaccess.util.Misc; public class EngineContextManager { @@ -32,8 +32,29 @@ public static IEngineContext getEngineContext(Object contentContext) { IEngineContext engineContext = null; if (contentContext == null) { engineContext = new EngineContextLocal(); - } else if (Misc.classIsAvailable("org.openqa.selenium.WebDriver") && contentContext instanceof org.openqa.selenium.WebDriver) { - engineContext = new EngineContextSelenium((WebDriver) contentContext); + } + if (engineContext == null + && Misc.classIsAvailable("org.openqa.selenium.WebDriver")) + { + if (!Misc.classIsAvailable("com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium")) { + System.err.println("Attempted scan with WebDriver, but com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium could not be loaded"); + throw new ACError("Attempted scan with WebDriver, but com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium could not be loaded"); + } + try { + Class webdriverClass = Class.forName("org.openqa.selenium.WebDriver"); + if (webdriverClass.isAssignableFrom(contentContext.getClass())) { + // We have a webdriver, use EngineContextSelenium to instantiate it + Class ecClass = Class.forName("com.ibm.able.equalaccess.enginecontext.selenium.EngineContextSelenium"); + engineContext = (IEngineContext) ecClass.getConstructor(webdriverClass).newInstance(contentContext); + } + } catch (ClassNotFoundException e) { + } catch (NoSuchMethodException e) { + } catch (SecurityException e) { + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } catch (IllegalArgumentException e) { + } catch (InvocationTargetException e) { + } } if (engineContext != null) { try { @@ -42,6 +63,9 @@ public static IEngineContext getEngineContext(Object contentContext) { System.err.println("aChecker: Unable to load engine due to IOException: "+e.toString()); e.printStackTrace(); } + } else { + System.err.println("Unable to load engine context for "+contentContext.getClass().getName()); + throw new ACError("Unable to load engine context for "+contentContext.getClass().getName()); } return engineContext; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java index dac3d8e2a..3d5b00236 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java @@ -29,4 +29,11 @@ public interface IEngineContext { public String getTitle(); public Guideline[] getGuidelines(); public Rule[] getRules(); + public String getHelp(String ruleId, String reasonId, String helpRoot); + public String encodeURIComponent(String s); + /** + * The profile to use in metrics for this engine context + * @return profile string (e.g., Selenium) + */ + public String getProfile(); } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java similarity index 92% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextSelenium.java rename to java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java index 608db3a46..10ceeb8db 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextSelenium.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. *****************************************************************************/ -package com.ibm.able.equalaccess.enginecontext; +package com.ibm.able.equalaccess.enginecontext.selenium; import java.io.IOException; import java.time.Duration; @@ -31,6 +31,7 @@ import com.ibm.able.equalaccess.engine.ACError; import com.ibm.able.equalaccess.engine.Guideline; import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; import com.ibm.able.equalaccess.engine.ACEReport; import com.ibm.able.equalaccess.util.Fetch; @@ -154,7 +155,6 @@ public ACEReport getCompliance(String label) { ACEReport report; try { this.driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(60)); - this.driver.manage().timeouts().setScriptTimeout(Duration.ofMinutes(60)); String jsonReport = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); if (!jsonReport.startsWith("{\"results\":[")) { throw new ACError(jsonReport); @@ -229,4 +229,21 @@ public Rule[] getRules() { String jsonGuidelines = ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr).toString(); return gson.fromJson(jsonGuidelines, Rule[].class); } + + @Override + public String getProfile() { + return "Selenium"; + } + + @Override + public String getHelp(String ruleId, String reasonId, String helpRoot) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getHelp'"); + } + + @Override + public String encodeURIComponent(String s) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'encodeURIComponent'"); + } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java index d5a664155..8ba8b1446 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java @@ -18,7 +18,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -62,7 +61,7 @@ public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, scanTimesV2.get(profile).add(""+storedReport.engineReport.summary.scanTime); } return null; - }; + } @Override public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, @@ -88,7 +87,7 @@ public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, // Dispatch the call to the metrics server try { - Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); + Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs); } catch (Throwable t) { System.err.println(t); } @@ -100,8 +99,7 @@ public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, // Dispatch the call to the metrics server try { - System.out.println(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); - Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs.toString()); + Fetch.get(this.metricsURLV2 + "/api/pub/meter/v2" + qs); } catch (Throwable t) { System.err.println(t); } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java index 0b2f7673f..0ea851961 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java @@ -20,7 +20,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import java.util.stream.Stream; import com.google.gson.Gson; import com.ibm.able.equalaccess.abs.IAbstractAPI; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java index 683008c5a..fa8962176 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java @@ -27,6 +27,7 @@ import com.google.gson.Gson; import com.ibm.able.equalaccess.abs.IAbstractAPI; +import com.ibm.able.equalaccess.config.ACConfigManager; import com.ibm.able.equalaccess.config.ConfigInternal; import com.ibm.able.equalaccess.engine.ACEReport; import com.ibm.able.equalaccess.engine.ACError; @@ -35,6 +36,8 @@ import com.ibm.able.equalaccess.engine.eRuleConfidence; import com.ibm.able.equalaccess.engine.eRuleLevel; import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.enginecontext.EngineContextManager; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; public class ReporterManager { private static Gson gson = new Gson(); @@ -199,9 +202,11 @@ public static eRuleLevel valueToLevel(String[] reportValue) { return reportLevel; } + private static final IEngineContext engine = EngineContextManager.getEngineContext(null); private String getHelpUrl(ACReport.Result issue) { if (issue.help != null && issue.help.length() > 0) return issue.help; - return ""; + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String helpUrl = engine.getHelp(issue.ruleId, issue.reasonId, config.ruleArchivePath == null ? config.ruleArchive : config.ruleArchivePath.substring(config.ruleArchivePath.lastIndexOf("/")+1)); // TODO: // let config = ReporterManager.config; // let helpUrl = ReporterManager.absAPI.getChecker().engine.getHelp(issue.ruleId, issue.reasonId, !config.ruleArchivePath ? config.ruleArchive : config.ruleArchivePath.substring(config.ruleArchivePath.lastIndexOf("/")+1)); @@ -213,7 +218,7 @@ private String getHelpUrl(ACReport.Result issue) { // ruleId: issue.ruleId, // msgArgs: issue.messageArgs // }; - // return `${helpUrl}#${encodeURIComponent(JSON.stringify(minIssue))}` + return helpUrl+"#";//+encodeURIComponent(JSON.stringify(minIssue))}` } public void generateSummaries() { diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java index e882adb59..fe23e7b62 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java @@ -31,6 +31,7 @@ import java.util.Set; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.openqa.selenium.SessionNotCreatedException; import org.openqa.selenium.chrome.ChromeDriver; @@ -73,6 +74,11 @@ public static class UnitTestInfo { * Setup a Selenium Chrome environment before tests */ @BeforeClass public static void setup() { + // Make sure we're starting with a clean config + File configFile = new File("achecker.json"); + configFile.delete(); + ACConfigManager.resetConfig(); + String workingDir = System.getProperty("user.dir"); String chromeDriverDir = System.getenv("chromedriverpath"); ChromeOptions options = new ChromeOptions(); diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java index c22d8b7e2..f04a6b0d3 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java @@ -26,9 +26,17 @@ import java.nio.file.Paths; import java.util.regex.Pattern; +import org.junit.Before; import org.junit.Test; public class ACConfigManagerTest { + @Before public void setup() throws IOException { + // Make sure we're starting with a clean slate + File configFile = new File("achecker.json"); + configFile.delete(); + ACConfigManager.resetConfig(); + } + @Test public void getConfigWithNoConfigFile() { Config config = ACConfigManager.getConfig(); @@ -76,10 +84,10 @@ public class ACConfigManagerTest { } @Test public void getConfigWithConfigFile() throws IOException { - ACConfigManager.resetConfig(); File configFile = new File("achecker.json"); try { configFile.delete(); + ACConfigManager.resetConfig(); FileWriter myWriter = new FileWriter("achecker.json"); myWriter.write(""" { @@ -149,14 +157,15 @@ public class ACConfigManagerTest { assertEquals("DEFAULT", configInternal.engineMode); } finally { configFile.delete(); + ACConfigManager.resetConfig(); } } @Test public void getConfigWithConfigFileVersioned() throws IOException { - ACConfigManager.resetConfig(); File configFile = new File("achecker.json"); try { configFile.delete(); + ACConfigManager.resetConfig(); FileWriter myWriter = new FileWriter("achecker.json"); myWriter.write(""" { @@ -226,6 +235,7 @@ public class ACConfigManagerTest { assertEquals("DEFAULT", configInternal.engineMode); } finally { configFile.delete(); + ACConfigManager.resetConfig(); } } diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java index c9882d5bf..6ce610e2d 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java @@ -20,8 +20,6 @@ import java.io.IOException; -import com.ibm.able.equalaccess.util.Fetch; - public class FetchTest { @Test public void getArr() { String s = null; From 255c20940f6ad88864222e6a5f45ce8e23a72877 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 15 Aug 2024 12:01:11 -0500 Subject: [PATCH 43/73] CSV report / memory improvements --- .../able/equalaccess/abs/IAbstractAPI.java | 2 + .../com/ibm/able/equalaccess/abs/MyFS.java | 5 +- .../equalaccess/engine/ACReportSummary.java | 14 +-- .../equalaccess/report/ACReporterCSV.java | 90 +++++++++++++++++++ .../equalaccess/report/ACReporterJSON.java | 7 +- .../equalaccess/report/ACReporterMetrics.java | 3 +- .../equalaccess/report/CompressedReport.java | 30 +++++++ .../able/equalaccess/report/IReporter.java | 4 +- .../equalaccess/report/ReporterManager.java | 6 +- 9 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java index 0808d5ea8..df2e47a6b 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java @@ -15,11 +15,13 @@ *****************************************************************************/ package com.ibm.able.equalaccess.abs; +import java.io.File; import java.io.IOException; import com.ibm.able.equalaccess.engine.ACReport; public interface IAbstractAPI { public ACReport loadBaseline(String scanLabel); + public File prepFile(String filePath); public void writeFile(String path, Object contents) throws IOException; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java index a0237e697..956c41a7f 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java @@ -35,13 +35,14 @@ public class MyFS implements IAbstractAPI { @Override public void writeFile(String filePath, Object contents) throws IOException { - File outFile = this.prepFileSync(filePath); + File outFile = this.prepFile(filePath); FileWriter myWriter = new FileWriter(outFile); myWriter.write(contents.toString()); myWriter.close(); } - private File prepFileSync(String filePath) { + @Override + public File prepFile(String filePath) { ConfigInternal config = ACConfigManager.getConfigUnsupported(); Path outFile = Paths.get(System.getProperty("user.dir"), config.outputFolder, filePath); File f = outFile.toFile(); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java index 85d08e118..4fb1b57c9 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java @@ -16,6 +16,8 @@ package com.ibm.able.equalaccess.engine; +import java.util.List; + import com.ibm.able.equalaccess.config.ConfigInternal; import com.ibm.able.equalaccess.report.CompressedReport; import com.ibm.able.equalaccess.report.ReporterStored; @@ -50,8 +52,8 @@ public static class PageSummary { public PageSummary[] pageScanSummary = new PageSummary[0]; public ACReportSummary() {} - public ACReportSummary(ConfigInternal config, long endReport, CompressedReport[] compressedReports) { - this.startReport = compressedReports[0].getStartScan(); + public ACReportSummary(ConfigInternal config, long endReport, List compressedReports) { + this.startReport = compressedReports.get(0).getStartScan(); this.endReport = endReport; this.toolID = config.toolID; this.policies = config.policies; @@ -59,11 +61,11 @@ public ACReportSummary(ConfigInternal config, long endReport, CompressedReport[] this.labels = config.label; this.failLevels = config.failLevels; this.scanID = config.scanID; - this.pageScanSummary = new PageSummary[compressedReports.length]; - for (int idx=0; idx compressedReports) + { + long startScan = !compressedReports.isEmpty() ? compressedReports.get(0).getStartScan() : 0; + Date startScanD = new Date(startScan); + String reportFilename = "results_"+Misc.toISOString(startScanD).replace(":","-")+".csv"; + if (!config.outputFilenameTimestamp) { + reportFilename = "results.csv"; + } + + try { + FileWriter resultStr = new FileWriter(fsApi.prepFile(reportFilename)); + // StringBuilder resultStr = new StringBuilder(); + resultStr.append("Label,Level,RuleId,Message,Xpath,Help\n"); + for (CompressedReport compressedReport: compressedReports) { + for (int idx=0; idx compressedReports) { - if (compressedReports != null && compressedReports.length > 0) { + if (compressedReports != null && compressedReports.size() > 0) { ACReportSummary summReport = new ACReportSummary(config, endReport, compressedReports); if (summReport != null) { - Date startScan = new Date(compressedReports[0].getStartScan()); + Date startScan = new Date(compressedReports.get(0).getStartScan()); String reportFilename = "summary_"+Misc.toISOString(startScan).replaceAll(":","-")+".json"; if (!config.outputFilenameTimestamp) { reportFilename = "summary.json"; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java index 8ba8b1446..c86de32f4 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java @@ -17,6 +17,7 @@ import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.Map.Entry; @@ -65,7 +66,7 @@ public ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, @Override public ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, - CompressedReport[] compressedReports) + List compressedReports) { try { // Variable Declaration diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java index b65fb0136..84e9fbe84 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java @@ -19,6 +19,7 @@ import java.util.Map; import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.eRuleLevel; public class CompressedReport { public static String scanID; @@ -130,4 +131,33 @@ public long getStartScan() { public String getLabel() { return (String)data[3]; } + + public int issuesLength() { + return ((Object[][])data[10]).length; + } + + public eRuleLevel issueLevel(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return ReporterManager.valueToLevel((String[])issue[2]); + } + + public String issueRuleId(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return (String)issue[1]; + } + + public String issueMessage(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return (String)issue[10]; + } + + public String issuePathDom(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return ((Map)issue[5]).get("dom"); + } + + public String issueHelp(int idx) { + Object[] issue = ((Object[][])data[10])[idx]; + return (String)issue[8]; + } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java index 95c5ed20a..9830bdac2 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java @@ -15,6 +15,8 @@ *****************************************************************************/ package com.ibm.able.equalaccess.report; +import java.util.List; + import com.ibm.able.equalaccess.config.ConfigInternal; import com.ibm.able.equalaccess.engine.Guideline; @@ -24,5 +26,5 @@ public interface IReporter { * @return [ reportPath: string, report: string ] */ ReporterFile generateReport(ConfigInternal config, Guideline[] rulesets, ReporterStored reportData); - ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, CompressedReport[] summaryData); + ReporterFile generateSummary(ConfigInternal config, Guideline[] rulesets, long endReport, List summaryData); }; \ No newline at end of file diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java index fa8962176..04c1f3a4a 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java @@ -74,8 +74,7 @@ private ReporterManager(ConfigInternal config, IAbstractAPI absAPI, Guideline[] // reporters.push(new ACReporterHTML()) } if (Arrays.asList(config.outputFormat).contains("csv")) { - // TODO: - // reporters.add(new ACReporterCSV()); + reporters.add(new ACReporterCSV(absAPI)); } if (Arrays.asList(config.outputFormat).contains("xlsx")) { // TODO: @@ -226,8 +225,7 @@ public void generateSummaries() { // If no scans, don't generate summaries if (reports.isEmpty()) return; for (IReporter reporter: reporters) { - CompressedReport[] cReports = reports.toArray(new CompressedReport[reports.size()]); - ReporterFile summaryInfo = reporter.generateSummary(config, rulesets, endReport, cReports); + ReporterFile summaryInfo = reporter.generateSummary(config, rulesets, endReport, reports); if (summaryInfo != null) { try { absAPI.writeFile(summaryInfo.path, summaryInfo.contents); From a3d937a44ffd54c21bf4b3b65d2ca6cb2b321b1e Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 15 Aug 2024 14:03:28 -0500 Subject: [PATCH 44/73] A minimal issue params to the help urls --- .../able/equalaccess/engine/ACEReport.java | 5 ++- .../ibm/able/equalaccess/engine/ACReport.java | 38 ++++++++++++++++++- .../enginecontext/EngineContextLocal.java | 2 +- .../equalaccess/report/ReporterManager.java | 13 +------ 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java index 77eddea40..0ed0f672d 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java @@ -17,6 +17,8 @@ package com.ibm.able.equalaccess.engine; import java.util.Map; +import com.google.gson.annotations.SerializedName; + public class ACEReport { public static class Result implements Cloneable { @@ -42,6 +44,7 @@ public Result(Result o) { /** Result message describing what was found */ public String message; /** Parameter parts used to construct the message */ + @SerializedName(value = "messageArgs", alternate = "msgArgs") public String[] messageArgs; /** Mapping of "dom", "aria", etc to identify the location of the result */ public Map path; @@ -68,7 +71,7 @@ public Object clone() { } ret.bounds = (Bounds) bounds.clone(); return ret; - } + } } public int numExecuted; diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java index c2161abcd..4486f28e2 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java @@ -15,6 +15,7 @@ *****************************************************************************/ package com.ibm.able.equalaccess.engine; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -23,6 +24,13 @@ import java.util.Set; import java.util.stream.Stream; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; import com.ibm.able.equalaccess.config.ConfigInternal; public class ACReport implements Cloneable { @@ -85,6 +93,34 @@ public Result(ACEReport.Result engineResult) { public Object clone() { return super.clone(); } + + public String toHelpData() { + return gsonMinimal.toJson(this); + } + + public static Gson gsonMinimal = new GsonBuilder() + .registerTypeAdapter(Result.class, new JsonSerializer() { + @Override + public JsonElement serialize(Result issue, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jObject = new JsonObject(); + jObject.addProperty("ruleId", issue.ruleId); + jObject.addProperty("reasonId", issue.reasonId); + jObject.addProperty("message", issue.message); + jObject.addProperty("snippet", issue.snippet); + JsonArray buildValue = new JsonArray(); + for (String s: issue.value) { + buildValue.add(s); + } + jObject.add("value", buildValue); + JsonArray buildMsgArgs = new JsonArray(); + for (String s : issue.messageArgs) { + buildMsgArgs.add(s); + } + jObject.add("msgArgs", buildMsgArgs); + return jObject; + } + }) + .create(); } /** List of items detected by the getCompliance scan */ public Result[] results = new Result[0]; @@ -238,5 +274,5 @@ public Object clone() { ret.results[idx] = (ACReport.Result) results[idx].clone(); } return ret; - } + } } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java index b7e2d7109..918b81c5c 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java @@ -92,7 +92,7 @@ public String encodeURIComponent(String s) { // a scope object that we use in later calls. engineScope = engine.initStandardObjects(); } - String scriptStr = String.format("encodeURIComponent(`%s`)", s); + String scriptStr = String.format("encodeURIComponent(`%s`)", s.replace("\"", "\\\"")); return engine.evaluateString(engineScope, scriptStr, "", 1, null).toString(); } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java index 04c1f3a4a..f7000f4a6 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java @@ -206,18 +206,7 @@ private String getHelpUrl(ACReport.Result issue) { if (issue.help != null && issue.help.length() > 0) return issue.help; ConfigInternal config = ACConfigManager.getConfigUnsupported(); String helpUrl = engine.getHelp(issue.ruleId, issue.reasonId, config.ruleArchivePath == null ? config.ruleArchive : config.ruleArchivePath.substring(config.ruleArchivePath.lastIndexOf("/")+1)); - // TODO: - // let config = ReporterManager.config; - // let helpUrl = ReporterManager.absAPI.getChecker().engine.getHelp(issue.ruleId, issue.reasonId, !config.ruleArchivePath ? config.ruleArchive : config.ruleArchivePath.substring(config.ruleArchivePath.lastIndexOf("/")+1)); - // let minIssue = { - // message: issue.message, - // snippet: issue.snippet, - // value: issue.value, - // reasonId: issue.reasonId, - // ruleId: issue.ruleId, - // msgArgs: issue.messageArgs - // }; - return helpUrl+"#";//+encodeURIComponent(JSON.stringify(minIssue))}` + return helpUrl+"#"+engine.encodeURIComponent(issue.toHelpData()); } public void generateSummaries() { From 0eb83ff1b3e6648197194e781d4cedad7dde3d15 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 16 Aug 2024 09:30:18 -0500 Subject: [PATCH 45/73] Tighten dependencies, IOException --- java-accessibility-checker/lib/build.gradle | 21 +++++++----- .../enginecontext/EngineContextLocal.java | 34 +++++++++++-------- .../enginecontext/EngineContextManager.java | 7 +--- .../enginecontext/IEngineContext.java | 4 +-- .../selenium/EngineContextSelenium.java | 16 +++++---- 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 44437ba39..0d9aac871 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -47,22 +47,27 @@ repositories { } dependencies { + implementation 'com.google.code.gson:gson:2.11.0' + // https://mavenlibs.com/maven/dependency/org.mozilla/rhino + implementation 'org.mozilla:rhino:1.7.14' + + // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java + seleniumImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' + seleniumImplementation 'com.google.code.gson:gson:2.11.0' + // https://mavenlibs.com/maven/dependency/org.mozilla/rhino + seleniumImplementation 'org.mozilla:rhino:1.7.14' + // Use JUnit test framework. testImplementation libs.junit + testImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' // This dependency is exported to consumers, that is to say found on their compile classpath. - api libs.commons.math3 + // api libs.commons.math3 // This dependency is used internally, and not exposed to consumers on their own compile classpath. - implementation libs.guava + // implementation libs.guava - implementation 'com.google.code.gson:gson:2.11.0' - // https://mavenlibs.com/maven/dependency/org.mozilla/rhino - implementation 'org.mozilla:rhino:1.7.14' - // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java - seleniumImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - testImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' // implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java index 918b81c5c..7179552e0 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java @@ -32,21 +32,27 @@ public class EngineContextLocal implements IEngineContext { private Scriptable engineScope = null; @Override - public void loadEngine() throws IOException { + public void loadEngine() { ConfigInternal config = ACConfigManager.getConfigUnsupported(); - String engineContent = Fetch.get(config.rulePack+"/ace.js", config.ignoreHTTPSErrors)+";var ace_checker = new ace.Checker();"; - - // Creates and enters a Context. The Context stores information - // about the execution environment of a script. - engine = Context.enter(); - - // Initialize the standard objects (Object, Function, etc.) - // This must be done before scripts can be executed. Returns - // a scope object that we use in later calls. - engineScope = engine.initStandardObjects(); - - // Now evaluate the string we've colected. - engine.evaluateString(engineScope, engineContent, "", 1, null); + String engineUrl = config.rulePack+"/ace.js"; + try { + String engineContent = Fetch.get(engineUrl, config.ignoreHTTPSErrors)+";var ace_checker = new ace.Checker();"; + + // Creates and enters a Context. The Context stores information + // about the execution environment of a script. + engine = Context.enter(); + + // Initialize the standard objects (Object, Function, etc.) + // This must be done before scripts can be executed. Returns + // a scope object that we use in later calls. + engineScope = engine.initStandardObjects(); + + // Now evaluate the string we've colected. + engine.evaluateString(engineScope, engineContent, "", 1, null); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine fromm "+engineUrl+" due to IOException: "+e.toString()); + e.printStackTrace(); + } } @Override diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java index 795c0b34a..6c157a6ee 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java @@ -57,12 +57,7 @@ public static IEngineContext getEngineContext(Object contentContext) { } } if (engineContext != null) { - try { - engineContext.loadEngine(); - } catch (IOException e) { - System.err.println("aChecker: Unable to load engine due to IOException: "+e.toString()); - e.printStackTrace(); - } + engineContext.loadEngine(); } else { System.err.println("Unable to load engine context for "+contentContext.getClass().getName()); throw new ACError("Unable to load engine context for "+contentContext.getClass().getName()); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java index 3d5b00236..91e37586d 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java @@ -15,14 +15,12 @@ *****************************************************************************/ package com.ibm.able.equalaccess.enginecontext; -import java.io.IOException; - import com.ibm.able.equalaccess.engine.ACEReport; import com.ibm.able.equalaccess.engine.Guideline; import com.ibm.able.equalaccess.engine.Rule; public interface IEngineContext { - public void loadEngine() throws IOException; + public void loadEngine(); public ACEReport getCompliance(String label); public String getUrl(); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java index 10ceeb8db..b01c6bc1c 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java @@ -45,18 +45,19 @@ public EngineContextSelenium(WebDriver driver) { } @Override - public void loadEngine() throws IOException { + public void loadEngine() { ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String engineUrl = config.rulePack+"/ace.js"; String engineLoadMode = config.engineMode; if ("DEFAULT".equals(engineLoadMode)) { engineLoadMode = "INJECT"; } - if ("INJECT".equals(engineLoadMode) && engineContent == null) { - engineContent = Fetch.get(config.rulePack+"/ace.js", config.ignoreHTTPSErrors); - } - - if (config.DEBUG) System.out.println("[INFO] aChecker.loadEngine detected Selenium"); try { + if ("INJECT".equals(engineLoadMode) && engineContent == null) { + engineContent = Fetch.get(engineUrl, config.ignoreHTTPSErrors); + } + + if (config.DEBUG) System.out.println("[INFO] aChecker.loadEngine detected Selenium"); String scriptStr; if ("REMOTE".equals(engineLoadMode)) { scriptStr = String.format(""" @@ -125,6 +126,9 @@ public void loadEngine() throws IOException { ((JavascriptExecutor)this.driver).executeAsyncScript(scriptStr); } catch (Error e) { System.err.println(e); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine from "+engineUrl+" due to IOException: "+e.toString()); + e.printStackTrace(); } } From a6624cf8ad5c35123ef4ec07d210bb1353eae9d7 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 16 Aug 2024 11:02:12 -0500 Subject: [PATCH 46/73] Tweak dependencies to not include selenium --- .../junit-selenium/lib/build.gradle | 14 ++---------- .../src/test/java/com/foo/SomeClassTest.java | 2 +- java-accessibility-checker/lib/build.gradle | 22 ++++++------------- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index 1a6a4d2fb..538ac5366 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -28,20 +28,10 @@ dependencies { // Use JUnit test framework. testImplementation libs.junit - // This dependency is exported to consumers, that is to say found on their compile classpath. - api libs.commons.math3 - - // This dependency is used internally, and not exposed to consumers on their own compile classpath. - implementation libs.guava - // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - implementation 'com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-3' - implementation('com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-3') { - capabilities { - requireCapability("com.ibm.able.equalaccess:selenium") - } - }} + implementation 'com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-5:selenium' +} // Apply a specific Java toolchain to ease working on different environments. java { diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java index c04b93aca..e3b86591d 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java @@ -68,6 +68,6 @@ public class SomeClassTest { ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); eAssertResult resultCode = AccessibilityChecker.assertCompliance(report); - assertEquals(eAssertResult.PASS, resultCode); + assertEquals("Scan resulted in "+resultCode.toString(), eAssertResult.PASS, resultCode); } } diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle index 0d9aac871..88702f448 100644 --- a/java-accessibility-checker/lib/build.gradle +++ b/java-accessibility-checker/lib/build.gradle @@ -13,7 +13,7 @@ plugins { } group 'com.ibm.able.equalaccess' -version '1.0.0-beta-3' +version '1.0.0-beta-5' archivesBaseName = 'accessibility-checker' sourceSets { @@ -50,9 +50,10 @@ dependencies { implementation 'com.google.code.gson:gson:2.11.0' // https://mavenlibs.com/maven/dependency/org.mozilla/rhino implementation 'org.mozilla:rhino:1.7.14' + seleniumCompileOnly 'org.seleniumhq.selenium:selenium-java:4.23.0' // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java - seleniumImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' + // seleniumImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' seleniumImplementation 'com.google.code.gson:gson:2.11.0' // https://mavenlibs.com/maven/dependency/org.mozilla/rhino seleniumImplementation 'org.mozilla:rhino:1.7.14' @@ -60,15 +61,6 @@ dependencies { // Use JUnit test framework. testImplementation libs.junit testImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - - // This dependency is exported to consumers, that is to say found on their compile classpath. - // api libs.commons.math3 - - // This dependency is used internally, and not exposed to consumers on their own compile classpath. - // implementation libs.guava - - - // implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' } // Apply a specific Java toolchain to ease working on different environments. @@ -90,11 +82,11 @@ jar { // attributes "Main-Class": "com.baeldung.fatjar.Application" // } - from { - configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } - } + // from { + // configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + // } - duplicatesStrategy = DuplicatesStrategy.INCLUDE + // duplicatesStrategy = DuplicatesStrategy.INCLUDE } publishing { From a01115592efd84f60b25969b70eb0a3e446bd375 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 23 Aug 2024 23:14:49 -0500 Subject: [PATCH 47/73] Handle large result --- .../karmaaction.conf.js | 2 +- .../able/equalaccess/engine/ACEReport.java | 33 +++++++++++ .../ibm/able/equalaccess/engine/ACReport.java | 49 ++++++++++++---- .../selenium/EngineContextSelenium.java | 56 ++++++++++++++++++- .../equalaccess/report/CompressedReport.java | 5 +- .../equalaccess/report/ReporterManager.java | 2 +- .../equalaccess/AccessibilityCheckerTest.java | 6 +- 7 files changed, 136 insertions(+), 17 deletions(-) diff --git a/accessibility-checker-engine/karmaaction.conf.js b/accessibility-checker-engine/karmaaction.conf.js index ff4a434ad..f56a824fe 100644 --- a/accessibility-checker-engine/karmaaction.conf.js +++ b/accessibility-checker-engine/karmaaction.conf.js @@ -63,7 +63,7 @@ module.exports = (config) => { customLaunchers: { ChromeCustom: { base: 'ChromeHeadless', - flags: ['--disable-web-security', '--no-sandbox'] + flags: ['--disable-gpu', '--disable-web-security', '--no-sandbox'] } }, preprocessors: { diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java index 0ed0f672d..3441196e3 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java @@ -20,6 +20,38 @@ import com.google.gson.annotations.SerializedName; public class ACEReport { + public static class SummaryCounts implements Cloneable { + public int violation = 0; + public int potentialviolation = 0; + public int recommendation = 0; + public int potentialrecommendation = 0; + public int manual = 0; + public int pass = 0; + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + } + } + public static class Summary implements Cloneable { + public SummaryCounts counts = new SummaryCounts(); + + public Object clone() { + Summary ret = null; + try { + ret = (Summary) super.clone(); + } catch (CloneNotSupportedException ex) { + System.err.println(ex); + throw new RuntimeException(); + } + ret.counts = (SummaryCounts)counts.clone(); + return ret; + } + } public static class Result implements Cloneable { public Result() {} @@ -80,4 +112,5 @@ public Object clone() { public Map> nls; public Result[] results; public String screenshot=null; + public Summary summary; } diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java index 4486f28e2..b0da859fb 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java @@ -54,6 +54,18 @@ public Object clone() { throw new RuntimeException(); } } + + public SummaryCounts() { + } + + public SummaryCounts(ACEReport.SummaryCounts rhs) { + violation = rhs.violation; + potentialviolation = rhs.potentialviolation; + recommendation = rhs.recommendation; + potentialrecommendation = rhs.potentialrecommendation; + manual = rhs.manual; + pass = rhs.pass; + } } public static class Summary implements Cloneable { public SummaryCounts counts = new SummaryCounts(); @@ -167,6 +179,25 @@ public void updateSummaryCounts() { counts.potentialrecommendation = 0; counts.manual = 0; counts.pass = 0; + for (Result issue: results) { + if (eRuleLevel.violation.equals(issue.level)) { + ++counts.violation; + } else if (eRuleLevel.potentialviolation.equals(issue.level)) { + ++counts.potentialviolation; + } else if (eRuleLevel.recommendation.equals(issue.level)) { + ++counts.recommendation; + } else if (eRuleLevel.potentialrecommendation.equals(issue.level)) { + ++counts.potentialrecommendation; + } else if (eRuleLevel.manual.equals(issue.level)) { + ++counts.manual; + } else if (eRuleLevel.pass.equals(issue.level)) { + ++counts.pass; + } + } + } + + public void addCounts(ACEReport.SummaryCounts summaryCounts) { + SummaryCounts counts = this.summary.counts = new SummaryCounts(summaryCounts); counts.ignored = 0; counts.elements = 0; counts.elementsViolation = 0; @@ -178,22 +209,20 @@ public void updateSummaryCounts() { elementSet.add(issue.path.get("dom")); if (issue.ignored) { ++counts.ignored; - } else { if (eRuleLevel.violation.equals(issue.level)) { - ++counts.violation; + --counts.violation; } else if (eRuleLevel.potentialviolation.equals(issue.level)) { - ++counts.potentialviolation; + --counts.potentialviolation; } else if (eRuleLevel.recommendation.equals(issue.level)) { - ++counts.recommendation; + --counts.recommendation; } else if (eRuleLevel.potentialrecommendation.equals(issue.level)) { - ++counts.potentialrecommendation; + --counts.potentialrecommendation; } else if (eRuleLevel.manual.equals(issue.level)) { - ++counts.manual; + --counts.manual; } else if (eRuleLevel.pass.equals(issue.level)) { - ++counts.pass; - } else if (eRuleLevel.ignored.equals(issue.level)) { - ++counts.ignored; - } + --counts.pass; + } + } else { if (eRuleLevel.violation.equals(issue.level)) { elementViolationSet.add(issue.path.get("dom")); elementViolationReviewSet.add(issue.path.get("dom")); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java index b01c6bc1c..02c9705a8 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java @@ -17,6 +17,9 @@ import java.io.IOException; import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.OutputType; @@ -136,10 +139,54 @@ public void loadEngine() { public ACEReport getCompliance(String label) { Config config = ACConfigManager.getConfig(); try { + List resultList = new ArrayList<>(config.reportLevels.length + config.failLevels.length); + Collections.addAll(resultList, config.reportLevels); + Collections.addAll(resultList, config.failLevels); String scriptStr = String.format(""" let cb = arguments[arguments.length - 1]; try { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + const getCounts = (engineReport) => { + let counts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } let policies = %s; + let reportLevels = %s; let checker = new window.ace_ibma.Checker(); let customRulesets = []; @@ -148,14 +195,19 @@ public ACEReport getCompliance(String label) { checker.check(document, policies).then(function(report) { for (const result of report.results) { delete result.node; + result.level = valueToLevel(result.value) } - cb(JSON.stringify(report)); + report.summary ||= {}; + report.summary.counts ||= getCounts(report); + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + report.results = report.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); cb(JSON.stringify(report)); }) },0) } catch (e) { cb(e); } - """, gson.toJson(config.policies) /* TODO: ${JSON.stringify(ACEngineManager.customRulesets)}; */); + """, gson.toJson(config.policies), gson.toJson(resultList.toArray()) /* TODO: ${JSON.stringify(ACEngineManager.customRulesets)}; */); ACEReport report; try { this.driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(60)); diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java index 84e9fbe84..ad21645fc 100644 --- a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java +++ b/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java @@ -44,7 +44,8 @@ public CompressedReport(ReporterStored info) { summary.ruleArchive, // ruleArchive (7) summary.policies, // policies (8) summary.reportLevels, // reportLevels (9) - new Object[report.results.length][] // (10) + new Object[report.results.length][], // (10) + summary.counts }; for (int idx=0; idx Date: Fri, 23 Aug 2024 23:49:26 -0500 Subject: [PATCH 48/73] Debug --- .../com/ibm/able/equalaccess/AccessibilityCheckerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java index 67ac5554c..8337e2b8e 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java @@ -229,8 +229,8 @@ private void listFiles(File f, java.util.List retFiles) { } } } - assertEquals("Issue triggered was not expected", 0, actualIssues.size()); - assertEquals("Expected issue was not triggered ("+testFile.getAbsolutePath()+")\n---\n"+gson.toJson(report.results)+"\n---\n"+gson.toJson(expectedIssues), 0, expectedIssues.size()); + assertEquals(testFile.toString()+": Issue triggered was not expected", 0, actualIssues.size()); + assertEquals(testFile.toString()+": Expected issue was not triggered ("+testFile.getAbsolutePath()+")\n---\n"+gson.toJson(report.results)+"\n---\n"+gson.toJson(expectedIssues), 0, expectedIssues.size()); } } } From 00bfa8a185a0bce5ba7cde4dd17510290a72398e Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 3 Sep 2024 19:48:38 -0500 Subject: [PATCH 49/73] Switch from gradle to maven --- .github/workflows/test.yml | 15 +- java-accessibility-checker/.gitattributes | 3 - java-accessibility-checker/.gitignore | 8 +- .../junit-selenium/lib/build.gradle | 2 +- .../gradle/libs.versions.toml | 12 - .../gradle/wrapper/gradle-wrapper.jar | Bin 43504 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - java-accessibility-checker/gradlew | 252 ------------------ java-accessibility-checker/gradlew.bat | 94 ------- java-accessibility-checker/lib/.gitignore | 1 - java-accessibility-checker/lib/build.gradle | 130 --------- java-accessibility-checker/pom.xml | 135 ++++++++++ java-accessibility-checker/settings.gradle | 14 - .../equalaccess/AccessibilityChecker.java | 0 .../able/equalaccess/abs/IAbstractAPI.java | 0 .../com/ibm/able/equalaccess/abs/MyFS.java | 0 .../equalaccess/config/ACConfigManager.java | 0 .../ibm/able/equalaccess/config/Archive.java | 0 .../ibm/able/equalaccess/config/Config.java | 0 .../equalaccess/config/ConfigInternal.java | 0 .../able/equalaccess/engine/ACEReport.java | 0 .../ibm/able/equalaccess/engine/ACError.java | 0 .../ibm/able/equalaccess/engine/ACReport.java | 0 .../equalaccess/engine/ACReportSummary.java | 0 .../ibm/able/equalaccess/engine/Bounds.java | 0 .../able/equalaccess/engine/Guideline.java | 0 .../com/ibm/able/equalaccess/engine/Rule.java | 0 .../equalaccess/engine/eRuleConfidence.java | 0 .../able/equalaccess/engine/eRuleLevel.java | 0 .../enginecontext/EngineContextLocal.java | 0 .../enginecontext/EngineContextManager.java | 0 .../enginecontext/IEngineContext.java | 0 .../selenium/EngineContextSelenium.java | 0 .../equalaccess/report/ACReporterCSV.java | 0 .../equalaccess/report/ACReporterJSON.java | 0 .../equalaccess/report/ACReporterMetrics.java | 0 .../equalaccess/report/BaselineManager.java | 0 .../equalaccess/report/CompressedReport.java | 0 .../able/equalaccess/report/IReporter.java | 0 .../able/equalaccess/report/ReporterFile.java | 0 .../equalaccess/report/ReporterManager.java | 0 .../equalaccess/report/ReporterStored.java | 0 .../com/ibm/able/equalaccess/util/Fetch.java | 0 .../com/ibm/able/equalaccess/util/Misc.java | 0 .../equalaccess/AccessibilityCheckerTest.java | 2 +- .../config/ACConfigManagerTest.java | 0 .../able/equalaccess/engine/ACReportTest.java | 0 .../ibm/able/equalaccess/util/FetchTest.java | 0 48 files changed, 147 insertions(+), 528 deletions(-) delete mode 100644 java-accessibility-checker/gradle/libs.versions.toml delete mode 100644 java-accessibility-checker/gradle/wrapper/gradle-wrapper.jar delete mode 100644 java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties delete mode 100755 java-accessibility-checker/gradlew delete mode 100644 java-accessibility-checker/gradlew.bat delete mode 100644 java-accessibility-checker/lib/.gitignore delete mode 100644 java-accessibility-checker/lib/build.gradle create mode 100644 java-accessibility-checker/pom.xml delete mode 100644 java-accessibility-checker/settings.gradle rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/config/Archive.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/config/Config.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/ACError.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/Rule.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/IReporter.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/util/Fetch.java (100%) rename java-accessibility-checker/{lib => }/src/main/java/com/ibm/able/equalaccess/util/Misc.java (100%) rename java-accessibility-checker/{lib => }/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java (99%) rename java-accessibility-checker/{lib => }/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java (100%) rename java-accessibility-checker/{lib => }/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java (100%) rename java-accessibility-checker/{lib => }/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7926ed346..ab5d3ef73 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -414,16 +414,15 @@ jobs: with: distribution: 'semeru' # See 'Supported distributions' for available options java-version: '17' - - run: ./gradlew jar - working-directory: java-accessibility-checker - - run: ./gradlew generatePomFileForGithubJavaPublication - working-directory: java-accessibility-checker - - name: Publish to GitHub Packages - run: ./gradlew publish + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + - name: Publish package + run: mvn --batch-mode deploy working-directory: java-accessibility-checker env: - USERNAME: ${{ secrets.MVN_GITHUB_USER }} - PASSWORD: ${{ secrets.MVN_GITHUB_TOKEN }} + MAVEN_USERNAME: ${{ secrets.MVN_GITHUB_USER }} + MAVEN_PASSWORD: ${{ secrets.MVN_GITHUB_TOKEN }} ############################################################################### # Karma Tests diff --git a/java-accessibility-checker/.gitattributes b/java-accessibility-checker/.gitattributes index f91f64602..a777e6858 100644 --- a/java-accessibility-checker/.gitattributes +++ b/java-accessibility-checker/.gitattributes @@ -1,9 +1,6 @@ # # https://help.github.com/articles/dealing-with-line-endings/ # -# Linux start script should use lf -/gradlew text eol=lf - # These are Windows script files and should use crlf *.bat text eol=crlf diff --git a/java-accessibility-checker/.gitignore b/java-accessibility-checker/.gitignore index 1b6985c00..af978774f 100644 --- a/java-accessibility-checker/.gitignore +++ b/java-accessibility-checker/.gitignore @@ -1,5 +1,3 @@ -# Ignore Gradle project-specific cache directory -.gradle - -# Ignore Gradle build output directory -build +.mvn +results +target \ No newline at end of file diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index 538ac5366..62b1c39f4 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -30,7 +30,7 @@ dependencies { // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - implementation 'com.ibm.able.equalaccess:accessibility-checker:1.0.0-beta-5:selenium' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-5:selenium' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/gradle/libs.versions.toml b/java-accessibility-checker/gradle/libs.versions.toml deleted file mode 100644 index ab0036d1b..000000000 --- a/java-accessibility-checker/gradle/libs.versions.toml +++ /dev/null @@ -1,12 +0,0 @@ -# This file was generated by the Gradle 'init' task. -# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format - -[versions] -commons-math3 = "3.6.1" -guava = "33.1.0-jre" -junit = "4.13.2" - -[libraries] -commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" } -guava = { module = "com.google.guava:guava", version.ref = "guava" } -junit = { module = "junit:junit", version.ref = "junit" } diff --git a/java-accessibility-checker/gradle/wrapper/gradle-wrapper.jar b/java-accessibility-checker/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 2c3521197d7c4586c843d1d3e9090525f1898cde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43504 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 TZiJi*F`$tkWLn) diff --git a/java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties b/java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 09523c0e5..000000000 --- a/java-accessibility-checker/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/java-accessibility-checker/gradlew b/java-accessibility-checker/gradlew deleted file mode 100755 index f5feea6d6..000000000 --- a/java-accessibility-checker/gradlew +++ /dev/null @@ -1,252 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/java-accessibility-checker/gradlew.bat b/java-accessibility-checker/gradlew.bat deleted file mode 100644 index 9d21a2183..000000000 --- a/java-accessibility-checker/gradlew.bat +++ /dev/null @@ -1,94 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/java-accessibility-checker/lib/.gitignore b/java-accessibility-checker/lib/.gitignore deleted file mode 100644 index 872aa273a..000000000 --- a/java-accessibility-checker/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -results \ No newline at end of file diff --git a/java-accessibility-checker/lib/build.gradle b/java-accessibility-checker/lib/build.gradle deleted file mode 100644 index 88702f448..000000000 --- a/java-accessibility-checker/lib/build.gradle +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * This generated file contains a sample Java library project to get you started. - * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.9/userguide/building_java_projects.html in the Gradle documentation. - */ - -plugins { - // Apply the java-library plugin for API and implementation separation. - id 'java-library' - id 'maven-publish' - // id 'signing' -} - -group 'com.ibm.able.equalaccess' -version '1.0.0-beta-5' -archivesBaseName = 'accessibility-checker' - -sourceSets { - selenium { - java { - srcDir 'src/main/java' - } - } - main { - java { - srcDir 'src/main/java' - exclude '**/enginecontext/selenium/**' - } - } - test { - java { - srcDir 'src/main/java' - } - } -} - -java { - registerFeature('selenium') { - usingSourceSet(sourceSets.selenium) - } -} - -repositories { - // Use Maven Central for resolving dependencies. - mavenCentral() -} - -dependencies { - implementation 'com.google.code.gson:gson:2.11.0' - // https://mavenlibs.com/maven/dependency/org.mozilla/rhino - implementation 'org.mozilla:rhino:1.7.14' - seleniumCompileOnly 'org.seleniumhq.selenium:selenium-java:4.23.0' - - // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java - // seleniumImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - seleniumImplementation 'com.google.code.gson:gson:2.11.0' - // https://mavenlibs.com/maven/dependency/org.mozilla/rhino - seleniumImplementation 'org.mozilla:rhino:1.7.14' - - // Use JUnit test framework. - testImplementation libs.junit - testImplementation 'org.seleniumhq.selenium:selenium-java:4.23.0' -} - -// Apply a specific Java toolchain to ease working on different environments. -java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } -} - -test { - testLogging { - showStandardStreams = true - showStackTraces = true - } -} - -jar { - // manifest { - // attributes "Main-Class": "com.baeldung.fatjar.Application" - // } - - // from { - // configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } - // } - - // duplicatesStrategy = DuplicatesStrategy.INCLUDE -} - -publishing { - repositories { - maven { - name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/IBMa/equal-access") - credentials { - username = project.findProperty("githubJava.user") ?: System.getenv("USERNAME") - password = project.findProperty("githubJava.key") ?: System.getenv("TOKEN") - } - } - } - publications { - githubJava(MavenPublication) { - from components.java - artifactId = 'accessibility-checker' - - pom { - name = 'accessibility-checker' - description = 'A module that allows you to perform integrated accessibility testing for environments such as JUnit and Selenium' - url = 'https://www.ibm.com/able/toolkit/tools/' - licenses { - license { - name = 'The Apache License, Version 2.0' - url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - } - } - scm { - connection = 'scm:git:git://github.com/IBMa/equal-access.git' - developerConnection = 'scm:git:ssh://github.com/IBMa/equal-access.git' - url = 'https://github.com/IBMa/equal-access' - } - } - } - } -} - -// signing { -// sign publishing.publications.githubJava -// } \ No newline at end of file diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml new file mode 100644 index 000000000..ff2c1ecf1 --- /dev/null +++ b/java-accessibility-checker/pom.xml @@ -0,0 +1,135 @@ + + + 4.0.0 + + com.ibm.able + accessibility-checker + 1.0.0-beta-1 + jar + + accessibility-checker + A module that allows you to perform integrated accessibility testing for environments such as JUnit and Selenium + https://www.ibm.com/able/toolkit/tools/ + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + https://github.com/IBMa/equal-access + + + + UTF-8 + 17 + + + + + + org.junit + junit-bom + 5.11.0 + pom + import + + + + + + + + junit + junit + 4.13.2 + test + + + + + + + com.google.code.gson + gson + 2.11.0 + + + org.mozilla + rhino + 1.7.14 + + + org.seleniumhq.selenium + selenium-java + 4.23.0 + + + + + + + + + maven-clean-plugin + 3.4.0 + + + + maven-resources-plugin + 3.3.1 + + + maven-compiler-plugin + 3.13.0 + + + maven-surefire-plugin + 3.3.0 + + + maven-jar-plugin + 3.4.2 + + + maven-install-plugin + 3.1.2 + + + maven-deploy-plugin + 3.1.2 + + + + maven-site-plugin + 3.12.1 + + + maven-project-info-reports-plugin + 3.6.1 + + + + + + + + ossrh + Central Repository OSSRH + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + diff --git a/java-accessibility-checker/settings.gradle b/java-accessibility-checker/settings.gradle deleted file mode 100644 index 60a3ed8fe..000000000 --- a/java-accessibility-checker/settings.gradle +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.9/userguide/multi_project_builds.html in the Gradle documentation. - */ - -plugins { - // Apply the foojay-resolver plugin to allow automatic download of JDKs - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' -} - -rootProject.name = 'java-accessibility-checker' -include('lib') diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/IAbstractAPI.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/abs/MyFS.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ACConfigManager.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Archive.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Archive.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Archive.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Archive.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Config.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Config.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/Config.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/Config.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/config/ConfigInternal.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACEReport.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACError.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACError.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACError.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACError.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReportSummary.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/Bounds.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/Guideline.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Rule.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/Rule.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/Rule.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/Rule.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleConfidence.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/eRuleLevel.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextLocal.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/IEngineContext.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterCSV.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterJSON.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ACReporterMetrics.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/BaselineManager.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/CompressedReport.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/IReporter.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/IReporter.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/IReporter.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterFile.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterManager.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/report/ReporterStored.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Fetch.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Fetch.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Fetch.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Fetch.java diff --git a/java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Misc.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Misc.java similarity index 100% rename from java-accessibility-checker/lib/src/main/java/com/ibm/able/equalaccess/util/Misc.java rename to java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/util/Misc.java diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java similarity index 99% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java rename to java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java index 8337e2b8e..d83d7ea90 100644 --- a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java @@ -182,7 +182,7 @@ private void listFiles(File f, java.util.List retFiles) { ACConfigManager.getConfig(); Gson gson = new Gson(); - File testRootDir = Paths.get(System.getProperty("user.dir"), "..","..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); + File testRootDir = Paths.get(System.getProperty("user.dir"), "..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); ArrayList testFiles = new ArrayList<>(); listFiles(testRootDir, testFiles); diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java similarity index 100% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java rename to java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/config/ACConfigManagerTest.java diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java similarity index 100% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java rename to java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/engine/ACReportTest.java diff --git a/java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java similarity index 100% rename from java-accessibility-checker/lib/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java rename to java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/util/FetchTest.java From 66f592170f9f794b45f8034e5eded2b06847122c Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 3 Sep 2024 20:06:43 -0500 Subject: [PATCH 50/73] fix maven test --- .github/workflows/test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab5d3ef73..ab207f3a8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -391,7 +391,8 @@ jobs: working-directory: rule-server/dist - run: sleep 10 working-directory: rule-server/dist - - run: ./gradlew test + - name: Publish package + run: mvn --batch-mode test working-directory: java-accessibility-checker env: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} @@ -423,6 +424,8 @@ jobs: env: MAVEN_USERNAME: ${{ secrets.MVN_GITHUB_USER }} MAVEN_PASSWORD: ${{ secrets.MVN_GITHUB_TOKEN }} + chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} + chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} ############################################################################### # Karma Tests From 0b0b1369a667f19ad79a22a63d8605f08dff2d99 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Tue, 3 Sep 2024 20:14:36 -0500 Subject: [PATCH 51/73] chromedriver missing in deploy --- .github/workflows/test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab207f3a8..8ca0515db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -418,6 +418,12 @@ jobs: server-id: ossrh server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD + - name: Latest Chrome + uses: browser-actions/setup-chrome@v1 + with: + chrome-version: latest + install-chromedriver: true + id: setup-chrome - name: Publish package run: mvn --batch-mode deploy working-directory: java-accessibility-checker From dd0aff64b1b3ffbad8511883bda2787a67e7c256 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Wed, 4 Sep 2024 08:45:53 -0500 Subject: [PATCH 52/73] Start local rule server for testing --- .github/workflows/test.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8ca0515db..db594fe36 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -391,7 +391,7 @@ jobs: working-directory: rule-server/dist - run: sleep 10 working-directory: rule-server/dist - - name: Publish package + - name: Test package run: mvn --batch-mode test working-directory: java-accessibility-checker env: @@ -424,6 +424,14 @@ jobs: chrome-version: latest install-chromedriver: true id: setup-chrome + - run: npm install + working-directory: rule-server + - run: npm run build + working-directory: rule-server + - run: node main.js & + working-directory: rule-server/dist + - run: sleep 10 + working-directory: rule-server/dist - name: Publish package run: mvn --batch-mode deploy working-directory: java-accessibility-checker From 5b3a5940292ac219386f892e6802470bdfae4728 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Wed, 4 Sep 2024 14:29:03 -0500 Subject: [PATCH 53/73] Deploy test --- .github/workflows/test.yml | 10 +- java-accessibility-checker/.gitignore | 3 +- java-accessibility-checker/pom.xml | 240 ++++++++++-------- .../equalaccess/AccessibilityCheckerTest.java | 2 +- 4 files changed, 141 insertions(+), 114 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db594fe36..03a3dc582 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -418,6 +418,14 @@ jobs: server-id: ossrh server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD + - uses: s4u/maven-settings-action@v3.0.0 + with: + servers: | + [{ + "id": "central", + "username": "${{ secrets.MVN_GITHUB_USER }}", + "password": "${{ secrets.MVN_GITHUB_TOKEN }}" + }] - name: Latest Chrome uses: browser-actions/setup-chrome@v1 with: @@ -436,8 +444,6 @@ jobs: run: mvn --batch-mode deploy working-directory: java-accessibility-checker env: - MAVEN_USERNAME: ${{ secrets.MVN_GITHUB_USER }} - MAVEN_PASSWORD: ${{ secrets.MVN_GITHUB_TOKEN }} chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} diff --git a/java-accessibility-checker/.gitignore b/java-accessibility-checker/.gitignore index af978774f..7efcebc83 100644 --- a/java-accessibility-checker/.gitignore +++ b/java-accessibility-checker/.gitignore @@ -1,3 +1,4 @@ .mvn results -target \ No newline at end of file +target +settings.xml \ No newline at end of file diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml index ff2c1ecf1..e65e59065 100644 --- a/java-accessibility-checker/pom.xml +++ b/java-accessibility-checker/pom.xml @@ -1,135 +1,155 @@ - - 4.0.0 + + 4.0.0 - com.ibm.able - accessibility-checker - 1.0.0-beta-1 - jar + com.ibm.able + accessibility-checker + 1.0.0-beta-1 + pom - accessibility-checker - A module that allows you to perform integrated accessibility testing for environments such as JUnit and Selenium - https://www.ibm.com/able/toolkit/tools/ + accessibility-checker + A module that allows you to perform integrated accessibility testing for environments such as JUnit and Selenium + https://www.ibm.com/able/toolkit/tools/ - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + - - https://github.com/IBMa/equal-access - + + scm:git:git://github.com/IBMa/equal-access.git + scm:git:ssh://github.com:IBMa/equal-access.git + http://github.com/IBMa/equal-access/tree/master + - - UTF-8 - 17 - + + UTF-8 + 17 + - - - - org.junit - junit-bom - 5.11.0 - pom - import - - - + + + + org.junit + junit-bom + 5.11.0 + pom + import + + + - - - - junit - junit - 4.13.2 - test - + + + + junit + junit + 4.13.2 + test + - - - + - - com.google.code.gson - gson - 2.11.0 - - - org.mozilla - rhino - 1.7.14 - - - org.seleniumhq.selenium - selenium-java - 4.23.0 - - + + com.google.code.gson + gson + 2.11.0 + + + org.mozilla + rhino + 1.7.14 + + + org.seleniumhq.selenium + selenium-java + 4.23.0 + + - - - - - - maven-clean-plugin - 3.4.0 - - - - maven-resources-plugin - 3.3.1 - - - maven-compiler-plugin - 3.13.0 - - - maven-surefire-plugin - 3.3.0 - - - maven-jar-plugin - 3.4.2 - - - maven-install-plugin - 3.1.2 - - - maven-deploy-plugin - 3.1.2 - - - - maven-site-plugin - 3.12.1 - - - maven-project-info-reports-plugin - 3.6.1 - - - - + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.5.0 + true + + central + + + + + + + + Tom Brunet + thbrunet@us.ibm.com + IBM Accessibility + http://ibm.com/able + + + \ No newline at end of file diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java index d83d7ea90..e5e644c16 100644 --- a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java @@ -150,7 +150,7 @@ private void listFiles(File f, java.util.List retFiles) { } } - @Test public void getComplianceTestsuite() throws IOException { + public void getComplianceTestsuite() throws IOException { ACConfigManager.resetConfig(); File configFile = new File("achecker.json"); try { From e12ce3bdfeef0bfc677b2314fde2fd2d2295adfc Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 13:48:41 -0500 Subject: [PATCH 54/73] Try deploy from git --- .github/workflows/test.yml | 7 +++++- java-accessibility-checker/.gitignore | 3 ++- java-accessibility-checker/README-DEV.md | 31 +++++++++++++++--------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 03a3dc582..eb8fd8c8f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -426,6 +426,11 @@ jobs: "username": "${{ secrets.MVN_GITHUB_USER }}", "password": "${{ secrets.MVN_GITHUB_TOKEN }}" }] + - name: Configure GPG Key + run: | + echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import + env: + GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - name: Latest Chrome uses: browser-actions/setup-chrome@v1 with: @@ -441,7 +446,7 @@ jobs: - run: sleep 10 working-directory: rule-server/dist - name: Publish package - run: mvn --batch-mode deploy + run: mvn --batch-mode deploy -Dgpg.passphrase=${{ secrets.GPG_SIGNING_KEY_PASS }} working-directory: java-accessibility-checker env: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} diff --git a/java-accessibility-checker/.gitignore b/java-accessibility-checker/.gitignore index 7efcebc83..1364bf4a5 100644 --- a/java-accessibility-checker/.gitignore +++ b/java-accessibility-checker/.gitignore @@ -1,4 +1,5 @@ .mvn results target -settings.xml \ No newline at end of file +settings.xml +*.gpg \ No newline at end of file diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index ef76cd2a9..3b36e1731 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -1,26 +1,33 @@ -## Example gradle commands +## Example maven commands -Run a specific testcase: +Run all tests: ``` -./gradlew test --tests com.ibm.able.equalaccess.AccessibilityCheckerTest +mvn test ``` -Run all tests: +Deploy ``` -./gradlew test +mvn -s ./settings.xml clean deploy -Dgpg.passphrase=yourpassphrase ``` -Create jar (result in lib/build/libs): +## PGP Key Management + +Generate PGP key: ``` -./gradlew jar +gpg --gen-key +> Real name: IBM Accessibility +> Email address: eatools@us.ibm.com +gpg --armor --output public-key.gpg --export eatools@us.ibm.com ``` +Go to https://keyserver.ubuntu.com/, Click `Submit Key`, and paste in public-key.gpg -Generate javadoc +Export private key: ``` -./gradlew javadoc +gpg --export-secret-keys 7A58C8C58C35FF078630FA3615954E19FBC774C4 | base64 ``` -Create maven POM file: +Verify Key: +``` +gpg --list-signatures ``` -./gradlew generatePomFileForMavenJavaPublication -``` \ No newline at end of file +Go to https://keyserver.ubuntu.com/pks/lookup?search=7A58C8C58C35FF078630FA3615954E19FBC774C4&fingerprint=on&op=index and replace `7A58C8C58C35FF078630FA3615954E19FBC774C4` with the key signature \ No newline at end of file From fbc70c18180d4ba9ae56690c046bef3bb860a6ca Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 13:53:15 -0500 Subject: [PATCH 55/73] ioctl error --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eb8fd8c8f..08bba77a7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -428,7 +428,7 @@ jobs: }] - name: Configure GPG Key run: | - echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import + export GPG_TTY=$(tty) echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - name: Latest Chrome @@ -446,7 +446,7 @@ jobs: - run: sleep 10 working-directory: rule-server/dist - name: Publish package - run: mvn --batch-mode deploy -Dgpg.passphrase=${{ secrets.GPG_SIGNING_KEY_PASS }} + run: mvn --batch-mode deploy -DskipTests -Dgpg.passphrase=${{ secrets.GPG_SIGNING_KEY_PASS }} working-directory: java-accessibility-checker env: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} From e26e72d26121534d116c84d055968d5b72ae133c Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 13:56:57 -0500 Subject: [PATCH 56/73] Try another way to pass key --- .github/workflows/test.yml | 7 ++----- .../com/ibm/able/equalaccess/AccessibilityCheckerTest.java | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 08bba77a7..720f5b250 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -426,11 +426,6 @@ jobs: "username": "${{ secrets.MVN_GITHUB_USER }}", "password": "${{ secrets.MVN_GITHUB_TOKEN }}" }] - - name: Configure GPG Key - run: | - export GPG_TTY=$(tty) echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import - env: - GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - name: Latest Chrome uses: browser-actions/setup-chrome@v1 with: @@ -451,6 +446,8 @@ jobs: env: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_KEY_PASS }} + MAVEN_GPG_KEY: ${{ secrets.GPG_SIGNING_KEY }} ############################################################################### # Karma Tests diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java index e5e644c16..d83d7ea90 100644 --- a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerTest.java @@ -150,7 +150,7 @@ private void listFiles(File f, java.util.List retFiles) { } } - public void getComplianceTestsuite() throws IOException { + @Test public void getComplianceTestsuite() throws IOException { ACConfigManager.resetConfig(); File configFile = new File("achecker.json"); try { From db70f27330f5e825ff2490e1653b217dd8dda186 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 14:10:46 -0500 Subject: [PATCH 57/73] gpg import --- .github/workflows/test.yml | 4 ++++ java-accessibility-checker/README-DEV.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 720f5b250..1c85e87f4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -426,6 +426,10 @@ jobs: "username": "${{ secrets.MVN_GITHUB_USER }}", "password": "${{ secrets.MVN_GITHUB_TOKEN }}" }] + - name: Configure GPG Key + run: echo "$GPG_SIGNING_KEY" | gpg --import + env: + GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - name: Latest Chrome uses: browser-actions/setup-chrome@v1 with: diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index 3b36e1731..fbc5d89b1 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -23,7 +23,7 @@ Go to https://keyserver.ubuntu.com/, Click `Submit Key`, and paste in public-key Export private key: ``` -gpg --export-secret-keys 7A58C8C58C35FF078630FA3615954E19FBC774C4 | base64 +gpg --export-secret-keys -a 7A58C8C58C35FF078630FA3615954E19FBC774C4 ``` Verify Key: From 47c8988fdf9086814dac00b122e3fad1cb9eff49 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 14:13:06 -0500 Subject: [PATCH 58/73] import key --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1c85e87f4..24ce142b1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -427,9 +427,11 @@ jobs: "password": "${{ secrets.MVN_GITHUB_TOKEN }}" }] - name: Configure GPG Key - run: echo "$GPG_SIGNING_KEY" | gpg --import + run: echo "$GPG_SIGNING_KEY" >private.key env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} + - name: Import GPG Key + run: gpg --import private.key - name: Latest Chrome uses: browser-actions/setup-chrome@v1 with: From 9fbc81b3f3e1fbedb5590c68f02ef58b2bb3bbaf Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 14:23:15 -0500 Subject: [PATCH 59/73] gpg --- .github/workflows/test.yml | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 24ce142b1..b392a1f5a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -415,9 +415,9 @@ jobs: with: distribution: 'semeru' # See 'Supported distributions' for available options java-version: '17' - server-id: ossrh - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD + server-id: central + server-username: ${{ secrets.MVN_GITHUB_USER }} + server-password: ${{ secrets.MVN_GITHUB_TOKEN }} - uses: s4u/maven-settings-action@v3.0.0 with: servers: | @@ -431,29 +431,14 @@ jobs: env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - name: Import GPG Key - run: gpg --import private.key - - name: Latest Chrome - uses: browser-actions/setup-chrome@v1 - with: - chrome-version: latest - install-chromedriver: true - id: setup-chrome - - run: npm install - working-directory: rule-server - - run: npm run build - working-directory: rule-server - - run: node main.js & - working-directory: rule-server/dist - - run: sleep 10 - working-directory: rule-server/dist + run: gpg --import private.key --pinentry-mode=loopback --passphrase "$GPG_SIGNING_KEY_PASS" + env: + GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} - name: Publish package - run: mvn --batch-mode deploy -DskipTests -Dgpg.passphrase=${{ secrets.GPG_SIGNING_KEY_PASS }} + run: mvn --batch-mode deploy -DskipTests -Dgpg.passphrase=$GPG_SIGNING_KEY_PASS working-directory: java-accessibility-checker env: - chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} - chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_KEY_PASS }} - MAVEN_GPG_KEY: ${{ secrets.GPG_SIGNING_KEY }} + GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} ############################################################################### # Karma Tests From 4d9afb12351385859116bad23a209d4d4df9078e Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 14:26:50 -0500 Subject: [PATCH 60/73] param order --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b392a1f5a..267e1aee5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -431,7 +431,7 @@ jobs: env: GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - name: Import GPG Key - run: gpg --import private.key --pinentry-mode=loopback --passphrase "$GPG_SIGNING_KEY_PASS" + run: gpg --pinentry-mode=loopback --passphrase "$GPG_SIGNING_KEY_PASS" --import private.key env: GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} - name: Publish package From c03652434deaa21fe53b9aff317d825eda8ea06f Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 14:36:35 -0500 Subject: [PATCH 61/73] gpg loopback --- java-accessibility-checker/README-DEV.md | 2 ++ java-accessibility-checker/pom.xml | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index fbc5d89b1..5c82af7f0 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -1,3 +1,5 @@ +Deployments found at https://central.sonatype.com/publishing/deployments + ## Example maven commands Run all tests: diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml index e65e59065..a5c2a0fab 100644 --- a/java-accessibility-checker/pom.xml +++ b/java-accessibility-checker/pom.xml @@ -110,6 +110,13 @@ + + + + --pinentry-mode + loopback + + org.apache.maven.plugins From 570683ca8067e875aa3f338869d390c88f12f8db Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 15:01:38 -0500 Subject: [PATCH 62/73] Try jar package --- .../boilerplates/junit-selenium/lib/build.gradle | 9 +-------- java-accessibility-checker/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index 62b1c39f4..b626fe4fe 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -15,13 +15,6 @@ version '1.0.0' repositories { // Use Maven Central for resolving dependencies. mavenCentral() - maven { - url = uri("https://maven.pkg.github.com/IBMa/equal-access") - credentials { - username = project.findProperty("gpr.user") ?: System.getenv("USERNAME") - password = project.findProperty("gpr.key") ?: System.getenv("TOKEN") - } - } } dependencies { @@ -30,7 +23,7 @@ dependencies { // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-5:selenium' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-2' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml index a5c2a0fab..6d62ece54 100644 --- a/java-accessibility-checker/pom.xml +++ b/java-accessibility-checker/pom.xml @@ -6,8 +6,8 @@ com.ibm.able accessibility-checker - 1.0.0-beta-1 - pom + 1.0.0-beta-2 + jar accessibility-checker A module that allows you to perform integrated accessibility testing for environments such as JUnit and Selenium From b4a8e76c7139924bdcae3a1b9fb8d4f9cd9b339e Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 15:09:47 -0500 Subject: [PATCH 63/73] maven compiler props --- java-accessibility-checker/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml index 6d62ece54..c51806418 100644 --- a/java-accessibility-checker/pom.xml +++ b/java-accessibility-checker/pom.xml @@ -30,6 +30,8 @@ UTF-8 17 + 17 + 17 From 19b09d9b85270681eaca6feff739874ed5dfc728 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 16:01:35 -0500 Subject: [PATCH 64/73] Setup release deployments for java checker --- .github/workflows/publish.yml | 44 +++++++++++++++++++++++++++++- .github/workflows/test.yml | 42 ---------------------------- java-accessibility-checker/pom.xml | 22 +++++++-------- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index effb8a43e..3f6b552e4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -222,4 +222,46 @@ jobs: BLUEMIX_USERID: apikey BLUEMIX_PASS: ${{ secrets.BLUEMIX_PASS }} CLOUD_PWD: ${{ secrets.CLOUD_PWD }} - TRAVIS_BRANCH: prod \ No newline at end of file + TRAVIS_BRANCH: prod + + java-accessibility-checker-deploy: + runs-on: ubuntu-22.04 + permissions: + packages: write + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v4 + with: + distribution: 'semeru' # See 'Supported distributions' for available options + java-version: '17' + server-id: central + server-username: ${{ secrets.MVN_GITHUB_USER }} + server-password: ${{ secrets.MVN_GITHUB_TOKEN }} + - uses: s4u/maven-settings-action@v3.0.0 + with: + servers: | + [{ + "id": "central", + "username": "${{ secrets.MVN_GITHUB_USER }}", + "password": "${{ secrets.MVN_GITHUB_TOKEN }}" + }] + - name: Configure GPG Key + run: echo "$GPG_SIGNING_KEY" >private.key + env: + GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} + - name: Import GPG Key + run: gpg --pinentry-mode=loopback --passphrase "$GPG_SIGNING_KEY_PASS" --import private.key + env: + GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} + - name: Set version + run: sed -i'.old' -e 's/\3\.0\.0\<\/version\>/\'"${GITHUB_REF:10}"'\<\/version\>/g' ./pom.xml + working-directory: java-accessibility-checker + - name: Publish package + run: mvn --batch-mode deploy -DskipTests -Dgpg.passphrase=$GPG_SIGNING_KEY_PASS + working-directory: java-accessibility-checker + env: + GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 267e1aee5..319df1214 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -398,48 +398,6 @@ jobs: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} -############################################################################### -# Java test -#### - java-accessibility-checker-buildtest: - runs-on: ubuntu-22.04 - permissions: - packages: write - strategy: - matrix: - node-version: [18.x] - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v4 - with: - distribution: 'semeru' # See 'Supported distributions' for available options - java-version: '17' - server-id: central - server-username: ${{ secrets.MVN_GITHUB_USER }} - server-password: ${{ secrets.MVN_GITHUB_TOKEN }} - - uses: s4u/maven-settings-action@v3.0.0 - with: - servers: | - [{ - "id": "central", - "username": "${{ secrets.MVN_GITHUB_USER }}", - "password": "${{ secrets.MVN_GITHUB_TOKEN }}" - }] - - name: Configure GPG Key - run: echo "$GPG_SIGNING_KEY" >private.key - env: - GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }} - - name: Import GPG Key - run: gpg --pinentry-mode=loopback --passphrase "$GPG_SIGNING_KEY_PASS" --import private.key - env: - GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} - - name: Publish package - run: mvn --batch-mode deploy -DskipTests -Dgpg.passphrase=$GPG_SIGNING_KEY_PASS - working-directory: java-accessibility-checker - env: - GPG_SIGNING_KEY_PASS: ${{ secrets.GPG_SIGNING_KEY_PASS }} - ############################################################################### # Karma Tests #### diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml index c51806418..97db7c3c7 100644 --- a/java-accessibility-checker/pom.xml +++ b/java-accessibility-checker/pom.xml @@ -6,7 +6,7 @@ com.ibm.able accessibility-checker - 1.0.0-beta-2 + 3.0.0 jar accessibility-checker @@ -39,7 +39,7 @@ org.junit junit-bom - 5.11.0 + xxxx pom import @@ -51,14 +51,14 @@ junit junit - 4.13.2 + xxxx test @@ -70,17 +70,17 @@ com.google.code.gson gson - 2.11.0 + xxxx org.mozilla rhino - 1.7.14 + xxxx org.seleniumhq.selenium selenium-java - 4.23.0 + xxxx @@ -89,7 +89,7 @@ org.apache.maven.plugins maven-source-plugin - 2.2.1 + xxxx attach-sources @@ -102,7 +102,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + xxxx sign-artifacts @@ -123,7 +123,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.9.1 + xxxx attach-javadocs @@ -136,7 +136,7 @@ org.sonatype.central central-publishing-maven-plugin - 0.5.0 + xxxx true central From 75552a44bd30dd860b2c3b5f37b8eaa2213be300 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 16:42:20 -0500 Subject: [PATCH 65/73] Add note to README --- java-accessibility-checker/README-DEV.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index 5c82af7f0..bcb3d15ce 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -12,6 +12,8 @@ Deploy mvn -s ./settings.xml clean deploy -Dgpg.passphrase=yourpassphrase ``` +Deployments show up on https://central.sonatype.com/publishing/deployments and then they can be Dropped or Published. Once Published, they cannot be Dropped. + ## PGP Key Management Generate PGP key: From 881454dfc765d2c9abc9c600de8e92f365a0d0cd Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 21:40:16 -0500 Subject: [PATCH 66/73] Add Playwright support --- .github/workflows/test.yml | 38 ++- java-accessibility-checker/pom.xml | 45 ++- .../enginecontext/EngineContextManager.java | 25 ++ .../playwright/EngineContextPlaywright.java | 308 ++++++++++++++++++ .../AccessibilityCheckerPlaywrightTest.java | 223 +++++++++++++ ... => AccessibilityCheckerSeleniumTest.java} | 30 +- 6 files changed, 634 insertions(+), 35 deletions(-) create mode 100644 java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java create mode 100644 java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerPlaywrightTest.java rename java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/{AccessibilityCheckerTest.java => AccessibilityCheckerSeleniumTest.java} (87%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 319df1214..b22b0cad2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -364,7 +364,7 @@ jobs: ############################################################################### # Java test #### - java-accessibility-checker-test: + java-accessibility-checker-selenium-test: runs-on: ubuntu-22.04 strategy: @@ -392,7 +392,41 @@ jobs: - run: sleep 10 working-directory: rule-server/dist - name: Test package - run: mvn --batch-mode test + run: mvn --batch-mode test -Dtest="AccessibilityCheckerSeleniumTest" + working-directory: java-accessibility-checker + env: + chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} + chromebinpath: ${{ steps.setup-chrome.outputs.chrome-path }} + + java-accessibility-checker-playwright-test: + runs-on: ubuntu-22.04 + + strategy: + matrix: + node-version: [18.x] + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v4 + with: + distribution: 'semeru' # See 'Supported distributions' for available options + java-version: '17' + - name: Latest Chrome + uses: browser-actions/setup-chrome@v1 + with: + chrome-version: latest + install-chromedriver: true + id: setup-chrome + - run: npm install + working-directory: rule-server + - run: npm run build + working-directory: rule-server + - run: node main.js & + working-directory: rule-server/dist + - run: sleep 10 + working-directory: rule-server/dist + - name: Test package + run: mvn --batch-mode test -Dtest="AccessibilityCheckerPlaywrightTest" working-directory: java-accessibility-checker env: chromedriverpath: ${{ steps.setup-chrome.outputs.chromedriver-path }} diff --git a/java-accessibility-checker/pom.xml b/java-accessibility-checker/pom.xml index 97db7c3c7..529001e71 100644 --- a/java-accessibility-checker/pom.xml +++ b/java-accessibility-checker/pom.xml @@ -39,7 +39,7 @@ org.junit junit-bom - xxxx + 5.11.0 pom import @@ -51,14 +51,14 @@ junit junit - xxxx + 4.13.2 test @@ -70,26 +70,42 @@ com.google.code.gson gson - xxxx + 2.11.0 org.mozilla rhino - xxxx + 1.7.14 org.seleniumhq.selenium selenium-java - xxxx + 4.23.0 + provided + + + com.microsoft.playwright + playwright + 1.46.0 + provided + org.apache.maven.plugins maven-source-plugin - xxxx + 2.2.1 attach-sources @@ -102,7 +118,7 @@ org.apache.maven.plugins maven-gpg-plugin - xxxx + 1.5 sign-artifacts @@ -123,7 +139,7 @@ org.apache.maven.plugins maven-javadoc-plugin - xxxx + 2.9.1 attach-javadocs @@ -136,7 +152,7 @@ org.sonatype.central central-publishing-maven-plugin - xxxx + 0.5.0 true central @@ -145,14 +161,7 @@ - + Tom Brunet diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java index 6c157a6ee..4731e4e82 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/EngineContextManager.java @@ -33,6 +33,7 @@ public static IEngineContext getEngineContext(Object contentContext) { if (contentContext == null) { engineContext = new EngineContextLocal(); } + // See if this is Selenium and we can load it if (engineContext == null && Misc.classIsAvailable("org.openqa.selenium.WebDriver")) { @@ -56,6 +57,30 @@ public static IEngineContext getEngineContext(Object contentContext) { } catch (InvocationTargetException e) { } } + // See if this is Playwright and we can load it + if (engineContext == null + && Misc.classIsAvailable("com.microsoft.playwright.Page")) + { + if (!Misc.classIsAvailable("com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright")) { + System.err.println("Attempted scan with Page, but com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright could not be loaded"); + throw new ACError("Attempted scan with Page, but com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright could not be loaded"); + } + try { + Class playwrightPageClass = Class.forName("com.microsoft.playwright.Page"); + if (playwrightPageClass.isAssignableFrom(contentContext.getClass())) { + // We have a webdriver, use EngineContextSelenium to instantiate it + Class ecClass = Class.forName("com.ibm.able.equalaccess.enginecontext.playwright.EngineContextPlaywright"); + engineContext = (IEngineContext) ecClass.getConstructor(playwrightPageClass).newInstance(contentContext); + } + } catch (ClassNotFoundException e) { + } catch (NoSuchMethodException e) { + } catch (SecurityException e) { + } catch (InstantiationException e) { + } catch (IllegalAccessException e) { + } catch (IllegalArgumentException e) { + } catch (InvocationTargetException e) { + } + } if (engineContext != null) { engineContext.loadEngine(); } else { diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java new file mode 100644 index 000000000..d770e3a98 --- /dev/null +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java @@ -0,0 +1,308 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess.enginecontext.playwright; + +import java.io.IOException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Arrays; + +import com.google.gson.Gson; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.config.Config; +import com.ibm.able.equalaccess.config.ConfigInternal; +import com.ibm.able.equalaccess.engine.ACError; +import com.ibm.able.equalaccess.engine.Guideline; +import com.ibm.able.equalaccess.engine.Rule; +import com.ibm.able.equalaccess.enginecontext.IEngineContext; +import com.ibm.able.equalaccess.engine.ACEReport; +import com.ibm.able.equalaccess.util.Fetch; +import com.microsoft.playwright.*; + +public class EngineContextPlaywright implements IEngineContext { + private static Gson gson = new Gson(); + private Page driver = null; + private String engineContent = null; + + public EngineContextPlaywright(Page driver) { + this.driver = driver; + } + + @Override + public void loadEngine() { + ConfigInternal config = ACConfigManager.getConfigUnsupported(); + String engineUrl = config.rulePack+"/ace.js"; + String engineLoadMode = config.engineMode; + if ("DEFAULT".equals(engineLoadMode)) { + engineLoadMode = "INJECT"; + } + try { + if ("INJECT".equals(engineLoadMode) && engineContent == null) { + engineContent = Fetch.get(engineUrl, config.ignoreHTTPSErrors); + } + + if (config.DEBUG) System.out.println("[INFO] aChecker.loadEngine detected Selenium"); + String scriptStr; + if ("REMOTE".equals(engineLoadMode)) { + scriptStr = """ +(scriptUrl) => { + try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + return new Promise((resolve, reject) => { + let script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script.setAttribute('aChecker', 'ACE'); + script.setAttribute('src', scriptUrl); + script.addEventListener('load', function () { + globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + resolve(); + }); + script.addEventListener('error', function (evt) { + reject(new Error(`Unable to load engine into ${document.location.href}. This can happen if the page server sets a Content-Security-Policy that prevents ${scriptUrl} from loading.`)) + }); + let heads = document.getElementsByTagName('head'); + if (heads.length > 0) { heads[0].appendChild(script); } + else if (document.body) { document.body.appendChild(script); } + else { Promise.reject("Invalid document"); } + }) + } + } catch (e) { + return Promise.reject(e); + } +} +"""; + this.driver.evaluate(scriptStr, config.rulePack); + } else if ("INJECT".equals(engineLoadMode)) { + // Selenium + scriptStr = """ +(engineContent) => { + try { + var ace_backup_in_ibma; + if ('undefined' !== typeof(ace)) { + if (!ace || !ace.Checker) + ace_backup_in_ibma = ace; + ace = null; + } + if ('undefined' === typeof (ace) || ace === null) { + return new Promise((resolve, reject) => { + eval(engineContent); + globalThis.ace_ibma = ace; + if ('undefined' !== typeof(ace)) { + ace = ace_backup_in_ibma; + } + resolve(); + }) + } + } catch (e) { + return Promise.reject(e); + } +} +"""; + this.driver.evaluate(scriptStr, engineContent); + } else { + scriptStr = ""; + } + + // this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(60)); + + } catch (Error e) { + System.err.println(e); + } catch (IOException e) { + System.err.println("aChecker: Unable to load engine from "+engineUrl+" due to IOException: "+e.toString()); + e.printStackTrace(); + } + } + + @Override + public ACEReport getCompliance(String label) { + Config config = ACConfigManager.getConfig(); + try { + List resultList = new ArrayList<>(config.reportLevels.length + config.failLevels.length); + Collections.addAll(resultList, config.reportLevels); + Collections.addAll(resultList, config.failLevels); + String scriptStr = """ +([policies, reportLevels]) => { + try { + const valueToLevel = (reportValue) => { + let reportLevel; + if (reportValue[1] === "PASS") { + reportLevel = "pass"; + } + else if ((reportValue[0] === "VIOLATION" || reportValue[0] === "RECOMMENDATION") && reportValue[1] === "MANUAL") { + reportLevel = "manual"; + } + else if (reportValue[0] === "VIOLATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "violation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialviolation"; + } + } + else if (reportValue[0] === "RECOMMENDATION") { + if (reportValue[1] === "FAIL") { + reportLevel = "recommendation"; + } + else if (reportValue[1] === "POTENTIAL") { + reportLevel = "potentialrecommendation"; + } + } + return reportLevel; + } + const getCounts = (engineReport) => { + let counts = { + violation: 0, + potentialviolation: 0, + recommendation: 0, + potentialrecommendation: 0, + manual: 0, + pass: 0 + } + for (const issue of engineReport.results) { + ++counts[issue.level]; + } + return counts; + } + + let checker = new window.ace_ibma.Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + return new Promise((resolve, reject) => { + checker.check(document, policies).then(async function(report) { + for (const result of report.results) { + delete result.node; + result.level = valueToLevel(result.value) + } + report.summary ||= {}; + report.summary.counts ||= getCounts(report); + // Filter out pass results unless they asked for them in reports + // We don't want to mess with baseline functions, but pass results can break the response object + report.results = report.results.filter(result => reportLevels.includes(result.level) || result.level !== "pass"); + resolve(JSON.stringify(report)); + }) + }); + } catch (e) { + return Promise.reject(e); + } +} + """; + ACEReport report; + String jsonReport = this.driver.evaluate(scriptStr, Arrays.asList( + config.policies, + resultList.toArray() + /* TODO: ${JSON.stringify(ACEngineManager.customRulesets)}; */ + )).toString(); + if (!jsonReport.startsWith("{\"results\":[")) { + throw new ACError(jsonReport); + } else { + report = gson.fromJson(jsonReport, ACEReport.class); + } + + // TODO: + // String getPolicies = "return new window.ace_ibma.Checker().rulesetIds;"; + // if (curPol != null && !checkPolicy) { + // checkPolicy = true; + // const valPolicies = ACEngineManager.customRulesets.map(rs => rs.id).concat(await browser.executeScript(getPolicies)); + // areValidPolicy(valPolicies, curPol); + // } + + // If there is something to report... + if (report.results != null) { + if (config.captureScreenshots) { + // TODO: Screenshot? + // String image = ((TakesScreenshot)this.driver).getScreenshotAs(OutputType.BASE64); + // report.screenshot = image; + } + } + return report; + } catch (Error err) { + System.err.println(err); + throw err; + } + } + + @Override + public String getUrl() { + return this.driver.url(); + } + + @Override + public String getTitle() { + return this.driver.title(); + } + + @Override + public Guideline[] getGuidelines() { + String scriptStr = String.format(""" +() => { + try { + let checker = new window.ace_ibma.Checker(); + let customRulesets = []; + customRulesets.forEach((rs) => checker.addRuleset(rs)); + return Promise.resolve(JSON.stringify(checker.getGuidelines())); + } catch (e) { + return Promise.reject(e); + } +} +"""); + String jsonGuidelines = this.driver.evaluate(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Guideline[].class); + } + + @Override + public Rule[] getRules() { + String scriptStr = String.format(""" +() => { + try { + let checker = new window.ace_ibma.Checker(); + return Promise.resolve(JSON.stringify(checker.getRules())); + } catch (e) { + return Promise.reject(e); + } +} +"""); + String jsonGuidelines = this.driver.evaluate(scriptStr).toString(); + return gson.fromJson(jsonGuidelines, Rule[].class); + } + + @Override + public String getProfile() { + return "Selenium"; + } + + @Override + public String getHelp(String ruleId, String reasonId, String helpRoot) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getHelp'"); + } + + @Override + public String encodeURIComponent(String s) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'encodeURIComponent'"); + } +} diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerPlaywrightTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerPlaywrightTest.java new file mode 100644 index 000000000..4c462436d --- /dev/null +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerPlaywrightTest.java @@ -0,0 +1,223 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess; + +import org.junit.Test; +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Arrays; +import java.util.Map; +import java.util.List; +import java.util.HashSet; +import java.util.Set; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; + +import com.google.common.io.Files; +import com.google.gson.Gson; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; +import com.microsoft.playwright.*; + +public class AccessibilityCheckerPlaywrightTest { + public static class UnitTestInfoResult { + public String ruleId; + public String reasonId; + public String category; + public String message; + public String[] messageArgs; + public String[] value; + public Map path; + + public boolean matches(Result result) { + return ruleId.equals(result.ruleId) + && reasonId.equals(result.reasonId) + && category.equals(result.category) + && message.equals(result.message) + && value[1].equals(result.value[1]) + && path.get("dom").equals(result.path.get("dom")) + && path.get("aria").equals(result.path.get("aria")); + } + } + public static class UnitTestInfo { + public String[] ruleIds; + public UnitTestInfoResult[] results; + } + private static Page driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + try { + Playwright playwright = Playwright.create(); + Browser browser = playwright.chromium().launch(); + AccessibilityCheckerPlaywrightTest.driver = browser.newPage(); + } catch (Throwable err) { + System.err.println(err.toString()); + err.printStackTrace(); + } + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + AccessibilityCheckerPlaywrightTest.driver.close(); + AccessibilityChecker.close(); + } + + @Test public void getCompliance() { + ACConfigManager.getConfig().label = new String[] { "IBMa-Java-TeSt" }; + AccessibilityCheckerPlaywrightTest.driver.navigate("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceTest"); + assertNotNull(report); + assertTrue(report.results.length > 0); + } + + @Test public void baselines() throws IOException { + Paths.get("baselines", "Playwright_getComplianceTest3.json").toFile().delete(); + AccessibilityCheckerPlaywrightTest.driver.navigate("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceTest2"); + assertEquals(eAssertResult.FAIL, AccessibilityChecker.assertCompliance(report)); + new File("baselines").mkdirs(); + Files.copy(Paths.get("results", "Playwright_getComplianceTest2.json").toFile(), Paths.get("baselines", "Playwright_getComplianceTest3.json").toFile()); + + report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceTest3"); + assertEquals(eAssertResult.PASS, AccessibilityChecker.assertCompliance(report)); + Paths.get("baselines", "Playwright_getComplianceTest3.json").toFile().delete(); + } + + // @Test public void getComplianceLong() { + // AccessibilityCheckerTest.driver.navigate("https://openliberty.io/docs/latest/reference/javadoc/liberty-jakartaee8-javadoc.html?path=liberty-javaee8-javadoc/index-all.html"); + // ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_getComplianceLong"); + // assertNotNull(report); + // assertTrue(report.results.length > 0); + // } + + private void listFiles(File f, java.util.List retFiles) { + if (f.isFile() && f.exists() && (f.getName().endsWith("html") || f.getName().endsWith("htm"))) { + retFiles.add(f); + } else if (f.isDirectory()) { + for (File subF: f.listFiles((testFile, name) -> testFile.isDirectory() || name.endsWith(".htm") || name.endsWith(".html"))) { + listFiles(subF, retFiles); + } + } + + } + @Test public void getComplianceTestsuite() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "customRuleServer": true, + "rulePack": "https://localhost:9445/rules/archives/preview/js", + "ruleArchive": "preview", + "ignoreHTTPSErrors": true, + "policies": [ "IBM_Accessibility", "IBM_Accessibility_next"], + "failLevels": [ "violation", "potentialviolation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual", + "pass" + ], + "outputFormat": [ "json" ], + "label": [ + "IBMa-Java-TeSt" + ] +} +"""); + myWriter.close(); + ACConfigManager.getConfig(); + + Gson gson = new Gson(); + File testRootDir = Paths.get(System.getProperty("user.dir"), "..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); + ArrayList testFiles = new ArrayList<>(); + listFiles(testRootDir, testFiles); + + + // Skip test cases that don't work in this environment (e.g., can't disable meta refresh in chrome) + Set skipList = new HashSet<>(Arrays.asList(new File[] { + //not in karma conf file + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-hasTextEmbedded.html").toFile(), + // path.join(testRootDir, "a_text_purpose_ruleunit", "A-nonTabable.html"), + + // Meta refresh + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-invalidRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-validRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_redirect_optional_ruleunit", "Meta-RefreshZero.html").toFile(), + + // CSS test issues + Paths.get(testRootDir.getAbsolutePath(), "style_color_misuse_ruleunit","D543.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_before_after_review_ruleunit","D100.html").toFile(), + + // Misc + // path.join(testRootDir, "aria_banner_label_unique_ruleunit", "validLandMarks-testCaseFromAnn.html"), + })); + + for (File testFile: testFiles) { + if (skipList.contains(testFile)) continue; + AccessibilityCheckerPlaywrightTest.driver.navigate("file://"+testFile.getAbsolutePath()); + ACReport report = AccessibilityChecker.getCompliance(driver, "Playwright_"+testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); + String unitTestInfoStr = AccessibilityCheckerPlaywrightTest.driver.evaluate("() => JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); + if (!"false".equals(unitTestInfoStr)) { + UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); + List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); + if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { + System.out.println(testFile.getCanonicalPath()); + System.out.flush(); + List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); + List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); + for (int idxActual=0; idxActual 0); } @Test public void baselines() throws IOException { - Paths.get("baselines", "getComplianceTest3.json").toFile().delete(); - AccessibilityCheckerTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); - ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest2"); + Paths.get("baselines", "Selenium_getComplianceTest3.json").toFile().delete(); + AccessibilityCheckerSeleniumTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_getComplianceTest2"); assertEquals(eAssertResult.FAIL, AccessibilityChecker.assertCompliance(report)); new File("baselines").mkdirs(); - Files.copy(Paths.get("results", "getComplianceTest2.json").toFile(), Paths.get("baselines", "getComplianceTest3.json").toFile()); + Files.copy(Paths.get("results", "Selenium_getComplianceTest2.json").toFile(), Paths.get("baselines", "Selenium_getComplianceTest3.json").toFile()); - report = AccessibilityChecker.getCompliance(driver, "getComplianceTest3"); + report = AccessibilityChecker.getCompliance(driver, "Selenium_getComplianceTest3"); assertEquals(eAssertResult.PASS, AccessibilityChecker.assertCompliance(report)); - Paths.get("baselines", "getComplianceTest3.json").toFile().delete(); + Paths.get("baselines", "Selenium_getComplianceTest3.json").toFile().delete(); } // @Test public void getComplianceLong() { // AccessibilityCheckerTest.driver.get("https://openliberty.io/docs/latest/reference/javadoc/liberty-jakartaee8-javadoc.html?path=liberty-javaee8-javadoc/index-all.html"); - // ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceLong"); + // ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_getComplianceLong"); // assertNotNull(report); // assertTrue(report.results.length > 0); // } @@ -208,9 +208,9 @@ private void listFiles(File f, java.util.List retFiles) { for (File testFile: testFiles) { if (skipList.contains(testFile)) continue; - AccessibilityCheckerTest.driver.get("file://"+testFile.getAbsolutePath()); - ACReport report = AccessibilityChecker.getCompliance(driver, testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); - String unitTestInfoStr = AccessibilityCheckerTest.driver.executeScript("return JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); + AccessibilityCheckerSeleniumTest.driver.get("file://"+testFile.getAbsolutePath()); + ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_"+testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); + String unitTestInfoStr = AccessibilityCheckerSeleniumTest.driver.executeScript("return JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); if (!"false".equals(unitTestInfoStr)) { UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); From 80c6d79d1655d769cff6f61b293eec42aa2e05cf Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 22:17:16 -0500 Subject: [PATCH 67/73] Add Playwright support --- .../junit-playwright/.gitattributes | 12 + .../boilerplates/junit-playwright/.gitignore | 5 + .../gradle/libs.versions.toml | 12 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43504 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../boilerplates/junit-playwright/gradlew | 252 ++++++++++++++++++ .../boilerplates/junit-playwright/gradlew.bat | 94 +++++++ .../junit-playwright/lib/.gitignore | 1 + .../junit-playwright/lib/build.gradle | 39 +++ .../java/com/foo/SomeClassPlaywright.java | 23 ++ .../java/com/foo/SomeClassPlaywrightTest.java | 63 +++++ .../junit-playwright/settings.gradle | 14 + .../junit-selenium/lib/build.gradle | 2 +- ...{SomeClass.java => SomeClassSelenium.java} | 2 +- ...ssTest.java => SomeClassSeleniumTest.java} | 9 +- .../equalaccess/AccessibilityChecker.java | 4 +- 16 files changed, 532 insertions(+), 7 deletions(-) create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/.gitattributes create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/.gitignore create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/gradle/libs.versions.toml create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.jar create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.properties create mode 100755 java-accessibility-checker/boilerplates/junit-playwright/gradlew create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/gradlew.bat create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/lib/.gitignore create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/lib/src/main/java/com/foo/SomeClassPlaywright.java create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/lib/src/test/java/com/foo/SomeClassPlaywrightTest.java create mode 100644 java-accessibility-checker/boilerplates/junit-playwright/settings.gradle rename java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/{SomeClass.java => SomeClassSelenium.java} (96%) rename java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/{SomeClassTest.java => SomeClassSeleniumTest.java} (88%) diff --git a/java-accessibility-checker/boilerplates/junit-playwright/.gitattributes b/java-accessibility-checker/boilerplates/junit-playwright/.gitattributes new file mode 100644 index 000000000..f91f64602 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/.gitattributes @@ -0,0 +1,12 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + diff --git a/java-accessibility-checker/boilerplates/junit-playwright/.gitignore b/java-accessibility-checker/boilerplates/junit-playwright/.gitignore new file mode 100644 index 000000000..1b6985c00 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/.gitignore @@ -0,0 +1,5 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradle/libs.versions.toml b/java-accessibility-checker/boilerplates/junit-playwright/gradle/libs.versions.toml new file mode 100644 index 000000000..ab0036d1b --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradle/libs.versions.toml @@ -0,0 +1,12 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[versions] +commons-math3 = "3.6.1" +guava = "33.1.0-jre" +junit = "4.13.2" + +[libraries] +commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } +junit = { module = "junit:junit", version.ref = "junit" } diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.jar b/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2c3521197d7c4586c843d1d3e9090525f1898cde GIT binary patch literal 43504 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 TZiJi*F`$tkWLn) literal 0 HcmV?d00001 diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.properties b/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..09523c0e5 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradlew b/java-accessibility-checker/boilerplates/junit-playwright/gradlew new file mode 100755 index 000000000..f5feea6d6 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradlew @@ -0,0 +1,252 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/java-accessibility-checker/boilerplates/junit-playwright/gradlew.bat b/java-accessibility-checker/boilerplates/junit-playwright/gradlew.bat new file mode 100644 index 000000000..9d21a2183 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/.gitignore b/java-accessibility-checker/boilerplates/junit-playwright/lib/.gitignore new file mode 100644 index 000000000..872aa273a --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/.gitignore @@ -0,0 +1 @@ +results \ No newline at end of file diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle new file mode 100644 index 000000000..cb91ecf13 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle @@ -0,0 +1,39 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java library project to get you started. + * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.9/userguide/building_java_projects.html in the Gradle documentation. + */ + +plugins { + id 'java-library' +} + +group 'com.foo' +version '1.0.0' + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + // Use JUnit test framework. + testImplementation libs.junit + + implementation 'com.microsoft.playwright:playwright:1.46.0' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-3' +} + +// Apply a specific Java toolchain to ease working on different environments. +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +test { + testLogging { + showStandardStreams = true + } +} diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/src/main/java/com/foo/SomeClassPlaywright.java b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/main/java/com/foo/SomeClassPlaywright.java new file mode 100644 index 000000000..9183700fd --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/main/java/com/foo/SomeClassPlaywright.java @@ -0,0 +1,23 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.foo; + +public class SomeClassPlaywright { + + public boolean someFunction() { + return true; + } +} diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/src/test/java/com/foo/SomeClassPlaywrightTest.java b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/test/java/com/foo/SomeClassPlaywrightTest.java new file mode 100644 index 000000000..57e961a8c --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/src/test/java/com/foo/SomeClassPlaywrightTest.java @@ -0,0 +1,63 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.foo; + +import org.junit.Test; +import static org.junit.Assert.*; + +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import com.ibm.able.equalaccess.AccessibilityChecker; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; +import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; +import com.microsoft.playwright.*; + +public class SomeClassPlaywrightTest { + private static Page driver; + + /** + * Setup a Playwright Chromium environment before tests + */ + @BeforeClass public static void setup() { + try { + Playwright playwright = Playwright.create(); + Browser browser = playwright.chromium().launch(); + driver = browser.newPage(); + } catch (Throwable err) { + System.err.println(err.toString()); + err.printStackTrace(); + } + } + + /** + * Close Playwright environment after tests + */ + @AfterClass public static void teardown() { + SomeClassPlaywrightTest.driver.close(); + AccessibilityChecker.close(); + } + + @Test public void getCompliance() { + SomeClassPlaywrightTest.driver.navigate("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + + ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); + eAssertResult resultCode = AccessibilityChecker.assertCompliance(report); + // The page has compliance issues, so this assert should fail + assertEquals("Scan resulted in "+resultCode.toString(), eAssertResult.PASS, resultCode); + } +} diff --git a/java-accessibility-checker/boilerplates/junit-playwright/settings.gradle b/java-accessibility-checker/boilerplates/junit-playwright/settings.gradle new file mode 100644 index 000000000..7665fe699 --- /dev/null +++ b/java-accessibility-checker/boilerplates/junit-playwright/settings.gradle @@ -0,0 +1,14 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.9/userguide/multi_project_builds.html in the Gradle documentation. + */ + +plugins { + // Apply the foojay-resolver plugin to allow automatic download of JDKs + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + +rootProject.name = 'java-accessibility-checker-boilerplate-playwright' +include('lib') diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index b626fe4fe..a1674a246 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -23,7 +23,7 @@ dependencies { // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-2' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-3' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClass.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClassSelenium.java similarity index 96% rename from java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClass.java rename to java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClassSelenium.java index e6fae59ed..e509be553 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClass.java +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/main/java/com/foo/SomeClassSelenium.java @@ -15,7 +15,7 @@ *****************************************************************************/ package com.foo; -public class SomeClass { +public class SomeClassSelenium { public boolean someFunction() { return true; diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassSeleniumTest.java similarity index 88% rename from java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java rename to java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassSeleniumTest.java index e3b86591d..c2a02072c 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassTest.java +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/src/test/java/com/foo/SomeClassSeleniumTest.java @@ -29,7 +29,7 @@ import com.ibm.able.equalaccess.engine.ACReport.Result; import com.ibm.able.equalaccess.report.BaselineManager.eAssertResult; -public class SomeClassTest { +public class SomeClassSeleniumTest { private static ChromeDriver driver; /** @@ -47,7 +47,7 @@ public class SomeClassTest { System.setProperty("webdriver.chrome.driver", chromeDriverDir); options.addArguments("--headless=new"); try { - SomeClassTest.driver = new ChromeDriver(options); + SomeClassSeleniumTest.driver = new ChromeDriver(options); } catch (SessionNotCreatedException e) { System.out.println(e.getMessage()); System.out.println(e.getAdditionalInformation()); @@ -59,15 +59,16 @@ public class SomeClassTest { * Close Selenium Chrome environment after tests */ @AfterClass public static void teardown() { - SomeClassTest.driver.close(); + SomeClassSeleniumTest.driver.close(); AccessibilityChecker.close(); } @Test public void getCompliance() { - SomeClassTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + SomeClassSeleniumTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest"); eAssertResult resultCode = AccessibilityChecker.assertCompliance(report); + // The page has compliance issues, so this assert should fail assertEquals("Scan resulted in "+resultCode.toString(), eAssertResult.PASS, resultCode); } } diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java index b7c0f2ea4..a91bb545f 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java @@ -55,7 +55,9 @@ public static ConfigInternal getConfigUnsupported() { } /** - * Perform a scan of the provided context. Currently supported contexts: WebDriver. + * Perform a scan of the provided context. + * + * Currently supported content contexts: org.openqa.selenium.WebDriver, com.microsoft.playwright.Page. * @param content The content to scan. * @param label Provide a label for the scan that is being performed * @return Resulting report From 77a003dce566aaf663d90713dfdff00d13e50ada Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Thu, 5 Sep 2024 23:16:07 -0500 Subject: [PATCH 68/73] Starting javadoc --- .../equalaccess/AccessibilityChecker.java | 5 +- .../src/main/javadoc/overview.html | 257 ++++++++++++++++++ 2 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 java-accessibility-checker/src/main/javadoc/overview.html diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java index a91bb545f..3298c988e 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java @@ -35,6 +35,9 @@ import com.ibm.able.equalaccess.abs.IAbstractAPI; import com.ibm.able.equalaccess.abs.MyFS; +/** + * The main checker object. See the .jar overview for usage information. + */ public class AccessibilityChecker { private AccessibilityChecker() {} @@ -44,7 +47,7 @@ private AccessibilityChecker() {} /** * Get the processed configuration object - * @return + * @return Current configuration set for the checker */ public static Config getConfig() { return ACConfigManager.getConfig(); diff --git a/java-accessibility-checker/src/main/javadoc/overview.html b/java-accessibility-checker/src/main/javadoc/overview.html new file mode 100644 index 000000000..dca9b7135 --- /dev/null +++ b/java-accessibility-checker/src/main/javadoc/overview.html @@ -0,0 +1,257 @@ + + + + accessibility-checker overview + + + +
+

accessibility-checker

+
+
+

Overview

+
+

+ accessibility-checker is a Java module that + allows you to do the following: +

+
    +
  • + perform integrated accessibility testing within a + continuous integration pipeline, such as Travis CI +
  • +
  • + works with test frameworks (parsing engines), such as + Selenium and Playwright +
  • +
  • + aside from just performing accessibility scanning, it + provides a framework to validate accessibility scan + results against baseline files and/or simply failing the + test cases based on the levels of violations found + during the scan +
  • +
+

+ The Java module is a component of the + IBM Equal Access Toolkit. The Toolkit provides the tools and + guidance to create + experiences that are delightful for people of all abilities. + The guidance is organized by phase, such as Plan, Design, + Develop, and Verify, and explains how to integrate the + automated testing tools into the + Verify phase. The Toolkit is a major part + of the accessibility + information and applications at + ibm.com/able. +

+
+

Usage

+ +
+
+

Programmatic

+ +
+

+ The following is how to perform an accessibility scan within + your test cases and verify the scan results. See the AccessibilityChecker docs for details. +

+
+
+ACReport report = AccessibilityChecker.getCompliance(driver, "getComplianceTest");
+eAssertResult resultCode = AccessibilityChecker.assertCompliance(report);
+// The page has compliance issues, so this assert should fail
+assertEquals("Scan resulted in "+resultCode.toString(), eAssertResult.PASS, resultCode);            
+                
+
+

+ Note that it's critical to close the engine, otherwise, + output files for the report may not be generated properly. + If you execute batch scans, the engine should be closed + after all the scans are completed for better performance. + The following is a sample usage scenario: +

+ +
+
+AccessibilityChecker.close();
+                
+
+

+ Refer to + Examples + for sample usage scenarios. +

+
+

+ Quick Start and installation +

+ +
+

+ Grab a + boilerplate +

+ +
+

Prerequisites

+ +
+
    +
  1. Java 17
  2. +
  3. org.seleniumhq.selenium:selenium-java:4.23.0 or com.microsoft.playwright:playwright:1.46.0
  4. +
+
+

Configuration

+
+
+

+ Configuring accessibility-checker +

+ +
+

+ A default configuration is defined which uses the latest + archive, IBM_Accessibility policy, and some + default settings. If you would like to override any of these + values, create an accessibility-checker configuration file. +

+

+ Configuring accessibility-checker plugin + involves constructing a AccessibilityChecker.json file in + the project root, which will contain all the configuration + options for accessibility-checker. Following is + the structure of the AccessibilityChecker.json file: +

+
+
+{
+    // optional - Specify the rule archive
+    // Default: latest
+    // Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids.
+    // If "latest", will use the latest rule release
+    // If "versioned" (supported in 3.1.61+), will use the latest rule release at
+    // the time this version of the tool was released 
+    "ruleArchive": "versioned",
+
+    // optional - Specify one or many policies to scan.
+    // i.e. For one policy use policies: IBM_Accessibility
+    // i.e. Multiple policies: IBM_Accessibility, WCAG_2_1
+    // Run `npx achecker archives` for a list of valid ruleArchive ids and policy ids
+    "policies": ["IBM_Accessibility"],
+
+    // optional - Specify one or many violation levels on which to fail the test
+    //            i.e. If specified violation then the testcase will only fail if
+    //                 a violation is found during the scan.
+    // i.e. failLevels: violation
+    // i.e. failLevels: violation,potential violation or refer to below as a list
+    // Default: violation, potentialviolation
+    "failLevels": [ "violation", "potentialviolation" ],
+
+    // optional - Specify one or many violation levels that should be reported
+    //            i.e. If specified violation then in the report it would only contain
+    //                 results which are level of violation.
+    // i.e. reportLevels: violation
+    // Valid values: violation, potentialviolation, recommendation, potentialrecommendation, manual
+    // Default: violation, potentialviolation
+    "reportLevels": [ "violation", "potentialviolation",
+        "recommendation", "potentialrecommendation", "manual" ],
+
+    // Optional - In which formats should the results be output
+    // Valid values: json, csv, disable
+    // Default: json
+    "outputFormat": [ "json" ],
+
+    // Optional - Specify labels that you would like associated to your scan
+    // i.e.
+    //   label: Firefox,master,V12,Linux
+    //   label:
+    //       - Firefox
+    //       - master
+    //       - V12
+    //       - Linux
+    // Default: N/A
+    "label": [ "master" ],
+
+    // optional - Where the scan results should be saved.
+    // Default: results
+    "outputFolder": "results"
+
+    // Optional - Should the timestamp be included in the filename of the reports?
+    // Default: true
+    "outputFilenameTimestamp": true
+
+    // optional - Where the baseline results should be loaded from
+    // Default: baselines
+    "baselineFolder": "test/baselines"
+
+    // optional - Where the tool can read/write cached files (ace-node.js / archive.json)
+    // Default: `${os.tmpdir()}/accessibility-checker/`
+    "cacheFolder": "/tmp/accessibility-checker"
+}
+
+ +
+

+ Known issues and workarounds +

+ +
+
    +
  1. +

    + If your site has a + Content Security Policy, the engine + script may be prevented from loading. In the browser + console, you'll see something like: +

    +
    +

    + VM43:24 Refused to load the script ‘https://cdn.jsdelivr.net/npm/accessibility-checker-engine@3.1.42/ace.js’ + because it violates the following Content + Security Policy directive: +

    +
    +

    + If you would prefer not to add cdn.jsdelivr.net to + the CSP, you can add able.ibm.com instead via your + config file (e.g., ruleServer: "https://able.ibm.com/rules") +

    +
  2. +
+
+

Feedback and reporting bugs

+ +
+

+ If you think you've found a bug, have questions or + suggestions, open a + GitHub + Issue, tagged with java-accessibility-checker. +

+

+ If you are an IBM employee, feel free to ask questions in + the IBM internal Slack channel + #accessibility-at-ibm. +

+
+

License

+ +
+

+ IBM Equal Access Toolkit is released under the Apache-2.0 license +

+
+
+ + + \ No newline at end of file From 3ece6d8611df0f9e3065fa3151e89cbe7bd9bdf6 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 6 Sep 2024 10:01:33 -0500 Subject: [PATCH 69/73] Javadoc updates --- java-accessibility-checker/README-DEV.md | 5 + .../equalaccess/AccessibilityChecker.java | 67 ++++++------- .../ibm/able/equalaccess/engine/ACReport.java | 93 +++++++++---------- 3 files changed, 84 insertions(+), 81 deletions(-) diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index bcb3d15ce..31dff9860 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -14,6 +14,11 @@ mvn -s ./settings.xml clean deploy -Dgpg.passphrase=yourpassphrase Deployments show up on https://central.sonatype.com/publishing/deployments and then they can be Dropped or Published. Once Published, they cannot be Dropped. +Generate javadoc for local review (files in target/site/apidocs/) +``` +mvn javadoc:javadoc +``` + ## PGP Key Management Generate PGP key: diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java index 3298c988e..0b3475519 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java @@ -45,26 +45,15 @@ private AccessibilityChecker() {} private static IAbstractAPI myFS = new MyFS(); private static IEngineContext localEngine; + /** - * Get the processed configuration object - * @return Current configuration set for the checker + * Perform a scan of the provided context. + * + * Currently supported content contexts: org.openqa.selenium.WebDriver, com.microsoft.playwright.Page. + * @param content The page to scan. + * @param label Provide a label for the scan that is being performed + * @return Resulting report */ - public static Config getConfig() { - return ACConfigManager.getConfig(); - } - - public static ConfigInternal getConfigUnsupported() { - return ACConfigManager.getConfigUnsupported(); - } - - /** - * Perform a scan of the provided context. - * - * Currently supported content contexts: org.openqa.selenium.WebDriver, com.microsoft.playwright.Page. - * @param content The content to scan. - * @param label Provide a label for the scan that is being performed - * @return Resulting report - */ public static ACReport getCompliance(Object content, String label) { if (content == null) { System.err.println("aChecker: Unable to get compliance of null or undefined object"); @@ -85,6 +74,14 @@ public static ACReport getCompliance(Object content, String label) { return finalReport; } + /** + * Close the checker and ensure all summary reports are generated + */ + public static void close() { + ReporterManager.get().generateSummaries(); + } + + /** * Check the scan results against configured failLevels or against a previously set baseline. * @param report Report generated by getCompliance @@ -97,23 +94,31 @@ public static eAssertResult assertCompliance(ACReport report) { } /** - * Close the checker and ensure all summary reports are generated + * Get the processed configuration object + * @return Current configuration set for the checker */ - public static void close() { - ReporterManager.get().generateSummaries(); + public static Config getConfig() { + return ACConfigManager.getConfig(); } -// /** -// * This function is responsible for printing the scan results to console. -// * -// * @param {Object} results - Provide the results from the scan. -// * -// * @return {String} resultsString - String representation of the results/violations. -// */ -// export function stringifyResults(report: ICheckerReport) : string { -// return ReporterManager.stringifyResults(report) -// } + /** + * Get a processed configuration object that include properties used internally to the checker + * @return Current configuration set for the checker + */ + public static ConfigInternal getConfigUnsupported() { + return ACConfigManager.getConfigUnsupported(); + } + /** + * Provides a string representation of a report that can be output to console + * + * @param report Report from a getCompliance scan + * @return String representation of the results/violations. + */ + // public static String stringifyResults(ACReport report) { + // TODO: + // return ReporterManager.stringifyResults(report); + // } /** * This function is responsible for getting the diff results based on label for a scan that was already performed. diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java index b0da859fb..c5a69a6c4 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java @@ -34,6 +34,10 @@ import com.ibm.able.equalaccess.config.ConfigInternal; public class ACReport implements Cloneable { + + /** + * Summary of counts from the scan + */ public static class SummaryCounts implements Cloneable { public int violation = 0; public int potentialviolation = 0; @@ -67,6 +71,10 @@ public SummaryCounts(ACEReport.SummaryCounts rhs) { pass = rhs.pass; } } + + /** + * Scan summary information + */ public static class Summary implements Cloneable { public SummaryCounts counts = new SummaryCounts(); public long scanTime = 0; @@ -88,6 +96,10 @@ public Object clone() { return ret; } } + + /** + * An individual issue identified by a rule + */ public static class Result extends ACEReport.Result { /** Did this issue match a baseline */ public boolean ignored = false; @@ -111,32 +123,33 @@ public String toHelpData() { } public static Gson gsonMinimal = new GsonBuilder() - .registerTypeAdapter(Result.class, new JsonSerializer() { - @Override - public JsonElement serialize(Result issue, Type typeOfSrc, JsonSerializationContext context) { - JsonObject jObject = new JsonObject(); - jObject.addProperty("ruleId", issue.ruleId); - jObject.addProperty("reasonId", issue.reasonId); - jObject.addProperty("message", issue.message); - jObject.addProperty("snippet", issue.snippet); - JsonArray buildValue = new JsonArray(); - for (String s: issue.value) { - buildValue.add(s); - } - jObject.add("value", buildValue); - JsonArray buildMsgArgs = new JsonArray(); - for (String s : issue.messageArgs) { - buildMsgArgs.add(s); + .registerTypeAdapter(Result.class, new JsonSerializer() { + @Override + public JsonElement serialize(Result issue, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jObject = new JsonObject(); + jObject.addProperty("ruleId", issue.ruleId); + jObject.addProperty("reasonId", issue.reasonId); + jObject.addProperty("message", issue.message); + jObject.addProperty("snippet", issue.snippet); + JsonArray buildValue = new JsonArray(); + for (String s: issue.value) { + buildValue.add(s); + } + jObject.add("value", buildValue); + JsonArray buildMsgArgs = new JsonArray(); + for (String s : issue.messageArgs) { + buildMsgArgs.add(s); + } + jObject.add("msgArgs", buildMsgArgs); + return jObject; } - jObject.add("msgArgs", buildMsgArgs); - return jObject; - } - }) - .create(); + }) + .create(); } - /** List of items detected by the getCompliance scan */ + + /** Array of items detected by the getCompliance scan */ public Result[] results = new Result[0]; - /** Number of rules executed */ + /** Number of rules executed as part of the scan */ public int numExecuted = 0; /** Mapping of ruleId to reasonId to a parameterized message */ public Map> nls = new HashMap<>(); @@ -150,7 +163,7 @@ public JsonElement serialize(Result issue, Type typeOfSrc, JsonSerializationCont public String label = ""; /** base64 screenshot, if one was taken */ public String screenshot=null; - /** Amount of time in ms that rules were running */ + /** Amount of time in ms that was spent executing rule functions (as opposed to walking the tree) */ public int ruleTime = 0; public ACReport() {} @@ -169,33 +182,9 @@ public ACReport(ConfigInternal config, ACEReport engineReport, String label) { } /** - * Update the summary counts to match the included results + * Ignore: To be used by the ReporterManager + * @param summaryCounts */ - public void updateSummaryCounts() { - SummaryCounts counts = summary.counts; - counts.violation = 0; - counts.potentialviolation = 0; - counts.recommendation = 0; - counts.potentialrecommendation = 0; - counts.manual = 0; - counts.pass = 0; - for (Result issue: results) { - if (eRuleLevel.violation.equals(issue.level)) { - ++counts.violation; - } else if (eRuleLevel.potentialviolation.equals(issue.level)) { - ++counts.potentialviolation; - } else if (eRuleLevel.recommendation.equals(issue.level)) { - ++counts.recommendation; - } else if (eRuleLevel.potentialrecommendation.equals(issue.level)) { - ++counts.potentialrecommendation; - } else if (eRuleLevel.manual.equals(issue.level)) { - ++counts.manual; - } else if (eRuleLevel.pass.equals(issue.level)) { - ++counts.pass; - } - } - } - public void addCounts(ACEReport.SummaryCounts summaryCounts) { SummaryCounts counts = this.summary.counts = new SummaryCounts(summaryCounts); counts.ignored = 0; @@ -236,6 +225,10 @@ public void addCounts(ACEReport.SummaryCounts summaryCounts) { counts.elementsViolationReview = elementViolationReviewSet.size(); } + /** + * Filters the report using the specified reportLevels + * @param reportLevels + */ public void filter(String[] reportLevels) { Map> keepNlsKeys = new HashMap<>(); List reportLevelsList = Arrays.asList(reportLevels); From 3193a0d67fcdca97344a1d0e9a58577bba017e13 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 6 Sep 2024 10:17:34 -0500 Subject: [PATCH 70/73] Enable playwrite screenshots, and report.toString --- .../equalaccess/AccessibilityChecker.java | 11 -------- .../ibm/able/equalaccess/engine/ACReport.java | 27 +++++++++++++++++++ .../playwright/EngineContextPlaywright.java | 9 +++---- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java index 0b3475519..2cdefd2a7 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/AccessibilityChecker.java @@ -109,17 +109,6 @@ public static ConfigInternal getConfigUnsupported() { return ACConfigManager.getConfigUnsupported(); } - /** - * Provides a string representation of a report that can be output to console - * - * @param report Report from a getCompliance scan - * @return String representation of the results/violations. - */ - // public static String stringifyResults(ACReport report) { - // TODO: - // return ReporterManager.stringifyResults(report); - // } - /** * This function is responsible for getting the diff results based on label for a scan that was already performed. * diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java index c5a69a6c4..2066a06b4 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/engine/ACReport.java @@ -166,8 +166,11 @@ public JsonElement serialize(Result issue, Type typeOfSrc, JsonSerializationCont /** Amount of time in ms that was spent executing rule functions (as opposed to walking the tree) */ public int ruleTime = 0; + private ConfigInternal config; + public ACReport() {} public ACReport(ConfigInternal config, ACEReport engineReport, String label) { + this.config = config; numExecuted = engineReport.numExecuted; nls = engineReport.nls; screenshot = engineReport.screenshot; @@ -297,4 +300,28 @@ public Object clone() { } return ret; } + + public String toString() { + if (results == null) { + return "ERROR: results null"; + } + + StringBuilder resultsString = new StringBuilder(); + resultsString.append("Scan: "+label+"\n"); + List reportLevelsList = Arrays.asList(config.reportLevels); + + for (Result issue: results) { + if (reportLevelsList.contains(issue.level.toString())) { + // Build string of the issues with only level, messageCode, xpath and snippet. + resultsString.append("- Message: " + issue.message + + "\n Level: " + issue.level + + "\n XPath: " + issue.path.get("dom") + + "\n Snippet: " + issue.snippet + + "\n Help: " + issue.help + + "\n"); + } + } + + return resultsString.toString(); + } } diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java index d770e3a98..6d78554a8 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/playwright/EngineContextPlaywright.java @@ -231,12 +231,9 @@ else if (reportValue[1] === "POTENTIAL") { // } // If there is something to report... - if (report.results != null) { - if (config.captureScreenshots) { - // TODO: Screenshot? - // String image = ((TakesScreenshot)this.driver).getScreenshotAs(OutputType.BASE64); - // report.screenshot = image; - } + if (report.results != null && config.captureScreenshots) { + byte[] image = this.driver.screenshot(); + report.screenshot = new String(image); } return report; } catch (Error err) { From f706bd0a168d80efe87f477d989276ad0df77b49 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 6 Sep 2024 10:31:21 -0500 Subject: [PATCH 71/73] Add copyright statement to javadoc --- .../src/main/javadoc/overview.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/java-accessibility-checker/src/main/javadoc/overview.html b/java-accessibility-checker/src/main/javadoc/overview.html index dca9b7135..478934911 100644 --- a/java-accessibility-checker/src/main/javadoc/overview.html +++ b/java-accessibility-checker/src/main/javadoc/overview.html @@ -1,3 +1,18 @@ + From 5ca20e4a57d5537648a5062b8a59d171dea96a59 Mon Sep 17 00:00:00 2001 From: Tom Brunet Date: Fri, 6 Sep 2024 14:58:52 -0500 Subject: [PATCH 72/73] Fix for Firefox --- java-accessibility-checker/README-DEV.md | 5 + .../selenium/EngineContextSelenium.java | 12 +- .../AccessibilityCheckerSeleniumFFTest.java | 222 ++++++++++++++++++ 3 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java diff --git a/java-accessibility-checker/README-DEV.md b/java-accessibility-checker/README-DEV.md index 31dff9860..d1bcffc17 100644 --- a/java-accessibility-checker/README-DEV.md +++ b/java-accessibility-checker/README-DEV.md @@ -7,6 +7,11 @@ Run all tests: mvn test ``` +Run specific test +``` +mvn test -Dtest="TheSecondUnitTest#whenTestCase2_thenPrintTest2_1" +``` + Deploy ``` mvn -s ./settings.xml clean deploy -Dgpg.passphrase=yourpassphrase diff --git a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java index 02c9705a8..778c1fc5b 100644 --- a/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java +++ b/java-accessibility-checker/src/main/java/com/ibm/able/equalaccess/enginecontext/selenium/EngineContextSelenium.java @@ -78,7 +78,7 @@ public void loadEngine() { script.setAttribute('aChecker', 'ACE'); script.setAttribute('src', '%s/ace.js'); script.addEventListener('load', function() { - globalThis.ace_ibma = ace; + window.ace_ibma = globalThis.ace_ibma = ace; if ('undefined' !== typeof(ace)) { ace = ace_backup_in_ibma; } @@ -107,7 +107,7 @@ public void loadEngine() { } if ('undefined' === typeof (ace) || ace === null) { eval(%s) - globalThis.ace_ibma = ace; + window.ace_ibma = globalThis.ace_ibma = ace; if ('undefined' !== typeof(ace)) { ace = ace_backup_in_ibma; } @@ -188,7 +188,7 @@ else if (reportValue[1] === "POTENTIAL") { let policies = %s; let reportLevels = %s; - let checker = new window.ace_ibma.Checker(); + let checker = new (globalThis.ace_ibma || window.ace_ibma).Checker(); let customRulesets = []; customRulesets.forEach((rs) => checker.addRuleset(rs)); setTimeout(function() { @@ -223,7 +223,7 @@ else if (reportValue[1] === "POTENTIAL") { } // TODO: - // String getPolicies = "return new window.ace_ibma.Checker().rulesetIds;"; + // String getPolicies = "return new (globalThis.ace_ibma || window.ace_ibma).Checker().rulesetIds;"; // if (curPol != null && !checkPolicy) { // checkPolicy = true; // const valPolicies = ACEngineManager.customRulesets.map(rs => rs.id).concat(await browser.executeScript(getPolicies)); @@ -259,7 +259,7 @@ public Guideline[] getGuidelines() { String scriptStr = String.format(""" let cb = arguments[arguments.length - 1]; try { - let checker = new window.ace_ibma.Checker(); + let checker = new (globalThis.ace_ibma || window.ace_ibma).Checker(); let customRulesets = []; customRulesets.forEach((rs) => checker.addRuleset(rs)); cb(JSON.stringify(checker.getGuidelines())); @@ -276,7 +276,7 @@ public Rule[] getRules() { String scriptStr = String.format(""" let cb = arguments[arguments.length - 1]; try { - let checker = new window.ace_ibma.Checker(); + let checker = new (globalThis.ace_ibma || window.ace_ibma).Checker(); cb(JSON.stringify(checker.getRules())); } catch (e) { cb(e); diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java new file mode 100644 index 000000000..8be5234c2 --- /dev/null +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java @@ -0,0 +1,222 @@ +/****************************************************************************** + Copyright:: 2024- IBM, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + *****************************************************************************/ +package com.ibm.able.equalaccess; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.SessionNotCreatedException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxOptions; + +import com.google.gson.Gson; +import com.ibm.able.equalaccess.config.ACConfigManager; +import com.ibm.able.equalaccess.engine.ACReport; +import com.ibm.able.equalaccess.engine.ACReport.Result; + +public class AccessibilityCheckerSeleniumFFTest { + public static class UnitTestInfoResult { + public String ruleId; + public String reasonId; + public String category; + public String message; + public String[] messageArgs; + public String[] value; + public Map path; + + public boolean matches(Result result) { + return ruleId.equals(result.ruleId) + && reasonId.equals(result.reasonId) + && category.equals(result.category) + && message.equals(result.message) + && value[1].equals(result.value[1]) + && path.get("dom").equals(result.path.get("dom")) + && path.get("aria").equals(result.path.get("aria")); + } + } + public static class UnitTestInfo { + public String[] ruleIds; + public UnitTestInfoResult[] results; + } + private static WebDriver driver; + + /** + * Setup a Selenium Chrome environment before tests + */ + @BeforeClass public static void setup() { + // Make sure we're starting with a clean config + File configFile = new File("achecker.json"); + configFile.delete(); + ACConfigManager.resetConfig(); + + try { + // ClientConfig timeoutConfig = ClientConfig.defaultConfig().readTimeout(Duration.ofMinutes(60)); + FirefoxOptions options = new FirefoxOptions(); + driver = new FirefoxDriver(options); + } catch (SessionNotCreatedException e) { + System.out.println(e.getMessage()); + System.out.println(e.getAdditionalInformation()); + throw e; + } + } + + /** + * Close Selenium Chrome environment after tests + */ + @AfterClass public static void teardown() { + AccessibilityCheckerSeleniumFFTest.driver.close(); + AccessibilityChecker.close(); + } + + private void listFiles(File f, java.util.List retFiles) { + if (f.isFile() && f.exists() && (f.getName().endsWith("html") || f.getName().endsWith("htm"))) { + retFiles.add(f); + } else if (f.isDirectory()) { + for (File subF: f.listFiles((testFile, name) -> testFile.isDirectory() || name.endsWith(".htm") || name.endsWith(".html"))) { + listFiles(subF, retFiles); + } + } + + } + + @Test public void getCompliance() { + ACConfigManager.getConfig().label = new String[] { "IBMa-Java-TeSt" }; + AccessibilityCheckerSeleniumFFTest.driver.get("https://altoromutual.12mc9fdq8fib.us-south.codeengine.appdomain.cloud/"); + ACReport report = AccessibilityChecker.getCompliance(driver, "SeleniumFF_getComplianceTest"); + assertNotNull(report); + assertTrue(report.results.length > 0); + } + + public void getComplianceTestsuite() throws IOException { + ACConfigManager.resetConfig(); + File configFile = new File("achecker.json"); + try { + configFile.delete(); + FileWriter myWriter = new FileWriter("achecker.json"); + myWriter.write(""" +{ + "customRuleServer": true, + "rulePack": "https://localhost:9445/rules/archives/preview/js", + "ruleArchive": "preview", + "ignoreHTTPSErrors": true, + "policies": [ "IBM_Accessibility", "IBM_Accessibility_next"], + "failLevels": [ "violation", "potentialviolation" ], + "reportLevels": [ + "violation", + "potentialviolation", + "recommendation", + "potentialrecommendation", + "manual", + "pass" + ], + "outputFormat": [ "json" ], + "label": [ + "IBMa-Java-TeSt" + ] +} +"""); + myWriter.close(); + ACConfigManager.getConfig(); + + Gson gson = new Gson(); + File testRootDir = Paths.get(System.getProperty("user.dir"), "..","accessibility-checker-engine","test","v2","checker","accessibility","rules").toFile(); + ArrayList testFiles = new ArrayList<>(); + listFiles(testRootDir, testFiles); + + + // Skip test cases that don't work in this environment (e.g., can't disable meta refresh in chrome) + Set skipList = new HashSet<>(Arrays.asList(new File[] { + //not in karma conf file + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-hasTextEmbedded.html").toFile(), + // path.join(testRootDir, "a_text_purpose_ruleunit", "A-nonTabable.html"), + + // Meta refresh + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-invalidRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_refresh_delay_ruleunit", "Meta-validRefresh.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "meta_redirect_optional_ruleunit", "Meta-RefreshZero.html").toFile(), + + // CSS test issues + Paths.get(testRootDir.getAbsolutePath(), "style_color_misuse_ruleunit","D543.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_before_after_review_ruleunit","D100.html").toFile(), + + // Firefox + Paths.get(testRootDir.getAbsolutePath(), "aria_role_redundant_ruleunit", "Fail.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "style_focus_visible_ruleunit", "CSS-used.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "object_text_exists_ruleunit", "act_fail_3.html").toFile() + + // Misc + // path.join(testRootDir, "aria_banner_label_unique_ruleunit", "validLandMarks-testCaseFromAnn.html"), + })); + + for (File testFile: testFiles) { + if (testFile.getAbsolutePath().contains("aria_attribute_valid_ruleunit")) continue; + if (testFile.getAbsolutePath().contains("target_spacing_sufficient_ruleunit")) continue; + if (testFile.getAbsolutePath().contains("aria_role_valid_ruleunit")) continue; + if (testFile.getAbsolutePath().contains("element_scrollable_tabbable_ruleunit")) continue; + if (testFile.getAbsolutePath().contains("fieldset_label_valid_ruleunit")) continue; + if (testFile.getAbsolutePath().contains("a_text_purpose_ruleunit")) continue; + if (skipList.contains(testFile)) continue; + AccessibilityCheckerSeleniumFFTest.driver.get("file://"+testFile.getAbsolutePath()); + ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_"+testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); + String unitTestInfoStr = ((JavascriptExecutor)driver).executeScript("return JSON.stringify((typeof (window.UnitTest) !== 'undefined' && window.UnitTest))").toString(); + if (!"false".equals(unitTestInfoStr)) { + UnitTestInfo expectedInfo = gson.fromJson(unitTestInfoStr, UnitTestInfo.class); + List coveredRuleIds = Arrays.asList(expectedInfo.ruleIds); + if (expectedInfo != null && expectedInfo.ruleIds != null && expectedInfo.ruleIds.length > 0) { + System.out.println(testFile.getCanonicalPath()); + System.out.flush(); + List actualIssues = new LinkedList<>(Arrays.stream(report.results).filter(actualIssue -> coveredRuleIds.contains(actualIssue.ruleId)).toList()); + List expectedIssues = new LinkedList<>(Arrays.asList(expectedInfo.results)); + for (int idxActual=0; idxActual Date: Fri, 6 Sep 2024 15:25:29 -0500 Subject: [PATCH 73/73] Fixes for Firefox --- .../junit-playwright/lib/build.gradle | 2 +- .../junit-selenium/lib/build.gradle | 2 +- .../AccessibilityCheckerSeleniumFFTest.java | 36 +++++++++++++++---- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle index cb91ecf13..18de9eba5 100644 --- a/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-playwright/lib/build.gradle @@ -22,7 +22,7 @@ dependencies { testImplementation libs.junit implementation 'com.microsoft.playwright:playwright:1.46.0' - implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-3' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-4' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle index a1674a246..53f9c854c 100644 --- a/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle +++ b/java-accessibility-checker/boilerplates/junit-selenium/lib/build.gradle @@ -23,7 +23,7 @@ dependencies { // https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java implementation 'org.seleniumhq.selenium:selenium-java:4.23.0' - implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-3' + implementation 'com.ibm.able:accessibility-checker:1.0.0-beta-4' } // Apply a specific Java toolchain to ease working on different environments. diff --git a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java index 8be5234c2..fabeacc68 100644 --- a/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java +++ b/java-accessibility-checker/src/test/java/com/ibm/able/equalaccess/AccessibilityCheckerSeleniumFFTest.java @@ -173,19 +173,38 @@ public void getComplianceTestsuite() throws IOException { // Firefox Paths.get(testRootDir.getAbsolutePath(), "aria_role_redundant_ruleunit", "Fail.html").toFile(), Paths.get(testRootDir.getAbsolutePath(), "style_focus_visible_ruleunit", "CSS-used.html").toFile(), - Paths.get(testRootDir.getAbsolutePath(), "object_text_exists_ruleunit", "act_fail_3.html").toFile() + Paths.get(testRootDir.getAbsolutePath(), "object_text_exists_ruleunit", "act_fail_3.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_conflict_ruleunit", "aria-hidden.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecified.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecifiedValidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InvalidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InValidRoleInvalidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InValidRoleSpecified.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecifiedInvalidAttribute.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "ValidRoleSpecifiedMultiple.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "InValidRoleSpecifiedMultiple.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "area_element_test.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_attribute_valid_ruleunit", "elementsWithSupportingAttributes.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_role_valid_ruleunit", "area_no_href.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "element_scrollable_tabbable_ruleunit", "act_fail2.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "element_scrollable_tabbable_ruleunit", "textarea_pass2.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "element_scrollable_tabbable_ruleunit", "act_fail1.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "fieldset_label_valid_ruleunit", "FieldSet-hasarialabel.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "fieldset_label_valid_ruleunit", "FieldSet-nested.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "fieldset_label_valid_ruleunit", "test_mixed_1.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-nonTabable.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-slot-text-error2.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "a_text_purpose_ruleunit", "A-slot-text-error1.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "target_spacing_sufficient_ruleunit", "link_in_text.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "target_spacing_sufficient_ruleunit", "block_element_inline.html").toFile(), + Paths.get(testRootDir.getAbsolutePath(), "aria_landmark_name_unique_ruleunit", "example_0_fail.html").toFile() // Misc // path.join(testRootDir, "aria_banner_label_unique_ruleunit", "validLandMarks-testCaseFromAnn.html"), })); for (File testFile: testFiles) { - if (testFile.getAbsolutePath().contains("aria_attribute_valid_ruleunit")) continue; - if (testFile.getAbsolutePath().contains("target_spacing_sufficient_ruleunit")) continue; - if (testFile.getAbsolutePath().contains("aria_role_valid_ruleunit")) continue; - if (testFile.getAbsolutePath().contains("element_scrollable_tabbable_ruleunit")) continue; - if (testFile.getAbsolutePath().contains("fieldset_label_valid_ruleunit")) continue; - if (testFile.getAbsolutePath().contains("a_text_purpose_ruleunit")) continue; if (skipList.contains(testFile)) continue; AccessibilityCheckerSeleniumFFTest.driver.get("file://"+testFile.getAbsolutePath()); ACReport report = AccessibilityChecker.getCompliance(driver, "Selenium_"+testFile.getAbsolutePath().substring(testRootDir.getAbsolutePath().length())); @@ -208,6 +227,9 @@ public void getComplianceTestsuite() throws IOException { } } } + // if (actualIssues.size() != 0 || expectedIssues.size () != 0) { + // System.err.println("XXXX: "+testFile.toString()); + // } assertEquals(testFile.toString()+": Issue triggered was not expected", 0, actualIssues.size()); assertEquals(testFile.toString()+": Expected issue was not triggered ("+testFile.getAbsolutePath()+")\n---\n"+gson.toJson(report.results)+"\n---\n"+gson.toJson(expectedIssues)+"\n"+testFile.toString(), 0, expectedIssues.size()); }