package jfxtras.icalendarfx.component;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.Temporal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Test;
import jfxtras.icalendarfx.components.VComponent;
import jfxtras.icalendarfx.components.VDisplayable;
import jfxtras.icalendarfx.components.VEvent;
import jfxtras.icalendarfx.components.VJournal;
import jfxtras.icalendarfx.components.VTodo;
import jfxtras.icalendarfx.properties.component.change.DateTimeCreated;
import jfxtras.icalendarfx.properties.component.change.LastModified;
import jfxtras.icalendarfx.properties.component.change.Sequence;
import jfxtras.icalendarfx.properties.component.descriptive.Attachment;
import jfxtras.icalendarfx.properties.component.descriptive.Categories;
import jfxtras.icalendarfx.properties.component.descriptive.Classification;
import jfxtras.icalendarfx.properties.component.descriptive.Status;
import jfxtras.icalendarfx.properties.component.descriptive.Summary;
import jfxtras.icalendarfx.properties.component.descriptive.Classification.ClassificationType;
import jfxtras.icalendarfx.properties.component.descriptive.Status.StatusType;
import jfxtras.icalendarfx.properties.component.recurrence.ExceptionDates;
import jfxtras.icalendarfx.properties.component.recurrence.RecurrenceDates;
import jfxtras.icalendarfx.properties.component.recurrence.RecurrenceRule;
import jfxtras.icalendarfx.properties.component.recurrence.rrule.FrequencyType;
import jfxtras.icalendarfx.properties.component.recurrence.rrule.RecurrenceRuleValue;
import jfxtras.icalendarfx.properties.component.relationship.Contact;
import jfxtras.icalendarfx.properties.component.relationship.RecurrenceId;
import jfxtras.icalendarfx.properties.component.relationship.RelatedTo;
import jfxtras.icalendarfx.properties.component.time.DateTimeStart;
import jfxtras.icalendarfx.utilities.DateTimeUtilities.DateTimeType;
/**
* Test following components:
* @see VEvent
* @see VTodo
* @see VJournal
*
* for the following properties:
* @see Attachment - extended from Describable
* @see Categories
* @see Classification
* @see Contact
* @see DateTimeCreated
* @see ExceptionDates
* @see LastModified - extended from LastModified
* @see RecurrenceId
* @see RecurrenceRule - extended from Repeatable
* @see RecurrenceDates - extended from Repeatable
* @see RelatedTo
* @see Sequence
* @see Status
* @see Summary - extended from Describable
*
* @author David Bal
*
*/
public class DisplayableTest
{
@Test
public void canBuildDisplayable() throws InstantiationException, IllegalAccessException
{
List<VDisplayable<?>> components = Arrays.asList(
new VEvent()
.withAttachments(Attachment.parse("ATTACH:CID:jsmith.part3.960817T083000.xyzMail@example.com"))
.withCategories("group03","group04","group05")
.withCategories("group06")
.withClassification(ClassificationType.PUBLIC)
.withContacts("CONTACT:Jim Dolittle\\, ABC Industries\\, +1-919-555-1234", "Harry Potter\\, Hogwarts\\, by owl")
.withDateTimeCreated("20160420T080000Z")
.withExceptionDates("EXDATE:19960301T010000Z,19960304T010000Z,19960307T010000Z")
.withDateTimeLastModified("20160306T080000Z")
.withRecurrenceDates("RDATE:19960302T010000Z,19960304T010000Z")
.withRecurrenceId(ZonedDateTime.of(LocalDateTime.of(2016, 1, 1, 12, 0), ZoneId.of("Z")))
.withRelatedTo("jsmith.part7.19960817T083000.xyzMail@example.com",
"RELATED-TO;RELTYPE=SIBLING:19960401-080045-4000F192713@example.com")
.withRecurrenceRule("RRULE:FREQ=DAILY")
.withSequence(2)
.withStatus(StatusType.NEEDS_ACTION)
.withSummary("a test summary"),
new VTodo()
.withAttachments(Attachment.parse("ATTACH:CID:jsmith.part3.960817T083000.xyzMail@example.com"))
.withCategories("group03","group04","group05")
.withCategories("group06")
.withClassification(ClassificationType.PUBLIC)
.withContacts("CONTACT:Jim Dolittle\\, ABC Industries\\, +1-919-555-1234", "Harry Potter\\, Hogwarts\\, by owl")
.withDateTimeCreated("20160420T080000Z")
.withExceptionDates("EXDATE:19960301T010000Z,19960304T010000Z,19960307T010000Z")
.withDateTimeLastModified("20160306T080000Z")
.withRecurrenceDates("RDATE:19960302T010000Z,19960304T010000Z")
.withRecurrenceId(ZonedDateTime.of(LocalDateTime.of(2016, 1, 1, 12, 0), ZoneId.of("Z")))
.withRelatedTo("jsmith.part7.19960817T083000.xyzMail@example.com",
"RELATED-TO;RELTYPE=SIBLING:19960401-080045-4000F192713@example.com")
.withRecurrenceRule("RRULE:FREQ=DAILY")
.withSequence(2)
.withStatus(StatusType.NEEDS_ACTION)
.withSummary("a test summary"),
new VJournal()
.withAttachments(Attachment.parse("ATTACH:CID:jsmith.part3.960817T083000.xyzMail@example.com"))
.withCategories("group03","group04","group05")
.withCategories("group06")
.withClassification(ClassificationType.PUBLIC)
.withContacts("CONTACT:Jim Dolittle\\, ABC Industries\\, +1-919-555-1234", "Harry Potter\\, Hogwarts\\, by owl")
.withDateTimeCreated("20160420T080000Z")
.withExceptionDates("EXDATE:19960301T010000Z,19960304T010000Z,19960307T010000Z")
.withDateTimeLastModified("20160306T080000Z")
.withRecurrenceDates("RDATE:19960302T010000Z,19960304T010000Z")
.withRecurrenceId(ZonedDateTime.of(LocalDateTime.of(2016, 1, 1, 12, 0), ZoneId.of("Z")))
.withRelatedTo("jsmith.part7.19960817T083000.xyzMail@example.com",
"RELATED-TO;RELTYPE=SIBLING:19960401-080045-4000F192713@example.com")
.withRecurrenceRule("RRULE:FREQ=DAILY")
.withSequence(2)
.withStatus(StatusType.NEEDS_ACTION)
.withSummary("a test summary")
);
List<ZonedDateTime> expectedDates = Arrays.asList(
ZonedDateTime.of(LocalDateTime.of(1996, 3, 2, 1, 0), ZoneId.of("Z")),
ZonedDateTime.of(LocalDateTime.of(1996, 3, 3, 1, 0), ZoneId.of("Z")),
ZonedDateTime.of(LocalDateTime.of(1996, 3, 5, 1, 0), ZoneId.of("Z")),
ZonedDateTime.of(LocalDateTime.of(1996, 3, 9, 1, 0), ZoneId.of("Z")),
ZonedDateTime.of(LocalDateTime.of(1996, 3, 11, 1, 0), ZoneId.of("Z")),
ZonedDateTime.of(LocalDateTime.of(1996, 3, 13, 1, 0), ZoneId.of("Z"))
);
for (VDisplayable<?> builtComponent : components)
{
String componentName = builtComponent.name();
String expectedContent = "BEGIN:" + componentName + System.lineSeparator() +
"ATTACH:CID:jsmith.part3.960817T083000.xyzMail@example.com" + System.lineSeparator() +
"CATEGORIES:group03,group04,group05" + System.lineSeparator() +
"CATEGORIES:group06" + System.lineSeparator() +
"CLASS:PUBLIC" + System.lineSeparator() +
"CONTACT:Jim Dolittle\\, ABC Industries\\, +1-919-555-1234" + System.lineSeparator() +
"CONTACT:Harry Potter\\, Hogwarts\\, by owl" + System.lineSeparator() +
"CREATED:20160420T080000Z" + System.lineSeparator() +
"EXDATE:19960301T010000Z,19960304T010000Z,19960307T010000Z" + System.lineSeparator() +
"LAST-MODIFIED:20160306T080000Z" + System.lineSeparator() +
"RDATE:19960302T010000Z,19960304T010000Z" + System.lineSeparator() +
"RECURRENCE-ID:20160101T120000Z" + System.lineSeparator() +
"RELATED-TO:jsmith.part7.19960817T083000.xyzMail@example.com" + System.lineSeparator() +
"RELATED-TO;RELTYPE=SIBLING:19960401-080045-4000F192713@example.com" + System.lineSeparator() +
"RRULE:FREQ=DAILY" + System.lineSeparator() +
"SEQUENCE:2" + System.lineSeparator() +
"STATUS:NEEDS-ACTION" + System.lineSeparator() +
"SUMMARY:a test summary" + System.lineSeparator() +
"END:" + componentName;
VComponent parsedComponent = builtComponent.getClass().newInstance();
parsedComponent.addChild(expectedContent);
assertEquals(parsedComponent, builtComponent);
assertEquals(expectedContent, builtComponent.toString());
builtComponent.setRecurrenceRule("RRULE:FREQ=DAILY;INTERVAL=2");
builtComponent.setDateTimeStart(DateTimeStart.parse(ZonedDateTime.class, "19960301T010000Z"));
List<Temporal> myDates = builtComponent.streamRecurrences().limit(6).collect(Collectors.toList());
assertEquals(expectedDates, myDates);
}
}
@Test
public void exceptionTest1()
{
VEvent e = new VEvent()
.withDateTimeStart(LocalDateTime.of(2015, 11, 9, 10, 0))
.withRecurrenceRule(new RecurrenceRuleValue()
.withFrequency("DAILY")
.withInterval(3)
.withCount(6))
.withExceptionDates(new ExceptionDates(LocalDateTime.of(2015, 11, 12, 10, 0)
, LocalDateTime.of(2015, 11, 15, 10, 0)));
List<Temporal> madeDates = e
.streamRecurrences()
.collect(Collectors.toList());
List<LocalDateTime> expectedDates = new ArrayList<LocalDateTime>(Arrays.asList(
LocalDateTime.of(2015, 11, 9, 10, 0)
, LocalDateTime.of(2015, 11, 18, 10, 0)
, LocalDateTime.of(2015, 11, 21, 10, 0)
, LocalDateTime.of(2015, 11, 24, 10, 0)
));
assertEquals(expectedDates, madeDates);
String expectedContent = "EXDATE:20151112T100000,20151115T100000";
assertEquals(expectedContent, e.getExceptionDates().get(0).toString());
String expectedContent2 = "RRULE:FREQ=DAILY;INTERVAL=3;COUNT=6";
assertEquals(expectedContent2, e.getRecurrenceRule().toString());
}
@Test // 2 separate EXDATE properties, and out of order too
public void exceptionTest2()
{
VEvent e = new VEvent()
.withDateTimeStart(LocalDateTime.of(2015, 11, 9, 10, 0))
.withRecurrenceRule(new RecurrenceRuleValue()
.withFrequency("DAILY")
.withInterval(3)
.withCount(6))
.withExceptionDates(new ExceptionDates(LocalDateTime.of(2015, 11, 15, 10, 0)))
.withSequence(2)
.withExceptionDates(LocalDateTime.of(2015, 11, 12, 10, 0));
List<Temporal> madeDates = e
.streamRecurrences()
.collect(Collectors.toList());
List<LocalDateTime> expectedDates = new ArrayList<LocalDateTime>(Arrays.asList(
LocalDateTime.of(2015, 11, 9, 10, 0)
, LocalDateTime.of(2015, 11, 18, 10, 0)
, LocalDateTime.of(2015, 11, 21, 10, 0)
, LocalDateTime.of(2015, 11, 24, 10, 0)
));
assertEquals(expectedDates, madeDates);
String expectedContent = "EXDATE:20151115T100000";
assertEquals(expectedContent, e.getExceptionDates().get(0).toString());
String expectedContent2 = "EXDATE:20151112T100000";
assertEquals(expectedContent2, e.getExceptionDates().get(1).toString());
String expectedContent3 = "RRULE:FREQ=DAILY;INTERVAL=3;COUNT=6";
assertEquals(expectedContent3, e.getRecurrenceRule().toString());
}
// Google test
@Test
public void canStreamGoogleWithExDates()
{
VEvent e = new VEvent()
.withDateTimeStart(ZonedDateTime.of(LocalDateTime.of(2016, 2, 7, 12, 30), ZoneId.of("America/Los_Angeles")))
.withExceptionDates(new ExceptionDates(
ZonedDateTime.of(LocalDateTime.of(2016, 2, 10, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 12, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 9, 12, 30), ZoneId.of("America/Los_Angeles"))))
.withRecurrenceRule(new RecurrenceRuleValue()
.withFrequency(FrequencyType.DAILY)
.withUntil(ZonedDateTime.of(LocalDateTime.of(2016, 5, 12, 19, 30, 0), ZoneId.of("Z"))));
List<Temporal> madeDates = e
.streamRecurrences()
.limit(5)
.collect(Collectors.toList());
List<Temporal> expectedDates = new ArrayList<>(Arrays.asList(
ZonedDateTime.of(LocalDateTime.of(2016, 2, 7, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 8, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 11, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 13, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 14, 12, 30), ZoneId.of("America/Los_Angeles"))
));
assertEquals(expectedDates, madeDates);
}
@Test
public void canChangeGoogleWithExDatesToWholeDay()
{
VEvent e = new VEvent()
.withDateTimeStart(ZonedDateTime.of(LocalDateTime.of(2016, 2, 7, 12, 30), ZoneId.of("America/Los_Angeles")))
.withExceptionDates(new ExceptionDates(
ZonedDateTime.of(LocalDateTime.of(2016, 2, 10, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 12, 12, 30), ZoneId.of("America/Los_Angeles"))
, ZonedDateTime.of(LocalDateTime.of(2016, 2, 9, 12, 30), ZoneId.of("America/Los_Angeles"))))
.withRecurrenceRule(new RecurrenceRuleValue()
.withFrequency(FrequencyType.DAILY)
.withUntil(ZonedDateTime.of(LocalDateTime.of(2016, 5, 12, 19, 30, 0), ZoneId.of("Z"))));
e.setDateTimeCreated((DateTimeCreated) null);
e.setExceptionDates(null);
e.setDateTimeStart(new DateTimeStart(LocalDate.of(2016, 2, 7)));
e.setExceptionDates(Arrays.asList(new ExceptionDates(
LocalDate.of(2016, 2, 10)
, LocalDate.of(2016, 2, 12)
, LocalDate.of(2016, 2, 9)
)));
List<Temporal> madeDates = e
.streamRecurrences()
.limit(5)
.collect(Collectors.toList());
List<Temporal> expectedDates = new ArrayList<>(Arrays.asList(
LocalDate.of(2016, 2, 7)
, LocalDate.of(2016, 2, 8)
, LocalDate.of(2016, 2, 11)
, LocalDate.of(2016, 2, 13)
, LocalDate.of(2016, 2, 14)
));
assertEquals(expectedDates, madeDates);
}
@Test
public void canHandleDTStartTypeChange()
{
VEvent component = new VEvent()
.withDateTimeStart(LocalDate.of(1997, 3, 1))
.withExceptionDates("EXDATE;VALUE=DATE:19970304,19970504,19970704,19970904");
component.setDateTimeStart(DateTimeStart.parse(ZonedDateTime.class, "20160302T223316Z")); // invalid
String expectedError = "DTSTART, EXDATE: The value type of EXDATE elements MUST be the same as the DTSTART property (DTSTART=" +
DateTimeType.DATE_WITH_UTC_TIME + ", EXDATE=" + DateTimeType.DATE;
boolean isErrorPresent = component.errors().stream()
.anyMatch(s -> s.equals(expectedError));
assertTrue(isErrorPresent);
}
@Test
public void canCatchWrongDateType()
{
VEvent component = new VEvent()
.withDateTimeStart(LocalDate.of(1997, 3, 1));
List<ExceptionDates> exceptions = new ArrayList<>();
exceptions.add(ExceptionDates.parse("20160228T093000"));
component.setExceptionDates(exceptions); // invalid
String expectedError = "DTSTART, EXDATE: The value type of EXDATE elements MUST be the same as the DTSTART property (DTSTART=" +
DateTimeType.DATE + ", EXDATE=" + DateTimeType.DATE_WITH_LOCAL_TIME;
boolean isErrorPresent = component.errors()
.stream()
.anyMatch(s -> s.equals(expectedError));
assertTrue(isErrorPresent);
}
}