aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store/src
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-03-07 22:10:42 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-04-07 14:55:46 +0200
commit16a9b534adec2c53b50f92a43c1623918b1c59c0 (patch)
tree690b299a2ca31e302ddad219a7aa94bcf86d5d0b /subprojects/store/src
parentfix(frontend): * operator highlighting (diff)
downloadrefinery-16a9b534adec2c53b50f92a43c1623918b1c59c0.tar.gz
refinery-16a9b534adec2c53b50f92a43c1623918b1c59c0.tar.zst
refinery-16a9b534adec2c53b50f92a43c1623918b1c59c0.zip
refactor: move terms and DNF into logic subproject
Diffstat (limited to 'subprojects/store/src')
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java37
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java12
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java76
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java66
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityDomain.java68
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java28
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java51
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java71
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java83
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java106
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java66
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java38
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java32
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java61
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java128
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java28
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java20
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java28
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java18
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java30
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java117
21 files changed, 0 insertions, 1164 deletions
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java
deleted file mode 100644
index dfdb43bd..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation;
7
8import java.util.Objects;
9import java.util.Optional;
10
11public non-sealed interface AbstractDomain<A, C> extends AnyAbstractDomain {
12 @Override
13 Class<A> abstractType();
14
15 @Override
16 Class<C> concreteType();
17
18 A toAbstract(C concreteValue);
19
20 Optional<C> toConcrete(A abstractValue);
21
22 default boolean isConcrete(A abstractValue) {
23 return toConcrete(abstractValue).isPresent();
24 }
25
26 default boolean isRefinement(A originalValue, A refinedValue) {
27 return Objects.equals(commonRefinement(originalValue, refinedValue), refinedValue);
28 }
29
30 A commonRefinement(A leftValue, A rightValue);
31
32 A commonAncestor(A leftValue, A rightValue);
33
34 A unknown();
35
36 boolean isError(A abstractValue);
37}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java
deleted file mode 100644
index c354fab7..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java
+++ /dev/null
@@ -1,12 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation;
7
8public sealed interface AnyAbstractDomain permits AbstractDomain {
9 Class<?> abstractType();
10
11 Class<?> concreteType();
12}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
deleted file mode 100644
index f81ee9a4..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
+++ /dev/null
@@ -1,76 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation;
7
8public enum TruthValue {
9 TRUE("true"),
10
11 FALSE("false"),
12
13 UNKNOWN("unknown"),
14
15 ERROR("error");
16
17 private final String name;
18
19 TruthValue(String name) {
20 this.name = name;
21 }
22
23 public String getName() {
24 return name;
25 }
26
27 public static TruthValue toTruthValue(boolean value) {
28 return value ? TRUE : FALSE;
29 }
30
31 public boolean isConsistent() {
32 return this != ERROR;
33 }
34
35 public boolean isComplete() {
36 return this != UNKNOWN;
37 }
38
39 public boolean isConcrete() {
40 return this == TRUE || this == FALSE;
41 }
42
43 public boolean must() {
44 return this == TRUE || this == ERROR;
45 }
46
47 public boolean may() {
48 return this == TRUE || this == UNKNOWN;
49 }
50
51 public TruthValue not() {
52 return switch (this) {
53 case TRUE -> FALSE;
54 case FALSE -> TRUE;
55 default -> this;
56 };
57 }
58
59 public TruthValue merge(TruthValue other) {
60 return switch (this) {
61 case TRUE -> other == UNKNOWN || other == TRUE ? TRUE : ERROR;
62 case FALSE -> other == UNKNOWN || other == FALSE ? FALSE : ERROR;
63 case UNKNOWN -> other;
64 case ERROR -> ERROR;
65 };
66 }
67
68 public TruthValue join(TruthValue other) {
69 return switch (this) {
70 case TRUE -> other == ERROR || other == TRUE ? TRUE : UNKNOWN;
71 case FALSE -> other == ERROR || other == FALSE ? FALSE : UNKNOWN;
72 case UNKNOWN -> UNKNOWN;
73 case ERROR -> other;
74 };
75 }
76}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java
deleted file mode 100644
index 61696dca..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java
+++ /dev/null
@@ -1,66 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation;
7
8import java.util.Optional;
9
10// Singleton pattern, because there is only one domain for truth values.
11@SuppressWarnings("squid:S6548")
12public final class TruthValueDomain implements AbstractDomain<TruthValue, Boolean> {
13 public static final TruthValueDomain INSTANCE = new TruthValueDomain();
14
15 private TruthValueDomain() {
16 }
17
18 @Override
19 public Class<TruthValue> abstractType() {
20 return TruthValue.class;
21 }
22
23 @Override
24 public Class<Boolean> concreteType() {
25 return Boolean.class;
26 }
27
28 @Override
29 public TruthValue toAbstract(Boolean concreteValue) {
30 return TruthValue.toTruthValue(concreteValue);
31 }
32
33 @Override
34 public Optional<Boolean> toConcrete(TruthValue abstractValue) {
35 return switch (abstractValue) {
36 case TRUE -> Optional.of(true);
37 case FALSE -> Optional.of(false);
38 default -> Optional.empty();
39 };
40 }
41
42 @Override
43 public boolean isConcrete(TruthValue abstractValue) {
44 return abstractValue.isConcrete();
45 }
46
47 @Override
48 public TruthValue commonRefinement(TruthValue leftValue, TruthValue rightValue) {
49 return leftValue.merge(rightValue);
50 }
51
52 @Override
53 public TruthValue commonAncestor(TruthValue leftValue, TruthValue rightValue) {
54 return leftValue.join(rightValue);
55 }
56
57 @Override
58 public TruthValue unknown() {
59 return TruthValue.UNKNOWN;
60 }
61
62 @Override
63 public boolean isError(TruthValue abstractValue) {
64 return !abstractValue.isConsistent();
65 }
66}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityDomain.java
deleted file mode 100644
index 7ae2d935..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityDomain.java
+++ /dev/null
@@ -1,68 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import tools.refinery.store.representation.AbstractDomain;
9
10import java.util.Optional;
11
12// Singleton pattern, because there is only one domain for truth values.
13@SuppressWarnings("squid:S6548")
14public class CardinalityDomain implements AbstractDomain<CardinalityInterval, Integer> {
15 public static final CardinalityDomain INSTANCE = new CardinalityDomain();
16
17 private CardinalityDomain() {
18 }
19
20 @Override
21 public Class<CardinalityInterval> abstractType() {
22 return CardinalityInterval.class;
23 }
24
25 @Override
26 public Class<Integer> concreteType() {
27 return Integer.class;
28 }
29
30 @Override
31 public CardinalityInterval toAbstract(Integer concreteValue) {
32 return CardinalityIntervals.exactly(concreteValue);
33 }
34
35 @Override
36 public Optional<Integer> toConcrete(CardinalityInterval abstractValue) {
37 return isConcrete(abstractValue) ? Optional.of(abstractValue.lowerBound()) : Optional.empty();
38 }
39
40 @Override
41 public boolean isConcrete(CardinalityInterval abstractValue) {
42 if (!(abstractValue instanceof NonEmptyCardinalityInterval nonEmptyValue) ||
43 !((nonEmptyValue.upperBound()) instanceof FiniteUpperCardinality finiteUpperCardinality)) {
44 return false;
45 }
46 return nonEmptyValue.lowerBound() == finiteUpperCardinality.finiteUpperBound();
47 }
48
49 @Override
50 public CardinalityInterval commonRefinement(CardinalityInterval leftValue, CardinalityInterval rightValue) {
51 return leftValue.meet(rightValue);
52 }
53
54 @Override
55 public CardinalityInterval commonAncestor(CardinalityInterval leftValue, CardinalityInterval rightValue) {
56 return leftValue.join(rightValue);
57 }
58
59 @Override
60 public CardinalityInterval unknown() {
61 return CardinalityIntervals.SET;
62 }
63
64 @Override
65 public boolean isError(CardinalityInterval abstractValue) {
66 return abstractValue.isEmpty();
67 }
68}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
deleted file mode 100644
index b20c685a..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
+++ /dev/null
@@ -1,28 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval {
9 int lowerBound();
10
11 UpperCardinality upperBound();
12
13 boolean isEmpty();
14
15 CardinalityInterval min(CardinalityInterval other);
16
17 CardinalityInterval max(CardinalityInterval other);
18
19 CardinalityInterval add(CardinalityInterval other);
20
21 CardinalityInterval take(int count);
22
23 CardinalityInterval multiply(CardinalityInterval other);
24
25 CardinalityInterval meet(CardinalityInterval other);
26
27 CardinalityInterval join(CardinalityInterval other);
28}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
deleted file mode 100644
index 855fd248..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
+++ /dev/null
@@ -1,51 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8public final class CardinalityIntervals {
9 public static final CardinalityInterval NONE = exactly(0);
10
11 public static final CardinalityInterval ONE = exactly(1);
12
13 public static final CardinalityInterval LONE = atMost(1);
14
15 public static final CardinalityInterval SET = atLeast(0);
16
17 public static final CardinalityInterval SOME = atLeast(1);
18
19 public static final CardinalityInterval ERROR = EmptyCardinalityInterval.INSTANCE;
20
21 private CardinalityIntervals() {
22 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
23 }
24
25 public static CardinalityInterval between(int lowerBound, UpperCardinality upperBound) {
26 if (upperBound.compareToInt(lowerBound) < 0) {
27 return ERROR;
28 }
29 return new NonEmptyCardinalityInterval(lowerBound, upperBound);
30 }
31
32 public static CardinalityInterval between(int lowerBound, int upperBound) {
33 return between(lowerBound, UpperCardinalities.atMost(upperBound));
34 }
35
36 public static CardinalityInterval atMost(UpperCardinality upperBound) {
37 return new NonEmptyCardinalityInterval(0, upperBound);
38 }
39
40 public static CardinalityInterval atMost(int upperBound) {
41 return atMost(UpperCardinalities.atMost(upperBound));
42 }
43
44 public static CardinalityInterval atLeast(int lowerBound) {
45 return new NonEmptyCardinalityInterval(lowerBound, UpperCardinalities.UNBOUNDED);
46 }
47
48 public static CardinalityInterval exactly(int lowerBound) {
49 return new NonEmptyCardinalityInterval(lowerBound, UpperCardinalities.atMost(lowerBound));
50 }
51}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
deleted file mode 100644
index 9e371e21..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
+++ /dev/null
@@ -1,71 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8// Singleton implementation, because there is only a single empty interval.
9@SuppressWarnings("squid:S6548")
10public final class EmptyCardinalityInterval implements CardinalityInterval {
11 static final EmptyCardinalityInterval INSTANCE = new EmptyCardinalityInterval();
12
13 private EmptyCardinalityInterval() {
14 // Singleton constructor.
15 }
16
17 @Override
18 public int lowerBound() {
19 return 1;
20 }
21
22 @Override
23 public boolean isEmpty() {
24 return true;
25 }
26
27 @Override
28 public UpperCardinality upperBound() {
29 return UpperCardinalities.ZERO;
30 }
31
32 @Override
33 public CardinalityInterval min(CardinalityInterval other) {
34 return this;
35 }
36
37 @Override
38 public CardinalityInterval max(CardinalityInterval other) {
39 return this;
40 }
41
42 @Override
43 public CardinalityInterval add(CardinalityInterval other) {
44 return this;
45 }
46
47 @Override
48 public CardinalityInterval take(int count) {
49 return this;
50 }
51
52 @Override
53 public CardinalityInterval multiply(CardinalityInterval other) {
54 return this;
55 }
56
57 @Override
58 public CardinalityInterval meet(CardinalityInterval other) {
59 return this;
60 }
61
62 @Override
63 public CardinalityInterval join(CardinalityInterval other) {
64 return other;
65 }
66
67 @Override
68 public String toString() {
69 return "error";
70 }
71}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
deleted file mode 100644
index b63a8637..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
+++ /dev/null
@@ -1,83 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.jetbrains.annotations.NotNull;
9import org.jetbrains.annotations.Nullable;
10
11import java.util.function.IntBinaryOperator;
12
13public record FiniteUpperCardinality(int finiteUpperBound) implements UpperCardinality {
14 public FiniteUpperCardinality {
15 if (finiteUpperBound < 0) {
16 throw new IllegalArgumentException("finiteUpperBound must not be negative");
17 }
18 }
19
20 @Override
21 public UpperCardinality add(UpperCardinality other) {
22 return lift(other, Integer::sum);
23 }
24
25 @Override
26 @Nullable
27 public UpperCardinality take(int count) {
28 if (finiteUpperBound < count) {
29 return null;
30 }
31 return new FiniteUpperCardinality(finiteUpperBound - count);
32 }
33
34 @Override
35 public UpperCardinality multiply(UpperCardinality other) {
36 return lift(other, (a, b) -> a * b);
37 }
38
39 @Override
40 public int compareTo(@NotNull UpperCardinality upperCardinality) {
41 if (upperCardinality instanceof FiniteUpperCardinality finiteUpperCardinality) {
42 return compareToInt(finiteUpperCardinality.finiteUpperBound);
43 }
44 if (upperCardinality instanceof UnboundedUpperCardinality) {
45 return -1;
46 }
47 throw new IllegalArgumentException("Unknown UpperCardinality: " + upperCardinality);
48 }
49
50 @Override
51 public int compareToInt(int value) {
52 return Integer.compare(finiteUpperBound, value);
53 }
54
55 @Override
56 public String toString() {
57 return Integer.toString(finiteUpperBound);
58 }
59
60 private UpperCardinality lift(@NotNull UpperCardinality other, IntBinaryOperator operator) {
61 if (other instanceof FiniteUpperCardinality finiteUpperCardinality) {
62 return UpperCardinalities.atMost(operator.applyAsInt(finiteUpperBound,
63 finiteUpperCardinality.finiteUpperBound));
64 }
65 if (other instanceof UnboundedUpperCardinality) {
66 return UpperCardinalities.UNBOUNDED;
67 }
68 throw new IllegalArgumentException("Unknown UpperCardinality: " + other);
69 }
70
71 @Override
72 public boolean equals(Object o) {
73 if (this == o) return true;
74 if (o == null || getClass() != o.getClass()) return false;
75 FiniteUpperCardinality that = (FiniteUpperCardinality) o;
76 return finiteUpperBound == that.finiteUpperBound;
77 }
78
79 @Override
80 public int hashCode() {
81 return finiteUpperBound;
82 }
83}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
deleted file mode 100644
index 6bd66df7..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
+++ /dev/null
@@ -1,106 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import java.util.Objects;
9import java.util.function.BinaryOperator;
10import java.util.function.IntBinaryOperator;
11
12public record NonEmptyCardinalityInterval(int lowerBound, UpperCardinality upperBound) implements CardinalityInterval {
13 public NonEmptyCardinalityInterval {
14 if (lowerBound < 0) {
15 throw new IllegalArgumentException("lowerBound must not be negative");
16 }
17 if (upperBound.compareToInt(lowerBound) < 0) {
18 throw new IllegalArgumentException("lowerBound must not be larger than upperBound");
19 }
20 }
21
22 @Override
23 public boolean isEmpty() {
24 return false;
25 }
26
27 @Override
28 public CardinalityInterval min(CardinalityInterval other) {
29 return lift(other, Math::min, UpperCardinality::min);
30 }
31
32 @Override
33 public CardinalityInterval max(CardinalityInterval other) {
34 return lift(other, Math::max, UpperCardinality::max);
35 }
36
37 @Override
38 public CardinalityInterval add(CardinalityInterval other) {
39 return lift(other, Integer::sum, UpperCardinality::add);
40 }
41
42 @Override
43 public CardinalityInterval multiply(CardinalityInterval other) {
44 return lift(other, (a, b) -> a * b, UpperCardinality::multiply);
45 }
46
47 @Override
48 public CardinalityInterval meet(CardinalityInterval other) {
49 return lift(other, Math::max, UpperCardinality::min);
50 }
51
52 @Override
53 public CardinalityInterval join(CardinalityInterval other) {
54 return lift(other, Math::min, UpperCardinality::max, this);
55 }
56
57 @Override
58 public CardinalityInterval take(int count) {
59 int newLowerBound = Math.max(lowerBound - count, 0);
60 var newUpperBound = upperBound.take(count);
61 if (newUpperBound == null) {
62 return CardinalityIntervals.ERROR;
63 }
64 return CardinalityIntervals.between(newLowerBound, newUpperBound);
65 }
66
67 private CardinalityInterval lift(CardinalityInterval other, IntBinaryOperator lowerOperator,
68 BinaryOperator<UpperCardinality> upperOperator,
69 CardinalityInterval whenEmpty) {
70 if (other instanceof NonEmptyCardinalityInterval nonEmptyOther) {
71 return CardinalityIntervals.between(lowerOperator.applyAsInt(lowerBound, nonEmptyOther.lowerBound),
72 upperOperator.apply(upperBound, nonEmptyOther.upperBound));
73 }
74 if (other instanceof EmptyCardinalityInterval) {
75 return whenEmpty;
76 }
77 throw new IllegalArgumentException("Unknown CardinalityInterval: " + other);
78 }
79
80 private CardinalityInterval lift(CardinalityInterval other, IntBinaryOperator lowerOperator,
81 BinaryOperator<UpperCardinality> upperOperator) {
82 return lift(other, lowerOperator, upperOperator, CardinalityIntervals.ERROR);
83 }
84
85 @Override
86 public String toString() {
87 if (upperBound instanceof FiniteUpperCardinality finiteUpperCardinality &&
88 finiteUpperCardinality.finiteUpperBound() == lowerBound) {
89 return "[%d]".formatted(lowerBound);
90 }
91 return "[%d..%s]".formatted(lowerBound, upperBound);
92 }
93
94 @Override
95 public boolean equals(Object o) {
96 if (this == o) return true;
97 if (o == null || getClass() != o.getClass()) return false;
98 NonEmptyCardinalityInterval that = (NonEmptyCardinalityInterval) o;
99 return lowerBound == that.lowerBound && Objects.equals(upperBound, that.upperBound);
100 }
101
102 @Override
103 public int hashCode() {
104 return lowerBound * 31 + upperBound.hashCode();
105 }
106}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
deleted file mode 100644
index 03c701ae..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
+++ /dev/null
@@ -1,66 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.jetbrains.annotations.NotNull;
9
10// Singleton implementation, because there is only a single countable infinity.
11@SuppressWarnings("squid:S6548")
12public final class UnboundedUpperCardinality implements UpperCardinality {
13 static final UnboundedUpperCardinality INSTANCE = new UnboundedUpperCardinality();
14
15 private UnboundedUpperCardinality() {
16 // Singleton constructor.
17 }
18
19 @Override
20 public UpperCardinality add(UpperCardinality other) {
21 return this;
22 }
23
24 @Override
25 public UpperCardinality take(int count) {
26 return this;
27 }
28
29 @Override
30 public UpperCardinality multiply(UpperCardinality other) {
31 return this;
32 }
33
34 // This should always be greater than any finite cardinality.
35 @SuppressWarnings("ComparatorMethodParameterNotUsed")
36 @Override
37 public int compareTo(@NotNull UpperCardinality upperCardinality) {
38 if (upperCardinality instanceof FiniteUpperCardinality) {
39 return 1;
40 }
41 if (upperCardinality instanceof UnboundedUpperCardinality) {
42 return 0;
43 }
44 throw new IllegalArgumentException("Unknown UpperCardinality: " + upperCardinality);
45 }
46
47 @Override
48 public int compareToInt(int value) {
49 return 1;
50 }
51
52 @Override
53 public String toString() {
54 return "*";
55 }
56
57 @Override
58 public boolean equals(Object obj) {
59 return this == obj || (obj != null && getClass() == obj.getClass());
60 }
61
62 @Override
63 public int hashCode() {
64 return -1;
65 }
66}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
deleted file mode 100644
index 17d1b292..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
+++ /dev/null
@@ -1,38 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8public final class UpperCardinalities {
9 public static final UpperCardinality UNBOUNDED = UnboundedUpperCardinality.INSTANCE;
10
11 public static final UpperCardinality ZERO;
12
13 public static final UpperCardinality ONE;
14
15 private static final FiniteUpperCardinality[] cache = new FiniteUpperCardinality[256];
16
17 static {
18 for (int i = 0; i < cache.length; i++) {
19 cache[i] = new FiniteUpperCardinality(i);
20 }
21 ZERO = cache[0];
22 ONE = cache[1];
23 }
24
25 private UpperCardinalities() {
26 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
27 }
28
29 public static UpperCardinality atMost(int upperBound) {
30 if (upperBound < 0) {
31 return UNBOUNDED;
32 }
33 if (upperBound < cache.length) {
34 return cache[upperBound];
35 }
36 return new FiniteUpperCardinality(upperBound);
37 }
38}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
deleted file mode 100644
index 3f0db028..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
+++ /dev/null
@@ -1,32 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.jetbrains.annotations.Nullable;
9
10public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality,
11 UnboundedUpperCardinality {
12 default UpperCardinality min(UpperCardinality other) {
13 return this.compareTo(other) <= 0 ? this : other;
14 }
15
16 default UpperCardinality max(UpperCardinality other) {
17 return this.compareTo(other) >= 0 ? this : other;
18 }
19
20 UpperCardinality add(UpperCardinality other);
21
22 @Nullable
23 UpperCardinality take(int count);
24
25 UpperCardinality multiply(UpperCardinality other);
26
27 int compareToInt(int value);
28
29 static UpperCardinality of(int upperBound) {
30 return UpperCardinalities.atMost(upperBound);
31 }
32}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java
deleted file mode 100644
index 2e302663..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java
+++ /dev/null
@@ -1,61 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.util;
7
8import java.util.*;
9import java.util.function.Function;
10import java.util.stream.Collectors;
11
12public class CycleDetectingMapper<T, R> {
13 private static final String SEPARATOR = " -> ";
14
15 private final Function<T, String> getName;
16
17 private final Function<T, R> doMap;
18
19 private final Set<T> inProgress = new LinkedHashSet<>();
20
21 private final Map<T, R> results = new HashMap<>();
22
23 public CycleDetectingMapper(Function<T, R> doMap) {
24 this(Objects::toString, doMap);
25 }
26
27 public CycleDetectingMapper(Function<T, String> getName, Function<T, R> doMap) {
28 this.getName = getName;
29 this.doMap = doMap;
30 }
31
32 public R map(T input) {
33 if (inProgress.contains(input)) {
34 var path = inProgress.stream().map(getName).collect(Collectors.joining(SEPARATOR));
35 throw new IllegalArgumentException("Circular reference %s%s%s detected".formatted(path, SEPARATOR,
36 getName.apply(input)));
37 }
38 // We can't use computeIfAbsent here, because translating referenced queries calls this method in a reentrant
39 // way, which would cause a ConcurrentModificationException with computeIfAbsent.
40 @SuppressWarnings("squid:S3824")
41 var result = results.get(input);
42 if (result == null) {
43 inProgress.add(input);
44 try {
45 result = doMap.apply(input);
46 results.put(input, result);
47 } finally {
48 inProgress.remove(input);
49 }
50 }
51 return result;
52 }
53
54 public List<T> getInProgress() {
55 return List.copyOf(inProgress);
56 }
57
58 public R getAlreadyMapped(T input) {
59 return results.get(input);
60 }
61}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
deleted file mode 100644
index 6a66fa84..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.store.representation.cardinality.CardinalityInterval;
12
13import java.util.stream.Stream;
14
15import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.equalTo;
17import static tools.refinery.store.representation.cardinality.CardinalityIntervals.*;
18
19class CardinalityIntervalTest {
20 @ParameterizedTest(name = "min({0}, {1}) == {2}")
21 @MethodSource
22 void minTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
23 assertThat(a.min(b), equalTo(expected));
24 }
25
26 static Stream<Arguments> minTest() {
27 return Stream.of(
28 Arguments.of(atMost(1), atMost(1), atMost(1)),
29 Arguments.of(atMost(1), between(2, 3), atMost(1)),
30 Arguments.of(atMost(1), atLeast(2), atMost(1)),
31 Arguments.of(atMost(1), ERROR, ERROR),
32 Arguments.of(atLeast(1), atLeast(2), atLeast(1)),
33 Arguments.of(atLeast(1), ERROR, ERROR),
34 Arguments.of(ERROR, atLeast(2), ERROR),
35 Arguments.of(ERROR, ERROR, ERROR)
36 );
37 }
38
39 @ParameterizedTest(name = "max({0}, {1}) == {2}")
40 @MethodSource
41 void maxTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
42 assertThat(a.max(b), equalTo(expected));
43 }
44
45 static Stream<Arguments> maxTest() {
46 return Stream.of(
47 Arguments.of(atMost(1), atMost(1), atMost(1)),
48 Arguments.of(atMost(1), between(2, 3), between(2, 3)),
49 Arguments.of(atMost(1), atLeast(2), atLeast(2)),
50 Arguments.of(atMost(1), ERROR, ERROR),
51 Arguments.of(atLeast(1), atLeast(2), atLeast(2)),
52 Arguments.of(atLeast(1), ERROR, ERROR),
53 Arguments.of(ERROR, atLeast(2), ERROR),
54 Arguments.of(ERROR, ERROR, ERROR)
55 );
56 }
57
58 @ParameterizedTest(name = "{0} + {1} == {2}")
59 @MethodSource
60 void addTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
61 assertThat(a.add(b), equalTo(expected));
62 }
63
64 static Stream<Arguments> addTest() {
65 return Stream.of(
66 Arguments.of(atMost(1), atMost(1), atMost(2)),
67 Arguments.of(atMost(1), between(2, 3), between(2, 4)),
68 Arguments.of(atMost(1), atLeast(2), atLeast(2)),
69 Arguments.of(atMost(1), ERROR, ERROR),
70 Arguments.of(atLeast(1), atLeast(2), atLeast(3)),
71 Arguments.of(atLeast(1), ERROR, ERROR),
72 Arguments.of(ERROR, atLeast(2), ERROR),
73 Arguments.of(ERROR, ERROR, ERROR)
74 );
75 }
76
77 @ParameterizedTest(name = "{0} * {1} == {2}")
78 @MethodSource
79 void multiplyTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
80 assertThat(a.multiply(b), equalTo(expected));
81 }
82
83 static Stream<Arguments> multiplyTest() {
84 return Stream.of(
85 Arguments.of(between(2, 3), between(4, 5), between(8, 15)),
86 Arguments.of(atLeast(2), between(4, 5), atLeast(8)),
87 Arguments.of(between(2, 3), atLeast(4), atLeast(8)),
88 Arguments.of(between(2, 3), ERROR, ERROR),
89 Arguments.of(ERROR, between(4, 5), ERROR),
90 Arguments.of(ERROR, ERROR, ERROR)
91 );
92 }
93
94 @ParameterizedTest(name = "{0} /\\ {1} == {2}")
95 @MethodSource
96 void meetTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
97 assertThat(a.meet(b), equalTo(expected));
98 }
99
100 static Stream<Arguments> meetTest() {
101 return Stream.of(
102 Arguments.of(atMost(1), atMost(2), atMost(1)),
103 Arguments.of(atMost(2), between(1, 3), between(1, 2)),
104 Arguments.of(atMost(1), between(1, 3), exactly(1)),
105 Arguments.of(atMost(1), between(2, 3), ERROR),
106 Arguments.of(atMost(1), ERROR, ERROR),
107 Arguments.of(ERROR, atMost(1), ERROR),
108 Arguments.of(ERROR, ERROR, ERROR)
109 );
110 }
111
112 @ParameterizedTest(name = "{0} \\/ {1} == {2}")
113 @MethodSource
114 void joinTest(CardinalityInterval a, CardinalityInterval b, CardinalityInterval expected) {
115 assertThat(a.join(b), equalTo(expected));
116 }
117
118 static Stream<Arguments> joinTest() {
119 return Stream.of(
120 Arguments.of(atMost(1), atMost(2), atMost(2)),
121 Arguments.of(atMost(2), between(1, 3), atMost(3)),
122 Arguments.of(atMost(1), between(2, 3), atMost(3)),
123 Arguments.of(atMost(1), ERROR, atMost(1)),
124 Arguments.of(ERROR, atMost(1), atMost(1)),
125 Arguments.of(ERROR, ERROR, ERROR)
126 );
127 }
128}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
deleted file mode 100644
index 9fe76159..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.representation.cardinality.CardinalityIntervals;
10import tools.refinery.store.representation.cardinality.UpperCardinalities;
11
12import static org.hamcrest.MatcherAssert.assertThat;
13import static org.hamcrest.Matchers.*;
14
15class CardinalityIntervalsTest {
16 @Test
17 void betweenEmptyTest() {
18 var interval = CardinalityIntervals.between(2, 1);
19 assertThat(interval.isEmpty(), equalTo(true));
20 }
21
22 @Test
23 void betweenNegativeUpperBoundTest() {
24 var interval = CardinalityIntervals.between(0, -1);
25 assertThat(interval.upperBound(), equalTo(UpperCardinalities.UNBOUNDED));
26 assertThat(interval.isEmpty(), equalTo(false));
27 }
28}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
deleted file mode 100644
index 24a788a8..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
+++ /dev/null
@@ -1,20 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.representation.cardinality.CardinalityIntervals;
10
11import static org.hamcrest.MatcherAssert.assertThat;
12import static org.hamcrest.Matchers.lessThan;
13
14class EmptyCardinalityIntervalTest {
15 @Test
16 void inconsistentBoundsTest() {
17 assertThat(CardinalityIntervals.ERROR.upperBound().compareToInt(CardinalityIntervals.ERROR.lowerBound()),
18 lessThan(0));
19 }
20}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
deleted file mode 100644
index 6cf56fae..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.representation.cardinality.NonEmptyCardinalityInterval;
10import tools.refinery.store.representation.cardinality.UpperCardinalities;
11import tools.refinery.store.representation.cardinality.UpperCardinality;
12
13import static org.junit.jupiter.api.Assertions.assertThrows;
14
15class FiniteCardinalityIntervalTest {
16 @Test
17 void invalidLowerBoundConstructorTest() {
18 assertThrows(IllegalArgumentException.class, () -> new NonEmptyCardinalityInterval(-1,
19 UpperCardinalities.UNBOUNDED));
20 }
21
22 @Test
23 void invalidUpperBoundConstructorTest() {
24 var upperCardinality = UpperCardinality.of(1);
25 assertThrows(IllegalArgumentException.class, () -> new NonEmptyCardinalityInterval(2,
26 upperCardinality));
27 }
28}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
deleted file mode 100644
index 7c641c47..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
+++ /dev/null
@@ -1,18 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
10
11import static org.junit.jupiter.api.Assertions.assertThrows;
12
13class FiniteUpperCardinalityTest {
14 @Test
15 void invalidConstructorTest() {
16 assertThrows(IllegalArgumentException.class, () -> new FiniteUpperCardinality(-1));
17 }
18}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
deleted file mode 100644
index e403eec2..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.junit.jupiter.api.Test;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.ValueSource;
11
12import static org.hamcrest.MatcherAssert.assertThat;
13import static org.hamcrest.Matchers.equalTo;
14import static org.hamcrest.Matchers.instanceOf;
15
16class UpperCardinalitiesTest {
17 @ParameterizedTest
18 @ValueSource(ints = {0, 1, 255, 256, 1000, Integer.MAX_VALUE})
19 void valueOfBoundedTest(int value) {
20 var upperCardinality = UpperCardinalities.atMost(value);
21 assertThat(upperCardinality, instanceOf(FiniteUpperCardinality.class));
22 assertThat(((FiniteUpperCardinality) upperCardinality).finiteUpperBound(), equalTo(value));
23 }
24
25 @Test
26 void valueOfUnboundedTest() {
27 var upperCardinality = UpperCardinalities.atMost(-1);
28 assertThat(upperCardinality, instanceOf(UnboundedUpperCardinality.class));
29 }
30}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
deleted file mode 100644
index 10b4dd20..00000000
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.representation.cardinality;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.store.representation.cardinality.UpperCardinalities;
12import tools.refinery.store.representation.cardinality.UpperCardinality;
13
14import java.util.stream.Stream;
15
16import static org.hamcrest.MatcherAssert.assertThat;
17import static org.hamcrest.Matchers.equalTo;
18
19class UpperCardinalityTest {
20 @ParameterizedTest(name = "min({0}, {1}) == {2}")
21 @MethodSource
22 void minTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
23 assertThat(a.min(b), equalTo(expected));
24 }
25
26 static Stream<Arguments> minTest() {
27 return Stream.of(
28 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
29 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(0)),
30 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(0)),
31 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinality.of(0)),
32 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinality.of(0)),
33 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
34 );
35 }
36
37 @ParameterizedTest(name = "max({0}, {1}) == {2}")
38 @MethodSource
39 void maxTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
40 assertThat(a.max(b), equalTo(expected));
41 }
42
43 static Stream<Arguments> maxTest() {
44 return Stream.of(
45 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
46 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(1)),
47 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(1)),
48 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
49 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinalities.UNBOUNDED),
50 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
51 );
52 }
53
54 @ParameterizedTest(name = "{0} + {1} == {2}")
55 @MethodSource
56 void addTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
57 assertThat(a.add(b), equalTo(expected));
58 }
59
60 static Stream<Arguments> addTest() {
61 return Stream.of(
62 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(5)),
63 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
64 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
65 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
66 );
67 }
68
69 @ParameterizedTest(name = "{0} * {1} == {2}")
70 @MethodSource
71 void multiplyTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
72 assertThat(a.multiply(b), equalTo(expected));
73 }
74
75 static Stream<Arguments> multiplyTest() {
76 return Stream.of(
77 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(6)),
78 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
79 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
80 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED)
81 );
82 }
83
84 @ParameterizedTest(name = "{0}.compareTo({1}) == {2}")
85 @MethodSource
86 void compareToTest(UpperCardinality a, UpperCardinality b, int expected) {
87 assertThat(a.compareTo(b), equalTo(expected));
88 }
89
90 static Stream<Arguments> compareToTest() {
91 return Stream.of(
92 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), 0),
93 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), -1),
94 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), 1),
95 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, -1),
96 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), 1),
97 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, 0)
98 );
99 }
100
101 @ParameterizedTest(name = "{0}.compareToInt({1}) == {2}")
102 @MethodSource
103 void compareToIntTest(UpperCardinality a, int b, int expected) {
104 assertThat(a.compareToInt(b), equalTo(expected));
105 }
106
107 static Stream<Arguments> compareToIntTest() {
108 return Stream.of(
109 Arguments.of(UpperCardinality.of(3), -1, 1),
110 Arguments.of(UpperCardinality.of(3), 2, 1),
111 Arguments.of(UpperCardinality.of(3), 3, 0),
112 Arguments.of(UpperCardinality.of(3), 4, -1),
113 Arguments.of(UpperCardinalities.UNBOUNDED, -1, 1),
114 Arguments.of(UpperCardinalities.UNBOUNDED, 3, 1)
115 );
116 }
117}