From 4f2ca1f4f146d3956969571454cb892852ff04fd Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sun, 21 Sep 2025 14:52:27 +0800 Subject: [PATCH] Add random test program to write --- cmd/write-tests/main.ha | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/cmd/write-tests/main.ha b/cmd/write-tests/main.ha new file mode 100644 index 0000000000000000000000000000000000000000..2cb43e1434e165845a4d5669093037c7da04a5ac --- /dev/null +++ b/cmd/write-tests/main.ha @@ -0,0 +1,222 @@ +use errors; +use fmt; +use fs; +use getopt; +use io; +use os; +use strings; +use time; +use time::date; + +use git; + +fn dupu8(s: str) []u8 = { + const src = strings::toutf8(s); + let dst: []u8 = alloc([], len(src))!; + dst[..] = src; + return dst; +}; + +fn mkident(name: str, email: str) git::ident = { + let now = time::now(time::clock::REALTIME); + let d = date::localnow(); + let z = date::zone(&d); + let ofs = (z.zoff / time::SECOND): i32; // seconds? + + return git::ident{ + name = dupu8(name), + email = dupu8(email), + when = now.sec, + ofs = ofs, + }; +}; + +fn bail(msg: str) never = { + fmt::errorfln("fatal: {}", msg)!; + os::exit(1); +}; + +fn usage(cmd: *getopt::command) void = { + getopt::printusage(os::stderr, os::args[0], cmd.help)!; +}; + +export fn main() void = { + let repo_path: (str | void) = void; + + let cmd = getopt::parse( + os::args, + "create a test commit with random blobs and a tree, then print its OID", + ('r', "repo", "path to bare repo or .git"), + ); + defer getopt::finish(&cmd); + + for (let opt .. cmd.opts) { + switch (opt.0) { + case 'r' => + repo_path = opt.1; + case => + abort(); + }; + }; + + let rp: str = match (repo_path) { + case void => + usage(&cmd); + os::exit(2); + case let s: str => + yield s; + }; + + let r = match (git::repo_open(rp)) { + case let rr: git::repo => + fmt::errorfln("opened repo: {}", rp)!; + yield rr; + case let fe: fs::error => + fmt::errorfln("open repo: {}", fs::strerror(fe))!; + os::exit(1); + }; + defer git::repo_close(r); + + // Blobs + + const blob1_body = "blabla\n"; + const blob2_body = "woah\n"; + + let b1 = match (git::blob_parse(strings::toutf8(blob1_body))) { + case let bb: git::blob => + fmt::errorfln("parsed blob #1 ({} bytes)", len(strings::toutf8(blob1_body)))!; + yield bb; + case => + bail("OOM parsing blob #1"); + }; + + let id1 = match (git::loose_write(r, b1)) { + case let oid1: git::oid => + const hex = git::oid_stringify(oid1)!; + defer free(hex); + fmt::errorfln("wrote blob #1: {}", hex)!; + yield oid1; + case let fe: fs::error => + fmt::errorfln("write blob #1: {}", fs::strerror(fe))!; + os::exit(1); + case let ioe: io::error => + fmt::errorfln("write blob #1: {}", io::strerror(ioe))!; + os::exit(1); + case let ee: errors::invalid => + fmt::errorfln("write blob #1: {}", errors::strerror(ee))!; + os::exit(1); + case => + bail("write blob #1: OOM"); + }; + git::blob_finish(b1); + + let b2 = match (git::blob_parse(strings::toutf8(blob2_body))) { + case let bb: git::blob => + fmt::errorfln("parsed blob #2 ({} bytes)", len(strings::toutf8(blob2_body)))!; + yield bb; + case => + bail("OOM parsing blob #2"); + }; + + let id2 = match (git::loose_write(r, b2)) { + case let oid2: git::oid => + const hex = git::oid_stringify(oid2)!; + defer free(hex); + fmt::errorfln("wrote blob #2: {}", hex)!; + yield oid2; + case let fe: fs::error => + fmt::errorfln("write blob #2: {}", fs::strerror(fe))!; + os::exit(1); + case let ioe: io::error => + fmt::errorfln("write blob #2: {}", io::strerror(ioe))!; + os::exit(1); + case let ee: errors::invalid => + fmt::errorfln("write blob #2: {}", errors::strerror(ee))!; + os::exit(1); + case => + bail("write blob #2: OOM"); + }; + git::blob_finish(b2); + + // Tree entries + + const MODE_BLOB: u32 = (0o100644: u32); + + let ents: []git::tree_entry = alloc([], 2)!; + append(ents, git::tree_entry{ + mode = MODE_BLOB, + name = dupu8("a.txt"), + oid = id1, + })!; + append(ents, git::tree_entry{ + mode = MODE_BLOB, + name = dupu8("b.txt"), + oid = id2, + })!; + fmt::errorfln("constructed 2 tree entries")!; + + let t = git::tree{ + entries = ents, + }; + + // Tree + + let tree_id = match (git::loose_write(r, t)) { + case let toid: git::oid => + const hex = git::oid_stringify(toid)!; + defer free(hex); + fmt::errorfln("wrote tree: {}", hex)!; + yield toid; + case let fe: fs::error => + fmt::errorfln("write tree: {}", fs::strerror(fe))!; + os::exit(1); + case let ioe: io::error => + fmt::errorfln("write tree: {}", io::strerror(ioe))!; + os::exit(1); + case let ee: errors::invalid => + fmt::errorfln("write tree: {}", errors::strerror(ee))!; + os::exit(1); + case => + bail("write tree: OOM"); + }; + git::tree_finish(t); + + // Commit + + let author = mkident("Hare Example", "author@example.com"); + let committer = mkident("Hare Example", "author@example.com"); + + let parents: []git::oid = []; + let msg = dupu8("adfawjahlejfljljlj\n"); + + let c = git::commit{ + tree = tree_id, + parents = parents, + author = author, + committer = committer, + message = msg, + }; + fmt::errorfln("constructed commit object")!; + + let commit_id = match (git::loose_write(r, c)) { + case let coid: git::oid => + const hex = git::oid_stringify(coid)!; + defer free(hex); + fmt::errorfln("wrote commit: {}", hex)!; + fmt::println(hex)!; + yield coid; + case let fe: fs::error => + fmt::errorfln("write commit: {}", fs::strerror(fe))!; + os::exit(1); + case let ioe: io::error => + fmt::errorfln("write commit: {}", io::strerror(ioe))!; + os::exit(1); + case let ee: errors::invalid => + fmt::errorfln("write commit: {}", errors::strerror(ee))!; + os::exit(1); + case => + bail("write commit: OOM"); + }; + + git::commit_finish(c); +}; -- 2.48.1