chore: initial domain and infrastructure layers
Signed-off-by: Alan Brault <alan.brault@visus.io>
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import TempestasInfrastructure
|
||||
|
||||
@Suite struct OpenMeteoDateDecodingTests {
|
||||
private static let json = """
|
||||
{
|
||||
"latitude": 35.7,
|
||||
"longitude": 139.7,
|
||||
"timezone": "Asia/Tokyo",
|
||||
"daily": {
|
||||
"time": ["2024-06-01"],
|
||||
"dew_point_2m_max": [15.0],
|
||||
"relative_humidity_2m_min": [50.0],
|
||||
"sunrise": ["2024-06-01T04:25"],
|
||||
"sunset": ["2024-06-01T18:52"],
|
||||
"surface_pressure_min": [1008.0],
|
||||
"apparent_temperature_max": [26.0],
|
||||
"uv_index_max": [7.0],
|
||||
"visibility_mean": [12000.0],
|
||||
"weather_code": [0],
|
||||
"wind_direction_10m_dominant": [90],
|
||||
"wind_gusts_10m_min": [10.0],
|
||||
"wind_speed_10m_min": [8.0]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@Test func decodesTruncatedIso8601SunriseInRequestedTimeZone() throws {
|
||||
let timeZone = TimeZone(identifier: "Asia/Tokyo")!
|
||||
let decoder = OpenMeteoDateDecoding.decoder(timeZone: timeZone)
|
||||
let contract = try decoder.decode(WeatherApiResponseContract.self, from: Data(Self.json.utf8))
|
||||
|
||||
var calendar = Calendar(identifier: .gregorian)
|
||||
calendar.timeZone = timeZone
|
||||
|
||||
let components = calendar.dateComponents([.hour, .minute], from: contract.items.sunriseTimes[0])
|
||||
#expect(components.hour == 4)
|
||||
#expect(components.minute == 25)
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import Foundation
|
||||
import SwiftData
|
||||
import Testing
|
||||
@testable import TempestasInfrastructure
|
||||
|
||||
@Suite struct WeatherResponseRecordMapperTests {
|
||||
private static let json = """
|
||||
{
|
||||
"latitude": 45.5,
|
||||
"longitude": -73.6,
|
||||
"timezone": "America/Toronto",
|
||||
"daily": {
|
||||
"time": ["2026-08-05", "2026-08-06"],
|
||||
"dew_point_2m_max": [12.3, 13.1],
|
||||
"relative_humidity_2m_min": [55.4, 60.2],
|
||||
"sunrise": ["2026-08-05T05:52", "2026-08-06T05:53"],
|
||||
"sunset": ["2026-08-05T20:31", "2026-08-06T20:30"],
|
||||
"surface_pressure_min": [1012.5, 1010.1],
|
||||
"apparent_temperature_max": [24.5, 23.1],
|
||||
"uv_index_max": [6.0, 5.5],
|
||||
"visibility_mean": [10000.0, 9500.0],
|
||||
"weather_code": [1, 61],
|
||||
"wind_direction_10m_dominant": [180, 200],
|
||||
"wind_gusts_10m_min": [15.0, 18.0],
|
||||
"wind_speed_10m_min": [10.0, 12.0]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
private func makeContract() throws -> WeatherApiResponseContract {
|
||||
let decoder = OpenMeteoDateDecoding.decoder(timeZone: TimeZone(identifier: "America/Toronto")!)
|
||||
return try decoder.decode(WeatherApiResponseContract.self, from: Data(Self.json.utf8))
|
||||
}
|
||||
|
||||
@Test func mapperProducesOneChildPerDay() throws {
|
||||
let contract = try makeContract()
|
||||
let record = WeatherResponseRecordMapper.map(contract)
|
||||
|
||||
#expect(record.dailyForecasts.count == 2)
|
||||
#expect(record.latitude == 45.5)
|
||||
#expect(record.timeZoneIdentifier == "America/Toronto")
|
||||
#expect(record.dailyForecasts.allSatisfy { $0.response === record })
|
||||
}
|
||||
|
||||
@Test func roundTripsThroughInMemoryModelContainer() throws {
|
||||
let schema = Schema([WeatherResponseRecord.self, DailyForecastRecord.self])
|
||||
let configuration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)
|
||||
let container = try ModelContainer(for: schema, configurations: [configuration])
|
||||
let context = ModelContext(container)
|
||||
|
||||
let contract = try makeContract()
|
||||
let record = WeatherResponseRecordMapper.map(contract)
|
||||
context.insert(record)
|
||||
try context.save()
|
||||
|
||||
let fetched = try context.fetch(FetchDescriptor<WeatherResponseRecord>())
|
||||
#expect(fetched.count == 1)
|
||||
#expect(fetched.first?.dailyForecasts.count == 2)
|
||||
|
||||
let firstDay = fetched.first?.dailyForecasts.sorted { $0.day < $1.day }.first
|
||||
#expect(firstDay?.year == 2026)
|
||||
#expect(firstDay?.month == 8)
|
||||
#expect(firstDay?.day == 5)
|
||||
#expect(firstDay?.weatherCode == 1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user