cli: Replace `trycmd` with our own test runner
This will allow us to run commands other than `rad` and to have tests that switch between different users. Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
parent
ca69fdc4fa
commit
e63f334890
|
|
@ -371,16 +371,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concolor"
|
||||
version = "0.0.11"
|
||||
|
|
@ -452,30 +442,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.14"
|
||||
|
|
@ -1114,12 +1080,6 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.12.1"
|
||||
|
|
@ -1260,22 +1220,6 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "humantime-serde"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.23"
|
||||
|
|
@ -1444,15 +1388,6 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.4"
|
||||
|
|
@ -1625,15 +1560,6 @@ version = "2.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
|
|
@ -1868,16 +1794,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6a252f1f8c11e84b3ab59d7a488e48e4478a93937e027076638c49536204639"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.3"
|
||||
|
|
@ -2196,16 +2112,18 @@ dependencies = [
|
|||
"json-color",
|
||||
"lexopt",
|
||||
"log",
|
||||
"pretty_assertions",
|
||||
"radicle",
|
||||
"radicle-cob",
|
||||
"radicle-crypto",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"shlex",
|
||||
"snapbox",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"timeago",
|
||||
"trycmd",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
|
|
@ -2472,29 +2390,6 @@ dependencies = [
|
|||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
|
|
@ -2657,12 +2552,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.2"
|
||||
|
|
@ -2821,6 +2710,12 @@ dependencies = [
|
|||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
|
|
@ -2865,12 +2760,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "efbd7b250c7243273b5aec4ca366fced84ad716d110bb7baae4814678952ebde"
|
||||
dependencies = [
|
||||
"concolor",
|
||||
"libc",
|
||||
"normalize-line-endings",
|
||||
"os_pipe",
|
||||
"similar",
|
||||
"snapbox-macros",
|
||||
"wait-timeout",
|
||||
"windows-sys",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
|
|
@ -3241,28 +3133,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808b51e57d0ef8f71115d8f3a01e7d3750d01c79cac4b3eda910f4389fdf92fd"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1541ba70885967e662f69d31ab3aeca7b1aaecfcd58679590b893e9239c3646"
|
||||
dependencies = [
|
||||
"combine",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"serde",
|
||||
"toml_datetime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
|
|
@ -3392,22 +3262,6 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||
|
||||
[[package]]
|
||||
name = "trycmd"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e381af441e13a3635303d26769620a9454aef05ec3303711efc3f1dd785a33af"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"humantime",
|
||||
"humantime-serde",
|
||||
"rayon",
|
||||
"serde",
|
||||
"shlex",
|
||||
"snapbox",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
|
|
@ -3488,15 +3342,6 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wait-timeout"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.0"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ version = "0"
|
|||
path = "../radicle-crypto"
|
||||
|
||||
[dev-dependencies]
|
||||
trycmd = { version = "0.14.4", default-features = false, features = ["color-auto"] }
|
||||
pretty_assertions = { version = "1.3.0" }
|
||||
tempfile = { version = "3.3.0" }
|
||||
radicle = { path = "../radicle", features = ["test"] }
|
||||
shlex = { version = "1.1.0" }
|
||||
snapbox = { version = "0.4.3" }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
Initializing a new identity with `rad-auth`.
|
||||
The example below is run with `RAD_PASSPHRASE` set.
|
||||
|
||||
|
|
@ -13,7 +12,6 @@ ok Profile z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi created.
|
|||
Your radicle Node ID is z6MknSLrJoTcukLrE435hVNQT4JUhbvWLX4kUzqkEStBU8Vi. This identifies your device.
|
||||
|
||||
=> To create a radicle project, run `rad init` from a git repository.
|
||||
|
||||
```
|
||||
|
||||
You can get the above information at all times using the `self` command:
|
||||
|
|
@ -26,5 +24,4 @@ Key (full) AAAAC3NzaC1lZDI1NTE5AAAAIHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2Y
|
|||
Storage (git) [..]/storage
|
||||
Storage (keys) [..]/keys
|
||||
Node (socket) [..]/node/radicle.sock
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -15,19 +15,17 @@ ok Project acme created
|
|||
}
|
||||
|
||||
|
||||
Your project id is [..]. You can show it any time by running:
|
||||
Your project id is rad:z4EXAgDJk11uFThfVir5FivKhiAeK. You can show it any time by running:
|
||||
rad .
|
||||
|
||||
To publish your project to the network, run:
|
||||
rad push
|
||||
|
||||
|
||||
```
|
||||
|
||||
Projects can be listed with the `ls` command:
|
||||
|
||||
```
|
||||
$ rad ls
|
||||
acme [..] [..] Acme's repository
|
||||
|
||||
acme rad:z4EXAgDJk11uFThfVir5FivKhiAeK cdf76ce Acme's repository
|
||||
```
|
||||
|
|
|
|||
|
|
@ -6,4 +6,6 @@ pub mod git;
|
|||
pub mod project;
|
||||
pub mod terminal;
|
||||
#[cfg(test)]
|
||||
mod testing;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,245 @@
|
|||
#![allow(clippy::collapsible_else_if)]
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, io, mem};
|
||||
|
||||
use snapbox::cmd::Command;
|
||||
use snapbox::{Assert, Substitutions};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("parsing failed")]
|
||||
Parse,
|
||||
#[error("i/o: {0}")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("snapbox: {0}")]
|
||||
Snapbox(#[from] snapbox::Error),
|
||||
}
|
||||
|
||||
/// A test which may contain multiple assertions.
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub struct Test {
|
||||
/// Human-readable context around the test. Functions as documentation.
|
||||
context: Vec<String>,
|
||||
/// Test assertions to run.
|
||||
assertions: Vec<Assertion>,
|
||||
}
|
||||
|
||||
/// An assertion is a command to run with an expected output.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Assertion {
|
||||
/// Name of program to run, eg. `git`.
|
||||
program: String,
|
||||
/// Program arguments, eg. `["push"]`.
|
||||
args: Vec<String>,
|
||||
/// Expected output (stdout or stderr).
|
||||
expected: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub struct TestFormula {
|
||||
/// Current working directory to run the test in.
|
||||
cwd: PathBuf,
|
||||
/// Environment to pass to the test.
|
||||
env: HashMap<String, String>,
|
||||
/// Tests to run.
|
||||
tests: Vec<Test>,
|
||||
/// Output substitutions.
|
||||
subs: Substitutions,
|
||||
}
|
||||
|
||||
impl TestFormula {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cwd: PathBuf::new(),
|
||||
env: HashMap::new(),
|
||||
tests: Vec::new(),
|
||||
subs: Substitutions::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cwd(&mut self, path: impl AsRef<Path>) -> &mut Self {
|
||||
self.cwd = path.as_ref().into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn env(&mut self, key: impl Into<String>, val: impl Into<String>) -> &mut Self {
|
||||
self.env.insert(key.into(), val.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn file(&mut self, path: impl AsRef<Path>) -> Result<&mut Self, Error> {
|
||||
let contents = fs::read(path)?;
|
||||
self.read(io::Cursor::new(contents))
|
||||
}
|
||||
|
||||
pub fn read(&mut self, r: impl io::BufRead) -> Result<&mut Self, Error> {
|
||||
let mut test = Test::default();
|
||||
let mut fenced = false; // Whether we're inside a fenced code block.
|
||||
|
||||
for line in r.lines() {
|
||||
let line = line?;
|
||||
|
||||
if line.starts_with("```") {
|
||||
if fenced {
|
||||
// End existing code block.
|
||||
self.tests.push(mem::take(&mut test));
|
||||
}
|
||||
fenced = !fenced;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if fenced {
|
||||
if let Some(line) = line.strip_prefix('$') {
|
||||
let line = line.trim();
|
||||
let parts = shlex::split(line).ok_or(Error::Parse)?;
|
||||
let (program, args) = parts.split_first().ok_or(Error::Parse)?;
|
||||
|
||||
test.assertions.push(Assertion {
|
||||
program: program.to_owned(),
|
||||
args: args.to_owned(),
|
||||
expected: String::new(),
|
||||
});
|
||||
} else if let Some(test) = test.assertions.last_mut() {
|
||||
test.expected.push_str(line.as_str());
|
||||
test.expected.push('\n');
|
||||
} else {
|
||||
return Err(Error::Parse);
|
||||
}
|
||||
} else {
|
||||
test.context.push(line);
|
||||
}
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn substitute(
|
||||
&mut self,
|
||||
value: &'static str,
|
||||
other: impl Into<Cow<'static, str>>,
|
||||
) -> Result<&mut Self, Error> {
|
||||
self.subs.insert(value, other)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Result<bool, io::Error> {
|
||||
let assert = Assert::new().substitutions(self.subs.clone());
|
||||
|
||||
for test in &self.tests {
|
||||
for assertion in &test.assertions {
|
||||
let program = if assertion.program == "rad" {
|
||||
snapbox::cmd::cargo_bin("rad")
|
||||
} else {
|
||||
PathBuf::from(&assertion.program)
|
||||
};
|
||||
|
||||
Command::new(program)
|
||||
.envs(self.env.clone())
|
||||
.args(&assertion.args)
|
||||
.with_assert(assert.clone())
|
||||
.assert()
|
||||
.stdout_matches(&assertion.expected)
|
||||
.success();
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
let input = r#"
|
||||
Let's try to track @dave and @sean:
|
||||
```
|
||||
$ rad track @dave
|
||||
Tracking relationship established for @dave.
|
||||
Nothing to do.
|
||||
|
||||
$ rad track @sean
|
||||
Tracking relationship established for @sean.
|
||||
Nothing to do.
|
||||
```
|
||||
Super, now let's move on to the next step.
|
||||
```
|
||||
$ rad sync
|
||||
```
|
||||
"#
|
||||
.trim()
|
||||
.as_bytes()
|
||||
.to_owned();
|
||||
|
||||
let mut actual = TestFormula::new();
|
||||
actual
|
||||
.read(io::BufReader::new(io::Cursor::new(input)))
|
||||
.unwrap();
|
||||
|
||||
let expected = TestFormula {
|
||||
cwd: PathBuf::new(),
|
||||
env: HashMap::new(),
|
||||
subs: Substitutions::new(),
|
||||
tests: vec![
|
||||
Test {
|
||||
context: vec![String::from("Let's try to track @dave and @sean:")],
|
||||
assertions: vec![
|
||||
Assertion {
|
||||
program: String::from("rad"),
|
||||
args: vec![String::from("track"), String::from("@dave")],
|
||||
expected: String::from(
|
||||
"Tracking relationship established for @dave.\nNothing to do.\n\n",
|
||||
),
|
||||
},
|
||||
Assertion {
|
||||
program: String::from("rad"),
|
||||
args: vec![String::from("track"), String::from("@sean")],
|
||||
expected: String::from(
|
||||
"Tracking relationship established for @sean.\nNothing to do.\n",
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
Test {
|
||||
context: vec![String::from("Super, now let's move on to the next step.")],
|
||||
assertions: vec![Assertion {
|
||||
program: String::from("rad"),
|
||||
args: vec![String::from("sync")],
|
||||
expected: String::new(),
|
||||
}],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run() {
|
||||
let input = r#"
|
||||
Running a simple command such as `head`:
|
||||
```
|
||||
$ head -n 2 Cargo.toml
|
||||
[package]
|
||||
name = "radicle-cli"
|
||||
```
|
||||
"#
|
||||
.trim()
|
||||
.as_bytes()
|
||||
.to_owned();
|
||||
|
||||
let mut formula = TestFormula::new();
|
||||
formula
|
||||
.cwd(env!("CARGO_MANIFEST_DIR"))
|
||||
.read(io::BufReader::new(io::Cursor::new(input)))
|
||||
.unwrap();
|
||||
formula.run().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +1,57 @@
|
|||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::{env, time};
|
||||
|
||||
use radicle::profile::Profile;
|
||||
use radicle::test::fixtures;
|
||||
|
||||
use crate::testing::TestFormula;
|
||||
|
||||
/// Run a CLI test file.
|
||||
fn test(
|
||||
path: impl AsRef<Path>,
|
||||
profile: Option<Profile>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let base = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let home = if let Some(profile) = profile {
|
||||
profile.home.as_path().to_path_buf()
|
||||
} else {
|
||||
tmp.path().to_path_buf()
|
||||
};
|
||||
|
||||
TestFormula::new()
|
||||
.env("RAD_PASSPHRASE", "radicle")
|
||||
.env("RAD_HOME", home.to_string_lossy())
|
||||
.env("RAD_DEBUG", "1")
|
||||
.file(base.join(path))?
|
||||
.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a new user profile.
|
||||
fn profile(home: &Path) -> Profile {
|
||||
// Set debug mode, to make test output more predictable.
|
||||
env::set_var("RAD_DEBUG", "1");
|
||||
// Setup a new user.
|
||||
Profile::init(home, "radicle").unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rad_auth() {
|
||||
let base = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
|
||||
trycmd::TestCases::new()
|
||||
.env("RAD_DEBUG", "1")
|
||||
.env("RAD_PASSPHRASE", "radicle")
|
||||
.env("RAD_HOME", home.path().to_string_lossy())
|
||||
.timeout(time::Duration::from_secs(6))
|
||||
.case(base.join("examples/rad-auth.md"))
|
||||
.run();
|
||||
test("examples/rad-auth.md", None).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rad_init() {
|
||||
let base = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||
let home = tempfile::tempdir().unwrap();
|
||||
let cwd = tempfile::tempdir().unwrap();
|
||||
let working = tempfile::tempdir().unwrap();
|
||||
let profile = profile(home.path());
|
||||
|
||||
// Setup a test repository.
|
||||
fixtures::repository(cwd.path());
|
||||
fixtures::repository(working.path());
|
||||
// Navigate to repository.
|
||||
env::set_current_dir(cwd.path()).unwrap();
|
||||
// Setup a new user.
|
||||
Profile::init(home.path(), "radicle").unwrap();
|
||||
env::set_current_dir(working.path()).unwrap();
|
||||
|
||||
trycmd::TestCases::new()
|
||||
.env("RAD_DEBUG", "1")
|
||||
.env("RAD_PASSPHRASE", "radicle")
|
||||
.env("RAD_HOME", home.path().to_string_lossy())
|
||||
.timeout(time::Duration::from_secs(6))
|
||||
.case(base.join("examples/rad-init.md"))
|
||||
.run();
|
||||
test("examples/rad-init.md", Some(profile)).unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,12 +254,11 @@ pub fn commit<'a>(
|
|||
parent: &'a git2::Commit,
|
||||
target: &RefStr,
|
||||
message: &str,
|
||||
user: &str,
|
||||
sig: &git2::Signature,
|
||||
) -> Result<git2::Commit<'a>, git2::Error> {
|
||||
let sig = git2::Signature::now(user, "anonymous@radicle.xyz")?;
|
||||
let tree_id = repo.index()?.write_tree()?;
|
||||
let tree = repo.find_tree(tree_id)?;
|
||||
let oid = repo.commit(Some(target.as_str()), &sig, &sig, message, &tree, &[parent])?;
|
||||
let oid = repo.commit(Some(target.as_str()), sig, sig, message, &tree, &[parent])?;
|
||||
let commit = repo.find_commit(oid)?;
|
||||
|
||||
Ok(commit)
|
||||
|
|
|
|||
|
|
@ -964,9 +964,16 @@ mod tests {
|
|||
|
||||
let alice_proj_storage = alice.repository(proj_id).unwrap();
|
||||
let alice_head = proj_repo.find_commit(alice_head).unwrap();
|
||||
let alice_head = git::commit(&proj_repo, &alice_head, &refname, "Making changes", "Alice")
|
||||
.unwrap()
|
||||
.id();
|
||||
let alice_sig = git2::Signature::now("Alice", "alice@radicle.xyz").unwrap();
|
||||
let alice_head = git::commit(
|
||||
&proj_repo,
|
||||
&alice_head,
|
||||
&refname,
|
||||
"Making changes",
|
||||
&alice_sig,
|
||||
)
|
||||
.unwrap()
|
||||
.id();
|
||||
git::push(&proj_repo, "rad", [(&refname, &refname)]).unwrap();
|
||||
alice_proj_storage.sign_refs(&alice_signer).unwrap();
|
||||
alice_proj_storage.set_head().unwrap();
|
||||
|
|
@ -1140,7 +1147,7 @@ mod tests {
|
|||
&head,
|
||||
&git::RefString::try_from(format!("refs/remotes/{alice}/heads/master")).unwrap(),
|
||||
"Second commit",
|
||||
&alice.to_string(),
|
||||
&sig,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ use crate::storage::git::transport;
|
|||
use crate::storage::git::Storage;
|
||||
use crate::storage::refs::SignedRefs;
|
||||
|
||||
/// The birth of the radicle project, January 1st, 2018.
|
||||
const RADICLE_EPOCH: i64 = 1514817556;
|
||||
|
||||
/// Create a new storage with a project.
|
||||
pub fn storage<P: AsRef<Path>, G: Signer>(path: P, signer: &G) -> Result<Storage, rad::InitError> {
|
||||
let path = path.as_ref();
|
||||
|
|
@ -52,14 +55,19 @@ pub fn project<P: AsRef<Path>, G: Signer>(
|
|||
/// Creates a regular repository at the given path with a couple of commits.
|
||||
pub fn repository<P: AsRef<Path>>(path: P) -> (git2::Repository, git2::Oid) {
|
||||
let repo = git2::Repository::init(path).unwrap();
|
||||
let sig = git2::Signature::now("anonymous", "anonymous@radicle.xyz").unwrap();
|
||||
let sig = git2::Signature::new(
|
||||
"anonymous",
|
||||
"anonymous@radicle.xyz",
|
||||
&git2::Time::new(RADICLE_EPOCH, 0),
|
||||
)
|
||||
.unwrap();
|
||||
let head = git::initial_commit(&repo, &sig).unwrap();
|
||||
let oid = git::commit(
|
||||
&repo,
|
||||
&head,
|
||||
git::refname!("refs/heads/master").as_refstr(),
|
||||
"Second commit",
|
||||
"anonymous",
|
||||
&sig,
|
||||
)
|
||||
.unwrap()
|
||||
.id();
|
||||
|
|
|
|||
Loading…
Reference in New Issue