Skip to content

Commit c00c062

Browse files
committed
Added tests for TopicLevel, TopicLevels, TopicIterator
1 parent 0f2967a commit c00c062

File tree

5 files changed

+562
-2
lines changed

5 files changed

+562
-2
lines changed

src/main/java/com/hivemq/client/internal/mqtt/datatypes/MqttTopicIterator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@ public boolean forwardIfEqual(final @NotNull MqttTopicLevels topicLevels) {
103103
final byte[] topicLevelsArray = topicLevels.getArray();
104104
final int topicLevelsEnd = topicLevels.getEnd();
105105
final int to = end + topicLevelsArray.length - topicLevelsEnd;
106-
if ((to <= allEnd) && ByteArrayUtil.equals(array, end + 1, to, topicLevelsArray, topicLevelsEnd + 1,
107-
topicLevelsArray.length)) {
106+
if ((to <= allEnd) && ((to == allEnd) || (array[to] == MqttTopic.TOPIC_LEVEL_SEPARATOR)) &&
107+
ByteArrayUtil.equals(array, end + 1, to, topicLevelsArray, topicLevelsEnd + 1,
108+
topicLevelsArray.length)) {
108109
start = end = to;
109110
return true;
110111
}
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
/*
2+
* Copyright 2018 dc-square and the HiveMQ MQTT Client Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.hivemq.client.internal.mqtt.datatypes;
19+
20+
import org.jetbrains.annotations.NotNull;
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.params.ParameterizedTest;
23+
import org.junit.jupiter.params.provider.CsvSource;
24+
25+
import java.util.NoSuchElementException;
26+
27+
import static org.junit.jupiter.api.Assertions.*;
28+
29+
/**
30+
* @author Silvio Giebl
31+
*/
32+
class MqttTopicIteratorTest {
33+
34+
@Test
35+
void of_topic() {
36+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicImpl.of("test/topic"));
37+
38+
assertTrue(topicIterator.hasNext());
39+
final MqttTopicLevel level1 = topicIterator.next();
40+
assertEquals(MqttTopicLevel.of("test".getBytes(), 0, 4), level1);
41+
assertFalse(level1.isSingleLevelWildcard());
42+
43+
assertTrue(topicIterator.hasNext());
44+
final MqttTopicLevel level2 = topicIterator.next();
45+
assertEquals(MqttTopicLevel.of("topic".getBytes(), 0, 5), level2);
46+
assertFalse(level2.isSingleLevelWildcard());
47+
48+
assertFalse(topicIterator.hasNext());
49+
assertFalse(topicIterator.hasMultiLevelWildcard());
50+
assertThrows(NoSuchElementException.class, topicIterator::next);
51+
}
52+
53+
@Test
54+
void of_topicFilter() {
55+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of("test/+/topic/#"));
56+
57+
assertTrue(topicIterator.hasNext());
58+
final MqttTopicLevel level1 = topicIterator.next();
59+
assertEquals(MqttTopicLevel.of("test".getBytes(), 0, 4), level1);
60+
assertFalse(level1.isSingleLevelWildcard());
61+
62+
assertTrue(topicIterator.hasNext());
63+
final MqttTopicLevel level2 = topicIterator.next();
64+
assertEquals(MqttTopicLevel.of("+".getBytes(), 0, 1), level2);
65+
assertTrue(level2.isSingleLevelWildcard());
66+
67+
assertTrue(topicIterator.hasNext());
68+
final MqttTopicLevel level3 = topicIterator.next();
69+
assertEquals(MqttTopicLevel.of("topic".getBytes(), 0, 5), level3);
70+
assertFalse(level3.isSingleLevelWildcard());
71+
72+
assertFalse(topicIterator.hasNext());
73+
assertTrue(topicIterator.hasMultiLevelWildcard());
74+
assertThrows(NoSuchElementException.class, topicIterator::next);
75+
}
76+
77+
@Test
78+
void fork() {
79+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of("test/+/topic/#"));
80+
topicIterator.next();
81+
82+
final MqttTopicIterator fork = topicIterator.fork();
83+
84+
assertTrue(topicIterator.hasNext());
85+
final MqttTopicLevel level2 = topicIterator.next();
86+
assertEquals(MqttTopicLevel.of("+".getBytes(), 0, 1), level2);
87+
assertTrue(level2.isSingleLevelWildcard());
88+
assertTrue(topicIterator.hasNext());
89+
final MqttTopicLevel level3 = topicIterator.next();
90+
assertEquals(MqttTopicLevel.of("topic".getBytes(), 0, 5), level3);
91+
assertFalse(level3.isSingleLevelWildcard());
92+
assertFalse(topicIterator.hasNext());
93+
assertTrue(topicIterator.hasMultiLevelWildcard());
94+
assertThrows(NoSuchElementException.class, topicIterator::next);
95+
96+
assertTrue(fork.hasNext());
97+
final MqttTopicLevel forkLevel2 = fork.next();
98+
assertEquals(MqttTopicLevel.of("+".getBytes(), 0, 1), forkLevel2);
99+
assertTrue(forkLevel2.isSingleLevelWildcard());
100+
assertTrue(fork.hasNext());
101+
final MqttTopicLevel forkLevel3 = fork.next();
102+
assertEquals(MqttTopicLevel.of("topic".getBytes(), 0, 5), forkLevel3);
103+
assertFalse(forkLevel3.isSingleLevelWildcard());
104+
assertFalse(fork.hasNext());
105+
assertTrue(fork.hasMultiLevelWildcard());
106+
assertThrows(NoSuchElementException.class, fork::next);
107+
}
108+
109+
@ParameterizedTest
110+
@CsvSource({"test/topic, topic", "test/+, +", "test/+/#, +"})
111+
void trim_topicLevel(final @NotNull String topicFilter, final @NotNull String topicLevels) {
112+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
113+
topicIterator.next();
114+
115+
final MqttTopicLevel trim = topicIterator.next().trim();
116+
final MqttTopicLevel level = MqttTopicLevel.of(topicLevels.getBytes(), 0, topicLevels.getBytes().length);
117+
MqttTopicLevelsTest.assertEqualsWithClass(level, trim);
118+
}
119+
120+
@ParameterizedTest
121+
@CsvSource({"test/+/topic, +/topic", "test/+/topic/#, +/topic"})
122+
void trim_topicLevels(final @NotNull String topicFilter, final @NotNull String topicLevels) {
123+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
124+
topicIterator.next();
125+
126+
final MqttTopicLevel trim = topicIterator.next().trim();
127+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
128+
MqttTopicLevelsTest.assertEqualsWithClass(levels, trim);
129+
}
130+
131+
@ParameterizedTest
132+
@CsvSource({"test/topic/filter, test/topic/filter", "test/+/topic, test/+/topic", "test/+/topic/#, test/+/topic"})
133+
void forwardIfEqual_equalToEnd(final @NotNull String topicFilter, final @NotNull String topicLevels) {
134+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
135+
topicIterator.next();
136+
137+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
138+
assertTrue(topicIterator.forwardIfEqual(levels));
139+
140+
assertFalse(topicIterator.hasNext());
141+
assertEquals(topicFilter.endsWith("#"), topicIterator.hasMultiLevelWildcard());
142+
}
143+
144+
@ParameterizedTest
145+
@CsvSource({
146+
"test/topic/filter/abc, test/topic/filter", "test/+/topic/abc, test/+/topic",
147+
"test/+/topic/abc/#, test/+/topic"
148+
})
149+
void forwardIfEqual_remainingLevels(final @NotNull String topicFilter, final @NotNull String topicLevels) {
150+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
151+
topicIterator.next();
152+
153+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
154+
assertTrue(topicIterator.forwardIfEqual(levels));
155+
156+
assertTrue(topicIterator.hasNext());
157+
final MqttTopicLevel lastLevel = topicIterator.next();
158+
assertEquals(MqttTopicLevel.of("abc".getBytes(), 0, 3), lastLevel);
159+
assertFalse(lastLevel.isSingleLevelWildcard());
160+
assertFalse(topicIterator.hasNext());
161+
assertEquals(topicFilter.endsWith("#"), topicIterator.hasMultiLevelWildcard());
162+
}
163+
164+
@ParameterizedTest
165+
@CsvSource({
166+
"test/topic/filter, test/topic/filter/abc", "test/+/topic, test/+/topic/abc",
167+
"test/+/topic/#, test/+/topic/abc"
168+
})
169+
void forwardIfEqual_tooShort(final @NotNull String topicFilter, final @NotNull String topicLevels) {
170+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
171+
topicIterator.next();
172+
final int start = topicIterator.getStart();
173+
final int end = topicIterator.getEnd();
174+
175+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
176+
assertFalse(topicIterator.forwardIfEqual(levels));
177+
178+
assertEquals(start, topicIterator.getStart());
179+
assertEquals(end, topicIterator.getEnd());
180+
}
181+
182+
@ParameterizedTest
183+
@CsvSource({
184+
"test, test/topic", "test/topic/filter, test/topic/filte2", "test/topic/filter, test/topic/filter2",
185+
"test/topic/filter2, test/topic/filter", "test/+/topic, test/+/topi2", "test/+/topic, test/+/topic2",
186+
"test/+/topic2, test/+/topic", "test/+/topic/#, test/+/topi2", "test/+/topic/#, test/+/topic2",
187+
"test/+/topic2/#, test/+/topic", "test/topic/+, test/topic/abc"
188+
})
189+
void forwardIfEqual_notFullyEqual(final @NotNull String topicFilter, final @NotNull String topicLevels) {
190+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
191+
topicIterator.next();
192+
final int start = topicIterator.getStart();
193+
final int end = topicIterator.getEnd();
194+
195+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
196+
assertFalse(topicIterator.forwardIfEqual(levels));
197+
198+
assertEquals(start, topicIterator.getStart());
199+
assertEquals(end, topicIterator.getEnd());
200+
}
201+
202+
@ParameterizedTest
203+
@CsvSource({"test/topic/filter, test/topic/filter", "test/+/topic, test/+/topic", "test/+/topic/#, test/+/topic"})
204+
void forwardWhileEqual_equalToEnd(final @NotNull String topicFilter, final @NotNull String topicLevels) {
205+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
206+
topicIterator.next();
207+
208+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
209+
assertEquals(topicLevels.length(), topicIterator.forwardWhileEqual(levels));
210+
211+
assertFalse(topicIterator.hasNext());
212+
assertEquals(topicFilter.endsWith("#"), topicIterator.hasMultiLevelWildcard());
213+
}
214+
215+
@ParameterizedTest
216+
@CsvSource({
217+
"test/topic/filter/abc, test/topic/filter", "test/+/topic/abc, test/+/topic",
218+
"test/+/topic/abc/#, test/+/topic"
219+
})
220+
void forwardWhileEqual_remainingLevels(final @NotNull String topicFilter, final @NotNull String topicLevels) {
221+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
222+
topicIterator.next();
223+
224+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
225+
assertEquals(topicLevels.length(), topicIterator.forwardWhileEqual(levels));
226+
227+
assertTrue(topicIterator.hasNext());
228+
final MqttTopicLevel lastLevel = topicIterator.next();
229+
assertEquals(MqttTopicLevel.of("abc".getBytes(), 0, 3), lastLevel);
230+
assertFalse(lastLevel.isSingleLevelWildcard());
231+
assertFalse(topicIterator.hasNext());
232+
assertEquals(topicFilter.endsWith("#"), topicIterator.hasMultiLevelWildcard());
233+
}
234+
235+
@ParameterizedTest
236+
@CsvSource({
237+
"test, test/topic", "test/topic/filter, test/topic/filter/abc", "test/+/topic, test/+/topic/abc",
238+
"test/+/topic/#, test/+/topic/abc"
239+
})
240+
void forwardWhileEqual_tooShort(final @NotNull String topicFilter, final @NotNull String topicLevels) {
241+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
242+
topicIterator.next();
243+
244+
final boolean hasMultiLevelWildcard = topicFilter.endsWith("#");
245+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
246+
assertEquals(
247+
hasMultiLevelWildcard ? topicFilter.length() - 2 : topicFilter.length(),
248+
topicIterator.forwardWhileEqual(levels));
249+
250+
assertFalse(topicIterator.hasNext());
251+
assertEquals(hasMultiLevelWildcard, topicIterator.hasMultiLevelWildcard());
252+
}
253+
254+
@ParameterizedTest
255+
@CsvSource({
256+
"test/topic/filter, test/topic/filte2, 10", "test/topic/filter, test/topic/filter2, 10",
257+
"test/topic/filter2, test/topic/filter, 10", "test/+/topic, test/+/topi2, 6",
258+
"test/+/topic, test/+/topic2, 6", "test/+/topic2, test/+/topic, 6", "test/+/topic/#, test/+/topi2, 6",
259+
"test/+/topic/#, test/+/topic2, 6", "test/+/topic2/#, test/+/topic, 6", "test/topic/+, test/topic/abc, 10"
260+
})
261+
void forwardWhileEqual_notFullyEqual(
262+
final @NotNull String topicFilter, final @NotNull String topicLevels, final int branchIndex) {
263+
264+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
265+
topicIterator.next();
266+
267+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
268+
assertEquals(branchIndex, topicIterator.forwardWhileEqual(levels));
269+
270+
assertEquals(branchIndex, topicIterator.getStart());
271+
assertEquals(branchIndex, topicIterator.getEnd());
272+
}
273+
274+
@ParameterizedTest
275+
@CsvSource(
276+
{"test/topic/filter, test/topic/filter", "test/topic/filter, test/+/filter", "test/topic/filter, test/+/+"})
277+
void forwardIfMatch_equalToEnd(final @NotNull String topic, final @NotNull String topicLevels) {
278+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicImpl.of(topic));
279+
topicIterator.next();
280+
281+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
282+
assertTrue(topicIterator.forwardIfMatch(levels));
283+
284+
assertFalse(topicIterator.hasNext());
285+
}
286+
287+
@ParameterizedTest
288+
@CsvSource({
289+
"test/topic/filter/abc, test/topic/filter", "test/topic/filter/abc, test/+/filter",
290+
"test/topic/filter/abc, test/+/+"
291+
})
292+
void forwardIfMatch_remainingLevels(final @NotNull String topicFilter, final @NotNull String topicLevels) {
293+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
294+
topicIterator.next();
295+
296+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
297+
assertTrue(topicIterator.forwardIfMatch(levels));
298+
299+
assertTrue(topicIterator.hasNext());
300+
final MqttTopicLevel lastLevel = topicIterator.next();
301+
assertEquals(MqttTopicLevel.of("abc".getBytes(), 0, 3), lastLevel);
302+
assertFalse(lastLevel.isSingleLevelWildcard());
303+
assertFalse(topicIterator.hasNext());
304+
}
305+
306+
@ParameterizedTest
307+
@CsvSource({
308+
"test/topic/filter, test/topic/filter/abc", "test/topic/filter, test/+/filter/abc",
309+
"test/topic/filter, test/+/+/abc", "test/topic/filter, test/+/filter/+"
310+
})
311+
void forwardIfMatch_tooShort(final @NotNull String topicFilter, final @NotNull String topicLevels) {
312+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
313+
topicIterator.next();
314+
final int start = topicIterator.getStart();
315+
final int end = topicIterator.getEnd();
316+
317+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
318+
assertFalse(topicIterator.forwardIfMatch(levels));
319+
320+
assertEquals(start, topicIterator.getStart());
321+
assertEquals(end, topicIterator.getEnd());
322+
}
323+
324+
@ParameterizedTest
325+
@CsvSource({
326+
"test, test/topic", "test/topic/filter, test/topic/filte2", "test/topic/filter, test/topic/filter2",
327+
"test/topic/filter2, test/topic/filter", "test/topic/filter, test/+/filte2",
328+
"test/topic/filter, test/+/filter2", "test/topic/filter2, test/+/filter"
329+
})
330+
void forwardIfMatch_notFullyEqual(final @NotNull String topicFilter, final @NotNull String topicLevels) {
331+
final MqttTopicIterator topicIterator = MqttTopicIterator.of(MqttTopicFilterImpl.of(topicFilter));
332+
topicIterator.next();
333+
final int start = topicIterator.getStart();
334+
final int end = topicIterator.getEnd();
335+
336+
final MqttTopicLevels levels = createTopicLevels(topicLevels);
337+
assertFalse(topicIterator.forwardIfMatch(levels));
338+
339+
assertEquals(start, topicIterator.getStart());
340+
assertEquals(end, topicIterator.getEnd());
341+
}
342+
343+
private static @NotNull MqttTopicLevels createTopicLevels(final @NotNull String levels) {
344+
final byte[] bytes = levels.getBytes();
345+
final int firstEnd = levels.indexOf('/');
346+
return new MqttTopicLevels(bytes, (firstEnd == -1) ? bytes.length : firstEnd);
347+
}
348+
}

0 commit comments

Comments
 (0)