Kiki is setting up a delivery service that will accept orders via a command line application.
Accept packages and calculate the delivery cost allowing 1 coupon per package to be applied that will give a discount to the cost of the package.
(Base + (Package total weight * $10) + (Distance to Destination * $5)) * (1 - discount)
Kiki has given coupons to people for her new delivery service.
These are the current valid coupons:
| Code | Discount | Distance (km) | Weight (kg) |
|---|---|---|---|
| OFR001 | 10% | 0km-200km | 70kg-200kg |
| OFR002 | 7% | 50km-150km | 70kg-200kg |
| OFR003 | 5% | 50km-250km | 10kg-150kg |
- Base price:
- In $ only (No cents allowed)
- Greater than 0
- Max Value: Kotlin's max integer value
- Due to the above, the total after discount applied will always have a maximum decimal to 2 places (In cents, e.g. :$XXX.XX)
- This will be enforced when reading from the command line
- Weight:
- In KGs only (grams are not allowed)
- Greater than 0
- Max Value: Kotlin's max integer value
- This will be enforced when reading from the command line
- Distance:
- In KMs only (meters are not allowed)
- Greater than 0
- Max Value: Kotlin's max integer value
- This will be enforced when reading from the command line
- Discount:
- Set by Tombo so assumed it will never be greater than 100 (My boundary)
- This won't be enforced through the code
- Coupon codes:
- Set by Tombo so assumed that they will always have a valid name
- Will be in uppercase when stored
- Can work for multiple packages in the same order
- They don't have an expiry or a start date
- Coupon code naming standard won't be enforced through the code
- Packages
- There will always be at least 1 package
- There is no limit to the number of package that can be delivered (except the memory limit of where the computer is running but I don't believe that will be exceeded)
- The package name will be limited to a single word
1st line of input: base_delivery_cost no_of_packages
2nd line of input: package_id package_weight distance offer_code?
3rd line of input: package_id package_weight distance offer_code?
...
Continue adding packages until you are finished and hit enter
The output will be a list of packages entered, with this format:
packages_id discount_percent total_cost
User Input:
- 100 3
- PKG1 5 5 OFR001
- PKG2 15 5 OFR002
- PKG3 10 100 OFR003
Output:
- PKG1 0 175
- PKG2 0 275
- PKG 35 665
- id (Not needed but good practice to have it)
- code
- discount
- distanceCriteria: IntRange
- weightCriteria: IntRange
- start date (Versus an is active flag in case she mis-printed coupon criteria - I removed this as I can add this functionality later as it is not needed now)
- expiry date (Versus an is active flag in case she mis-printed coupon criteria - I removed this as I can add this functionality later as it is not needed now)
- id (Not needed but good practice to have it)
- name
- weight
- distance
- couponCode
- id
- name
- discountPercent
- price: BigDecimal
I'm writing a list of things I would like to test for, looking for boundary cases and any other test that would help me to ensure correctness.
| Code | Discount | Distance (km) | Weight (kg) |
|---|---|---|---|
| STATIC | 0.1 | 2km-2km | 2kg-2kg |
| 1%OFF | 0.01 | 1km-10km | 1kg-10kg |
| HALF-OFF | 0.5 | 1km-10km | 1kg-10kg |
| 100-OFF | 1.0 | 1km-10km | 1kg-10kg |
- Delivery with 1 package and no coupon code
- Input:
- 100 1
- PKG1 1 1
- Output:
- PKG1 0 115
- Input:
- Delivery with 1 package and a coupon code that doesn't exist
- Input:
- 100 1
- PKG1 1 1 NO-COUPON
- Output:
- PKG1 0 115
- Input:
- Delivery with 1 package and a coupon code that exists but is not valid due to weight and distance
- Input:
- 100 1
- PKG1 1 1 STATIC
- Output:
- PKG1 0 115
- Input:
- Delivery with 1 package and a coupon code that exists but is not valid due to the weight being lighter than allowed
- Input:
- 100 1
- PKG1 1 2 STATIC
- Output:
- PKG1 0 120
- Input:
- Delivery with 1 package and a coupon code that exists but is not valid due to the weight being heavier than allowed
- Input:
- 100 1
- PKG1 3 2 STATIC
- Output:
- PKG1 0 140
- Input:
- Delivery with 1 package and a coupon code that exists and is not valid due to the distance being longer than allowed
- Input:
- 100 1
- PKG1 2 1 STATIC
- Output:
- PKG1 0 125
- Input:
- Delivery with 1 package and a coupon code that exists and is not valid due to the distance being shorter than allowed
- Input:
- 100 1
- PKG1 2 3 STATIC
- Output:
- PKG1 0 135
- Input:
- Delivery with 1 package and a coupon code that exists and is valid
- Input:
- 1 1
- PKG1 2 2 STATIC
- Output:
- PKG1 10 27.9
- Input:
- Delivery with 1 package and 1% off coupon code
- Input:
- 1 1
- PKG1 1 1 1%OFF
- Output:
- PKG1 1 15.84
- Input:
- Delivery with 1 package and 50% off coupon code
- Input:
- 1 1
- PKG1 1 1 HALF-OFF
- Output:
- PKG1 50 8
- Input:
- Delivery with 1 package and 100% off coupon code
- Input:
- 1 1
- PKG1 1 1 100-OFF
- Output:
- PKG1 100 0
- Input:
- Delivery with multiple packages and using the same coupon code
3. Input:
- 1 2
- PKG1 2 2 STATIC
- PKG2 2 2 STATIC
- Output:
- PKG1 10 27.9
- PKG2 10 27.9
- Delivery with multiple packages and using different coupon codes
- Input:
- 1 2
- PKG1 2 2 NO-COUPON
- PKG2 2 2 STATIC 4PKG2 2 2 HALF-OFF
- Output:
- PKG1 0 31
- PKG2 10 27.9
- PKG2 10 15.5
- Input:
I feel the above will give me confidence in my test coverage for boundaries. I will start from the simplest which I think is the 1st.
I will test the delivery calculation first via tests. I'll manually test user input afterwards as this is harder to test.
- The cost of $5 and $10 for the base weight and base distance should be moved to an environment variable in the future.
- The display, validation and outputStream could be separated further but I think the logic to get the user input is good enough.
- I've left package and coupon to have an id as it is good practice from them to have some difference from packages of the same name and coupons with the same name.
- I would ideally like to add an expiry date and start date for coupons but the current requirements don't need it.
- I removed the white space test as it was complicated to get via user input (I'd have to do some regular expressions which I didn't want to do for this application right now)