-- SPDX-FileCopyrightText: © 2022—2026 Vladimir Zorin -- SPDX-License-Identifier: LicenseRef-OWL-1.0-or-later -- Licensed under OWL v1.0+. See LICENSE. local testimony = require("testimony") local std = require("std") local git = require("git") local testify = testimony.new("== git (core) ==") -- os.execute returns a boolean with LUA52COMPAT, a number otherwise local sh = function(cmd) local r = os.execute(cmd .. " >/dev/null 2>&1") return r == true or r == 0 end local has_git = sh("git --version") local sh_out = function(cmd) local f = io.popen(cmd) if not f then return nil end local out = f:read("*a") f:close() return out and out:match("^%s*(.-)%s*$") end local make_fixture = function() local dir = "/tmp/" .. std.nanoid() local g = "git -C " .. dir .. " -c user.name=test -c user.email=test@test" if not sh("git init -q " .. dir) then return nil end std.fs.write_file(dir .. "/readme.txt", "hello lilush git core\n") std.fs.mkdir(dir .. "/sub") std.fs.write_file(dir .. "/sub/data.bin", string.rep("\0\1\2\3", 1024)) sh(g .. " add -A") sh(g .. " commit -q -m first") std.fs.write_file(dir .. "/readme.txt", "hello again\n") sh(g .. " add -A") sh(g .. " commit -q -m second") sh(g .. " tag -a v1 -m release-one") local head = sh_out("git -C " .. dir .. " rev-parse HEAD") local head_ref = sh_out("git -C " .. dir .. " symbolic-ref HEAD") if not head or #head ~= 40 then return nil end return { dir = dir, git_dir = dir .. "/.git", head = head, head_ref = head_ref } end local fixture = has_git and make_fixture() or nil if fixture then testify:that("find_git_dir: resolves from a subdirectory", function() local git_dir, worktree = git.find_git_dir(fixture.dir .. "/sub") testimony.assert_equal(fixture.git_dir, git_dir) testimony.assert_equal(fixture.dir, worktree) end) testify:that("read_head + resolve_ref: symbolic HEAD resolves to commit sha", function() local head = git.read_head(fixture.git_dir) testimony.assert_equal("branch", head.type) testimony.assert_equal(fixture.head_ref, head.ref) testimony.assert_equal(fixture.head, git.resolve_ref(fixture.git_dir, head.ref)) end) testify:that("read_object: reads and types commit, tree, blob, tag", function() local commit_obj = git.read_object(fixture.git_dir, fixture.head) testimony.assert_equal("commit", commit_obj.type) local commit = git.parse_commit(commit_obj.content) testimony.assert_equal(1, #commit.parents) testimony.assert_match("second", commit.message) local tree_obj = git.read_object(fixture.git_dir, commit.tree) testimony.assert_equal("tree", tree_obj.type) local entries = git.parse_tree(tree_obj.content) testimony.assert_equal(2, #entries) local by_name = {} for _, e in ipairs(entries) do by_name[e.name] = e end testimony.assert_not_nil(by_name["readme.txt"]) testimony.assert_equal("40000", by_name["sub"].mode) local blob = git.read_object(fixture.git_dir, by_name["readme.txt"].sha) testimony.assert_equal("blob", blob.type) testimony.assert_equal("hello again\n", blob.content) end) testify:that("flatten_tree: maps full paths to blob shas", function() local commit = git.parse_commit(git.read_object(fixture.git_dir, fixture.head).content) local files = git.flatten_tree(fixture.git_dir, commit.tree) testimony.assert_not_nil(files["readme.txt"]) testimony.assert_not_nil(files["sub/data.bin"]) end) testify:that("list_refs: finds branch, tag, and peeled tag", function() local refs = git.list_refs(fixture.git_dir) testimony.assert_equal(fixture.head, refs[fixture.head_ref]) testimony.assert_not_nil(refs["refs/tags/v1"]) testimony.assert_not_nil(refs["refs/tags/v1^{}"]) testimony.assert_equal(fixture.head, refs["refs/tags/v1^{}"]) end) testify:that("parse_index: reads the staging index", function() local entries = git.parse_index(fixture.git_dir) testimony.assert_equal(2, #entries) local names = {} for _, e in ipairs(entries) do names[e.name] = true end testimony.assert_true(names["readme.txt"]) testimony.assert_true(names["sub/data.bin"]) end) else print("-- git binary not found (or fixture failed), skipping git core tests --") end if fixture then os.execute("rm -rf " .. fixture.dir) end testify:conclude()