Changes
15 changed files (+374/-3)
-
-
@@ -26,7 +26,7 @@ sunwait-list - Lists sunset and sunrise time== Synposis *sunwait* *list* [_DAYS_] ++[++[-e | --event _<event>_]...] *sunwait* *list* [_DAYS_] [*--from* _<YYYY-MM-DD>_] ++[++[-e | --event _<event>_]...] == Description
-
@@ -34,8 +34,13 @@ This command prints a list of clock time when sunset and/or sunrise happens to stdout.== Options *--from* _<YYYY-MM-DD>_:: Calendar date list starts at. Defaults to today. _DAYS_:: Prints report for _DAYS_ days, including today. Prints report for _DAYS_ days from *--from*, inclusive. Defaults to *1* (only today). *-e* _<event>_, *--event* _<event>_::
-
-
-
@@ -142,6 +142,7 @@pub const ListOptions = struct { event_type: ?EventType = null, days: c_uint = c.DEFAULT_LIST, from: ?CalendarDate = null, pub fn parseArg(self: *@This(), arg: []const u8, args: *std.process.ArgIterator) ParseArgsError!void { if (EventType.parseArg(self.event_type, arg, args)) |e| {
-
@@ -150,6 +151,19 @@ return;} else |err| switch (err) { ParseArgsError.UnknownArg => {}, else => return err, } if (std.mem.eql(u8, "--from", arg)) { const next = args.next() orelse { std.log.err("{s} option requires a value", .{arg}); return ParseArgsError.MissingValue; }; self.from = CalendarDate.fromString(next) catch |err| { std.log.err("\"{s}\" is not a valid date string: {s}", .{ next, @errorName(err) }); return ParseArgsError.InvalidDateFormat; }; return; } if (std.fmt.parseUnsigned(c_uint, arg, 10)) |days| {
-
@@ -529,7 +543,24 @@ }pub fn toC(self: *const @This()) c.runStruct { var now: c.time_t = undefined; _ = c.time(&now); switch (self.command) { .list => |opts| { if (opts.from) |from| { var tm: c.tm = .{ .tm_year = from.year - 1900, .tm_mon = from.month - 1, .tm_mday = from.day, }; now = if (self.utc) c.timegm(&tm) else c.timelocal(&tm); } else { _ = c.time(&now); } }, else => { _ = c.time(&now); }, } var target_time: c.time_t = switch (self.command) { .report => |opts| getTargetDay(now, .{
-
-
tests/snapshot/list.zig (new)
-
@@ -0,0 +1,295 @@// Copyright (C) 2025 Shota FUJI // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. // // SPDX-License-Identifier: GPL-3.0-only const std = @import("std"); const config = @import("config"); const snapshot = @import("./snapshot.zig"); test "snapshots/list_basic.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "UTC"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "--from", "2025-07-07", "31.132484E", "29.977435N" }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_asia_tokyo.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Asia/Tokyo"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--from", "2025-01-01", "31.132484E", "29.977435N" }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_utc_flag.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Paris"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--utc", "--from", "2025-01-01", "31.132484E", "29.977435N" }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_sunrise_only.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Paris"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--from", "2025-01-01", "31.132484E", "29.977435N", "-e", "sunrise", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_sunset_only.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Paris"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--from", "2025-01-01", "31.132484E", "29.977435N", "-e", "sunset", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_civil.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Paris"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--from", "2025-01-01", "31.132484E", "29.977435N", "--twilight", "civil", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_custom_twilight_angle.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Paris"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--from", "2025-01-01", "31.132484E", "29.977435N", "--twilight", "2.1", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_offset.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Paris"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--from", "2025-01-01", "31.132484E", "29.977435N", "--offset", "00:30", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_negative_offset.txt" { var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Paris"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "3", "--from", "2025-01-01", "31.132484E", "29.977435N", "--offset", "-11:00", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_moscow_6days.txt" { // From original USAGE.txt // > List civil sunrise and sunset times for today and next 6 days. Moscow. var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Europe/Moscow"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "7", "--from", "2025-01-01", "--twilight", "civil", "--lat", "55.752163N", "--lon", "37.617524E", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); } test "snapshots/list_default_location_7days.txt" { // From original USAGE.txt // > List next 7 days sunrise times, custom +3 degree twilight angle, default location. // > Uses GMT; as any change in daylight saving over the specified period is not considered. var env = std.process.EnvMap.init(std.testing.allocator); defer env.deinit(); try env.put("TZ", "Asia/Tokyo"); const result = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.bin, "list", "7", "--utc", "-e", "sunrise", "--twilight", "3", }, .env_map = &env, }); defer std.testing.allocator.free(result.stderr); defer std.testing.allocator.free(result.stdout); try snapshot.expectMatchSnapshot(@src(), &result); }
-
-
-
@@ -17,4 +17,5 @@ // SPDX-License-Identifier: GPL-3.0-onlytest { _ = @import("./version.zig"); _ = @import("./list.zig"); }
-
-
-
@@ -0,0 +1,3 @@04:49, 15:07 04:49, 15:07 04:50, 15:08
-
-
-
@@ -0,0 +1,1 @@02:58, 17:01
-
-
-
@@ -0,0 +1,3 @@04:24, 15:32 04:25, 15:32 04:25, 15:33
-
-
-
@@ -0,0 +1,3 @@05:06, 14:50 05:06, 14:51 05:06, 14:52
-
-
-
@@ -0,0 +1,7 @@11:10 11:11 11:12 11:12 11:13 11:14 11:15
-
-
-
@@ -0,0 +1,7 @@05:12, 13:52 05:12, 13:53 05:12, 13:54 05:12, 13:55 05:12, 13:56 05:11, 13:57 05:11, 13:59
-
-
-
@@ -0,0 +1,3 @@--:--, --:-- (Midnight sun) --:--, --:-- (Midnight sun) --:--, --:-- (Midnight sun)
-
-
-
@@ -0,0 +1,3 @@05:19, 14:37 05:19, 14:37 05:20, 14:38
-
-
-
@@ -0,0 +1,3 @@04:49 04:49 04:50
-
-
-
@@ -0,0 +1,3 @@15:07 15:07 15:08
-
-
-
@@ -0,0 +1,3 @@04:49, 15:07 04:49, 15:07 04:50, 15:08
-