summary refs log tree commit diff stats
path: root/src/git/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/git/tests.rs')
-rw-r--r--src/git/tests.rs389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/git/tests.rs b/src/git/tests.rs
new file mode 100644
index 0000000..ef6c763
--- /dev/null
+++ b/src/git/tests.rs
@@ -0,0 +1,389 @@
+// This file is part of GAnarchy - decentralized development hub
+// Copyright (C) 2021  Soni L.
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+// 
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+//! Unit tests for the git module.
+
+use super::*;
+
+use std::panic::AssertUnwindSafe;
+
+use assert_fs::assert::PathAssert;
+use assert_fs::fixture::{TempDir, PathChild};
+use predicates;
+use testserver::serve;
+
+const MAGIC_BRANCH: &'static str = "gan\
+          0000000000000000000000000000000000000000000000000000000000000000";
+
+const MAGIC_COMMIT: &'static str = "9d7224353c34ad675ee5e43fb3115aaaf98832e9";
+
+// Oh yes.
+static REPO: &'static str =
+r#####"!<arch>
+branches.a/     0           0     0     644     8         `
+!<arch>
+config.t/       0           0     0     644     66        `
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = true
+description.t/  0           0     0     644     73        `
+Unnamed repository; edit this file 'description' to name the repository.
+
+HEAD.t/         0           0     0     644     24        `
+ref: refs/heads/default
+hooks.a/        0           0     0     644     8         `
+!<arch>
+info.a/         0           0     0     644     428       `
+!<arch>
+exclude.t/      0           0     0     644     240       `
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+refs.t/         0           0     0     644     60        `
+9d7224353c34ad675ee5e43fb3115aaaf98832e9	refs/heads/default
+objects.a/      0           0     0     644     916       `
+!<arch>
+4b.a/           0           0     0     644     192       `
+!<arch>
+//                                              42        `
+825dc642cb6eb9a060e54bf8d69288fbee4904.b/
+/0              0           0     0     644     21        `
+eAErKUpNVTBgAAAKLAIB
+
+9d.a/           0           0     0     644     398       `
+!<arch>
+//                                              42        `
+7224353c34ad675ee5e43fb3115aaaf98832e9.b/
+/0              0           0     0     644     227       `
+eAGdjUsKwjAURR1nFW8DlpikIQURHRSngs7EQT6vNtIkJUZod2/BrkC4o3M5HJtC8AUYp5uSEUEY
+xWpnpWDWSDSNppJiLUynnGyYUp1BFA0VRH9KnzJcU/TtxGCP0WEOKeIckjs+g/ZDZVM4wE4yXnMm
+dw1sKaeULHRJFvxLJvdLTi+05QHtpMM4IKyAkFvv37BMR8D1O5+izrafYfxZFfkCj/1MqQ==
+
+info.a/         0           0     0     644     70        `
+!<arch>
+packs.t/        0           0     0     644     1         `
+
+
+pack.a/         0           0     0     644     8         `
+!<arch>
+refs.a/         0           0     0     644     246       `
+!<arch>
+heads.a/        0           0     0     644     110       `
+!<arch>
+default.t/      0           0     0     644     41        `
+9d7224353c34ad675ee5e43fb3115aaaf98832e9
+
+tags.a/         0           0     0     644     8         `
+!<arch>
+"#####;
+
+/// Tests the low-level (raw) commands.
+mod low_level {
+    use super::*;
+
+    /// Tests that cmd_init works.
+    #[test]
+    fn test_cmd_git_init() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.cmd_init(|args| {
+            // templates actually override the -b flag, but at least
+            // this tests that passing args to git init actually works.
+            // also note that the -b flag requires a fairly recent version
+            // of git but ah well. .-.
+            args.arg("-b").arg("hello");
+        }).unwrap();
+        // git init *always* creates HEAD, even for bare repos!
+        // we don't actually care about what HEAD contains tho.
+        repo.child("HEAD").assert(predicates::path::exists());
+    }
+
+    /// Tests that cmd_clone works.
+    #[test]
+    fn test_cmd_git_clone() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.cmd_init(|_| {}).unwrap();
+        // check that a HEAD exists
+        repo.child("HEAD").assert(predicates::path::exists());
+        let clone = dir.child("ganarchy-fetch-0.git");
+        // have to create a Git manually for this one. ah well. :(
+        let git_clone = Git {
+            path: clone.path().into(),
+            pending_branches: None,
+            sha256: false,
+        };
+        git_clone.cmd_clone_from(repo.path(), |args| {
+            // also test if git clone args work.
+            args.arg("--shared");
+        }).unwrap();
+        // git clone should carry over the HEAD
+        let pred = predicates::path::eq_file(repo.child("HEAD").path());
+        clone.child("HEAD").assert(pred);
+    }
+
+    /// Tests that cmd works and that we can get output from it.
+    #[test]
+    fn test_cmd() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let git = Git::at_path(Initializer, repo.path()).unwrap();
+        // we do need to init this because git attempts to cd to it.
+        git.cmd_init(|_| {}).unwrap();
+        let output = git.cmd(|args| {
+            args.arg("check-ref-format");
+            args.arg("--normalize");
+            args.arg("//refs/heads/headache");
+        }).unwrap();
+        assert_eq!(output.stdout, b"refs/heads/headache\n");
+    }
+}
+
+/// Tests private operations.
+mod privates {
+    use super::*;
+
+    /// Tests that fork works.
+    #[test]
+    fn test_fork() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let clone = dir.child("ganarchy-fetch-0.git");
+        // have to create a Git manually for this one. ah well. :(
+        let mut git_clone = Git {
+            path: clone.path().into(),
+            pending_branches: Some(Default::default()),
+            sha256: false,
+        };
+        git.fork(&mut git_clone).unwrap();
+    }
+
+    /// Tests that delete works.
+    #[test]
+    fn test_delete() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let clone = dir.child("ganarchy-fetch-0.git");
+        // have to create a Git manually for this one. ah well. :(
+        let mut git_clone = Git {
+            path: clone.path().into(),
+            pending_branches: Some(Default::default()),
+            sha256: false,
+        };
+        git.fork(&mut git_clone).unwrap();
+        git_clone.delete().unwrap();
+    }
+
+    // TODO rm_branch, replace, fetch_work, etc!
+    // (or we can rely on with_work_repos as an integration test)
+}
+
+/// Tests public operations.
+mod publics {
+    use super::*;
+
+    /// Tests that ensure_exists works.
+    #[test]
+    fn test_ensure_exists() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+    }
+
+    /// Tests that with_work_repos works.
+    #[test]
+    fn test_with_work_repos() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD")
+        }).unwrap();
+        git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            // This is basically check_history, but we skip cache repo check.
+            repo.cmd(|args| {
+                args.arg("merge-base");
+                args.arg("--is-ancestor");
+                args.arg(MAGIC_COMMIT);
+                args.arg(format!("refs/heads/{}", MAGIC_BRANCH));
+            })
+        }).unwrap();
+    }
+
+    /// Tests that fetch_source works.
+    #[test]
+    fn test_fetch_source() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD")
+        }).unwrap();
+    }
+
+    /// Tests that with_work_repos works properly on failure.
+    #[test]
+    fn test_with_work_repos_failure() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        let addr2 = format!("{}{}", &addr, "nonexistent");
+        let res = git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD").unwrap();
+            repo.fetch_source(&addr2, MAGIC_BRANCH, "HEAD")
+        });
+        assert!(res.is_err());
+        // it should not merge the successful one.
+        assert!(git.check_history(MAGIC_BRANCH, MAGIC_COMMIT).is_err());
+    }
+
+    /// Tests that panicking through with_work_repos leaves the disk "dirty".
+    /// Also tests that a future call to with_work_repos fails gracefully.
+    #[test]
+    fn test_with_work_repos_panic() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        let res = std::panic::catch_unwind(AssertUnwindSafe(|| {
+            // we DO NOT want to call unwrap() on ANY of these.
+            git.with_work_repos::<_, ()>(1, |repos| {
+                let repo = &mut repos[0];
+                repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD")?;
+                panic!()
+            })
+        }));
+        // check that it panicked.
+        assert!(res.is_err());
+        // now check that future calls return an error, without calling the
+        // closure.
+        let res: Result<(), _> = git.with_work_repos(1, |_| panic!());
+        assert!(res.is_err());
+    }
+
+    /// Tests that check_branch is correct.
+    #[test]
+    fn test_check_branch() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        git.check_branch("default").unwrap();
+        assert!(git.check_branch("HEAD").is_err());
+    }
+
+    /// Tests that check_history is correct.
+    #[test]
+    fn test_check_history() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD")
+        }).unwrap();
+        git.check_history(MAGIC_BRANCH, MAGIC_COMMIT).unwrap();
+    }
+
+    /// Tests that get_counts is correct. (non-exhaustive)
+    #[test]
+    fn test_get_counts() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        let counts = git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD")?;
+            repo.get_counts(MAGIC_COMMIT, MAGIC_COMMIT)
+        }).unwrap();
+        // Unfortunately we can only check MAGIC_COMMIT...MAGIC_COMMIT,
+        // so this is always gonna be (0, 0).
+        assert_eq!(counts, (0, 0));
+    }
+
+    /// Tests that get_hash is correct.
+    #[test]
+    fn test_get_hash() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        let hash = git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD")?;
+            repo.get_hash(MAGIC_BRANCH)
+        }).unwrap();
+        let hashtoo = git.get_hash(MAGIC_BRANCH).unwrap();
+        assert_eq!(hash, MAGIC_COMMIT);
+        assert_eq!(hash, hashtoo);
+    }
+
+    /// Tests that get_message is correct.
+    #[test]
+    fn test_get_message() {
+        let dir = TempDir::new().unwrap();
+        let repo = dir.child("ganarchy-cache.git");
+        let mut git = Git::at_path(Initializer, repo.path()).unwrap();
+        git.ensure_exists().unwrap();
+        let server = serve(REPO);
+        let addr = format!("http://{}:{}/", testserver::IP, server.port());
+        let msg = git.with_work_repos(1, |repos| {
+            let repo = &mut repos[0];
+            repo.fetch_source(&addr, MAGIC_BRANCH, "HEAD")?;
+            repo.get_message(MAGIC_COMMIT)
+        }).unwrap();
+        let msgtoo = git.get_message(MAGIC_COMMIT).unwrap();
+        let expect = "[Project] Example Project\n\
+                      \n\
+                      This is an example GAnarchy project.\n";
+        assert_eq!(msg, expect);
+        assert_eq!(msg, msgtoo);
+    }
+}