-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDeliveryEstimationServiceTests.cs
More file actions
179 lines (154 loc) · 6.92 KB
/
Copy pathDeliveryEstimationServiceTests.cs
File metadata and controls
179 lines (154 loc) · 6.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
using FluentAssertions;
using ParcelTracking.Application.DTOs.EstimatedDelivery;
using ParcelTracking.Application.Services;
using ParcelTracking.Domain.Entities;
using ParcelTracking.Domain.Enums;
using System;
using Xunit;
namespace ParcelTracking.Application.Tests
{
public class DeliveryEstimationServiceTests
{
private readonly DeliveryEstimationService _service;
public DeliveryEstimationServiceTests()
{
_service = new DeliveryEstimationService();
}
[Theory]
[InlineData(ServiceType.Economy, false, 5, 7)]
[InlineData(ServiceType.Standard, false, 3, 5)]
[InlineData(ServiceType.Express, false, 1, 2)]
[InlineData(ServiceType.Overnight, false, 1, 1)]
[InlineData(ServiceType.Economy, true, 8, 12)]
[InlineData(ServiceType.Standard, true, 6, 10)]
[InlineData(ServiceType.Express, true, 4, 7)]
[InlineData(ServiceType.Overnight, true, 4, 6)]
public void Calculate_ReturnsCorrectTransitTimes(ServiceType serviceType, bool isInternational, int expectedMin, int expectedMax)
{
// Arrange
var createdAt = new DateTimeOffset(2023, 1, 1, 10, 0, 0, TimeSpan.Zero); // Monday
var parcel = new Parcel
{
Id = Guid.NewGuid(),
CreatedAt = createdAt,
ServiceType = serviceType,
Status = ParcelStatus.LabelCreated,
ShipperAddress = new Address { CountryCode = isInternational ? "US" : "CA" },
RecipientAddress = new Address { CountryCode = "CA" }
};
// Act
var result = _service.Calculate(parcel);
// Assert
var expectedEarliest = AddBusinessDays(DateOnly.FromDateTime(createdAt.DateTime), expectedMin);
var expectedLatest = AddBusinessDays(DateOnly.FromDateTime(createdAt.DateTime), expectedMax);
result.EarliestDelivery.Should().Be(expectedEarliest);
result.LatestDelivery.Should().Be(expectedLatest);
result.Confidence.Should().Be(DeliveryConfidenceLevel.Low);
}
[Theory]
[InlineData(ParcelStatus.LabelCreated, DeliveryConfidenceLevel.Low)]
[InlineData(ParcelStatus.InTransit, DeliveryConfidenceLevel.Medium)]
[InlineData(ParcelStatus.OutForDelivery, DeliveryConfidenceLevel.High)]
[InlineData(ParcelStatus.Delivered, DeliveryConfidenceLevel.High)]
public void Calculate_ReturnsCorrectConfidence(ParcelStatus status, DeliveryConfidenceLevel expectedConfidence)
{
// Arrange
var parcel = new Parcel
{
Id = Guid.NewGuid(),
CreatedAt = DateTimeOffset.UtcNow,
ServiceType = ServiceType.Standard,
Status = status,
ShipperAddress = new Address { CountryCode = "US" },
RecipientAddress = new Address { CountryCode = "US" }
};
// Act
var result = _service.Calculate(parcel);
// Assert
result.Confidence.Should().Be(expectedConfidence);
}
[Fact]
public void Calculate_HandlesInternationalShipping()
{
// Arrange
var parcel = new Parcel
{
Id = Guid.NewGuid(),
CreatedAt = new DateTimeOffset(2023, 1, 1, 10, 0, 0, TimeSpan.Zero),
ServiceType = ServiceType.Standard,
Status = ParcelStatus.LabelCreated,
ShipperAddress = new Address { CountryCode = "US" },
RecipientAddress = new Address { CountryCode = "CA" }
};
// Act
var result = _service.Calculate(parcel);
// Assert - Standard domestic is 3-5, international adds 3-5, so 6-10
var expectedEarliest = AddBusinessDays(DateOnly.FromDateTime(parcel.CreatedAt.DateTime), 6);
var expectedLatest = AddBusinessDays(DateOnly.FromDateTime(parcel.CreatedAt.DateTime), 10);
result.EarliestDelivery.Should().Be(expectedEarliest);
result.LatestDelivery.Should().Be(expectedLatest);
}
[Fact]
public void Recalculate_AdjustsBasedOnElapsedTime()
{
// Arrange
var createdAt = new DateTimeOffset(2023, 1, 1, 10, 0, 0, TimeSpan.Zero); // Monday
var fromDate = DateOnly.FromDateTime(createdAt.AddDays(2).DateTime); // Wednesday, 2 business days elapsed
var parcel = new Parcel
{
Id = Guid.NewGuid(),
CreatedAt = createdAt,
ServiceType = ServiceType.Standard, // 3-5 days domestic
Status = ParcelStatus.InTransit,
ShipperAddress = new Address { CountryCode = "US" },
RecipientAddress = new Address { CountryCode = "US" }
};
// Act
var result = _service.Recalculate(parcel, fromDate);
// Assert - Remaining time: max(1, 3-2)=1 to max(1, 5-2)=3
var expectedEarliest = AddBusinessDays(fromDate, 1);
var expectedLatest = AddBusinessDays(fromDate, 3);
result.EarliestDelivery.Should().Be(expectedEarliest);
result.LatestDelivery.Should().Be(expectedLatest);
result.Confidence.Should().Be(DeliveryConfidenceLevel.Medium);
}
[Fact]
public void Recalculate_NeverGoesBelowOneDay()
{
// Arrange
var createdAt = new DateTimeOffset(2023, 1, 1, 10, 0, 0, TimeSpan.Zero);
var fromDate = DateOnly.FromDateTime(createdAt.AddDays(10).DateTime); // Way past original estimate
var parcel = new Parcel
{
Id = Guid.NewGuid(),
CreatedAt = createdAt,
ServiceType = ServiceType.Express, // 1-2 days
Status = ParcelStatus.InTransit,
ShipperAddress = new Address { CountryCode = "US" },
RecipientAddress = new Address { CountryCode = "US" }
};
// Act
var result = _service.Recalculate(parcel, fromDate);
// Assert - Remaining time should be at least 1 day
var expectedEarliest = AddBusinessDays(fromDate, 1);
var expectedLatest = AddBusinessDays(fromDate, 1); // max(1, 2-10)=1
result.EarliestDelivery.Should().Be(expectedEarliest);
result.LatestDelivery.Should().Be(expectedLatest);
}
private static DateOnly AddBusinessDays(DateOnly startDate, int businessDays)
{
var current = startDate;
var added = 0;
while (added < businessDays)
{
current = current.AddDays(1);
if (current.DayOfWeek is not DayOfWeek.Saturday
and not DayOfWeek.Sunday)
{
added++;
}
}
return current;
}
}
}