]> git.basschouten.com Git - openhab-addons.git/blob
7c60c4fb68f3444a19cfbb32861b893bcab399bf
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.icalendar.internal.logic;
14
15 import static org.junit.jupiter.api.Assertions.*;
16
17 import java.io.FileInputStream;
18 import java.io.IOException;
19 import java.time.Instant;
20 import java.time.LocalDate;
21 import java.time.ZoneId;
22 import java.util.List;
23
24 import org.junit.jupiter.api.BeforeEach;
25 import org.junit.jupiter.api.Test;
26 import org.openhab.core.library.types.DecimalType;
27 import org.openhab.core.library.types.HSBType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.OpenClosedType;
30 import org.openhab.core.library.types.PercentType;
31 import org.openhab.core.library.types.PlayPauseType;
32 import org.openhab.core.library.types.QuantityType;
33 import org.openhab.core.library.types.RewindFastforwardType;
34 import org.openhab.core.library.types.StringType;
35 import org.openhab.core.library.types.UpDownType;
36 import org.openhab.core.types.Command;
37
38 /**
39  * Tests for presentable calendar.
40  *
41  * @author Michael Wodniok - Initial contribution.
42  * @author Andrew Fiddian-Green - Tests for Command Tag code
43  * @author Michael Wodniok - Extended Tests for filtered Events
44  * @author Michael Wodniok - Extended Test for parallel current events
45  */
46 public class BiweeklyPresentableCalendarTest {
47     private AbstractPresentableCalendar calendar;
48     private AbstractPresentableCalendar calendar2;
49     private AbstractPresentableCalendar calendar3;
50     private AbstractPresentableCalendar calendar_issue9647;
51     private AbstractPresentableCalendar calendar_issue10808;
52
53     @BeforeEach
54     public void setUp() throws IOException, CalendarException {
55         calendar = new BiweeklyPresentableCalendar(new FileInputStream("src/test/resources/test.ics"));
56         calendar2 = new BiweeklyPresentableCalendar(new FileInputStream("src/test/resources/test2.ics"));
57         calendar3 = new BiweeklyPresentableCalendar(new FileInputStream("src/test/resources/test3.ics"));
58         calendar_issue9647 = new BiweeklyPresentableCalendar(
59                 new FileInputStream("src/test/resources/test-issue9647.ics"));
60         calendar_issue10808 = new BiweeklyPresentableCalendar(
61                 new FileInputStream("src/test/resources/test-issue10808.ics"));
62     }
63
64     /**
65      * Tests recurrence and whether TimeZone is interpolated in a right way.
66      */
67     @Test
68     public void testIsEventPresent() {
69         // Test series
70         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-08T09:04:00Z")));
71         assertTrue(calendar.isEventPresent(Instant.parse("2019-09-08T09:08:00Z")));
72         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-08T09:11:00Z")));
73
74         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-09T09:04:00Z")));
75         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-09T09:08:00Z")));
76         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-09T09:11:00Z")));
77
78         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-10T09:04:00Z")));
79         assertTrue(calendar.isEventPresent(Instant.parse("2019-09-10T09:08:00Z")));
80         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-10T09:11:00Z")));
81
82         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-11T09:04:00Z")));
83         assertTrue(calendar.isEventPresent(Instant.parse("2019-09-11T09:08:00Z")));
84         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-11T09:11:00Z")));
85
86         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-12T09:04:00Z")));
87         assertTrue(calendar.isEventPresent(Instant.parse("2019-09-12T09:08:00Z")));
88         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-12T09:11:00Z")));
89
90         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-13T09:04:00Z")));
91         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-13T09:08:00Z")));
92         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-13T09:11:00Z")));
93
94         // Test in CEST (UTC+2)
95         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-14T07:59:00Z")));
96         assertTrue(calendar.isEventPresent(Instant.parse("2019-09-14T08:03:00Z")));
97         assertFalse(calendar.isEventPresent(Instant.parse("2019-09-14T09:01:00Z")));
98
99         // Test Series with cancelled event by Davdroid
100         assertFalse(calendar2.isEventPresent(Instant.parse("2019-11-03T09:55:00Z")));
101         assertTrue(calendar2.isEventPresent(Instant.parse("2019-11-03T10:01:00Z")));
102         assertFalse(calendar2.isEventPresent(Instant.parse("2019-11-03T13:00:00Z")));
103
104         assertFalse(calendar2.isEventPresent(Instant.parse("2019-11-24T09:55:00Z")));
105         assertFalse(calendar2.isEventPresent(Instant.parse("2019-11-24T10:01:00Z")));
106         assertFalse(calendar2.isEventPresent(Instant.parse("2019-11-24T13:00:00Z")));
107     }
108
109     /**
110      * This test relies on a working isEventPresent and assumes the calculation
111      * of recurrence is done the same way.
112      */
113     @Test
114     public void testGetCurrentEvent() {
115         Event currentEvent = calendar.getCurrentEvent(Instant.parse("2019-09-10T09:07:00Z"));
116         assertNotNull(currentEvent);
117         assertTrue("Test Series in UTC".contentEquals(currentEvent.title));
118         assertEquals(0, Instant.parse("2019-09-10T09:05:00Z").compareTo(currentEvent.start));
119         assertEquals(0, Instant.parse("2019-09-10T09:10:00Z").compareTo(currentEvent.end));
120
121         Event nonExistingEvent = calendar.getCurrentEvent(Instant.parse("2019-09-09T09:07:00Z"));
122         assertNull(nonExistingEvent);
123
124         Event currentEvent2 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:10:05Z"));
125         assertNotNull(currentEvent2);
126         assertTrue("Test event 1".contentEquals(currentEvent2.title));
127
128         Event currentEvent3 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:13:05Z"));
129         assertNotNull(currentEvent3);
130         assertTrue("Test event 2".contentEquals(currentEvent3.title));
131
132         Event currentEvent4 = calendar_issue10808.getCurrentEvent(Instant.parse("2021-06-05T17:18:05Z"));
133         assertNotNull(currentEvent4);
134         assertTrue("Test event 1".contentEquals(currentEvent4.title));
135     }
136
137     /**
138      * This test relies on a working isEventPresent and assumes the calculation
139      * of recurrence is done the same way.
140      */
141     @Test
142     public void testGetNextEvent() {
143         // positive case: next event of series
144         Event nextEventOfSeries = calendar.getNextEvent(Instant.parse("2019-09-10T09:07:00Z"));
145         assertNotNull(nextEventOfSeries);
146         assertTrue("Test Series in UTC".contentEquals(nextEventOfSeries.title));
147         assertEquals(0, Instant.parse("2019-09-11T09:05:00Z").compareTo(nextEventOfSeries.start));
148         assertEquals(0, Instant.parse("2019-09-11T09:10:00Z").compareTo(nextEventOfSeries.end));
149
150         // positive case: next event after series
151         Event nextEventOutsideSeries = calendar.getNextEvent(Instant.parse("2019-09-12T09:07:00Z"));
152         assertNotNull(nextEventOutsideSeries);
153         assertTrue("Test Event in UTC+2".contentEquals(nextEventOutsideSeries.title));
154         assertEquals(0, Instant.parse("2019-09-14T08:00:00Z").compareTo(nextEventOutsideSeries.start));
155         assertEquals(0, Instant.parse("2019-09-14T09:00:00Z").compareTo(nextEventOutsideSeries.end));
156
157         // positive case: next event should be also set if currently none is present
158         Event nextEventIndependent = calendar.getNextEvent(Instant.parse("2019-09-13T09:07:00Z"));
159         assertTrue(nextEventOutsideSeries.equals(nextEventIndependent));
160
161         // negative case: after last event there is no next
162         Event nonExistingEvent = calendar.getNextEvent(Instant.parse("2019-09-14T12:00:00Z"));
163         assertNull(nonExistingEvent);
164
165         // mixed case: cancelled events also not show up as next
166         Event nextEventAfterCancelled = calendar2.getNextEvent(Instant.parse("2019-11-24T09:55:00Z"));
167         assertNotNull(nextEventAfterCancelled);
168         assertEquals(0, Instant.parse("2019-12-01T10:00:00Z").compareTo(nextEventAfterCancelled.start));
169     }
170
171     /**
172      * This test checks for Events that have just begun or ended, and if so it checks for Command Tags
173      * and checks if these tags are valid
174      */
175     @SuppressWarnings("null")
176     @Test
177     public void testCommandTagCode() {
178         List<Event> events = null;
179         int eventCount = 2;
180         int tagsPerEvent = 8;
181
182         // test just begun events: first in the series
183         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T15:55:00Z"),
184                 Instant.parse("2020-01-28T16:05:00Z"));
185         assertNotNull(events);
186         assertEquals(eventCount, events.size());
187         for (Event event : events) {
188             List<CommandTag> cmdTags = event.commandTags;
189             assertEquals(tagsPerEvent, cmdTags.size());
190             int beginTags = 0;
191             for (CommandTag cmdTag : cmdTags) {
192                 if (cmdTag.getTagType() == CommandTagType.BEGIN) {
193                     assertTrue(cmdTag.isAuthorized("abc"));
194                     assertTrue(cmdTag.getItemName().matches("^\\w+$"));
195                     assertTrue(cmdTag.getCommand() != null);
196                     beginTags++;
197                 }
198             }
199             assertEquals(tagsPerEvent / 2, beginTags);
200         }
201
202         // test just begun events: third in the series
203         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-30T15:55:00Z"),
204                 Instant.parse("2020-01-30T16:05:00Z"));
205         assertNotNull(events);
206         assertEquals(eventCount, events.size());
207         for (Event event : events) {
208             List<CommandTag> cmdTags = event.commandTags;
209             assertEquals(tagsPerEvent, cmdTags.size());
210             int beginTags = 0;
211             for (CommandTag cmdTag : cmdTags) {
212                 if (cmdTag.getTagType() == CommandTagType.BEGIN) {
213                     assertTrue(cmdTag.isAuthorized("abc"));
214                     assertTrue(cmdTag.getItemName().matches("^\\w+$"));
215                     assertTrue(cmdTag.getCommand() != null);
216                     beginTags++;
217                 }
218             }
219             assertEquals(tagsPerEvent / 2, beginTags);
220         }
221
222         // test outside of window: begun events, too early
223         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T15:50:00Z"),
224                 Instant.parse("2020-01-28T15:55:00Z"));
225         assertNotNull(events);
226         assertEquals(0, events.size());
227
228         // test outside of window: begun events, too late
229         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T16:05:00Z"),
230                 Instant.parse("2020-01-28T16:10:00Z"));
231         assertNotNull(events);
232         assertEquals(0, events.size());
233
234         // test just ended events: first in the series
235         events = calendar3.getJustEndedEvents(Instant.parse("2020-01-28T16:25:00Z"),
236                 Instant.parse("2020-01-28T16:35:00Z"));
237         assertNotNull(events);
238         assertEquals(eventCount, events.size());
239         for (Event event : events) {
240             List<CommandTag> cmdTags = event.commandTags;
241             assertEquals(tagsPerEvent, cmdTags.size());
242             int endTags = 0;
243             for (CommandTag cmdTag : cmdTags) {
244                 if (cmdTag.getTagType() == CommandTagType.END) {
245                     assertTrue(cmdTag.isAuthorized("abc"));
246                     assertTrue(cmdTag.getItemName().matches("^\\w+$"));
247                     assertTrue(cmdTag.getCommand() != null);
248                     endTags++;
249                 }
250             }
251             assertEquals(tagsPerEvent / 2, endTags);
252         }
253
254         // test outside of window: ended events, too early
255         events = calendar3.getJustEndedEvents(Instant.parse("2020-01-28T16:20:00Z"),
256                 Instant.parse("2020-01-28T16:25:00Z"));
257         assertNotNull(events);
258         assertEquals(0, events.size());
259
260         // test outside of window: ended events, too late
261         events = calendar3.getJustEndedEvents(Instant.parse("2020-01-28T16:35:00Z"),
262                 Instant.parse("2020-01-28T16:40:00Z"));
263         assertNotNull(events);
264         assertEquals(0, events.size());
265
266         // test a valid just begun event with both good and bad authorization codes
267         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T15:55:00Z"),
268                 Instant.parse("2020-01-28T16:05:00Z"));
269         assertNotNull(events);
270         assertTrue(!events.isEmpty());
271         List<CommandTag> cmdTags = events.get(0).commandTags;
272         assertTrue(!cmdTags.isEmpty());
273         CommandTag cmd = cmdTags.get(0);
274         // accept correct, empty or null configuration codes
275         assertTrue(cmd.isAuthorized("abc"));
276         assertTrue(cmd.isAuthorized(""));
277         assertTrue(cmd.isAuthorized(null));
278         // reject incorrect configuration code
279         assertFalse(cmd.isAuthorized("123"));
280
281         // test tag syntax: Test Series #1
282         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T19:25:00Z"),
283                 Instant.parse("2020-01-28T19:35:00Z"));
284         assertNotNull(events);
285         assertEquals(1, events.size());
286         cmdTags = events.get(0).commandTags;
287         assertEquals(11, cmdTags.size());
288
289         // BEGIN:Calendar_Test_Color:ON:abc
290         assertEquals("Calendar_Test_Color", cmdTags.get(0).getItemName());
291         assertTrue(cmdTags.get(0).isAuthorized("abc"));
292         Command cmd0 = cmdTags.get(0).getCommand();
293         assertNotNull(cmd0);
294         assertEquals(OnOffType.class, cmd0.getClass());
295
296         // BEGIN:Calendar_Test_Contact:OPEN:abc
297         Command cmd1 = cmdTags.get(1).getCommand();
298         assertNotNull(cmd1);
299         assertEquals(OpenClosedType.class, cmd1.getClass());
300
301         // BEGIN:Calendar_Test_Dimmer:ON:abc
302         Command cmd2 = cmdTags.get(2).getCommand();
303         assertNotNull(cmd2);
304         assertEquals(OnOffType.class, cmd2.getClass());
305
306         // BEGIN:Calendar_Test_Number:12.3:abc
307         Command cmd3 = cmdTags.get(3).getCommand();
308         assertNotNull(cmd3);
309         assertEquals(DecimalType.class, cmd3.getClass());
310
311         // BEGIN:Calendar_Test_Temperature:12.3°C:abc
312         Command cmd4 = cmdTags.get(4).getCommand();
313         assertNotNull(cmd4);
314         assertEquals(QuantityType.class, cmd4.getClass());
315
316         // BEGIN:Calendar_Test_Pressure:12.3hPa:abc
317         Command cmd5 = cmdTags.get(5).getCommand();
318         assertNotNull(cmd5);
319         assertEquals(QuantityType.class, cmd5.getClass());
320
321         // BEGIN:Calendar_Test_Speed:12.3m/s:abc
322         Command cmd6 = cmdTags.get(6).getCommand();
323         assertNotNull(cmd6);
324         assertEquals(QuantityType.class, cmd6.getClass());
325
326         // BEGIN:Calendar_Test_Player:PLAY:abc
327         Command cmd7 = cmdTags.get(7).getCommand();
328         assertNotNull(cmd7);
329         assertEquals(PlayPauseType.class, cmd7.getClass());
330
331         // BEGIN:Calendar_Test_RollerShutter:UP:abc
332         Command cmd8 = cmdTags.get(8).getCommand();
333         assertNotNull(cmd8);
334         assertEquals(UpDownType.class, cmd8.getClass());
335
336         // BEGIN:Calendar_Test_String:Test Series #1:abc
337         Command cmd9 = cmdTags.get(9).getCommand();
338         assertNotNull(cmd9);
339         assertEquals(StringType.class, cmd9.getClass());
340
341         // BEGIN:Calendar_Test_Switch:ON:abc
342         Command cmd10 = cmdTags.get(10).getCommand();
343         assertNotNull(cmd10);
344         assertEquals(OnOffType.class, cmd10.getClass());
345
346         // test tag syntax: Test Series #4
347         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T20:10:00Z"),
348                 Instant.parse("2020-01-28T20:20:00Z"));
349         assertNotNull(events);
350         assertEquals(1, events.size());
351         cmdTags = events.get(0).commandTags;
352         assertEquals(11, cmdTags.size());
353
354         // BEGIN:Calendar_Test_Color:0%:abc
355         cmd0 = cmdTags.get(0).getCommand();
356         assertNotNull(cmd0);
357         assertEquals(PercentType.class, cmd0.getClass());
358
359         // BEGIN:Calendar_Test_Contact:CLOSED:abc
360         cmd1 = cmdTags.get(1).getCommand();
361         assertNotNull(cmd1);
362         assertEquals(OpenClosedType.class, cmd1.getClass());
363
364         // BEGIN:Calendar_Test_Dimmer:0%:abc
365         cmd2 = cmdTags.get(2).getCommand();
366         assertNotNull(cmd2);
367         assertEquals(PercentType.class, cmd2.getClass());
368
369         // BEGIN:Calendar_Test_Number:-12.3:abc
370         cmd3 = cmdTags.get(3).getCommand();
371         assertNotNull(cmd3);
372         assertEquals(DecimalType.class, cmd3.getClass());
373
374         // BEGIN:Calendar_Test_Temperature:-12.3°C:abc
375         cmd4 = cmdTags.get(4).getCommand();
376         assertNotNull(cmd4);
377         assertEquals(QuantityType.class, cmd4.getClass());
378
379         // BEGIN:Calendar_Test_Pressure:500mmHg:abc
380         cmd5 = cmdTags.get(5).getCommand();
381         assertNotNull(cmd5);
382         assertEquals(QuantityType.class, cmd5.getClass());
383
384         // BEGIN:Calendar_Test_Speed:12300000mm/h:abc
385         cmd6 = cmdTags.get(6).getCommand();
386         assertNotNull(cmd6);
387         assertEquals(QuantityType.class, cmd6.getClass());
388
389         // BEGIN:Calendar_Test_Player:REWIND:abc
390         cmd7 = cmdTags.get(7).getCommand();
391         assertNotNull(cmd7);
392         assertEquals(RewindFastforwardType.class, cmd7.getClass());
393
394         // BEGIN:Calendar_Test_RollerShutter:100%:abc
395         cmd8 = cmdTags.get(8).getCommand();
396         assertNotNull(cmd8);
397         assertEquals(PercentType.class, cmd8.getClass());
398
399         // BEGIN:Calendar_Test_String:Test Series #4:abc
400         cmd9 = cmdTags.get(9).getCommand();
401         assertNotNull(cmd9);
402         assertEquals(StringType.class, cmd9.getClass());
403
404         // BEGIN:Calendar_Test_Switch:OFF:abc
405         cmd10 = cmdTags.get(10).getCommand();
406         assertNotNull(cmd10);
407         assertEquals(OnOffType.class, cmd10.getClass());
408
409         // test tag syntax: Test Series #5
410         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T20:25:00Z"),
411                 Instant.parse("2020-01-28T20:35:00Z"));
412         assertNotNull(events);
413         assertEquals(1, events.size());
414         cmdTags = events.get(0).commandTags;
415         assertEquals(11, cmdTags.size());
416
417         // BEGIN:Calendar_Test_Color:240,100,100:abc
418         cmd0 = cmdTags.get(0).getCommand();
419         assertNotNull(cmd0);
420         assertEquals(HSBType.class, cmd0.getClass());
421
422         // BEGIN:Calendar_Test_Contact:OPEN:abc
423         cmd1 = cmdTags.get(1).getCommand();
424         assertNotNull(cmd1);
425         assertEquals(OpenClosedType.class, cmd1.getClass());
426
427         // BEGIN:Calendar_Test_Dimmer:50%:abc
428         cmd2 = cmdTags.get(2).getCommand();
429         assertNotNull(cmd2);
430         assertEquals(PercentType.class, cmd2.getClass());
431
432         // BEGIN:Calendar_Test_Number:-0:abc
433         cmd3 = cmdTags.get(3).getCommand();
434         assertNotNull(cmd3);
435         assertEquals(DecimalType.class, cmd3.getClass());
436
437         // BEGIN:Calendar_Test_Temperature:0K:abc
438         cmd4 = cmdTags.get(4).getCommand();
439         assertNotNull(cmd4);
440         assertEquals(QuantityType.class, cmd4.getClass());
441
442         // BEGIN:Calendar_Test_Pressure:12.3hPa:abc
443         cmd5 = cmdTags.get(5).getCommand();
444         assertNotNull(cmd5);
445         assertEquals(QuantityType.class, cmd5.getClass());
446
447         // BEGIN:Calendar_Test_Speed:12.3km/h:abc
448         cmd6 = cmdTags.get(6).getCommand();
449         assertNotNull(cmd6);
450         assertEquals(QuantityType.class, cmd6.getClass());
451
452         // BEGIN:Calendar_Test_Player:PLAY:abc
453         cmd7 = cmdTags.get(7).getCommand();
454         assertNotNull(cmd7);
455         assertEquals(PlayPauseType.class, cmd7.getClass());
456
457         // BEGIN:Calendar_Test_RollerShutter:50%:abc
458         cmd8 = cmdTags.get(8).getCommand();
459         assertNotNull(cmd8);
460         assertEquals(PercentType.class, cmd8.getClass());
461
462         // BEGIN:Calendar_Test_String:Test Series #5:abc
463         cmd9 = cmdTags.get(9).getCommand();
464         assertNotNull(cmd9);
465         assertEquals(StringType.class, cmd9.getClass());
466
467         // BEGIN:Calendar_Test_Switch:ON:abc
468         cmd10 = cmdTags.get(10).getCommand();
469         assertNotNull(cmd10);
470         assertEquals(OnOffType.class, cmd10.getClass());
471
472         // test bad command tag syntax: Test Series #6
473         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T20:40:00Z"),
474                 Instant.parse("2020-01-28T20:50:00Z"));
475         assertNotNull(events);
476         assertEquals(1, events.size());
477         cmdTags = events.get(0).commandTags;
478         // Test Series #6 contains only "bad" command tags as follows..
479
480         // tags with wrong case prefix..
481         // begin
482         // Begin
483         // BEGIn
484
485         // tags that are missing ":" field delimiters..
486         // BEGIN
487
488         // tags with too few field delimiters..
489         // BEGIN:www
490
491         // tags with too many field delimiters..
492         // BEGIN:www:xxx:yyy:zzz
493
494         // tags with an invalid prefix..
495         // BEGINX:xxx:yyy:zzz
496         // ENDX:xxx:yyy:zzz
497         // BEGIN :xxx:yyy:zzz
498         // BEGIN :xxx:yyy:zzz
499
500         // tags with an empty Item Name
501         // BEGIN::yyy:zzz
502         // BEGIN: :yyy:zzz
503         // BEGIN: :yyy:zzz
504
505         // tags with bad Item Name
506         // BEGIN:!:yyy:zzz
507         // BEGIN:@:yyy:zzz
508         // BEGIN:£:yyy:zzz
509
510         // tags with an empty Target State value
511         // BEGIN:xxx::zzz
512         // BEGIN:xxx: :zzz
513         // BEGIN:xxx: :zzz
514
515         // Note: All of the above tags must be rejected! => Assert cmdTags.size() == 0 !
516
517         assertEquals(0, cmdTags.size());
518
519         // test HTML command tag syntax: Test Series #7
520         events = calendar3.getJustBegunEvents(Instant.parse("2020-01-28T20:55:00Z"),
521                 Instant.parse("2020-01-28T21:05:00Z"));
522         assertNotNull(events);
523         assertEquals(1, events.size());
524         cmdTags = events.get(0).commandTags;
525         assertEquals(8, cmdTags.size());
526
527         // <p>BEGIN:Calendar_Test_Temperature:12.3°C:abc</p>
528         cmd0 = cmdTags.get(0).getCommand();
529         assertNotNull(cmd0);
530         assertEquals(QuantityType.class, cmd0.getClass());
531
532         // <p>END:Calendar_Test_Temperature:23.4°C:abc</p>
533         cmd1 = cmdTags.get(1).getCommand();
534         assertNotNull(cmd1);
535         assertEquals(QuantityType.class, cmd1.getClass());
536
537         // <p>BEGIN:Calendar_Test_Switch:ON:abc</p>
538         cmd2 = cmdTags.get(2).getCommand();
539         assertNotNull(cmd2);
540         assertEquals(OnOffType.class, cmd2.getClass());
541
542         // <p>END:Calendar_Test_Switch:OFF:abc</p>
543         cmd3 = cmdTags.get(3).getCommand();
544         assertNotNull(cmd3);
545         assertEquals(OnOffType.class, cmd3.getClass());
546
547         // <p>BEGIN:Calendar_Test_String:the quick:abc</p>
548         cmd4 = cmdTags.get(4).getCommand();
549         assertNotNull(cmd4);
550         assertEquals(StringType.class, cmd4.getClass());
551
552         // <p>END:Calendar_Test_String:brown fox:abc</p>
553         cmd5 = cmdTags.get(5).getCommand();
554         assertNotNull(cmd5);
555         assertEquals(StringType.class, cmd5.getClass());
556
557         // </p><p>BEGIN:Calendar_Test_Number:12.3:abc</p>
558         cmd6 = cmdTags.get(6).getCommand();
559         assertNotNull(cmd6);
560         assertEquals(DecimalType.class, cmd6.getClass());
561
562         // <p>END:Calendar_Test_Number:23.4:abc</p>
563         cmd7 = cmdTags.get(7).getCommand();
564         assertNotNull(cmd7);
565         assertEquals(DecimalType.class, cmd7.getClass());
566     }
567
568     @SuppressWarnings("null")
569     @Test
570     public void testGetFilteredEventsBetween() {
571         Event[] expectedFilteredEvents1 = new Event[] {
572                 new Event("Test Series in UTC", Instant.parse("2019-09-12T09:05:00Z"),
573                         Instant.parse("2019-09-12T09:10:00Z"), ""),
574                 new Event("Test Event in UTC+2", Instant.parse("2019-09-14T08:00:00Z"),
575                         Instant.parse("2019-09-14T09:00:00Z"), "") };
576         List<Event> realFilteredEvents1 = calendar.getFilteredEventsBetween(Instant.parse("2019-09-12T06:00:00Z"),
577                 Instant.parse("2019-09-15T06:00:00Z"), null, 3);
578         assertArrayEquals(expectedFilteredEvents1, realFilteredEvents1.toArray(new Event[0]));
579
580         Event[] expectedFilteredEvents2 = new Event[] {
581                 new Event("Evt", Instant.parse("2019-11-10T10:00:00Z"), Instant.parse("2019-11-10T11:45:00Z"), ""),
582                 new Event("Evt", Instant.parse("2019-11-17T10:00:00Z"), Instant.parse("2019-11-17T11:45:00Z"), ""),
583                 new Event("Evt", Instant.parse("2019-12-01T10:00:00Z"), Instant.parse("2019-12-01T11:45:00Z"), "") };
584         List<Event> realFilteredEvents2 = calendar2.getFilteredEventsBetween(Instant.parse("2019-11-08T06:00:00Z"),
585                 Instant.parse("2019-12-31T06:00:00Z"), null, 3);
586         assertArrayEquals(expectedFilteredEvents2, realFilteredEvents2.toArray(new Event[] {}));
587
588         Event[] expectedFilteredEvents3 = new Event[] { new Event("Test Event in UTC+2",
589                 Instant.parse("2019-09-14T08:00:00Z"), Instant.parse("2019-09-14T09:00:00Z"), "") };
590         List<Event> realFilteredEvents3 = calendar.getFilteredEventsBetween(Instant.parse("2019-09-12T06:00:00Z"),
591                 Instant.parse("2019-09-15T06:00:00Z"),
592                 new EventTextFilter(EventTextFilter.Field.SUMMARY, "utc+2", EventTextFilter.Type.TEXT), 3);
593         assertArrayEquals(expectedFilteredEvents3, realFilteredEvents3.toArray(new Event[] {}));
594
595         Event[] expectedFilteredEvents4 = new Event[] { new Event("Test Series in UTC",
596                 Instant.parse("2019-09-12T09:05:00Z"), Instant.parse("2019-09-12T09:10:00Z"), "") };
597         List<Event> realFilteredEvents4 = calendar.getFilteredEventsBetween(Instant.parse("2019-09-12T06:00:00Z"),
598                 Instant.parse("2019-09-15T06:00:00Z"),
599                 new EventTextFilter(EventTextFilter.Field.SUMMARY, ".*UTC$", EventTextFilter.Type.REGEX), 3);
600         assertArrayEquals(expectedFilteredEvents4, realFilteredEvents4.toArray(new Event[] {}));
601
602         List<Event> realFilteredEvents5 = calendar.getFilteredEventsBetween(Instant.parse("2019-09-15T06:00:00Z"),
603                 Instant.parse("2019-09-12T06:00:00Z"), null, 3);
604         assertEquals(0, realFilteredEvents5.size());
605
606         List<Event> realFilteredEvents6 = calendar.getFilteredEventsBetween(Instant.parse("2019-09-15T06:00:00Z"),
607                 Instant.parse("2019-12-31T00:00:00Z"), null, 3);
608         assertEquals(0, realFilteredEvents6.size());
609
610         List<Event> realFilteredEvents7 = calendar_issue9647.getFilteredEventsBetween(
611                 LocalDate.parse("2021-01-01").atStartOfDay(ZoneId.systemDefault()).toInstant(),
612                 LocalDate.parse("2021-01-02").atStartOfDay(ZoneId.systemDefault()).toInstant(), null, 3);
613         assertEquals(0, realFilteredEvents7.size());
614
615         Event[] expectedFilteredEvents8 = new Event[] {
616                 new Event("Restabfall", LocalDate.parse("2021-01-04").atStartOfDay(ZoneId.systemDefault()).toInstant(),
617                         LocalDate.parse("2021-01-05").atStartOfDay(ZoneId.systemDefault()).toInstant(), ""),
618                 new Event("Gelbe Tonne", LocalDate.parse("2021-01-04").atStartOfDay(ZoneId.systemDefault()).toInstant(),
619                         LocalDate.parse("2021-01-05").atStartOfDay(ZoneId.systemDefault()).toInstant(), "") };
620         List<Event> realFilteredEvents8 = calendar_issue9647.getFilteredEventsBetween(
621                 LocalDate.parse("2021-01-04").atStartOfDay(ZoneId.systemDefault()).toInstant(),
622                 LocalDate.parse("2021-01-05").atStartOfDay(ZoneId.systemDefault()).toInstant(), null, 3);
623         assertArrayEquals(expectedFilteredEvents8, realFilteredEvents8.toArray(new Event[] {}));
624     }
625 }