Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
schmee committed Jan 27, 2024
1 parent 4eb6357 commit 2ea3f1e
Show file tree
Hide file tree
Showing 5 changed files with 859 additions and 24 deletions.
14 changes: 13 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ concurrency:

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest, windows-latest]

runs-on: ${{ matrix.os }}

steps:
- name: Set up Zig
Expand All @@ -19,6 +23,14 @@ jobs:
- name: Check out repository
uses: actions/checkout@v3

- name: Zig build test Debug
run: |
zig build test
- name: Zig build test Release
run: |
zig build test -Drelease
- name: Zig build cross
run: |
zig env
Expand Down
11 changes: 11 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ pub fn build(b: *std.Build) !void {

const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);

const test_step = b.step("test", "Run tests");
const tests = b.addTest(.{
.root_source_file = .{ .path = "src/test.zig" },
.optimize = optimize,
.target = target,
.link_libc = true,
});
const run_tests = b.addRunArtifact(tests);
run_tests.step.dependOn(b.getInstallStep());
test_step.dependOn(&run_tests.step);
}

const triples = .{
Expand Down
56 changes: 43 additions & 13 deletions src/date.zig
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ pub const LocalDate = struct {
return buf;
}

pub fn yyyyMMdd(self: Self) [8]u8 {
var buf: [8]u8 = undefined;
_ = std.fmt.bufPrint(&buf, "{d}{d:0>2}{d:0>2}", .{ self.year, self.month, self.day }) catch unreachable;
return buf;
}

pub fn compare(self: Self, other: Self) std.math.Order {
return switch (std.math.order(self.year, other.year)) {
.lt => .lt,
Expand Down Expand Up @@ -273,26 +279,52 @@ pub fn daysBetween(a: i64, b: i64) u64 {
return @divFloor(@as(u64, @intCast(b - a)), secs_per_day) -| 1;
}

var constant_now: ?i64 = null;

pub fn overrideNow(now: i64) void {
constant_now = now;
}

pub fn epochNow() i64 {
return std.time.timestamp();
return if (constant_now) |now|
now
else
std.time.timestamp();
}

pub const Transition = struct {
ts: i64,
offset: i32,
};

pub fn initTimetype(allocator: Allocator) !void {
switch (builtin.os.tag) {
.windows => try initTimetypeWindows(allocator),
else => try initTimetypePosix(allocator),
pub fn initTransitions(allocator: Allocator, transitions_str: ?[]const u8) !void {
transitions = if (transitions_str) |str|
try initTransitionsFromStr(allocator, str)
else switch (builtin.os.tag) {
.windows => try initTransitionsWindows(allocator),
else => try initTransitionsPosix(allocator),
};
tz_init = true;
}

fn initTransitionsFromStr(allocator: Allocator, transitions_str: []const u8) !?[]const Transition {
var root = (try std.json.parseFromSliceLeaky(std.json.Value, allocator, transitions_str, .{}));
var transitions_array = std.ArrayList(Transition).init(allocator);
for (root.array.items) |v| {
const obj = v.object;
const transition = Transition{
.ts = @intCast(obj.get("ts").?.integer),
.offset = @intCast(obj.get("offset").?.integer),
};
try transitions_array.append(transition);
}
return try transitions_array.toOwnedSlice();
}

pub fn initTimetypePosix(allocator: Allocator) !void {
fn initTransitionsPosix(allocator: Allocator) !?[]const Transition {
defer tz_init = true;
var db = getUserTimeZoneDb(allocator) catch |err| switch (err) {
error.FileNotFound => return, // Assume UTC
error.FileNotFound => return null, // Assume UTC
else => return err,
};
defer db.deinit();
Expand All @@ -304,12 +336,10 @@ pub fn initTimetypePosix(allocator: Allocator) !void {
.offset = t.timetype.offset,
});
}
transitions = try transitions_array.toOwnedSlice();
return try transitions_array.toOwnedSlice();
}

pub fn initTimetypeWindows(allocator: Allocator) !void {
defer tz_init = true;

fn initTransitionsWindows(allocator: Allocator) !?[]const Transition {
var tz: TIME_DYNAMIC_ZONE_INFORMATION = undefined;
const result = GetDynamicTimeZoneInformation(&tz);
if (result == TIME_ZONE_ID_INVALID ) {
Expand All @@ -333,7 +363,7 @@ pub fn initTimetypeWindows(allocator: Allocator) !void {
}
};
std.sort.pdq(Transition, transitions_array.items, {}, S.order);
transitions = try transitions_array.toOwnedSlice();
return try transitions_array.toOwnedSlice();
}

const TIME_ZONE_ID_INVALID: windows.DWORD = 0xffffffff;
Expand Down Expand Up @@ -386,7 +416,7 @@ fn transitionFromTz(comptime prefix: []const u8, tz: TIME_DYNAMIC_ZONE_INFORMATI
};
}

// `initTimetype` MUST be called before any of these functions are used!
// `initTransitions` MUST be called before any of these functions are used!

pub fn utcOffset(instant: i64) i64 {
std.debug.assert(tz_init);
Expand Down
35 changes: 25 additions & 10 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ comptime {
std.debug.assert(@sizeOf(Chain) == 256);
}

const ChainDb = struct {
pub const ChainDb = struct {
allocator: Allocator,
file: std.fs.File,
show: Show,
Expand All @@ -156,7 +156,7 @@ const ChainDb = struct {

const Self = @This();

fn materialize(self: *Self) !void {
pub fn materialize(self: *Self) !void {
std.debug.assert(!self.materialized);
try self.file.seekTo(0);
var r = self.file.reader();
Expand Down Expand Up @@ -243,7 +243,7 @@ pub const LinkMeta = extern struct {
pub const Link = extern struct {
_padding1: u16 = 0,
chain_id: u16,
tags: u8, // bitmap
tags: u8 = 0, // bitmap
_padding2: u8 = 0,
_padding3: u16 = 0,
timestamp: i64,
Expand All @@ -268,7 +268,7 @@ comptime {
std.debug.assert(@sizeOf(Link) == 16);
}

const LinkDb = struct {
pub const LinkDb = struct {
allocator: Allocator,
file: std.fs.File,
meta: LinkMeta = undefined,
Expand All @@ -279,7 +279,7 @@ const LinkDb = struct {
const NO_WRITE = std.math.maxInt(usize);
const Self = @This();

fn materialize(self: *Self, n_chains: usize) !void {
pub fn materialize(self: *Self, n_chains: usize) !void {
std.debug.assert(!self.materialized);

const stat = try self.file.stat();
Expand Down Expand Up @@ -767,7 +767,7 @@ fn parseMinDaysOrExit(str: []const u8) u8 {
return min_days;
}

fn parseLocalDateOrExit(str: []const u8, label: []const u8) LocalDate {
pub fn parseLocalDateOrExit(str: []const u8, label: []const u8) LocalDate {
const parsed = parseLocalDateOrExitInternal(str, label);
const now = date.epochNow();
if (parsed.toEpoch() > now) {
Expand Down Expand Up @@ -925,11 +925,11 @@ fn parseChainIndexes(allocator: Allocator, chain_db: *ChainDb, str: []const u8)
return cids.toOwnedSlice();
}

const Files = struct {
pub const Files = struct {
chains: std.fs.File,
links: std.fs.File,

fn close(self: @This()) void {
pub fn close(self: @This()) void {
self.chains.close();
self.links.close();
}
Expand Down Expand Up @@ -958,7 +958,7 @@ fn getConfigDirPath() ![]const u8 {
}
}

fn openOrCreateDbFiles(data_dir_path: ?[]const u8, suffix: []const u8) !Files {
pub fn openOrCreateDbFiles(data_dir_path: ?[]const u8, suffix: []const u8) !Files {
var sow = std.io.getStdOut().writer();

var habu: struct { dir: std.fs.Dir, path: []const u8} = if (data_dir_path) |ddp| blk: {
Expand Down Expand Up @@ -1030,6 +1030,8 @@ const Show = enum {

const Options = struct {
data_dir: ?[]const u8 = null,
transitions_str: ?[]const u8 = null,
override_now: ?i64 = null,
show: Show = .active,
};

Expand All @@ -1044,6 +1046,15 @@ fn parseOptionsAndPrepareArgs(allocator: Allocator, args: [][]const u8, options:
_ = args_array.orderedRemove(i);
options.data_dir = args_array.orderedRemove(i);
hit = true;
// Hidden option used for integration tests
} else if (std.mem.eql(u8, arg, "--transitions")) {
_ = args_array.orderedRemove(i);
options.transitions_str = args_array.orderedRemove(i);
hit = true;
} else if (std.mem.eql(u8, arg, "--now")) {
_ = args_array.orderedRemove(i);
options.override_now = try std.fmt.parseInt(i64, args_array.orderedRemove(i), 10);
hit = true;
} else if (std.mem.eql(u8, arg, "--show")) {
if (i == args_array.items.len - 1) printAndExit("Missing argument to --show, expected one of {s}\n", .{try formatEnumValuesForPrint(Show, allocator)});
_ = args_array.orderedRemove(i);
Expand Down Expand Up @@ -1075,7 +1086,6 @@ pub fn main() !void {
const end = std.time.Instant.now() catch unreachable;
std.log.debug("finished in {}", .{std.fmt.fmtDuration(end.since(start))});
}
try date.initTimetype(allocator);

var stdout_writer = std.io.getStdOut().writer();
var buffered_writer = std.io.bufferedWriter(stdout_writer);
Expand All @@ -1086,6 +1096,11 @@ pub fn main() !void {
var options: Options = .{};
args = try parseOptionsAndPrepareArgs(allocator, args, &options);

try date.initTransitions(allocator, options.transitions_str);
if (options.override_now) |now| {
date.overrideNow(now);
}

var files = try openOrCreateDbFiles(options.data_dir, "");
defer files.close();
var chain_db = ChainDb{ .allocator = allocator, .file = files.chains, .show = options.show };
Expand Down
Loading

0 comments on commit 2ea3f1e

Please sign in to comment.