org.asqatasun.rules.rgaa30.Rgaa30Rule010306.java Source code

Java tutorial

Introduction

Here is the source code for org.asqatasun.rules.rgaa30.Rgaa30Rule010306.java

Source

/*
 * Asqatasun - Automated webpage assessment
 * Copyright (C) 2008-2015  Asqatasun.org
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contact us by mail: asqatasun AT asqatasun DOT org
 */
package org.asqatasun.rules.rgaa30;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.jsoup.nodes.Element;
import static org.asqatasun.entity.audit.TestSolution.FAILED;
import static org.asqatasun.entity.audit.TestSolution.NEED_MORE_INFO;
import static org.asqatasun.entity.audit.TestSolution.NOT_APPLICABLE;
import static org.asqatasun.entity.audit.TestSolution.PASSED;
import org.asqatasun.processor.SSPHandler;
import org.asqatasun.ruleimplementation.AbstractMarkerPageRuleImplementation;
import org.asqatasun.ruleimplementation.ElementHandler;
import org.asqatasun.ruleimplementation.ElementHandlerImpl;
import org.asqatasun.ruleimplementation.TestSolutionHandler;
import org.asqatasun.rules.elementchecker.ElementChecker;
import org.asqatasun.rules.elementchecker.element.ElementPresenceChecker;
import org.asqatasun.rules.elementselector.SimpleElementSelector;
import static org.asqatasun.rules.keystore.AttributeStore.ARIA_LABEL_ATTR;
import static org.asqatasun.rules.keystore.AttributeStore.ROLE_ATTR;
import static org.asqatasun.rules.keystore.AttributeStore.TITLE_ATTR;
import static org.asqatasun.rules.keystore.CssLikeQueryStore.SVG_NOT_IN_LINK_CSS_LIKE_QUERY;
import static org.asqatasun.rules.keystore.HtmlElementStore.DESC_ELEMENT;
import static org.asqatasun.rules.keystore.MarkerStore.DECORATIVE_IMAGE_MARKER;
import static org.asqatasun.rules.keystore.MarkerStore.INFORMATIVE_IMAGE_MARKER;
import static org.asqatasun.rules.keystore.RemarkMessageStore.CHECK_ALT_PERTINENCE_OF_INFORMATIVE_SVG_MSG;
import static org.asqatasun.rules.keystore.RemarkMessageStore.CHECK_NATURE_OF_SVG_AND_ALT_PERTINENCE_MSG;
import static org.asqatasun.rules.keystore.RemarkMessageStore.CHECK_NATURE_OF_SVG_WITH_NOT_PERTINENT_ALT_MSG;
import static org.asqatasun.rules.keystore.RemarkMessageStore.INFORMATIVE_SVG_WITH_NOT_PERTINENT_ALT_MSG;
import static org.asqatasun.rules.keystore.RemarkMessageStore.SVG_WITHOUT_ROLE_IMAGE_MSG;

/**
 * Implementation of the rule 1.3.6 of the referential Rgaa 3.0.
 *
 * For more details about the implementation, refer to <a href="http://doc.asqatasun.org/en/90_Rules/rgaa3.0/01.Images/Rule-1-3-6.html">the rule 1.3.6 design page.</a>
 * @see <a href="http://references.modernisation.gouv.fr/referentiel-technique-0#test-1-3-6"> 1.3.6 rule specification</a>
 */

public class Rgaa30Rule010306 extends AbstractMarkerPageRuleImplementation {

    /**
     * Contains all the informative SVG elements without the "img" role
     */
    private final ElementHandler<Element> ariaRoleMissingOnInformativeSvg = new ElementHandlerImpl();

    /*
     * Contains all the  SVG elements without the "img" role.
     */
    private final ElementHandler<Element> ariaRoleMissingOnSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements identifed as informative with an empty
     * aria-label
     */
    private final ElementHandler<Element> emptyAriaLabelOnInformativeSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements not identifed as informative with an empty
     * aria-label
     */
    private final ElementHandler<Element> emptyAriaLabelOnSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements identifed as informative with an empty
     * child desc tag
     */
    private final ElementHandler<Element> emptyChildDescOnInformativeSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements not identifed as informative with an empty
     * child desc tag
     */
    private final ElementHandler<Element> emptyChildDescOnSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements identifed as informative with an
     * aria-label different from the label attribute
     */
    private final ElementHandler<Element> ariaLabelDifferentFromTitleOnInformativeSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements not identifed as informative with an 
     * aria-label different from the label attribute
     */
    private final ElementHandler<Element> ariaLabelDifferentFromTitleOnSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements identifed as informative with a
     * child desc tag different from the label attribute
     */
    private final ElementHandler<Element> childDescDifferentFromTitleOnInformativeSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements not identifed as informative with a
     * child desc tag different from the label attribute
     */
    private final ElementHandler<Element> childDescDifferentFromTitleOnSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements identifed as informative with a
     * a correct markup. Pertinence needs then a human check 
     */
    private final ElementHandler<Element> markupOkOnInformativeSvg = new ElementHandlerImpl();

    /*
     * Contains all the SVG elements not identifed as informative with a
     * a correct markup. Pertinence needs then a human check 
     */
    private final ElementHandler<Element> markupOkOnSvg = new ElementHandlerImpl();

    /**
     * Default constructor
     */
    public Rgaa30Rule010306() {
        super(INFORMATIVE_IMAGE_MARKER, DECORATIVE_IMAGE_MARKER);
        setElementSelector(new SimpleElementSelector(SVG_NOT_IN_LINK_CSS_LIKE_QUERY));
    }

    @Override
    protected void select(SSPHandler sspHandler) {
        super.select(sspHandler);

        extractBadConditionPatterns(getSelectionWithMarkerHandler(), // all svg identified as decorative by marker
                ariaRoleMissingOnInformativeSvg, emptyAriaLabelOnInformativeSvg,
                ariaLabelDifferentFromTitleOnInformativeSvg, emptyChildDescOnInformativeSvg,
                childDescDifferentFromTitleOnInformativeSvg, markupOkOnInformativeSvg);

        extractBadConditionPatterns(getSelectionWithoutMarkerHandler(), // all svg that are neither decorative, nor informative by marker
                ariaRoleMissingOnSvg, emptyAriaLabelOnSvg, ariaLabelDifferentFromTitleOnSvg, emptyChildDescOnSvg,
                childDescDifferentFromTitleOnSvg, markupOkOnSvg);
    }

    /**
     * 
     * @param svgElements
     * @param ariaRoleMissingOnSvg
     * @param emptyAriaLabelAttrOnSvg
     * @param ariaLabelDifferentFromTitleAttrOnSvg
     * @param emptyChildDescOnSvg
     * @param childDescDifferentFromTitleAttrOnSvg
     * @param wellFormedSvgElements 
     */
    private void extractBadConditionPatterns(ElementHandler<Element> svgElements,
            ElementHandler<Element> ariaRoleMissingOnSvg, ElementHandler<Element> emptyAriaLabelAttrOnSvg,
            ElementHandler<Element> ariaLabelDifferentFromTitleAttrOnSvg,
            ElementHandler<Element> emptyChildDescOnSvg,
            ElementHandler<Element> childDescDifferentFromTitleAttrOnSvg,
            ElementHandler<Element> wellFormedSvgElements) {
        for (Element element : svgElements.get()) {
            boolean patternDetected = false;
            if (!isRoleImagePresent(element)) {
                ariaRoleMissingOnSvg.add(element);
                patternDetected = true;
            }
            if (isAriaLabelExistsAndEmpty(element)) {
                emptyAriaLabelAttrOnSvg.add(element);
                patternDetected = true;
            }
            if (isAriaLabelExistsAndNotEmpty(element) && isTitleExistsAndNotEmpty(element)
                    && !StringUtils.equalsIgnoreCase(getAriaLabelAttrText(element), getTitleAttrText(element))) {
                ariaLabelDifferentFromTitleAttrOnSvg.add(element);
                patternDetected = true;
            }
            if (isChildDescExistsAndEmpty(element)) {
                emptyChildDescOnSvg.add(element);
                patternDetected = true;
            }
            if (isChildDescExistsAndNotEmpty(element) && isTitleExistsAndNotEmpty(element)
                    && !StringUtils.equalsIgnoreCase(getDescText(element), getTitleAttrText(element))) {
                childDescDifferentFromTitleAttrOnSvg.add(element);
                patternDetected = true;
            }
            if (!patternDetected) {
                wellFormedSvgElements.add(element);
            }
        }
    }

    @Override
    protected void check(SSPHandler sspHandler, TestSolutionHandler testSolutionHandler) {
        if (getSelectionWithMarkerHandler().isEmpty() && getSelectionWithoutMarkerHandler().isEmpty()) {
            testSolutionHandler.addTestSolution(NOT_APPLICABLE);
            return;
        }

        ElementChecker ec = new ElementPresenceChecker(new ImmutablePair(FAILED, SVG_WITHOUT_ROLE_IMAGE_MSG),
                new ImmutablePair(PASSED, ""));

        if (!ariaRoleMissingOnInformativeSvg.isEmpty()) {
            // result is failed for sure
            ec.check(sspHandler, ariaRoleMissingOnInformativeSvg, testSolutionHandler);
        }

        if (!ariaRoleMissingOnSvg.isEmpty()) {
            // result is failed for sure
            ec.check(sspHandler, ariaRoleMissingOnSvg, testSolutionHandler);
        }

        ec = new ElementPresenceChecker(
                new ImmutablePair(NEED_MORE_INFO, INFORMATIVE_SVG_WITH_NOT_PERTINENT_ALT_MSG),
                new ImmutablePair(NOT_APPLICABLE, ""), ROLE_ATTR, ARIA_LABEL_ATTR, TITLE_ATTR);

        if (!emptyAriaLabelOnInformativeSvg.isEmpty()) {
            ec.check(sspHandler, emptyAriaLabelOnInformativeSvg, testSolutionHandler);
        }
        if (!ariaLabelDifferentFromTitleOnInformativeSvg.isEmpty()) {
            ec.check(sspHandler, ariaLabelDifferentFromTitleOnInformativeSvg, testSolutionHandler);
        }
        if (!emptyChildDescOnInformativeSvg.isEmpty()) {
            ec.check(sspHandler, emptyChildDescOnInformativeSvg, testSolutionHandler);
        }
        if (!childDescDifferentFromTitleOnInformativeSvg.isEmpty()) {
            ec.check(sspHandler, childDescDifferentFromTitleOnInformativeSvg, testSolutionHandler);
        }

        ec = new ElementPresenceChecker(
                new ImmutablePair(NEED_MORE_INFO, CHECK_NATURE_OF_SVG_WITH_NOT_PERTINENT_ALT_MSG),
                new ImmutablePair(NOT_APPLICABLE, ""), ROLE_ATTR, ARIA_LABEL_ATTR, TITLE_ATTR);

        if (!emptyAriaLabelOnSvg.isEmpty()) {
            ec.check(sspHandler, emptyAriaLabelOnSvg, testSolutionHandler);
        }
        if (!ariaLabelDifferentFromTitleOnSvg.isEmpty()) {
            ec.check(sspHandler, ariaLabelDifferentFromTitleOnSvg, testSolutionHandler);
        }
        if (!emptyChildDescOnSvg.isEmpty()) {
            ec.check(sspHandler, emptyChildDescOnSvg, testSolutionHandler);
        }
        if (!childDescDifferentFromTitleOnSvg.isEmpty()) {
            ec.check(sspHandler, childDescDifferentFromTitleOnSvg, testSolutionHandler);
        }

        ec = new ElementPresenceChecker(
                new ImmutablePair(NEED_MORE_INFO, CHECK_ALT_PERTINENCE_OF_INFORMATIVE_SVG_MSG),
                new ImmutablePair(NOT_APPLICABLE, ""), ROLE_ATTR, ARIA_LABEL_ATTR, TITLE_ATTR);
        if (!markupOkOnInformativeSvg.isEmpty()) {
            ec.check(sspHandler, markupOkOnInformativeSvg, testSolutionHandler);
        }

        ec = new ElementPresenceChecker(
                new ImmutablePair(NEED_MORE_INFO, CHECK_NATURE_OF_SVG_AND_ALT_PERTINENCE_MSG),
                new ImmutablePair(NOT_APPLICABLE, ""), ROLE_ATTR, ARIA_LABEL_ATTR, TITLE_ATTR);
        if (!markupOkOnSvg.isEmpty()) {
            ec.check(sspHandler, markupOkOnSvg, testSolutionHandler);
        }
    }

    /**
     * 
     * @param element
     * @return whether the aria label exists and is empty
     */
    private boolean isRoleImagePresent(Element element) {
        return element.hasAttr(ROLE_ATTR) && StringUtils.equalsIgnoreCase("img", element.attr(ROLE_ATTR));
    }

    /**
     * 
     * @param element
     * @return whether the aria label exists and is empty
     */
    private boolean isAriaLabelExistsAndEmpty(Element element) {
        return element.hasAttr(ARIA_LABEL_ATTR) && StringUtils.isEmpty(getAriaLabelAttrText(element));
    }

    /**
     * 
     * @param element
     * @return whether the aria label exists and is not empty
     */
    private boolean isAriaLabelExistsAndNotEmpty(Element element) {
        return element.hasAttr(ARIA_LABEL_ATTR) && StringUtils.isNotEmpty(getAriaLabelAttrText(element));
    }

    /**
     * 
     * @param element
     * @return whether the aria label and the title are present, not empty 
     * and identical
     */
    private boolean isTitleExistsAndNotEmpty(Element element) {
        return element.hasAttr(TITLE_ATTR) && StringUtils.isNotEmpty(getTitleAttrText(element));
    }

    /**
     * 
     * @param element
     * @return whether the aria label and the title are present, not empty 
     * and identical
     */
    private boolean isChildDescExists(Element element) {
        return !element.select(DESC_ELEMENT).isEmpty();
    }

    /**
     * 
     * @param element
     * @return whether the child desc tag is present and empty
     */
    private boolean isChildDescExistsAndEmpty(Element element) {
        if (!isChildDescExists(element)) {
            return false;
        }
        return StringUtils.isEmpty(getDescText(element));
    }

    /**
     * 
     * @param element
     * @return whether the child desc tag is present and not empty
     */
    private boolean isChildDescExistsAndNotEmpty(Element element) {
        if (!isChildDescExists(element)) {
            return false;
        }
        return StringUtils.isNotEmpty(getDescText(element));
    }

    /**
     * 
     * @param element
     * @return the textual content of the desc tag
     */
    private String getDescText(Element element) {
        return element.select(DESC_ELEMENT).first().text();
    }

    /**
     * 
     * @param element
     * @return the textual content of the aria-label attribute
     */
    private String getAriaLabelAttrText(Element element) {
        return element.attr(ARIA_LABEL_ATTR);
    }

    /**
     * 
     * @param element
     * @return the textual content of the title attribute
     */
    private String getTitleAttrText(Element element) {
        return element.attr(TITLE_ATTR);
    }
}