Cleaned up code

This commit is contained in:
Erik C. Thauvin 2023-11-01 22:02:54 -07:00
parent d700aa06df
commit 4c90870f4a
61 changed files with 496 additions and 481 deletions

View file

@ -63,7 +63,7 @@ object Constants {
* User-Agent * User-Agent
*/ */
const val USER_AGENT = const val USER_AGENT =
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"
/** /**
* The help command. * The help command.

View file

@ -97,9 +97,9 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
event.sendMessage("Type a URL on $channel to post it.") event.sendMessage("Type a URL on $channel to post it.")
event.sendMessage("For more information on a specific command, type:") event.sendMessage("For more information on a specific command, type:")
event.sendMessage( event.sendMessage(
helpFormat( helpFormat(
helpCmdSyntax("%c ${Constants.HELP_CMD} <command>", event.bot().nick, event is PrivateMessageEvent) helpCmdSyntax("%c ${Constants.HELP_CMD} <command>", event.bot().nick, event is PrivateMessageEvent)
) )
) )
event.sendMessage("The commands are:") event.sendMessage("The commands are:")
event.sendList(addons.names.commands, 8, isBold = true, isIndent = true) event.sendList(addons.names.commands, 8, isBold = true, isIndent = true)
@ -161,7 +161,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
with(event.getBot<PircBotX>()) { with(event.getBot<PircBotX>()) {
if (user.nick == nick) { if (user.nick == nick) {
LinksManager.socialManager.notification( LinksManager.socialManager.notification(
"$nick has joined ${event.channel.name} on $serverHostname" "$nick has joined ${event.channel.name} on $serverHostname"
) )
seen.add(userChannelDao.getChannel(channel).users) seen.add(userChannelDao.getChannel(channel).users)
} else { } else {
@ -209,7 +209,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
with(event.getBot<PircBotX>()) { with(event.getBot<PircBotX>()) {
if (user.nick == nick) { if (user.nick == nick) {
LinksManager.socialManager.notification( LinksManager.socialManager.notification(
"$nick has left ${event.channel.name} on $serverHostname" "$nick has left ${event.channel.name} on $serverHostname"
) )
seen.add(userChannelDao.getChannel(channel).users) seen.add(userChannelDao.getChannel(channel).users)
} else { } else {
@ -232,22 +232,22 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
// Set up the command line options // Set up the command line options
val parser = ArgParser(Constants.CLI_CMD) val parser = ArgParser(Constants.CLI_CMD)
val debug by parser.option( val debug by parser.option(
ArgType.Boolean, ArgType.Boolean,
Constants.DEBUG_ARG, Constants.DEBUG_ARG,
Constants.DEBUG_ARG.substring(0, 1), Constants.DEBUG_ARG.substring(0, 1),
"Print debug & logging data directly to the console" "Print debug & logging data directly to the console"
).default(false) ).default(false)
val property by parser.option( val property by parser.option(
ArgType.String, ArgType.String,
Constants.PROPS_ARG, Constants.PROPS_ARG,
Constants.PROPS_ARG.substring(0, 1), Constants.PROPS_ARG.substring(0, 1),
"Use alternate properties file" "Use alternate properties file"
).default("./${ReleaseInfo.PROJECT}.properties") ).default("./${ReleaseInfo.PROJECT}.properties")
val version by parser.option( val version by parser.option(
ArgType.Boolean, ArgType.Boolean,
Constants.VERSION_ARG, Constants.VERSION_ARG,
Constants.VERSION_ARG.substring(0, 1), Constants.VERSION_ARG.substring(0, 1),
"Print version info" "Print version info"
).default(false) ).default(false)
// Parse the command line // Parse the command line
@ -256,8 +256,8 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
if (version) { if (version) {
// Output the version // Output the version
println( println(
"${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" + "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION}" +
" (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})" " (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})"
) )
println(ReleaseInfo.WEBSITE) println(ReleaseInfo.WEBSITE)
} else { } else {
@ -265,7 +265,7 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
val p = Properties() val p = Properties()
try { try {
Files.newInputStream( Files.newInputStream(
Paths.get(property) Paths.get(property)
).use { fis -> ).use { fis ->
p.load(fis) p.load(fis)
} }
@ -284,11 +284,11 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
if (!debug) { if (!debug) {
try { try {
val stdout = PrintStream( val stdout = PrintStream(
BufferedOutputStream( BufferedOutputStream(
FileOutputStream( FileOutputStream(
logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true logsDir + channel.substring(1) + '.' + Utils.today() + ".log", true
) )
), true ), true
) )
System.setOut(stdout) System.setOut(stdout)
} catch (ignore: IOException) { } catch (ignore: IOException) {
@ -297,9 +297,9 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
} }
try { try {
val stderr = PrintStream( val stderr = PrintStream(
BufferedOutputStream( BufferedOutputStream(
FileOutputStream("$logsDir$nickname.err", true) FileOutputStream("$logsDir$nickname.err", true)
), true ), true
) )
System.setErr(stderr) System.setErr(stderr)
} catch (ignore: IOException) { } catch (ignore: IOException) {
@ -324,8 +324,8 @@ class Mobibot(nickname: String, val channel: String, logsDirPath: String, p: Pro
login = p.getProperty("login", nickname) login = p.getProperty("login", nickname)
realName = p.getProperty("realname", nickname) realName = p.getProperty("realname", nickname)
addServer( addServer(
ircServer, ircServer,
p.getIntProperty("port", Constants.DEFAULT_PORT) p.getIntProperty("port", Constants.DEFAULT_PORT)
) )
addAutoJoinChannel(channel) addAutoJoinChannel(channel)
addListener(this@Mobibot) addListener(this@Mobibot)

View file

@ -92,7 +92,7 @@ class Pinboard {
*/ */
private fun Date.toTimestamp(): String { private fun Date.toTimestamp(): String {
return ZonedDateTime.ofInstant( return ZonedDateTime.ofInstant(
toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault() toInstant().truncatedTo(ChronoUnit.SECONDS), ZoneId.systemDefault()
).format(DateTimeFormatter.ISO_INSTANT) ).format(DateTimeFormatter.ISO_INSTANT)
} }

View file

@ -128,12 +128,15 @@ object Utils {
isNullOrEmpty() -> { isNullOrEmpty() -> {
"" ""
} }
color == DEFAULT_COLOR -> { color == DEFAULT_COLOR -> {
this this
} }
Colors.BOLD == color || Colors.REVERSE == color -> { Colors.BOLD == color || Colors.REVERSE == color -> {
color + this + color color + this + color
} }
else -> { else -> {
color + this + Colors.NORMAL color + this + Colors.NORMAL
} }
@ -220,7 +223,7 @@ object Utils {
if (serialFile.exists() && serialFile.fileSize() > 0) { if (serialFile.exists() && serialFile.fileSize() > 0) {
try { try {
ObjectInputStream( ObjectInputStream(
BufferedInputStream(Files.newInputStream(serialFile)) BufferedInputStream(Files.newInputStream(serialFile))
).use { input -> ).use { input ->
if (logger.isDebugEnabled) logger.debug("Loading the ${description}.") if (logger.isDebugEnabled) logger.debug("Loading the ${description}.")
return input.readObject() return input.readObject()
@ -307,20 +310,20 @@ object Utils {
@JvmStatic @JvmStatic
@JvmOverloads @JvmOverloads
fun GenericMessageEvent.sendList( fun GenericMessageEvent.sendList(
list: List<String>, list: List<String>,
maxPerLine: Int, maxPerLine: Int,
separator: String = " ", separator: String = " ",
isBold: Boolean = false, isBold: Boolean = false,
isIndent: Boolean = false isIndent: Boolean = false
) { ) {
var i = 0 var i = 0
while (i < list.size) { while (i < list.size) {
sendMessage( sendMessage(
helpFormat( helpFormat(
list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""), list.subList(i, list.size.coerceAtMost(i + maxPerLine)).joinToString(separator, truncated = ""),
isBold, isBold,
isIndent isIndent
), ),
) )
i += maxPerLine i += maxPerLine
} }
@ -419,8 +422,8 @@ object Utils {
fun URL.reader(): UrlReaderResponse { fun URL.reader(): UrlReaderResponse {
val connection = this.openConnection() as HttpURLConnection val connection = this.openConnection() as HttpURLConnection
connection.setRequestProperty( connection.setRequestProperty(
"User-Agent", "User-Agent",
"Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/109.0"
) )
return if (connection.responseCode.isHttpSuccess()) { return if (connection.responseCode.isHttpSuccess()) {
UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() }) UrlReaderResponse(connection.responseCode, connection.inputStream.bufferedReader().use { it.readText() })

View file

@ -50,15 +50,15 @@ class Ignore : AbstractCommand() {
override val name = IGNORE_CMD override val name = IGNORE_CMD
override val help = listOf( override val help = listOf(
"To ignore a link posted to the channel:", "To ignore a link posted to the channel:",
helpFormat("https://www.foo.bar %n"), helpFormat("https://www.foo.bar %n"),
"To check your ignore status:", "To check your ignore status:",
helpFormat("%c $name"), helpFormat("%c $name"),
"To toggle your ignore status:", "To toggle your ignore status:",
helpFormat("%c $name $me") helpFormat("%c $name $me")
) )
private val helpOp = help.plus( private val helpOp = help.plus(
arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name <nick> [<nick> ...]")) arrayOf("To add/remove nicks from the ignored list:", helpFormat("%c $name <nick> [<nick> ...]"))
) )
override val isOpOnly = false override val isOpOnly = false

View file

@ -48,8 +48,8 @@ import kotlin.time.toDuration
class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() { class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() {
private val allVersions = listOf( private val allVersions = listOf(
"${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})", "${ReleaseInfo.PROJECT.capitalise()} ${ReleaseInfo.VERSION} (${ReleaseInfo.WEBSITE.green()})",
"Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})" "Written by ${ReleaseInfo.AUTHOR} (${ReleaseInfo.AUTHOR_URL.green()})"
) )
override val name = "info" override val name = "info"
override val help = listOf("To view information about the bot:", helpFormat("%c $name")) override val help = listOf("To view information about the bot:", helpFormat("%c $name"))
@ -104,9 +104,9 @@ class Info(private val tell: Tell, private val seen: Seen) : AbstractCommand() {
event.sendList(allVersions, 1) event.sendList(allVersions, 1)
val info = StringBuilder() val info = StringBuilder()
info.append("Uptime: ") info.append("Uptime: ")
.append(ManagementFactory.getRuntimeMXBean().uptime.toUptime()) .append(ManagementFactory.getRuntimeMXBean().uptime.toUptime())
.append(" [Entries: ") .append(" [Entries: ")
.append(LinksManager.entries.links.size) .append(LinksManager.entries.links.size)
if (seen.isEnabled()) { if (seen.isEnabled()) {
info.append(", Seen: ").append(seen.count()) info.append(", Seen: ").append(seen.count())
} }

View file

@ -39,8 +39,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent
class Msg : AbstractCommand() { class Msg : AbstractCommand() {
override val name = "msg" override val name = "msg"
override val help = listOf( override val help = listOf(
"To have the bot send a private message to someone:", "To have the bot send a private message to someone:",
helpFormat("%c $name <nick> <text>") helpFormat("%c $name <nick> <text>")
) )
override val isOpOnly = true override val isOpOnly = true
override val isPublic = false override val isPublic = false

View file

@ -41,8 +41,8 @@ import java.time.LocalDateTime
class Recap : AbstractCommand() { class Recap : AbstractCommand() {
override val name = "recap" override val name = "recap"
override val help = listOf( override val help = listOf(
"To list the last 10 public channel messages:", "To list the last 10 public channel messages:",
helpFormat("%c $name") helpFormat("%c $name")
) )
override val isOpOnly = false override val isOpOnly = false
override val isPublic = true override val isPublic = true
@ -60,8 +60,8 @@ class Recap : AbstractCommand() {
@JvmStatic @JvmStatic
fun storeRecap(sender: String, message: String, isAction: Boolean) { fun storeRecap(sender: String, message: String, isAction: Boolean) {
recaps.add( recaps.add(
LocalDateTime.now(Clock.systemUTC()).toUtcDateTime() LocalDateTime.now(Clock.systemUTC()).toUtcDateTime()
+ " - $sender" + (if (isAction) " " else ": ") + message + " - $sender" + (if (isAction) " " else ": ") + message
) )
if (recaps.size > MAX_RECAPS) { if (recaps.size > MAX_RECAPS) {
recaps.removeFirst() recaps.removeFirst()

View file

@ -40,10 +40,10 @@ import org.pircbotx.hooks.types.GenericMessageEvent
class Versions : AbstractCommand() { class Versions : AbstractCommand() {
private val allVersions = listOf( private val allVersions = listOf(
"Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})", "Version: ${ReleaseInfo.VERSION} (${ReleaseInfo.BUILDDATE.toIsoLocalDate()})",
"${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" + "${System.getProperty("os.name")} ${System.getProperty("os.version")} (${System.getProperty("os.arch")})" +
", JVM ${System.getProperty("java.runtime.version")}", ", JVM ${System.getProperty("java.runtime.version")}",
"Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}" "Kotlin ${KotlinVersion.CURRENT}, PircBotX ${PircBotX.VERSION}"
) )
override val name = "versions" override val name = "versions"
override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name")) override val help = listOf("To view the versions data (bot, platform, java, etc.):", helpFormat("%c $name"))

View file

@ -45,13 +45,13 @@ import org.pircbotx.hooks.types.GenericMessageEvent
class Comment : AbstractCommand() { class Comment : AbstractCommand() {
override val name = COMMAND override val name = COMMAND
override val help = listOf( override val help = listOf(
"To add a comment:", "To add a comment:",
helpFormat("${Constants.LINK_CMD}1:This is a comment"), helpFormat("${Constants.LINK_CMD}1:This is a comment"),
"I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1",
"To edit a comment, use its label: ", "To edit a comment, use its label: ",
helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"), helpFormat("${Constants.LINK_CMD}1.1:This is an edited comment"),
"To delete a comment, use its label and a minus sign: ", "To delete a comment, use its label and a minus sign: ",
helpFormat("${Constants.LINK_CMD}1.1:-") helpFormat("${Constants.LINK_CMD}1.1:-")
) )
override val isOpOnly = false override val isOpOnly = false
override val isPublic = true override val isPublic = true
@ -100,12 +100,12 @@ class Comment : AbstractCommand() {
} }
private fun changeAuthor( private fun changeAuthor(
channel: String, channel: String,
cmd: String, cmd: String,
entry: EntryLink, entry: EntryLink,
entryIndex: Int, entryIndex: Int,
commentIndex: Int, commentIndex: Int,
event: GenericMessageEvent event: GenericMessageEvent
) { ) {
if (event.isChannelOp(channel) && cmd.length > 1) { if (event.isChannelOp(channel) && cmd.length > 1) {
val comment = entry.getComment(commentIndex) val comment = entry.getComment(commentIndex)
@ -118,11 +118,11 @@ class Comment : AbstractCommand() {
} }
private fun deleteComment( private fun deleteComment(
channel: String, channel: String,
entry: EntryLink, entry: EntryLink,
entryIndex: Int, entryIndex: Int,
commentIndex: Int, commentIndex: Int,
event: GenericMessageEvent event: GenericMessageEvent
) { ) {
if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) { if (event.isChannelOp(channel) || event.user.nick == entry.getComment(commentIndex).nick) {
entry.deleteComment(commentIndex) entry.deleteComment(commentIndex)
@ -134,11 +134,11 @@ class Comment : AbstractCommand() {
} }
private fun setComment( private fun setComment(
cmd: String, cmd: String,
entry: EntryLink, entry: EntryLink,
entryIndex: Int, entryIndex: Int,
commentIndex: Int, commentIndex: Int,
event: GenericMessageEvent event: GenericMessageEvent
) { ) {
entry.setComment(commentIndex, cmd, event.user.nick) entry.setComment(commentIndex, cmd, event.user.nick)
event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex))) event.sendMessage(printComment(entryIndex, commentIndex, entry.getComment(commentIndex)))

View file

@ -161,8 +161,8 @@ class LinksManager : AbstractCommand() {
internal fun fetchTitle(link: String): String { internal fun fetchTitle(link: String): String {
try { try {
val html = Jsoup.connect(link) val html = Jsoup.connect(link)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0") .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0")
.get() .get()
val title = html.title() val title = html.title()
if (title.isNotBlank()) { if (title.isNotBlank()) {
return title return title
@ -178,7 +178,7 @@ class LinksManager : AbstractCommand() {
return try { return try {
val match = entries.links.single { it.link == link } val match = entries.links.single { it.link == link }
event.sendMessage( event.sendMessage(
"Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match) "Duplicate".bold() + " >> " + printLink(entries.links.indexOf(match), match)
) )
true true
} catch (ignore: NoSuchElementException) { } catch (ignore: NoSuchElementException) {

View file

@ -47,16 +47,16 @@ import org.pircbotx.hooks.types.GenericMessageEvent
class Posting : AbstractCommand() { class Posting : AbstractCommand() {
override val name = "posting" override val name = "posting"
override val help = listOf( override val help = listOf(
"Post a URL, by saying it on a line on its own:", "Post a URL, by saying it on a line on its own:",
helpFormat("<url> [<title>] ${Tags.COMMAND}: <+tag> [...]]"), helpFormat("<url> [<title>] ${Tags.COMMAND}: <+tag> [...]]"),
"I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1", "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1",
"To add a title, use its label and a pipe:", "To add a title, use its label and a pipe:",
helpFormat("${Constants.LINK_CMD}1:|This is the title"), helpFormat("${Constants.LINK_CMD}1:|This is the title"),
"To add a comment:", "To add a comment:",
helpFormat("${Constants.LINK_CMD}1:This is a comment"), helpFormat("${Constants.LINK_CMD}1:This is a comment"),
"I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1", "I will reply with a label, for example: ${Constants.LINK_CMD.bold()}1.1",
"To edit a comment, see: ", "To edit a comment, see: ",
helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}") helpFormat("%c ${Constants.HELP_CMD} ${Comment.COMMAND}")
) )
override val isOpOnly = false override val isOpOnly = false
override val isPublic = true override val isPublic = true

View file

@ -44,8 +44,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent
class Tags : AbstractCommand() { class Tags : AbstractCommand() {
override val name = COMMAND override val name = COMMAND
override val help = listOf( override val help = listOf(
"To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:", "To categorize or tag a URL, use its label and a ${Constants.TAG_CMD}:",
helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]") helpFormat("${Constants.LINK_CMD}1${Constants.TAG_CMD}:<+tag|-tag> [...]")
) )
override val isOpOnly = false override val isOpOnly = false
override val isPublic = true override val isPublic = true

View file

@ -46,8 +46,8 @@ import org.pircbotx.hooks.types.GenericMessageEvent
class View : AbstractCommand() { class View : AbstractCommand() {
override val name = VIEW_CMD override val name = VIEW_CMD
override val help = listOf( override val help = listOf(
"To list or search the current URL posts:", "To list or search the current URL posts:",
helpFormat("%c $name [<start>] [<query>]") helpFormat("%c $name [<start>] [<query>]")
) )
override val isOpOnly = false override val isOpOnly = false
override val isPublic = true override val isPublic = true
@ -107,9 +107,9 @@ class View : AbstractCommand() {
if (sent == MAX_ENTRIES && index < entries.links.size) { if (sent == MAX_ENTRIES && index < entries.links.size) {
event.sendMessage("To view more, try: ") event.sendMessage("To view more, try: ")
event.sendMessage( event.sendMessage(
helpFormat( helpFormat(
helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent) helpCmdSyntax("%c $name ${index + 1} $query", event.bot().nick, event is PrivateMessageEvent)
) )
) )
} }
} }

View file

@ -39,6 +39,7 @@ class NickComparator : Comparator<String>, Serializable {
} }
companion object { companion object {
@Suppress("ConstPropertyName")
private const val serialVersionUID = 1L private const val serialVersionUID = 1L
} }
} }

View file

@ -58,7 +58,7 @@ class Seen(private val serialObject: String) : AbstractCommand() {
override val name = "seen" override val name = "seen"
override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>")) override val help = listOf("To view when a nickname was last seen:", helpFormat("%c $name <nick>"))
private val helpOp = help.plus( private val helpOp = help.plus(
arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword")) arrayOf("To view all ${"seen".bold()} nicks:", helpFormat("%c $name $allKeyword"))
) )
override val isOpOnly = false override val isOpOnly = false
override val isPublic = true override val isPublic = true
@ -130,12 +130,12 @@ class Seen(private val serialObject: String) : AbstractCommand() {
if (isEnabled()) { if (isEnabled()) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
seenNicks.putAll( seenNicks.putAll(
loadSerialData( loadSerialData(
serialObject, serialObject,
TreeMap<String, SeenNick>(), TreeMap<String, SeenNick>(),
logger, logger,
"seen nicknames" "seen nicknames"
) as TreeMap<String, SeenNick> ) as TreeMap<String, SeenNick>
) )
} }
} }

View file

@ -35,6 +35,7 @@ import java.io.Serializable
data class SeenNick(val nick: String, val lastSeen: Long) : Serializable { data class SeenNick(val nick: String, val lastSeen: Long) : Serializable {
companion object { companion object {
@Suppress("ConstPropertyName")
private const val serialVersionUID = 1L private const val serialVersionUID = 1L
} }
} }

View file

@ -66,11 +66,11 @@ class Tell(private val serialObject: String) : AbstractCommand() {
override val name = "tell" override val name = "tell"
override val help = listOf( override val help = listOf(
"To send a message to someone when they join the channel:", "To send a message to someone when they join the channel:",
helpFormat("%c $name <nick> <message>"), helpFormat("%c $name <nick> <message>"),
"To view queued and sent messages:", "To view queued and sent messages:",
helpFormat("%c $name ${View.VIEW_CMD}"), helpFormat("%c $name ${View.VIEW_CMD}"),
"Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.' "Messages are kept for ${maxDays.bold()}" + " day".plural(maxDays.toLong()) + '.'
) )
override val isOpOnly: Boolean = false override val isOpOnly: Boolean = false
override val isPublic: Boolean = isEnabled() override val isPublic: Boolean = isEnabled()
@ -89,6 +89,7 @@ class Tell(private val serialObject: String) : AbstractCommand() {
args.isBlank() -> { args.isBlank() -> {
helpResponse(channel, args, event) helpResponse(channel, args, event)
} }
args.startsWith(View.VIEW_CMD) -> { args.startsWith(View.VIEW_CMD) -> {
if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) { if (event.isChannelOp(channel) && "${View.VIEW_CMD} $TELL_ALL_KEYWORD" == args) {
viewAll(event) viewAll(event)
@ -96,9 +97,11 @@ class Tell(private val serialObject: String) : AbstractCommand() {
viewMessages(event) viewMessages(event)
} }
} }
args.startsWith("$TELL_DEL_KEYWORD ") -> { args.startsWith("$TELL_DEL_KEYWORD ") -> {
deleteMessage(channel, args, event) deleteMessage(channel, args, event)
} }
else -> { else -> {
newMessage(channel, args, event) newMessage(channel, args, event)
} }
@ -123,9 +126,9 @@ class Tell(private val serialObject: String) : AbstractCommand() {
} }
} else { } else {
if (messages.removeIf { if (messages.removeIf {
it.id == id && it.id == id &&
(it.sender.equals(event.user.nick, true) || event.isChannelOp(channel)) (it.sender.equals(event.user.nick, true) || event.isChannelOp(channel))
}) { }) {
save() save()
event.sendMessage("The message was deleted from the queue.") event.sendMessage("The message was deleted from the queue.")
} else { } else {
@ -185,7 +188,7 @@ class Tell(private val serialObject: String) : AbstractCommand() {
if (message.sender == nickname) { if (message.sender == nickname) {
if (event !is MessageEvent) { if (event !is MessageEvent) {
event.user.send().message( event.user.send().message(
"${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}" "${"You".bold()} wanted me to remind you: ${message.message.reverseColor()}"
) )
message.isReceived = true message.isReceived = true
message.isNotified = true message.isNotified = true
@ -193,17 +196,17 @@ class Tell(private val serialObject: String) : AbstractCommand() {
} }
} else { } else {
event.user.send().message( event.user.send().message(
"${message.sender} wanted me to tell you: ${message.message.reverseColor()}" "${message.sender} wanted me to tell you: ${message.message.reverseColor()}"
) )
message.isReceived = true message.isReceived = true
save() save()
} }
} else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived } else if (message.sender.equals(nickname, ignoreCase = true) && message.isReceived
&& !message.isNotified && !message.isNotified
) { ) {
event.user.send().message( event.user.send().message(
"Your message ${"[ID ${message.id}]".reverseColor()} was sent to " "Your message ${"[ID ${message.id}]".reverseColor()} was sent to "
+ "${message.recipient.bold()} on ${message.receptionDate}" + "${message.recipient.bold()} on ${message.receptionDate}"
) )
message.isNotified = true message.isNotified = true
save() save()
@ -224,8 +227,8 @@ class Tell(private val serialObject: String) : AbstractCommand() {
if (messages.isNotEmpty()) { if (messages.isNotEmpty()) {
for (message in messages) { for (message in messages) {
event.sendMessage( event.sendMessage(
"${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " + "${message.sender.bold()}$ARROW${message.recipient.bold()} [ID: ${message.id}, " +
(if (message.isReceived) "DELIVERED]" else "QUEUED]") (if (message.isReceived) "DELIVERED]" else "QUEUED]")
) )
} }
} else { } else {
@ -243,13 +246,13 @@ class Tell(private val serialObject: String) : AbstractCommand() {
} }
if (message.isReceived) { if (message.isReceived) {
event.sendMessage( event.sendMessage(
message.sender.bold() + ARROW + message.recipient.bold() + message.sender.bold() + ARROW + message.recipient.bold() +
" [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]" " [${message.receptionDate.toUtcDateTime()}, ID: ${message.id.bold()}, DELIVERED]"
) )
} else { } else {
event.sendMessage( event.sendMessage(
message.sender.bold() + ARROW + message.recipient.bold() + message.sender.bold() + ARROW + message.recipient.bold() +
" [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]" " [${message.queued.toUtcDateTime()}, ID: ${message.id.bold()}, QUEUED]"
) )
} }
event.sendMessage(helpFormat(message.message)) event.sendMessage(helpFormat(message.message))
@ -259,9 +262,9 @@ class Tell(private val serialObject: String) : AbstractCommand() {
} else { } else {
event.sendMessage("To delete one or all delivered messages:") event.sendMessage("To delete one or all delivered messages:")
event.sendMessage( event.sendMessage(
helpFormat( helpFormat(
helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true) helpCmdSyntax("%c $name $TELL_DEL_KEYWORD <id|$TELL_ALL_KEYWORD>", event.bot().nick, true)
) )
) )
event.sendMessage(help.last()) event.sendMessage(help.last())
} }

View file

@ -39,20 +39,20 @@ import java.time.format.DateTimeFormatter
* Tell Message. * Tell Message.
*/ */
class TellMessage( class TellMessage(
/** /**
* Returns the message's sender. * Returns the message's sender.
*/ */
val sender: String, val sender: String,
/** /**
* Returns the message's recipient. * Returns the message's recipient.
*/ */
val recipient: String, val recipient: String,
/** /**
* Returns the message text. * Returns the message text.
*/ */
val message: String val message: String
) : Serializable { ) : Serializable {
/** /**
* Returns the queued date/time. * Returns the queued date/time.
@ -98,6 +98,7 @@ class TellMessage(
} }
companion object { companion object {
@Suppress("ConstPropertyName")
private const val serialVersionUID = 2L private const val serialVersionUID = 2L
} }
} }

View file

@ -34,10 +34,10 @@ package net.thauvin.erik.mobibot.entries
import net.thauvin.erik.mobibot.Utils.today import net.thauvin.erik.mobibot.Utils.today
class Entries( class Entries(
var channel: String = "", var channel: String = "",
var ircServer: String = "", var ircServer: String = "",
var logsDir: String = "", var logsDir: String = "",
var backlogs: String = "" var backlogs: String = ""
) { ) {
val links = mutableListOf<EntryLink>() val links = mutableListOf<EntryLink>()

View file

@ -43,7 +43,7 @@ object EntriesUtils {
*/ */
@JvmStatic @JvmStatic
fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String = fun printComment(entryIndex: Int, commentIndex: Int, comment: EntryComment): String =
("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}") ("${entryIndex.toLinkLabel()}.${commentIndex + 1}: [${comment.nick}] ${comment.comment}")
/** /**
* Prints an entry's link for display on the channel. * Prints an entry's link for display on the channel.
@ -52,7 +52,7 @@ object EntriesUtils {
@JvmOverloads @JvmOverloads
fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String { fun printLink(entryIndex: Int, entry: EntryLink, isView: Boolean = false): String {
val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ") val buff = StringBuilder().append(entryIndex.toLinkLabel()).append(": ")
.append('[').append(entry.nick).append(']') .append('[').append(entry.nick).append(']')
if (isView && entry.comments.isNotEmpty()) { if (isView && entry.comments.isNotEmpty()) {
buff.append("[+").append(entry.comments.size).append(']') buff.append("[+").append(entry.comments.size).append(']')
} }
@ -73,7 +73,7 @@ object EntriesUtils {
*/ */
@JvmStatic @JvmStatic
fun printTags(entryIndex: Int, entry: EntryLink): String = fun printTags(entryIndex: Int, entry: EntryLink): String =
entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ") entryIndex.toLinkLabel() + "${Constants.TAG_CMD}: " + entry.formatTags(", ")
/** /**
* Builds link label based on its index. e.g: L1 * Builds link label based on its index. e.g: L1

View file

@ -46,6 +46,7 @@ data class EntryComment(var comment: String, var nick: String) : Serializable {
companion object { companion object {
// Serial version UID // Serial version UID
@Suppress("ConstPropertyName")
private const val serialVersionUID: Long = 1L private const val serialVersionUID: Long = 1L
} }
} }

View file

@ -40,40 +40,40 @@ import java.util.*
* The class used to store link entries. * The class used to store link entries.
*/ */
class EntryLink( class EntryLink(
// Link's comments // Link's comments
val comments: MutableList<EntryComment> = mutableListOf(), val comments: MutableList<EntryComment> = mutableListOf(),
// Tags/categories // Tags/categories
val tags: MutableList<SyndCategory> = mutableListOf(), val tags: MutableList<SyndCategory> = mutableListOf(),
// Channel // Channel
var channel: String, var channel: String,
// Creation date // Creation date
var date: Date = Calendar.getInstance().time, var date: Date = Calendar.getInstance().time,
// Link's URL // Link's URL
var link: String, var link: String,
// Author's login // Author's login
var login: String = "", var login: String = "",
// Author's nickname // Author's nickname
var nick: String, var nick: String,
// Link's title // Link's title
var title: String var title: String
) : Serializable { ) : Serializable {
/** /**
* Creates a new entry. * Creates a new entry.
*/ */
constructor( constructor(
link: String, link: String,
title: String, title: String,
nick: String, nick: String,
login: String, login: String,
channel: String, channel: String,
tags: List<String?> tags: List<String?>
) : this(link = link, title = title, nick = nick, login = login, channel = channel) { ) : this(link = link, title = title, nick = nick, login = login, channel = channel) {
setTags(tags) setTags(tags)
} }
@ -82,12 +82,12 @@ class EntryLink(
* Creates a new entry. * Creates a new entry.
*/ */
constructor( constructor(
link: String, link: String,
title: String, title: String,
nick: String, nick: String,
channel: String, channel: String,
date: Date, date: Date,
tags: List<SyndCategory> tags: List<SyndCategory>
) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) { ) : this(link = link, title = title, nick = nick, channel = channel, date = Date(date.time)) {
this.tags.addAll(tags) this.tags.addAll(tags)
} }
@ -207,6 +207,7 @@ class EntryLink(
companion object { companion object {
// Serial version UID // Serial version UID
@Suppress("ConstPropertyName")
private const val serialVersionUID: Long = 1L private const val serialVersionUID: Long = 1L
} }
} }

View file

@ -55,24 +55,24 @@ class FeedsManager private constructor() {
private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java) private val logger: Logger = LoggerFactory.getLogger(FeedsManager::class.java)
// The file containing the current entries. // The file containing the current entries.
private const val currentXml = "current.xml" private const val CURRENT_XML = "current.xml"
// The .xml extension. // The .xml extension.
private const val dotXml = ".xml" private const val DOT_XML = ".xml"
/** /**
* Loads the current feed. * Loads the current feed.
*/ */
@JvmStatic @JvmStatic
@Throws(IOException::class, FeedException::class) @Throws(IOException::class, FeedException::class)
fun loadFeed(entries: Entries, currentFile: String = currentXml): String { fun loadFeed(entries: Entries, currentFile: String = CURRENT_XML): String {
entries.links.clear() entries.links.clear()
val xml = Paths.get("${entries.logsDir}${currentFile}") val xml = Paths.get("${entries.logsDir}${currentFile}")
var pubDate = today() var pubDate = today()
if (xml.exists()) { if (xml.exists()) {
val input = SyndFeedInput() val input = SyndFeedInput()
InputStreamReader( InputStreamReader(
Files.newInputStream(xml), StandardCharsets.UTF_8 Files.newInputStream(xml), StandardCharsets.UTF_8
).use { reader -> ).use { reader ->
val feed = input.build(reader) val feed = input.build(reader)
pubDate = feed.publishedDate.toIsoLocalDate() pubDate = feed.publishedDate.toIsoLocalDate()
@ -81,12 +81,12 @@ class FeedsManager private constructor() {
for (i in items.indices.reversed()) { for (i in items.indices.reversed()) {
with(items[i]) { with(items[i]) {
entry = EntryLink( entry = EntryLink(
link, link,
title, title,
author.substring(author.lastIndexOf('(') + 1, author.length - 1), author.substring(author.lastIndexOf('(') + 1, author.length - 1),
entries.channel, entries.channel,
publishedDate, publishedDate,
categories categories
) )
var split: List<String> var split: List<String>
for (comment in description.value.split("<br/>")) { for (comment in description.value.split("<br/>")) {
@ -110,7 +110,7 @@ class FeedsManager private constructor() {
* Saves the feeds. * Saves the feeds.
*/ */
@JvmStatic @JvmStatic
fun saveFeed(entries: Entries, currentFile: String = currentXml) { fun saveFeed(entries: Entries, currentFile: String = CURRENT_XML) {
if (logger.isDebugEnabled) logger.debug("Saving the feeds...") if (logger.isDebugEnabled) logger.debug("Saving the feeds...")
if (entries.logsDir.isNotBlank()) { if (entries.logsDir.isNotBlank()) {
try { try {
@ -119,7 +119,7 @@ class FeedsManager private constructor() {
val items: MutableList<SyndEntry> = mutableListOf() val items: MutableList<SyndEntry> = mutableListOf()
var item: SyndEntry var item: SyndEntry
OutputStreamWriter( OutputStreamWriter(
Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8 Files.newOutputStream(Paths.get("${entries.logsDir}${currentFile}")), StandardCharsets.UTF_8
).use { fw -> ).use { fw ->
with(rss) { with(rss) {
feedType = "rss_2.0" feedType = "rss_2.0"
@ -134,13 +134,13 @@ class FeedsManager private constructor() {
with(entries.links[i]) { with(entries.links[i]) {
buff.setLength(0) buff.setLength(0)
buff.append("Posted by <b>") buff.append("Posted by <b>")
.append(nick) .append(nick)
.append("</b> on <a href=\"irc://") .append("</b> on <a href=\"irc://")
.append(entries.ircServer).append('/') .append(entries.ircServer).append('/')
.append(channel) .append(channel)
.append("\"><b>") .append("\"><b>")
.append(channel) .append(channel)
.append("</b></a>") .append("</b></a>")
if (comments.isNotEmpty()) { if (comments.isNotEmpty()) {
buff.append(" <br/><br/>") buff.append(" <br/><br/>")
for (j in comments.indices) { for (j in comments.indices) {
@ -165,11 +165,11 @@ class FeedsManager private constructor() {
output.output(rss, fw) output.output(rss, fw)
} }
OutputStreamWriter( OutputStreamWriter(
Files.newOutputStream( Files.newOutputStream(
Paths.get( Paths.get(
entries.logsDir + today() + dotXml entries.logsDir + today() + DOT_XML
) )
), StandardCharsets.UTF_8 ), StandardCharsets.UTF_8
).use { fw -> output.output(rss, fw) } ).use { fw -> output.output(rss, fw) }
} catch (e: FeedException) { } catch (e: FeedException) {
if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e) if (logger.isWarnEnabled) logger.warn("Unable to generate the entries feed.", e)

View file

@ -56,8 +56,8 @@ class ChatGpt : AbstractModule() {
if (args.isNotBlank()) { if (args.isNotBlank()) {
try { try {
val answer = chat( val answer = chat(
args.trim(), properties[API_KEY_PROP], args.trim(), properties[API_KEY_PROP],
properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt() properties.getOrDefault(MAX_TOKENS_PROP, "1024").toInt()
) )
if (answer.isNotBlank()) { if (answer.isNotBlank()) {
event.sendMessage(WordUtils.wrap(answer, 400)) event.sendMessage(WordUtils.wrap(answer, 400))
@ -107,13 +107,13 @@ class ChatGpt : AbstractModule() {
if (!apiKey.isNullOrEmpty()) { if (!apiKey.isNullOrEmpty()) {
val prompt = JSONWriter.valueToString("Q:$query\nA:") val prompt = JSONWriter.valueToString("Q:$query\nA:")
val request = HttpRequest.newBuilder() val request = HttpRequest.newBuilder()
.uri(URI.create(API_URL)) .uri(URI.create(API_URL))
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Authorization", "Bearer $apiKey") .header("Authorization", "Bearer $apiKey")
.header("User-Agent", Constants.USER_AGENT) .header("User-Agent", Constants.USER_AGENT)
.POST( .POST(
HttpRequest.BodyPublishers.ofString( HttpRequest.BodyPublishers.ofString(
"""{ """{
"model": "text-davinci-003", "model": "text-davinci-003",
"prompt": $prompt, "prompt": $prompt,
"temperature": 0, "temperature": 0,
@ -122,9 +122,9 @@ class ChatGpt : AbstractModule() {
"frequency_penalty": 0, "frequency_penalty": 0,
"presence_penalty": 0 "presence_penalty": 0
}""".trimIndent() }""".trimIndent()
)
) )
.build() )
.build()
try { try {
val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
if (response.statusCode() == 200) { if (response.statusCode() == 200) {
@ -134,16 +134,16 @@ class ChatGpt : AbstractModule() {
return choices.getJSONObject(0).getString("text").trim() return choices.getJSONObject(0).getString("text").trim()
} catch (e: JSONException) { } catch (e: JSONException) {
throw ModuleException( throw ModuleException(
"$CHATGPT_CMD($query): JSON", "$CHATGPT_CMD($query): JSON",
"A JSON error has occurred while conversing with $CHATGPT_NAME.", "A JSON error has occurred while conversing with $CHATGPT_NAME.",
e e
) )
} }
} else { } else {
if (response.statusCode() == 429) { if (response.statusCode() == 429) {
throw ModuleException( throw ModuleException(
"$CHATGPT_CMD($query): Rate limit reached", "$CHATGPT_CMD($query): Rate limit reached",
"Rate limit reached. Please try again later." "Rate limit reached. Please try again later."
) )
} else { } else {
throw IOException("HTTP Status Code: " + response.statusCode()) throw IOException("HTTP Status Code: " + response.statusCode())
@ -151,9 +151,9 @@ class ChatGpt : AbstractModule() {
} }
} catch (e: IOException) { } catch (e: IOException) {
throw ModuleException( throw ModuleException(
"$CHATGPT_CMD($query): IO", "$CHATGPT_CMD($query): IO",
"An IO error has occurred while conversing with $CHATGPT_NAME.", "An IO error has occurred while conversing with $CHATGPT_NAME.",
e e
) )
} }
} else { } else {

View file

@ -134,9 +134,9 @@ class CryptoPrices : AbstractModule() {
} }
} catch (e: CryptoException) { } catch (e: CryptoException) {
throw ModuleException( throw ModuleException(
"loadCurrencies(): CE", "loadCurrencies(): CE",
"An error has occurred while retrieving the currencies table.", "An error has occurred while retrieving the currencies table.",
e e
) )
} }
} }

View file

@ -78,6 +78,7 @@ class CurrencyConverter : AbstractModule() {
SYMBOLS.isEmpty() -> { SYMBOLS.isEmpty() -> {
event.respond(EMPTY_SYMBOLS_TABLE) event.respond(EMPTY_SYMBOLS_TABLE)
} }
args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> { args.matches("\\d+([,\\d]+)?(\\.\\d+)? [a-zA-Z]{3}+ (to|in) [a-zA-Z]{3}+".toRegex()) -> {
val msg = convertCurrency(properties[API_KEY_PROP], args) val msg = convertCurrency(properties[API_KEY_PROP], args)
event.respond(msg.msg) event.respond(msg.msg)
@ -85,10 +86,12 @@ class CurrencyConverter : AbstractModule() {
helpResponse(event) helpResponse(event)
} }
} }
args.contains(CODES_KEYWORD) -> { args.contains(CODES_KEYWORD) -> {
event.sendMessage("The supported currency codes are:") event.sendMessage("The supported currency codes are:")
event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true) event.sendList(SYMBOLS.keys.toList(), 11, isIndent = true)
} }
else -> { else -> {
helpResponse(event) helpResponse(event)
} }

View file

@ -65,10 +65,10 @@ class GoogleSearch : AbstractModule() {
if (args.isNotBlank()) { if (args.isNotBlank()) {
try { try {
val results = searchGoogle( val results = searchGoogle(
args, args,
properties[API_KEY_PROP], properties[API_KEY_PROP],
properties[CSE_KEY_PROP], properties[CSE_KEY_PROP],
event.user.nick event.user.nick
) )
for (msg in results) { for (msg in results) {
if (msg.isError) { if (msg.isError) {
@ -104,23 +104,23 @@ class GoogleSearch : AbstractModule() {
@JvmStatic @JvmStatic
@Throws(ModuleException::class) @Throws(ModuleException::class)
fun searchGoogle( fun searchGoogle(
query: String, query: String,
apiKey: String?, apiKey: String?,
cseKey: String?, cseKey: String?,
quotaUser: String = ReleaseInfo.PROJECT quotaUser: String = ReleaseInfo.PROJECT
): List<Message> { ): List<Message> {
if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) { if (apiKey.isNullOrBlank() || cseKey.isNullOrBlank()) {
throw ModuleException( throw ModuleException(
"${GoogleSearch::class.java.name} is disabled.", "${GoogleSearch::class.java.name} is disabled.",
"${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing." "${GOOGLE_CMD.capitalise()} is disabled. The API keys are missing."
) )
} }
val results = mutableListOf<Message>() val results = mutableListOf<Message>()
if (query.isNotBlank()) { if (query.isNotBlank()) {
try { try {
val url = URL( val url = URL(
"https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" + "https://www.googleapis.com/customsearch/v1?key=$apiKey&cx=$cseKey" +
"&quotaUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json" "&quotaUser=${quotaUser}&q=${query.encodeUrl()}&filter=1&num=5&alt=json"
) )
val json = JSONObject(url.reader().body) val json = JSONObject(url.reader().body)
if (json.has("items")) { if (json.has("items")) {
@ -141,9 +141,9 @@ class GoogleSearch : AbstractModule() {
throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e) throw ModuleException("searchGoogle($query): IOE", "An IO error has occurred searching Google.", e)
} catch (e: JSONException) { } catch (e: JSONException) {
throw ModuleException( throw ModuleException(
"searchGoogle($query): JSON", "searchGoogle($query): JSON",
"A JSON error has occurred searching Google.", "A JSON error has occurred searching Google.",
e e
) )
} }
} else { } else {

View file

@ -55,9 +55,9 @@ class Lookup : AbstractModule() {
event.respondWith(nslookup(args).prependIndent()) event.respondWith(nslookup(args).prependIndent())
} catch (ignore: UnknownHostException) { } catch (ignore: UnknownHostException) {
if (args.matches( if (args.matches(
("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)") ("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
.toRegex() .toRegex()
) )
) { ) {
try { try {
val lines = whois(args) val lines = whois(args)

View file

@ -65,7 +65,7 @@ class Mastodon : SocialModule() {
private fun formatTags(entry: EntryLink): String { private fun formatTags(entry: EntryLink): String {
return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) } return entry.tags.filter { !it.name.equals(entry.channel.removePrefix("#"), true) }
.joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" } .joinToString(separator = " ", prefix = "\n\n") { "#${it.name}" }
} }
/** /**
@ -74,11 +74,11 @@ class Mastodon : SocialModule() {
@Throws(ModuleException::class) @Throws(ModuleException::class)
override fun post(message: String, isDm: Boolean): String { override fun post(message: String, isDm: Boolean): String {
return toot( return toot(
apiKey = properties[ACCESS_TOKEN_PROP], apiKey = properties[ACCESS_TOKEN_PROP],
instance = properties[INSTANCE_PROP], instance = properties[INSTANCE_PROP],
handle = handle, handle = handle,
message = message, message = message,
isDm = isDm isDm = isDm
) )
} }
@ -99,21 +99,21 @@ class Mastodon : SocialModule() {
@Throws(ModuleException::class) @Throws(ModuleException::class)
fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String { fun toot(apiKey: String?, instance: String?, handle: String?, message: String, isDm: Boolean): String {
val request = HttpRequest.newBuilder() val request = HttpRequest.newBuilder()
.uri(URI.create("https://$instance/api/v1/statuses")) .uri(URI.create("https://$instance/api/v1/statuses"))
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("Authorization", "Bearer $apiKey") .header("Authorization", "Bearer $apiKey")
.POST( .POST(
HttpRequest.BodyPublishers.ofString( HttpRequest.BodyPublishers.ofString(
JSONWriter.valueToString( JSONWriter.valueToString(
if (isDm) { if (isDm) {
mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct") mapOf("status" to "${handle?.prefixIfMissing('@')} $message", "visibility" to "direct")
} else { } else {
mapOf("status" to message) mapOf("status" to message)
} }
) )
)
) )
.build() )
.build()
try { try {
val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()) val response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString())
if (response.statusCode() == 200) { if (response.statusCode() == 200) {

View file

@ -34,11 +34,12 @@ package net.thauvin.erik.mobibot.modules
* The `ModuleException` class. * The `ModuleException` class.
*/ */
class ModuleException @JvmOverloads constructor( class ModuleException @JvmOverloads constructor(
val debugMessage: String, val debugMessage: String,
message: String? = null, message: String? = null,
cause: Throwable? = null cause: Throwable? = null
) : Exception(message, cause) { ) : Exception(message, cause) {
companion object { companion object {
@Suppress("ConstPropertyName")
private const val serialVersionUID = 1L private const val serialVersionUID = 1L
} }
} }

View file

@ -50,18 +50,18 @@ class Ping : AbstractModule() {
*/ */
@JvmField @JvmField
val PINGS = listOf( val PINGS = listOf(
"is barely alive.", "is barely alive.",
"is trying to stay awake.", "is trying to stay awake.",
"has gone fishing.", "has gone fishing.",
"is somewhere over the rainbow.", "is somewhere over the rainbow.",
"has fallen and can't get up.", "has fallen and can't get up.",
"is running. You better go chase it.", "is running. You better go chase it.",
"has just spontaneously combusted.", "has just spontaneously combusted.",
"is talking to itself... don't interrupt. That's rude.", "is talking to itself... don't interrupt. That's rude.",
"is bartending at an AA meeting.", "is bartending at an AA meeting.",
"is hibernating.", "is hibernating.",
"is saving energy: apathetic mode activated.", "is saving energy: apathetic mode activated.",
"is busy. Go away!" "is busy. Go away!"
) )
@JvmStatic @JvmStatic

View file

@ -52,10 +52,10 @@ class RockPaperScissors : AbstractModule() {
with(help) { with(help) {
add("To play Rock Paper Scissors:") add("To play Rock Paper Scissors:")
add( add(
helpFormat( helpFormat(
"%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}" "%c ${Hands.ROCK.name.lowercase()} | ${Hands.PAPER.name.lowercase()}"
+ " | ${Hands.SCISSORS.name.lowercase()}" + " | ${Hands.SCISSORS.name.lowercase()}"
) )
) )
} }
} }

View file

@ -132,8 +132,8 @@ class StockQuote : AbstractModule() {
fun getQuote(symbol: String, apiKey: String?): List<Message> { fun getQuote(symbol: String, apiKey: String?): List<Message> {
if (apiKey.isNullOrBlank()) { if (apiKey.isNullOrBlank()) {
throw ModuleException( throw ModuleException(
"${StockQuote::class.java.name} is disabled.", "${StockQuote::class.java.name} is disabled.",
"${STOCK_CMD.capitalise()} is disabled. The API key is missing." "${STOCK_CMD.capitalise()} is disabled. The API key is missing."
) )
} }
val messages = mutableListOf<Message>() val messages = mutableListOf<Message>()
@ -144,8 +144,8 @@ class StockQuote : AbstractModule() {
with(messages) { with(messages) {
// Search for symbol/keywords // Search for symbol/keywords
response = URL( response = URL(
"${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey=" "${API_URL}SYMBOL_SEARCH&keywords=" + symbol.encodeUrl() + "&apikey="
+ apiKey.encodeUrl() + apiKey.encodeUrl()
).reader().body ).reader().body
var json = getJsonResponse(response, debugMessage) var json = getJsonResponse(response, debugMessage)
val symbols = json.getJSONArray("bestMatches") val symbols = json.getJSONArray("bestMatches")
@ -156,9 +156,9 @@ class StockQuote : AbstractModule() {
// Get quote for symbol // Get quote for symbol
response = URL( response = URL(
"${API_URL}GLOBAL_QUOTE&symbol=" "${API_URL}GLOBAL_QUOTE&symbol="
+ symbolInfo.getString("1. symbol").encodeUrl() + "&apikey=" + symbolInfo.getString("1. symbol").encodeUrl() + "&apikey="
+ apiKey.encodeUrl() + apiKey.encodeUrl()
).reader().body ).reader().body
json = getJsonResponse(response, debugMessage) json = getJsonResponse(response, debugMessage)
val quote = json.getJSONObject("Global Quote") val quote = json.getJSONObject("Global Quote")
@ -167,50 +167,50 @@ class StockQuote : AbstractModule() {
} else { } else {
add( add(
PublicMessage( PublicMessage(
"Symbol: " + quote.getString("01. symbol").unescapeXml() "Symbol: " + quote.getString("01. symbol").unescapeXml()
+ " [" + symbolInfo.getString("2. name").unescapeXml() + ']' + " [" + symbolInfo.getString("2. name").unescapeXml() + ']'
) )
) )
val pad = 10 val pad = 10
add( add(
PublicMessage( PublicMessage(
"Price:".padEnd(pad).prependIndent() "Price:".padEnd(pad).prependIndent()
+ quote.getString("05. price").unescapeXml() + quote.getString("05. price").unescapeXml()
) )
) )
add( add(
PublicMessage( PublicMessage(
"Previous:".padEnd(pad).prependIndent() "Previous:".padEnd(pad).prependIndent()
+ quote.getString("08. previous close").unescapeXml() + quote.getString("08. previous close").unescapeXml()
) )
) )
val data = arrayOf( val data = arrayOf(
"Open" to "02. open", "Open" to "02. open",
"High" to "03. high", "High" to "03. high",
"Low" to "04. low", "Low" to "04. low",
"Volume" to "06. volume", "Volume" to "06. volume",
"Latest" to "07. latest trading day" "Latest" to "07. latest trading day"
) )
data.forEach { data.forEach {
add( add(
NoticeMessage( NoticeMessage(
"${it.first}:".padEnd(pad).prependIndent() "${it.first}:".padEnd(pad).prependIndent()
+ quote.getString(it.second).unescapeXml() + quote.getString(it.second).unescapeXml()
) )
) )
} }
add( add(
NoticeMessage( NoticeMessage(
"Change:".padEnd(pad).prependIndent() "Change:".padEnd(pad).prependIndent()
+ quote.getString("09. change").unescapeXml() + quote.getString("09. change").unescapeXml()
+ " [" + quote.getString("10. change percent").unescapeXml() + ']' + " [" + quote.getString("10. change percent").unescapeXml() + ']'
) )
) )
} }
} }

View file

@ -120,8 +120,8 @@ class Weather2 : AbstractModule() {
fun getWeather(query: String, apiKey: String?): List<Message> { fun getWeather(query: String, apiKey: String?): List<Message> {
if (apiKey.isNullOrBlank()) { if (apiKey.isNullOrBlank()) {
throw ModuleException( throw ModuleException(
"${Weather2::class.java.name} is disabled.", "${Weather2::class.java.name} is disabled.",
"${WEATHER_CMD.capitalise()} is disabled. The API key is missing." "${WEATHER_CMD.capitalise()} is disabled. The API key is missing."
) )
} }
val owm = OWM(apiKey) val owm = OWM(apiKey)
@ -145,10 +145,10 @@ class Weather2 : AbstractModule() {
} }
if (cwd.hasCityName()) { if (cwd.hasCityName()) {
messages.add( messages.add(
PublicMessage( PublicMessage(
"City: ${cwd.cityName}, " + "City: ${cwd.cityName}, " +
country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]" country.name.replace('_', ' ').capitalizeWords() + " [${country.value}]"
) )
) )
cwd.mainData?.let { cwd.mainData?.let {
with(it) { with(it) {
@ -181,8 +181,8 @@ class Weather2 : AbstractModule() {
for (w in it) { for (w in it) {
w?.let { w?.let {
condition.append(' ') condition.append(' ')
.append(w.getDescription().capitalise()) .append(w.getDescription().capitalise())
.append('.') .append('.')
} }
} }
messages.add(NoticeMessage(condition.toString())) messages.add(NoticeMessage(condition.toString()))
@ -192,15 +192,15 @@ class Weather2 : AbstractModule() {
cwd.cityId?.let { cwd.cityId?.let {
if (it > 0) { if (it > 0) {
messages.add( messages.add(
NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN) NoticeMessage("https://openweathermap.org/city/$it", Colors.GREEN)
) )
} else { } else {
messages.add( messages.add(
NoticeMessage( NoticeMessage(
"https://openweathermap.org/find?q=" "https://openweathermap.org/find?q="
+ "$city,${code.uppercase()}".encodeUrl(), + "$city,${code.uppercase()}".encodeUrl(),
Colors.GREEN Colors.GREEN
) )
) )
} }
} }
@ -209,9 +209,9 @@ class Weather2 : AbstractModule() {
} catch (e: APIException) { } catch (e: APIException) {
if (e.code == 404) { if (e.code == 404) {
throw ModuleException( throw ModuleException(
"getWeather($query): API ${e.code}", "getWeather($query): API ${e.code}",
"The requested city was not found.", "The requested city was not found.",
e e
) )
} else { } else {
throw ModuleException("getWeather($query): API ${e.code}", e.message, e) throw ModuleException("getWeather($query): API ${e.code}", e.message, e)

View file

@ -60,15 +60,15 @@ class WolframAlpha : AbstractModule() {
try { try {
val query = args.trim().split("units=", limit = 2, ignoreCase = true) val query = args.trim().split("units=", limit = 2, ignoreCase = true)
event.sendMessage( event.sendMessage(
queryWolfram( queryWolfram(
query[0].trim(), query[0].trim(),
units = if (query.size == 2) { units = if (query.size == 2) {
getUnits(query[1].trim()) getUnits(query[1].trim())
} else { } else {
getUnits(properties[UNITS_PROP]) getUnits(properties[UNITS_PROP])
}, },
appId = properties[APPID_KEY_PROP] appId = properties[APPID_KEY_PROP]
) )
) )
} catch (e: ModuleException) { } catch (e: ModuleException) {
if (logger.isWarnEnabled) logger.warn(e.debugMessage, e) if (logger.isWarnEnabled) logger.warn(e.debugMessage, e)
@ -111,15 +111,15 @@ class WolframAlpha : AbstractModule() {
return urlReader.body return urlReader.body
} else { } else {
throw ModuleException( throw ModuleException(
"wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ", "wolfram($query): ${urlReader.responseCode} : ${urlReader.body} ",
urlReader.body.ifEmpty { urlReader.body.ifEmpty {
"Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})" "Looks like Wolfram Alpha isn't able to answer that. (${urlReader.responseCode})"
} }
) )
} }
} catch (ioe: IOException) { } catch (ioe: IOException) {
throw ModuleException( throw ModuleException(
"wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe "wolfram($query): IOE", "An IO Error occurred while querying Wolfram Alpha.", ioe
) )
} }
} else { } else {

View file

@ -322,7 +322,7 @@ class WorldTime : AbstractModule() {
put("ZULU", "Zulu") put("ZULU", "Zulu")
put("ZW", "Africa/Harare") put("ZW", "Africa/Harare")
ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) } ZoneId.getAvailableZoneIds().filter { it.length <= 3 && !containsKey(it) }
.forEach { tz -> put(tz, tz) } .forEach { tz -> put(tz, tz) }
} }
// The Time command // The Time command
@ -336,7 +336,7 @@ class WorldTime : AbstractModule() {
// Date/Time Format // Date/Time Format
private var dtf = private var dtf =
DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '") DateTimeFormatter.ofPattern("'The time is ${"'HH:mm'".bold()} on ${"'EEEE, d MMMM yyyy'".bold()} in '")
/** /**
* Returns the current Internet (beat) Time. * Returns the current Internet (beat) Time.

View file

@ -34,4 +34,4 @@ package net.thauvin.erik.mobibot.msg
* The `ErrorMessage` class. * The `ErrorMessage` class.
*/ */
class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : class ErrorMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) :
Message(msg, color, isError = true) Message(msg, color, isError = true)

View file

@ -36,11 +36,11 @@ import net.thauvin.erik.semver.Constants
* The `Message` class. * The `Message` class.
*/ */
open class Message @JvmOverloads constructor( open class Message @JvmOverloads constructor(
var msg: String, var msg: String,
var color: String = DEFAULT_COLOR, var color: String = DEFAULT_COLOR,
var isNotice: Boolean = false, var isNotice: Boolean = false,
isError: Boolean = false, isError: Boolean = false,
var isPrivate: Boolean = false var isPrivate: Boolean = false
) { ) {
companion object { companion object {
var DEFAULT_COLOR = Constants.EMPTY var DEFAULT_COLOR = Constants.EMPTY

View file

@ -34,5 +34,5 @@ package net.thauvin.erik.mobibot.msg
* The `NoticeMessage` class. * The `NoticeMessage` class.
*/ */
class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : class NoticeMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) :
Message(msg, color, isNotice = true) Message(msg, color, isNotice = true)

View file

@ -34,4 +34,4 @@ package net.thauvin.erik.mobibot.msg
* The `PrivateMessage` class. * The `PrivateMessage` class.
*/ */
class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) : class PrivateMessage @JvmOverloads constructor(msg: String, color: String = DEFAULT_COLOR) :
Message(msg, color, isPrivate = true) Message(msg, color, isPrivate = true)

View file

@ -76,8 +76,8 @@ abstract class SocialModule : AbstractModule() {
post(message = formatEntry(LinksManager.entries.links[index]), isDm = false) post(message = formatEntry(LinksManager.entries.links[index]), isDm = false)
} catch (e: ModuleException) { } catch (e: ModuleException) {
if (logger.isWarnEnabled) logger.warn( if (logger.isWarnEnabled) logger.warn(
"Failed to post entry ${index.toLinkLabel()} on $name.", "Failed to post entry ${index.toLinkLabel()} on $name.",
e e
) )
} }
} }

View file

@ -76,11 +76,11 @@ class AddonsTest {
assertThat(addons.names.ops, "names.ops").containsExactly("cycle") assertThat(addons.names.ops, "names.ops").containsExactly("cycle")
assertThat(addons.names.commands, "names.command").containsExactly( assertThat(addons.names.commands, "names.command").containsExactly(
"joke", "joke",
"rock", "rock",
"paper", "paper",
"scissors", "scissors",
"ignore" "ignore"
) )
} }
} }

View file

@ -46,9 +46,9 @@ object ExceptionSanitizer {
with(this) { with(this) {
if (!cause?.message.isNullOrBlank()) { if (!cause?.message.isNullOrBlank()) {
return ModuleException( return ModuleException(
debugMessage, debugMessage,
cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate), cause?.javaClass?.name + ": " + cause?.message?.replaceEach(search, obfuscate),
this this
) )
} else if (!message.isNullOrBlank()) { } else if (!message.isNullOrBlank()) {
return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this) return ModuleException(debugMessage, message?.replaceEach(search, obfuscate), this)

View file

@ -68,7 +68,7 @@ class PinboardTest : LocalProperties() {
private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean { private fun validatePin(apiToken: String, url: String, vararg matches: String): Boolean {
val response = val response =
URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body URL("https://api.pinboard.in/v1/posts/get?auth_token=${apiToken}&tag=test&" + url.encodeUrl()).reader().body
matches.forEach { matches.forEach {
if (!response.contains(it)) { if (!response.contains(it)) {

View file

@ -73,7 +73,7 @@ import java.util.*
*/ */
class UtilsTest { class UtilsTest {
private val ascii = private val ascii =
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
private val cal = Calendar.getInstance() private val cal = Calendar.getInstance()
private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0) private val localDateTime = LocalDateTime.of(1952, 2, 17, 12, 30, 0)
private val test = "This is a test." private val test = "This is a test."
@ -89,7 +89,7 @@ class UtilsTest {
val sep = '/' val sep = '/'
val url = "https://erik.thauvin.net" val url = "https://erik.thauvin.net"
assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)") assertThat(dir.appendIfMissing(File.separatorChar), "appendIfMissing(dir)")
.isEqualTo(dir + File.separatorChar) .isEqualTo(dir + File.separatorChar)
assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep") assertThat(url.appendIfMissing(sep), "appendIfMissing(url)").isEqualTo("$url$sep")
assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep") assertThat("$url$sep".appendIfMissing(sep), "appendIfMissing($url$sep)").isEqualTo("$url$sep")
} }
@ -115,24 +115,24 @@ class UtilsTest {
fun textCapitaliseWords() { fun textCapitaliseWords() {
assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.") assertThat(test.capitalizeWords(), "captiatlizeWords(test)").isEqualTo("This Is A Test.")
assertThat("Already Capitalized".capitalizeWords(), "already capitalized") assertThat("Already Capitalized".capitalizeWords(), "already capitalized")
.isEqualTo("Already Capitalized") .isEqualTo("Already Capitalized")
assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ") assertThat(" a test ".capitalizeWords(), "with spaces").isEqualTo(" A Test ")
} }
@Test @Test
fun testColorize() { fun testColorize() {
assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo( assertThat(ascii.colorize(Colors.REVERSE), "reverse.colorize()").isEqualTo(
Colors.REVERSE + ascii + Colors.REVERSE Colors.REVERSE + ascii + Colors.REVERSE
) )
assertThat(ascii.colorize(Colors.RED), "red.colorize()") assertThat(ascii.colorize(Colors.RED), "red.colorize()")
.isEqualTo(Colors.RED + ascii + Colors.NORMAL) .isEqualTo(Colors.RED + ascii + Colors.NORMAL)
assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)") assertThat(ascii.colorize(Colors.BOLD), "colorized(bold)")
.isEqualTo(Colors.BOLD + ascii + Colors.BOLD) .isEqualTo(Colors.BOLD + ascii + Colors.BOLD)
assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("") assertThat(null.colorize(Colors.RED), "null.colorize()").isEqualTo("")
assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("") assertThat("".colorize(Colors.RED), "colorize()").isEqualTo("")
assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii) assertThat(ascii.colorize(DEFAULT_COLOR), "ascii.colorize()").isEqualTo(ascii)
assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()") assertThat(" ".colorize(Colors.NORMAL), "blank.colorize()")
.isEqualTo(Colors.NORMAL + " " + Colors.NORMAL) .isEqualTo(Colors.NORMAL + " " + Colors.NORMAL)
} }
@Test @Test
@ -164,19 +164,19 @@ class UtilsTest {
fun testHelpCmdSyntax() { fun testHelpCmdSyntax() {
val bot = "mobibot" val bot = "mobibot"
assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)") assertThat(helpCmdSyntax("%c $test %n $test", bot, false), "helpCmdSyntax(private)")
.isEqualTo("$bot: $test $bot $test") .isEqualTo("$bot: $test $bot $test")
assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)") assertThat(helpCmdSyntax("%c %n $test %c $test %n", bot, true), "helpCmdSyntax(public)")
.isEqualTo("/msg $bot $bot $test /msg $bot $test $bot") .isEqualTo("/msg $bot $bot $test /msg $bot $test $bot")
} }
@Test @Test
fun testHelpFormat() { fun testHelpFormat() {
assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)") assertThat(helpFormat(test, isBold = true, isIndent = false), "helpFormat(bold)")
.isEqualTo("${Colors.BOLD}$test${Colors.BOLD}") .isEqualTo("${Colors.BOLD}$test${Colors.BOLD}")
assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)") assertThat(helpFormat(test, isBold = false, isIndent = true), "helpFormat(indent)")
.isEqualTo(test.prependIndent()) .isEqualTo(test.prependIndent())
assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)") assertThat(helpFormat(test, isBold = true, isIndent = true), "helpFormat(bold,indent)")
.isEqualTo(test.colorize(Colors.BOLD).prependIndent()) .isEqualTo(test.colorize(Colors.BOLD).prependIndent())
} }
@ -218,15 +218,15 @@ class UtilsTest {
val search = arrayOf("one", "two", "three") val search = arrayOf("one", "two", "three")
val replace = arrayOf("1", "2", "3") val replace = arrayOf("1", "2", "3")
assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3") assertThat(search.joinToString(",").replaceEach(search, replace), "replaceEach(1,2,3")
.isEqualTo(replace.joinToString(",")) .isEqualTo(replace.joinToString(","))
assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test) assertThat(test.replaceEach(search, replace), "replaceEach(nothing)").isEqualTo(test)
assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)") assertThat(test.replaceEach(arrayOf("t", "e"), arrayOf("", "E")), "replaceEach($test)")
.isEqualTo(test.replace("t", "").replace("e", "E")) .isEqualTo(test.replace("t", "").replace("e", "E"))
assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)") assertThat(test.replaceEach(search, emptyArray()), "replaceEach(search, empty)")
.isEqualTo(test) .isEqualTo(test)
} }
@Test @Test
@ -258,7 +258,7 @@ class UtilsTest {
@Test @Test
fun testUnescapeXml() { fun testUnescapeXml() {
assertThat("&lt;a name=&quot;test &amp; &apos;&#39;&quot;&gt;".unescapeXml()).isEqualTo( assertThat("&lt;a name=&quot;test &amp; &apos;&#39;&quot;&gt;".unescapeXml()).isEqualTo(
"<a name=\"test & ''\">" "<a name=\"test & ''\">"
) )
} }

View file

@ -40,14 +40,14 @@ class InfoTest {
@Test(groups = ["commands"]) @Test(groups = ["commands"])
fun testToUptime() { fun testToUptime() {
assertThat( assertThat(
547800300076L.toUptime(), 547800300076L.toUptime(),
"upTime(full)" "upTime(full)"
).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes") ).isEqualTo("17 years 4 months 2 weeks 1 day 6 hours 45 minutes")
assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes") assertThat(24300000L.toUptime(), "upTime(hours minutes)").isEqualTo("6 hours 45 minutes")
assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes") assertThat(110700000L.toUptime(), "upTime(days hours minutes)").isEqualTo("1 day 6 hours 45 minutes")
assertThat( assertThat(
1320300000L.toUptime(), 1320300000L.toUptime(),
"upTime(weeks days hours minutes)" "upTime(weeks days hours minutes)"
).isEqualTo("2 weeks 1 day 6 hours 45 minutes") ).isEqualTo("2 weeks 1 day 6 hours 45 minutes")
assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes") assertThat(2700000L.toUptime(), "upTime(45 minutes)").isEqualTo("45 minutes")
assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute") assertThat(60000L.toUptime(), "upTime(1 minute)").isEqualTo("1 minute")

View file

@ -48,13 +48,13 @@ class RecapTest {
assertThat(Recap.recaps, "Recap.recaps").all { assertThat(Recap.recaps, "Recap.recaps").all {
size().isEqualTo(Recap.MAX_RECAPS) size().isEqualTo(Recap.MAX_RECAPS)
prop(MutableList<String>::first) prop(MutableList<String>::first)
.matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex()) .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender11: test 11".toRegex())
prop(MutableList<String>::last) prop(MutableList<String>::last)
.matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex()) .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender20: test 20".toRegex())
} }
Recap.storeRecap("sender", "test action", true) Recap.storeRecap("sender", "test action", true)
assertThat(Recap.recaps.last()) assertThat(Recap.recaps.last())
.matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex()) .matches("[1-2]\\d{3}-[01]\\d-[0-3]\\d [0-2]\\d:[0-6]\\d - sender test action".toRegex())
} }
} }

View file

@ -47,8 +47,8 @@ class LinksManagerTest {
fun fetchTitle() { fun fetchTitle() {
assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog") assertThat(linksManager.fetchTitle("https://erik.thauvin.net/"), "fetchTitle(Erik)").contains("Erik's Weblog")
assertThat( assertThat(
linksManager.fetchTitle("https://www.google.com/foo"), linksManager.fetchTitle("https://www.google.com/foo"),
"fetchTitle(Foo)" "fetchTitle(Foo)"
).isEqualTo(Constants.NO_TITLE) ).isEqualTo(Constants.NO_TITLE)
} }

View file

@ -45,14 +45,14 @@ class ViewTest {
for (i in 1..10) { for (i in 1..10) {
LinksManager.entries.links.add( LinksManager.entries.links.add(
EntryLink( EntryLink(
"https://www.example.com/$i", "https://www.example.com/$i",
"Example $i", "Example $i",
"nick$i", "nick$i",
"login$i", "login$i",
"#channel", "#channel",
emptyList() emptyList()
) )
) )
} }

View file

@ -46,14 +46,14 @@ class EntriesUtilsTest {
private val links = buildList { private val links = buildList {
for (i in 0..5) { for (i in 0..5) {
add( add(
EntryLink( EntryLink(
"https://www.mobitopia.org/$i", "https://www.mobitopia.org/$i",
"Mobitopia$i", "Mobitopia$i",
"Skynx$i", "Skynx$i",
"JimH$i", "JimH$i",
"#mobitopia$i", "#mobitopia$i",
listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") listOf("tag1", "tag2", "tag3", "TAG4", "Tag5")
) )
) )
} }
} }
@ -67,7 +67,7 @@ class EntriesUtilsTest {
fun printLinkTest() { fun printLinkTest() {
for (i in links.indices) { for (i in links.indices) {
assertThat( assertThat(
printLink(i - 1, links[i]), "link $i" printLink(i - 1, links[i]), "link $i"
).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )") ).isEqualTo("L$i: [Skynx$i] \u0002Mobitopia$i\u0002 ( \u000303https://www.mobitopia.org/$i\u000F )")
} }
@ -79,7 +79,7 @@ class EntriesUtilsTest {
fun printTagsTest() { fun printTagsTest() {
for (i in links.indices) { for (i in links.indices) {
assertThat( assertThat(
printTags(i - 1, links[i]), "tag $i" printTags(i - 1, links[i]), "tag $i"
).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5") ).isEqualTo("L${i}T: tag1, tag2, tag3, tag4, tag5")
} }
} }

View file

@ -48,8 +48,8 @@ import java.util.*
*/ */
class EntryLinkTest { class EntryLinkTest {
private val entryLink = EntryLink( private val entryLink = EntryLink(
"https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia", "https://www.mobitopia.org/", "Mobitopia", "Skynx", "JimH", "#mobitopia",
listOf("tag1", "tag2", "tag3", "TAG4", "Tag5") listOf("tag1", "tag2", "tag3", "TAG4", "Tag5")
) )
@Test(groups = ["entries"]) @Test(groups = ["entries"])
@ -117,12 +117,12 @@ class EntryLinkTest {
entryLink.setTags("+mobitopia") entryLink.setTags("+mobitopia")
entryLink.setTags("-mobitopia") entryLink.setTags("-mobitopia")
assertThat( assertThat(
entryLink.formatTags(","), entryLink.formatTags(","),
"formatTags(',')" "formatTags(',')"
).isEqualTo("tag1,tag2,tag3,tag4,mobitopia") ).isEqualTo("tag1,tag2,tag3,tag4,mobitopia")
entryLink.setTags("-tag4 tag5") entryLink.setTags("-tag4 tag5")
assertThat( assertThat(
entryLink.formatTags(" ", ","), "formatTag(' ',',')" entryLink.formatTags(" ", ","), "formatTag(' ',',')"
).isEqualTo(",tag1 tag2 tag3 mobitopia tag5") ).isEqualTo(",tag1 tag2 tag3 mobitopia tag5")
val size = entryLink.tags.size val size = entryLink.tags.size
entryLink.setTags("") entryLink.setTags("")

View file

@ -42,21 +42,21 @@ class ChatGptTest : LocalProperties() {
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testApiKey() { fun testApiKey() {
assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) } assertFailure { ChatGpt.chat("1 gallon to liter", "", 0) }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasNoCause() .hasNoCause()
} }
@Test(groups = ["modules", "no-ci"]) @Test(groups = ["modules", "no-ci"])
fun testChat() { fun testChat() {
val apiKey = getProperty(ChatGpt.API_KEY_PROP) val apiKey = getProperty(ChatGpt.API_KEY_PROP)
assertThat( assertThat(
ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100) ChatGpt.chat("how do I make an HTTP request in Javascript?", apiKey, 100)
).contains("XMLHttpRequest") ).contains("XMLHttpRequest")
assertThat( assertThat(
ChatGpt.chat("how do I encode a URL in java?", apiKey, 60) ChatGpt.chat("how do I encode a URL in java?", apiKey, 60)
).contains("URLEncoder") ).contains("URLEncoder")
assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) } assertFailure { ChatGpt.chat("1 liter to gallon", apiKey, 0) }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
} }
} }

View file

@ -49,7 +49,7 @@ import org.testng.annotations.Test
/** /**
* The `CurrencyConvertTest` class. * The `CurrencyConvertTest` class.
*/ */
class CurrencyConverterTest: LocalProperties() { class CurrencyConverterTest : LocalProperties() {
@BeforeClass @BeforeClass
@Throws(ModuleException::class) @Throws(ModuleException::class)
@ -62,22 +62,22 @@ class CurrencyConverterTest: LocalProperties() {
fun testConvertCurrency() { fun testConvertCurrency() {
val apiKey = getProperty(CurrencyConverter.API_KEY_PROP) val apiKey = getProperty(CurrencyConverter.API_KEY_PROP)
assertThat( assertThat(
convertCurrency(apiKey,"100 USD to EUR").msg, convertCurrency(apiKey, "100 USD to EUR").msg,
"convertCurrency(100 USD to EUR)" "convertCurrency(100 USD to EUR)"
).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex()) ).matches("100 United States Dollar = \\d{2,3}\\.\\d{2,3} Euro".toRegex())
assertThat( assertThat(
convertCurrency(apiKey,"1 USD to GBP").msg, convertCurrency(apiKey, "1 USD to GBP").msg,
"convertCurrency(1 USD to BGP)" "convertCurrency(1 USD to BGP)"
).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex()) ).matches("1 United States Dollar = 0\\.\\d{2,3} Pound Sterling".toRegex())
assertThat( assertThat(
convertCurrency(apiKey,"100,000.00 CAD to USD").msg, convertCurrency(apiKey, "100,000.00 CAD to USD").msg,
"convertCurrency(100,000.00 GBP to USD)" "convertCurrency(100,000.00 GBP to USD)"
).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex()) ).matches("100,000.00 Canadian Dollar = \\d+\\.\\d{2,3} United States Dollar".toRegex())
assertThat(convertCurrency(apiKey,"100 USD to USD"), "convertCurrency(100 USD to USD)").all { assertThat(convertCurrency(apiKey, "100 USD to USD"), "convertCurrency(100 USD to USD)").all {
prop(Message::msg).contains("You're kidding, right?") prop(Message::msg).contains("You're kidding, right?")
isInstanceOf(PublicMessage::class.java) isInstanceOf(PublicMessage::class.java)
} }
assertThat(convertCurrency(apiKey,"100 USD"), "convertCurrency(100 USD)").all { assertThat(convertCurrency(apiKey, "100 USD"), "convertCurrency(100 USD)").all {
prop(Message::msg).contains("Invalid query.") prop(Message::msg).contains("Invalid query.")
isInstanceOf(ErrorMessage::class.java) isInstanceOf(ErrorMessage::class.java)
} }

View file

@ -42,12 +42,12 @@ class DiceTest {
fun testRoll() { fun testRoll() {
assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002") assertThat(Dice.roll(1, 1), "roll(1d1)").isEqualTo("\u00021\u0002")
assertThat(Dice.roll(2, 1), "roll(2d1)") assertThat(Dice.roll(2, 1), "roll(2d1)")
.isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002") .isEqualTo("\u00021\u0002 + \u00021\u0002 = \u00022\u0002")
assertThat(Dice.roll(5, 1), "roll(5d1)") assertThat(Dice.roll(5, 1), "roll(5d1)")
.isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002") .isEqualTo("\u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 + \u00021\u0002 = \u00025\u0002")
assertThat(Dice.roll(2, 6), "roll(2d6)") assertThat(Dice.roll(2, 6), "roll(2d6)")
.matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex()) .matches("\u0002[1-6]\u0002 \\+ \u0002[1-6]\u0002 = \u0002[1-9][0-2]?\u0002".toRegex())
assertThat(Dice.roll(3, 7), "roll(3d7)") assertThat(Dice.roll(3, 7), "roll(3d7)")
.matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex()) .matches("\u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 \\+ \u0002[1-7]\u0002 = \u0002\\d{1,2}\u0002".toRegex())
} }
} }

View file

@ -48,19 +48,19 @@ class GoogleSearchTest : LocalProperties() {
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testAPIKeys() { fun testAPIKeys() {
assertThat( assertThat(
searchGoogle("", "apikey", "cssKey").first(), searchGoogle("", "apikey", "cssKey").first(),
"searchGoogle(empty)" "searchGoogle(empty)"
).isInstanceOf(ErrorMessage::class.java) ).isInstanceOf(ErrorMessage::class.java)
assertFailure { searchGoogle("test", "", "apiKey") } assertFailure { searchGoogle("test", "", "apiKey") }
.isInstanceOf(ModuleException::class.java).hasNoCause() .isInstanceOf(ModuleException::class.java).hasNoCause()
assertFailure { searchGoogle("test", "apiKey", "") } assertFailure { searchGoogle("test", "apiKey", "") }
.isInstanceOf(ModuleException::class.java).hasNoCause() .isInstanceOf(ModuleException::class.java).hasNoCause()
assertFailure { searchGoogle("test", "apiKey", "cssKey") } assertFailure { searchGoogle("test", "apiKey", "cssKey") }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasMessage("API key not valid. Please pass a valid API key.") .hasMessage("API key not valid. Please pass a valid API key.")
} }
@Test(groups = ["no-ci", "modules"]) @Test(groups = ["no-ci", "modules"])

View file

@ -42,13 +42,13 @@ class MastodonTest : LocalProperties() {
fun testToot() { fun testToot() {
val msg = "Testing Mastodon API from ${getHostName()}" val msg = "Testing Mastodon API from ${getHostName()}"
assertThat( assertThat(
toot( toot(
getProperty(Mastodon.ACCESS_TOKEN_PROP), getProperty(Mastodon.ACCESS_TOKEN_PROP),
getProperty(Mastodon.INSTANCE_PROP), getProperty(Mastodon.INSTANCE_PROP),
getProperty(Mastodon.HANDLE_PROP), getProperty(Mastodon.HANDLE_PROP),
msg, msg,
true true
) )
).contains(msg) ).contains(msg)
} }
} }

View file

@ -44,58 +44,58 @@ import java.lang.reflect.Method
*/ */
class ModuleExceptionTest { class ModuleExceptionTest {
companion object { companion object {
const val debugMessage = "debugMessage" const val DEBUG_MESSAGE = "debugMessage"
const val message = "message" const val MESSAGE = "message"
} }
@DataProvider(name = "dp") @DataProvider(name = "dp")
fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array<Array<Any>> { fun createData(@Suppress("UNUSED_PARAMETER") m: Method?): Array<Array<Any>> {
return arrayOf( return arrayOf(
arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com"))), arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com"))),
arrayOf(ModuleException(debugMessage, message, IOException("URL http://foobar.com?"))), arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foobar.com?"))),
arrayOf(ModuleException(debugMessage, message)) arrayOf(ModuleException(DEBUG_MESSAGE, MESSAGE))
) )
} }
@Test(dataProvider = "dp") @Test(dataProvider = "dp")
fun testGetDebugMessage(e: ModuleException) { fun testGetDebugMessage(e: ModuleException) {
assertThat(e::debugMessage).isEqualTo(debugMessage) assertThat(e::debugMessage).isEqualTo(DEBUG_MESSAGE)
} }
@Test(dataProvider = "dp") @Test(dataProvider = "dp")
fun testGetMessage(e: ModuleException) { fun testGetMessage(e: ModuleException) {
assertThat(e).hasMessage(message) assertThat(e).hasMessage(MESSAGE)
} }
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testSanitizeMessage() { fun testSanitizeMessage() {
val apiKey = "1234567890" val apiKey = "1234567890"
var e = ModuleException(debugMessage, message, IOException("URL http://foo.com?apiKey=$apiKey&userID=me")) var e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException("URL http://foo.com?apiKey=$apiKey&userID=me"))
assertThat( assertThat(
e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))" e.sanitize(apiKey, "", "me").message, "ModuleException(debugMessage, message, IOException(url))"
).isNotNull().all { ).isNotNull().all {
contains("xxxxxxxxxx", "userID=xx", "java.io.IOException") contains("xxxxxxxxxx", "userID=xx", "java.io.IOException")
doesNotContain(apiKey, "me") doesNotContain(apiKey, "me")
} }
e = ModuleException(debugMessage, message, null) e = ModuleException(DEBUG_MESSAGE, MESSAGE, null)
assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(message) assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, null)").hasMessage(MESSAGE)
e = ModuleException(debugMessage, message, IOException()) e = ModuleException(DEBUG_MESSAGE, MESSAGE, IOException())
assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(message) assertThat(e.sanitize(apiKey), "ModuleException(debugMessage, message, IOException())").hasMessage(MESSAGE)
e = ModuleException(debugMessage, apiKey) e = ModuleException(DEBUG_MESSAGE, apiKey)
assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull() assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, apiKey)").isNotNull()
.doesNotContain(apiKey) .doesNotContain(apiKey)
val msg: String? = null val msg: String? = null
e = ModuleException(debugMessage, msg, IOException(msg)) e = ModuleException(DEBUG_MESSAGE, msg, IOException(msg))
assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, msg, IOException(msg))").isNull() assertThat(e.sanitize(apiKey).message, "ModuleException(debugMessage, msg, IOException(msg))").isNull()
e = ModuleException(debugMessage, msg, IOException("foo is $apiKey")) e = ModuleException(DEBUG_MESSAGE, msg, IOException("foo is $apiKey"))
assertThat( assertThat(
e.sanitize(" ", apiKey, "foo").message, e.sanitize(" ", apiKey, "foo").message,
"ModuleException(debugMessage, msg, IOException(foo is $apiKey))" "ModuleException(debugMessage, msg, IOException(foo is $apiKey))"
).isNotNull().all { ).isNotNull().all {
doesNotContain(apiKey) doesNotContain(apiKey)
endsWith("xxx is xxxxxxxxxx") endsWith("xxx is xxxxxxxxxx")

View file

@ -60,7 +60,7 @@ class StockQuoteTest : LocalProperties() {
assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex()) assertThat(messages, "getQuote($symbol)").index(0).prop(Message::msg).matches("Symbol: AAPL .*".toRegex())
assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex()) assertThat(messages, "getQuote($symbol)").index(1).prop(Message::msg).matches(buildMatch("Price").toRegex())
assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg) assertThat(messages, "getQuote($symbol)").index(2).prop(Message::msg)
.matches(buildMatch("Previous").toRegex()) .matches(buildMatch("Previous").toRegex())
assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex()) assertThat(messages, "getQuote($symbol)").index(3).prop(Message::msg).matches(buildMatch("Open").toRegex())
symbol = "blahfoo" symbol = "blahfoo"

View file

@ -45,11 +45,11 @@ class WolframAlphaTest : LocalProperties() {
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testAppId() { fun testAppId() {
assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") } assertFailure { queryWolfram("1 gallon to liter", appId = "DEMO") }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
.hasMessage("Error 1: Invalid appid") .hasMessage("Error 1: Invalid appid")
assertFailure { queryWolfram("1 gallon to liter", appId = "") } assertFailure { queryWolfram("1 gallon to liter", appId = "") }
.isInstanceOf(ModuleException::class.java) .isInstanceOf(ModuleException::class.java)
} }
@Test(groups = ["modules", "no-ci"]) @Test(groups = ["modules", "no-ci"])
@ -62,8 +62,8 @@ class WolframAlphaTest : LocalProperties() {
query = "SFO to LAX" query = "SFO to LAX"
assertThat( assertThat(
queryWolfram(query, WolframAlpha.METRIC, apiKey), queryWolfram(query, WolframAlpha.METRIC, apiKey),
"queryWolfram($query)" "queryWolfram($query)"
).contains("kilometers") ).contains("kilometers")
} catch (e: ModuleException) { } catch (e: ModuleException) {
// Avoid displaying api key in CI logs // Avoid displaying api key in CI logs

View file

@ -49,9 +49,9 @@ class WordTimeTest {
@Test(groups = ["modules"]) @Test(groups = ["modules"])
fun testTime() { fun testTime() {
assertThat(time(), "time()").matches( assertThat(time(), "time()").matches(
("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " + ("The time is ${Colors.BOLD}\\d{1,2}:\\d{2}${Colors.BOLD} " +
"on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " + "on ${Colors.BOLD}\\w+, \\d{1,2} \\w+ \\d{4}${Colors.BOLD} " +
"in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex() "in ${Colors.BOLD}Los Angeles${Colors.BOLD}").toRegex()
) )
assertThat(time(""), "time()").endsWith("Los Angeles".bold()) assertThat(time(""), "time()").endsWith("Los Angeles".bold())
assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold()) assertThat(time("PST"), "time(PST)").endsWith("Los Angeles".bold())