Skip to content

Commit

Permalink
use assertEquals for verifying quest answers
Browse files Browse the repository at this point in the history
  • Loading branch information
westnordost committed Jan 24, 2024
1 parent 9cc28f8 commit bdf02fe
Show file tree
Hide file tree
Showing 63 changed files with 2,143 additions and 1,960 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ fun SurfaceAndNote.applyTo(tags: Tags, prefix: String? = null, updateCheckDate:
}

// always clean up old source tags - source should be in changeset tags
tags.remove("source:$key")
tags.remove("source:surface")
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import de.westnordost.streetcomplete.osm.LocalizedName

sealed interface BusStopNameAnswer

object NoBusStopName : BusStopNameAnswer
data object NoBusStopName : BusStopNameAnswer
data class BusStopName(val localizedNames: List<LocalizedName>) : BusStopNameAnswer
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,9 @@ class AddProhibitedForPedestrians : OsmFilterQuestType<ProhibitedForPedestriansA
YES -> tags["foot"] = "no"
NO -> tags["foot"] = "yes"
HAS_SEPARATE_SIDEWALK -> {
tags["sidewalk"] = "separate"
tags["sidewalk:both"] = "separate"
// wrong tagging may exist, it should be removed to prevent quest from reappearing
// technically it may remove sidewalk:both=separate and replace it with less accurate
// sidewalk=separate but it will happen only with contradicting wrong data such as
// sidewalk:left=no or sidewalk:right=none or sidewalk=no
// And in such case all sidewalk tagging is suspect anyway
tags.remove("sidewalk:both")
tags.remove("sidewalk")
tags.remove("sidewalk:left")
tags.remove("sidewalk:right")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package de.westnordost.streetcomplete.quests.lanes
sealed interface LanesAnswer

data class MarkedLanes(val count: Int) : LanesAnswer
object UnmarkedLanes : LanesAnswer
data object UnmarkedLanes : LanesAnswer
data class MarkedLanesSides(val forward: Int, val backward: Int, val centerLeftTurnLane: Boolean) : LanesAnswer

val LanesAnswer.total: Int? get() = when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ data class MaxSpeedSign(val value: Speed) : MaxSpeedAnswer
data class MaxSpeedZone(val value: Speed, val countryCode: String, val roadType: String) : MaxSpeedAnswer
data class AdvisorySpeedSign(val value: Speed) : MaxSpeedAnswer
data class ImplicitMaxSpeed(val countryCode: String, val roadType: String, val lit: Boolean?) : MaxSpeedAnswer
object IsLivingStreet : MaxSpeedAnswer
data object IsLivingStreet : MaxSpeedAnswer
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package de.westnordost.streetcomplete.quests.max_weight
sealed interface MaxWeightAnswer

data class MaxWeight(val sign: MaxWeightSign, val weight: Weight) : MaxWeightAnswer
object NoMaxWeightSign : MaxWeightAnswer
data object NoMaxWeightSign : MaxWeightAnswer
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,8 @@ class AddOpeningHours(
if (tags["opening_hours:signed"] == "no") {
tags.remove("opening_hours:signed")
}
if ("opening_hours:covid19" in tags) {
tags.remove("opening_hours:covid19")
}
}
tags.remove("opening_hours:covid19")
}

private fun hasName(tags: Map<String, String>) = hasProperName(tags) || hasFeatureName(tags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,19 @@ class AddParkingFeeForm : AbstractOsmQuestForm<FeeAndMaxStay>() {
applyAnswer(FeeAndMaxStay(fee))
}
MAX_STAY -> {
val duration = MaxstayDuration(
val duration = MaxStayDuration(
maxstayDurationInput!!.durationValue,
when (maxstayDurationInput!!.durationUnit) {
DurationUnit.MINUTES -> Maxstay.Unit.MINUTES
DurationUnit.HOURS -> Maxstay.Unit.HOURS
DurationUnit.DAYS -> Maxstay.Unit.DAYS
DurationUnit.MINUTES -> MaxStay.Unit.MINUTES
DurationUnit.HOURS -> MaxStay.Unit.HOURS
DurationUnit.DAYS -> MaxStay.Unit.DAYS
}
)
val hours = maxstayAtHoursSelect!!.times.toOpeningHoursRules()
val maxstay = when (maxstayAtHoursSelect!!.timeRestriction) {
AT_ANY_TIME -> duration
ONLY_AT_HOURS -> MaxstayAtHours(duration, hours)
EXCEPT_AT_HOURS -> MaxstayExceptAtHours(duration, hours)
ONLY_AT_HOURS -> MaxStayAtHours(duration, hours)
EXCEPT_AT_HOURS -> MaxStayExceptAtHours(duration, hours)
}
applyAnswer(FeeAndMaxStay(HasNoFee, maxstay))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import de.westnordost.streetcomplete.osm.updateWithCheckDate

sealed interface Fee

object HasFee : Fee
object HasNoFee : Fee
data object HasFee : Fee
data object HasNoFee : Fee
data class HasFeeAtHours(val hours: OpeningHoursRuleList) : Fee
data class HasFeeExceptAtHours(val hours: OpeningHoursRuleList) : Fee

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package de.westnordost.streetcomplete.quests.parking_fee

import de.westnordost.streetcomplete.osm.Tags

data class FeeAndMaxStay(val fee: Fee, val maxstay: Maxstay? = null)
data class FeeAndMaxStay(val fee: Fee, val maxstay: MaxStay? = null)

fun FeeAndMaxStay.applyTo(tags: Tags) {
fee.applyTo(tags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,42 @@ package de.westnordost.streetcomplete.quests.parking_fee
import de.westnordost.streetcomplete.osm.Tags
import de.westnordost.streetcomplete.osm.opening_hours.parser.OpeningHoursRuleList
import de.westnordost.streetcomplete.osm.updateWithCheckDate
import de.westnordost.streetcomplete.quests.parking_fee.Maxstay.Unit.DAYS
import de.westnordost.streetcomplete.quests.parking_fee.Maxstay.Unit.HOURS
import de.westnordost.streetcomplete.quests.parking_fee.Maxstay.Unit.MINUTES
import de.westnordost.streetcomplete.quests.parking_fee.MaxStay.Unit.DAYS
import de.westnordost.streetcomplete.quests.parking_fee.MaxStay.Unit.HOURS
import de.westnordost.streetcomplete.quests.parking_fee.MaxStay.Unit.MINUTES
import de.westnordost.streetcomplete.util.ktx.toShortString

sealed interface Maxstay {
sealed interface MaxStay {
enum class Unit { MINUTES, HOURS, DAYS }
}

object NoMaxstay : Maxstay
data class MaxstayDuration(val value: Double, val unit: Maxstay.Unit) : Maxstay
data class MaxstayAtHours(val duration: MaxstayDuration, val hours: OpeningHoursRuleList) : Maxstay
data class MaxstayExceptAtHours(val duration: MaxstayDuration, val hours: OpeningHoursRuleList) : Maxstay
data object NoMaxStay : MaxStay
data class MaxStayDuration(val value: Double, val unit: MaxStay.Unit) : MaxStay
data class MaxStayAtHours(val duration: MaxStayDuration, val hours: OpeningHoursRuleList) : MaxStay
data class MaxStayExceptAtHours(val duration: MaxStayDuration, val hours: OpeningHoursRuleList) : MaxStay

fun MaxstayDuration.toOsmValue(): String =
fun MaxStayDuration.toOsmValue(): String =
value.toShortString() + " " + when (unit) {
MINUTES -> if (value != 1.0) "minutes" else "minute"
HOURS -> if (value != 1.0) "hours" else "hour"
DAYS -> if (value != 1.0) "days" else "day"
}

fun Maxstay.applyTo(tags: Tags) {
fun MaxStay.applyTo(tags: Tags) {
when (this) {
is MaxstayExceptAtHours -> {
is MaxStayExceptAtHours -> {
tags.updateWithCheckDate("maxstay", duration.toOsmValue())
tags["maxstay:conditional"] = "no @ ($hours)"
}
is MaxstayAtHours -> {
is MaxStayAtHours -> {
tags.updateWithCheckDate("maxstay", "no")
tags["maxstay:conditional"] = "${duration.toOsmValue()} @ ($hours)"
}
is MaxstayDuration -> {
is MaxStayDuration -> {
tags.updateWithCheckDate("maxstay", toOsmValue())
tags.remove("maxstay:conditional")
}
NoMaxstay -> {
NoMaxStay -> {
tags.updateWithCheckDate("maxstay", "no")
tags.remove("maxstay:conditional")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import de.westnordost.streetcomplete.osm.LocalizedName
sealed interface PlaceNameAnswer

data class PlaceName(val localizedNames: List<LocalizedName>) : PlaceNameAnswer
object NoPlaceNameSign : PlaceNameAnswer
data object NoPlaceNameSign : PlaceNameAnswer
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import de.westnordost.streetcomplete.osm.opening_hours.parser.OpeningHoursRuleLi
sealed interface CollectionTimesAnswer

data class CollectionTimes(val times: OpeningHoursRuleList) : CollectionTimesAnswer
object NoCollectionTimesSign : CollectionTimesAnswer
data object NoCollectionTimesSign : CollectionTimesAnswer
Original file line number Diff line number Diff line change
Expand Up @@ -70,41 +70,26 @@ class AddRecyclingContainerMaterials : OsmElementQuestType<RecyclingContainerMat
}

// if the user chose deliberately not "all plastic", also tag it explicitly
if (materials.any { it in RecyclingMaterial.plastics }) {
for (plastic in RecyclingMaterial.plastics) {
val selectedPlastics = materials.filter { it in RecyclingMaterial.allPlastics }
if (selectedPlastics.isNotEmpty()) {
for (plastic in RecyclingMaterial.allPlastics) {
tags.remove("recycling:${plastic.value}")
}
when {
PLASTIC_PACKAGING in materials -> {
tags["recycling:plastic"] = "no"
}
BEVERAGE_CARTONS in materials && PLASTIC_BOTTLES in materials -> {
tags["recycling:plastic_packaging"] = "no"
tags["recycling:plastic"] = "no"
}
BEVERAGE_CARTONS in materials -> {
tags["recycling:plastic_bottles"] = "no"
tags["recycling:plastic_packaging"] = "no"
tags["recycling:plastic"] = "no"
}
PLASTIC_BOTTLES in materials -> {
tags["recycling:beverage_cartons"] = "no"
tags["recycling:plastic_packaging"] = "no"
tags["recycling:plastic"] = "no"
}
PET in materials -> {
tags["recycling:plastic_bottles"] = "no"
tags["recycling:beverage_cartons"] = "no"
tags["recycling:plastic_packaging"] = "no"
tags["recycling:plastic"] = "no"
}

val selectedAndIndirectlySelectedPlastics =
selectedPlastics + selectedPlastics.flatMapTo(HashSet()) { it.subValues }

val notSelectedPlastics =
RecyclingMaterial.allPlastics - selectedAndIndirectlySelectedPlastics.toSet()

for (notSelectedPlastic in notSelectedPlastics) {
tags["recycling:${notSelectedPlastic.value}"] = "no"
}
}

// set selected recycling:* taggings to "yes"
val selectedMaterials = materials.map { "recycling:${it.value}" }
for (material in selectedMaterials) {
tags[material] = "yes"
for (material in materials) {
tags["recycling:${material.value}"] = "yes"
}

// only set the check date if nothing was changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package de.westnordost.streetcomplete.quests.recycling_material

sealed interface RecyclingContainerMaterialsAnswer

object IsWasteContainer : RecyclingContainerMaterialsAnswer
data object IsWasteContainer : RecyclingContainerMaterialsAnswer
data class RecyclingMaterials(val materials: List<RecyclingMaterial>) : RecyclingContainerMaterialsAnswer
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ enum class RecyclingMaterial(val value: String) {
COOKING_OIL("cooking_oil"),
ENGINE_OIL("engine_oil");

val subValues get() = when (this) {
PLASTIC ->
listOf(PLASTIC_PACKAGING, PLASTIC_BOTTLES, BEVERAGE_CARTONS, PET)
PLASTIC_PACKAGING ->
listOf(PLASTIC_BOTTLES, BEVERAGE_CARTONS, PET)
PLASTIC_BOTTLES ->
listOf(PET)
else ->
listOf()
}

companion object {
val selectableValues = listOf(
GLASS_BOTTLES, PAPER, PLASTIC, CANS, SCRAP_METAL, CLOTHES, SHOES,
Expand All @@ -42,6 +53,6 @@ enum class RecyclingMaterial(val value: String) {
listOf(GLASS)
)

val plastics = setOf(PLASTIC, PLASTIC_PACKAGING, PLASTIC_BOTTLES, BEVERAGE_CARTONS, PET)
val allPlastics = setOf(PLASTIC, PLASTIC_PACKAGING, PLASTIC_BOTTLES, BEVERAGE_CARTONS, PET)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ data class RoadName(
val wayGeometry: List<LatLon>
) : RoadNameAnswer

object NoRoadName : RoadNameAnswer
object RoadIsServiceRoad : RoadNameAnswer
object RoadIsTrack : RoadNameAnswer
object RoadIsLinkRoad : RoadNameAnswer
data object NoRoadName : RoadNameAnswer
data object RoadIsServiceRoad : RoadNameAnswer
data object RoadIsTrack : RoadNameAnswer
data object RoadIsLinkRoad : RoadNameAnswer
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import de.westnordost.streetcomplete.data.osm.osmquests.OsmFilterQuestType
import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.BICYCLIST
import de.westnordost.streetcomplete.data.user.achievements.EditTypeAchievement.OUTDOORS
import de.westnordost.streetcomplete.osm.Tags
import de.westnordost.streetcomplete.osm.removeCheckDatesForKey
import de.westnordost.streetcomplete.osm.surface.ANYTHING_PAVED
import de.westnordost.streetcomplete.osm.updateWithCheckDate
import de.westnordost.streetcomplete.quests.segregated.CyclewaySegregation.*
Expand All @@ -29,7 +30,7 @@ class AddCyclewaySegregation : OsmFilterQuestType<CyclewaySegregation>() {
and surface ~ ${ANYTHING_PAVED.joinToString("|")}
and area != yes
and !sidewalk
and (!segregated or segregated older today -8 years)
and !segregated
and ~path|footway|cycleway !~ link
"""
override val changesetComment = "Specify whether combined foot- and cycleways are segregated"
Expand All @@ -43,8 +44,8 @@ class AddCyclewaySegregation : OsmFilterQuestType<CyclewaySegregation>() {

override fun applyAnswerTo(answer: CyclewaySegregation, tags: Tags, geometry: ElementGeometry, timestampEdited: Long) {
when (answer) {
YES -> tags.updateWithCheckDate("segregated", "yes")
NO -> tags.updateWithCheckDate("segregated", "no")
YES -> tags["segregated"] = "yes"
NO -> tags["segregated"] = "no"
SIDEWALK -> tags["sidewalk"] = "yes"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class AddPathSurface : OsmFilterQuestType<SurfaceOrIsStepsAnswer>() {
and (!indoor or indoor = no)
and (
!surface
or surface ~ ${ANYTHING_UNPAVED.joinToString("|")} and surface older today -6 years
or surface older today -8 years
or (
surface ~ paved|unpaved|${INVALID_SURFACES.joinToString("|")}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import de.westnordost.streetcomplete.osm.sidewalk_surface.LeftAndRightSidewalkSu
sealed interface SidewalkSurfaceAnswer

data class SidewalkSurface(val value: LeftAndRightSidewalkSurface) : SidewalkSurfaceAnswer
object SidewalkIsDifferent : SidewalkSurfaceAnswer
data object SidewalkIsDifferent : SidewalkSurfaceAnswer
73 changes: 73 additions & 0 deletions app/src/test/java/de/westnordost/streetcomplete/osm/ShopKtTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package de.westnordost.streetcomplete.osm

import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapChangesBuilder
import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryAdd
import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryChange
import de.westnordost.streetcomplete.data.osm.edits.update_tags.StringMapEntryDelete
import kotlin.test.Test
import kotlin.test.assertEquals

class ShopKtTest {

@Test fun `replaceShop removes all previous survey keys`() {
assertEquals(
setOf(
StringMapEntryAdd("a", "b"),
StringMapEntryDelete("check_date", "1"),
StringMapEntryDelete("lastcheck", "a"),
StringMapEntryDelete("last_checked", "b"),
StringMapEntryDelete("survey:date", "c"),
StringMapEntryDelete("survey_date", "d"),
),
replaceShopApplied(
newTags = mapOf("a" to "b"),
oldTags = mapOf(
"check_date" to "1",
"lastcheck" to "a",
"last_checked" to "b",
"survey:date" to "c",
"survey_date" to "d"
)
)
)
}

// see KEYS_THAT_SHOULD_BE_REMOVED_WHEN_SHOP_IS_REPLACED
@Test fun `replaceShop removes certain tags connected with the type of shop`() {
assertEquals(
setOf(
StringMapEntryAdd("shop", "ice_cream"),
StringMapEntryDelete("disused:amenity", "yes"),
StringMapEntryDelete("phone", "123456"),
StringMapEntryDelete("name", "Juppiebude"),
StringMapEntryDelete("ref", "1111"),
StringMapEntryDelete("fee", "yes"),
StringMapEntryDelete("office", "it"),
StringMapEntryDelete("tourism", "information"),
StringMapEntryDelete("information", "office"),
),
replaceShopApplied(
newTags = mapOf("shop" to "ice_cream"),
oldTags = mapOf(
"building" to "yes", // <- should not be cleared
"disused:amenity" to "yes",
"phone" to "123456",
"ref" to "1111",
"fee" to "yes",
"nycdoitt:bin" to "22222",
"barrier" to "wall",
"office" to "it",
"tourism" to "information",
"information" to "office",
"name" to "Juppiebude"
)
)
)
}
}

private fun replaceShopApplied(newTags: Map<String, String>, oldTags: Map<String, String>): Set<StringMapEntryChange> {
val cb = StringMapChangesBuilder(oldTags)
cb.replaceShop(newTags)
return cb.create().changes
}
Loading

0 comments on commit bdf02fe

Please sign in to comment.