@@ -7,127 +7,136 @@ import travelator.destinations.FeaturedDestination
7
7
import travelator.domain.Location
8
8
9
9
class RecommendationsTests {
10
-
11
- private val featuredDestinations =
12
- mutableMapOf<Location , List <FeaturedDestination >>()
13
- .withDefault { emptyList() }
14
- private val distanceInMetersBetween =
15
- mutableMapOf<Pair <Location , Location >, Int > ()
16
- .withDefault { - 1 }
17
-
18
- private val recommendations =
19
- Recommendations (
20
- featuredDestinations::getValue,
21
- distanceInMetersBetween::getValue
10
+ companion object {
11
+ val distances = mapOf (
12
+ (paris to eiffelTower.location) to 5000 ,
13
+ (paris to louvre.location) to 1000 ,
14
+ (alton to flowerFarm.location) to 5300 ,
15
+ (alton to watercressLine.location) to 320 ,
16
+ (froyle to flowerFarm.location) to 0 ,
17
+ (froyle to watercressLine.location) to 6300
22
18
)
19
+ }
23
20
24
- private val paris = location(" Paris" )
25
- private val louvre = featured(" Louvre" , " Rue de Rivoli" )
26
- private val eiffelTower = featured(" Eiffel Tower" , " Champ de Mars" )
27
- private val alton = location(" Alton" )
28
- private val froyle = location(" Froyle" )
29
- private val watercressLine = featured(" Watercress Line" , " Alton Station" )
30
- private val flowerFarm = featured(" West End Flower Farm" , froyle)
31
21
32
22
@Test
33
23
fun returns_no_recommendations_when_no_locations () {
34
- assertEquals(
35
- emptyList<Any >(),
36
- recommendations.recommendationsFor(emptySet())
24
+ check(
25
+ featuredDestinations = emptyMap(),
26
+ distances = distances,
27
+ recommendations = emptySet(),
28
+ shouldReturn = emptyList()
37
29
)
38
30
}
39
31
32
+
40
33
@Test
41
34
fun returns_no_recommendations_when_no_featured () {
42
- givenFeaturedDestinationsFor(paris, of())
43
- assertEquals(
44
- emptyList<Any >(),
45
- recommendations.recommendationsFor(setOf (paris))
35
+ check(
36
+ featuredDestinations = emptyMap(),
37
+ distances = distances,
38
+ recommendations = setOf (paris),
39
+ shouldReturn = emptyList()
46
40
)
47
41
}
48
42
43
+
49
44
@Test
50
45
fun returns_recommendations_for_single_location () {
51
- givenFeaturedDestinationsFor(paris, of(eiffelTower, louvre))
52
-
53
- givenADistanceFrom( paris, to = eiffelTower, of = 5000 )
54
- givenADistanceFrom(paris, to = louvre, of = 1000 )
55
-
56
- assertEquals(
57
- listOf (
46
+ check(
47
+ featuredDestinations = mapOf (
48
+ paris to listOf ( eiffelTower, louvre),
49
+ ),
50
+ distances = distances,
51
+ recommendations = setOf (paris),
52
+ shouldReturn = listOf (
58
53
FeaturedDestinationSuggestion (paris, louvre, 1000 ),
59
54
FeaturedDestinationSuggestion (paris, eiffelTower, 5000 )
60
- ),
61
- recommendations.recommendationsFor(setOf (paris))
55
+ )
62
56
)
63
57
}
64
58
59
+
65
60
@Test
66
61
fun returns_recommendations_for_multi_location () {
67
- givenFeaturedDestinationsFor(paris, of(eiffelTower, louvre))
68
- givenADistanceFrom(paris, to = eiffelTower, of = 5000 )
69
- givenADistanceFrom(paris, to = louvre, of = 1000 )
70
-
71
- givenFeaturedDestinationsFor(alton, of(flowerFarm, watercressLine))
72
- givenADistanceFrom(alton, to = flowerFarm, of = 5300 )
73
- givenADistanceFrom(alton, to = watercressLine, of = 320 )
74
-
75
- assertEquals(
76
- listOf (
62
+ check(
63
+ featuredDestinations = mapOf (
64
+ paris to listOf (eiffelTower, louvre),
65
+ alton to listOf (flowerFarm, watercressLine),
66
+ ),
67
+ distances = distances,
68
+ recommendations = setOf (paris, alton),
69
+ shouldReturn = listOf (
77
70
FeaturedDestinationSuggestion (alton, watercressLine, 320 ),
78
71
FeaturedDestinationSuggestion (paris, louvre, 1000 ),
79
72
FeaturedDestinationSuggestion (paris, eiffelTower, 5000 ),
80
73
FeaturedDestinationSuggestion (alton, flowerFarm, 5300 )
81
- ),
82
- recommendations.recommendationsFor(setOf (paris, alton))
74
+ )
83
75
)
84
76
}
85
77
86
78
@Test
87
79
fun deduplicates_using_smallest_distance () {
88
- givenFeaturedDestinationsFor(alton, of(flowerFarm, watercressLine))
89
- givenADistanceFrom(alton, to = flowerFarm, of = 5300 )
90
- givenADistanceFrom(alton, to = watercressLine, of = 320 )
91
-
92
- givenFeaturedDestinationsFor(froyle, of(flowerFarm, watercressLine))
93
- givenADistanceFrom(froyle, to = flowerFarm, of = 0 )
94
- givenADistanceFrom(froyle, to = watercressLine, of = 6300 )
95
-
96
- assertEquals(
97
- listOf (
80
+ check(
81
+ featuredDestinations = mapOf (
82
+ alton to listOf (flowerFarm, watercressLine),
83
+ froyle to listOf (flowerFarm, watercressLine)
84
+ ),
85
+ distances = distances,
86
+ recommendations = setOf (alton, froyle),
87
+ shouldReturn = listOf (
98
88
FeaturedDestinationSuggestion (froyle, flowerFarm, 0 ),
99
89
FeaturedDestinationSuggestion (alton, watercressLine, 320 )
100
- ),
101
- recommendations.recommendationsFor(setOf (alton, froyle))
90
+ )
102
91
)
103
92
}
93
+ }
104
94
105
- private fun givenFeaturedDestinationsFor (
106
- location : Location ,
107
- of : List <FeaturedDestination >
108
- ) {
109
- featuredDestinations[location] = of
110
- }
111
-
112
- private fun givenADistanceFrom (
113
- from : Location ,
114
- to : FeaturedDestination ,
115
- of : Int
116
- ) {
117
- distanceInMetersBetween[from to to.location] = of
118
- }
119
-
120
- private fun location (name : String ) = Location (Id .of(name), name, name)
121
-
122
- private fun featured (name : String , locationName : String ) =
123
- featured(name, location(locationName))
95
+ private fun subjectFor (
96
+ featuredDestinations : Map <Location , List <FeaturedDestination >>,
97
+ distances : Map <Pair <Location , Location >, Int >
98
+ ): Recommendations {
99
+ val destinationsLookup = featuredDestinations.withDefault { emptyList() }
100
+ val distanceLookup = distances.withDefault { - 1 }
101
+ return Recommendations (destinationsLookup::getValue, distanceLookup::getValue)
102
+ }
124
103
125
- private fun featured (name : String , location : Location ) =
126
- FeaturedDestination (name, location)
104
+ private fun check (
105
+ featuredDestinations : Map <Location , List <FeaturedDestination >>,
106
+ distances : Map <Pair <Location , Location >, Int >,
107
+ recommendations : Set <Location >,
108
+ shouldReturn : List <FeaturedDestinationSuggestion >
109
+ ) {
110
+ assertEquals(
111
+ shouldReturn,
112
+ resultFor(featuredDestinations, distances, recommendations)
113
+ )
127
114
}
128
115
129
- private fun of (vararg destination : FeaturedDestination )
130
- = destination.toList()
116
+ private fun resultFor (
117
+ featuredDestinations : Map <Location , List <FeaturedDestination >>,
118
+ distances : Map <Pair <Location , Location >, Int >,
119
+ locations : Set <Location >
120
+ ): List <FeaturedDestinationSuggestion > {
121
+ val subject = subjectFor(featuredDestinations, distances)
122
+ return subject.recommendationsFor(locations)
123
+ }
131
124
132
125
private fun <K1 , K2 , V > Map <Pair <K1 , K2 >, V>.getValue (k1 : K1 , k2 : K2 ) =
133
126
getValue(k1 to k2)
127
+
128
+ private val paris = location(" Paris" )
129
+ private val louvre = featured(" Louvre" , " Rue de Rivoli" )
130
+ private val eiffelTower = featured(" Eiffel Tower" , " Champ de Mars" )
131
+ private val alton = location(" Alton" )
132
+ private val froyle = location(" Froyle" )
133
+ private val watercressLine = featured(" Watercress Line" , " Alton Station" )
134
+ private val flowerFarm = featured(" West End Flower Farm" , froyle)
135
+
136
+ private fun location (name : String ) = Location (Id .of(name), name, name)
137
+
138
+ private fun featured (name : String , locationName : String ) =
139
+ featured(name, location(locationName))
140
+
141
+ private fun featured (name : String , location : Location ) =
142
+ FeaturedDestination (name, location)
0 commit comments