From 03b932d50224c9808f9f6505edcd550a0aceaa57 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Sun, 7 Apr 2019 14:46:45 -0700 Subject: [PATCH] Added tests. --- .../mobibot/modules/CurrencyConverter.java | 189 +++++++++--------- .../mobibot/modules/CurrencyConvertTest.java | 62 ++++++ 2 files changed, 158 insertions(+), 93 deletions(-) create mode 100644 src/test/java/net/thauvin/erik/mobibot/modules/CurrencyConvertTest.java diff --git a/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java index 49c7710..3cd623c 100644 --- a/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java +++ b/src/main/java/net/thauvin/erik/mobibot/modules/CurrencyConverter.java @@ -32,8 +32,11 @@ package net.thauvin.erik.mobibot.modules; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import net.thauvin.erik.mobibot.Mobibot; -import net.thauvin.erik.mobibot.Utils; +import net.thauvin.erik.mobibot.*; +import net.thauvin.erik.mobibot.msg.ErrorMessage; +import net.thauvin.erik.mobibot.msg.Message; +import net.thauvin.erik.mobibot.msg.PrivateMessage; +import net.thauvin.erik.mobibot.msg.PublicMessage; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.JDOMException; @@ -56,24 +59,22 @@ import java.util.TreeMap; * @since 1.0 */ public final class CurrencyConverter extends AbstractModule { - /** - * The currency command. - */ - public static final String CURRENCY_CMD = "currency"; - /** * The rates keyword. */ - public static final String CURRENCY_RATES_KEYWORD = "rates"; + static final String CURRENCY_RATES_KEYWORD = "rates"; + + // The currency command. + private static final String CURRENCY_CMD = "currency"; // The exchange rates. private static final Map EXCHANGE_RATES = new TreeMap<>(); // The exchange rates table URL. - private static final String EXCHANGE_TABLE_URL = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml"; + private static final String EXCHANGE_TABLE_URL = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"; // The last exchange rates table publication date. - private String pubDate = ""; + private static String pubDate = ""; /** * Creates a new {@link CurrencyConverter} instance. @@ -82,6 +83,85 @@ public final class CurrencyConverter extends AbstractModule { commands.add(CURRENCY_CMD); } + static Message converyCurrency(String query) { + if (EXCHANGE_RATES.isEmpty()) { + try { + final SAXBuilder builder = new SAXBuilder(); + builder.setIgnoringElementContentWhitespace(true); + + final Document doc = builder.build(new URL(EXCHANGE_TABLE_URL)); + final Element root = doc.getRootElement(); + final Namespace ns = root.getNamespace(""); + final Element cubeRoot = root.getChild("Cube", ns); + final Element cubeTime = cubeRoot.getChild("Cube", ns); + + pubDate = cubeTime.getAttribute("time").getValue(); + + final List cubes = cubeTime.getChildren(); + Element cube; + + for (final Object rawCube : cubes) { + cube = (Element) rawCube; + EXCHANGE_RATES.put( + cube.getAttribute("currency").getValue(), + cube.getAttribute("rate").getValue()); + } + + EXCHANGE_RATES.put("EUR", "1"); + } catch (JDOMException e) { + return new ErrorMessage("An error has occurred while parsing the exchange rates table."); + } catch (IOException e) { + return new ErrorMessage( + "An error has occurred while fetching the exchange rates table: " + e.getMessage()); + } + } + + if (EXCHANGE_RATES.isEmpty()) { + return new ErrorMessage("Sorry, but the exchange rate table is empty."); + } else { + final String[] cmds = query.split(" "); + + if (cmds.length == 4) { + if (cmds[3].equals(cmds[1]) || cmds[0].equals("0")) { + return new ErrorMessage("You're kidding, right?"); + } else { + try { + final double amt = Double.parseDouble(cmds[0].replaceAll(",", "")); + final double from = Double.parseDouble(EXCHANGE_RATES.get(cmds[1].toUpperCase())); + final double to = Double.parseDouble(EXCHANGE_RATES.get(cmds[3].toUpperCase())); + + return new PublicMessage( + NumberFormat.getCurrencyInstance(Locale.US).format(amt).substring(1) + + ' ' + + cmds[1].toUpperCase() + + " = " + + NumberFormat.getCurrencyInstance(Locale.US) + .format((amt * to) / from) + .substring(1) + + ' ' + + cmds[3].toUpperCase()); + } catch (NullPointerException ignored) { + return new ErrorMessage( + "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); + } + } + } else if (query.equals(CURRENCY_RATES_KEYWORD)) { + + final StringBuilder buff = new StringBuilder('[' + pubDate + "]: "); + + int i = 0; + for (final Map.Entry rate : EXCHANGE_RATES.entrySet()) { + if (i > 0) buff.append(", "); + buff.append(rate.getKey()).append(": ").append(rate.getValue()); + i++; + } + + return new PrivateMessage(buff.toString()); + } + } + return new ErrorMessage("The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); + } + /** * {@inheritDoc} */ @@ -117,92 +197,15 @@ public final class CurrencyConverter extends AbstractModule { */ @SuppressFBWarnings(value = "REDOS") private void run(final Mobibot bot, final String sender, final String query) { - if (Utils.isValidString(sender)) { - if (EXCHANGE_RATES.isEmpty()) { - try { - final SAXBuilder builder = new SAXBuilder(); - builder.setIgnoringElementContentWhitespace(true); - - final Document doc = builder.build(new URL(EXCHANGE_TABLE_URL)); - final Element root = doc.getRootElement(); - final Namespace ns = root.getNamespace(""); - final Element cubeRoot = root.getChild("Cube", ns); - final Element cubeTime = cubeRoot.getChild("Cube", ns); - - pubDate = cubeTime.getAttribute("time").getValue(); - - final List cubes = cubeTime.getChildren(); - Element cube; - - for (final Object rawCube : cubes) { - cube = (Element) rawCube; - EXCHANGE_RATES.put( - cube.getAttribute("currency").getValue(), - cube.getAttribute("rate").getValue()); - } - - EXCHANGE_RATES.put("EUR", "1"); - } catch (JDOMException e) { - bot.getLogger().debug("Unable to parse the exchange rates table.", e); - bot.send(sender, "An error has occurred while parsing the exchange rates table."); - } catch (IOException e) { - bot.getLogger().debug("Unable to fetch the exchange rates table.", e); - bot.send(sender, - "An error has occurred while fetching the exchange rates table: " + e.getMessage()); - } - } - - if (EXCHANGE_RATES.isEmpty()) { - bot.getLogger().debug("The exchange rate table is empty."); - bot.send(sender, "Sorry, but the exchange rate table is empty."); - } else if (Utils.isValidString(query)) { - if (!EXCHANGE_RATES.isEmpty()) { - if (query.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+")) { - final String[] cmds = query.split(" "); - - if (cmds.length == 4) { - if (cmds[3].equals(cmds[1]) || cmds[0].equals("0")) { - bot.send(sender, "You're kidding, right?"); - } else { - try { - final double amt = Double.parseDouble(cmds[0].replaceAll(",", "")); - final double from = Double.parseDouble(EXCHANGE_RATES.get(cmds[1].toUpperCase())); - final double to = Double.parseDouble(EXCHANGE_RATES.get(cmds[3].toUpperCase())); - - bot.send(bot.getChannel(), - NumberFormat.getCurrencyInstance(Locale.US).format(amt).substring(1) - + ' ' - + cmds[1].toUpperCase() - + " = " - + NumberFormat.getCurrencyInstance(Locale.US) - .format((amt * to) / from) - .substring(1) - + ' ' - + cmds[3].toUpperCase()); - } catch (NullPointerException ignored) { - bot.send(sender, - "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); - } - } - } - } else if (query.equals(CURRENCY_RATES_KEYWORD)) { - bot.send(sender, "Last Update: " + pubDate); - - final StringBuilder buff = new StringBuilder(0); - - for (final Map.Entry rate : EXCHANGE_RATES.entrySet()) { - if (buff.length() > 0) { - buff.append(", "); - } - buff.append(rate.getKey()).append(": ").append(rate.getValue()); - } - - bot.send(sender, buff.toString()); - } + if (Utils.isValidString(sender) && Utils.isValidString(query)) { + if (query.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ to [a-zA-Z]{3}+")) { + final Message msg = converyCurrency(query.substring(query.indexOf(' '))); + if (msg.isError()) { + helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, true); } + bot.send(msg.isPrivate() ? sender : bot.getChannel(), msg.getMessage()); } else { helpResponse(bot, sender, CURRENCY_CMD + ' ' + query, true); - bot.send(sender, "The supported currencies are: " + EXCHANGE_RATES.keySet().toString()); } } } diff --git a/src/test/java/net/thauvin/erik/mobibot/modules/CurrencyConvertTest.java b/src/test/java/net/thauvin/erik/mobibot/modules/CurrencyConvertTest.java new file mode 100644 index 0000000..9c9238a --- /dev/null +++ b/src/test/java/net/thauvin/erik/mobibot/modules/CurrencyConvertTest.java @@ -0,0 +1,62 @@ +/* + * CurrencyConvertTest.java + * + * Copyright (c) 2004-2019, Erik C. Thauvin (erik@thauvin.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of this project nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.thauvin.erik.mobibot.modules; + +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * The CurrencyConvertTest class. + * + * @author Erik C. Thauvin + * @created 2019-04-07 + * @since 1.0 + */ +public class CurrencyConvertTest { + @Test + public void testLookupImpl() { + AbstractModuleTest.testAbstractModule(new CurrencyConverter()); + } + + @Test + public void testConvertCurrency() { + assertThat(CurrencyConverter.converyCurrency("100 USD to EUR").getMessage()) + .as("100 USD to EUR").startsWith("100.00 USD = "); + assertThat(CurrencyConverter.converyCurrency("100 BLA to USD").isError()) + .as("100 BLA to USD").isTrue(); + assertThat(CurrencyConverter.converyCurrency(CurrencyConverter.CURRENCY_RATES_KEYWORD).isPrivate()) + .as(CurrencyConverter.CURRENCY_RATES_KEYWORD + " is private").isTrue(); + assertThat(CurrencyConverter.converyCurrency(CurrencyConverter.CURRENCY_RATES_KEYWORD).getMessage()) + .as(CurrencyConverter.CURRENCY_RATES_KEYWORD).contains("USD: "); + } +}