🏡 index : ~doyle/packfile.git

author Jordan Doyle <jordan@doyle.la> 2023-07-04 20:10:49.0 +00:00:00
committer Jordan Doyle <jordan@doyle.la> 2023-07-04 20:11:56.0 +00:00:00
commit
55938bb8888a89723e60517d9367cec83e0e18d4 [patch]
tree
d2cd2f67a5c93d476267bffca49e8151d9b614a1
parent
4937c4a5508361aedc0a2b31c8940343349bdab7
download
55938bb8888a89723e60517d9367cec83e0e18d4.tar.gz

Add snapshot and git-verify-pack tests for low-level API



Diff

 src/high_level.rs                                                          |  31 +-----------
 src/lib.rs                                                                 |  37 +++++++++++++-
 src/low_level.rs                                                           | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/snapshots/packfile__low_level__test__packfile__is_readable_by_git.snap |  10 ++++-
 src/snapshots/packfile__low_level__test__packfile__snapshot.snap           |   5 ++-
 src/snapshots/packfile__low_level__test__packfile_entry__blob__full.snap   |   5 ++-
 src/snapshots/packfile__low_level__test__packfile_entry__commit__full.snap |   5 ++-
 src/snapshots/packfile__low_level__test__packfile_entry__tree__full.snap   |   5 ++-
 8 files changed, 292 insertions(+), 29 deletions(-)

diff --git a/src/high_level.rs b/src/high_level.rs
index 9e3035c..94b6472 100644
--- a/src/high_level.rs
+++ b/src/high_level.rs
@@ -183,8 +183,6 @@ enum TreeItem {
mod test {
    use crate::{high_level::GitRepository, low_level::PackFile};
    use bytes::{Bytes, BytesMut};
    use std::process::{Command, Stdio};
    use tempfile::TempDir;

    #[test]
    fn deterministic() {
@@ -198,7 +196,7 @@ mod test {
            .unwrap();

        assert_eq!(
            hex::encode(&hash),
            hex::encode(hash),
            "6ba08bda5731edfb2a0a00e602d1dd4bbd9d341c"
        );
        insta::assert_debug_snapshot!(packfile);
@@ -217,36 +215,11 @@ mod test {
            .commit("me", "me@example.com", "initial commit")
            .unwrap();

        let scratch_dir = TempDir::new().unwrap();
        let packfile_path = scratch_dir.path().join("example.pack");

        let mut output = BytesMut::new();
        PackFile::new(&packfile).encode_to(&mut output).unwrap();

        std::fs::write(&packfile_path, &output).unwrap();

        let res = Command::new("git")
            .arg("index-pack")
            .arg(&packfile_path)
            .stdout(Stdio::piped())
            .spawn()
            .unwrap()
            .wait()
            .unwrap();
        assert!(res.success());

        let command = Command::new("git")
            .arg("verify-pack")
            .arg("-v")
            .stdout(Stdio::piped())
            .arg(&packfile_path)
            .spawn()
            .unwrap();

        let out = command.wait_with_output().unwrap();
        assert!(out.status.success(), "git exited non-0");
        let stdout = crate::test::verify_pack_file(output.freeze());

        let stdout = String::from_utf8_lossy(&out.stdout);
        insta::with_settings!({filters => vec![
            (r#"/(.*)/example.pack"#, "/path/to/example.pack")
        ]}, {
diff --git a/src/lib.rs b/src/lib.rs
index 4c4b38d..f8af8dd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -30,3 +30,40 @@ mod util;

pub use error::Error;
pub use packet_line::PktLine;

#[cfg(test)]
mod test {
    use bytes::Bytes;
    use std::process::{Command, Stdio};
    use tempfile::TempDir;

    pub fn verify_pack_file(packed: Bytes) -> String {
        let scratch_dir = TempDir::new().unwrap();
        let packfile_path = scratch_dir.path().join("example.pack");

        std::fs::write(&packfile_path, packed).unwrap();

        let res = Command::new("git")
            .arg("index-pack")
            .arg(&packfile_path)
            .stdout(Stdio::piped())
            .spawn()
            .unwrap()
            .wait()
            .unwrap();
        assert!(res.success());

        let command = Command::new("git")
            .arg("verify-pack")
            .arg("-v")
            .stdout(Stdio::piped())
            .arg(&packfile_path)
            .spawn()
            .unwrap();

        let out = command.wait_with_output().unwrap();
        assert!(out.status.success(), "git exited non-0");

        String::from_utf8(out.stdout).unwrap()
    }
}
diff --git a/src/low_level.rs b/src/low_level.rs
index 4d51d6c..37d9ad5 100644
--- a/src/low_level.rs
+++ b/src/low_level.rs
@@ -355,6 +355,64 @@ impl PackFileEntry {

#[cfg(test)]
mod test {
    mod packfile {
        use crate::low_level::{
            Commit, CommitUserInfo, PackFile, PackFileEntry, TreeItem, TreeItemKind,
        };
        use bytes::{Bytes, BytesMut};

        fn example() -> Bytes {
            let blob = PackFileEntry::Blob(Bytes::from("hello world"));

            let tree = PackFileEntry::Tree(vec![TreeItem {
                kind: TreeItemKind::File,
                name: "helloworld.txt".into(),
                hash: blob.hash().unwrap(),
                sort_name: "helloworld.txt".to_string(),
            }]);

            let commit = PackFileEntry::Commit(Commit {
                tree: tree.hash().unwrap(),
                author: CommitUserInfo {
                    name: "example",
                    email: "example@me.com",
                    time: time::OffsetDateTime::UNIX_EPOCH,
                },
                committer: CommitUserInfo {
                    name: "example",
                    email: "example@me.com",
                    time: time::OffsetDateTime::UNIX_EPOCH,
                },
                message: "initial commit",
            });

            let mut out = BytesMut::new();

            PackFile::new(&[blob, tree, commit])
                .encode_to(&mut out)
                .unwrap();

            out.freeze()
        }

        #[test]
        fn snapshot() {
            let actual = example();
            insta::assert_debug_snapshot!(actual);
        }

        #[test]
        fn is_readable_by_git() {
            let stdout = crate::test::verify_pack_file(example());

            insta::with_settings!({filters => vec![
                (r#"/(.*)/example.pack"#, "/path/to/example.pack")
            ]}, {
                insta::assert_snapshot!(stdout);
            });
        }
    }

    mod packfile_entry {
        use crate::low_level::PackFileEntry;
        use bytes::{Bytes, BytesMut};
@@ -378,5 +436,170 @@ mod test {

            assert_eq!(header.to_vec(), &[0xbf, 0x00]);
        }

        mod commit {
            use crate::low_level::{Commit, CommitUserInfo, PackFileEntry};
            use bytes::BytesMut;

            fn example() -> PackFileEntry {
                PackFileEntry::Commit(Commit {
                    tree: [0; 20],
                    author: CommitUserInfo {
                        name: "author",
                        email: "author@example.com",
                        time: time::OffsetDateTime::from_unix_timestamp(1_688_494_158).unwrap(),
                    },
                    committer: CommitUserInfo {
                        name: "committer",
                        email: "committer@example.com",
                        time: time::OffsetDateTime::from_unix_timestamp(1_687_494_158).unwrap(),
                    },
                    message: "hello world!",
                })
            }

            #[test]
            fn hash() {
                let commit = example();

                let actual = hex::encode(commit.hash().unwrap());
                let expected = "0cc33510a70f7e9ad5f35738385d7ace25d0bbf4";
                assert_eq!(actual, expected);
            }

            #[test]
            fn uncompressed_size() {
                let commit = example();

                let actual = commit.uncompressed_size();
                let expected = 172;
                assert_eq!(actual, expected);
            }

            #[test]
            fn headers() {
                let commit = example();

                let mut actual = BytesMut::new();
                commit.write_header(&mut actual);

                let expected = &[0x9c, 0x0a];

                assert_eq!(actual.to_vec(), expected);
            }

            #[test]
            fn full() {
                let commit = example();

                let mut actual = BytesMut::new();
                commit.encode_to(&mut actual).unwrap();

                insta::assert_debug_snapshot!(actual);
            }
        }

        mod tree {
            use crate::low_level::{PackFileEntry, TreeItem, TreeItemKind};
            use bytes::BytesMut;

            fn example() -> PackFileEntry {
                PackFileEntry::Tree(vec![TreeItem {
                    kind: TreeItemKind::File,
                    name: "hello".into(),
                    hash: [0u8; 20],
                    sort_name: "/hello".to_string(),
                }])
            }

            #[test]
            fn hash() {
                let commit = example();

                let actual = hex::encode(commit.hash().unwrap());
                let expected = "9fc911650c548e4aa7b6dfd085a9347df8743e17";
                assert_eq!(actual, expected);
            }

            #[test]
            fn uncompressed_size() {
                let commit = example();

                let actual = commit.uncompressed_size();
                let expected = 33;
                assert_eq!(actual, expected);
            }

            #[test]
            fn headers() {
                let commit = example();

                let mut actual = BytesMut::new();
                commit.write_header(&mut actual);

                let expected = &[0xa1, 0x02];

                assert_eq!(actual.to_vec(), expected);
            }

            #[test]
            fn full() {
                let commit = example();

                let mut actual = BytesMut::new();
                commit.encode_to(&mut actual).unwrap();

                insta::assert_debug_snapshot!(actual);
            }
        }

        mod blob {
            use crate::low_level::PackFileEntry;
            use bytes::{Bytes, BytesMut};

            fn example() -> PackFileEntry {
                PackFileEntry::Blob(Bytes::from("hello world"))
            }

            #[test]
            fn hash() {
                let commit = example();

                let actual = hex::encode(commit.hash().unwrap());
                let expected = "95d09f2b10159347eece71399a7e2e907ea3df4f";
                assert_eq!(actual, expected);
            }

            #[test]
            fn uncompressed_size() {
                let commit = example();

                let actual = commit.uncompressed_size();
                let expected = 11;
                assert_eq!(actual, expected);
            }

            #[test]
            fn headers() {
                let commit = example();

                let mut actual = BytesMut::new();
                commit.write_header(&mut actual);

                let expected = &[0xbb, 0x00];

                assert_eq!(actual.to_vec(), expected);
            }

            #[test]
            fn full() {
                let commit = example();

                let mut actual = BytesMut::new();
                commit.encode_to(&mut actual).unwrap();

                insta::assert_debug_snapshot!(actual);
            }
        }
    }
}
diff --git a/src/snapshots/packfile__low_level__test__packfile__is_readable_by_git.snap b/src/snapshots/packfile__low_level__test__packfile__is_readable_by_git.snap
new file mode 100644
index 0000000..e2e89b1
--- /dev/null
+++ b/src/snapshots/packfile__low_level__test__packfile__is_readable_by_git.snap
@@ -0,0 +1,10 @@
---
source: src/low_level.rs
expression: stdout
---
95d09f2b10159347eece71399a7e2e907ea3df4f blob   11 21 12
33afd6485aadae927bc4bc2986ea9a0d86d5d699 tree   42 55 33
b740d25b3a4f2cfe1c472542712249a70e1463eb commit 144 108 88
non delta: 3 objects
/path/to/example.pack: ok

diff --git a/src/snapshots/packfile__low_level__test__packfile__snapshot.snap b/src/snapshots/packfile__low_level__test__packfile__snapshot.snap
new file mode 100644
index 0000000..7a1d745
--- /dev/null
+++ b/src/snapshots/packfile__low_level__test__packfile__snapshot.snap
@@ -0,0 +1,5 @@
---
source: src/low_level.rs
expression: actual
---
b"PACK\0\0\0\x02\0\0\0\x03\xbb\0x\x9c\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\x01\0\x1a\x0b\x04]\xaa\x02x\x9c\x01*\0\xd5\xff100644 helloworld.txt\0\x95\xd0\x9f+\x10\x15\x93G\xee\xceq9\x9a~.\x90~\xa3\xdfO<\r\x10\xd3\x90\tx\x9c\x8d\x8bK\n\x840\x10D\xf79E\xef\x07\x86\xe0'\x93\x86a\x98\xab\x94\xe9\x16\x03FEZ\xf0\xf8\nz\0kU\x0f\xde\xb3U\x95\xea\x1a\xbd\x84&\xb6\x80@\xb9\xfat\xa9\xe9R\xc51(\x18^b\x90V\x02\xb3\xc3f\xc3\xbc\x92\xee(\xcb\xa8\xf4\xbd\xcf\xbf\xe8;\xcd\xe5G\x9e^\xfe\x9c;\xa1d3}\xa0\xba<e\xcb\x18\xe9j\x0e\xf9\xdf._L\xcf-\x10\xa1\x87\xe6\x96\xf9\xf4!\xa5\xecZ\x9f[\xc6\xe4\xbd\x01"
diff --git a/src/snapshots/packfile__low_level__test__packfile_entry__blob__full.snap b/src/snapshots/packfile__low_level__test__packfile_entry__blob__full.snap
new file mode 100644
index 0000000..59ddbf0
--- /dev/null
+++ b/src/snapshots/packfile__low_level__test__packfile_entry__blob__full.snap
@@ -0,0 +1,5 @@
---
source: src/low_level.rs
expression: actual
---
b"\xbb\0x\x9c\xcbH\xcd\xc9\xc9W(\xcf/\xcaI\x01\0\x1a\x0b\x04]"
diff --git a/src/snapshots/packfile__low_level__test__packfile_entry__commit__full.snap b/src/snapshots/packfile__low_level__test__packfile_entry__commit__full.snap
new file mode 100644
index 0000000..aec9817
--- /dev/null
+++ b/src/snapshots/packfile__low_level__test__packfile_entry__commit__full.snap
@@ -0,0 +1,5 @@
---
source: src/low_level.rs
expression: actual
---
b"\x9c\nx\x9c\x8d\x8b\xd1\n@@\x10E\xdf}\xc5xV\xb2\xb5X\xb5\xc9\xaflL\xad\xdam4\x8d\xf8|B$/\xee\xcb9\xdd:\xc2\x88P\xfc\\\xe2f\xf1\xc4p\xc1\x9e\xecpuq\n\x98\xf7\x14[P\x951\xba\xd1\xaa4\x90\x1d\xcd\xfe\xc6Q\x04\x19\x1e\xb3\xb7~\xe2\xfa\x15'\x1eC X\x88\xc3\x90n%S2R"
diff --git a/src/snapshots/packfile__low_level__test__packfile_entry__tree__full.snap b/src/snapshots/packfile__low_level__test__packfile_entry__tree__full.snap
new file mode 100644
index 0000000..494ce24
--- /dev/null
+++ b/src/snapshots/packfile__low_level__test__packfile_entry__tree__full.snap
@@ -0,0 +1,5 @@
---
source: src/low_level.rs
expression: actual
---
b"\xa1\x02x\x9c340031Q\xc8H\xcd\xc9\xc9g\xc0\x06\0YU\x03d"