From 4d5c7d74b2d8ca59e9abe69bd032693bc98ed18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Papp=20=28TWiStErRob=29?= Date: Sat, 13 Jan 2024 03:46:42 +0000 Subject: [PATCH] Seal differences --- .../controller/LineStatusHistoryController.kt | 17 +-- .../{ResultChange.kt => Difference.kt} | 65 ++++++---- .../travel/statushistory/viewmodel/Result.kt | 7 +- .../viewmodel/ResultChangeCalculator.kt | 102 +++++++++------ .../viewmodel/ResultChangeModel.kt | 2 +- .../viewmodel/ResultChangeModelMapper.kt | 97 +++++++++----- .../statushistory/viewmodel/GwenChange.kt | 24 ++-- .../ResultChangeCalculatorUnitTest_Delays.kt | 8 +- ...ltChangeCalculatorUnitTest_Descriptions.kt | 2 +- .../ResultChangeCalculatorUnitTest_Errors.kt | 122 ------------------ ...hangeCalculatorUnitTest_NonContentDiffs.kt | 97 ++++++++++++++ 11 files changed, 285 insertions(+), 258 deletions(-) rename web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/{ResultChange.kt => Difference.kt} (61%) delete mode 100644 web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Errors.kt create mode 100644 web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_NonContentDiffs.kt diff --git a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/controller/LineStatusHistoryController.kt b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/controller/LineStatusHistoryController.kt index fb59e017..e32cdc00 100644 --- a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/controller/LineStatusHistoryController.kt +++ b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/controller/LineStatusHistoryController.kt @@ -10,11 +10,10 @@ import io.micronaut.views.View import net.twisterrob.blt.data.StaticData import net.twisterrob.blt.io.feeds.trackernet.LineStatusFeed import net.twisterrob.travel.domain.london.status.Feed -import net.twisterrob.travel.domain.london.status.api.StatusHistoryRepository import net.twisterrob.travel.domain.london.status.api.ParsedStatusItem +import net.twisterrob.travel.domain.london.status.api.StatusHistoryRepository import net.twisterrob.travel.statushistory.viewmodel.LineColor import net.twisterrob.travel.statushistory.viewmodel.Result -import net.twisterrob.travel.statushistory.viewmodel.ResultChange import net.twisterrob.travel.statushistory.viewmodel.ResultChangeCalculator import net.twisterrob.travel.statushistory.viewmodel.ResultChangeModel import net.twisterrob.travel.statushistory.viewmodel.ResultChangeModelMapper @@ -39,7 +38,7 @@ class LineStatusHistoryController( val results = history .filter { displayErrors || it !is ParsedStatusItem.ParseFailed } .map(ParsedStatusItem::toResult) - val differences = getDifferences(results) + val differences = ResultChangeCalculator().getDifferences(results) return HttpResponse.ok( LineStatusHistoryModel( @@ -69,15 +68,3 @@ private fun ParsedStatusItem.toResult(): Result { Result.ErrorResult(date, Result.ErrorResult.Error("Error while displaying loaded XML: ${this.error.stacktrace}")) } } - -private fun getDifferences(results: List): List { - val resultChanges: MutableList = ArrayList(results.size) - var newResult: Result? = null - for (oldResult in results) { // We're going forward, but the list is backwards. - resultChanges.add(ResultChangeCalculator().diff(oldResult, newResult)) - newResult = oldResult - } - resultChanges.add(ResultChangeCalculator().diff(null, newResult)) - resultChanges.removeAt(0) - return resultChanges -} diff --git a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChange.kt b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/Difference.kt similarity index 61% rename from web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChange.kt rename to web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/Difference.kt index 2f903895..ae040237 100644 --- a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChange.kt +++ b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/Difference.kt @@ -4,18 +4,33 @@ import net.twisterrob.blt.io.feeds.trackernet.model.DelayType import net.twisterrob.blt.io.feeds.trackernet.model.LineStatus import net.twisterrob.blt.model.Line -open class ResultChange( - val previous: Result?, - val current: Result?, - val error: ErrorChange, // STOPSHIP seal for error and changes -) { +sealed interface Difference { - interface HasDescriptionChange { + data object Nothing : Difference - val desc: DescriptionChange - } + data class NewStatus( + val current: Result, + ) : Difference + + data class LastStatus( + val previous: Result, + ) : Difference + + data class Changes( + val previous: Result, + val current: Result, + val changes: Map, + ) : Difference sealed class StatusChange { + data class Appeared( + val newDelay: DelayType, + ) : StatusChange() + + data class Disappeared( + val oldDelay: DelayType, + ) : StatusChange() + data class Better( val oldDelay: DelayType, val newDelay: DelayType, @@ -32,8 +47,11 @@ open class ResultChange( val delay: DelayType, override val desc: DescriptionChange, ) : StatusChange(), HasDescriptionChange + } + + interface HasDescriptionChange { - data object Unknown : StatusChange() + val desc: DescriptionChange } sealed class DescriptionChange { @@ -61,29 +79,24 @@ open class ResultChange( ) : DescriptionChange() } - sealed interface ErrorChange { + sealed interface ErrorDifference : Difference { data class Same( - val error: Result.ErrorResult.Error, - ) : ErrorChange + val error: Result.ErrorResult, + ) : ErrorDifference data class Change( - val oldError: Result.ErrorResult.Error, - val newError: Result.ErrorResult.Error, - ) : ErrorChange + val oldError: Result.ErrorResult, + val newError: Result.ErrorResult, + ) : ErrorDifference data class Failed( - val newError: Result.ErrorResult.Error, - ) : ErrorChange + val oldResult: Result.ContentResult, + val newError: Result.ErrorResult, + ) : ErrorDifference data class Fixed( - val oldError: Result.ErrorResult.Error, - ) : ErrorChange - - data class NoErrors( - val changes: Map, - ) : ErrorChange - - data object NewStatus : ErrorChange - data object LastStatus : ErrorChange + val oldError: Result.ErrorResult, + val newResult: Result.ContentResult, + ) : ErrorDifference } } diff --git a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/Result.kt b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/Result.kt index 22f673a8..717d847a 100644 --- a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/Result.kt +++ b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/Result.kt @@ -5,13 +5,16 @@ import java.util.Date sealed interface Result { + @Suppress("detekt.VariableNaming") + val `when`: Date + class ContentResult( - val `when`: Date, + override val `when`: Date, val content: LineStatusFeed, ) : Result class ErrorResult( - val `when`: Date, + override val `when`: Date, val error: Error, ) : Result { diff --git a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculator.kt b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculator.kt index c77ff554..a2e4afdf 100644 --- a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculator.kt +++ b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculator.kt @@ -2,27 +2,45 @@ package net.twisterrob.travel.statushistory.viewmodel import net.twisterrob.blt.io.feeds.trackernet.model.LineStatus import net.twisterrob.blt.model.Line -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.DescriptionChange -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.ErrorChange -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.StatusChange +import net.twisterrob.travel.statushistory.viewmodel.Difference.DescriptionChange +import net.twisterrob.travel.statushistory.viewmodel.Difference.ErrorDifference +import net.twisterrob.travel.statushistory.viewmodel.Difference.StatusChange import java.util.EnumMap class ResultChangeCalculator { - fun diff(oldResult: Result?, newResult: Result?): ResultChange { - val errorChange = when { - oldResult != null && newResult != null -> diffError(oldResult, newResult) - oldResult == null && newResult != null -> ErrorChange.NewStatus - oldResult != null && newResult == null -> ErrorChange.LastStatus - else /* oldResult == null && newResult == null */ -> ErrorChange.NoErrors(emptyMap()) + fun getDifferences(results: List): List { + val changes: MutableList = ArrayList(results.size) + var newResult: Result? = null + for (oldResult in results) { // We're going forward, but the list is backwards. + changes.add(diff(oldResult, newResult)) + newResult = oldResult } - return ResultChange( - oldResult, - newResult, - errorChange, - ) + changes.add(diff(null, newResult)) + changes.removeAt(0) + return changes } + fun diff(oldResult: Result?, newResult: Result?): Difference = + when { + oldResult == null && newResult != null -> Difference.NewStatus(newResult) + oldResult != null && newResult == null -> Difference.LastStatus(oldResult) + oldResult != null && newResult != null -> diffResults(oldResult, newResult) + else /* oldResult == null && newResult == null */ -> Difference.Nothing + } + + private fun diffResults(oldResult: Result, newResult: Result): Difference = + when { + oldResult is Result.ContentResult && newResult is Result.ContentResult -> + Difference.Changes(oldResult, newResult, diffContent(oldResult, newResult)) + + oldResult is Result.ErrorResult || newResult is Result.ErrorResult -> + diffError(oldResult, newResult) + + else -> + error("Unknown combination of results: old=${oldResult}, new=${newResult}.") + } + private fun diffContent(oldResult: Result.ContentResult, newResult: Result.ContentResult): Map { val statusChanges: MutableMap = EnumMap(Line::class.java) val oldMap = oldResult.content.statusMap @@ -36,18 +54,24 @@ class ResultChangeCalculator { return statusChanges } - private fun statusChange(oldStatus: LineStatus?, newStatus: LineStatus?): StatusChange { - if (oldStatus == null || newStatus == null) { - return StatusChange.Unknown - } - val statusDiff = oldStatus.type.compareTo(newStatus.type) - val desc = diffDesc(oldStatus, newStatus) - return when { - statusDiff < 0 -> StatusChange.Better(oldStatus.type, newStatus.type, desc) - statusDiff > 0 -> StatusChange.Worse(oldStatus.type, newStatus.type, desc) - else /* statusDiff == 0 */ -> StatusChange.Same(newStatus.type, desc) + private fun statusChange(oldStatus: LineStatus?, newStatus: LineStatus?): StatusChange = + when { + oldStatus == null && newStatus == null -> error("Missing statuses") + oldStatus == null && newStatus != null -> StatusChange.Appeared(newStatus.type) + oldStatus != null && newStatus == null -> StatusChange.Disappeared(oldStatus.type) + + oldStatus != null && newStatus != null -> { + val statusDiff = oldStatus.type.compareTo(newStatus.type) + val desc = diffDesc(oldStatus, newStatus) + when { + statusDiff < 0 -> StatusChange.Better(oldStatus.type, newStatus.type, desc) + statusDiff > 0 -> StatusChange.Worse(oldStatus.type, newStatus.type, desc) + else /* statusDiff == 0 */ -> StatusChange.Same(newStatus.type, desc) + } + } + + else -> error("Unknown combination of statuses: old=${oldStatus}, new=${newStatus}.") } - } private fun diffDesc(oldStatus: LineStatus, newStatus: LineStatus): DescriptionChange { val oldDesc = oldStatus.description @@ -67,41 +91,33 @@ class ResultChangeCalculator { } } - oldDesc == null && newDesc != null -> { - DescriptionChange.Added(newDesc) - } - - oldDesc != null && newDesc == null -> { - DescriptionChange.Removed(oldDesc) - } - - else /* oldDesc == null && newDesc == null */ -> { - DescriptionChange.Missing - } + oldDesc == null && newDesc != null -> DescriptionChange.Added(newDesc) + oldDesc != null && newDesc == null -> DescriptionChange.Removed(oldDesc) + else /* oldDesc == null && newDesc == null */ -> DescriptionChange.Missing } } - private fun diffError(oldResult: Result, newResult: Result): ErrorChange { + private fun diffError(oldResult: Result, newResult: Result): Difference { val oldError = (oldResult as? Result.ErrorResult)?.error val newError = (newResult as? Result.ErrorResult)?.error return when { oldError != null && newError != null -> { if (oldError.header == newError.header) - ErrorChange.Same(newError) + ErrorDifference.Same(newResult) else - ErrorChange.Change(oldError, newError) + ErrorDifference.Change(oldResult, newResult) } oldError == null && newError != null -> { - ErrorChange.Failed(newError) + ErrorDifference.Failed(oldResult as Result.ContentResult, newResult) } oldError != null && newError == null -> { - ErrorChange.Fixed(oldError) + ErrorDifference.Fixed(oldResult, newResult as Result.ContentResult) } - else /* oldErrorHeader == null && newErrorHeader == null */ -> { - ErrorChange.NoErrors(diffContent(oldResult as Result.ContentResult, newResult as Result.ContentResult)) + else /* oldError == null && newError == null */ -> { + error("Neither result has an error: ${oldResult}, ${newResult}") } } } diff --git a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModel.kt b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModel.kt index 494c372a..ed5bc86f 100644 --- a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModel.kt +++ b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModel.kt @@ -5,7 +5,7 @@ import net.twisterrob.blt.model.Line open class ResultChangeModel( val previous: Result?, val current: Result?, - val error: ErrorChange, + val error: ErrorChange?, val statuses: Map, val descriptions: Map, ) { diff --git a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModelMapper.kt b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModelMapper.kt index 8d2d71d0..c0112578 100644 --- a/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModelMapper.kt +++ b/web/status-history/src/main/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeModelMapper.kt @@ -5,57 +5,84 @@ import net.twisterrob.blt.io.feeds.trackernet.model.LineStatus class ResultChangeModelMapper { - fun map(resultChange: ResultChange): ResultChangeModel { - val changes = (resultChange.error as? ResultChange.ErrorChange.NoErrors)?.changes.orEmpty() + fun map(difference: Difference): ResultChangeModel { + val changes = (difference as? Difference.Changes)?.changes.orEmpty() return ResultChangeModel( - previous = resultChange.previous, - current = resultChange.current, - error = map(resultChange.error), + previous = difference.previous, + current = difference.current, + error = mapError(difference), statuses = changes.mapValues { map(it.value) }, descriptions = changes - .filterValues { it is ResultChange.HasDescriptionChange } - .mapValues { it.value as ResultChange.HasDescriptionChange } + .filterValues { it is Difference.HasDescriptionChange } + .mapValues { it.value as Difference.HasDescriptionChange } .mapValues { diffDesc(it.value.desc) }, ) } - private fun map(resultChange: ResultChange.ErrorChange): ResultChangeModel.ErrorChange = - when (resultChange) { - is ResultChange.ErrorChange.Same -> ResultChangeModel.ErrorChange.Same - is ResultChange.ErrorChange.Change -> ResultChangeModel.ErrorChange.Change - is ResultChange.ErrorChange.Failed -> ResultChangeModel.ErrorChange.Failed - is ResultChange.ErrorChange.Fixed -> ResultChangeModel.ErrorChange.Fixed - is ResultChange.ErrorChange.NoErrors -> ResultChangeModel.ErrorChange.NoErrors - ResultChange.ErrorChange.NewStatus -> ResultChangeModel.ErrorChange.NewStatus - ResultChange.ErrorChange.LastStatus -> ResultChangeModel.ErrorChange.LastStatus + private fun mapError(difference: Difference): ResultChangeModel.ErrorChange = + when (difference) { + is Difference.Changes -> ResultChangeModel.ErrorChange.NoErrors + Difference.Nothing -> ResultChangeModel.ErrorChange.NoErrors + is Difference.NewStatus -> ResultChangeModel.ErrorChange.NewStatus + is Difference.LastStatus -> ResultChangeModel.ErrorChange.LastStatus + is Difference.ErrorDifference.Same -> ResultChangeModel.ErrorChange.Same + is Difference.ErrorDifference.Change -> ResultChangeModel.ErrorChange.Change + is Difference.ErrorDifference.Failed -> ResultChangeModel.ErrorChange.Failed + is Difference.ErrorDifference.Fixed -> ResultChangeModel.ErrorChange.Fixed } - private fun map(value: ResultChange.StatusChange): ResultChangeModel.StatusChange = + private fun map(value: Difference.StatusChange): ResultChangeModel.StatusChange = when (value) { - is ResultChange.StatusChange.Better -> ResultChangeModel.StatusChange.Better - is ResultChange.StatusChange.Worse -> ResultChangeModel.StatusChange.Worse - is ResultChange.StatusChange.Same -> when (value.desc) { - is ResultChange.DescriptionChange.Same -> ResultChangeModel.StatusChange.SameDescriptionSame - is ResultChange.DescriptionChange.Changed -> ResultChangeModel.StatusChange.SameDescriptionChange - is ResultChange.DescriptionChange.Added -> ResultChangeModel.StatusChange.SameDescriptionAdd - is ResultChange.DescriptionChange.Removed -> ResultChangeModel.StatusChange.SameDescriptionDel - is ResultChange.DescriptionChange.Branches -> ResultChangeModel.StatusChange.BranchesChange - ResultChange.DescriptionChange.Missing -> ResultChangeModel.StatusChange.Same + is Difference.StatusChange.Better -> ResultChangeModel.StatusChange.Better + is Difference.StatusChange.Worse -> ResultChangeModel.StatusChange.Worse + is Difference.StatusChange.Appeared -> ResultChangeModel.StatusChange.Unknown + is Difference.StatusChange.Disappeared -> ResultChangeModel.StatusChange.Unknown + is Difference.StatusChange.Same -> when (value.desc) { + is Difference.DescriptionChange.Same -> ResultChangeModel.StatusChange.SameDescriptionSame + is Difference.DescriptionChange.Changed -> ResultChangeModel.StatusChange.SameDescriptionChange + is Difference.DescriptionChange.Added -> ResultChangeModel.StatusChange.SameDescriptionAdd + is Difference.DescriptionChange.Removed -> ResultChangeModel.StatusChange.SameDescriptionDel + is Difference.DescriptionChange.Branches -> ResultChangeModel.StatusChange.BranchesChange + Difference.DescriptionChange.Missing -> ResultChangeModel.StatusChange.Same } - - ResultChange.StatusChange.Unknown -> ResultChangeModel.StatusChange.Unknown } - private fun diffDesc(change: ResultChange.DescriptionChange): String = + private fun diffDesc(change: Difference.DescriptionChange): String = when (change) { - is ResultChange.DescriptionChange.Same -> change.desc - is ResultChange.DescriptionChange.Changed -> diffDesc(change.oldDesc, change.newDesc) - is ResultChange.DescriptionChange.Added -> diffDesc("", change.newDesc) - is ResultChange.DescriptionChange.Removed -> diffDesc(change.oldDesc, "") - is ResultChange.DescriptionChange.Branches -> diffDesc(describe(change.oldBranches), describe(change.newBranches)) - ResultChange.DescriptionChange.Missing -> "" + is Difference.DescriptionChange.Same -> change.desc + is Difference.DescriptionChange.Changed -> diffDesc(change.oldDesc, change.newDesc) + is Difference.DescriptionChange.Added -> diffDesc("", change.newDesc) + is Difference.DescriptionChange.Removed -> diffDesc(change.oldDesc, "") + is Difference.DescriptionChange.Branches -> diffDesc(describe(change.oldBranches), describe(change.newBranches)) + Difference.DescriptionChange.Missing -> "" } + private val Difference.previous: Result? + get() = + when (this) { + is Difference.Changes -> previous + is Difference.NewStatus -> null + is Difference.LastStatus -> previous + is Difference.Nothing -> null + is Difference.ErrorDifference.Change -> oldError + is Difference.ErrorDifference.Failed -> null + is Difference.ErrorDifference.Fixed -> oldError + is Difference.ErrorDifference.Same -> error + } + + private val Difference.current: Result? + get() = + when (this) { + is Difference.Changes -> current + is Difference.NewStatus -> current + is Difference.LastStatus -> null + is Difference.Nothing -> null + is Difference.ErrorDifference.Change -> newError + is Difference.ErrorDifference.Failed -> newError + is Difference.ErrorDifference.Fixed -> newResult + is Difference.ErrorDifference.Same -> error + } + private fun diffDesc(oldDesc: String, newDesc: String): String = HtmlDiff().diff(oldDesc, newDesc) diff --git a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/GwenChange.kt b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/GwenChange.kt index 8bcc1069..0afa6f9f 100644 --- a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/GwenChange.kt +++ b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/GwenChange.kt @@ -4,7 +4,7 @@ import com.shazam.gwen.collaborators.Actor import com.shazam.gwen.collaborators.Asserter import net.twisterrob.blt.io.feeds.trackernet.model.DelayType import net.twisterrob.blt.model.Line -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.HasDescriptionChange +import net.twisterrob.travel.statushistory.viewmodel.Difference.HasDescriptionChange import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.either import org.hamcrest.Matchers.equalTo @@ -15,23 +15,29 @@ import org.hamcrest.Matchers.not internal class GwenChange : Actor, Asserter { - private lateinit var change: ResultChange + private lateinit var difference: Difference - private val changes: Map - get() = (change.error as ResultChange.ErrorChange.NoErrors).changes + private val changes: Map + get() = (difference as Difference.Changes).changes fun between(status1: GwenStatus, status2: GwenStatus) { - change = ResultChangeCalculator().diff(status1.createResult(), status2.createResult()) + difference = ResultChangeCalculator().diff(status1.createResult(), status2.createResult()) } - fun has(line: Line, desc: ResultChange.DescriptionChange): GwenChange = apply { - assertThat(changes, hasEntry(line, ResultChange.StatusChange.Same(DelayType.Unknown, desc))) + fun has(line: Line, desc: Difference.DescriptionChange): GwenChange = apply { + assertThat(changes, hasEntry(line, Difference.StatusChange.Same(DelayType.Unknown, desc))) } - fun has(line: Line, status: ResultChange.StatusChange): GwenChange = apply { + fun has(line: Line, status: Difference.StatusChange): GwenChange = apply { assertThat(changes, hasEntry(line, status)) } + fun hasNoStatusChangeFor(vararg lines: Line): GwenChange = apply { + for (line in lines) { + assertThat(changes, not(hasKey(line))) + } + } + fun hasNoDescriptionChangeFor(vararg lines: Line): GwenChange = apply { for (line in lines) { assertThat(changes, either(not(hasKey(line))).or(not(instanceOf(HasDescriptionChange::class.java)))) @@ -45,6 +51,6 @@ internal class GwenChange : Actor, Asserter { } fun hasNoErrorChange(): GwenChange = apply { - assertThat(change.error, instanceOf(ResultChange.ErrorChange.NoErrors::class.java)) + assertThat(difference, instanceOf(Difference.Changes::class.java)) } } diff --git a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Delays.kt b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Delays.kt index bb552267..800fb9d9 100644 --- a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Delays.kt +++ b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Delays.kt @@ -5,8 +5,8 @@ import com.shazam.gwen.Gwen.then import com.shazam.gwen.Gwen.`when` import net.twisterrob.blt.io.feeds.trackernet.model.DelayType import net.twisterrob.blt.model.Line -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.DescriptionChange.Missing -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.StatusChange +import net.twisterrob.travel.statushistory.viewmodel.Difference.DescriptionChange.Missing +import net.twisterrob.travel.statushistory.viewmodel.Difference.StatusChange import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -60,7 +60,7 @@ class ResultChangeCalculatorUnitTest_Delays { then(change) .hasNoErrorChange() - .has(Line.Jubilee, StatusChange.Unknown) + .has(Line.Jubilee, StatusChange.Appeared(DelayType.GoodService)) .hasNoDescriptionChangeFor(Line.Northern, Line.Jubilee) } @@ -72,7 +72,7 @@ class ResultChangeCalculatorUnitTest_Delays { then(change) .hasNoErrorChange() - .has(Line.Jubilee, StatusChange.Unknown) + .has(Line.Jubilee, StatusChange.Disappeared(DelayType.GoodService)) .hasNoDescriptionChangeFor(Line.Northern, Line.Jubilee) } } diff --git a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Descriptions.kt b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Descriptions.kt index e4046c8f..c4379031 100644 --- a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Descriptions.kt +++ b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Descriptions.kt @@ -5,7 +5,7 @@ import com.shazam.gwen.Gwen.then import com.shazam.gwen.Gwen.`when` import net.twisterrob.blt.io.feeds.trackernet.model.LineStatus.BranchStatus import net.twisterrob.blt.model.Line -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.DescriptionChange +import net.twisterrob.travel.statushistory.viewmodel.Difference.DescriptionChange import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test diff --git a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Errors.kt b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Errors.kt deleted file mode 100644 index e1e44699..00000000 --- a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_Errors.kt +++ /dev/null @@ -1,122 +0,0 @@ -package net.twisterrob.travel.statushistory.viewmodel - -import net.twisterrob.travel.statushistory.viewmodel.ResultChange.ErrorChange -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.mockito.Mockito.mock -import java.util.Date - -class ResultChangeCalculatorUnitTest_Errors { - - private val subject = ResultChangeCalculator() - - @Test fun testErrorChange() { - val error1 = Result.ErrorResult.Error("error1") - val result1 = Result.ErrorResult(Date(), error1) - val error2 = Result.ErrorResult.Error("error2") - val result2 = Result.ErrorResult(Date(), error2) - - val change = subject.diff(result1, result2) - - assertError(change, ErrorChange.Change(error1, error2)) - } - - @Test fun testErrorNoChange() { - val result1 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) - val result2 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) - - val change = subject.diff(result1, result2) - - assertError(change, ErrorChange.Same(Result.ErrorResult.Error("error"))) - } - - @Test fun testErrorIntroduced() { - val result1 = Result.ContentResult(Date(), mock()) - val result2 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) - - val change = subject.diff(result1, result2) - - assertError(change, ErrorChange.Failed(Result.ErrorResult.Error("error"))) - } - - @Test fun testErrorDisappeared() { - val result1 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) - val result2 = Result.ContentResult(Date(), mock()) - - val change = subject.diff(result1, result2) - - assertError(change, ErrorChange.Fixed(Result.ErrorResult.Error("error"))) - } - - @Test fun testErrorNone() { - val result1 = Result.ContentResult(Date(), mock()) - val result2 = Result.ContentResult(Date(), mock()) - - val change = subject.diff(result1, result2) - - assertError(change, ErrorChange.NoErrors(emptyMap())) - } - - @Test fun testFirstOne() { - val result: Result = Result.ContentResult(Date(), mock()) - - val change = subject.diff(null, result) - - assertError(change, ErrorChange.NewStatus) - } - - @Test fun testFirstError() { - val result: Result = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) - - val change = subject.diff(null, result) - - assertError(change, ErrorChange.NewStatus) - } - - @Test fun testLastOne() { - val result: Result = Result.ContentResult(Date(), mock()) - - val change = subject.diff(result, null) - - assertError(change, ErrorChange.LastStatus) - } - - @Test fun testLastError() { - val result: Result = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) - - val change = subject.diff(result, null) - - assertError(change, ErrorChange.LastStatus) - } - - @Test fun testMissingResults() { - val change = subject.diff(null, null) - - assertError(change, ErrorChange.NoErrors(emptyMap())) - } - - @Test fun testErrorNewFeedMissing() { - val result1 = Result.ContentResult(Date(), mock()) - val result2 = Result.ContentResult(Date(), mock()) - - val change = subject.diff(result1, result2) - - assertError(change, ErrorChange.NoErrors(emptyMap())) - } - - @Test fun testErrorOldFeedMissing() { - val result1 = Result.ContentResult(Date(), mock()) - val result2 = Result.ContentResult(Date(), mock()) - - val change = subject.diff(result2, result1) - - assertError(change, ErrorChange.NoErrors(emptyMap())) - } - - companion object { - - private fun assertError(result: ResultChange, errors: ErrorChange) { - assertEquals(errors, result.error) - } - } -} diff --git a/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_NonContentDiffs.kt b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_NonContentDiffs.kt new file mode 100644 index 00000000..4955c04c --- /dev/null +++ b/web/status-history/src/test/java/net/twisterrob/travel/statushistory/viewmodel/ResultChangeCalculatorUnitTest_NonContentDiffs.kt @@ -0,0 +1,97 @@ +package net.twisterrob.travel.statushistory.viewmodel + +import net.twisterrob.travel.statushistory.viewmodel.Difference.ErrorDifference +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.mockito.Mockito.mock +import java.util.Date + +class ResultChangeCalculatorUnitTest_NonContentDiffs { + + private val subject = ResultChangeCalculator() + + @Test fun testErrorChange() { + val error1 = Result.ErrorResult.Error("error1") + val result1 = Result.ErrorResult(Date(), error1) + val error2 = Result.ErrorResult.Error("error2") + val result2 = Result.ErrorResult(Date(), error2) + + val difference = subject.diff(result1, result2) + + assertEquals(difference, ErrorDifference.Change(result1, result2)) + } + + @Test fun testErrorNoChange() { + val result1 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) + val result2 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) + + val difference = subject.diff(result1, result2) + + assertEquals(difference, ErrorDifference.Same(result2)) + } + + @Test fun testErrorIntroduced() { + val result1 = Result.ContentResult(Date(), mock()) + val result2 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) + + val difference = subject.diff(result1, result2) + + assertEquals(difference, ErrorDifference.Failed(result1, result2)) + } + + @Test fun testErrorDisappeared() { + val result1 = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) + val result2 = Result.ContentResult(Date(), mock()) + + val difference = subject.diff(result1, result2) + + assertEquals(difference, ErrorDifference.Fixed(result1, result2)) + } + + @Test fun testEmpty() { + val result1 = Result.ContentResult(Date(), mock()) + val result2 = Result.ContentResult(Date(), mock()) + + val difference = subject.diff(result1, result2) + + assertEquals(difference, Difference.Changes(result1, result2, emptyMap())) + } + + @Test fun testFirstOne() { + val result: Result = Result.ContentResult(Date(), mock()) + + val difference = subject.diff(null, result) + + assertEquals(difference, Difference.NewStatus(result)) + } + + @Test fun testFirstError() { + val result: Result = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) + + val difference = subject.diff(null, result) + + assertEquals(difference, Difference.NewStatus(result)) + } + + @Test fun testLastOne() { + val result: Result = Result.ContentResult(Date(), mock()) + + val difference = subject.diff(result, null) + + assertEquals(difference, Difference.LastStatus(result)) + } + + @Test fun testLastError() { + val result: Result = Result.ErrorResult(Date(), Result.ErrorResult.Error("error")) + + val difference = subject.diff(result, null) + + assertEquals(difference, Difference.LastStatus(result)) + } + + @Test fun testMissingResults() { + val difference = subject.diff(null, null) + + assertEquals(difference, Difference.Nothing) + } +}