Java tutorial
/* Cards Against Humanity Card Generator * Copyright (C) 2012 Sheila Thomson * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.kaikoda.cah; import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.io.File; import java.io.IOException; import java.util.Locale; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.commons.cli.MissingArgumentException; import org.apache.commons.cli.ParseException; import org.apache.commons.io.FileUtils; import org.custommonkey.xmlunit.XMLUnit; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.w3c.dom.Document; import org.xml.sax.SAXException; import com.kaikoda.cah.CardGenerator.CardGeneratorProduct; import com.kaikoda.cah.ProgressReporter.ProgressReporterMode; /** * @author Sheila Thomson */ public class TestCardGenerator { /** * A reusable instance of a document builder configured for use by Deck. */ private static DocumentBuilder documentBuilder; /** * A pointer to where the asset files that accompany the HTML file are * expected to be saved. */ private static final File OUTPUT_FILE_ASSETS = new File( System.getProperty("user.dir") + File.separator + "assets"); /** * A pointer to where the CSS file that accompanies the HTML file is * expected to be saved. */ private static final File OUTPUT_FILE_CSS = new File( System.getProperty("user.dir") + File.separator + "assets" + File.separator + "style.css"); /** * A pointer to where the HTML file is expected to be saved. */ private static final File OUTPUT_FILE_HTML = new File( System.getProperty("user.dir") + File.separator + "cards_against_humanity.html"); /** * A pointer to where the XML file is expected to be saved. */ private static final File OUTPUT_FILE_XML = new File( System.getProperty("user.dir") + File.separator + "cards_against_humanity.xml"); /** * For declaring what kind of exception is expected, when one is expected. */ @Rule public ExpectedException exception = ExpectedException.none(); /** * A reusable instance of CardGenerator. */ private CardGenerator generator; /** * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws ParserConfigurationException */ @BeforeClass public static void setupOnce() throws CardGeneratorConfigurationException, ParserConfigurationException { documentBuilder = Deck.newDocumentBuilder(); } /** * Configure the test environment prior to each test. * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. */ @Before public void setup() throws CardGeneratorConfigurationException { this.generator = new CardGenerator(); this.generator.setVerbosity(ProgressReporterMode.CALLBACK); XMLUnit.setIgnoreWhitespace(true); XMLUnit.setIgnoreAttributeOrder(true); XMLUnit.setIgnoreComments(true); XMLUnit.setXSLTVersion("2.0"); XMLUnit.setControlEntityResolver(null); XMLUnit.setTestEntityResolver(null); } /** * Delete files generated by tests and release objects for garbage * collection. * * @throws IOException if there's an error deleting the assets directory. */ @After public void tearDown() throws IOException { // Delete the output files. TestCardGenerator.OUTPUT_FILE_HTML.delete(); TestCardGenerator.OUTPUT_FILE_XML.delete(); FileUtils.deleteDirectory(TestCardGenerator.OUTPUT_FILE_ASSETS); // Release the re-usable instance of CardGenerator. this.generator = null; } /** * Check that it's possible to construct a usable instance of CardGenerator. */ @Test public void testCardGenerator_constructor() { assertNotNull(generator); } /** * Check that the Card Generator correctly removes duplicates entries in the * card data. * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorGenerate_dedupe() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve test card data containing multiple decks and duplicate cards File xml = this.getFile("/data/test/cards/duplicates.xml"); // Build the cards String result = this.getXmlString(generator.generate(xml, null, null)); // Retrieve test card data that contains the same cards but no // duplicates. String expected = this.getXmlString("/data/control/cards/no_duplicates.html"); // Check that the result is the same cards, but in just two decks and // with no duplicates. assertXMLEqual(expected, result); } /** * Check that the Card Generator correctly removes duplicate entries in the * card data. * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorGenerate_elementBlanks() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve test card data containing multiple decks and duplicate cards File xml = this.getFile("/data/test/cards/blanks_element.xml"); // Build the cards Document result = this.getDocument(generator.generate(xml, null, null)); // Retrieve test card data that contains the same cards but no // duplicates. Document expected = this.getDocument("/data/control/cards/blanks_element.html"); // Check that the result is the same cards, but in just two decks and // with no duplicates. assertXMLEqual(expected, result); } /** * Check that the Card Generator correctly translates from American to * British English. * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorGenerate_translate_english() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve the test card data for American CAH. File xml = this.getFile("/data/test/cards/usa.xml"); // Build the cards Document result = this.getDocument(generator.generate(xml, Locale.forLanguageTag("en-gb"), this.getFile("/data/control/dictionaries/english.xml"))); // Retrieve the test card data for British CAH. Document expected = this.getDocument("/data/control/cards/uk.html"); // Check that the result is the same cards, translated into British // English (which is the default output language). assertXMLEqual(expected, result); } /** * Check that a null parameter value is ignored. * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorGenerate_translate_nullTargetLanguage() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve the test card data for British CAH. File xml = this.getFile("/data/test/cards/uk.xml"); // Build the cards Document result = this .getDocument(generator.generate(xml, null, this.getFile("/data/control/dictionaries/english.xml"))); // Retrieve the control card data for American CAH. Document expected = this.getDocument("/data/control/cards/uk.html"); // Check that the result is the same cards, still in British English. assertXMLEqual(expected, result); } /** * Check that the Card Generator falls back to the default output language * when none other is specified (and an English dictionary is available). * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorGenerate_translate_params_defaultOutputLangage() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve the test card data for British CAH. File xml = this.getFile("/data/test/cards/uk.xml"); // Build the cards Document result = this .getDocument(generator.generate(xml, null, this.getFile("/data/control/dictionaries/english.xml"))); // Retrieve the control card HTML for British CAH. Document expected = this.getDocument("/data/control/cards/uk.html"); // Check that the result is the same cards, still in British English // (source language). assertXMLEqual(expected, result); } /** * Check that the Card Generator doesn't fail when params is null. * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorGenerate_translate_params_null() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve the test card data for British CAH. File xml = this.getFile("/data/test/cards/uk.xml"); // Build the cards String result = this.getXmlString(generator.generate(xml, null, null)); // Retrieve the control card data for British CAH. String expected = this.getXmlString(this.getFile("/data/control/cards/uk.html")); // Check that the result is untranslated (as no dictionary has been // specified). assertXMLEqual(expected, result); } /** * Check that the Card Generator falls back to the default output language * when none other is specified (and an English dictionary is available). * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorGenerate_translate_params_outputLangageEqualsCurrentLanguage() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve the test card data for British CAH. File xml = this.getFile("/data/test/cards/uk.xml"); // Build the cards Document result = this.getDocument(generator.generate(xml, Locale.forLanguageTag("en-gb"), this.getFile("/data/control/dictionaries/english.xml"))); // Retrieve the control card HTML for British CAH. Document expected = this.getDocument("/data/control/cards/uk.html"); // Check that the result is the same cards, still in British English // (source language). assertXMLEqual(expected, result); } /** * Check that the Card Generator correctly saves a file * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws SAXException when something goes wrong while building the DOM * Document. * @throws IOException when something goes wrong while reading or writing to * the file. * @throws ParserConfigurationException * @throws ParseException if there are any problems encountered while * parsing the command line tokens. */ @Test public void testCardGeneratorMain() throws CardGeneratorConfigurationException, SAXException, IOException, ParserConfigurationException, ParseException { File input = this.getFile("/data/test/cards/html5.xml"); String[] args = new String[] { "-f", input.getAbsolutePath(), "-v", "callback" }; CardGenerator.main(args); // Check that a file has been created where the HTML file is expected. assertEquals(true, OUTPUT_FILE_HTML.exists()); Document expected = this.getDocument("/data/control/cards/html5.html"); Document result = this.getDocument(OUTPUT_FILE_HTML); assertXMLEqual(expected, result); // Check that a file has been created where the CSS file is expected. assertEquals(true, OUTPUT_FILE_CSS.exists()); } /** * Check that the Card Generator correctly fails to execute if the card data * isn't found. * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws ParseException if there are any problems encountered while * parsing the command line tokens. */ @Test public void testCardGeneratorMain_cardDataNotFound() throws CardGeneratorConfigurationException, SAXException, IOException, ParserConfigurationException, ParseException { String[] args = new String[] { "-f", "phantom.xml", "-v", "callback" }; exception.expect(IllegalArgumentException.class); exception.expectMessage("File not found: "); CardGenerator.main(args); } /** * Check that the Card Generator correctly fails to execute if a path to the * card data isn't supplied. * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws ParseException if there are any problems encountered while * parsing the command line tokens. */ @Test public void testCardGeneratorMain_cardDataNotSupplied() throws CardGeneratorConfigurationException, SAXException, IOException, ParserConfigurationException, ParseException { exception.expect(MissingArgumentException.class); exception.expectMessage("Missing argument for option: f"); String[] args = new String[] { "-f", "-v", "callback" }; CardGenerator.main(args); File result = OUTPUT_FILE_HTML; assertEquals(false, result.exists()); } /** * Check that the Card Generator correctly fails to execute if no dictionary * is specified when the dictionary option is supplied as an argument. * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws ParseException if there are any problems encountered while * parsing the command line tokens. */ @Test public void testCardGeneratorMain_dictionaryNotFound() throws CardGeneratorConfigurationException, SAXException, IOException, ParserConfigurationException, ParseException { exception.expect(MissingArgumentException.class); exception.expectMessage("Missing argument for option: d"); File input = this.getFile("/data/test/cards/html5.xml"); String[] args = new String[] { "-f", input.getAbsolutePath(), "-d", "-v", "callback" }; CardGenerator.main(args); File result = OUTPUT_FILE_HTML; assertEquals(false, result.exists()); } /** * Check that the Card Generator correctly fails to execute if help is * requested. * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws ParseException if there are any problems encountered while * parsing the command line tokens. */ @Test public void testCardGeneratorMain_help() throws CardGeneratorConfigurationException, SAXException, IOException, ParserConfigurationException, ParseException { File input = this.getFile("/data/test/cards/html5.xml"); String[] args = new String[] { "-f", input.getAbsolutePath(), "-h", "-v", "callback" }; CardGenerator.main(args); File result = OUTPUT_FILE_HTML; assertEquals(false, result.exists()); } /** * Check that the Card Generator correctly fails to execute if no card data * is supplied. * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws ParseException if there are any problems encountered while * parsing the command line tokens. */ @Test public void testCardGeneratorMain_noCardData() throws CardGeneratorConfigurationException, SAXException, IOException, ParserConfigurationException, ParseException { exception.expect(IllegalArgumentException.class); exception.expectMessage("Nothing to process; no file or directory was specified."); String[] args = new String[] { "-v", "callback" }; CardGenerator.main(args); File result = OUTPUT_FILE_HTML; assertEquals(false, result.exists()); } /** * Check that the Card Generator correctly translates card data when * generating an HTML file. * * @throws CardGeneratorConfigurationException if it's not possible to * construct a usable instance of CardGenerator. * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws ParserConfigurationException * @throws ParseException if there are any problems encountered while * parsing the command line tokens. */ @Test public void testCardGeneratorMain_translate() throws CardGeneratorConfigurationException, SAXException, IOException, ParserConfigurationException, ParseException { File input = this.getFile("/data/test/cards/usa.xml"); File dictionary = this.getFile("/data/control/dictionaries/english.xml"); String[] args = new String[] { "-f", input.getAbsolutePath(), "-d", dictionary.getAbsolutePath(), "-l", "en-gb", "-v", "callback" }; CardGenerator.main(args); // Check that a file has been created where the HTML file is expected. assertEquals(true, OUTPUT_FILE_HTML.exists()); String expected = this.getXmlString("/data/control/cards/uk.html"); String result = this.getXmlString(OUTPUT_FILE_HTML); assertXMLEqual(expected, result); // Check that a file has been created where the CSS file is expected. assertEquals(true, OUTPUT_FILE_CSS.exists()); } /** * Check that the HTML version is generated correctly. * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorToHtml() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve test card data containing enough cards for multiple pages of // each deck File xml = this.getFile("/data/test/cards/html5.xml"); // Build the cards String result = this.getXmlString(generator.generate(xml, null, null, CardGeneratorProduct.HTML)); // Retrieve test card data that contains the same cards but no // duplicates. String expected = this.getXmlString(this.getFile("/data/control/cards/html5.html")); // Check that the result is the same cards, but in just two decks and // with no duplicates. assertXMLEqual(expected, result); } /** * Check that the XML version is generated correctly. * * @throws SAXException if an error occurs while building one of the test or * control documents. * @throws IOException if an error occurs while reading one of the test or * control documents. * @throws TransformerException is an unrecoverable error occurs during the * transformation. * @throws ParserConfigurationException */ @Test public void testCardGeneratorToXml() throws SAXException, IOException, TransformerException, ParserConfigurationException { // Retrieve test card data containing enough cards for multiple pages of // each deck File xml = this.getFile("/data/test/cards/html5.xml"); // Build the cards String result = this.getXmlString(generator.generate(xml, null, null, CardGeneratorProduct.XML)); // Retrieve test card data that contains the same cards but no // duplicates. String expected = this.getXmlString(this.getFile("/data/control/cards/html5.xml")); // Check that the result is the same cards, but in just two decks and // with no duplicates. assertXMLEqual(expected, result); } /** * Builds a DOM Document from the file specified. * * @param input a file containing XML. * @return the XML as a DOM Document. * @throws SAXException when something goes wrong while building the DOM * Document. * @throws IOException when something goes wrong while reading or writing to * the file. * @throws ParserConfigurationException */ private Document getDocument(File input) throws SAXException, IOException, ParserConfigurationException { TestCardGenerator.documentBuilder.reset(); return TestCardGenerator.documentBuilder.parse(input); } /** * Builds a DOM Document from a file at the path specified. * * @param path a path to a file containing XML. * @return the XML as a DOM Document. * @throws SAXException when something goes wrong while building the DOM * Document. * @throws IOException when something goes wrong while reading or writing to * the file. * @throws ParserConfigurationException */ private Document getDocument(String path) throws SAXException, IOException, ParserConfigurationException { return this.getDocument(this.getFile(path)); } /** * Finds a file that matches the path specified. * * @param path a potential path to the file sought. * @return the file sought. */ private File getFile(String path) { return new File(this.getClass().getResource(path).getFile()); } /** * Builds an XML String from the file specified. * * @param input a file containing XML. * @return the XML as an XML String. * @throws IOException when something goes wrong while reading the input * file. */ private String getXmlString(File input) throws IOException { return FileUtils.readFileToString(input, "UTF-8"); } /** * Builds an XML String from the file at the location specified. * * @param input a file containing XML. * @return the XML as an XML String. * @throws IOException when something goes wrong while reading the input * file. */ private String getXmlString(String input) throws IOException { return this.getXmlString(this.getFile(input)); } }