AI: Fix issues of imperial units in various renderers
This commit is contained in:
parent
58d09b1f7e
commit
4746ad81b9
6 changed files with 264 additions and 48 deletions
|
|
@ -4,6 +4,7 @@ const Cache = @import("../cache/cache.zig").Cache;
|
|||
const WeatherProvider = @import("../weather/provider.zig").WeatherProvider;
|
||||
const Resolver = @import("../location/resolver.zig").Resolver;
|
||||
const Location = @import("../location/resolver.zig").Location;
|
||||
const QueryParams = @import("query.zig").QueryParams;
|
||||
const ansi = @import("../render/ansi.zig");
|
||||
const line = @import("../render/line.zig");
|
||||
const json = @import("../render/json.zig");
|
||||
|
|
@ -130,21 +131,27 @@ fn handleWeatherInternal(
|
|||
};
|
||||
defer weather.deinit();
|
||||
|
||||
const query = try req.query();
|
||||
const format = query.get("format");
|
||||
const query_string = req.url.query;
|
||||
const params = try QueryParams.parse(allocator, query_string);
|
||||
defer {
|
||||
if (params.format) |f| allocator.free(f);
|
||||
if (params.lang) |l| allocator.free(l);
|
||||
}
|
||||
|
||||
const output = if (format) |fmt| blk: {
|
||||
const use_imperial = if (params.units) |u| u == .uscs else false;
|
||||
|
||||
const output = if (params.format) |fmt| blk: {
|
||||
if (std.mem.eql(u8, fmt, "j1")) {
|
||||
res.content_type = .JSON;
|
||||
break :blk try json.render(allocator, weather);
|
||||
} else if (std.mem.eql(u8, fmt, "v2")) {
|
||||
break :blk try v2.render(allocator, weather);
|
||||
break :blk try v2.render(allocator, weather, use_imperial);
|
||||
} else if (std.mem.startsWith(u8, fmt, "%")) {
|
||||
break :blk try custom.render(allocator, weather, fmt);
|
||||
break :blk try custom.render(allocator, weather, fmt, use_imperial);
|
||||
} else {
|
||||
break :blk try line.render(allocator, weather, fmt);
|
||||
break :blk try line.render(allocator, weather, fmt, use_imperial);
|
||||
}
|
||||
} else try ansi.render(allocator, weather, .{});
|
||||
} else try ansi.render(allocator, weather, .{ .use_imperial = use_imperial });
|
||||
|
||||
const ttl = 1000 + std.crypto.random.intRangeAtMost(u64, 0, 1000);
|
||||
try opts.cache.put(cache_key, output, ttl);
|
||||
|
|
@ -161,12 +168,11 @@ fn generateCacheKey(
|
|||
location: ?[]const u8,
|
||||
) ![]const u8 {
|
||||
const loc = location orelse "";
|
||||
const query = try req.query();
|
||||
const format = query.get("format") orelse "";
|
||||
const query_string = req.url.query;
|
||||
return std.fmt.allocPrint(allocator, "{s}:{s}:{s}", .{
|
||||
req.url.path,
|
||||
loc,
|
||||
format,
|
||||
query_string,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,23 @@ test "parse format parameter" {
|
|||
try std.testing.expectEqualStrings("j1", params.format.?);
|
||||
}
|
||||
|
||||
test "parse units with question mark" {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
// Test with just "u" (no question mark in query string)
|
||||
const params1 = try QueryParams.parse(allocator, "u");
|
||||
try std.testing.expectEqual(QueryParams.Units.uscs, params1.units.?);
|
||||
|
||||
// Test with "u=" (empty value)
|
||||
const params2 = try QueryParams.parse(allocator, "u=");
|
||||
try std.testing.expectEqual(QueryParams.Units.uscs, params2.units.?);
|
||||
|
||||
// Test combined with other params
|
||||
const params3 = try QueryParams.parse(allocator, "format=3&u");
|
||||
defer if (params3.format) |f| allocator.free(f);
|
||||
try std.testing.expectEqual(QueryParams.Units.uscs, params3.units.?);
|
||||
}
|
||||
|
||||
test "parse units parameters" {
|
||||
const allocator = std.testing.allocator;
|
||||
const params_m = try QueryParams.parse(allocator, "m");
|
||||
|
|
@ -66,6 +83,9 @@ test "parse units parameters" {
|
|||
|
||||
const params_u = try QueryParams.parse(allocator, "u");
|
||||
try std.testing.expectEqual(QueryParams.Units.uscs, params_u.units.?);
|
||||
|
||||
const params_u_query = try QueryParams.parse(allocator, "u=");
|
||||
try std.testing.expectEqual(QueryParams.Units.uscs, params_u_query.units.?);
|
||||
}
|
||||
|
||||
test "parse multiple parameters" {
|
||||
|
|
|
|||
|
|
@ -27,3 +27,27 @@ pub fn render(allocator: std.mem.Allocator, data: types.WeatherData, options: Re
|
|||
|
||||
return output.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
test "render with imperial units" {
|
||||
const data = types.WeatherData{
|
||||
.location = "Chicago",
|
||||
.current = .{
|
||||
.temp_c = 10.0,
|
||||
.temp_f = 50.0,
|
||||
.condition = "Clear",
|
||||
.weather_code = 113,
|
||||
.humidity = 60,
|
||||
.wind_kph = 16.0,
|
||||
.wind_dir = "N",
|
||||
.pressure_mb = 1013.0,
|
||||
.precip_mm = 0.0,
|
||||
},
|
||||
.forecast = &.{},
|
||||
.allocator = std.testing.allocator,
|
||||
};
|
||||
|
||||
const output = try render(std.testing.allocator, data, .{ .use_imperial = true });
|
||||
defer std.testing.allocator.free(output);
|
||||
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "50.0°F") != null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ fn getWeatherIcon(code: u16) []const u8 {
|
|||
return weather_icons[idx];
|
||||
}
|
||||
|
||||
pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData, format: []const u8) ![]const u8 {
|
||||
pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData, format: []const u8, use_imperial: bool) ![]const u8 {
|
||||
var output: std.ArrayList(u8) = .empty;
|
||||
errdefer output.deinit(allocator);
|
||||
const writer = output.writer(allocator);
|
||||
|
|
@ -26,12 +26,32 @@ pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData, format:
|
|||
'c' => try writer.print("{s}", .{getWeatherIcon(weather.current.weather_code)}),
|
||||
'C' => try writer.print("{s}", .{weather.current.condition}),
|
||||
'h' => try writer.print("{d}%", .{weather.current.humidity}),
|
||||
't' => try writer.print("{d:.0}°C", .{weather.current.temp_c}),
|
||||
'f' => try writer.print("{d:.0}°C", .{weather.current.temp_c}), // Feels like (same as temp for now)
|
||||
'w' => try writer.print("{d:.0} km/h {s}", .{ weather.current.wind_kph, weather.current.wind_dir }),
|
||||
't' => {
|
||||
const temp = if (use_imperial) weather.current.temp_f else weather.current.temp_c;
|
||||
const unit = if (use_imperial) "°F" else "°C";
|
||||
try writer.print("{d:.0}{s}", .{ temp, unit });
|
||||
},
|
||||
'f' => {
|
||||
const temp = if (use_imperial) weather.current.temp_f else weather.current.temp_c;
|
||||
const unit = if (use_imperial) "°F" else "°C";
|
||||
try writer.print("{d:.0}{s}", .{ temp, unit });
|
||||
},
|
||||
'w' => {
|
||||
const wind = if (use_imperial) weather.current.wind_kph * 0.621371 else weather.current.wind_kph;
|
||||
const unit = if (use_imperial) "mph" else "km/h";
|
||||
try writer.print("{d:.0} {s} {s}", .{ wind, unit, weather.current.wind_dir });
|
||||
},
|
||||
'l' => try writer.print("{s}", .{weather.location}),
|
||||
'p' => try writer.print("{d:.1} mm", .{weather.current.precip_mm}),
|
||||
'P' => try writer.print("{d:.0} hPa", .{weather.current.pressure_mb}),
|
||||
'p' => {
|
||||
const precip = if (use_imperial) weather.current.precip_mm * 0.0393701 else weather.current.precip_mm;
|
||||
const unit = if (use_imperial) "in" else "mm";
|
||||
try writer.print("{d:.1} {s}", .{ precip, unit });
|
||||
},
|
||||
'P' => {
|
||||
const pressure = if (use_imperial) weather.current.pressure_mb * 0.02953 else weather.current.pressure_mb;
|
||||
const unit = if (use_imperial) "inHg" else "hPa";
|
||||
try writer.print("{d:.2} {s}", .{ pressure, unit });
|
||||
},
|
||||
'm' => try writer.print("🌕", .{}), // Moon phase placeholder
|
||||
'M' => try writer.print("15", .{}), // Moon day placeholder
|
||||
'o' => try writer.print("0%", .{}), // Probability of precipitation placeholder
|
||||
|
|
@ -76,7 +96,7 @@ test "render custom format with location and temp" {
|
|||
.allocator = allocator,
|
||||
};
|
||||
|
||||
const output = try render(allocator, weather, "%l: %c %t");
|
||||
const output = try render(allocator, weather, "%l: %c %t", false);
|
||||
defer allocator.free(output);
|
||||
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "London") != null);
|
||||
|
|
@ -103,7 +123,7 @@ test "render custom format with newline" {
|
|||
.allocator = allocator,
|
||||
};
|
||||
|
||||
const output = try render(allocator, weather, "%l%n%C");
|
||||
const output = try render(allocator, weather, "%l%n%C", false);
|
||||
defer allocator.free(output);
|
||||
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "Paris\nClear") != null);
|
||||
|
|
@ -129,9 +149,37 @@ test "render custom format with humidity and pressure" {
|
|||
.allocator = allocator,
|
||||
};
|
||||
|
||||
const output = try render(allocator, weather, "Humidity: %h, Pressure: %P");
|
||||
const output = try render(allocator, weather, "Humidity: %h, Pressure: %P", false);
|
||||
defer allocator.free(output);
|
||||
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "85%") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "1012") != null);
|
||||
}
|
||||
|
||||
test "render custom format with imperial units" {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
const weather = types.WeatherData{
|
||||
.location = "NYC",
|
||||
.current = .{
|
||||
.temp_c = 10.0,
|
||||
.temp_f = 50.0,
|
||||
.condition = "Clear",
|
||||
.weather_code = 113,
|
||||
.humidity = 60,
|
||||
.wind_kph = 16.0,
|
||||
.wind_dir = "N",
|
||||
.pressure_mb = 1013.0,
|
||||
.precip_mm = 2.5,
|
||||
},
|
||||
.forecast = &[_]types.ForecastDay{},
|
||||
.allocator = allocator,
|
||||
};
|
||||
|
||||
const output = try render(allocator, weather, "%t %w %p", true);
|
||||
defer allocator.free(output);
|
||||
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "50°F") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "mph") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "in") != null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,72 @@
|
|||
const std = @import("std");
|
||||
const types = @import("../weather/types.zig");
|
||||
|
||||
pub fn render(allocator: std.mem.Allocator, data: types.WeatherData, format: []const u8) ![]const u8 {
|
||||
pub fn render(allocator: std.mem.Allocator, data: types.WeatherData, format: []const u8, use_imperial: bool) ![]const u8 {
|
||||
if (std.mem.eql(u8, format, "1")) {
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}°C", .{
|
||||
const temp = if (use_imperial) data.current.temp_f else data.current.temp_c;
|
||||
const unit = if (use_imperial) "°F" else "°C";
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}{s}", .{
|
||||
data.location,
|
||||
getConditionEmoji(data.current.weather_code),
|
||||
data.current.temp_c,
|
||||
temp,
|
||||
unit,
|
||||
});
|
||||
} else if (std.mem.eql(u8, format, "2")) {
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}°C {s}{s}{d:.0}km/h", .{
|
||||
const temp = if (use_imperial) data.current.temp_f else data.current.temp_c;
|
||||
const unit = if (use_imperial) "°F" else "°C";
|
||||
const wind = if (use_imperial) data.current.wind_kph * 0.621371 else data.current.wind_kph;
|
||||
const wind_unit = if (use_imperial) "mph" else "km/h";
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}{s} {s}{s}{d:.0}{s}", .{
|
||||
data.location,
|
||||
getConditionEmoji(data.current.weather_code),
|
||||
data.current.temp_c,
|
||||
temp,
|
||||
unit,
|
||||
"🌬️",
|
||||
data.current.wind_dir,
|
||||
data.current.wind_kph,
|
||||
wind,
|
||||
wind_unit,
|
||||
});
|
||||
} else if (std.mem.eql(u8, format, "3")) {
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}°C {s}{s}{d:.0}km/h {s}{d}%%", .{
|
||||
const temp = if (use_imperial) data.current.temp_f else data.current.temp_c;
|
||||
const unit = if (use_imperial) "°F" else "°C";
|
||||
const wind = if (use_imperial) data.current.wind_kph * 0.621371 else data.current.wind_kph;
|
||||
const wind_unit = if (use_imperial) "mph" else "km/h";
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}{s} {s}{s}{d:.0}{s} {s}{d}%%", .{
|
||||
data.location,
|
||||
getConditionEmoji(data.current.weather_code),
|
||||
data.current.temp_c,
|
||||
temp,
|
||||
unit,
|
||||
"🌬️",
|
||||
data.current.wind_dir,
|
||||
data.current.wind_kph,
|
||||
wind,
|
||||
wind_unit,
|
||||
"💧",
|
||||
data.current.humidity,
|
||||
});
|
||||
} else if (std.mem.eql(u8, format, "4")) {
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}°C {s}{s}{d:.0}km/h {s}{d}%% {s}", .{
|
||||
const temp = if (use_imperial) data.current.temp_f else data.current.temp_c;
|
||||
const unit = if (use_imperial) "°F" else "°C";
|
||||
const wind = if (use_imperial) data.current.wind_kph * 0.621371 else data.current.wind_kph;
|
||||
const wind_unit = if (use_imperial) "mph" else "km/h";
|
||||
return std.fmt.allocPrint(allocator, "{s}: {s} {d:.0}{s} {s}{s}{d:.0}{s} {s}{d}%% {s}", .{
|
||||
data.location,
|
||||
getConditionEmoji(data.current.weather_code),
|
||||
data.current.temp_c,
|
||||
temp,
|
||||
unit,
|
||||
"🌬️",
|
||||
data.current.wind_dir,
|
||||
data.current.wind_kph,
|
||||
wind,
|
||||
wind_unit,
|
||||
"💧",
|
||||
data.current.humidity,
|
||||
"☀️",
|
||||
});
|
||||
} else {
|
||||
return renderCustom(allocator, data, format);
|
||||
return renderCustom(allocator, data, format, use_imperial);
|
||||
}
|
||||
}
|
||||
|
||||
fn renderCustom(allocator: std.mem.Allocator, data: types.WeatherData, format: []const u8) ![]const u8 {
|
||||
fn renderCustom(allocator: std.mem.Allocator, data: types.WeatherData, format: []const u8, use_imperial: bool) ![]const u8 {
|
||||
var output: std.ArrayList(u8) = .empty;
|
||||
errdefer output.deinit(allocator);
|
||||
|
||||
|
|
@ -57,12 +78,28 @@ fn renderCustom(allocator: std.mem.Allocator, data: types.WeatherData, format: [
|
|||
'c' => try output.appendSlice(allocator, getConditionEmoji(data.current.weather_code)),
|
||||
'C' => try output.appendSlice(allocator, data.current.condition),
|
||||
'h' => try output.writer(allocator).print("{d}", .{data.current.humidity}),
|
||||
't' => try output.writer(allocator).print("{d:.0}", .{data.current.temp_c}),
|
||||
'f' => try output.writer(allocator).print("{d:.0}", .{data.current.temp_c}),
|
||||
'w' => try output.writer(allocator).print("{s}{d:.0}km/h", .{ data.current.wind_dir, data.current.wind_kph }),
|
||||
't' => {
|
||||
const temp = if (use_imperial) data.current.temp_f else data.current.temp_c;
|
||||
try output.writer(allocator).print("{d:.0}", .{temp});
|
||||
},
|
||||
'f' => {
|
||||
const temp = if (use_imperial) data.current.temp_f else data.current.temp_c;
|
||||
try output.writer(allocator).print("{d:.0}", .{temp});
|
||||
},
|
||||
'w' => {
|
||||
const wind = if (use_imperial) data.current.wind_kph * 0.621371 else data.current.wind_kph;
|
||||
const wind_unit = if (use_imperial) "mph" else "km/h";
|
||||
try output.writer(allocator).print("{s}{d:.0}{s}", .{ data.current.wind_dir, wind, wind_unit });
|
||||
},
|
||||
'l' => try output.appendSlice(allocator, data.location),
|
||||
'p' => try output.writer(allocator).print("{d:.1}", .{data.current.precip_mm}),
|
||||
'P' => try output.writer(allocator).print("{d:.0}", .{data.current.pressure_mb}),
|
||||
'p' => {
|
||||
const precip = if (use_imperial) data.current.precip_mm * 0.0393701 else data.current.precip_mm;
|
||||
try output.writer(allocator).print("{d:.1}", .{precip});
|
||||
},
|
||||
'P' => {
|
||||
const pressure = if (use_imperial) data.current.pressure_mb * 0.02953 else data.current.pressure_mb;
|
||||
try output.writer(allocator).print("{d:.0}", .{pressure});
|
||||
},
|
||||
'%' => try output.append(allocator, '%'),
|
||||
else => {
|
||||
try output.append(allocator, '%');
|
||||
|
|
@ -112,7 +149,7 @@ test "format 1" {
|
|||
.allocator = std.testing.allocator,
|
||||
};
|
||||
|
||||
const output = try render(std.testing.allocator, data, "1");
|
||||
const output = try render(std.testing.allocator, data, "1", false);
|
||||
defer std.testing.allocator.free(output);
|
||||
|
||||
try std.testing.expectEqualStrings("London: ☀️ 15°C", output);
|
||||
|
|
@ -136,8 +173,32 @@ test "custom format" {
|
|||
.allocator = std.testing.allocator,
|
||||
};
|
||||
|
||||
const output = try render(std.testing.allocator, data, "%l: %c %t°C");
|
||||
const output = try render(std.testing.allocator, data, "%l: %c %t°C", false);
|
||||
defer std.testing.allocator.free(output);
|
||||
|
||||
try std.testing.expectEqualStrings("London: ☀️ 15°C", output);
|
||||
}
|
||||
|
||||
test "format 2 with imperial units" {
|
||||
const data = types.WeatherData{
|
||||
.location = "Portland",
|
||||
.current = .{
|
||||
.temp_c = 10.0,
|
||||
.temp_f = 50.0,
|
||||
.condition = "Cloudy",
|
||||
.weather_code = 119,
|
||||
.humidity = 70,
|
||||
.wind_kph = 20.0,
|
||||
.wind_dir = "SE",
|
||||
.pressure_mb = 1013.0,
|
||||
.precip_mm = 0.0,
|
||||
},
|
||||
.forecast = &.{},
|
||||
.allocator = std.testing.allocator,
|
||||
};
|
||||
|
||||
const output = try render(std.testing.allocator, data, "2", true);
|
||||
defer std.testing.allocator.free(output);
|
||||
|
||||
try std.testing.expectEqualStrings("Portland: ☁️ 50°F 🌬️SE12mph", output);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const types = @import("../weather/types.zig");
|
||||
|
||||
pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData) ![]const u8 {
|
||||
pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData, use_imperial: bool) ![]const u8 {
|
||||
var output: std.ArrayList(u8) = .empty;
|
||||
errdefer output.deinit(allocator);
|
||||
const writer = output.writer(allocator);
|
||||
|
|
@ -13,15 +13,34 @@ pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData) ![]const
|
|||
try writer.print(" Current conditions\n", .{});
|
||||
try writer.print(" {s}\n", .{weather.current.condition});
|
||||
try writer.writeAll(" 🌡️ ");
|
||||
try writer.print("{d:.1}°C ({d:.1}°F)\n", .{ weather.current.temp_c, weather.current.temp_f });
|
||||
if (use_imperial) {
|
||||
try writer.print("{d:.1}°F\n", .{weather.current.temp_f});
|
||||
} else {
|
||||
try writer.print("{d:.1}°C ({d:.1}°F)\n", .{ weather.current.temp_c, weather.current.temp_f });
|
||||
}
|
||||
try writer.writeAll(" 💧 ");
|
||||
try writer.print("{d}%\n", .{weather.current.humidity});
|
||||
try writer.writeAll(" 🌬️ ");
|
||||
try writer.print("{d:.1} km/h {s}\n", .{ weather.current.wind_kph, weather.current.wind_dir });
|
||||
if (use_imperial) {
|
||||
const wind_mph = weather.current.wind_kph * 0.621371;
|
||||
try writer.print("{d:.1} mph {s}\n", .{ wind_mph, weather.current.wind_dir });
|
||||
} else {
|
||||
try writer.print("{d:.1} km/h {s}\n", .{ weather.current.wind_kph, weather.current.wind_dir });
|
||||
}
|
||||
try writer.writeAll(" 🔽 ");
|
||||
try writer.print("{d:.1} hPa\n", .{weather.current.pressure_mb});
|
||||
if (use_imperial) {
|
||||
const pressure_inhg = weather.current.pressure_mb * 0.02953;
|
||||
try writer.print("{d:.2} inHg\n", .{pressure_inhg});
|
||||
} else {
|
||||
try writer.print("{d:.1} hPa\n", .{weather.current.pressure_mb});
|
||||
}
|
||||
try writer.writeAll(" 💦 ");
|
||||
try writer.print("{d:.1} mm\n\n", .{weather.current.precip_mm});
|
||||
if (use_imperial) {
|
||||
const precip_in = weather.current.precip_mm * 0.0393701;
|
||||
try writer.print("{d:.2} in\n\n", .{precip_in});
|
||||
} else {
|
||||
try writer.print("{d:.1} mm\n\n", .{weather.current.precip_mm});
|
||||
}
|
||||
|
||||
// Forecast
|
||||
if (weather.forecast.len > 0) {
|
||||
|
|
@ -29,9 +48,19 @@ pub fn render(allocator: std.mem.Allocator, weather: types.WeatherData) ![]const
|
|||
for (weather.forecast) |day| {
|
||||
try writer.print(" {s}: {s}\n", .{ day.date, day.condition });
|
||||
try writer.writeAll(" ↑ ");
|
||||
try writer.print("{d:.1}°C ", .{day.max_temp_c});
|
||||
if (use_imperial) {
|
||||
const max_f = day.max_temp_c * 9.0 / 5.0 + 32.0;
|
||||
try writer.print("{d:.1}°F ", .{max_f});
|
||||
} else {
|
||||
try writer.print("{d:.1}°C ", .{day.max_temp_c});
|
||||
}
|
||||
try writer.writeAll("↓ ");
|
||||
try writer.print("{d:.1}°C\n", .{day.min_temp_c});
|
||||
if (use_imperial) {
|
||||
const min_f = day.min_temp_c * 9.0 / 5.0 + 32.0;
|
||||
try writer.print("{d:.1}°F\n", .{min_f});
|
||||
} else {
|
||||
try writer.print("{d:.1}°C\n", .{day.min_temp_c});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +87,7 @@ test "render v2 format" {
|
|||
.allocator = allocator,
|
||||
};
|
||||
|
||||
const output = try render(allocator, weather);
|
||||
const output = try render(allocator, weather, false);
|
||||
defer allocator.free(output);
|
||||
|
||||
try std.testing.expect(output.len > 0);
|
||||
|
|
@ -66,3 +95,31 @@ test "render v2 format" {
|
|||
try std.testing.expect(std.mem.indexOf(u8, output, "Current conditions") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "12.0°C") != null);
|
||||
}
|
||||
|
||||
test "render v2 format with imperial units" {
|
||||
const allocator = std.testing.allocator;
|
||||
|
||||
const weather = types.WeatherData{
|
||||
.location = "Boston",
|
||||
.current = .{
|
||||
.temp_c = 10.0,
|
||||
.temp_f = 50.0,
|
||||
.condition = "Clear",
|
||||
.weather_code = 113,
|
||||
.humidity = 65,
|
||||
.wind_kph = 16.0,
|
||||
.wind_dir = "N",
|
||||
.pressure_mb = 1013.0,
|
||||
.precip_mm = 0.0,
|
||||
},
|
||||
.forecast = &[_]types.ForecastDay{},
|
||||
.allocator = allocator,
|
||||
};
|
||||
|
||||
const output = try render(allocator, weather, true);
|
||||
defer allocator.free(output);
|
||||
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "50.0°F") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "mph") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, output, "inHg") != null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue