Skip to content

Commit 696dd26

Browse files
committed
feat: ensure tier ranges does not overlap
1 parent 2dfd5a1 commit 696dd26

File tree

6 files changed

+103
-1
lines changed

6 files changed

+103
-1
lines changed

exercises/tiered_pricing/solutions/adrianliz/java/src/main/java/tv/codely/checkout/SubscriptionTier.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package tv.codely.checkout;
22

3+
import java.util.Objects;
4+
35
public final class SubscriptionTier {
46

57
private final SubscriptionTierRange range;
@@ -21,6 +23,10 @@ public boolean isLast() {
2123
return range.isLast();
2224
}
2325

26+
public boolean isAfter(final SubscriptionTier other) {
27+
return range.isAfter(other.range);
28+
}
29+
2430
public boolean isInRange(int numberOfSubscriptions) {
2531
return this.range.isSuitableFor(numberOfSubscriptions);
2632
}
@@ -32,4 +38,21 @@ public double unitPrice() {
3238
public double getTotalPrice(int numberOfSubscriptions) {
3339
return unitPrice() * numberOfSubscriptions;
3440
}
41+
42+
@Override
43+
public boolean equals(Object o) {
44+
if (this == o) {
45+
return true;
46+
}
47+
if (o == null || getClass() != o.getClass()) {
48+
return false;
49+
}
50+
SubscriptionTier that = (SubscriptionTier) o;
51+
return Objects.equals(range, that.range) && Objects.equals(price, that.price);
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Objects.hash(range, price);
57+
}
3558
}

exercises/tiered_pricing/solutions/adrianliz/java/src/main/java/tv/codely/checkout/SubscriptionTierPrice.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package tv.codely.checkout;
22

3+
import java.util.Objects;
4+
35
public final class SubscriptionTierPrice {
46

57
private final double value;
@@ -11,4 +13,21 @@ public SubscriptionTierPrice(double value) {
1113
public double unitPrice() {
1214
return value;
1315
}
16+
17+
@Override
18+
public boolean equals(Object o) {
19+
if (this == o) {
20+
return true;
21+
}
22+
if (o == null || getClass() != o.getClass()) {
23+
return false;
24+
}
25+
SubscriptionTierPrice that = (SubscriptionTierPrice) o;
26+
return Double.compare(that.value, value) == 0;
27+
}
28+
29+
@Override
30+
public int hashCode() {
31+
return Objects.hash(value);
32+
}
1433
}

exercises/tiered_pricing/solutions/adrianliz/java/src/main/java/tv/codely/checkout/SubscriptionTierRange.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package tv.codely.checkout;
22

3+
import java.util.Objects;
4+
35
public final class SubscriptionTierRange {
46

57
private final int numberOfSubscriptionsFrom;
@@ -10,6 +12,10 @@ public SubscriptionTierRange(int numberOfSubscriptionsFrom, int numberOfSubscrip
1012
this.numberOfSubscriptionsTo = numberOfSubscriptionsTo;
1113
}
1214

15+
public static SubscriptionTierRange first(int numberOfSubscriptionsTo) {
16+
return new SubscriptionTierRange(1, numberOfSubscriptionsTo);
17+
}
18+
1319
public static SubscriptionTierRange last(int numberOfSubscriptionsFrom) {
1420
return new SubscriptionTierRange(numberOfSubscriptionsFrom, Integer.MAX_VALUE);
1521
}
@@ -22,8 +28,30 @@ public boolean isLast() {
2228
return numberOfSubscriptionsTo == Integer.MAX_VALUE;
2329
}
2430

31+
public boolean isAfter(final SubscriptionTierRange other) {
32+
return numberOfSubscriptionsFrom > other.numberOfSubscriptionsTo;
33+
}
34+
2535
public boolean isSuitableFor(int numberOfSubscriptions) {
2636
return numberOfSubscriptions >= numberOfSubscriptionsFrom
2737
&& numberOfSubscriptions <= numberOfSubscriptionsTo;
2838
}
39+
40+
@Override
41+
public boolean equals(Object o) {
42+
if (this == o) {
43+
return true;
44+
}
45+
if (o == null || getClass() != o.getClass()) {
46+
return false;
47+
}
48+
SubscriptionTierRange that = (SubscriptionTierRange) o;
49+
return numberOfSubscriptionsFrom == that.numberOfSubscriptionsFrom
50+
&& numberOfSubscriptionsTo == that.numberOfSubscriptionsTo;
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
return Objects.hash(numberOfSubscriptionsFrom, numberOfSubscriptionsTo);
56+
}
2957
}

exercises/tiered_pricing/solutions/adrianliz/java/src/main/java/tv/codely/checkout/SubscriptionTiers.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package tv.codely.checkout;
22

3+
import java.util.HashSet;
34
import java.util.List;
45

56
public final class SubscriptionTiers {
@@ -23,6 +24,20 @@ private static void validate(final List<SubscriptionTier> tiers) {
2324
if (tiers.stream().noneMatch(SubscriptionTier::isLast)) {
2425
throw new InvalidSubscriptionTiers("There must be a last subscription tier");
2526
}
27+
28+
if (tiers.size() == 1) {
29+
return;
30+
}
31+
32+
final var validTiers = new HashSet<SubscriptionTier>();
33+
for (final SubscriptionTier tier : tiers) {
34+
if (tiers.stream()
35+
.anyMatch(
36+
t -> !validTiers.contains(t) && !t.equals(tier) && !t.isAfter(tier))) {
37+
throw new InvalidSubscriptionTiers("All tiers must be after the previous one");
38+
}
39+
validTiers.add(tier);
40+
}
2641
}
2742

2843
private SubscriptionTier findSuitableTier(int subscriptions) {

exercises/tiered_pricing/solutions/adrianliz/java/src/test/java/tv/codely/checkout/TieredPricingShould.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class TieredPricingShould {
1717
private static List<SubscriptionTier> defaultSubscriptionTiers() {
1818
return List.of(
1919
new SubscriptionTier(
20-
new SubscriptionTierRange(1, 2),
20+
SubscriptionTierRange.first(2),
2121
new SubscriptionTierPrice(299)),
2222
new SubscriptionTier(
2323
new SubscriptionTierRange(3, 10),
@@ -130,4 +130,17 @@ void throw_invalid_subscription_tiers_if_there_is_no_last_tier() {
130130

131131
assertThrows(InvalidSubscriptionTiers.class, () -> new TieredPricing(subscriptionTiers));
132132
}
133+
134+
@Test
135+
void throw_invalid_subscription_tiers_if_tiers_are_not_in_order() {
136+
final var subscriptionTiers =
137+
List.of(SubscriptionTierMother.create(SubscriptionTierRangeMother.first(10),
138+
SubscriptionTierPriceMother.random()),
139+
SubscriptionTierMother.create(SubscriptionTierRangeMother.create(9, 20),
140+
SubscriptionTierPriceMother.random()),
141+
SubscriptionTierMother.create(SubscriptionTierRangeMother.last(2),
142+
SubscriptionTierPriceMother.random()));
143+
144+
assertThrows(InvalidSubscriptionTiers.class, () -> new TieredPricing(subscriptionTiers));
145+
}
133146
}

exercises/tiered_pricing/solutions/adrianliz/java/src/test/java/tv/codely/checkout/mother/SubscriptionTierRangeMother.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public static SubscriptionTierRange create(
1313
return new SubscriptionTierRange(numberOfSubscriptionsFrom, numberOfSubscriptionsTo);
1414
}
1515

16+
public static SubscriptionTierRange first(final int numberOfSubscriptionsTo) {
17+
return SubscriptionTierRange.first(numberOfSubscriptionsTo);
18+
}
19+
1620
public static SubscriptionTierRange last(final int numberOfSubscriptionsFrom) {
1721
return SubscriptionTierRange.last(numberOfSubscriptionsFrom);
1822
}

0 commit comments

Comments
 (0)