<commit_before>package nl.hsac.fitnesse.fixture.util;

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Helper to work with Selenium.
 */
public class SeleniumHelper {

    private static WebDriver WEB_DRIVER = null;
    private static boolean SHUTDOWN_HOOK_ENABLED = false;

    private static WebDriver getWebDriver() {
        if(WEB_DRIVER == null) {
            if(!SHUTDOWN_HOOK_ENABLED) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    public void run() {
                        closeInstance();
                    }
                });
                SHUTDOWN_HOOK_ENABLED = true;
            }
            WEB_DRIVER = new FirefoxDriver();
        }

        return WEB_DRIVER;
    }

    private static void closeInstance() {
        if(WEB_DRIVER != null) {
            WEB_DRIVER.quit();
            WEB_DRIVER = null;
        }
    }

    /**
     * Shuts down selenium web driver.
     */
    public void close() {
        closeInstance();
    }

    /**
     * @return current page title.
     */
    public String getPageTitle() {
        return driver().getTitle();
    }

    /**
     * @return Selenium's navigation.
     */
    public WebDriver.Navigation navigate() {
        return driver().navigate();
    }

    /**
     * Finds element, by searching in multiple locations.
     * @param place identifier for element.
     * @return first element found, null if none could be found.
     */
    public WebElement getElement(String place) {
        WebElement element = null;
        if (element == null) {
            element = getElementByLabel(place);
        }
        if (element == null) {
            element = findElement(byXpath("//input[@value='%s']", place));
        }
        if (element == null) {
            element = findElement(By.linkText(place));
        }
        if (element == null) {
            element = findElement(By.name(place));
        }
        if (element == null) {
            element = findElement(By.id(place));
        }
        if (element == null) {
            element = getElementByPartialLabel(place);
        }
        if (element == null) {
            element = findElement(byXpath("//input[contains(@value, '%s')]", place));
        }
        if (element == null) {
            element = findElement(By.partialLinkText(place));
        }
        return element;
    }

    private WebElement getElementByLabel(String labelText) {
        return getElementByLabel(labelText, "//label[text()='%s']", "//*[@aria-label='%s']");
    }

    private WebElement getElementByPartialLabel(String labelText) {
        return getElementByLabel(labelText, "//label[contains(text(), '%s')]", "//*[contains(@aria-label, '%s')]");
    }

    private WebElement getElementByLabel(String labelText, String firstXPath, String secondXPath) {
        WebElement element = null;
        WebElement label = findElement(byXpath(firstXPath, labelText));
        if (label != null) {
            String forAttr = label.getAttribute("for");
            element = findElement(By.id(forAttr));
        }
        if (element == null) {
            element = findElement(byXpath(secondXPath, labelText));
        }
        return element;
    }

    /**
     * Sets value of hidden input field.
     * @param idOrName id or name of input field to set.
     * @param value value to set.
     * @return whether input field was found.
     */
    public boolean setHiddenInputValue(String idOrName, String value) {
        WebElement element = findElement(By.id(idOrName));
        if (element != null) {
            executeJavascript("document.getElementById('%s').value='%s'", idOrName, value);
        }
        if (element == null) {
            element = findElement(By.name(idOrName));
            if (element != null) {
                executeJavascript("document.getElementsByName('%s')[0].value='%s'", idOrName, value);
            }
        }
        return element != null;
    }

    /**
     * Executes Javascript in browser.
     * @param statementPattern javascript to run, possibly with placeholders to be replaced.
     * @param parameters placeholder values that should be replaced before executing the script.
     */
    public void executeJavascript(String statementPattern, Object... parameters) {
        String script = String.format(statementPattern, parameters);
        JavascriptExecutor jse = (JavascriptExecutor) driver();
        jse.executeScript(script);
    }

    /**
     * Creates By based on xPath, supporting placeholder replacement.
     * @param pattern basic XPATH, possibly with placeholders.
     * @param parameters values for placeholders.
     * @return ByXPath.
     */
    public By byXpath(String pattern, String... parameters) {
        Object[] escapedParams = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            escapedParams[i] = xpathEscape(parameters[i]);
        }
        String xpath = String.format(pattern, escapedParams);
        return By.xpath(xpath);
    }

    private String xpathEscape(String value) {
        return value.replace("\"", "&quot;")
                    .replace("'", "&apos;");
    }

    /**
     * Sets how long to wait before deciding an element does not exists.
     * @param implicitWait time in milliseconds to wait.
     */
    public void setImplicitlyWait(int implicitWait) {
        driver().manage().timeouts().implicitlyWait(implicitWait, TimeUnit.MILLISECONDS);
    }

    /**
     * Finds first element matching the By supplied.
     * @param by criteria.
     * @return element if found, null if none could be found.
     */
    public WebElement findElement(By by) {
        return findElement(false, by);
    }

    /**
     * Finds element matching the By supplied.
     * @param atMostOne true indicates multiple matching elements should trigger an exception
     * @param by criteria.
     * @return element if found, null if none could be found.
     * @throws RuntimeException if atMostOne is true and multiple elements match by.
     */
    public WebElement findElement(boolean atMostOne, By by) {
        return findElement(driver(), atMostOne, by);<commit_msg>Use proper XML escaping<commit_after>package nl.hsac.fitnesse.fixture.util;

import org.apache.commons.lang3.StringEscapeUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Helper to work with Selenium.
 */
public class SeleniumHelper {

    private static WebDriver WEB_DRIVER = null;
    private static boolean SHUTDOWN_HOOK_ENABLED = false;

    private static WebDriver getWebDriver() {
        if(WEB_DRIVER == null) {
            if(!SHUTDOWN_HOOK_ENABLED) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    public void run() {
                        closeInstance();
                    }
                });
                SHUTDOWN_HOOK_ENABLED = true;
            }
            WEB_DRIVER = new FirefoxDriver();
        }

        return WEB_DRIVER;
    }

    private static void closeInstance() {
        if(WEB_DRIVER != null) {
            WEB_DRIVER.quit();
            WEB_DRIVER = null;
        }
    }

    /**
     * Shuts down selenium web driver.
     */
    public void close() {
        closeInstance();
    }

    /**
     * @return current page title.
     */
    public String getPageTitle() {
        return driver().getTitle();
    }

    /**
     * @return Selenium's navigation.
     */
    public WebDriver.Navigation navigate() {
        return driver().navigate();
    }

    /**
     * Finds element, by searching in multiple locations.
     * @param place identifier for element.
     * @return first element found, null if none could be found.
     */
    public WebElement getElement(String place) {
        WebElement element = null;
        if (element == null) {
            element = getElementByLabel(place);
        }
        if (element == null) {
            element = findElement(byXpath("//input[@value='%s']", place));
        }
        if (element == null) {
            element = findElement(By.linkText(place));
        }
        if (element == null) {
            element = findElement(By.name(place));
        }
        if (element == null) {
            element = findElement(By.id(place));
        }
        if (element == null) {
            element = getElementByPartialLabel(place);
        }
        if (element == null) {
            element = findElement(byXpath("//input[contains(@value, '%s')]", place));
        }
        if (element == null) {
            element = findElement(By.partialLinkText(place));
        }
        return element;
    }

    private WebElement getElementByLabel(String labelText) {
        return getElementByLabel(labelText, "//label[text()='%s']", "//*[@aria-label='%s']");
    }

    private WebElement getElementByPartialLabel(String labelText) {
        return getElementByLabel(labelText, "//label[contains(text(), '%s')]", "//*[contains(@aria-label, '%s')]");
    }

    private WebElement getElementByLabel(String labelText, String firstXPath, String secondXPath) {
        WebElement element = null;
        WebElement label = findElement(byXpath(firstXPath, labelText));
        if (label != null) {
            String forAttr = label.getAttribute("for");
            element = findElement(By.id(forAttr));
        }
        if (element == null) {
            element = findElement(byXpath(secondXPath, labelText));
        }
        return element;
    }

    /**
     * Sets value of hidden input field.
     * @param idOrName id or name of input field to set.
     * @param value value to set.
     * @return whether input field was found.
     */
    public boolean setHiddenInputValue(String idOrName, String value) {
        WebElement element = findElement(By.id(idOrName));
        if (element != null) {
            executeJavascript("document.getElementById('%s').value='%s'", idOrName, value);
        }
        if (element == null) {
            element = findElement(By.name(idOrName));
            if (element != null) {
                executeJavascript("document.getElementsByName('%s')[0].value='%s'", idOrName, value);
            }
        }
        return element != null;
    }

    /**
     * Executes Javascript in browser.
     * @param statementPattern javascript to run, possibly with placeholders to be replaced.
     * @param parameters placeholder values that should be replaced before executing the script.
     */
    public void executeJavascript(String statementPattern, Object... parameters) {
        String script = String.format(statementPattern, parameters);
        JavascriptExecutor jse = (JavascriptExecutor) driver();
        jse.executeScript(script);
    }

    /**
     * Creates By based on xPath, supporting placeholder replacement.
     * @param pattern basic XPATH, possibly with placeholders.
     * @param parameters values for placeholders.
     * @return ByXPath.
     */
    public By byXpath(String pattern, String... parameters) {
        Object[] escapedParams = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            escapedParams[i] = xpathEscape(parameters[i]);
        }
        String xpath = String.format(pattern, escapedParams);
        return By.xpath(xpath);
    }

    private String xpathEscape(String value) {
        return StringEscapeUtils.escapeXml(value);
    }

    /**
     * Sets how long to wait before deciding an element does not exists.
     * @param implicitWait time in milliseconds to wait.
     */
    public void setImplicitlyWait(int implicitWait) {
        driver().manage().timeouts().implicitlyWait(implicitWait, TimeUnit.MILLISECONDS);
    }

    /**
     * Finds first element matching the By supplied.
     * @param by criteria.
     * @return element if found, null if none could be found.
     */
    public WebElement findElement(By by) {
        return findElement(false, by);
    }

    /**
     * Finds element matching the By supplied.
     * @param atMostOne true indicates multiple matching elements should trigger an exception
     * @param by criteria.
     * @return element if found, null if none could be found.
     * @throws RuntimeException if atMostOne is true and multiple elements match by.
     */
    public WebElement findElement(boolean atMostOne, By by) {
        return findElement(driver(), atMostOne, by);
{'fraction_non_alphanumeric': 0.11111962015622606, 'fraction_numerical': 0.000382907030173074, 'mean_word_length': 2.320366132723112, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3401920', 'n_tokens_mistral': 3622, 'n_tokens_neox': 3539, 'n_words': 951}