Skip to content

Commit 2dfd5a1

Browse files
committed
feat: ensure first and last tier range are valid
1 parent 68a1703 commit 2dfd5a1

File tree

6 files changed

+68
-40
lines changed

6 files changed

+68
-40
lines changed

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ public SubscriptionTier(
1313
this.price = price;
1414
}
1515

16+
public boolean isFirst() {
17+
return range.isFirst();
18+
}
19+
20+
public boolean isLast() {
21+
return range.isLast();
22+
}
23+
1624
public boolean isInRange(int numberOfSubscriptions) {
1725
return this.range.isSuitableFor(numberOfSubscriptions);
1826
}
@@ -24,8 +32,4 @@ public double unitPrice() {
2432
public double getTotalPrice(int numberOfSubscriptions) {
2533
return unitPrice() * numberOfSubscriptions;
2634
}
27-
28-
public boolean isLast() {
29-
return range.isLast();
30-
}
3135
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@ public static SubscriptionTierRange last(int numberOfSubscriptionsFrom) {
1414
return new SubscriptionTierRange(numberOfSubscriptionsFrom, Integer.MAX_VALUE);
1515
}
1616

17-
public boolean isSuitableFor(int numberOfSubscriptions) {
18-
return numberOfSubscriptions >= numberOfSubscriptionsFrom
19-
&& numberOfSubscriptions <= numberOfSubscriptionsTo;
17+
public boolean isFirst() {
18+
return numberOfSubscriptionsFrom == 1;
2019
}
2120

2221
public boolean isLast() {
2322
return numberOfSubscriptionsTo == Integer.MAX_VALUE;
2423
}
24+
25+
public boolean isSuitableFor(int numberOfSubscriptions) {
26+
return numberOfSubscriptions >= numberOfSubscriptionsFrom
27+
&& numberOfSubscriptions <= numberOfSubscriptionsTo;
28+
}
2529
}

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,28 @@ private static void validate(final List<SubscriptionTier> tiers) {
1616
throw new InvalidSubscriptionTiers("There must be at least one subscription tier");
1717
}
1818

19+
if (tiers.stream().noneMatch(SubscriptionTier::isFirst)) {
20+
throw new InvalidSubscriptionTiers("There must be a first subscription tier");
21+
}
22+
1923
if (tiers.stream().noneMatch(SubscriptionTier::isLast)) {
20-
throw new IllegalArgumentException("There must be a last subscription tier");
24+
throw new InvalidSubscriptionTiers("There must be a last subscription tier");
2125
}
2226
}
2327

24-
public List<SubscriptionTier> tiers() {
25-
return tiers;
28+
private SubscriptionTier findSuitableTier(int subscriptions) {
29+
return tiers.stream()
30+
.filter(tier -> tier.isInRange(subscriptions))
31+
.findFirst()
32+
.orElseThrow(() -> new InvalidSubscriptionTiers(
33+
"There is no subscription tier for " + subscriptions + " subscriptions"));
34+
}
35+
36+
public double getTotalPrice(int subscriptions) {
37+
return findSuitableTier(subscriptions).getTotalPrice(subscriptions);
38+
}
39+
40+
public double getBasePrice(int subscriptions) {
41+
return findSuitableTier(subscriptions).unitPrice();
2642
}
2743
}

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

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,22 @@
33
import java.util.List;
44

55
public class TieredPricing {
6-
7-
private final List<SubscriptionTier> subscriptionTiers;
6+
7+
private final SubscriptionTiers tiers;
88

99
public TieredPricing(final SubscriptionTiers subscriptionTiers) {
10-
this.subscriptionTiers = subscriptionTiers.tiers();
10+
this.tiers = subscriptionTiers;
1111
}
1212

1313
public TieredPricing(final List<SubscriptionTier> subscriptionTiers) {
1414
this(new SubscriptionTiers(subscriptionTiers));
1515
}
1616

1717
public double getTotalPrice(int subscriptions) {
18-
return subscriptionTiers.stream()
19-
.filter(subscriptionTier -> subscriptionTier.isInRange(subscriptions))
20-
.findFirst()
21-
.map(subscriptionTier -> subscriptionTier.getTotalPrice(subscriptions))
22-
.orElse(0D);
18+
return tiers.getTotalPrice(subscriptions);
2319
}
2420

2521
public double getBasePrice(int subscriptions) {
26-
return subscriptionTiers.stream()
27-
.filter(subscriptionTier -> subscriptionTier.isInRange(subscriptions))
28-
.findFirst()
29-
.map(SubscriptionTier::unitPrice)
30-
.orElse(0D);
22+
return tiers.getBasePrice(subscriptions);
3123
}
3224
}

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

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.junit.jupiter.api.Test;
1010
import tv.codely.checkout.mother.IntegerMother;
1111
import tv.codely.checkout.mother.SubscriptionTierMother;
12+
import tv.codely.checkout.mother.SubscriptionTierPriceMother;
13+
import tv.codely.checkout.mother.SubscriptionTierRangeMother;
1214

1315
public class TieredPricingShould {
1416

@@ -49,23 +51,6 @@ void return_total_price_based_on_number_of_subscriptions() {
4951
assertEquals(expectedPrice, totalPrice);
5052
}
5153

52-
@Test
53-
void should_throw_invalid_tiers_if_there_is_no_last_tier() {
54-
final var subscriptionTiers = SubscriptionTierMother.randoms();
55-
final var lastSubscriptionTier =
56-
subscriptionTiers.stream()
57-
.filter(SubscriptionTier::isLast)
58-
.findFirst()
59-
.orElse(null);
60-
61-
assertNotNull(lastSubscriptionTier);
62-
}
63-
64-
@Test
65-
void should_throw_invalid_tiers_if_there_is_no_tiers() {
66-
assertThrows(InvalidSubscriptionTiers.class, () -> new TieredPricing(List.of()));
67-
}
68-
6954
@Test
7055
void should_have_a_subscription_tier_range_with_no_upper_limit() {
7156
final var subscriptionTiers = SubscriptionTierMother.randoms();
@@ -122,4 +107,27 @@ void return_total_price_for_51_subscriptions() {
122107
final var totalPrice = tieredPricing.getTotalPrice(51);
123108
assertEquals(expectedPrice, totalPrice);
124109
}
110+
111+
@Test
112+
void throw_invalid_subscription_tiers_if_there_is_no_tiers() {
113+
assertThrows(InvalidSubscriptionTiers.class, () -> new TieredPricing(List.of()));
114+
}
115+
116+
@Test
117+
void throw_invalid_subscription_tiers_if_first_tier_range_does_not_start_at_1() {
118+
final var subscriptionTiers =
119+
List.of(SubscriptionTierMother.create(SubscriptionTierRangeMother.create(2, 10),
120+
SubscriptionTierPriceMother.random()));
121+
122+
assertThrows(InvalidSubscriptionTiers.class, () -> new TieredPricing(subscriptionTiers));
123+
}
124+
125+
@Test
126+
void throw_invalid_subscription_tiers_if_there_is_no_last_tier() {
127+
final var subscriptionTiers =
128+
List.of(SubscriptionTierMother.create(SubscriptionTierRangeMother.create(1, 10),
129+
SubscriptionTierPriceMother.random()));
130+
131+
assertThrows(InvalidSubscriptionTiers.class, () -> new TieredPricing(subscriptionTiers));
132+
}
125133
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ public final class SubscriptionTierPriceMother {
77
public static SubscriptionTierPrice create(final double value) {
88
return new SubscriptionTierPrice(value);
99
}
10+
11+
public static SubscriptionTierPrice random() {
12+
return create(DoubleMother.randomBetween(100, 300));
13+
}
1014
}

0 commit comments

Comments
 (0)