Something went wrong. Try again.
A Zig library that reads git repositories without running git, with log, show and diff output byte-identical to git's.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! Naming commits by refs, compared with git: `describe` of every commit//! of generated histories in each of its modes, its messages, and//! `%(describe...)` in log formats, under SHA-1 and SHA-256. Where//! `zig-git describe` refuses a case by name, the test checks it refuses//! rather than answers.
const std = @import("std");
const tool = @import("zig_git.zig");const Repo = tool.Repo;const walk_tests = @import("walk_tests.zig");
const testing = std.testing;
fn same(repo: *Repo, args: []const []const u8) !void { try tool.expectSameAsGitHow(repo, args, .{});}
/// Compares with git, unless zig-git refuses the case by name.fn sameOrRefused(repo: *Repo, args: []const []const u8) !bool { const ours = try tool.runOurs(repo, args, .{}); defer ours.deinit(repo.gpa); if (ours.code == 128 and std.mem.find(u8, ours.stderr, "not supported") != null) return false; const theirs = try repo.runIn(".", args, ""); defer theirs.deinit(repo.gpa); errdefer { std.debug.print("zig-git", .{}); for (args) |a| std.debug.print(" {s}", .{a}); std.debug.print("\n", .{}); } try testing.expectEqualStrings(theirs.stdout, ours.stdout); try testing.expectEqualStrings(theirs.stderr, ours.stderr); try testing.expectEqual(theirs.code, ours.code); return true;}
const modes = [_][]const []const u8{ &.{}, &.{"--tags"}, &.{"--all"}, &.{"--long"}, &.{ "--abbrev=5", "--long" }, &.{"--abbrev=0"}, &.{"--first-parent"}, &.{"--candidates=2"}, &.{"--exact-match"}, &.{ "--match", "t[2-5]*", "--exclude", "t3*" }, &.{ "--always", "--match=nothing" }, &.{ "--tags", "--match=l*" },};
test "describe names every commit as git does" { const gpa = testing.allocator; var repo = try Repo.init(gpa, testing.io); defer repo.deinit(); try walk_tests.makeHistory(&repo, 9, 60); const all = try repo.output(&.{ "rev-list", "--all" }); defer gpa.free(all); var answered: usize = 0; var args: std.ArrayList([]const u8) = .empty; defer args.deinit(gpa); for (modes) |mode| { var it = std.mem.tokenizeScalar(u8, all, '\n'); while (it.next()) |c| { args.clearRetainingCapacity(); try args.append(gpa, "describe"); try args.appendSlice(gpa, mode); try args.append(gpa, c); if (try sameOrRefused(&repo, args.items)) answered += 1; } } // Most are answered rather than refused. try testing.expect(answered * 2 > modes.len * std.mem.count(u8, all, "\n"));}
test "describe says what git says" { const gpa = testing.allocator; var repo = try Repo.init(gpa, testing.io); defer repo.deinit(); try repo.commit("one"); for ([_][]const []const u8{ &.{"describe"}, &.{ "describe", "--tags" }, &.{ "describe", "--all" }, &.{ "describe", "--always" }, }) |args| try same(&repo, args); try repo.git(&.{ "tag", "light" }); try repo.commit("two"); try repo.commit("three"); for ([_][]const []const u8{ &.{"describe"}, &.{ "describe", "--tags" }, &.{ "describe", "HEAD~2" }, &.{ "describe", "HEAD^{tree}" }, &.{ "describe", "bogus" }, &.{ "describe", "--exact-match" }, &.{ "describe", "--long", "--abbrev=0" }, &.{ "describe", "--abbrev=x" }, &.{ "describe", "--candidates=-1" }, &.{ "describe", "--tags", "--long", "HEAD~2" }, &.{ "describe", "--tags", "HEAD", "HEAD~1", "HEAD~2" }, }) |args| try tool.expectSameAsGitHow(&repo, args, .{ .compare = if (std.mem.eql(u8, args[args.len - 1], "--abbrev=x")) .output else .everything }); try repo.git(&.{ "tag", "-a", "-m", "v1", "v1", "HEAD~1" }); try repo.git(&.{ "tag", "-a", "-m", "of a tag", "v1-again", "v1" }); for ([_][]const []const u8{ &.{"describe"}, &.{ "describe", "--long", "HEAD~1" }, &.{ "describe", "v1-again" }, &.{ "describe", "--all", "HEAD~1" }, }) |args| try same(&repo, args);}
test "%(describe) in a format is what git describe says" { var repo = try Repo.init(testing.allocator, testing.io); defer repo.deinit(); try walk_tests.makeHistory(&repo, 4, 50); for ([_][]const u8{ "%h %(describe)", "%(describe:abbrev=3)|%(describe:abbrev=0)|%(describe:abbrev=x)", "%(describe:match=t2*,match=t4*)|%(describe:exclude=t4*)", "%(describe:bogus)|%(describe:)|%(describe:,tags)|%(describe:tags=no)", }) |f| { const arg = try std.fmt.allocPrint(testing.allocator, "--format={s}", .{f}); defer testing.allocator.free(arg); _ = try sameOrRefused(&repo, &.{ "log", arg, "--all" }); }}