Skip to content

Commit 67e85b1

Browse files
committed
Fixes test errors and Readme instructions
Fixes some of the tests that didn't mock ElpriserApi to handle tomorrows prices. Updates Readme instructions that sorted should return in ascending order.
1 parent 236e848 commit 67e85b1

File tree

2 files changed

+95
-69
lines changed

2 files changed

+95
-69
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Expected Command-Line Arguments:
4444

4545
* --zone SE1|SE2|SE3|SE4 (required)
4646
* --date YYYY-MM-DD (optional, defaults to current date)
47-
* --sorted (optional, to display prices in descending order)
47+
* --sorted (optional, to display prices in ascending order)
4848
* --charging 2h|4h|8h (optional, to find optimal charging windows)
4949
* --help (optional, to display usage information)
5050

src/test/java/com/example/MainTest.java

Lines changed: 94 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ void getPriser_shouldReturnParsedPrices_whenMockDataIsProvided() {
4343
[{"SEK_per_kWh":0.12229,"EUR_per_kWh":0.01112,"EXR":10.997148,"time_start":"2025-09-04T00:00:00+02:00","time_end":"2025-09-04T01:00:00+02:00"},{"SEK_per_kWh":0.09886,"EUR_per_kWh":0.00899,"EXR":10.997148,"time_start":"2025-09-04T01:00:00+02:00","time_end":"2025-09-04T02:00:00+02:00"},{"SEK_per_kWh":0.09095,"EUR_per_kWh":0.00827,"EXR":10.997148,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"},{"SEK_per_kWh":0.04201,"EUR_per_kWh":0.00382,"EXR":10.997148,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"},{"SEK_per_kWh":0.04146,"EUR_per_kWh":0.00377,"EXR":10.997148,"time_start":"2025-09-04T04:00:00+02:00","time_end":"2025-09-04T05:00:00+02:00"},{"SEK_per_kWh":0.04465,"EUR_per_kWh":0.00406,"EXR":10.997148,"time_start":"2025-09-04T05:00:00+02:00","time_end":"2025-09-04T06:00:00+02:00"},{"SEK_per_kWh":0.32991,"EUR_per_kWh":0.03,"EXR":10.997148,"time_start":"2025-09-04T06:00:00+02:00","time_end":"2025-09-04T07:00:00+02:00"},{"SEK_per_kWh":0.47123,"EUR_per_kWh":0.04285,"EXR":10.997148,"time_start":"2025-09-04T07:00:00+02:00","time_end":"2025-09-04T08:00:00+02:00"},{"SEK_per_kWh":0.68182,"EUR_per_kWh":0.062,"EXR":10.997148,"time_start":"2025-09-04T08:00:00+02:00","time_end":"2025-09-04T09:00:00+02:00"},{"SEK_per_kWh":0.4125,"EUR_per_kWh":0.03751,"EXR":10.997148,"time_start":"2025-09-04T09:00:00+02:00","time_end":"2025-09-04T10:00:00+02:00"},{"SEK_per_kWh":0.29571,"EUR_per_kWh":0.02689,"EXR":10.997148,"time_start":"2025-09-04T10:00:00+02:00","time_end":"2025-09-04T11:00:00+02:00"},{"SEK_per_kWh":0.06136,"EUR_per_kWh":0.00558,"EXR":10.997148,"time_start":"2025-09-04T11:00:00+02:00","time_end":"2025-09-04T12:00:00+02:00"},{"SEK_per_kWh":0.03662,"EUR_per_kWh":0.00333,"EXR":10.997148,"time_start":"2025-09-04T12:00:00+02:00","time_end":"2025-09-04T13:00:00+02:00"},{"SEK_per_kWh":0.0375,"EUR_per_kWh":0.00341,"EXR":10.997148,"time_start":"2025-09-04T13:00:00+02:00","time_end":"2025-09-04T14:00:00+02:00"},{"SEK_per_kWh":0.26822,"EUR_per_kWh":0.02439,"EXR":10.997148,"time_start":"2025-09-04T14:00:00+02:00","time_end":"2025-09-04T15:00:00+02:00"},{"SEK_per_kWh":0.30429,"EUR_per_kWh":0.02767,"EXR":10.997148,"time_start":"2025-09-04T15:00:00+02:00","time_end":"2025-09-04T16:00:00+02:00"},{"SEK_per_kWh":0.36675,"EUR_per_kWh":0.03335,"EXR":10.997148,"time_start":"2025-09-04T16:00:00+02:00","time_end":"2025-09-04T17:00:00+02:00"},{"SEK_per_kWh":0.58296,"EUR_per_kWh":0.05301,"EXR":10.997148,"time_start":"2025-09-04T17:00:00+02:00","time_end":"2025-09-04T18:00:00+02:00"},{"SEK_per_kWh":0.92145,"EUR_per_kWh":0.08379,"EXR":10.997148,"time_start":"2025-09-04T18:00:00+02:00","time_end":"2025-09-04T19:00:00+02:00"},{"SEK_per_kWh":1.5054,"EUR_per_kWh":0.13689,"EXR":10.997148,"time_start":"2025-09-04T19:00:00+02:00","time_end":"2025-09-04T20:00:00+02:00"},{"SEK_per_kWh":1.00888,"EUR_per_kWh":0.09174,"EXR":10.997148,"time_start":"2025-09-04T20:00:00+02:00","time_end":"2025-09-04T21:00:00+02:00"},{"SEK_per_kWh":0.63179,"EUR_per_kWh":0.05745,"EXR":10.997148,"time_start":"2025-09-04T21:00:00+02:00","time_end":"2025-09-04T22:00:00+02:00"},{"SEK_per_kWh":0.56382,"EUR_per_kWh":0.05127,"EXR":10.997148,"time_start":"2025-09-04T22:00:00+02:00","time_end":"2025-09-04T23:00:00+02:00"},{"SEK_per_kWh":0.52951,"EUR_per_kWh":0.04815,"EXR":10.997148,"time_start":"2025-09-04T23:00:00+02:00","time_end":"2025-09-05T00:00:00+02:00"}]""";
4444

4545
// 2. Set the mock response using the static method.
46-
ElpriserAPI.setMockResponse(fakeJson);
46+
LocalDate today = LocalDate.of(2025, 9, 4);
47+
ElpriserAPI.setMockResponseForDate(today,fakeJson);
4748

4849
// 3. Create an instance of the class as a student would.
4950
ElpriserAPI api = new ElpriserAPI(false); // Disable caching for predictable tests
@@ -109,7 +110,8 @@ void displayMeanPrice_withValidData() {
109110
{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"},
110111
{"SEK_per_kWh":0.40,"EUR_per_kWh":0.04,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"}]""";
111112

112-
ElpriserAPI.setMockResponse(mockJson);
113+
LocalDate today = LocalDate.of(2025, 9, 4);
114+
ElpriserAPI.setMockResponseForDate(today,mockJson);
113115

114116
Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04"});
115117

@@ -127,7 +129,8 @@ void displayMinMaxPrices_withValidData() {
127129
{"SEK_per_kWh":0.80,"EUR_per_kWh":0.08,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"},
128130
{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"}]""";
129131

130-
ElpriserAPI.setMockResponse(mockJson);
132+
LocalDate today = LocalDate.of(2025, 9, 4);
133+
ElpriserAPI.setMockResponseForDate(today,mockJson);
131134

132135
Main.main(new String[]{"--zone", "SE1", "--date", "2025-09-04"});
133136

@@ -144,24 +147,36 @@ void displayMinMaxPrices_withValidData() {
144147

145148
@Test
146149
void displaySortedPrices_whenRequested() {
147-
String mockJson = """
148-
[{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T00:00:00+02:00","time_end":"2025-09-04T01:00:00+02:00"},
149-
{"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T01:00:00+02:00","time_end":"2025-09-04T02:00:00+02:00"},
150-
{"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"},
151-
{"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"}]""";
150+
// This test ensures charging window can span days when next day data exists
151+
LocalDate today = LocalDate.of(2025, 9, 4);
152+
LocalDate tomorrow = today.plusDays(1);
152153

153-
ElpriserAPI.setMockResponse(mockJson);
154+
String mockJsonToday = """
155+
[{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T20:00:00+02:00","time_end":"2025-09-04T21:00:00+02:00"},
156+
{"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T21:00:00+02:00","time_end":"2025-09-04T22:00:00+02:00"},
157+
{"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T22:00:00+02:00","time_end":"2025-09-04T23:00:00+02:00"},
158+
{"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T23:00:00+02:00","time_end":"2025-09-04T00:00:00+02:00"}]""";
159+
String mockJsonTomorrow = """
160+
[{"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-05T00:00:00+02:00","time_end":"2025-09-05T01:00:00+02:00"},
161+
{"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T01:00:00+02:00","time_end":"2025-09-05T02:00:00+02:00"},
162+
{"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T02:00:00+02:00","time_end":"2025-09-05T03:00:00+02:00"}]""";
163+
164+
ElpriserAPI.setMockResponseForDate(today, mockJsonToday);
165+
ElpriserAPI.setMockResponseForDate(tomorrow, mockJsonTomorrow);
154166

155167
Main.main(new String[]{"--zone", "SE2", "--date", "2025-09-04", "--sorted"});
156168

157169
String output = bos.toString();
158170

159171
// Expected sorted output (ascending by price)
160172
List<String> expectedOrder = List.of(
161-
"01-02 10,00 öre",
162-
"03-04 10,00 öre",
163-
"02-03 20,00 öre",
164-
"00-01 30,00 öre"
173+
"21-22 10,00 öre",
174+
"23-00 10,00 öre",
175+
"00-01 10,00 öre",
176+
"01-02 15,00 öre",
177+
"02-03 15,00 öre",
178+
"22-23 20,00 öre",
179+
"20-21 30,00 öre"
165180
);
166181

167182
// Extract actual lines that match the pattern
@@ -183,7 +198,9 @@ void findOptimalCharging2Hours() {
183198
{"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-04T03:00:00+02:00","time_end":"2025-09-04T04:00:00+02:00"},
184199
{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T04:00:00+02:00","time_end":"2025-09-04T05:00:00+02:00"}]""";
185200

186-
ElpriserAPI.setMockResponse(mockJson);
201+
LocalDate today = LocalDate.of(2025, 9, 4);
202+
203+
ElpriserAPI.setMockResponseForDate(today, mockJson);
187204

188205
Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04", "--charging", "2h"});
189206

@@ -204,7 +221,9 @@ void findOptimalCharging4Hours() {
204221
{"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T04:00:00+02:00","time_end":"2025-09-04T05:00:00+02:00"},
205222
{"SEK_per_kWh":0.30,"EUR_per_kWh":0.03,"EXR":10.0,"time_start":"2025-09-04T05:00:00+02:00","time_end":"2025-09-04T06:00:00+02:00"}]""";
206223

207-
ElpriserAPI.setMockResponse(mockJson);
224+
LocalDate today = LocalDate.of(2025, 9, 4);
225+
226+
ElpriserAPI.setMockResponseForDate(today, mockJson);
208227

209228
Main.main(new String[]{"--zone", "SE1", "--date", "2025-09-04", "--charging", "4h"});
210229

@@ -223,7 +242,9 @@ void chargingWindowDoesNotUseNextDay_whenNextDayUnavailable() {
223242
[{"SEK_per_kWh":0.20,"EUR_per_kWh":0.02,"EXR":10.0,"time_start":"2025-09-04T00:00:00+02:00","time_end":"2025-09-04T01:00:00+02:00"},
224243
{"SEK_per_kWh":0.10,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-04T01:00:00+02:00","time_end":"2025-09-04T02:00:00+02:00"},
225244
{"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-04T02:00:00+02:00","time_end":"2025-09-04T03:00:00+02:00"}]""";
226-
ElpriserAPI.setMockResponse(mockJsonToday);
245+
LocalDate today = LocalDate.of(2025, 9, 4);
246+
ElpriserAPI.setMockResponseForDate(today,mockJsonToday);
247+
227248
Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04", "--charging", "2h"});
228249
String output = bos.toString();
229250
// Best 2h window should be 01-03 (0.10 + 0.15)
@@ -235,20 +256,28 @@ void chargingWindowDoesNotUseNextDay_whenNextDayUnavailable() {
235256
void findOptimalCharging8Hours() {
236257
// Create mock data with 12 hours to allow for 8-hour window
237258
StringBuilder jsonBuilder = new StringBuilder("[");
238-
double[] prices = {0.50, 0.10, 0.05, 0.15, 0.08, 0.12, 0.06, 0.09, 0.25, 0.30, 0.35, 0.40};
259+
double[] prices = {0.50, 0.10, 0.05, 0.15, 0.08, 0.12, 0.06, 0.09, 0.25, 0.30, 0.35, 0.40, 0.50, 0.10, 0.05, 0.15, 0.08, 0.12, 0.06, 0.09, 0.25, 0.30, 0.35, 0.40};
239260

240261
for (int i = 0; i < prices.length; i++) {
241262
if (i > 0) jsonBuilder.append(",");
242263
jsonBuilder.append(String.format(
243264
Locale.US,
244265
"""
245266
{"SEK_per_kWh":%.2f,"EUR_per_kWh":%.3f,"EXR":10.0,"time_start":"2025-09-04T%02d:00:00+02:00","time_end":"2025-09-04T%02d:00:00+02:00"}""",
246-
prices[i], prices[i] / 10, i, i + 1
267+
prices[i], prices[i] / 10, i, (i + 1) % 24
247268
));
248269
}
249270
jsonBuilder.append("]");
250271

251-
ElpriserAPI.setMockResponse(jsonBuilder.toString());
272+
LocalDate today = LocalDate.of(2025, 9, 4);
273+
ElpriserAPI.setMockResponseForDate(today, jsonBuilder.toString());
274+
275+
LocalDate tomorrow = today.plusDays(1);
276+
String mockJsonTomorrow = """
277+
[{"SEK_per_kWh":0.1,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"2025-09-05T00:00:00+02:00","time_end":"2025-09-05T01:00:00+02:00"},
278+
{"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T01:00:00+02:00","time_end":"2025-09-05T02:00:00+02:00"},
279+
{"SEK_per_kWh":0.15,"EUR_per_kWh":0.015,"EXR":10.0,"time_start":"2025-09-05T02:00:00+02:00","time_end":"2025-09-05T03:00:00+02:00"}]""";
280+
ElpriserAPI.setMockResponseForDate(tomorrow, mockJsonTomorrow);
252281

253282
Main.main(new String[]{"--zone", "SE4", "--date", "2025-09-04", "--charging", "8h"});
254283

@@ -359,66 +388,63 @@ void chargingWindowSpansToNextDay_whenCheapestCrossesMidnight() {
359388
}
360389

361390
@Test
362-
public void testHourlyMinMaxPrices() {
363-
List<Double> quarterHourPrices = new ArrayList<>();
364-
365-
// Simulate 96 prices: 24 hours, each with 4 quarter-hour prices
366-
for (int i = 0; i < 96; i++) {
367-
quarterHourPrices.add((double) (i % 24)); // repeating hourly pattern
368-
}
391+
void testHourlyMinMaxPrices_with96Entries() {
392+
// --- ARRANGE ---
393+
LocalDate today = LocalDate.of(2025, 9, 4);
394+
StringBuilder jsonBuilder = new StringBuilder("[");
369395

370-
// Expected hourly averages
371-
List<Double> hourlyAverages = new ArrayList<>();
372-
for (int i = 0; i < 24; i++) {
373-
double sum = 0;
374-
for (int j = 0; j < 4; j++) {
375-
sum += quarterHourPrices.get(i * 4 + j);
396+
for (int hour = 0; hour < 24; hour++) {
397+
for (int quarter = 0; quarter < 4; quarter++) {
398+
if (hour > 0 || quarter > 0) {
399+
jsonBuilder.append(",");
400+
}
401+
double price = (hour * 0.1) + (quarter * 0.01) + 0.10;
402+
String time_start = String.format("2025-09-04T%02d:%02d:00+02:00", hour, quarter * 15);
403+
String time_end = String.format("2025-09-04T%02d:%02d:00+02:00", hour, (quarter + 1) * 15);
404+
if (quarter == 3) { // Handle end of hour
405+
time_end = String.format("2025-09-04T%02d:00:00+02:00", (hour + 1) % 24);
406+
}
407+
408+
jsonBuilder.append(String.format(Locale.US,
409+
"""
410+
{"SEK_per_kWh":%.4f,"EUR_per_kWh":0.01,"EXR":10.0,"time_start":"%s","time_end":"%s"}""",
411+
price, time_start, time_end));
376412
}
377-
hourlyAverages.add(sum / 4.0);
378413
}
414+
jsonBuilder.append("]");
415+
ElpriserAPI.setMockResponseForDate(today, jsonBuilder.toString());
379416

380-
double expectedMin = Collections.min(hourlyAverages);
381-
double expectedMax = Collections.max(hourlyAverages);
417+
// --- ACT ---
418+
Main.main(new String[]{"--zone", "SE3", "--date", "2025-09-04"});
382419

383-
// Call your method under test
384-
PriceRange result = PriceCalculator.calculateHourlyMinMax(quarterHourPrices);
420+
// --- ASSERT ---
421+
String output = bos.toString();
422+
assertThat(output).containsIgnoringCase("lägsta pris");
423+
assertThat(output).containsIgnoringCase("högsta pris");
424+
assertThat(output).containsIgnoringCase("medelpris");
385425

386-
assertThat(result.getMin()).isCloseTo(expectedMin, within(0.001));
387-
assertThat(result.getMax()).isCloseTo(expectedMax, within(0.001));
426+
// Expected Min: Hour 0 -> avg(0.10, 0.11, 0.12, 0.13) = 0.115 SEK/kWh = 11,50 öre
427+
// Expected Max: Hour 23 -> avg(2.40, 2.41, 2.42, 2.43) = 2.415 SEK/kWh = 241,50 öre
428+
assertThat(output).contains("00-01"); // Cheapest hour
429+
assertThat(output).contains("23-00"); // Most expensive hour
430+
assertThat(output).contains(formatOre(0.115));
431+
assertThat(output).contains(formatOre(2.415));
432+
433+
// Calculate overall average for the day
434+
double totalSum = 0;
435+
for (int hour = 0; hour < 24; hour++) {
436+
for (int quarter = 0; quarter < 4; quarter++) {
437+
totalSum += (hour * 0.1) + (quarter * 0.01) + 0.10;
438+
}
439+
}
440+
double expectedMean = totalSum / 96;
441+
assertThat(output).contains("Medelpris: " + formatOre(expectedMean) + " öre");
388442
}
389443

390444
private String formatOre(double sekPerKWh) {
391445
double ore = sekPerKWh * 100.0;
392-
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.of("sv", "SE"));
446+
DecimalFormatSymbols symbols = new DecimalFormatSymbols(new Locale("sv", "SE"));
393447
DecimalFormat df = new DecimalFormat("0.00", symbols);
394448
return df.format(ore);
395449
}
396-
}
397-
class PriceRange {
398-
private final double min;
399-
private final double max;
400-
401-
public PriceRange(double min, double max) {
402-
this.min = min;
403-
this.max = max;
404-
}
405-
406-
public double getMin() { return min; }
407-
public double getMax() { return max; }
408-
}
409-
410-
class PriceCalculator {
411-
public static PriceRange calculateHourlyMinMax(List<Double> quarterHourPrices) {
412-
List<Double> hourlyAverages = new ArrayList<>();
413-
for (int i = 0; i < 24; i++) {
414-
double sum = 0;
415-
for (int j = 0; j < 4; j++) {
416-
sum += quarterHourPrices.get(i * 4 + j);
417-
}
418-
hourlyAverages.add(sum / 4.0);
419-
}
420-
double min = Collections.min(hourlyAverages);
421-
double max = Collections.max(hourlyAverages);
422-
return new PriceRange(min, max);
423-
}
424450
}

0 commit comments

Comments
 (0)