241 lines
8.6 KiB
Zig
241 lines
8.6 KiB
Zig
const std = @import("std");
|
|
const main = @import("main.zig");
|
|
const config = @import("config.zig");
|
|
const xml_parser = @import("xml_parser.zig");
|
|
|
|
const Release = main.Release;
|
|
const Config = config.Config;
|
|
const SourceHutConfig = config.SourceHutConfig;
|
|
|
|
test "Config loading without last_check field" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
// Create a test config file without last_check
|
|
const test_config_content =
|
|
\\{
|
|
\\ "github_token": "test_token",
|
|
\\ "gitlab_token": null,
|
|
\\ "codeberg_token": null,
|
|
\\ "sourcehut": {
|
|
\\ "repositories": ["~test/repo"]
|
|
\\ }
|
|
\\}
|
|
;
|
|
|
|
const temp_config_file = "test_config_no_last_check.json";
|
|
|
|
// Write test config to file
|
|
{
|
|
const file = try std.fs.cwd().createFile(temp_config_file, .{});
|
|
defer file.close();
|
|
try file.writeAll(test_config_content);
|
|
}
|
|
defer std.fs.cwd().deleteFile(temp_config_file) catch {};
|
|
|
|
// Load config
|
|
const loaded_config = try config.loadConfig(allocator, temp_config_file);
|
|
defer loaded_config.deinit();
|
|
|
|
// Verify config was loaded correctly
|
|
try std.testing.expectEqualStrings("test_token", loaded_config.github_token.?);
|
|
try std.testing.expect(loaded_config.gitlab_token == null);
|
|
}
|
|
|
|
test "parseReleaseTimestamp handles edge cases" {
|
|
// Test various timestamp formats
|
|
const test_cases = [_]struct {
|
|
input: []const u8,
|
|
expected_valid: bool,
|
|
}{
|
|
.{ .input = "2024-01-01T00:00:00Z", .expected_valid = true },
|
|
.{ .input = "2024-12-31T23:59:59Z", .expected_valid = true },
|
|
.{ .input = "1704067200", .expected_valid = true }, // This is a valid timestamp
|
|
.{ .input = "2024-01-01", .expected_valid = true }, // Zeit can parse date-only format
|
|
.{ .input = "", .expected_valid = false },
|
|
.{ .input = "invalid", .expected_valid = false },
|
|
.{ .input = "not-a-date", .expected_valid = false },
|
|
.{ .input = "definitely-not-a-date", .expected_valid = false },
|
|
};
|
|
|
|
for (test_cases) |test_case| {
|
|
const result = main.parseReleaseTimestamp(test_case.input) catch 0;
|
|
if (test_case.expected_valid) {
|
|
try std.testing.expect(result > 0);
|
|
} else {
|
|
try std.testing.expectEqual(@as(i64, 0), result);
|
|
}
|
|
}
|
|
|
|
// Test the special case of "0" timestamp - this should return 0
|
|
const zero_result = main.parseReleaseTimestamp("0") catch 0;
|
|
try std.testing.expectEqual(@as(i64, 0), zero_result);
|
|
|
|
// Test specific known values
|
|
const known_timestamp = main.parseReleaseTimestamp("1704067200") catch 0;
|
|
try std.testing.expectEqual(@as(i64, 1704067200), known_timestamp);
|
|
|
|
// Test that date-only format works
|
|
const date_only_result = main.parseReleaseTimestamp("2024-01-01") catch 0;
|
|
try std.testing.expectEqual(@as(i64, 1704067200), date_only_result);
|
|
}
|
|
|
|
test "filterNewReleases with various timestamp scenarios" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const releases = [_]Release{
|
|
Release{
|
|
.repo_name = "test/very-old",
|
|
.tag_name = "v0.1.0",
|
|
.published_at = "2023-01-01T00:00:00Z",
|
|
.html_url = "https://github.com/test/very-old/releases/tag/v0.1.0",
|
|
.description = "Very old release",
|
|
.provider = "github",
|
|
},
|
|
Release{
|
|
.repo_name = "test/old",
|
|
.tag_name = "v1.0.0",
|
|
.published_at = "2024-01-01T00:00:00Z",
|
|
.html_url = "https://github.com/test/old/releases/tag/v1.0.0",
|
|
.description = "Old release",
|
|
.provider = "github",
|
|
},
|
|
Release{
|
|
.repo_name = "test/recent",
|
|
.tag_name = "v2.0.0",
|
|
.published_at = "2024-06-01T00:00:00Z",
|
|
.html_url = "https://github.com/test/recent/releases/tag/v2.0.0",
|
|
.description = "Recent release",
|
|
.provider = "github",
|
|
},
|
|
Release{
|
|
.repo_name = "test/newest",
|
|
.tag_name = "v3.0.0",
|
|
.published_at = "2024-12-01T00:00:00Z",
|
|
.html_url = "https://github.com/test/newest/releases/tag/v3.0.0",
|
|
.description = "Newest release",
|
|
.provider = "github",
|
|
},
|
|
};
|
|
|
|
// Test filtering from beginning of time (should get all)
|
|
{
|
|
var filtered = try main.filterNewReleases(allocator, &releases, 0);
|
|
defer {
|
|
for (filtered.items) |release| {
|
|
release.deinit(allocator);
|
|
}
|
|
filtered.deinit();
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 4), filtered.items.len);
|
|
}
|
|
|
|
// Test filtering from middle of 2024 (should get recent and newest)
|
|
{
|
|
const march_2024 = main.parseReleaseTimestamp("2024-03-01T00:00:00Z") catch 0;
|
|
var filtered = try main.filterNewReleases(allocator, &releases, march_2024);
|
|
defer {
|
|
for (filtered.items) |release| {
|
|
release.deinit(allocator);
|
|
}
|
|
filtered.deinit();
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 2), filtered.items.len);
|
|
|
|
// Should contain recent and newest
|
|
var found_recent = false;
|
|
var found_newest = false;
|
|
for (filtered.items) |release| {
|
|
if (std.mem.eql(u8, release.repo_name, "test/recent")) {
|
|
found_recent = true;
|
|
}
|
|
if (std.mem.eql(u8, release.repo_name, "test/newest")) {
|
|
found_newest = true;
|
|
}
|
|
}
|
|
try std.testing.expect(found_recent);
|
|
try std.testing.expect(found_newest);
|
|
}
|
|
|
|
// Test filtering from future (should get none)
|
|
{
|
|
const future = main.parseReleaseTimestamp("2025-01-01T00:00:00Z") catch 0;
|
|
var filtered = try main.filterNewReleases(allocator, &releases, future);
|
|
defer {
|
|
for (filtered.items) |release| {
|
|
release.deinit(allocator);
|
|
}
|
|
filtered.deinit();
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 0), filtered.items.len);
|
|
}
|
|
}
|
|
|
|
test "XML parsing preserves timestamp precision" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const precise_xml =
|
|
\\<?xml version="1.0" encoding="UTF-8"?>
|
|
\\<feed xmlns="http://www.w3.org/2005/Atom">
|
|
\\<title>Repository Releases</title>
|
|
\\<entry>
|
|
\\ <title>precise/repo - v1.0.0</title>
|
|
\\ <link href="https://github.com/precise/repo/releases/tag/v1.0.0"/>
|
|
\\ <updated>2024-06-15T14:30:45Z</updated>
|
|
\\ <summary>Precise timestamp test</summary>
|
|
\\ <category term="github"/>
|
|
\\</entry>
|
|
\\</feed>
|
|
;
|
|
|
|
var releases = try xml_parser.parseAtomFeed(allocator, precise_xml);
|
|
defer {
|
|
for (releases.items) |release| {
|
|
release.deinit(allocator);
|
|
}
|
|
releases.deinit();
|
|
}
|
|
|
|
try std.testing.expectEqual(@as(usize, 1), releases.items.len);
|
|
try std.testing.expectEqualStrings("2024-06-15T14:30:45Z", releases.items[0].published_at);
|
|
|
|
// Verify the timestamp can be parsed correctly
|
|
const parsed_timestamp = main.parseReleaseTimestamp(releases.items[0].published_at) catch 0;
|
|
try std.testing.expect(parsed_timestamp > 0);
|
|
}
|
|
|
|
test "compareReleasesByDate with various timestamp formats" {
|
|
const release_iso_early = Release{
|
|
.repo_name = "test/iso-early",
|
|
.tag_name = "v1.0.0",
|
|
.published_at = "2024-01-01T00:00:00Z",
|
|
.html_url = "https://github.com/test/iso-early/releases/tag/v1.0.0",
|
|
.description = "Early ISO format",
|
|
.provider = "github",
|
|
};
|
|
|
|
const release_iso_late = Release{
|
|
.repo_name = "test/iso-late",
|
|
.tag_name = "v2.0.0",
|
|
.published_at = "2024-12-01T00:00:00Z",
|
|
.html_url = "https://github.com/test/iso-late/releases/tag/v2.0.0",
|
|
.description = "Late ISO format",
|
|
.provider = "github",
|
|
};
|
|
|
|
const release_invalid = Release{
|
|
.repo_name = "test/invalid",
|
|
.tag_name = "v3.0.0",
|
|
.published_at = "invalid-date",
|
|
.html_url = "https://github.com/test/invalid/releases/tag/v3.0.0",
|
|
.description = "Invalid format",
|
|
.provider = "github",
|
|
};
|
|
|
|
// Later date should come before earlier date (more recent first)
|
|
try std.testing.expect(main.compareReleasesByDate({}, release_iso_late, release_iso_early));
|
|
try std.testing.expect(!main.compareReleasesByDate({}, release_iso_early, release_iso_late));
|
|
|
|
// Invalid timestamps should be treated as 0 and come last
|
|
try std.testing.expect(main.compareReleasesByDate({}, release_iso_early, release_invalid));
|
|
try std.testing.expect(main.compareReleasesByDate({}, release_iso_late, release_invalid));
|
|
}
|