From dfa6f1aaf82fd4913281b908da37b7c1ba54fc4d Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 29 May 2016 20:00:09 +0200 Subject: [PATCH 1/1] Use a single state and trigger for weather services --- .../rhynodge/webpages/weather/WeatherState.kt | 40 ++++++++++ .../rhynodge/webpages/weather/WeatherTrigger.kt | 90 ++++++++++++++++++++++ .../webpages/weather/wettercom/WetterComFilter.kt | 3 +- .../weather/wettercom/WetterComHamburgWatcher.kt | 3 +- .../webpages/weather/wettercom/WetterComState.kt | 41 ---------- .../webpages/weather/wettercom/WetterComTrigger.kt | 77 ------------------ .../webpages/weather/wetterde/WetterDeFilter.kt | 5 +- .../weather/wetterde/WetterDeHamburgWatcher.kt | 3 +- .../webpages/weather/wetterde/WetterDeState.kt | 39 ---------- .../webpages/weather/wetterde/WetterDeTrigger.kt | 90 ---------------------- .../rhynodge/webpages/weather/WeatherStateTest.kt | 70 +++++++++++++++++ .../webpages/weather/WeatherTriggerTest.kt | 88 +++++++++++++++++++++ .../weather/wettercom/WetterComFilterTest.kt | 3 +- .../weather/wettercom/WetterComStateTest.kt | 62 --------------- .../weather/wettercom/WetterComTriggerTest.kt | 86 --------------------- .../weather/wetterde/WetterDeFilterTest.kt | 5 +- .../webpages/weather/wetterde/WetterDeStateTest.kt | 58 -------------- .../weather/wetterde/WetterDeTriggerTest.kt | 88 --------------------- 18 files changed, 302 insertions(+), 549 deletions(-) create mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherState.kt create mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTrigger.kt delete mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComState.kt delete mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTrigger.kt delete mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeState.kt delete mode 100644 src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt create mode 100644 src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherStateTest.kt create mode 100644 src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTriggerTest.kt delete mode 100644 src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComStateTest.kt delete mode 100644 src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt delete mode 100644 src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt delete mode 100644 src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherState.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherState.kt new file mode 100644 index 0000000..dff71d7 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherState.kt @@ -0,0 +1,40 @@ +package net.pterodactylus.rhynodge.webpages.weather + +import com.fasterxml.jackson.annotation.JsonGetter +import com.fasterxml.jackson.annotation.JsonProperty +import net.pterodactylus.rhynodge.states.AbstractState +import java.time.Instant +import java.time.ZoneId +import java.time.ZonedDateTime + +/** + * Contains a weather state. + * + * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) + */ +class WeatherState(val service: String, val dateTime: ZonedDateTime) : AbstractState(true), Iterable { + + constructor(@JsonProperty("service") service: String, @JsonProperty("dateTime") time: Long) : + this(service, Instant.ofEpochMilli(time).atZone(ZoneId.of("Europe/Berlin"))) + + @JsonProperty("hours") + val hours: List = mutableListOf() + + val timeMillis: Long + @JsonGetter("dateTime") + get() = dateTime.toInstant().toEpochMilli() + + operator fun plusAssign(hourState: HourState) { + (hours as MutableList).add(hourState) + } + + override fun iterator(): Iterator { + return hours.iterator() + } + + override fun equals(other: Any?): Boolean { + other as? WeatherState ?: return false + return (dateTime == other.dateTime) and (hours == other.hours) + } + +} diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTrigger.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTrigger.kt new file mode 100644 index 0000000..4bc46d4 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTrigger.kt @@ -0,0 +1,90 @@ +package net.pterodactylus.rhynodge.webpages.weather + +import kotlinx.html.body +import kotlinx.html.div +import kotlinx.html.h1 +import kotlinx.html.head +import kotlinx.html.html +import kotlinx.html.img +import kotlinx.html.stream.createHTML +import kotlinx.html.style +import kotlinx.html.unsafe +import net.pterodactylus.rhynodge.Reaction +import net.pterodactylus.rhynodge.State +import net.pterodactylus.rhynodge.Trigger +import net.pterodactylus.rhynodge.output.DefaultOutput +import net.pterodactylus.rhynodge.output.Output +import java.text.DateFormat +import java.time.temporal.ChronoUnit +import java.util.Locale + +/** + * Detects changes in the weather and creates email texts. + * + * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) + */ +class WeatherTrigger : Trigger { + + private val dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, Locale.ENGLISH) + private lateinit var state: WeatherState + private var changed = false + + override fun mergeStates(previousState: State, currentState: State): State { + changed = previousState != currentState + state = currentState as WeatherState + return currentState + } + + override fun triggers(): Boolean { + return changed + } + + override fun output(reaction: Reaction): Output { + val output = DefaultOutput("The Weather (according to ${state.service}) on ${dateFormatter.format(state.dateTime.toInstant().toEpochMilli())}") + output.addText("text/html", generateHtmlOutput()) + return output + } + + private fun generateHtmlOutput(): String { + return createHTML().html { + head { + style("text/css") { + unsafe { + +".hour-state { display: table-row; } " + +".hour-state > div { display: table-cell; padding-right: 1em; } " + } + } + } + body { + val startTime = state.dateTime.toInstant() + h1 { +"The Weather (according to wetter.de) on %s".format(dateFormatter.format(startTime.toEpochMilli())) } + state.forEach { + div("hour-state") { + div("time") { +"%tH:% { - - constructor(@JsonProperty("dateTime") time: Long) : - this(Instant.ofEpochMilli(time).atZone(ZoneId.of("Europe/Berlin"))) - - @JsonProperty("hours") - val hours: List = mutableListOf() - - val timeMillis: Long - @JsonGetter("dateTime") - get() = dateTime.toInstant().toEpochMilli() - - operator fun plusAssign(hourState: HourState) { - (hours as MutableList).add(hourState) - } - - override fun iterator(): Iterator { - return hours.iterator() - } - - override fun equals(other: Any?): Boolean { - other as? WetterComState ?: return false - return (dateTime == other.dateTime) and (hours == other.hours) - } - -} diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTrigger.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTrigger.kt deleted file mode 100644 index 7a9e7f0..0000000 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTrigger.kt +++ /dev/null @@ -1,77 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wettercom - -import kotlinx.html.body -import kotlinx.html.div -import kotlinx.html.h1 -import kotlinx.html.head -import kotlinx.html.html -import kotlinx.html.img -import kotlinx.html.stream.createHTML -import kotlinx.html.style -import kotlinx.html.unsafe -import net.pterodactylus.rhynodge.Reaction -import net.pterodactylus.rhynodge.State -import net.pterodactylus.rhynodge.Trigger -import net.pterodactylus.rhynodge.output.DefaultOutput -import net.pterodactylus.rhynodge.output.Output -import java.text.DateFormat -import java.time.temporal.ChronoUnit.HOURS -import java.util.Locale - -/** - * TODO - * - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -class WetterComTrigger : Trigger { - - private val dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, Locale.ENGLISH) - private var newState = false - private lateinit var currentState: WetterComState - - override fun mergeStates(previousState: State, currentState: State): State? { - newState = previousState != currentState - this.currentState = currentState as WetterComState - return currentState - } - - override fun triggers(): Boolean { - return newState - } - - override fun output(reaction: Reaction): Output { - val output = DefaultOutput("The weather (according to wetter.com) on %s".format(dateFormatter.format(currentState.dateTime.toInstant().toEpochMilli()))) - output.addText("text/html", htmlOutput()) - return output - } - - private fun htmlOutput(): String { - return createHTML().html { - head { - style("text/css") { - unsafe { - +".hour-state { display: table-row; } " - +".hour-state > div { display: table-cell; padding-right: 1em; } " - } - } - } - body { - val startTime = currentState.dateTime.toInstant() - h1 { +"The Weather (according to wetter.com) on %s".format(dateFormatter.format(startTime.toEpochMilli())) } - currentState.forEach { - div("hour-state") { - div("time") { +"%tH:% { - - constructor(@JsonProperty("dateTime") timeMillis: Long) : this(Instant.ofEpochMilli(timeMillis).atZone(of("Europe/Berlin"))) - - val hours: List = mutableListOf() - - val timeMillis: Long - @JsonProperty("dateTime") get() { - return dateTime.toInstant().toEpochMilli() - } - - override fun iterator(): Iterator = hours.iterator() - - operator fun plusAssign(hourState: HourState) { - (hours as MutableList).add(hourState) - } - - override fun equals(other: Any?): Boolean { - if (other !is WetterDeState) { - return false - } - return (dateTime == other.dateTime) and (hours == other.hours) - } - -} diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt b/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt deleted file mode 100644 index 178fce4..0000000 --- a/src/main/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTrigger.kt +++ /dev/null @@ -1,90 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wetterde - -import kotlinx.html.body -import kotlinx.html.div -import kotlinx.html.h1 -import kotlinx.html.head -import kotlinx.html.html -import kotlinx.html.img -import kotlinx.html.stream.createHTML -import kotlinx.html.style -import kotlinx.html.unsafe -import net.pterodactylus.rhynodge.Reaction -import net.pterodactylus.rhynodge.State -import net.pterodactylus.rhynodge.Trigger -import net.pterodactylus.rhynodge.output.DefaultOutput -import net.pterodactylus.rhynodge.output.Output -import java.text.DateFormat -import java.time.temporal.ChronoUnit -import java.util.Locale - -/** - * TODO - * - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -class WetterDeTrigger : Trigger { - - private val dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, Locale.ENGLISH) - private lateinit var state: WetterDeState - private var changed = false - - override fun mergeStates(previousState: State, currentState: State): State { - changed = previousState != currentState - state = currentState as WetterDeState - return currentState - } - - override fun triggers(): Boolean { - return changed - } - - override fun output(reaction: Reaction): Output { - val output = DefaultOutput("The Weather (according to wetter.de) on %s".format(dateFormatter.format(state.dateTime.toInstant().toEpochMilli()))) - output.addText("text/html", generateHtmlOutput()) - return output - } - - private fun generateHtmlOutput(): String { - return createHTML().html { - head { - style("text/css") { - unsafe { - +".hour-state { display: table-row; } " - +".hour-state > div { display: table-cell; padding-right: 1em; } " - } - } - } - body { - val startTime = state.dateTime.toInstant() - h1 { +"The Weather (according to wetter.de) on %s".format(dateFormatter.format(startTime.toEpochMilli())) } - state.forEach { - div("hour-state") { - div("time") { +"%tH:%)) + } + + @Test + fun stateIsSerializableAsJson() { + val objectMapper = ObjectMapper() + val now = now + val originalState = WeatherState(SERVICE_NAME, ZonedDateTime.from(now)) + originalState += HourState(0, 10, null, 0.05, 0.0, WindDirection.NORTH, 5, null, null, "Fine", "http://1") + originalState += HourState(1, 12, null, 0.1, 2.0, WindDirection.WEST, 8, null, null, "Superb", "http://2") + val json = objectMapper.writeValueAsString(originalState) + println(json) + val parsedState = objectMapper.readValue(json, WeatherState::class.java) + assertThat(parsedState, `is`(originalState)) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTriggerTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTriggerTest.kt new file mode 100644 index 0000000..48dfe89 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/WeatherTriggerTest.kt @@ -0,0 +1,88 @@ +package net.pterodactylus.rhynodge.webpages.weather + +import net.pterodactylus.rhynodge.Reaction +import net.pterodactylus.rhynodge.State +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.`is` +import org.hamcrest.Matchers.containsString +import org.junit.Test +import org.mockito.Mockito.mock +import java.io.File +import java.time.ZoneId.of +import java.time.ZonedDateTime + +/** + * Unit test for [WeatherTrigger]. + + * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) + */ +class WeatherTriggerTest { + + private val now = ZonedDateTime.now(of("Europe/Berlin")) + private val previousState = WeatherState("Weather", now.minusDays(1)) + private val trigger = WeatherTrigger() + + @Test + fun currentStateIsAlwaysReturned() { + val currentState = WeatherState("Weather", now) + assertThat(trigger.mergeStates(previousState, currentState), `is`(currentState as State)) + } + + @Test + fun triggerDoesNotTriggerIfStateHasNotChanged() { + val currentState = WeatherState("Weather", now.minusDays(1)) + trigger.mergeStates(previousState, currentState) + assertThat(trigger.triggers(), `is`(false)) + } + + @Test + fun triggerDoesTriggerIfStateHasChanged() { + val currentState = WeatherState("Weather", now) + trigger.mergeStates(previousState, currentState) + assertThat(trigger.triggers(), `is`(true)) + } + + @Test + fun outputContainsCorrectSummary() { + val currentState = WeatherState("Weather", ZonedDateTime.of(2016, 5, 28, 0, 0, 0, 0, of("Europe/Berlin"))) + trigger.mergeStates(previousState, currentState) + val reaction = mock(Reaction::class.java) + val output = trigger.output(reaction) + assertThat(output.summary(), `is`("The Weather (according to Weather) on May 28, 2016")) + } + + @Test + fun outputContainsCorrectHourData() { + val currentState = WeatherState("Weather", ZonedDateTime.of(2016, 5, 28, 0, 0, 0, 0, of("Europe/Berlin"))) + currentState += HourState(0, 10, 11, 0.12, 13.0, WindDirection.SOUTHSOUTHEAST, 14, 15, 0.16, "17", "http://18") + currentState += HourState(1, 20, 21, 0.22, 23.0, WindDirection.NORTHNORTHWEST, 24, 25, 0.26, "27", "http://28") + trigger.mergeStates(previousState, currentState) + val reaction = mock(Reaction::class.java) + val output = trigger.output(reaction) + val htmlText = output.text("text/html", -1) + File("/tmp/wetter.html").writer().use { it.write(htmlText) } + assertThat(htmlText, containsString("00:00")) + assertThat(htmlText, containsString("10 °C")) + assertThat(htmlText, containsString("(11 °C)")) + assertThat(htmlText, containsString("12%")) + assertThat(htmlText, containsString("13 l/m²")) + assertThat(htmlText, containsString("↖↑")) + assertThat(htmlText, containsString("14 km/h")) + assertThat(htmlText, containsString("15 km/h")) + assertThat(htmlText, containsString("16%")) + assertThat(htmlText, containsString("17")) + assertThat(htmlText, containsString("http://18")) + assertThat(htmlText, containsString("01:00")) + assertThat(htmlText, containsString("20 °C")) + assertThat(htmlText, containsString("(21 °C)")) + assertThat(htmlText, containsString("22%")) + assertThat(htmlText, containsString("23 l/m²")) + assertThat(htmlText, containsString("↘↓")) + assertThat(htmlText, containsString("24 km/h")) + assertThat(htmlText, containsString("25 km/h")) + assertThat(htmlText, containsString("26%")) + assertThat(htmlText, containsString("27")) + assertThat(htmlText, containsString("http://28")) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilterTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilterTest.kt index 8f28c0b..c58656f 100644 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComFilterTest.kt @@ -5,6 +5,7 @@ import net.pterodactylus.rhynodge.filters.ResourceLoader.loadDocument import net.pterodactylus.rhynodge.states.FailedState import net.pterodactylus.rhynodge.states.HtmlState import net.pterodactylus.rhynodge.webpages.weather.HourState +import net.pterodactylus.rhynodge.webpages.weather.WeatherState import net.pterodactylus.rhynodge.webpages.weather.WindDirection import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` @@ -51,7 +52,7 @@ class WetterComFilterTest { fun filterParsesHtmlCorrectly() { val document = loadDocument(javaClass, "wetter.com.html", url) val htmlState = HtmlState(url, document) - val newState = filter.filter(htmlState) as WetterComState + val newState = filter.filter(htmlState) as WeatherState assertThat(newState.dateTime, `is`(LocalDateTime.of(2016, Month.MAY, 23, 5, 0).atZone(ZoneId.of("Europe/Berlin")))) assertThat(newState.hours, contains( HourState(0, 15, null, 0.65, 0.8, WindDirection.NORTH, 5, null, null, "leichter Regen-schauer", "http://ls1.wettercomassets.com/wcomv5/images/icons/small/d_80_S.png?201605201518"), diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComStateTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComStateTest.kt deleted file mode 100644 index d32e563..0000000 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComStateTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wettercom - -import com.fasterxml.jackson.databind.ObjectMapper -import net.pterodactylus.rhynodge.webpages.weather.HourState -import net.pterodactylus.rhynodge.webpages.weather.WindDirection -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` -import org.junit.Test -import java.time.Instant -import java.time.ZoneId -import java.time.ZonedDateTime - -/** - * Unit test for [WetterComState]. - - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -class WetterComStateTest { - - @Test - fun statesWithoutHoursEqualOneAnother() { - val now = Instant.now().atZone(ZoneId.of("Europe/Berlin")) - val firstState = WetterComState(ZonedDateTime.from(now)) - val secondState = WetterComState(ZonedDateTime.from(now)) - assertThat(firstState, `is`(secondState)) - } - - @Test - fun statesWithTheSameHoursAreEqual() { - val now = Instant.now().atZone(ZoneId.of("Europe/Berlin")) - val firstState = WetterComState(ZonedDateTime.from(now)) - firstState += HourState(0, 10, null, 0.05, 0.0, WindDirection.NORTH, 5, null, null, "Fine", "http://1") - firstState += HourState(1, 12, null, 0.1, 2.0, WindDirection.WEST, 8, null, null, "Superb", "http://2") - val secondState = WetterComState(ZonedDateTime.from(now)) - secondState += HourState(0, 10, null, 0.05, 0.0, WindDirection.NORTH, 5, null, null, "Fine", "http://1") - secondState += HourState(1, 12, null, 0.1, 2.0, WindDirection.WEST, 8, null, null, "Superb", "http://2") - assertThat(firstState, `is`(secondState)) - } - - @Test - fun iteratingDeliversHourStates() { - val now = Instant.now().atZone(ZoneId.of("Europe/Berlin")) - val firstState = WetterComState(ZonedDateTime.from(now)) - firstState += HourState(0, 10, null, 0.05, 0.0, WindDirection.NORTH, 5, null, null, "Fine", "http://1") - firstState += HourState(1, 12, null, 0.1, 2.0, WindDirection.WEST, 8, null, null, "Superb", "http://2") - assertThat(firstState.iterator().asSequence().toList(), `is`(firstState.hours as Iterable)) - } - - @Test - fun stateIsSerializableAsJson() { - val objectMapper = ObjectMapper() - val now = Instant.now().atZone(ZoneId.of("Europe/Berlin")) - val originalState = WetterComState(ZonedDateTime.from(now)) - originalState += HourState(0, 10, null, 0.05, 0.0, WindDirection.NORTH, 5, null, null, "Fine", "http://1") - originalState += HourState(1, 12, null, 0.1, 2.0, WindDirection.WEST, 8, null, null, "Superb", "http://2") - val json = objectMapper.writeValueAsString(originalState) - println(json) - val parsedState = objectMapper.readValue(json, WetterComState::class.java) - assertThat(parsedState, `is`(originalState)) - } - -} diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt deleted file mode 100644 index aa69a07..0000000 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wettercom/WetterComTriggerTest.kt +++ /dev/null @@ -1,86 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wettercom - -import net.pterodactylus.rhynodge.Reaction -import net.pterodactylus.rhynodge.webpages.weather.HourState -import net.pterodactylus.rhynodge.webpages.weather.WindDirection -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` -import org.hamcrest.Matchers.containsString -import org.junit.Test -import org.mockito.Mockito -import java.time.ZoneId -import java.time.ZonedDateTime - -/** - * Unit test for [WetterComTrigger]. - - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -class WetterComTriggerTest { - - private val trigger = WetterComTrigger() - private val now = ZonedDateTime.now() - private val previousState = WetterComState(now) - - @Test - fun equalStatesAreNotMerged() { - val currentState = WetterComState(now) - val newState = trigger.mergeStates(previousState, currentState) as WetterComState - assertThat(newState, `is`(previousState)) - assertThat(newState, `is`(currentState)) - } - - @Test - fun currentStateIsReturnedIfDifferentFromPreviousState() { - val currentState = WetterComState(now.minusDays(1)) - val newState = trigger.mergeStates(previousState, currentState) as WetterComState - assertThat(newState, `is`(currentState)) - } - - @Test - fun mergingEqualStatesDoesNotTrigger() { - val currentState = WetterComState(now) - trigger.mergeStates(previousState, currentState) as WetterComState - assertThat(trigger.triggers(), `is`(false)) - } - - @Test - fun mergingDifferentStatesDoesTrigger() { - val currentState = WetterComState(now.minusDays(1)) - trigger.mergeStates(previousState, currentState) as WetterComState - assertThat(trigger.triggers(), `is`(true)) - } - - @Test - fun outputSummaryContainsCorrectDate() { - val currentState = WetterComState(ZonedDateTime.of(2000, 1, 1, 5, 0, 0, 0, ZoneId.of("Europe/Berlin"))) - trigger.mergeStates(previousState, currentState) as WetterComState - val reaction = Mockito.mock(Reaction::class.java) - val output = trigger.output(reaction) - assertThat(output.summary(), `is`("The weather (according to wetter.com) on January 1, 2000")) - } - - @Test - fun outputHtmlContainsHourStates() { - val currentState = WetterComState(now.minusDays(1)) - currentState += HourState(0, 10, null, 0.11, 12.0, WindDirection.NORTH, 13, null, null, "Rain", "http://1") - currentState += HourState(1, 14, null, 0.15, 16.0, WindDirection.SOUTH, 17, null, null, "Sun", "http://2") - trigger.mergeStates(previousState, currentState) as WetterComState - val reaction = Mockito.mock(Reaction::class.java) - val output = trigger.output(reaction) - val htmlText = output.text("text/html", -1) - assertThat(htmlText, containsString("10 °C")) - assertThat(htmlText, containsString("11%")) - assertThat(htmlText, containsString("12 l/m")) - assertThat(htmlText, containsString("13 km/h")) - assertThat(htmlText, containsString("Rain")) - assertThat(htmlText, containsString("http://1")) - assertThat(htmlText, containsString("14 °C")) - assertThat(htmlText, containsString("15%")) - assertThat(htmlText, containsString("16 l/m")) - assertThat(htmlText, containsString("17 km/h")) - assertThat(htmlText, containsString("Sun")) - assertThat(htmlText, containsString("http://2")) - } - -} diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt index fc435c2..fa79869 100644 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeFilterTest.kt @@ -5,6 +5,7 @@ import net.pterodactylus.rhynodge.states.AbstractState import net.pterodactylus.rhynodge.states.FailedState import net.pterodactylus.rhynodge.states.HtmlState import net.pterodactylus.rhynodge.webpages.weather.HourState +import net.pterodactylus.rhynodge.webpages.weather.WeatherState import net.pterodactylus.rhynodge.webpages.weather.WindDirection import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` @@ -43,14 +44,14 @@ class WetterDeFilterTest { @Test fun filterCanParseDateCorrectly() { val htmlState = HtmlState(url, ResourceLoader.loadDocument(javaClass, "wetter.de.html", url)) - val wetterDeState = filter.filter(htmlState) as WetterDeState + val wetterDeState = filter.filter(htmlState) as WeatherState assertThat(wetterDeState.dateTime, `is`(ZonedDateTime.of(2016, 5, 30, 0, 0, 0, 0, ZoneId.of("Europe/Berlin")))) } @Test fun filterParsesHoursCorrectly() { val htmlState = HtmlState(url, ResourceLoader.loadDocument(javaClass, "wetter.de.html", url)) - val wetterDeState = filter.filter(htmlState) as WetterDeState + val wetterDeState = filter.filter(htmlState) as WeatherState assertThat(wetterDeState, contains( HourState(0, 18, 18, 0.47, 0.4, WindDirection.NORTHEAST, 19, 41, 0.91, "gewittrig", "http://cdn.static-fra.de/wetterv3/css/images/icons/weather/m/017_M.png?o44shg"), HourState(1, 18, 18, 0.60, 0.6, WindDirection.NORTHEAST, 20, 39, 0.91, "gewittrig", "http://cdn.static-fra.de/wetterv3/css/images/icons/weather/m/017_M.png?o44shg"), diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt deleted file mode 100644 index aa21c0c..0000000 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeStateTest.kt +++ /dev/null @@ -1,58 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wetterde - -import com.fasterxml.jackson.databind.ObjectMapper -import net.pterodactylus.rhynodge.webpages.weather.HourState -import net.pterodactylus.rhynodge.webpages.weather.WindDirection -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` -import org.junit.Test -import java.time.ZoneId.of -import java.time.ZonedDateTime - -/** - * Unit test for [WetterDeState]. - * - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -class WetterDeStateTest { - - private val now = ZonedDateTime.now(of("Europe/Berlin")) - - @Test - fun statesWithTheSameDateAndHoursAreEqual() { - val firstState = WetterDeState(now) - firstState += createHourState(0) - firstState += createHourState(1) - val secondState = WetterDeState(now) - secondState += createHourState(0) - secondState += createHourState(1) - assertThat(firstState, `is`(secondState)) - } - - private fun createHourState(hourIndex: Int): HourState { - return HourState( - hourIndex, - 10 + hourIndex, - 12 + hourIndex, - (50 + hourIndex) / 100.0, - hourIndex.toDouble(), - WindDirection.values().get(hourIndex % WindDirection.values().size), - 20 + hourIndex, - 30 + hourIndex, - (40 + hourIndex) / 100.0, - "foo: " + hourIndex, - "//" + hourIndex - ) - } - - @Test - fun stateIsSerializableAsJson() { - val originalState = WetterDeState(now) - originalState += createHourState(0) - originalState += createHourState(1) - val json = ObjectMapper().writeValueAsString(originalState) - val parsedState = ObjectMapper().readValue(json, WetterDeState::class.java) - assertThat(parsedState, `is`(originalState)) - } - -} diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt deleted file mode 100644 index 1dac1ab..0000000 --- a/src/test/kotlin/net/pterodactylus/rhynodge/webpages/weather/wetterde/WetterDeTriggerTest.kt +++ /dev/null @@ -1,88 +0,0 @@ -package net.pterodactylus.rhynodge.webpages.weather.wetterde - -import net.pterodactylus.rhynodge.Reaction -import net.pterodactylus.rhynodge.State -import net.pterodactylus.rhynodge.webpages.weather.HourState -import net.pterodactylus.rhynodge.webpages.weather.WindDirection -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.`is` -import org.hamcrest.Matchers.containsString -import org.junit.Test -import org.mockito.Mockito.mock -import java.time.ZoneId.of -import java.time.ZonedDateTime - -/** - * Unit test for [WetterDeTriggerTest]. - - * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net) - */ -class WetterDeTriggerTest { - - private val now = ZonedDateTime.now(of("Europe/Berlin")) - private val previousState = WetterDeState(now.minusDays(1)) - private val trigger = WetterDeTrigger() - - @Test - fun currentStateIsAlwaysReturned() { - val currentState = WetterDeState(now) - assertThat(trigger.mergeStates(previousState, currentState), `is`(currentState as State)) - } - - @Test - fun triggerDoesNotTriggerIfStateHasNotChanged() { - val currentState = WetterDeState(now.minusDays(1)) - trigger.mergeStates(previousState, currentState) - assertThat(trigger.triggers(), `is`(false)) - } - - @Test - fun triggerDoesTriggerIfStateHasChanged() { - val currentState = WetterDeState(now) - trigger.mergeStates(previousState, currentState) - assertThat(trigger.triggers(), `is`(true)) - } - - @Test - fun outputContainsCorrectSummary() { - val currentState = WetterDeState(ZonedDateTime.of(2016, 5, 28, 0, 0, 0, 0, of("Europe/Berlin"))) - trigger.mergeStates(previousState, currentState) - val reaction = mock(Reaction::class.java) - val output = trigger.output(reaction) - assertThat(output.summary(), `is`("The Weather (according to wetter.de) on May 28, 2016")) - } - - @Test - fun outputContainsCorrectHourData() { - val currentState = WetterDeState(ZonedDateTime.of(2016, 5, 28, 0, 0, 0, 0, of("Europe/Berlin"))) - currentState += HourState(0, 10, 11, 0.12, 13.0, WindDirection.SOUTHSOUTHEAST, 14, 15, 0.16, "17", "http://18") - currentState += HourState(1, 20, 21, 0.22, 23.0, WindDirection.NORTHNORTHWEST, 24, 25, 0.26, "27", "http://28") - trigger.mergeStates(previousState, currentState) - val reaction = mock(Reaction::class.java) - val output = trigger.output(reaction) - val htmlText = output.text("text/html", -1) - assertThat(htmlText, containsString("00:00")) - assertThat(htmlText, containsString("10 °C")) - assertThat(htmlText, containsString("(11 °C)")) - assertThat(htmlText, containsString("12%")) - assertThat(htmlText, containsString("13 l/m²")) - assertThat(htmlText, containsString("↖↑")) - assertThat(htmlText, containsString("14 km/h")) - assertThat(htmlText, containsString("15 km/h")) - assertThat(htmlText, containsString("16%")) - assertThat(htmlText, containsString("17")) - assertThat(htmlText, containsString("http://18")) - assertThat(htmlText, containsString("01:00")) - assertThat(htmlText, containsString("20 °C")) - assertThat(htmlText, containsString("(21 °C)")) - assertThat(htmlText, containsString("22%")) - assertThat(htmlText, containsString("23 l/m²")) - assertThat(htmlText, containsString("↘↓")) - assertThat(htmlText, containsString("24 km/h")) - assertThat(htmlText, containsString("25 km/h")) - assertThat(htmlText, containsString("26%")) - assertThat(htmlText, containsString("27")) - assertThat(htmlText, containsString("http://28")) - } - -} -- 2.7.4