diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 00000000..b8ef489f
Binary files /dev/null and b/.DS_Store differ
diff --git a/.gradle/7.3.3/checksums/checksums.lock b/.gradle/7.3.3/checksums/checksums.lock
new file mode 100644
index 00000000..68f7ab5f
Binary files /dev/null and b/.gradle/7.3.3/checksums/checksums.lock differ
diff --git a/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock b/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock
new file mode 100644
index 00000000..59ac938b
Binary files /dev/null and b/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock differ
diff --git a/.gradle/7.3.3/dependencies-accessors/gc.properties b/.gradle/7.3.3/dependencies-accessors/gc.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/.gradle/7.3.3/executionHistory/executionHistory.bin b/.gradle/7.3.3/executionHistory/executionHistory.bin
new file mode 100644
index 00000000..290bbc72
Binary files /dev/null and b/.gradle/7.3.3/executionHistory/executionHistory.bin differ
diff --git a/.gradle/7.3.3/executionHistory/executionHistory.lock b/.gradle/7.3.3/executionHistory/executionHistory.lock
new file mode 100644
index 00000000..899fd081
Binary files /dev/null and b/.gradle/7.3.3/executionHistory/executionHistory.lock differ
diff --git a/.gradle/7.3.3/fileChanges/last-build.bin b/.gradle/7.3.3/fileChanges/last-build.bin
new file mode 100644
index 00000000..f76dd238
Binary files /dev/null and b/.gradle/7.3.3/fileChanges/last-build.bin differ
diff --git a/.gradle/7.3.3/fileHashes/fileHashes.bin b/.gradle/7.3.3/fileHashes/fileHashes.bin
new file mode 100644
index 00000000..c1a7f2f6
Binary files /dev/null and b/.gradle/7.3.3/fileHashes/fileHashes.bin differ
diff --git a/.gradle/7.3.3/fileHashes/fileHashes.lock b/.gradle/7.3.3/fileHashes/fileHashes.lock
new file mode 100644
index 00000000..974b0b24
Binary files /dev/null and b/.gradle/7.3.3/fileHashes/fileHashes.lock differ
diff --git a/.gradle/7.3.3/fileHashes/resourceHashesCache.bin b/.gradle/7.3.3/fileHashes/resourceHashesCache.bin
new file mode 100644
index 00000000..04ac79c9
Binary files /dev/null and b/.gradle/7.3.3/fileHashes/resourceHashesCache.bin differ
diff --git a/.gradle/7.3.3/gc.properties b/.gradle/7.3.3/gc.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 00000000..79ed8824
Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 00000000..a1ebabf9
--- /dev/null
+++ b/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Sat May 11 16:26:17 PDT 2024
+gradle.version=7.3.3
diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 00000000..75624932
Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe
new file mode 100644
index 00000000..88c8a8ff
Binary files /dev/null and b/.gradle/file-system.probe differ
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
new file mode 100644
index 00000000..e69de29b
diff --git a/build/reports/tests/test/css/base-style.css b/build/reports/tests/test/css/base-style.css
new file mode 100644
index 00000000..4afa73e3
--- /dev/null
+++ b/build/reports/tests/test/css/base-style.css
@@ -0,0 +1,179 @@
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: sans-serif;
+ font-size: 12pt;
+}
+
+body, a, a:visited {
+ color: #303030;
+}
+
+#content {
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 30px;
+ padding-bottom: 30px;
+}
+
+#content h1 {
+ font-size: 160%;
+ margin-bottom: 10px;
+}
+
+#footer {
+ margin-top: 100px;
+ font-size: 80%;
+ white-space: nowrap;
+}
+
+#footer, #footer a {
+ color: #a0a0a0;
+}
+
+#line-wrapping-toggle {
+ vertical-align: middle;
+}
+
+#label-for-line-wrapping-toggle {
+ vertical-align: middle;
+}
+
+ul {
+ margin-left: 0;
+}
+
+h1, h2, h3 {
+ white-space: nowrap;
+}
+
+h2 {
+ font-size: 120%;
+}
+
+ul.tabLinks {
+ padding-left: 0;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ overflow: auto;
+ min-width: 800px;
+ width: auto !important;
+ width: 800px;
+}
+
+ul.tabLinks li {
+ float: left;
+ height: 100%;
+ list-style: none;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ margin-bottom: 0;
+ -moz-border-radius: 7px;
+ border-radius: 7px;
+ margin-right: 25px;
+ border: solid 1px #d4d4d4;
+ background-color: #f0f0f0;
+}
+
+ul.tabLinks li:hover {
+ background-color: #fafafa;
+}
+
+ul.tabLinks li.selected {
+ background-color: #c5f0f5;
+ border-color: #c5f0f5;
+}
+
+ul.tabLinks a {
+ font-size: 120%;
+ display: block;
+ outline: none;
+ text-decoration: none;
+ margin: 0;
+ padding: 0;
+}
+
+ul.tabLinks li h2 {
+ margin: 0;
+ padding: 0;
+}
+
+div.tab {
+}
+
+div.selected {
+ display: block;
+}
+
+div.deselected {
+ display: none;
+}
+
+div.tab table {
+ min-width: 350px;
+ width: auto !important;
+ width: 350px;
+ border-collapse: collapse;
+}
+
+div.tab th, div.tab table {
+ border-bottom: solid #d0d0d0 1px;
+}
+
+div.tab th {
+ text-align: left;
+ white-space: nowrap;
+ padding-left: 6em;
+}
+
+div.tab th:first-child {
+ padding-left: 0;
+}
+
+div.tab td {
+ white-space: nowrap;
+ padding-left: 6em;
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+
+div.tab td:first-child {
+ padding-left: 0;
+}
+
+div.tab td.numeric, div.tab th.numeric {
+ text-align: right;
+}
+
+span.code {
+ display: inline-block;
+ margin-top: 0em;
+ margin-bottom: 1em;
+}
+
+span.code pre {
+ font-size: 11pt;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ margin: 0;
+ background-color: #f7f7f7;
+ border: solid 1px #d0d0d0;
+ min-width: 700px;
+ width: auto !important;
+ width: 700px;
+}
+
+span.wrapped pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+label.hidden {
+ display: none;
+}
\ No newline at end of file
diff --git a/build/reports/tests/test/css/style.css b/build/reports/tests/test/css/style.css
new file mode 100644
index 00000000..3dc4913e
--- /dev/null
+++ b/build/reports/tests/test/css/style.css
@@ -0,0 +1,84 @@
+
+#summary {
+ margin-top: 30px;
+ margin-bottom: 40px;
+}
+
+#summary table {
+ border-collapse: collapse;
+}
+
+#summary td {
+ vertical-align: top;
+}
+
+.breadcrumbs, .breadcrumbs a {
+ color: #606060;
+}
+
+.infoBox {
+ width: 110px;
+ padding-top: 15px;
+ padding-bottom: 15px;
+ text-align: center;
+}
+
+.infoBox p {
+ margin: 0;
+}
+
+.counter, .percent {
+ font-size: 120%;
+ font-weight: bold;
+ margin-bottom: 8px;
+}
+
+#duration {
+ width: 125px;
+}
+
+#successRate, .summaryGroup {
+ border: solid 2px #d0d0d0;
+ -moz-border-radius: 10px;
+ border-radius: 10px;
+}
+
+#successRate {
+ width: 140px;
+ margin-left: 35px;
+}
+
+#successRate .percent {
+ font-size: 180%;
+}
+
+.success, .success a {
+ color: #008000;
+}
+
+div.success, #successRate.success {
+ background-color: #bbd9bb;
+ border-color: #008000;
+}
+
+.failures, .failures a {
+ color: #b60808;
+}
+
+.skipped, .skipped a {
+ color: #c09853;
+}
+
+div.failures, #successRate.failures {
+ background-color: #ecdada;
+ border-color: #b60808;
+}
+
+ul.linkList {
+ padding-left: 0;
+}
+
+ul.linkList li {
+ list-style: none;
+ margin-bottom: 5px;
+}
diff --git a/build/reports/tests/test/index.html b/build/reports/tests/test/index.html
new file mode 100644
index 00000000..131eb52b
--- /dev/null
+++ b/build/reports/tests/test/index.html
@@ -0,0 +1,145 @@
+
+
+
+
+
+Test results - Test Summary
+
+
+
+
+
+
+
Test Summary
+
+
+
+
+
+
+
+|
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
diff --git a/build/reports/tests/test/js/report.js b/build/reports/tests/test/js/report.js
new file mode 100644
index 00000000..83bab4a1
--- /dev/null
+++ b/build/reports/tests/test/js/report.js
@@ -0,0 +1,194 @@
+(function (window, document) {
+ "use strict";
+
+ var tabs = {};
+
+ function changeElementClass(element, classValue) {
+ if (element.getAttribute("className")) {
+ element.setAttribute("className", classValue);
+ } else {
+ element.setAttribute("class", classValue);
+ }
+ }
+
+ function getClassAttribute(element) {
+ if (element.getAttribute("className")) {
+ return element.getAttribute("className");
+ } else {
+ return element.getAttribute("class");
+ }
+ }
+
+ function addClass(element, classValue) {
+ changeElementClass(element, getClassAttribute(element) + " " + classValue);
+ }
+
+ function removeClass(element, classValue) {
+ changeElementClass(element, getClassAttribute(element).replace(classValue, ""));
+ }
+
+ function initTabs() {
+ var container = document.getElementById("tabs");
+
+ tabs.tabs = findTabs(container);
+ tabs.titles = findTitles(tabs.tabs);
+ tabs.headers = findHeaders(container);
+ tabs.select = select;
+ tabs.deselectAll = deselectAll;
+ tabs.select(0);
+
+ return true;
+ }
+
+ function getCheckBox() {
+ return document.getElementById("line-wrapping-toggle");
+ }
+
+ function getLabelForCheckBox() {
+ return document.getElementById("label-for-line-wrapping-toggle");
+ }
+
+ function findCodeBlocks() {
+ var spans = document.getElementById("tabs").getElementsByTagName("span");
+ var codeBlocks = [];
+ for (var i = 0; i < spans.length; ++i) {
+ if (spans[i].className.indexOf("code") >= 0) {
+ codeBlocks.push(spans[i]);
+ }
+ }
+ return codeBlocks;
+ }
+
+ function forAllCodeBlocks(operation) {
+ var codeBlocks = findCodeBlocks();
+
+ for (var i = 0; i < codeBlocks.length; ++i) {
+ operation(codeBlocks[i], "wrapped");
+ }
+ }
+
+ function toggleLineWrapping() {
+ var checkBox = getCheckBox();
+
+ if (checkBox.checked) {
+ forAllCodeBlocks(addClass);
+ } else {
+ forAllCodeBlocks(removeClass);
+ }
+ }
+
+ function initControls() {
+ if (findCodeBlocks().length > 0) {
+ var checkBox = getCheckBox();
+ var label = getLabelForCheckBox();
+
+ checkBox.onclick = toggleLineWrapping;
+ checkBox.checked = false;
+
+ removeClass(label, "hidden");
+ }
+ }
+
+ function switchTab() {
+ var id = this.id.substr(1);
+
+ for (var i = 0; i < tabs.tabs.length; i++) {
+ if (tabs.tabs[i].id === id) {
+ tabs.select(i);
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ function select(i) {
+ this.deselectAll();
+
+ changeElementClass(this.tabs[i], "tab selected");
+ changeElementClass(this.headers[i], "selected");
+
+ while (this.headers[i].firstChild) {
+ this.headers[i].removeChild(this.headers[i].firstChild);
+ }
+
+ var h2 = document.createElement("H2");
+
+ h2.appendChild(document.createTextNode(this.titles[i]));
+ this.headers[i].appendChild(h2);
+ }
+
+ function deselectAll() {
+ for (var i = 0; i < this.tabs.length; i++) {
+ changeElementClass(this.tabs[i], "tab deselected");
+ changeElementClass(this.headers[i], "deselected");
+
+ while (this.headers[i].firstChild) {
+ this.headers[i].removeChild(this.headers[i].firstChild);
+ }
+
+ var a = document.createElement("A");
+
+ a.setAttribute("id", "ltab" + i);
+ a.setAttribute("href", "#tab" + i);
+ a.onclick = switchTab;
+ a.appendChild(document.createTextNode(this.titles[i]));
+
+ this.headers[i].appendChild(a);
+ }
+ }
+
+ function findTabs(container) {
+ return findChildElements(container, "DIV", "tab");
+ }
+
+ function findHeaders(container) {
+ var owner = findChildElements(container, "UL", "tabLinks");
+ return findChildElements(owner[0], "LI", null);
+ }
+
+ function findTitles(tabs) {
+ var titles = [];
+
+ for (var i = 0; i < tabs.length; i++) {
+ var tab = tabs[i];
+ var header = findChildElements(tab, "H2", null)[0];
+
+ header.parentNode.removeChild(header);
+
+ if (header.innerText) {
+ titles.push(header.innerText);
+ } else {
+ titles.push(header.textContent);
+ }
+ }
+
+ return titles;
+ }
+
+ function findChildElements(container, name, targetClass) {
+ var elements = [];
+ var children = container.childNodes;
+
+ for (var i = 0; i < children.length; i++) {
+ var child = children.item(i);
+
+ if (child.nodeType === 1 && child.nodeName === name) {
+ if (targetClass && child.className.indexOf(targetClass) < 0) {
+ continue;
+ }
+
+ elements.push(child);
+ }
+ }
+
+ return elements;
+ }
+
+ // Entry point.
+
+ window.onload = function() {
+ initTabs();
+ initControls();
+ };
+} (window, window.document));
\ No newline at end of file
diff --git a/build/reports/tests/test/packages/org.jointheleague.features.GooBotTests.html b/build/reports/tests/test/packages/org.jointheleague.features.GooBotTests.html
new file mode 100644
index 00000000..7f61e8a4
--- /dev/null
+++ b/build/reports/tests/test/packages/org.jointheleague.features.GooBotTests.html
@@ -0,0 +1,115 @@
+
+
+
+
+
+Test results - Package org.jointheleague.features.GooBotTests
+
+
+
+
+
+
+
Package org.jointheleague.features.GooBotTests
+
+
all > org.jointheleague.features.GooBotTests
+
+
+
+
+
+
+
+|
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
diff --git a/build/test-results/test/binary/output.bin b/build/test-results/test/binary/output.bin
new file mode 100644
index 00000000..e69de29b
diff --git a/build/test-results/test/binary/output.bin.idx b/build/test-results/test/binary/output.bin.idx
new file mode 100644
index 00000000..f76dd238
Binary files /dev/null and b/build/test-results/test/binary/output.bin.idx differ
diff --git a/build/test-results/test/binary/results.bin b/build/test-results/test/binary/results.bin
new file mode 100644
index 00000000..a1a8d343
Binary files /dev/null and b/build/test-results/test/binary/results.bin differ
diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin
new file mode 100644
index 00000000..e1162727
Binary files /dev/null and b/build/tmp/compileJava/previous-compilation-data.bin differ
diff --git a/build/tmp/compileTestJava/previous-compilation-data.bin b/build/tmp/compileTestJava/previous-compilation-data.bin
new file mode 100644
index 00000000..31fa3a66
Binary files /dev/null and b/build/tmp/compileTestJava/previous-compilation-data.bin differ
diff --git a/src/.DS_Store b/src/.DS_Store
new file mode 100644
index 00000000..5008ddfc
Binary files /dev/null and b/src/.DS_Store differ
diff --git a/src/main/java/org/jointheleague/discord_bot/DiscordBot.java b/src/main/java/org/jointheleague/discord_bot/DiscordBot.java
index ae863505..1a6378a7 100644
--- a/src/main/java/org/jointheleague/discord_bot/DiscordBot.java
+++ b/src/main/java/org/jointheleague/discord_bot/DiscordBot.java
@@ -3,12 +3,14 @@
import org.javacord.api.DiscordApi;
import org.javacord.api.DiscordApiBuilder;
import org.javacord.api.entity.intent.Intent;
+import org.jointheleague.features.GooBotFeatures.Calculator;
+import org.jointheleague.features.GooBotFeatures.RandomWordGenerator;
import org.jointheleague.features.abstract_classes.Feature;
+import org.jointheleague.features.GooBotFeatures.Greeting;
import org.jointheleague.features.examples.second_features.HighLowGame;
import org.jointheleague.features.examples.third_features.CatFactsApi;
import org.jointheleague.features.examples.third_features.NewsApi;
import org.jointheleague.features.examples.first_features.CurrentTime;
-import org.jointheleague.features.examples.first_features.RandomNumber;
import org.jointheleague.features.help_embed.HelpListener;
import org.jointheleague.features.student.first_feature.FeatureOne;
@@ -45,11 +47,14 @@ public void connect(boolean printInvite) {
api.addMessageCreateListener(helpListener);
//add features
+ addFeature(new Calculator(channelName));
+ addFeature(new Greeting(channelName));
addFeature(new FeatureOne(channelName));
addFeature(new CurrentTime(channelName));
addFeature(new HighLowGame(channelName));
addFeature(new NewsApi(channelName));
addFeature(new CatFactsApi(channelName));
+ addFeature(new RandomWordGenerator(channelName));
}
private void addFeature(Feature feature){
diff --git a/src/main/java/org/jointheleague/features/GooBotFeatures/Calculator.java b/src/main/java/org/jointheleague/features/GooBotFeatures/Calculator.java
new file mode 100644
index 00000000..8b17f452
--- /dev/null
+++ b/src/main/java/org/jointheleague/features/GooBotFeatures/Calculator.java
@@ -0,0 +1,80 @@
+package org.jointheleague.features.GooBotFeatures;
+
+import org.javacord.api.event.message.MessageCreateEvent;
+import org.jointheleague.features.abstract_classes.Feature;
+import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed;
+
+import java.lang.Math;
+
+public class Calculator extends Feature {
+
+ public final String COMMAND = "!calculator";
+ public static double answer;
+
+ public Calculator(String channelName) {
+ super(channelName);
+
+ //Create a help embed to describe feature when !help command is sent
+ helpEmbed = new HelpEmbed(COMMAND, "Give GooBot a number, an operation symbol, and" +
+ "another number, and GooBot will perform the operation for you! This includes: +, x, /, " +
+ "-, ^, %. Please have normal spacing in the operation provided. Have fun! Eg: !Calculator 55 + 12");
+ }
+
+ @Override
+ public void handle(MessageCreateEvent event) {
+ String messageContent = event.getMessageContent();
+ int num1;
+ String op;
+ int num2;
+ //respond to message here
+ if (messageContent.startsWith(COMMAND)) {
+ int index1 = messageContent.indexOf(",");
+ int index2 = messageContent.indexOf(",", index1 + 1);
+ String[] seperatedParts = messageContent.split(" ");
+ if (seperatedParts.length > 3) {
+ num1 = Integer.parseInt(seperatedParts[1]);
+ num2 = Integer.parseInt(seperatedParts[3]);
+ op = seperatedParts[2];
+ answer = calculate(event, num1, num2, op);
+ event.getChannel().sendMessage("I got the answer! It is... " + answer);
+ } else {
+ event.getChannel().sendMessage("Sorry, we've ran into an error. To be specific, the operation" +
+ " entered in seemed to not have properly processed, meaning you may have forgotten the correct amount" +
+ " of spaces or entered something else incorrect for the required format. Check in with the example" +
+ " at the !help section to make sure you entered your operation in correctly!");
+ }
+ }
+ }
+
+ public static double calculate(MessageCreateEvent event, double num1, double num2, String Op2) {
+ answer = 0;
+ switch (Op2) {
+ case "+":
+ answer = num1 + num2;
+ break;
+
+ case "-":
+ answer = num1 - num2;
+ break;
+
+ case "/":
+ answer = (double) num1 / num2;
+ break;
+
+ case "x":
+ answer = num1 * num2;
+ break;
+
+ case "^":
+ answer = Math.pow(num1, num2);
+ break;
+
+ case "%":
+ answer = num1 % num2;
+ break;
+
+ }
+ return answer;
+ }
+}
+
diff --git a/src/main/java/org/jointheleague/features/GooBotFeatures/Greeting.java b/src/main/java/org/jointheleague/features/GooBotFeatures/Greeting.java
new file mode 100644
index 00000000..d596acd7
--- /dev/null
+++ b/src/main/java/org/jointheleague/features/GooBotFeatures/Greeting.java
@@ -0,0 +1,35 @@
+package org.jointheleague.features.GooBotFeatures;
+
+import org.javacord.api.event.message.MessageCreateEvent;
+import org.jointheleague.features.abstract_classes.Feature;
+import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+public class Greeting extends Feature {
+
+ public final String COMMAND = "!greeting";
+
+ public Greeting(String channelName) {
+ super(channelName);
+
+ //Create a help embed to describe feature when !help command is sent
+ helpEmbed = new HelpEmbed(COMMAND, "Says hello in a kind, thoughtful way");
+ }
+
+ @Override
+ public void handle(MessageCreateEvent event) {
+ String messageContent = event.getMessageContent();
+ Random ran = new Random();
+ ArrayList responses = new ArrayList();
+ responses.add("Good day to you! I’m GooBot.");
+ responses.add("Pleased to meet you. My name is GooBot");
+ responses.add("How are you? I hope you are doing well. I'm GoodBot by the way");
+ if (messageContent.startsWith(COMMAND)) {
+ //respond to message here
+ event.getChannel().sendMessage(responses.get(ran.nextInt(3)));
+ }
+ }
+
+}
diff --git a/src/main/java/org/jointheleague/features/GooBotFeatures/RandomWordGenerator.java b/src/main/java/org/jointheleague/features/GooBotFeatures/RandomWordGenerator.java
new file mode 100644
index 00000000..25234454
--- /dev/null
+++ b/src/main/java/org/jointheleague/features/GooBotFeatures/RandomWordGenerator.java
@@ -0,0 +1,76 @@
+package org.jointheleague.features.GooBotFeatures;
+
+import org.jointheleague.features.GooBotFeatures.RandomWordWrapper;
+
+import org.javacord.api.event.message.MessageCreateEvent;
+import org.jointheleague.features.abstract_classes.Feature;
+import org.jointheleague.features.examples.third_features.plain_old_java_objects.cat_facts_api.CatWrapper;
+import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Scanner;
+
+public class RandomWordGenerator extends Feature {
+
+
+ public final String COMMAND = "!CoolWord";
+
+ private WebClient webClient;
+ private static final String baseUrl = "https://random-word-api.herokuapp.com/word";
+ private URL url;
+
+ public RandomWordGenerator(String channelName) {
+ super(channelName);
+ helpEmbed = new HelpEmbed(COMMAND, "This will use an API to grab a random word from any abbreviated language" +
+ "you put in!");
+
+ //build the WebClient
+
+ try {
+ url = new URL(baseUrl);
+ } catch (MalformedURLException e) {
+ System.out.println("Error of Malformed URL Exception:" + e.getStackTrace());
+ }
+
+ }
+
+ @Override
+ public void handle(MessageCreateEvent event) {
+ String messageContent = event.getMessageContent();
+ if (messageContent.startsWith(COMMAND)) {
+ String coolWord = getCoolWord();
+ event.getChannel().sendMessage("Here is your special word: " + coolWord);
+ }
+ }
+
+ public String getCoolWord() {
+ String word = "error";
+ try {
+ URLConnection con = url.openConnection();
+ InputStream is = con.getInputStream();
+ String encoding = con.getContentEncoding();
+ encoding = encoding == null ? "UTF-8" : encoding;
+ Scanner s = new Scanner(is);
+ word = s.next();
+ is.close();
+ s.close();
+ word = word.substring(1, word.length()-1);
+ } catch (IOException e) {
+ System.out.print("Here is the error: + " + e.getStackTrace());
+ }
+ return word;
+ }
+
+ public void setWebClient(WebClient webClient) {
+ this.webClient = webClient;
+ }
+
+}
+
+
diff --git a/src/main/java/org/jointheleague/features/GooBotFeatures/RandomWordWrapper.java b/src/main/java/org/jointheleague/features/GooBotFeatures/RandomWordWrapper.java
new file mode 100644
index 00000000..0b355d84
--- /dev/null
+++ b/src/main/java/org/jointheleague/features/GooBotFeatures/RandomWordWrapper.java
@@ -0,0 +1,23 @@
+package org.jointheleague.features.GooBotFeatures;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+public class RandomWordWrapper {
+
+ @SerializedName("data")
+ @Expose
+
+ private List data = null;
+
+ public List getData() {
+ return data;
+ }
+
+ public void setData(List data) {
+ this.data = data;
+ }
+
+}
diff --git a/src/main/java/org/jointheleague/features/templates/FeatureTemplate.java b/src/main/java/org/jointheleague/features/templates/FeatureTemplate.java
index f141564d..5792e955 100644
--- a/src/main/java/org/jointheleague/features/templates/FeatureTemplate.java
+++ b/src/main/java/org/jointheleague/features/templates/FeatureTemplate.java
@@ -12,10 +12,7 @@ public FeatureTemplate(String channelName) {
super(channelName);
//Create a help embed to describe feature when !help command is sent
- helpEmbed = new HelpEmbed(
- COMMAND,
- "Give a brief description of your feature here, including how the user interacts with it"
- );
+ helpEmbed = new HelpEmbed(COMMAND, "");
}
@Override
@@ -23,7 +20,7 @@ public void handle(MessageCreateEvent event) {
String messageContent = event.getMessageContent();
if (messageContent.startsWith(COMMAND)) {
//respond to message here
- event.getChannel().sendMessage("Sending a message to the channel");
+ event.getChannel().sendMessage("");
}
}
diff --git a/src/test/java/org/jointheleague/features/GooBotTests/CalculatorTest.java b/src/test/java/org/jointheleague/features/GooBotTests/CalculatorTest.java
new file mode 100644
index 00000000..3d59bc20
--- /dev/null
+++ b/src/test/java/org/jointheleague/features/GooBotTests/CalculatorTest.java
@@ -0,0 +1,205 @@
+package org.jointheleague.features.GooBotTests;
+
+import org.javacord.api.DiscordApi;
+import org.javacord.api.entity.channel.TextChannel;
+import org.javacord.api.entity.emoji.Emoji;
+import org.javacord.api.entity.message.Message;
+import org.javacord.api.entity.message.embed.EmbedBuilder;
+import org.javacord.api.entity.server.Server;
+import org.javacord.api.entity.user.User;
+import org.javacord.api.event.message.MessageCreateEvent;
+import org.jointheleague.features.GooBotFeatures.Calculator;
+import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import javax.swing.*;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+
+public class CalculatorTest {
+ private final String testChannelName = "calculator";
+ private final Calculator calculator = new Calculator(testChannelName);
+
+ private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ private final PrintStream originalOut = System.out;
+
+ @Mock
+ private MessageCreateEvent messageCreateEvent;
+
+ @Mock
+ private TextChannel textChannel;
+
+ double num1 = 5;
+
+ double num2 = 7;
+
+ String multiply = "x";
+ String divide = "/";
+ String subtract = "-";
+ String add = "+";
+ String modulo = "%";
+ String exponent = "^";
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ System.setOut(new PrintStream(outContent));
+ }
+
+ @AfterEach
+ public void itShouldNotPrintToSystemOut() {
+ String expected = "";
+ String actual = outContent.toString();
+
+ assertEquals(expected, actual);
+ System.setOut(originalOut);
+ }
+
+ @Test
+ void itShouldHaveACommand() {
+ //Given
+
+ //When
+ String command = calculator.COMMAND;
+
+ //Then
+
+ assertNotEquals("", command);
+ assertNotEquals("!", command);
+ assertNotEquals("!command", command);
+ assertEquals('!', command.charAt(0));
+ assertNotNull(command);
+ }
+
+ @Test
+ void itShouldHandleMessagesWithCommand() {
+ //Given
+ HelpEmbed helpEmbed = new HelpEmbed(calculator.COMMAND, "test");
+ when(messageCreateEvent.getMessageContent()).thenReturn(calculator.COMMAND);
+ when(messageCreateEvent.getChannel()).thenReturn((textChannel));
+
+ //When
+ calculator.handle(messageCreateEvent);
+
+ //Then
+ verify(textChannel, times(1)).sendMessage(anyString());
+ }
+
+ @Test
+ void itShouldNotHandleMessagesWithoutCommand() {
+ //Given
+ String command = "";
+ when(messageCreateEvent.getMessageContent()).thenReturn(command);
+
+ //When
+ calculator.handle(messageCreateEvent);
+
+ //Then
+ verify(textChannel, never()).sendMessage("");
+ }
+
+ @Test
+ void itShouldHaveAHelpEmbed() {
+ //Given
+
+ //When
+ HelpEmbed actualHelpEmbed = calculator.getHelpEmbed();
+
+ //Then
+ assertNotNull(actualHelpEmbed);
+ }
+
+ @Test
+ void itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed() {
+ //Given
+
+ //When
+ String helpEmbedTitle = calculator.getHelpEmbed().getTitle();
+ String command = calculator.COMMAND;
+
+ //Then
+ assertEquals(command, helpEmbedTitle);
+ }
+
+ @Test
+ void itShouldMultiply() {
+ //Test Multiply
+ when(messageCreateEvent.getMessageContent()).thenReturn("!Calculator 5,x,7");
+ calculator.calculate(messageCreateEvent, num1, num2, multiply);
+
+ double expected = 35;
+ double actual = calculator.answer;
+ assertEquals(expected, actual, 0);
+ }
+
+ @Test
+ void itShouldAdd() {
+ //Test Add
+ when(messageCreateEvent.getMessageContent()).thenReturn("!Calculator 5,+,7");
+ calculator.calculate(messageCreateEvent, num1, num2, add);
+
+ double expected = 12;
+ double actual = calculator.answer;
+ assertEquals(expected, actual, 0);
+ }
+
+ @Test
+ void itShouldSubtract() {
+ //Test Subtract
+ when(messageCreateEvent.getMessageContent()).thenReturn("!Calculator 5,-,7");
+ calculator.calculate(messageCreateEvent, num1, num2, subtract);
+
+ double expected = -2;
+ double actual = calculator.answer;
+ assertEquals(expected, actual, 0);
+ }
+
+ @Test
+ void itShouldDivide() {
+ //Test Divide
+ when(messageCreateEvent.getMessageContent()).thenReturn("!Calculator 5,/,7");
+ calculator.calculate(messageCreateEvent, num1, num2, divide);
+
+ double expected = 0.7142857143;
+ double actual = calculator.answer;
+ assertEquals(expected, actual, 0.1);
+ }
+
+ @Test
+ void itShouldExponentiate() {
+ //Test Exponentiation
+ when(messageCreateEvent.getMessageContent()).thenReturn("!Calculator 5,^,7");
+ calculator.calculate(messageCreateEvent, num1, num2, exponent);
+
+ double expected = 78125.0;
+ double actual = calculator.answer;
+ assertEquals(expected, actual, 0);
+
+ }
+
+ @Test
+ void itShouldUseModulo() {
+ //Test Modulo Ability
+ when(messageCreateEvent.getMessageContent()).thenReturn("!calculator 5,%,7");
+ calculator.calculate(messageCreateEvent, num1, num2, modulo);
+ double expected = 5;
+ double actual = calculator.answer;
+ assertEquals(expected, actual, 0);
+
+ }
+
+
+}
diff --git a/src/test/java/org/jointheleague/features/GooBotTests/GreetingTest.java b/src/test/java/org/jointheleague/features/GooBotTests/GreetingTest.java
new file mode 100644
index 00000000..e21dd32d
--- /dev/null
+++ b/src/test/java/org/jointheleague/features/GooBotTests/GreetingTest.java
@@ -0,0 +1,120 @@
+package org.jointheleague.features.GooBotTests;
+
+import org.javacord.api.entity.channel.TextChannel;
+import org.javacord.api.event.message.MessageCreateEvent;
+import org.jointheleague.features.abstract_classes.Feature;
+import org.jointheleague.features.GooBotFeatures.Greeting;
+import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+
+public class GreetingTest {
+ private final String testChannelName = "Greeting";
+ private final Greeting greeting = new Greeting(testChannelName);
+
+ private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ private final PrintStream originalOut = System.out;
+
+ @Mock
+ private MessageCreateEvent messageCreateEvent;
+
+ @Mock
+ private TextChannel textChannel;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ System.setOut(new PrintStream(outContent));
+ }
+
+ @AfterEach
+ public void itShouldNotPrintToSystemOut() {
+ String expected = "";
+ String actual = outContent.toString();
+
+ assertEquals(expected, actual);
+ System.setOut(originalOut);
+ }
+
+ @Test
+ void itShouldHaveACommand() {
+ //Given
+
+ //When
+ String command = greeting.COMMAND;
+
+ //Then
+ if (!(greeting instanceof Feature)) {
+ assertNotEquals("!command", command);
+ }
+
+ assertNotEquals("", command);
+ assertNotEquals("!", command);
+ assertNotEquals("!command", command);
+ assertEquals('!', command.charAt(0));
+ assertNotNull(command);
+ }
+
+ @Test
+ void itShouldHandleMessagesWithCommand() {
+ //Given
+ HelpEmbed helpEmbed = new HelpEmbed(greeting.COMMAND, "test");
+ when(messageCreateEvent.getMessageContent()).thenReturn(greeting.COMMAND);
+ when(messageCreateEvent.getChannel()).thenReturn((textChannel));
+
+ //When
+ greeting.handle(messageCreateEvent);
+
+ //Then
+ verify(textChannel, times(1)).sendMessage(anyString());
+ }
+
+ @Test
+ void itShouldNotHandleMessagesWithoutCommand() {
+ //Given
+ String command = "";
+ when(messageCreateEvent.getMessageContent()).thenReturn(command);
+
+ //When
+ greeting.handle(messageCreateEvent);
+
+ //Then
+ verify(textChannel, never()).sendMessage("");
+ }
+
+ @Test
+ void itShouldHaveAHelpEmbed() {
+ //Given
+
+ //When
+ HelpEmbed actualHelpEmbed = greeting.getHelpEmbed();
+
+ //Then
+ assertNotNull(actualHelpEmbed);
+ }
+
+ @Test
+ void itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed() {
+ //Given
+
+ //When
+ String helpEmbedTitle = greeting.getHelpEmbed().getTitle();
+ String command = greeting.COMMAND;
+
+ //Then
+ assertEquals(command, helpEmbedTitle);
+ }
+
+}
diff --git a/src/test/java/org/jointheleague/features/GooBotTests/RandomWordGeneratorApiTest.java b/src/test/java/org/jointheleague/features/GooBotTests/RandomWordGeneratorApiTest.java
new file mode 100644
index 00000000..daa3b3b5
--- /dev/null
+++ b/src/test/java/org/jointheleague/features/GooBotTests/RandomWordGeneratorApiTest.java
@@ -0,0 +1,153 @@
+package org.jointheleague.features.GooBotTests;
+
+import org.javacord.api.entity.channel.TextChannel;
+import org.javacord.api.event.message.MessageCreateEvent;
+import org.jointheleague.features.GooBotFeatures.RandomWordGenerator;
+import org.jointheleague.features.GooBotFeatures.RandomWordWrapper;
+import org.jointheleague.features.examples.third_features.plain_old_java_objects.cat_facts_api.CatWrapper;
+import org.jointheleague.features.help_embed.plain_old_java_objects.help_embed.HelpEmbed;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.mockito.Mockito.*;
+
+public class RandomWordGeneratorApiTest {
+
+ private final String testChannelName = "test";
+ private RandomWordGenerator RandomWordGenerator;
+
+ private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+ private final PrintStream originalOut = System.out;
+
+ @Mock
+ private MessageCreateEvent messageCreateEvent;
+
+ @Mock
+ private TextChannel textChannel;
+
+ @Mock
+ WebClient webClientMock;
+
+ @Mock
+ WebClient.RequestHeadersUriSpec requestHeadersUriSpecMock;
+
+ @Mock
+ WebClient.RequestHeadersSpec requestHeadersSpecMock;
+
+ @Mock
+ WebClient.ResponseSpec responseSpecMock;
+
+ @Mock
+ Mono RandomWordWrapperMock;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+
+ RandomWordGenerator = new RandomWordGenerator(testChannelName);
+ RandomWordGenerator.setWebClient(webClientMock);
+ System.setOut(new PrintStream(outContent));
+ }
+
+ @AfterEach
+ public void itShouldNotPrintToSystemOut() {
+ String expected = "";
+ String actual = outContent.toString();
+
+ assertEquals(expected, actual);
+ System.setOut(originalOut);
+ }
+
+
+ @Test
+ void itShouldHaveACommand() {
+ //Given
+
+ //When
+ String command = RandomWordGenerator.COMMAND;
+
+ //Then
+ assertNotEquals("", command);
+ assertNotEquals("!command", command);
+ assertNotNull(command);
+ }
+
+ @Test
+ void itShouldHaveAHelpEmbed() {
+ //Given
+
+ //When
+ HelpEmbed actualHelpEmbed = RandomWordGenerator.getHelpEmbed();
+
+ //Then
+ assertNotNull(actualHelpEmbed);
+ }
+
+ @Test
+ void itShouldHaveTheCommandAsTheTitleOfTheHelpEmbed() {
+ //Given
+
+ //When
+ String helpEmbedTitle = RandomWordGenerator.getHelpEmbed().getTitle();
+ String command = RandomWordGenerator.COMMAND;
+
+ //Then
+ assertEquals(command, helpEmbedTitle);
+ }
+
+ @Test
+ void givenMessageWithCommand_whenHandle_thenSendRandomWord() {
+ //given
+ String word = "Quizzical";
+ List data = Collections.singletonList(word);
+
+ RandomWordWrapper RandomWordWrapper = new RandomWordWrapper();
+ RandomWordWrapper.setData(data);
+
+ when(messageCreateEvent.getMessageContent()).thenReturn(RandomWordGenerator.COMMAND);
+ when(messageCreateEvent.getChannel()).thenReturn(textChannel);
+
+ when(webClientMock.get())
+ .thenReturn(requestHeadersUriSpecMock);
+ when(requestHeadersUriSpecMock.retrieve())
+ .thenReturn(responseSpecMock);
+ when(responseSpecMock.bodyToMono(RandomWordWrapper.class))
+ .thenReturn(RandomWordWrapperMock);
+ when(RandomWordWrapperMock.block())
+ .thenReturn(RandomWordWrapper);
+
+ //when
+ RandomWordGenerator.handle(messageCreateEvent);
+
+ //then
+ verify(webClientMock, times(1)).get();
+ verify(textChannel, times(1)).sendMessage(word);
+ }
+
+ @Test
+ void givenMessageWithoutCommand_whenHandle_thenDoNothing() {
+ //Given
+ String command = "";
+ when(messageCreateEvent.getMessageContent()).thenReturn(command);
+
+ //When
+ RandomWordGenerator.handle(messageCreateEvent);
+
+ //Then
+ verify(textChannel, never()).sendMessage("");
+ }
+
+}
\ No newline at end of file