convert mock.zig -> Mock.zig

This commit is contained in:
Emil Lerch 2025-12-18 15:01:50 -08:00
parent a2c2641558
commit 66d1e7fa79
Signed by: lobo
GPG key ID: A7B62D657EF764F8
3 changed files with 86 additions and 87 deletions

View file

@ -2,7 +2,6 @@ const std = @import("std");
const config = @import("config.zig");
const Cache = @import("cache/Cache.zig");
const MetNo = @import("weather/MetNo.zig");
const types = @import("weather/types.zig");
const Server = @import("http/Server.zig");
const RateLimiter = @import("http/RateLimiter.zig");
const GeoIp = @import("location/GeoIp.zig");
@ -80,7 +79,7 @@ test {
std.testing.refAllDecls(@This());
_ = @import("config.zig");
_ = @import("cache/Lru.zig");
_ = @import("weather/mock.zig");
_ = @import("weather/Mock.zig");
_ = @import("http/RateLimiter.zig");
_ = @import("http/query.zig");
_ = @import("http/help.zig");

85
src/weather/Mock.zig Normal file
View file

@ -0,0 +1,85 @@
const std = @import("std");
const weather_provider = @import("provider.zig");
const types = @import("types.zig");
const Mock = @This();
allocator: std.mem.Allocator,
responses: std.StringHashMap(types.WeatherData),
pub fn init(allocator: std.mem.Allocator) !Mock {
return Mock{
.allocator = allocator,
.responses = std.StringHashMap(types.WeatherData).init(allocator),
};
}
pub fn provider(self: *Mock) weather_provider.WeatherProvider {
return .{
.ptr = self,
.vtable = &.{
.fetch = fetch,
.deinit = deinitProvider,
},
};
}
pub fn addResponse(self: *Mock, location: []const u8, data: types.WeatherData) !void {
const key = try self.allocator.dupe(u8, location);
try self.responses.put(key, data);
}
fn fetch(ptr: *anyopaque, allocator: std.mem.Allocator, location: []const u8) !types.WeatherData {
const self: *Mock = @ptrCast(@alignCast(ptr));
const data = self.responses.get(location) orelse return error.LocationNotFound;
return types.WeatherData{
.location = try allocator.dupe(u8, data.location),
.current = data.current,
.forecast = try allocator.dupe(types.ForecastDay, data.forecast),
.allocator = allocator,
};
}
fn deinitProvider(ptr: *anyopaque) void {
const self: *Mock = @ptrCast(@alignCast(ptr));
self.deinit();
}
pub fn deinit(self: *Mock) void {
var it = self.responses.iterator();
while (it.next()) |entry| {
self.allocator.free(entry.key_ptr.*);
}
self.responses.deinit();
}
test "mock weather provider" {
var mock = try Mock.init(std.testing.allocator);
defer mock.deinit();
const data = types.WeatherData{
.location = "London",
.current = .{
.temp_c = 15.0,
.temp_f = 59.0,
.condition = "Clear",
.weather_code = 113,
.humidity = 65,
.wind_kph = 10.0,
.wind_dir = "N",
.pressure_mb = 1013.0,
.precip_mm = 0.0,
},
.forecast = &.{},
.allocator = std.testing.allocator,
};
try mock.addResponse("London", data);
const p = mock.provider();
const result = try p.fetch(std.testing.allocator, "London");
defer result.deinit();
try std.testing.expectEqual(@as(f32, 15.0), result.current.temp_c);
}

View file

@ -1,85 +0,0 @@
const std = @import("std");
const weather_provider = @import("provider.zig");
const types = @import("types.zig");
pub const MockWeather = struct {
allocator: std.mem.Allocator,
responses: std.StringHashMap(types.WeatherData),
pub fn init(allocator: std.mem.Allocator) !MockWeather {
return MockWeather{
.allocator = allocator,
.responses = std.StringHashMap(types.WeatherData).init(allocator),
};
}
pub fn provider(self: *MockWeather) weather_provider.WeatherProvider {
return .{
.ptr = self,
.vtable = &.{
.fetch = fetch,
.deinit = deinitProvider,
},
};
}
pub fn addResponse(self: *MockWeather, location: []const u8, data: types.WeatherData) !void {
const key = try self.allocator.dupe(u8, location);
try self.responses.put(key, data);
}
fn fetch(ptr: *anyopaque, allocator: std.mem.Allocator, location: []const u8) !types.WeatherData {
const self: *MockWeather = @ptrCast(@alignCast(ptr));
const data = self.responses.get(location) orelse return error.LocationNotFound;
return types.WeatherData{
.location = try allocator.dupe(u8, data.location),
.current = data.current,
.forecast = try allocator.dupe(types.ForecastDay, data.forecast),
.allocator = allocator,
};
}
fn deinitProvider(ptr: *anyopaque) void {
const self: *MockWeather = @ptrCast(@alignCast(ptr));
self.deinit();
}
pub fn deinit(self: *MockWeather) void {
var it = self.responses.iterator();
while (it.next()) |entry| {
self.allocator.free(entry.key_ptr.*);
}
self.responses.deinit();
}
};
test "mock weather provider" {
var mock = try MockWeather.init(std.testing.allocator);
defer mock.deinit();
const data = types.WeatherData{
.location = "London",
.current = .{
.temp_c = 15.0,
.temp_f = 59.0,
.condition = "Clear",
.weather_code = 113,
.humidity = 65,
.wind_kph = 10.0,
.wind_dir = "N",
.pressure_mb = 1013.0,
.precip_mm = 0.0,
},
.forecast = &.{},
.allocator = std.testing.allocator,
};
try mock.addResponse("London", data);
const p = mock.provider();
const result = try p.fetch(std.testing.allocator, "London");
defer result.deinit();
try std.testing.expectEqual(@as(f32, 15.0), result.current.temp_c);
}