From b2233f4d08e922416c1c10080744e6dd5513be9b Mon Sep 17 00:00:00 2001 From: Benjamin Jones Date: Mon, 12 Nov 2012 18:07:51 -0800 Subject: initial commit of headless rule set tester --- .../main/java/com/galois/fiveui/BatchRunner.java | 195 +++++++++++++++++++++ .../main/java/com/galois/fiveui/HeadlessAtom.java | 130 ++++++++++++++ .../com/galois/fiveui/HeadlessRunDescription.java | 171 ++++++++++++++++++ .../java/com/galois/fiveui/HeadlessRunner.java | 99 +++++++++++ .../java/com/galois/fiveui/BatchExecutorTest.java | 109 ++++++++++++ .../test/java/com/galois/fiveui/HeadlessTest.java | 104 +++++++++++ .../src/test/resources/ruleSets/emptyRuleSet.json | 4 + .../test/resources/ruleSets/headingGuidelines.json | 37 ++++ .../runDescriptions/headlessRunTest0.json | 4 + .../runDescriptions/headlessRunTestCNN.json | 4 + .../runDescriptions/headlessRunTestGalois.json | 11 ++ .../resources/runDescriptions/headlessSample0.json | 4 + .../resources/runDescriptions/headlessSample1.json | 4 + .../resources/runDescriptions/headlessSample2.json | 9 + 14 files changed, 885 insertions(+) create mode 100644 headless/src/main/java/com/galois/fiveui/BatchRunner.java create mode 100644 headless/src/main/java/com/galois/fiveui/HeadlessAtom.java create mode 100644 headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java create mode 100644 headless/src/main/java/com/galois/fiveui/HeadlessRunner.java create mode 100644 headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java create mode 100644 headless/src/test/java/com/galois/fiveui/HeadlessTest.java create mode 100644 headless/src/test/resources/ruleSets/emptyRuleSet.json create mode 100644 headless/src/test/resources/ruleSets/headingGuidelines.json create mode 100644 headless/src/test/resources/runDescriptions/headlessRunTest0.json create mode 100644 headless/src/test/resources/runDescriptions/headlessRunTestCNN.json create mode 100644 headless/src/test/resources/runDescriptions/headlessRunTestGalois.json create mode 100644 headless/src/test/resources/runDescriptions/headlessSample0.json create mode 100644 headless/src/test/resources/runDescriptions/headlessSample1.json create mode 100644 headless/src/test/resources/runDescriptions/headlessSample2.json (limited to 'headless/src') diff --git a/headless/src/main/java/com/galois/fiveui/BatchRunner.java b/headless/src/main/java/com/galois/fiveui/BatchRunner.java new file mode 100644 index 0000000..8c7338c --- /dev/null +++ b/headless/src/main/java/com/galois/fiveui/BatchRunner.java @@ -0,0 +1,195 @@ +/** + * Module : BatchRunner.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * 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.galois.fiveui; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.galois.fiveui.Result; +import com.galois.fiveui.RuleSet; +import com.galois.fiveui.Utils; + +/** + * BatchRunner is initialized with a WebDriver object. It provides an interface + * for running {@code RuleSet}s and {@code RuleTest}s with the WebDriver. + * + * @author bjones + */ +public class BatchRunner { + + private final WebDriver _driver; + private final JavascriptExecutor _exe; + + + /** + * BatchRunner constructor, stores the given WebDriver. + * + * @param driver the WebDriver object to run tests with + */ + public BatchRunner(WebDriver driver) { + _driver = driver; + _exe = (JavascriptExecutor) _driver; + } + + + + /** + * Run a headless run description, returning the raw results: 'PASS' if + * no inconsistencies were found, 'ERROR' for each inconsistency found, + * 'EXCEPTION' for each uncaught exception. + *

+ * The run.getURL() is loaded using the WebDriver and the rule set returned + * by {@code run.getRule()} is run. + * + * @param run a headless run description object + */ + public ImmutableList runHeadless(final HeadlessRunDescription run) { + + Builder builder = ImmutableList.builder(); + ImmutableList rawResults; + for (HeadlessAtom a: run.getAtoms()) { + RuleSet rs = a.getRuleSet(); + try { + loadURL(a.getURL()); // set state of the WebDriver + rawResults = runRule(rs); // run the ruleset, collect results + builder.addAll(rawResults); + } catch (Exception e) { + String errStr = "Exception during runRule: " + rs.getName() + "\n"; + errStr += e.toString(); + builder.add(Result.exception(_driver, "Could not run rule: "+errStr)); + } + } + + return builder.build(); + } + + /** + * Run a rule set on a page. + *

+ * This method uses the web driver instance to run a rule set on the currently + * loaded page. The webdriver injects javascript that + * includes all the dependencies (JQuery, etc..) as well as the function which + * executes the rule check. The method sleeps the thread for 1 second and + * queries the results, which are then parsed and returned as a list of + * Result objects. + * + * @param ruleSet the rule set to be run + * @return results of running the rule set + * @throws IOException + */ + private ImmutableList runRule(final RuleSet ruleSet) throws IOException { + String contentScript = wrapRule(ruleSet); + Builder builder = ImmutableList.builder(); + + _exe.executeScript(contentScript); + + try { + Thread.sleep(1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + + Object res = _exe.executeScript("return fiveui.selPort.query(type='ReportProblem')"); + + if (res.getClass() == String.class) { + // we received an error via the expected mechanisms: + System.err.println("Exception running rule: " + res); + builder.add(Result.exception(_driver, (String) res)); + return builder.build(); + } else { + + try { + @SuppressWarnings({ "unchecked", "rawtypes" }) + List>> results = (List) res; + + if (0 == results.size()) { + builder.add(Result.pass(_driver, "passed")); + } + + for (Map> r : results) { + Map problem = r.get("payload"); + + builder.add(Result.error(_driver, problem.get("descr"))); + } + + } catch (ClassCastException e) { + // An unexpected error happened: + builder.add(Result.exception(_driver, "Unexpected object returned: " + + res)); + e.printStackTrace(); + } + } + return builder.build(); + } + + // Relative to the batch directory. + private static final String DATA_DIR = "../contexts/data/"; + private static final String J_QUERY_JS = DATA_DIR + + "lib/jquery/jquery-1.7.1.min.js"; + private static final String PRELUDE_JS = DATA_DIR + + "fiveui/injected/prelude.js"; + private static final String MD5_JS = DATA_DIR + + "lib/jshash/md5.js"; + private static final String JQUERY_PLUGIN_JS = DATA_DIR + + "fiveui/injected/jquery-plugins.js"; + private static final String SEL_INJECTED_COMPUTE_JS = DATA_DIR + + "/fiveui/selenium/selenium-injected-compute.js"; + + private static final String INJECTED_COMPUTE_JS = DATA_DIR + + "/fiveui/injected/fiveui-injected-compute.js"; + + /** + * Build up the complete content script needed to run the rule. + *

+ * The string returned contains all the javascript dependencies required + * to run a rule set and the function that is injected into the page which + * executes the rule set. + * + * @param ruleSet a RuleSet object + * @throws IOException + */ + private String wrapRule(RuleSet ruleSet) throws IOException { + String injected = ""; + injected += Utils.readFile(SEL_INJECTED_COMPUTE_JS); + injected += Utils.readFile(J_QUERY_JS); + injected += Utils.readFile(PRELUDE_JS); + injected += Utils.readFile(MD5_JS); + injected += Utils.readFile(JQUERY_PLUGIN_JS); + injected += Utils.readFile(INJECTED_COMPUTE_JS); + + injected += "return fiveui.selPort.send('SetRules', " + ruleSet + ");"; + + return injected; + } + + /** + * Sets the state of the WebDriver by loading a given URL. + * + * @param url URL to load + */ + private void loadURL(String url) { + _driver.get(url); + } + +} diff --git a/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java b/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java new file mode 100644 index 0000000..2d40156 --- /dev/null +++ b/headless/src/main/java/com/galois/fiveui/HeadlessAtom.java @@ -0,0 +1,130 @@ +/** + * + */ +package com.galois.fiveui; + +import java.io.File; +import java.io.IOException; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +import com.galois.fiveui.RuleSet; +import com.galois.fiveui.Utils; + +/** + * @author bjones + * + */ +public class HeadlessAtom { + + private String _url; + private RuleSet _ruleSet; + + public HeadlessAtom(String url, RuleSet ruleSet) { + _url = url; + _ruleSet = ruleSet; + } + + public String getURL() { + return _url; + } + + public RuleSet getRuleSet() { + return _ruleSet; + } + + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + /** + * Parse a JSON file into a HeadlessAtom + * + * @param str The string to parse + * @return A populated HeadlessAtom object. + */ +// public static HeadlessAtom parse(String str) +// throws FileNotFoundException { +// GsonBuilder gsonBuilder = new GsonBuilder(); +// gsonBuilder.registerTypeAdapter(HeadlessAtom.class, +// new HeadlessAtom.Deserializer()); +// Gson gson = gsonBuilder.create(); +// return gson.fromJson(str, HeadlessAtom.class); +// } + + /** + * Construct a HeadlessAtom from a JsonObject + * + * @param obj JsonObject to convert from + * @param dir parent directory of the filenames referenced in the ruleSet field + * @return a HeadlessAtom POJO + * @throws IOException + * @throws JsonParseException + */ + public static HeadlessAtom fromJsonObject(JsonObject obj, String dir) throws IOException { + String url = obj.get("url").getAsString(); + String ruleSet = obj.get("ruleSet").getAsString(); + + if (url == null || ruleSet == null) { + throw new JsonParseException("could get either 'url' or 'ruleSet' properties"); + } + + String rsPath = dir + File.separator + ruleSet; + String ruleSetStr = Utils.readFile(rsPath); + + RuleSet parsed = RuleSet.parse(ruleSetStr); + + return new HeadlessAtom(url, parsed); + } + +// public static class Deserializer implements JsonDeserializer { +// +// public Deserializer() {} +// +// public HeadlessAtom deserialize(JsonElement json, Type typeOfT, +// JsonDeserializationContext context) throws JsonParseException { +// JsonObject obj = json.getAsJsonObject(); +// try { +// return HeadlessAtom.fromJsonObject(obj); +// } catch (IOException e) { +// e.printStackTrace(); +// // TODO bad stop gap +// return new HeadlessAtom(null, null); +// } +// } +// } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((_url == null) ? 0 : _url.hashCode()); + result = prime * result + ((_ruleSet == null) ? 0 : _ruleSet.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + HeadlessAtom other = (HeadlessAtom) obj; + if (_url == null) { + if (other._url != null) + return false; + } else if (!_url.equals(other._url)) + return false; + if (_ruleSet == null) { + if (other._ruleSet != null) + return false; + } else if (!_ruleSet.equals(other._ruleSet)) + return false; + return true; + } + +} diff --git a/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java b/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java new file mode 100644 index 0000000..49131ad --- /dev/null +++ b/headless/src/main/java/com/galois/fiveui/HeadlessRunDescription.java @@ -0,0 +1,171 @@ +/** + * + */ +package com.galois.fiveui; + + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.Type; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +/** + * @author bjones + * + */ +public class HeadlessRunDescription { + + private List _atoms; + + public HeadlessRunDescription (List atoms) { + _atoms = atoms; + } + + public List getAtoms() { + return _atoms; + } + + public int size() { + return _atoms.size(); + } + + /** + * Parse a JSON file into a HeadlessRunDescription + * + * @param runDescFileName The file to load. + * @return A populated HeadlessRunDescription object. + * @throws FileNotFoundException if runDescFile can't be found. + */ + public static HeadlessRunDescription parse(String runDescFileName) + throws FileNotFoundException { + + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(HeadlessRunDescription.class, + new HeadlessRunDescription.Deserializer(runDescFileName)); + Gson gson = gsonBuilder.create(); + + Reader in = new InputStreamReader(new FileInputStream(runDescFileName)); + + return gson.fromJson(in, HeadlessRunDescription.class); + } + + public static class Deserializer implements JsonDeserializer { + + private String _fn; // stores the filename on disk being parsed + private String _ctxDir; // stores the parent dir of _fn + + public Deserializer(String fn) { + _fn = fn; + _ctxDir = new File(_fn).getParent(); + if (null == _ctxDir) { + _ctxDir = "."; + } + } + + public static void printErr(JsonElement json) { + System.err.println("HeadlessRunDescription.parse: ran into unexpected jsonElement type"); + } + + /** + * Gracefully lookup property 'prop' in JsonObject 'obj'. + * + * @param obj a JSON object + * @param prop a key string to lookup in the JSON object + * @return string property or null if the prop doesn't resolve + */ + public static String objGetString(JsonObject obj, String prop) { + try { + return obj.get(prop).getAsString(); + } catch (NullPointerException e) { + System.err.println("HeadlessRunDescription.parse: failed to lookup property: " + prop); + e.printStackTrace(); + return null; + } + } + + public HeadlessRunDescription deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException { + + @SuppressWarnings("unused") + String ruleSetDir, crawlType; + JsonArray arr; + + if (json.isJsonObject()) { // check if the description is an extended one + JsonObject obj = json.getAsJsonObject(); + ruleSetDir = objGetString(obj, "rulePath"); + crawlType = objGetString(obj, "crawlType"); // TODO not implemented + arr = obj.get("runs").getAsJsonArray(); + } else if (json.isJsonArray()) { + ruleSetDir = _ctxDir; + crawlType = "none"; + arr = json.getAsJsonArray(); + } else { + printErr(json); + return new HeadlessRunDescription(null); + } + + Builder atoms = ImmutableList.builder(); + for (JsonElement jsonElement : arr) { + try { + JsonObject obj = jsonElement.getAsJsonObject(); + atoms.add(HeadlessAtom.fromJsonObject(obj, ruleSetDir)); + } catch (IOException e) { + System.err.println("HeadlessAtom.parse: error parsing ruleSet file: " + e.getMessage()); + } catch (IllegalStateException e) { + printErr(jsonElement); + } + } + + return new HeadlessRunDescription(atoms.build()); + } + } + + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + for (HeadlessAtom a: _atoms) { + result = prime * result + a.hashCode(); + } + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + HeadlessRunDescription other = (HeadlessRunDescription) obj; + if (_atoms == null) { + if (other._atoms != null) + return false; + } else if (!_atoms.equals(other._atoms)) + return false; + + return true; + } +} diff --git a/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java b/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java new file mode 100644 index 0000000..e743064 --- /dev/null +++ b/headless/src/main/java/com/galois/fiveui/HeadlessRunner.java @@ -0,0 +1,99 @@ +/** + * Module : HeadlessRunner.java Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : Stability : Provisional Portability: Portable + * + * 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.galois.fiveui; + +import java.io.IOException; +import java.net.URISyntaxException; + +import org.openqa.selenium.WebDriver; + +import com.galois.fiveui.Result; +import com.galois.fiveui.drivers.Drivers; +import com.google.common.collect.ImmutableList; + +/** + * The main entry point for running headless rule set runs. + *

+ * The {@link #main(String[])} method of this class sets up a WebDriver, loads + * a headless run description from disk, and executes the run which includes + * loading URL's and running rule sets on their content. + * + * @author bjones + * + */ +public class HeadlessRunner { + + /** + * @param args + * @throws IOException + * @throws URISyntaxException + */ + public static void main(final String[] args) throws IOException, + URISyntaxException { + + if (0 == args.length) { + printHelp(); + System.exit(1); + } + + for (int i = 0; i < args.length; i++) { + String runDescFileName = args[i]; + HeadlessRunDescription descr = HeadlessRunDescription.parse(runDescFileName); + + for (WebDriver driver : getDrivers()) { + try { + ImmutableList results = invokeHeadlessRun(driver, descr); + + for (Result result : results) { + System.out.println(result); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + driver.quit(); + } + } + } + } + + /** + * Helper method for executing headless runs. This method runs a single + * HeadlessRunDescription and returns the list of results. If the file cannot + * be read, an empty list is returned. + * + * @param driver webdrive to use for the run + * @param descr a headless run description object + */ + private static ImmutableList invokeHeadlessRun(WebDriver driver, HeadlessRunDescription descr) { + BatchRunner runner = new BatchRunner(driver); // setup the batch runner + return runner.runHeadless(descr); // execute the run + } + + private static ImmutableList getDrivers() { + return ImmutableList.of( + Drivers.buildFFDriver() + // , Drivers.buildChromeDriver() + ); + } + + private static void printHelp() { + System.out.println( + "Usage: HeadlessRunner []"); + } + +} diff --git a/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java b/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java new file mode 100644 index 0000000..f72c5a1 --- /dev/null +++ b/headless/src/test/java/com/galois/fiveui/BatchExecutorTest.java @@ -0,0 +1,109 @@ +/** + * Module : BatchExecutorTest.java + * Copyright : (c) 2011-2012, Galois, Inc. + * + * Maintainer : + * Stability : Provisional + * Portability: Portable + * + * 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.galois.fiveui; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.WebDriver; + +import com.galois.fiveui.BatchRunner; +import com.galois.fiveui.HeadlessRunDescription; +import com.galois.fiveui.Result; +import com.galois.fiveui.drivers.Drivers; +import com.google.common.collect.ImmutableList; + +import junit.framework.Assert; + + +/** + * @author bjones + * + */ +public class BatchExecutorTest { + + private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; + + @Test + public void simpleTest() { + Assert.assertEquals("Booleans are not equal.", true, true); + } + + /** + * This unit test requires that a webserver be running locally on port 8000, + * what it serves does not matter. + * + * @throws IOException + * @throws FileNotFoundException + */ + @Test + public void headlessRunTest0() throws IOException { + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessRunTest0.json"; + testHeadlessRun(jsonFileName); + } + + /** + * This unit test requires internet access to http://www.cnn.com + * + * @throws IOException + * @throws FileNotFoundException + */ + @Test + public void headlessRunTestCNN() throws IOException { + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessRunTestCNN.json"; + testHeadlessRun(jsonFileName); + } + + /** + * This unit test requires internet access to http://www.cnn.com + * + * @throws IOException + * @throws FileNotFoundException + */ + @Test + public void headlessRunTestMil() throws IOException { + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessRunTestMil.json"; + testHeadlessRun(jsonFileName); + } + + /** + * Helper method for headless run unit tests. + * + * @param fn filename of a .json file containing a headless run description + */ + private static void testHeadlessRun(String fn) { + WebDriver driver = Drivers.buildFFDriver(); // initialize the webdriver + boolean flag = true; + try { + HeadlessRunDescription descr = HeadlessRunDescription.parse(fn); + BatchRunner runner = new BatchRunner(driver); // setup the batch runner + ImmutableList results = runner.runHeadless(descr); // excecute the run + System.out.println(results.toString()); // print out results + } catch (Exception e) { + System.err.println("testHeadlessRun: exception caught while running a headless run description"); + flag = false; + } finally { + driver.quit(); + } + assert(flag); + } + +} diff --git a/headless/src/test/java/com/galois/fiveui/HeadlessTest.java b/headless/src/test/java/com/galois/fiveui/HeadlessTest.java new file mode 100644 index 0000000..e878661 --- /dev/null +++ b/headless/src/test/java/com/galois/fiveui/HeadlessTest.java @@ -0,0 +1,104 @@ +/** + * + */ +package com.galois.fiveui; + +import java.io.IOException; + +import junit.framework.Assert; + +import org.junit.Test; + +import com.galois.fiveui.HeadlessAtom; +import com.galois.fiveui.HeadlessRunDescription; +import com.galois.fiveui.RuleSet; +import com.galois.fiveui.Utils; +import com.google.common.collect.ImmutableList; + +/** + * @author bjones + * + */ +public class HeadlessTest { + private static final String RUN_DESCRIPTION_DIR = "src/test/resources/runDescriptions/"; + + /** + * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses + * 'src/test/resources/runDescriptions/headlessSample0.json'. + * + * @throws IOException + */ + @Test + public final void testDeserialize_headlessSample0() throws IOException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample0.json"; + String ruleSetLoc = + RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; + RuleSet ruleSetOracle = RuleSet.parse(Utils.readFile(ruleSetLoc)); + HeadlessAtom headlessAtomOracle = + new HeadlessAtom("http://testhost", ruleSetOracle); + HeadlessRunDescription oracle = + new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle)); + + HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + /** + * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses + * 'src/test/resources/runDescriptions/headlessSample1.json'. + * + * @throws IOException + */ + @Test + public final void testDeserialize_headlessSample1() throws IOException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample1.json"; + String ruleSetLoc = + RUN_DESCRIPTION_DIR + "../ruleSets/headingGuidelines.json"; + RuleSet ruleSetOracle = RuleSet.parse(Utils.readFile(ruleSetLoc)); + HeadlessAtom headlessAtomOracle = + new HeadlessAtom("http://testhost", ruleSetOracle); + HeadlessRunDescription oracle = + new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle)); + + HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + /** + * Test method for {@link com.galois.com.galois.fiveui.HeadlessRunDescription}, parses + * 'src/test/resources/runDescriptions/headlessSample2.json'. + * + * @throws IOException + */ + @Test + public final void testDeserialize_headlessSample2() throws IOException { + + String jsonFileName = RUN_DESCRIPTION_DIR + "headlessSample2.json"; + // manually build first HeadlessAtom + String ruleSetLoc1 = + RUN_DESCRIPTION_DIR + "../ruleSets/emptyRuleSet.json"; + RuleSet ruleSetOracle1 = RuleSet.parse(Utils.readFile(ruleSetLoc1)); + HeadlessAtom headlessAtomOracle1 = + new HeadlessAtom("http://testhost1", ruleSetOracle1); + // manually build second HeadlessAtom + String ruleSetLoc2 = + RUN_DESCRIPTION_DIR + "../ruleSets/headingGuidelines.json"; + RuleSet ruleSetOracle2 = RuleSet.parse(Utils.readFile(ruleSetLoc2)); + HeadlessAtom headlessAtomOracle2 = + new HeadlessAtom("http://testhost2", ruleSetOracle2); + + HeadlessRunDescription oracle = + new HeadlessRunDescription(ImmutableList.of(headlessAtomOracle1, + headlessAtomOracle2)); + + HeadlessRunDescription actual = HeadlessRunDescription.parse(jsonFileName); + assertObjEqual("Object deserialized incorrectly.", oracle, actual); + } + + private void assertObjEqual(String msg, Object oracle, Object actual) { + Assert.assertTrue(msg + ";\n expected: "+oracle+"\n actual: "+actual, + oracle.equals(actual)); + } +} diff --git a/headless/src/test/resources/ruleSets/emptyRuleSet.json b/headless/src/test/resources/ruleSets/emptyRuleSet.json new file mode 100644 index 0000000..a01bc68 --- /dev/null +++ b/headless/src/test/resources/ruleSets/emptyRuleSet.json @@ -0,0 +1,4 @@ +{ "name": "emptyRuleSet" +, "description": "" +, "rules": [] +} diff --git a/headless/src/test/resources/ruleSets/headingGuidelines.json b/headless/src/test/resources/ruleSets/headingGuidelines.json new file mode 100644 index 0000000..be69fac --- /dev/null +++ b/headless/src/test/resources/ruleSets/headingGuidelines.json @@ -0,0 +1,37 @@ +{ "name": "Heading Guidelines" +, "description": "Guidelines pertaining to the formatting and content of headings." +, "rules": [ { "id": 1 + , "name": "Headings are capitalized" + , "description": "Check to see if all headings use leading capital letters." + , "rule": + function() { + var badHeadings = + fiveui.query(':header').filter( + function(idx) { + var ch = $(this).text()[0]; + if (ch) { + return (ch == ch.toLowerCase() ); + } else { + return false; + } + }); + $(badHeadings).map(function(idx, elt){ + report('Heading does not start with a capitol letter.', elt); + }); + + } + }, + { "id": 2 + , "name": "Disallow Empty Headers" + , "description": "Heading elements should contain text." + , "rule": function() { + fiveui.query(':header').each( + function(ix, elt) { + if($(elt).text() == '') { + report('Heading does not contain text', elt); + } + }); + } + } + ] +} \ No newline at end of file diff --git a/headless/src/test/resources/runDescriptions/headlessRunTest0.json b/headless/src/test/resources/runDescriptions/headlessRunTest0.json new file mode 100644 index 0000000..e6c4c3b --- /dev/null +++ b/headless/src/test/resources/runDescriptions/headlessRunTest0.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://localhost:8000', + 'ruleSet': '../ruleSets/emptyRuleSet.json' +}] diff --git a/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json b/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json new file mode 100644 index 0000000..07aaab8 --- /dev/null +++ b/headless/src/test/resources/runDescriptions/headlessRunTestCNN.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://www.cnn.com', + 'ruleSet': '../ruleSets/headingGuidelines.json' +}] diff --git a/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json b/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json new file mode 100644 index 0000000..d12f9b0 --- /dev/null +++ b/headless/src/test/resources/runDescriptions/headlessRunTestGalois.json @@ -0,0 +1,11 @@ +{ + 'rulePath' : '/Users/bjones/galois/FiveUI/exampleData/ruleSets', + 'crawlType' : 'none', + 'runs': [ + { 'url': 'http://corp.galois.com', 'ruleSet': 'colorRulesRF.json' }, + { 'url': 'http://corp.galois.com', 'ruleSet': 'emptyHeadings.json' }, + { 'url': 'http://corp.galois.com', 'ruleSet': 'fontRules.json' }, + { 'url': 'http://corp.galois.com', 'ruleSet': 'headingGuidelines.json' }, + { 'url': 'http://corp.galois.com', 'ruleSet': 'imageRules.json' } + ] +} diff --git a/headless/src/test/resources/runDescriptions/headlessSample0.json b/headless/src/test/resources/runDescriptions/headlessSample0.json new file mode 100644 index 0000000..2b3a51a --- /dev/null +++ b/headless/src/test/resources/runDescriptions/headlessSample0.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://testhost', + 'ruleSet': '../ruleSets/emptyRuleSet.json' +}] diff --git a/headless/src/test/resources/runDescriptions/headlessSample1.json b/headless/src/test/resources/runDescriptions/headlessSample1.json new file mode 100644 index 0000000..a3ee34d --- /dev/null +++ b/headless/src/test/resources/runDescriptions/headlessSample1.json @@ -0,0 +1,4 @@ +[{ + 'url': 'http://testhost', + 'ruleSet': '../ruleSets/headingGuidelines.json' +}] diff --git a/headless/src/test/resources/runDescriptions/headlessSample2.json b/headless/src/test/resources/runDescriptions/headlessSample2.json new file mode 100644 index 0000000..277bd4d --- /dev/null +++ b/headless/src/test/resources/runDescriptions/headlessSample2.json @@ -0,0 +1,9 @@ +[ +{ + 'url': 'http://testhost1', + 'ruleSet': '../ruleSets/emptyRuleSet.json' +}, +{ + 'url': 'http://testhost2', + 'ruleSet': '../ruleSets/headingGuidelines.json' +}] -- cgit v1.2.3