From de3baf0a0fe0eeb38bf83c728d3850138d430b02 Mon Sep 17 00:00:00 2001 From: Marten Gajda Date: Fri, 16 Feb 2024 23:58:22 +0100 Subject: [PATCH] Add support for determining whether a set is infinite --- build.gradle | 1 + gradle/libs.versions.toml | 29 +++ lib-recur-confidence/build.gradle | 25 ++ .../quality/EmptyRecurrenceSet.java | 41 +++ .../rfc5545/confidence/quality/Finite.java | 34 +++ .../rfc5545/confidence/quality/Infinite.java | 33 +++ .../confidence/quality/StartsWith.java | 36 +++ .../quality/EmptyRecurrenceSetTest.java | 43 ++++ settings.gradle | 1 + .../java/org/dmfs/rfc5545/RecurrenceSet.java | 7 + .../rfc5545/recurrenceset/FastForwarded.java | 6 + .../dmfs/rfc5545/recurrenceset/FromList.java | 6 + .../dmfs/rfc5545/recurrenceset/FromRule.java | 7 + .../recurrenceset/FromRuleIncludingStart.java | 9 +- .../dmfs/rfc5545/recurrenceset/FromRules.java | 7 + .../org/dmfs/rfc5545/recurrenceset/Last.java | 53 ++++ .../dmfs/rfc5545/recurrenceset/Merged.java | 25 +- .../rfc5545/recurrenceset/WithExceptions.java | 7 + .../{ => iterable}/ParsedDatesTest.java | 6 +- .../recurrenceset/FastForwardedTest.java | 137 +++++----- .../rfc5545/recurrenceset/FromListTest.java | 29 ++- .../rfc5545/recurrenceset/FromRuleTest.java | 47 +++- .../rfc5545/recurrenceset/MergedTest.java | 240 ++++++++++++++---- .../recurrenceset/WithExceptionsTest.java | 115 ++++++--- 24 files changed, 770 insertions(+), 174 deletions(-) create mode 100644 gradle/libs.versions.toml create mode 100644 lib-recur-confidence/build.gradle create mode 100644 lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSet.java create mode 100644 lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Finite.java create mode 100644 lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Infinite.java create mode 100644 lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/StartsWith.java create mode 100644 lib-recur-confidence/src/test/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSetTest.java create mode 100644 src/main/java/org/dmfs/rfc5545/recurrenceset/Last.java rename src/test/java/org/dmfs/rfc5545/{ => iterable}/ParsedDatesTest.java (92%) diff --git a/build.gradle b/build.gradle index 5e3eab8..84b160d 100644 --- a/build.gradle +++ b/build.gradle @@ -77,6 +77,7 @@ dependencies { api 'org.dmfs:rfc5545-datetime:0.3' implementation 'org.dmfs:jems2:2.22.0' testImplementation project("lib-recur-hamcrest") + testImplementation project("lib-recur-confidence") testImplementation 'org.dmfs:jems2-testing:2.22.0' testImplementation 'org.saynotobugs:confidence-core:0.42.0' } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..f1eefad --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,29 @@ +[versions] +eclipse-jdt = "2.2.600" +hamcrest = "2.2" +jems2 = "2.22.0" +junit = "5.8.2" +junit-testkit = "1.9.2" +srcless = "0.3.0" +confidence = "0.42.0" + +[libraries] +srcless-annotations = { module = "org.dmfs:srcless-annotations", version.ref = "srcless" } +srcless-processors = { module = "org.dmfs:srcless-processors", version.ref = "srcless" } +eclipse-jdt-anntation = { module = 'org.eclipse.jdt:org.eclipse.jdt.annotation', version.ref = "eclipse-jdt" } +nullless-processors = { module = "org.dmfs:nullless-processors", version.ref = "srcless" } + +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } +junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } + +jems2 = { module = "org.dmfs:jems2", version.ref = "jems2" } +jems2-testing = { module = "org.dmfs:jems2-testing", version.ref = "jems2" } +jems2-confidence = { module = "org.dmfs:jems2-confidence", version.ref = "jems2" } + +confidence-core = { module = "org.saynotobugs:confidence-core", version.ref = "confidence" } +confidence-test = { module = "org.saynotobugs:confidence-test", version.ref = "confidence" } + +[bundles] +srcless-processors = ["srcless-processors", "nullless-processors"] + +[plugins] diff --git a/lib-recur-confidence/build.gradle b/lib-recur-confidence/build.gradle new file mode 100644 index 0000000..790a966 --- /dev/null +++ b/lib-recur-confidence/build.gradle @@ -0,0 +1,25 @@ +plugins { + id 'java-library' +} + +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 + +dependencies { + compileOnly libs.eclipse.jdt.anntation + compileOnly libs.srcless.annotations + annotationProcessor libs.bundles.srcless.processors + api libs.confidence.core + implementation libs.jems2 + implementation libs.jems2.confidence + api rootProject + + testImplementation libs.confidence.test + testImplementation libs.jems2.testing + testImplementation libs.junit.jupiter.api + testRuntimeOnly libs.junit.jupiter.engine +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSet.java b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSet.java new file mode 100644 index 0000000..50c509a --- /dev/null +++ b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSet.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Marten Gajda + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.rfc5545.confidence.quality; + +import org.dmfs.jems2.confidence.optional.Absent; +import org.dmfs.rfc5545.RecurrenceSet; +import org.dmfs.srcless.annotations.staticfactory.StaticFactories; +import org.saynotobugs.confidence.description.Text; +import org.saynotobugs.confidence.quality.composite.AllOf; +import org.saynotobugs.confidence.quality.composite.Has; +import org.saynotobugs.confidence.quality.composite.Not; +import org.saynotobugs.confidence.quality.composite.QualityComposition; +import org.saynotobugs.confidence.quality.iterable.EmptyIterable; +import org.saynotobugs.confidence.quality.object.Satisfies; + +@StaticFactories(value = "Recur", packageName = "org.dmfs.rfc5545.confidence") +public final class EmptyRecurrenceSet extends QualityComposition +{ + public EmptyRecurrenceSet() + { + super(new AllOf<>( + new EmptyIterable(), + new Not<>(new Satisfies<>(RecurrenceSet::isInfinite, new Text("is infinite"))) + )); + } +} diff --git a/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Finite.java b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Finite.java new file mode 100644 index 0000000..ae24a60 --- /dev/null +++ b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Finite.java @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Marten Gajda + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.rfc5545.confidence.quality; + +import org.dmfs.jems2.predicate.Not; +import org.dmfs.rfc5545.RecurrenceSet; +import org.dmfs.srcless.annotations.staticfactory.StaticFactories; +import org.saynotobugs.confidence.description.Text; +import org.saynotobugs.confidence.quality.composite.QualityComposition; +import org.saynotobugs.confidence.quality.object.Satisfies; + +@StaticFactories(value = "Recur", packageName = "org.dmfs.rfc5545.confidence") +public final class Finite extends QualityComposition +{ + public Finite() + { + super(new Satisfies<>(new Not<>(RecurrenceSet::isInfinite), new Text("finite"))); + } +} diff --git a/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Infinite.java b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Infinite.java new file mode 100644 index 0000000..ef7ae19 --- /dev/null +++ b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/Infinite.java @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Marten Gajda + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.rfc5545.confidence.quality; + +import org.dmfs.rfc5545.RecurrenceSet; +import org.dmfs.srcless.annotations.staticfactory.StaticFactories; +import org.saynotobugs.confidence.description.Text; +import org.saynotobugs.confidence.quality.composite.QualityComposition; +import org.saynotobugs.confidence.quality.object.Satisfies; + +@StaticFactories(value = "Recur", packageName = "org.dmfs.rfc5545.confidence") +public final class Infinite extends QualityComposition +{ + public Infinite() + { + super(new Satisfies<>(RecurrenceSet::isInfinite, new Text("infinite"))); + } +} diff --git a/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/StartsWith.java b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/StartsWith.java new file mode 100644 index 0000000..5b64f64 --- /dev/null +++ b/lib-recur-confidence/src/main/java/org/dmfs/rfc5545/confidence/quality/StartsWith.java @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Marten Gajda + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.rfc5545.confidence.quality; + +import org.dmfs.jems2.iterable.First; +import org.dmfs.rfc5545.DateTime; +import org.dmfs.rfc5545.RecurrenceSet; +import org.dmfs.srcless.annotations.staticfactory.StaticFactories; +import org.saynotobugs.confidence.quality.composite.Has; +import org.saynotobugs.confidence.quality.composite.QualityComposition; +import org.saynotobugs.confidence.quality.iterable.Iterates; + +@StaticFactories(value = "Recur", packageName = "org.dmfs.rfc5545.confidence") +public final class StartsWith extends QualityComposition +{ + public StartsWith(DateTime... instances) + { + super(new Has<>("first " + instances.length + " instances", + candidate -> new First<>(instances.length, candidate), new Iterates<>(instances))); + } +} diff --git a/lib-recur-confidence/src/test/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSetTest.java b/lib-recur-confidence/src/test/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSetTest.java new file mode 100644 index 0000000..6c9f124 --- /dev/null +++ b/lib-recur-confidence/src/test/java/org/dmfs/rfc5545/confidence/quality/EmptyRecurrenceSetTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Marten Gajda + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.rfc5545.confidence.quality; + +import org.dmfs.rfc5545.RecurrenceSet; +import org.dmfs.rfc5545.instanceiterator.EmptyIterator; +import org.junit.jupiter.api.Test; + +import static org.dmfs.jems2.mockito.Mock.*; +import static org.saynotobugs.confidence.Assertion.assertThat; +import static org.saynotobugs.confidence.quality.Core.allOf; + +class EmptyRecurrenceSetTest +{ + @Test + void test() + { + assertThat(new EmptyRecurrenceSet(), + allOf( + org.saynotobugs.confidence.test.quality.Test.passes(mock(RecurrenceSet.class, + with(RecurrenceSet::isInfinite, returning(false)), + with(RecurrenceSet::iterator, returning(new EmptyIterator())))), + org.saynotobugs.confidence.test.quality.Test.fails(mock(RecurrenceSet.class, + with(RecurrenceSet::isInfinite, returning(true)), + with(RecurrenceSet::iterator, returning(new EmptyIterator())))))); + } + +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 9f61e52..b744f16 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ rootProject.name = 'lib-recur' +include 'lib-recur-confidence' include 'lib-recur-hamcrest' include 'benchmark' diff --git a/src/main/java/org/dmfs/rfc5545/RecurrenceSet.java b/src/main/java/org/dmfs/rfc5545/RecurrenceSet.java index c6c5e18..f5bcad0 100644 --- a/src/main/java/org/dmfs/rfc5545/RecurrenceSet.java +++ b/src/main/java/org/dmfs/rfc5545/RecurrenceSet.java @@ -18,6 +18,8 @@ package org.dmfs.rfc5545; +import org.dmfs.jems2.Optional; + /** * A set of instances. */ @@ -27,4 +29,9 @@ public interface RecurrenceSet extends Iterable * Returns an {@link InstanceIterator} for this {@link RecurrenceSet}. */ InstanceIterator iterator(); + + /** + * Returns whether this {@link RecurrenceSet} is infinite or not. + */ + boolean isInfinite(); } \ No newline at end of file diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/FastForwarded.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/FastForwarded.java index 539d114..f26a6f8 100644 --- a/src/main/java/org/dmfs/rfc5545/recurrenceset/FastForwarded.java +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/FastForwarded.java @@ -57,4 +57,10 @@ public InstanceIterator iterator() iterator.fastForward(mTimeStamp); return iterator; } + + @Override + public boolean isInfinite() + { + return mDelegate.isInfinite(); + } } diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromList.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromList.java index 0804477..f608aae 100644 --- a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromList.java +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromList.java @@ -87,4 +87,10 @@ public InstanceIterator iterator() ? new FastForwardable(delegate.next(), delegate.hasNext() ? delegate : EmptyIterator.INSTANCE) : EmptyIterator.INSTANCE; } + + @Override + public boolean isInfinite() + { + return false; + } } diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRule.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRule.java index 1b03683..ab5000c 100644 --- a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRule.java +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRule.java @@ -41,4 +41,11 @@ public InstanceIterator iterator() { return mRecurrenceRule.iterator(mFirstInstance); } + + @Override + public boolean isInfinite() + { + return mRecurrenceRule.isInfinite(); + } + } diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRuleIncludingStart.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRuleIncludingStart.java index 72a2557..2a4601a 100644 --- a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRuleIncludingStart.java +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRuleIncludingStart.java @@ -20,8 +20,8 @@ import org.dmfs.rfc5545.DateTime; import org.dmfs.rfc5545.InstanceIterator; import org.dmfs.rfc5545.RecurrenceSet; -import org.dmfs.rfc5545.instanceiterator.Merged; import org.dmfs.rfc5545.instanceiterator.CountLimitedRecurrenceRuleIterator; +import org.dmfs.rfc5545.instanceiterator.Merged; import org.dmfs.rfc5545.recur.RecurrenceRule; import org.dmfs.rfc5545.recur.RecurrenceRuleIterator; @@ -61,4 +61,11 @@ public InstanceIterator iterator() } return ruleIterator; } + + @Override + public boolean isInfinite() + { + return mRecurrenceRule.isInfinite(); + } + } diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRules.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRules.java index 93ba139..26cf015 100644 --- a/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRules.java +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/FromRules.java @@ -56,4 +56,11 @@ public InstanceIterator iterator() { return mDelegate.iterator(); } + + @Override + public boolean isInfinite() + { + return mDelegate.isInfinite(); + } + } diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/Last.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/Last.java new file mode 100644 index 0000000..81fca1e --- /dev/null +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/Last.java @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Marten Gajda + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dmfs.rfc5545.recurrenceset; + +import org.dmfs.jems2.Optional; + +import java.util.Iterator; + +/** + * An {@link Optional} of the last element of a given {@link Iterable}. + */ +final class Last implements Optional +{ + private final Iterable mIterable; + + Last(Iterable iterable) + { + mIterable = iterable; + } + + @Override + public boolean isPresent() + { + return mIterable.iterator().hasNext(); + } + + @Override + public T value() + { + Iterator iterator = mIterable.iterator(); + T result = iterator.next(); + while (iterator.hasNext()) + { + result = iterator.next(); + } + return result; + } +} diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/Merged.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/Merged.java index f9bed32..f5f7523 100644 --- a/src/main/java/org/dmfs/rfc5545/recurrenceset/Merged.java +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/Merged.java @@ -19,6 +19,7 @@ import org.dmfs.jems2.iterable.Mapped; import org.dmfs.jems2.iterable.Seq; +import org.dmfs.jems2.iterable.Sieved; import org.dmfs.rfc5545.InstanceIterator; import org.dmfs.rfc5545.RecurrenceSet; @@ -40,7 +41,22 @@ public Merged(RecurrenceSet... delegates) public Merged(Iterable delegates) { - this(() -> new org.dmfs.rfc5545.instanceiterator.Merged(new Mapped<>(RecurrenceSet::iterator, delegates))); + this( + new RecurrenceSet() + { + @Override + public InstanceIterator iterator() + { + return new org.dmfs.rfc5545.instanceiterator.Merged(new Mapped<>(RecurrenceSet::iterator, delegates)); + } + + @Override + public boolean isInfinite() + { + return new Sieved<>(RecurrenceSet::isInfinite, delegates).iterator().hasNext(); + } + + }); } @@ -55,4 +71,11 @@ public InstanceIterator iterator() { return mDelegate.iterator(); } + + @Override + public boolean isInfinite() + { + return mDelegate.isInfinite(); + } + } diff --git a/src/main/java/org/dmfs/rfc5545/recurrenceset/WithExceptions.java b/src/main/java/org/dmfs/rfc5545/recurrenceset/WithExceptions.java index 0298430..f89a4fb 100644 --- a/src/main/java/org/dmfs/rfc5545/recurrenceset/WithExceptions.java +++ b/src/main/java/org/dmfs/rfc5545/recurrenceset/WithExceptions.java @@ -41,4 +41,11 @@ public InstanceIterator iterator() { return new EffectiveInstancesIterator(mInstances.iterator(), mExceptions.iterator()); } + + @Override + public boolean isInfinite() + { + return mInstances.isInfinite(); + } + } diff --git a/src/test/java/org/dmfs/rfc5545/ParsedDatesTest.java b/src/test/java/org/dmfs/rfc5545/iterable/ParsedDatesTest.java similarity index 92% rename from src/test/java/org/dmfs/rfc5545/ParsedDatesTest.java rename to src/test/java/org/dmfs/rfc5545/iterable/ParsedDatesTest.java index 1a2c2fa..a05549c 100644 --- a/src/test/java/org/dmfs/rfc5545/ParsedDatesTest.java +++ b/src/test/java/org/dmfs/rfc5545/iterable/ParsedDatesTest.java @@ -15,10 +15,12 @@ * limitations under the License. */ -package org.dmfs.rfc5545; +package org.dmfs.rfc5545.iterable; +import org.dmfs.rfc5545.DateTime; import org.dmfs.rfc5545.iterable.ParsedDates; import org.junit.jupiter.api.Test; +import org.saynotobugs.confidence.quality.Core; import static java.util.TimeZone.getTimeZone; import static org.saynotobugs.confidence.Assertion.assertThat; @@ -35,7 +37,7 @@ void testEmpty() @Test void testSingletonDate() { - assertThat(new ParsedDates("20240216"), iterates(DateTime.parse("20240216"))); + assertThat(new ParsedDates("20240216"), Core.iterates(DateTime.parse("20240216"))); } @Test diff --git a/src/test/java/org/dmfs/rfc5545/recurrenceset/FastForwardedTest.java b/src/test/java/org/dmfs/rfc5545/recurrenceset/FastForwardedTest.java index cbc59b8..f46c7ed 100644 --- a/src/test/java/org/dmfs/rfc5545/recurrenceset/FastForwardedTest.java +++ b/src/test/java/org/dmfs/rfc5545/recurrenceset/FastForwardedTest.java @@ -17,26 +17,48 @@ package org.dmfs.rfc5545.recurrenceset; -import org.dmfs.jems2.iterable.First; +import org.dmfs.jems2.iterable.EmptyIterable; import org.dmfs.rfc5545.DateTime; import org.dmfs.rfc5545.Duration; import org.dmfs.rfc5545.recur.InvalidRecurrenceRuleException; import org.dmfs.rfc5545.recur.RecurrenceRule; import org.junit.jupiter.api.Test; +import static org.dmfs.rfc5545.confidence.Recur.*; import static org.saynotobugs.confidence.Assertion.assertThat; -import static org.saynotobugs.confidence.quality.Core.iterates; +import static org.saynotobugs.confidence.quality.Core.*; class FastForwardedTest { @Test - void test() throws InvalidRecurrenceRuleException + void testFastForwardEmptySet() { - assertThat(new FastForwarded(DateTime.parse("20240218"), + assertThat( + new FastForwarded(DateTime.parse("20240225"), + new FromList(new EmptyIterable<>())), + is(emptyRecurrenceSet())); + } + + @Test + void testFastForwardBeyondLastInstance() throws InvalidRecurrenceRuleException + { + assertThat( + new FastForwarded(DateTime.parse("20240225"), new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215"))), - iterates( - DateTime.parse("20240218"), - DateTime.parse("20240219"))); + is(emptyRecurrenceSet())); + } + + @Test + void testSimpleCase() throws InvalidRecurrenceRuleException + { + assertThat( + new FastForwarded(DateTime.parse("20240218"), + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215"))), + allOf( + is(finite()), + iterates( + DateTime.parse("20240218"), + DateTime.parse("20240219")))); } @@ -49,24 +71,23 @@ void test_github_issue_61() throws InvalidRecurrenceRuleException { DateTime start = new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0); assertThat( - new First<>(8, - new FastForwarded( - new DateTime(DateTime.UTC, 2019, 1, 1, 22, 0, 0), - new Merged( - new FromRule(new RecurrenceRule("FREQ=HOURLY;INTERVAL=5"), start), - new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start) - ))), - iterates( - new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 1, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 6, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 11, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 16, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 21, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 3, 2, 0, 0) - ) - ); + new FastForwarded( + new DateTime(DateTime.UTC, 2019, 1, 1, 22, 0, 0), + new Merged( + new FromRule(new RecurrenceRule("FREQ=HOURLY;INTERVAL=5"), start), + new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start) + )), + allOf( + is(infinite()), + startsWith( + new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 1, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 6, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 11, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 16, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 21, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 3, 2, 0, 0)))); } /** @@ -76,19 +97,17 @@ void test_github_issue_61() throws InvalidRecurrenceRuleException void test_github_issue_85() throws InvalidRecurrenceRuleException { DateTime start = new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0); - assertThat( - new First<>(5, - new FastForwarded(start, - new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start))), - iterates( - new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 4, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 5, 0, 0, 0) - ) - ); + new FastForwarded(start, + new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start)), + allOf( + is(infinite()), + startsWith( + new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 4, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 5, 0, 0, 0)))); } @@ -96,19 +115,17 @@ void test_github_issue_85() throws InvalidRecurrenceRuleException void test_fast_forward_into_past() throws InvalidRecurrenceRuleException { DateTime start = new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0); - assertThat( - new First<>(5, - new FastForwarded(start.addDuration(new Duration(-1, 10)), - new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start))), - iterates( - new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 4, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 5, 0, 0, 0) - ) - ); + new FastForwarded(start.addDuration(new Duration(-1, 10)), + new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start)), + allOf( + is(infinite()), + startsWith( + new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 4, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 5, 0, 0, 0)))); } @@ -116,18 +133,16 @@ void test_fast_forward_into_past() throws InvalidRecurrenceRuleException void test_fast_forward_skipping_1st_instance() throws InvalidRecurrenceRuleException { DateTime start = new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0); - assertThat( - new First<>(5, - new FastForwarded(start.addDuration(new Duration(1, 0, 1)), - new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start))), - iterates( - new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 4, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 5, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 6, 0, 0, 0) - ) - ); + new FastForwarded(start.addDuration(new Duration(1, 0, 1)), + new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start)), + allOf( + is(infinite()), + startsWith( + new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 4, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 5, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 6, 0, 0, 0)))); } } \ No newline at end of file diff --git a/src/test/java/org/dmfs/rfc5545/recurrenceset/FromListTest.java b/src/test/java/org/dmfs/rfc5545/recurrenceset/FromListTest.java index a75fc0f..ebea83b 100644 --- a/src/test/java/org/dmfs/rfc5545/recurrenceset/FromListTest.java +++ b/src/test/java/org/dmfs/rfc5545/recurrenceset/FromListTest.java @@ -21,6 +21,8 @@ import org.junit.jupiter.api.Test; import static java.util.TimeZone.getTimeZone; +import static org.dmfs.rfc5545.confidence.Recur.emptyRecurrenceSet; +import static org.dmfs.rfc5545.confidence.Recur.finite; import static org.saynotobugs.confidence.Assertion.assertThat; import static org.saynotobugs.confidence.quality.Core.*; @@ -29,14 +31,17 @@ class FromListTest @Test void testEmptyList() { - assertThat(new FromList(new DateTime[0]), is(emptyIterable())); + assertThat(new FromList(new DateTime[0]), + is(emptyRecurrenceSet())); } @Test void testSingletonList() { assertThat(new FromList(DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501")), - iterates(DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501"))); + allOf( + is(finite()), + iterates(DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501")))); } @Test @@ -46,10 +51,12 @@ void testOrderedList() DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501"), DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T162501"), DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T182501")), - iterates( - DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501"), - DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T162501"), - DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T182501"))); + allOf( + is(finite()), + iterates( + DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501"), + DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T162501"), + DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T182501")))); } @Test @@ -59,9 +66,11 @@ void testUnorderedList() DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T162501"), DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501"), DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T182501")), - iterates( - DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501"), - DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T162501"), - DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T182501"))); + allOf( + is(finite()), + iterates( + DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T142501"), + DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T162501"), + DateTime.parse(getTimeZone("Europe/Berlin"), "20240216T182501")))); } } \ No newline at end of file diff --git a/src/test/java/org/dmfs/rfc5545/recurrenceset/FromRuleTest.java b/src/test/java/org/dmfs/rfc5545/recurrenceset/FromRuleTest.java index df33543..47e267c 100644 --- a/src/test/java/org/dmfs/rfc5545/recurrenceset/FromRuleTest.java +++ b/src/test/java/org/dmfs/rfc5545/recurrenceset/FromRuleTest.java @@ -22,21 +22,52 @@ import org.dmfs.rfc5545.recur.RecurrenceRule; import org.junit.jupiter.api.Test; +import static org.dmfs.rfc5545.confidence.Recur.*; import static org.saynotobugs.confidence.Assertion.assertThat; -import static org.saynotobugs.confidence.quality.Core.iterates; +import static org.saynotobugs.confidence.quality.Core.*; class FromRuleTest { @Test - void test() throws InvalidRecurrenceRuleException + void testRuleWithCount() throws InvalidRecurrenceRuleException { assertThat(new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215")), - iterates( - DateTime.parse("20240215"), - DateTime.parse("20240216"), - DateTime.parse("20240217"), - DateTime.parse("20240218"), - DateTime.parse("20240219"))); + allOf( + is(finite()), + iterates( + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219")))); } + @Test + void testRuleWithUntil() throws InvalidRecurrenceRuleException + { + assertThat(new FromRule(new RecurrenceRule("FREQ=DAILY;UNTIL=20240219"), DateTime.parse("20240215")), + allOf( + is(finite()), + iterates( + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219")))); + } + + + @Test + void testInfiniteRule() throws InvalidRecurrenceRuleException + { + assertThat(new FromRule(new RecurrenceRule("FREQ=DAILY"), DateTime.parse("20240215")), + allOf( + is(infinite()), + startsWith( + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219")))); + } } \ No newline at end of file diff --git a/src/test/java/org/dmfs/rfc5545/recurrenceset/MergedTest.java b/src/test/java/org/dmfs/rfc5545/recurrenceset/MergedTest.java index 0b8d05e..86802e1 100644 --- a/src/test/java/org/dmfs/rfc5545/recurrenceset/MergedTest.java +++ b/src/test/java/org/dmfs/rfc5545/recurrenceset/MergedTest.java @@ -17,65 +17,203 @@ package org.dmfs.rfc5545.recurrenceset; -import org.dmfs.jems2.iterable.First; +import org.dmfs.jems2.iterable.EmptyIterable; import org.dmfs.rfc5545.DateTime; import org.dmfs.rfc5545.recur.InvalidRecurrenceRuleException; import org.dmfs.rfc5545.recur.RecurrenceRule; import org.junit.jupiter.api.Test; +import static org.dmfs.rfc5545.confidence.Recur.*; import static org.saynotobugs.confidence.Assertion.assertThat; -import static org.saynotobugs.confidence.quality.Core.iterates; +import static org.saynotobugs.confidence.quality.Core.*; class MergedTest { @Test - void testSingle() throws InvalidRecurrenceRuleException + void testMergeSingleEmpty() + { + assertThat(new Merged( + new FromList(new EmptyIterable<>())), + is(emptyRecurrenceSet())); + } + + @Test + void testMergeMultipleEmpty() + { + assertThat(new Merged( + new FromList(new EmptyIterable<>()), + new FromList(new EmptyIterable<>())), + is(emptyRecurrenceSet())); + } + + @Test + void testMergeSingleFinite() throws InvalidRecurrenceRuleException { assertThat(new Merged( new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215"))), - iterates( - DateTime.parse("20240215"), - DateTime.parse("20240216"), - DateTime.parse("20240217"), - DateTime.parse("20240218"), - DateTime.parse("20240219"))); + allOf( + is(finite()), + iterates( + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219")))); + } + + + @Test + void testMergeSingleFiniteWithEmpty() throws InvalidRecurrenceRuleException + { + assertThat(new Merged( + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215")), + new FromList(new EmptyIterable<>())), + allOf( + is(finite()), + iterates( + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219")))); } + @Test + void testMergeEmptyWithSingleFinite() throws InvalidRecurrenceRuleException + { + assertThat(new Merged( + new FromList(new EmptyIterable<>()), + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215"))), + allOf( + is(finite()), + iterates( + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219")))); + } @Test - void testTwoDelegates() throws InvalidRecurrenceRuleException + void testSingleInfinite() throws InvalidRecurrenceRuleException + { + assertThat(new Merged( + new FromRule(new RecurrenceRule("FREQ=DAILY"), DateTime.parse("20240215"))), + allOf( + is(infinite()), + startsWith( + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219")))); + } + + + @Test + void testTwoFiniteDelegates() throws InvalidRecurrenceRuleException { assertThat(new Merged( new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215T180000")), new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215T120000"))), - iterates( - DateTime.parse("20240215T120000"), - DateTime.parse("20240215T180000"), - DateTime.parse("20240216T120000"), - DateTime.parse("20240216T180000"), - DateTime.parse("20240217T120000"), - DateTime.parse("20240217T180000"), - DateTime.parse("20240218T120000"), - DateTime.parse("20240218T180000"), - DateTime.parse("20240219T120000"), - DateTime.parse("20240219T180000"))); + allOf( + is(finite()), + iterates( + DateTime.parse("20240215T120000"), + DateTime.parse("20240215T180000"), + DateTime.parse("20240216T120000"), + DateTime.parse("20240216T180000"), + DateTime.parse("20240217T120000"), + DateTime.parse("20240217T180000"), + DateTime.parse("20240218T120000"), + DateTime.parse("20240218T180000"), + DateTime.parse("20240219T120000"), + DateTime.parse("20240219T180000")))); + } + + + @Test + void testOneFiniteAndOneInfiniteDelegates() throws InvalidRecurrenceRuleException + { + assertThat(new Merged( + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215T180000")), + new FromRule(new RecurrenceRule("FREQ=DAILY"), DateTime.parse("20240215T120000"))), + allOf( + is(infinite()), + startsWith( + DateTime.parse("20240215T120000"), + DateTime.parse("20240215T180000"), + DateTime.parse("20240216T120000"), + DateTime.parse("20240216T180000"), + DateTime.parse("20240217T120000"), + DateTime.parse("20240217T180000"), + DateTime.parse("20240218T120000"), + DateTime.parse("20240218T180000"), + DateTime.parse("20240219T120000"), + DateTime.parse("20240219T180000")))); + } + + + @Test + void testOneInfiniteAndOneFiniteDelegates() throws InvalidRecurrenceRuleException + { + assertThat(new Merged( + new FromRule(new RecurrenceRule("FREQ=DAILY"), DateTime.parse("20240215T180000")), + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215T120000"))), + allOf( + is(infinite()), + startsWith( + DateTime.parse("20240215T120000"), + DateTime.parse("20240215T180000"), + DateTime.parse("20240216T120000"), + DateTime.parse("20240216T180000"), + DateTime.parse("20240217T120000"), + DateTime.parse("20240217T180000"), + DateTime.parse("20240218T120000"), + DateTime.parse("20240218T180000"), + DateTime.parse("20240219T120000"), + DateTime.parse("20240219T180000")))); + } + + + @Test + void testTwoInfiniteDelegates() throws InvalidRecurrenceRuleException + { + assertThat(new Merged( + new FromRule(new RecurrenceRule("FREQ=DAILY"), DateTime.parse("20240215T180000")), + new FromRule(new RecurrenceRule("FREQ=DAILY"), DateTime.parse("20240215T120000"))), + allOf( + is(infinite()), + startsWith( + DateTime.parse("20240215T120000"), + DateTime.parse("20240215T180000"), + DateTime.parse("20240216T120000"), + DateTime.parse("20240216T180000"), + DateTime.parse("20240217T120000"), + DateTime.parse("20240217T180000"), + DateTime.parse("20240218T120000"), + DateTime.parse("20240218T180000"), + DateTime.parse("20240219T120000"), + DateTime.parse("20240219T180000")))); } @Test - void testMultiple() throws InvalidRecurrenceRuleException + void testMultipleFinite() throws InvalidRecurrenceRuleException { assertThat(new Merged( new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240216")), new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240214")), new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240215"))), - iterates( - DateTime.parse("20240214"), - DateTime.parse("20240215"), - DateTime.parse("20240216"), - DateTime.parse("20240217"), - DateTime.parse("20240218"), - DateTime.parse("20240219"), - DateTime.parse("20240220"))); + allOf( + is(finite()), + iterates( + DateTime.parse("20240214"), + DateTime.parse("20240215"), + DateTime.parse("20240216"), + DateTime.parse("20240217"), + DateTime.parse("20240218"), + DateTime.parse("20240219"), + DateTime.parse("20240220")))); } /** @@ -85,25 +223,27 @@ void testMultiple() throws InvalidRecurrenceRuleException void test_github_issue_61() throws InvalidRecurrenceRuleException { DateTime start = new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0); - assertThat(new First<>(13, // limit for the test - new Merged( - new FromRule(new RecurrenceRule("FREQ=HOURLY;INTERVAL=5"), start), - new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start) - )), - iterates( - new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 1, 5, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 1, 10, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 1, 15, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 1, 20, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 1, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 6, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 11, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 16, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 2, 21, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), - new DateTime(DateTime.UTC, 2019, 1, 3, 2, 0, 0) - )); + assertThat( + new Merged( + new FromRule(new RecurrenceRule("FREQ=HOURLY;INTERVAL=5"), start), + new FromRule(new RecurrenceRule("FREQ=DAILY;INTERVAL=1"), start) + ), + allOf( + is(infinite()), + startsWith( + new DateTime(DateTime.UTC, 2019, 1, 1, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 1, 5, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 1, 10, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 1, 15, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 1, 20, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 1, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 6, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 11, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 16, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 2, 21, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 3, 0, 0, 0), + new DateTime(DateTime.UTC, 2019, 1, 3, 2, 0, 0) + ))); } } \ No newline at end of file diff --git a/src/test/java/org/dmfs/rfc5545/recurrenceset/WithExceptionsTest.java b/src/test/java/org/dmfs/rfc5545/recurrenceset/WithExceptionsTest.java index 7feebac..5719166 100644 --- a/src/test/java/org/dmfs/rfc5545/recurrenceset/WithExceptionsTest.java +++ b/src/test/java/org/dmfs/rfc5545/recurrenceset/WithExceptionsTest.java @@ -17,30 +17,62 @@ package org.dmfs.rfc5545.recurrenceset; -import org.dmfs.jems2.iterable.First; +import org.dmfs.jems2.iterable.EmptyIterable; import org.dmfs.rfc5545.DateTime; import org.dmfs.rfc5545.recur.InvalidRecurrenceRuleException; import org.dmfs.rfc5545.recur.RecurrenceRule; import org.junit.jupiter.api.Test; +import static org.dmfs.rfc5545.confidence.Recur.*; import static org.saynotobugs.confidence.Assertion.assertThat; -import static org.saynotobugs.confidence.quality.Core.iterates; +import static org.saynotobugs.confidence.quality.Core.*; class WithExceptionsTest { @Test - void test() throws InvalidRecurrenceRuleException + void testEmptyInstancesAndExceptions() + { + assertThat(new WithExceptions( + new FromList(new EmptyIterable<>()), + new FromList(new EmptyIterable<>()) + ), + is(emptyRecurrenceSet())); + } + + @Test + void testEmptyInstancesAndNonEmptyExceptions() throws InvalidRecurrenceRuleException + { + assertThat(new WithExceptions( + new FromList(new EmptyIterable<>()), + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240224T120000"))), + is(emptyRecurrenceSet())); + } + + @Test + void testInstancesEqualExceptions() throws InvalidRecurrenceRuleException + { + assertThat(new WithExceptions( + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240224T120000")), + new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240224T120000"))), + is(emptyRecurrenceSet())); + } + + + @Test + void testInstancesAndExceptions() throws InvalidRecurrenceRuleException { assertThat(new WithExceptions( new FromRule(new RecurrenceRule("FREQ=HOURLY;INTERVAL=12;COUNT=10"), DateTime.parse("20240224T120000")), new FromRule(new RecurrenceRule("FREQ=DAILY;COUNT=5"), DateTime.parse("20240224T000000"))), - iterates( - DateTime.parse("20240224T120000"), - DateTime.parse("20240225T120000"), - DateTime.parse("20240226T120000"), - DateTime.parse("20240227T120000"), - DateTime.parse("20240228T120000"), - DateTime.parse("20240229T000000"))); + allOf( + is(finite()), + iterates( + DateTime.parse("20240224T120000"), + DateTime.parse("20240225T120000"), + DateTime.parse("20240226T120000"), + DateTime.parse("20240227T120000"), + DateTime.parse("20240228T120000"), + DateTime.parse("20240229T000000")))); } @@ -54,9 +86,11 @@ void test_github_issue_93() throws InvalidRecurrenceRuleException new WithExceptions( new FromRule(new RecurrenceRule("FREQ=WEEKLY;UNTIL=20200511T000000Z;BYDAY=TU"), DateTime.parse("20200414T160000Z")), new FromList(DateTime.parse("20200421T160000Z"), DateTime.parse("20200505T160000Z"))), - iterates( - DateTime.parse("20200414T160000Z"), - DateTime.parse("20200428T160000Z"))); + allOf( + is(finite()), + iterates( + DateTime.parse("20200414T160000Z"), + DateTime.parse("20200428T160000Z")))); } @@ -66,35 +100,34 @@ void test_multiple_rules_with_same_values_and_count() throws InvalidRecurrenceRu DateTime start = new DateTime(2019, 1, 1); assertThat( - new First<>(13, - new WithExceptions( - new Merged( - new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=MO,TU,WE"), start), - new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=WE,TH,FR;COUNT=10"), start), - new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=WE,FR,SA;COUNT=5"), start) - ), - new Merged( - new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=MO,TH;UNTIL=20190212"), start), - new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=MO;COUNT=4"), start), - new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=TH,FR"), start) - ) + new WithExceptions( + new Merged( + new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=MO,TU,WE"), start), + new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=WE,TH,FR;COUNT=10"), start), + new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=WE,FR,SA;COUNT=5"), start) + ), + new Merged( + new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=MO,TH;UNTIL=20190212"), start), + new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=MO;COUNT=4"), start), + new FromRule(new RecurrenceRule("FREQ=DAILY;BYDAY=TH,FR"), start) ) ), - iterates( - new DateTime(2019, 1, 2), // SA - new DateTime(2019, 1, 5), // TU - new DateTime(2019, 1, 6), // WE - new DateTime(2019, 1, 9), // SA - new DateTime(2019, 1, 12), // TU - new DateTime(2019, 1, 13), // WE - new DateTime(2019, 1, 19), // TU - new DateTime(2019, 1, 20), // WE - new DateTime(2019, 1, 26), // TU - new DateTime(2019, 1, 27), // WE - new DateTime(2019, 2, 4), // MO - new DateTime(2019, 2, 5), // TU - new DateTime(2019, 2, 6) // WE - ) - ); + allOf( + is(infinite()), + startsWith( + new DateTime(2019, 1, 2), // SA + new DateTime(2019, 1, 5), // TU + new DateTime(2019, 1, 6), // WE + new DateTime(2019, 1, 9), // SA + new DateTime(2019, 1, 12), // TU + new DateTime(2019, 1, 13), // WE + new DateTime(2019, 1, 19), // TU + new DateTime(2019, 1, 20), // WE + new DateTime(2019, 1, 26), // TU + new DateTime(2019, 1, 27), // WE + new DateTime(2019, 2, 4), // MO + new DateTime(2019, 2, 5), // TU + new DateTime(2019, 2, 6) // WE + ))); } } \ No newline at end of file