top10: 1.4.2 - RocksDB does nor work in Alpine-Linux
[demos/kafka/wordcount] / src / test / java / de / juplo / kafka / wordcount / top10 / RankingTest.java
1 package de.juplo.kafka.wordcount.top10;
2
3 import org.junit.jupiter.api.DisplayName;
4 import org.junit.jupiter.api.Test;
5 import org.junit.jupiter.params.ParameterizedTest;
6 import org.junit.jupiter.params.provider.MethodSource;
7 import org.junit.jupiter.params.provider.ValueSource;
8
9 import java.util.LinkedList;
10 import java.util.List;
11 import java.util.stream.Stream;
12
13 import static org.assertj.core.api.Assertions.assertThat;
14 import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
15
16
17 public class RankingTest
18 {
19   @DisplayName("A newly created instance is empty")
20   @Test
21   public void testNewRankingIsEmpty()
22   {
23     Ranking ranking = new Ranking();
24     assertThat(ranking.getEntries()).isEmpty();
25   }
26
27   @DisplayName("An instance that was build from an empty ranking is empty")
28   @Test
29   public void testRankingOfYieldsExpectedResultForEmptyList()
30   {
31     Ranking ranking = new Ranking();
32     assertThat(ranking.getEntries()).isEmpty();
33   }
34
35   @DisplayName("An instance that was build from a valid ranking contains the expected entries")
36   @ParameterizedTest
37   @MethodSource("validRankingsProvider")
38   public void testRankingOfYieldsExpectedResultsForValidRankings(List<Entry> entryList)
39   {
40     Ranking ranking = Ranking.of(toArray(entryList));
41     assertThat(ranking.getEntries()).containsExactlyElementsOf(entryList);
42   }
43
44   @DisplayName("The builder fails for invalid rankings")
45   @ParameterizedTest
46   @MethodSource("invalidRankingsProvider")
47   public void testRankingOfThrowsExceptionForInvalidRankings(List<Entry> entryList)
48   {
49     assertThatExceptionOfType(IllegalArgumentException.class)
50         .isThrownBy(() -> Ranking.of(toArray(entryList)));
51   }
52
53   @DisplayName("Adding a new word with highest ranking, pushes all other words down")
54   @ParameterizedTest
55   @MethodSource("validRankingsProvider")
56   public void testAddingNewWordWithHighestRanking(List<Entry> entryList)
57   {
58     Ranking ranking = Ranking.of(toArray(entryList));
59     Entry newEntry = Entry.of("NEW!", rankingForPosition(-1));
60     ranking.add(newEntry);
61     assertThat(ranking.getEntries()[0]).isEqualTo(newEntry);
62     for (int i = 0; i < entryList.size() && i < Ranking.MAX_ENTRIES - 1; i++)
63     {
64       assertThat(ranking.getEntries()[i + 1]).isEqualTo(entryList.get(i));
65     }
66   }
67
68   @DisplayName("Adding a new word with an existent ranking, pushes all words with lower ranking down")
69   @ParameterizedTest
70   @MethodSource("validRankingsProvider")
71   public void testAddingNewWordWithExistingRanking(List<Entry> entryList)
72   {
73     for (int position = 0; position < entryList.size(); position++ )
74     {
75       Ranking ranking = Ranking.of(toArray(entryList));
76       Entry newEntry = Entry.of("NEW!", rankingForPosition(position));
77       ranking.add(newEntry);
78       for (int i = 0; i < entryList.size() && i < Ranking.MAX_ENTRIES - 1; i++)
79       {
80         if (i < position)
81         {
82           assertThat(ranking.getEntries()[i]).isEqualTo(entryList.get(i));
83         }
84         if (i == position)
85         {
86           assertThat(ranking.getEntries()[i]).isEqualTo(entryList.get(i));
87           assertThat(ranking.getEntries()[i + 1]).isEqualTo(newEntry);
88         }
89         if (i > position)
90         {
91           assertThat(ranking.getEntries()[i + 1]).isEqualTo(entryList.get(i));
92         }
93       }
94     }
95   }
96
97   @DisplayName("Adding a highest ranking for an existing word shifts it to the first place")
98   @ParameterizedTest
99   @ValueSource(ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })
100   public void testAddingExistingWordWithHighestRanking(int position)
101   {
102     Ranking ranking = Ranking.of(toArray(VALID_RANKINGS[0]));
103     String word = wordForPosition(position);
104     Entry highestEntry = Entry.of(word, 100l);
105     ranking.add(highestEntry);
106     List<Entry> expectedEntries = Stream
107         .concat(
108             Stream.of(highestEntry),
109             VALID_RANKINGS[0]
110                 .stream()
111                 .filter(entry -> !entry.getWord().equals(word)))
112         .toList();
113     assertThat(ranking.getEntries()).containsExactlyElementsOf(expectedEntries);
114   }
115
116   @DisplayName("Adding an existing word with unchanged ranking changes nothing")
117   @ParameterizedTest
118   @ValueSource(ints = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })
119   public void testAddingExistingWordWithUnchangedRanking(int position)
120   {
121     Ranking ranking = Ranking.of(toArray(VALID_RANKINGS[0]));
122     Entry unchangedEntry = Entry.of(
123         wordForPosition(position),
124         rankingForPosition(position));
125     ranking.add(unchangedEntry);
126     assertThat(ranking.getEntries()).containsExactlyElementsOf(VALID_RANKINGS[0]);
127   }
128
129   @DisplayName("Adding an existing word with a lower ranking fails")
130   @ParameterizedTest
131   @MethodSource("validRankingsProvider")
132   public void testAddingExistingWordWithLowerRankingFails(List<Entry> entryList)
133   {
134     Ranking ranking = Ranking.of(toArray(entryList));
135     entryList.forEach(entry ->
136       assertThatExceptionOfType(IllegalArgumentException.class)
137           .isThrownBy(() -> ranking.add(Entry.of(entry.getWord(), entry.getCounter() - 1))));
138   }
139
140   @DisplayName("Identical rankings are considered equal")
141   @ParameterizedTest
142   @MethodSource("validRankingsProvider")
143   public void testIdenticalRankingsAreConsideredEaqual(List<Entry> entryList)
144   {
145     assertThat(Ranking.of(toArray(entryList))).isEqualTo(Ranking.of(toArray(entryList)));
146   }
147
148   @DisplayName("Two empty rankings are considered equal")
149   @Test
150   public void testTwoEmptyRankingsAreConsideredEaqual()
151   {
152     assertThat(Ranking.of()).isEqualTo(Ranking.of());
153   }
154
155   @DisplayName("A changed ranking is not considered equal to its unchanged counter-part")
156   @ParameterizedTest
157   @MethodSource("validRankingsProvider")
158   public void testChangedRankingsDoNotEaqualUnchangedOne(List<Entry> entryList)
159   {
160     Ranking changed = Ranking.of(toArray(entryList));
161     changed.add(Entry.of("devilish", 666l));
162     assertThat(changed).isNotEqualTo(Ranking.of(toArray(entryList)));
163   }
164
165   @DisplayName("Rankigs are considered equal, if only the order of words with the same count differ")
166   @Test
167   public void testRankingWithDifferentOrderForSameCountAreEqual()
168   {
169     assertThat(
170         Ranking.of(
171             Entry.of("a1",10l),
172             Entry.of("a2",10l),
173             Entry.of("b1", 9l),
174             Entry.of("b2",9l),
175             Entry.of("c1", 8l),
176             Entry.of("c2", 8l)))
177         .isEqualTo(Ranking.of(
178             Entry.of("a2",10l),
179             Entry.of("a1",10l),
180             Entry.of("b2", 9l),
181             Entry.of("b1",9l),
182             Entry.of("c2", 8l),
183             Entry.of("c1", 8l)));
184   }
185
186
187   Entry[] toArray(List<Entry> entryList)
188   {
189     return entryList.toArray(size -> new Entry[size]);
190   }
191
192   static String wordForPosition(int position)
193   {
194     return Integer.toString(position+1);
195   }
196
197   static long rankingForPosition(int position)
198   {
199     return (long)Ranking.MAX_ENTRIES * 2 - position;
200   }
201
202   static Stream<List<Entry>> validRankingsProvider()
203   {
204     return Stream.of(VALID_RANKINGS);
205   }
206
207   static Stream<List<Entry>> invalidRankingsProvider()
208   {
209     return Stream.of(INVALID_RANKINGS);
210   }
211
212   static String[] WORDS = new String[Ranking.MAX_ENTRIES];
213   static List<Entry>[] VALID_RANKINGS = new List[Ranking.MAX_ENTRIES];
214
215   static
216   {
217     for (int i = 0; i < Ranking.MAX_ENTRIES; i++)
218     {
219       List<Entry> ranking = new LinkedList<>();
220       String word = null;
221       for (int position = 0; position <= i; position++)
222       {
223         word = wordForPosition(position);
224         Entry entry = Entry.of(word, rankingForPosition(position));
225         ranking.add(entry);
226       }
227       WORDS[i] = word;
228       VALID_RANKINGS[Ranking.MAX_ENTRIES - (i + 1)] = ranking;
229     }
230   }
231
232   static List<Entry>[] INVALID_RANKINGS = new List[] {
233       List.of(
234           Entry.of("Platz eins", 1l),
235           Entry.of("Platz zwei", 2l)),
236       List.of(
237           Entry.of("Platz eins", 1111111111l),
238           Entry.of("Platz zwei", 222222222l),
239           Entry.of("Platz eins", 1l)),
240       List.of(
241           Entry.of("Platz eins", 11l),
242           Entry.of("Platz eins", 1l)),
243       List.of(
244           Entry.of("Platz eins", 1111111111l),
245           Entry.of("Platz zwei", 222222222l),
246           Entry.of("Platz eins", 11111111l),
247           Entry.of("Platz zwei", 2222222l),
248           Entry.of("Platz fünf", 555555l)),
249       List.of(
250           Entry.of("Platz eins", 1111111111l),
251           Entry.of("Platz zwei", 222222222l),
252           Entry.of("Platz drei", 33333333l),
253           Entry.of("Platz vier", 4444444l),
254           Entry.of("Platz eins", 111111l),
255           Entry.of("Platz sechs", 66666l)),
256       List.of(
257           Entry.of("Platz eins", 1111111111l),
258           Entry.of("Platz zwei", 222222222l),
259           Entry.of("Platz drei", 33333333l),
260           Entry.of("Platz vier", 4444444l),
261           Entry.of("Platz fünf", 555555l),
262           Entry.of("Platz sechs", 66666l),
263           Entry.of("Platz eins", 1l)),
264       List.of(
265           Entry.of("Platz eins", 1111111111l),
266           Entry.of("Platz zwei", 222222222l),
267           Entry.of("Platz drei", 33333333l),
268           Entry.of("Platz vier", 4444444l),
269           Entry.of("Platz fünf", 555555l),
270           Entry.of("Platz sechs", 66666l),
271           Entry.of("Platz sieben", 7777l),
272           Entry.of("Platz acht", 888l),
273           Entry.of("Platz neun", 99l),
274           Entry.of("Platz 10", 6l),
275           Entry.of("Platz 11", 3l))};
276 }