diff --git a/.gitignore b/.gitignore index 958be4e1..963cff61 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,3 @@ Cargo.lock # Intellij IDE configuration .idea/ - -# Cobertura coverage report -cobertura.xml diff --git a/README.md b/README.md index 576f003b..bae3808f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@

The cross-shell prompt for astronauts.

Azure Pipelines Build Status - Codecov Coverage All Contributors Chat on Discord

diff --git a/adapters/fish_prompt.fish b/adapters/fish_prompt.fish index 965398ea..cd3d7712 100644 --- a/adapters/fish_prompt.fish +++ b/adapters/fish_prompt.fish @@ -1,3 +1,3 @@ function fish_prompt - starship $status + starship prompt --status=$status end diff --git a/adapters/starship.zsh-theme b/adapters/starship.zsh-theme index ded50982..0da0bd71 100644 --- a/adapters/starship.zsh-theme +++ b/adapters/starship.zsh-theme @@ -1 +1 @@ -PROMPT='$(starship $?)' +PROMPT='$(starship prompt --status=$?)' diff --git a/ci/azure-test-docker.yml b/ci/azure-test-docker.yml index 93b8cfcb..22df04cb 100644 --- a/ci/azure-test-docker.yml +++ b/ci/azure-test-docker.yml @@ -5,11 +5,11 @@ jobs: vmImage: ubuntu-16.04 steps: - - script: ./integration_test - displayName: Run integration test within Docker + - script: docker pull starshipcommand/starship-test + displayName: Pull docker image - - script: bash <(curl -s https://codecov.io/bash) -t $(CODECOV_TOKEN) - displayName: Report coverage to Codecov + - script: ./integration_test + displayName: Run integration test suite - script: | docker login -u $(dockerUsername) -p $(dockerPassword) diff --git a/integration_test b/integration_test index 81c7ba3b..cf91a213 100755 --- a/integration_test +++ b/integration_test @@ -6,9 +6,6 @@ if ! (docker --version); then exit 1 fi -printf 'Pulling latest docker image' -docker pull starshipcommand/starship-test - printf 'Building test docker image:\n' docker build -f tests/Dockerfile \ --tag starshipcommand/starship-test \ @@ -16,6 +13,4 @@ docker build -f tests/Dockerfile \ . printf 'Running test suite:\n' -# `seccomp=unconfined` is needed to allow tarpaulin to disable ASLR -# Details found here: https://github.com/xd009642/tarpaulin/issues/146 -docker run --rm --security-opt seccomp=unconfined -v $(pwd):/starship starshipcommand/starship-test +docker run --rm -v $(pwd):/starship starshipcommand/starship-test diff --git a/src/context.rs b/src/context.rs index b86bd070..e0e7e286 100644 --- a/src/context.rs +++ b/src/context.rs @@ -15,11 +15,15 @@ pub struct Context<'a> { impl<'a> Context<'a> { pub fn new(arguments: ArgMatches) -> Context { - let current_dir = env::current_dir().expect("Unable to identify current directory."); - Context::new_with_dir(arguments, current_dir) + // Retreive the "path" flag. If unavailable, use the current directory instead. + let path = arguments + .value_of("path") + .map(From::from) + .unwrap_or_else(|| env::current_dir().expect("Unable to identify current directory.")); + + Context::new_with_dir(arguments, path) } - #[allow(dead_code)] pub fn new_with_dir(arguments: ArgMatches, dir: T) -> Context where T: Into, diff --git a/src/main.rs b/src/main.rs index 1f69d4ed..4707cd81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,36 +1,77 @@ #[macro_use] extern crate clap; -extern crate ansi_term; -extern crate battery; -extern crate dirs; -extern crate git2; -extern crate pretty_env_logger; - mod context; mod module; mod modules; mod print; mod segment; -use clap::{App, Arg}; +use clap::{App, Arg, SubCommand}; fn main() { pretty_env_logger::init(); - let args = App::new("Starship") + let matches = App::new("Starship") .about("The cross-shell prompt for astronauts. ✨🚀") // pull the version number from Cargo.toml .version(crate_version!()) // pull the authors from Cargo.toml .author(crate_authors!()) .after_help("https://github.com/matchai/starship") - .arg( - Arg::with_name("status_code") - .help("The status code of the previously run command") - .required(true), + .subcommand( + SubCommand::with_name("prompt") + .about("Prints the full starship prompt") + .arg( + Arg::with_name("status_code") + .short("s") + .long("status") + .value_name("STATUS_CODE") + .help("The status code of the previously run command") + .takes_value(true), + ) + .arg( + Arg::with_name("path") + .short("p") + .long("path") + .value_name("PATH") + .help("The path that the prompt should render for ($PWD by default)") + .takes_value(true), + ), + ) + .subcommand( + SubCommand::with_name("module") + .about("Prints a specific prompt module") + .arg( + Arg::with_name("name") + .help("The name of the module to be printed") + .required(true), + ) + .arg( + Arg::with_name("status_code") + .short("s") + .long("status") + .value_name("STATUS_CODE") + .help("The status code of the previously run command") + .takes_value(true), + ) + .arg( + Arg::with_name("path") + .short("p") + .long("path") + .value_name("PATH") + .help("The path the prompt should render for ($PWD by default)") + .takes_value(true), + ), ) .get_matches(); - print::prompt(args); + match matches.subcommand() { + ("prompt", Some(sub_m)) => print::prompt(sub_m.clone()), + ("module", Some(sub_m)) => { + let module_name = sub_m.value_of("name").expect("Module name missing."); + print::module(module_name, sub_m.clone()); + } + _ => {} + } } diff --git a/src/modules/character.rs b/src/modules/character.rs index 2a933489..1dfc2799 100644 --- a/src/modules/character.rs +++ b/src/modules/character.rs @@ -20,7 +20,7 @@ pub fn segment(context: &Context) -> Option { let symbol = module.new_segment("symbol", PROMPT_CHAR); let arguments = &context.arguments; - if arguments.value_of("status_code").unwrap() == "0" { + if arguments.value_of("status_code").unwrap_or("0") == "0" { symbol.set_style(color_success.bold()); } else { symbol.set_style(color_failure.bold()); diff --git a/src/print.rs b/src/print.rs index 53442f23..71d453e3 100644 --- a/src/print.rs +++ b/src/print.rs @@ -46,3 +46,14 @@ pub fn prompt(args: ArgMatches) { // Print all remaining modules printable.for_each(|module| write!(handle, "{}", module).unwrap()); } + +pub fn module(module_name: &str, args: ArgMatches) { + let context = Context::new(args); + + // If the module returns `None`, print an empty string + let module = modules::handle(module_name, &context) + .map(|m| m.to_string()) + .unwrap_or_default(); + + print!("{}", module); +} diff --git a/tests/Dockerfile b/tests/Dockerfile index 532b42dc..4d1cd321 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -1,9 +1,5 @@ FROM rust -# Install Tarpaulin (code coverage tool) -# https://github.com/xd009642/tarpaulin -COPY --from=xd009642/tarpaulin /usr/local/cargo/bin/cargo-tarpaulin /usr/local/cargo/bin/cargo-tarpaulin - # Install Node.js ENV NODE_VERSION 12.0.0 ENV PATH /root/.nvm/versions/node/v$NODE_VERSION/bin:$PATH @@ -54,5 +50,4 @@ RUN rm -rf /starship RUN mkdir starship WORKDIR /starship -# Instrument coverage tooling and run the full test suite -CMD ["cargo", "tarpaulin", "--ignored", "--out", "Xml"] +CMD ["cargo", "test", "--", "--ignored"] diff --git a/tests/character.rs b/tests/character.rs deleted file mode 100644 index be0b1a8e..00000000 --- a/tests/character.rs +++ /dev/null @@ -1,20 +0,0 @@ -use ansi_term::Color; -use std::path::Path; - -mod common; - -#[test] -fn char_module_success_status() { - let dir = Path::new("~"); - let expected = format!("{} ", Color::Green.bold().paint("➜")); - let actual = common::render_module_with_status("char", &dir, "0"); - assert_eq!(expected, actual); -} - -#[test] -fn char_module_failure_status() { - let dir = Path::new("~"); - let expected = format!("{} ", Color::Red.bold().paint("➜")); - let actual = common::render_module_with_status("char", &dir, "1"); - assert_eq!(expected, actual); -} diff --git a/tests/common.rs b/tests/common.rs deleted file mode 100644 index 2d2cd2a0..00000000 --- a/tests/common.rs +++ /dev/null @@ -1,27 +0,0 @@ -use clap::{App, Arg}; -use starship::context::Context; -use starship::modules; -use std::path::PathBuf; - -#[allow(dead_code)] -pub fn render_module(module: &str, path: T) -> String -where - T: Into, -{ - render_module_with_status(module, path.into(), "0") -} - -pub fn render_module_with_status(module: &str, path: T, status: &str) -> String -where - T: Into, -{ - // Create an `Arg` with status_code of "0" - let args = App::new("starship") - .arg(Arg::with_name("status_code")) - .get_matches_from(vec!["starship", status]); - let context = Context::new_with_dir(args, path.into()); - - let module = modules::handle(module, &context); - - module.unwrap().to_string() -} diff --git a/tests/directory.rs b/tests/directory.rs deleted file mode 100644 index 42d6398a..00000000 --- a/tests/directory.rs +++ /dev/null @@ -1,158 +0,0 @@ -use ansi_term::Color; -use dirs::home_dir; -use git2::Repository; -use std::fs; -use std::io; -use std::path::Path; -use tempfile::TempDir; - -mod common; - -#[test] -fn home_directory() -> io::Result<()> { - let dir = Path::new("~"); - - let expected = format!("in {} ", Color::Cyan.bold().paint("~").to_string()); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn directory_in_home() -> io::Result<()> { - let dir = home_dir().unwrap().join("starship/engine"); - fs::create_dir_all(&dir)?; - - let expected = format!( - "in {} ", - Color::Cyan.bold().paint("~/starship/engine").to_string() - ); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn truncated_directory_in_home() -> io::Result<()> { - let dir = home_dir().unwrap().join("starship/engine/schematics"); - fs::create_dir_all(&dir)?; - - let expected = format!( - "in {} ", - Color::Cyan - .bold() - .paint("starship/engine/schematics") - .to_string() - ); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -fn root_directory() -> io::Result<()> { - let dir = Path::new("/"); - - let expected = format!("in {} ", Color::Cyan.bold().paint("/").to_string()); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -fn directory_in_root() -> io::Result<()> { - let dir = Path::new("/tmp"); - - let expected = format!("in {} ", Color::Cyan.bold().paint("/tmp").to_string()); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn truncated_directory_in_root() -> io::Result<()> { - let dir = Path::new("/tmp/starship/thrusters/rocket"); - fs::create_dir_all(&dir)?; - - let expected = format!( - "in {} ", - Color::Cyan - .bold() - .paint("starship/thrusters/rocket") - .to_string() - ); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn git_repo_root() -> io::Result<()> { - let tmp_dir = TempDir::new_in(home_dir().unwrap())?; - let repo_dir = tmp_dir.path().join("rocket-controls"); - fs::create_dir(&repo_dir)?; - - Repository::init(&repo_dir).unwrap(); - - let expected = format!( - "in {} ", - Color::Cyan.bold().paint("rocket-controls").to_string() - ); - let actual = common::render_module("dir", &repo_dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn directory_in_git_repo() -> io::Result<()> { - let tmp_dir = TempDir::new_in(home_dir().unwrap())?; - let repo_dir = tmp_dir.path().join("rocket-controls"); - let dir = repo_dir.join("src"); - fs::create_dir_all(&dir)?; - - Repository::init(&repo_dir).unwrap(); - - let expected = format!( - "in {} ", - Color::Cyan.bold().paint("rocket-controls/src").to_string() - ); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn truncated_directory_in_git_repo() -> io::Result<()> { - let tmp_dir = TempDir::new()?; - let repo_dir = tmp_dir.path().join("rocket-controls"); - let dir = repo_dir.join("src/meters/fuel-gauge"); - fs::create_dir_all(&dir)?; - - Repository::init(&repo_dir).unwrap(); - - let expected = format!( - "in {} ", - Color::Cyan - .bold() - .paint("src/meters/fuel-gauge") - .to_string() - ); - let actual = common::render_module("dir", &dir); - assert_eq!(expected, actual); - - Ok(()) -} diff --git a/tests/go.rs b/tests/go.rs deleted file mode 100644 index 369530ab..00000000 --- a/tests/go.rs +++ /dev/null @@ -1,134 +0,0 @@ -use ansi_term::Color; -use starship::segment::Segment; -use std::fs::{self, File}; -use std::io; -use tempfile::TempDir; - -mod common; - -#[test] -#[ignore] -fn folder_with_go_file() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("main.go"))?; - - let expected = format!( - "via {} ", - Segment::new("go") - .set_value("🐹 v1.10") - .set_style(Color::Cyan.bold()) - ); - let actual = common::render_module("go", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_go_mod() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("go.mod"))?; - - let expected = format!( - "via {} ", - Segment::new("go") - .set_value("🐹 v1.10") - .set_style(Color::Cyan.bold()) - ); - let actual = common::render_module("go", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_go_sum() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("go.sum"))?; - - let expected = format!( - "via {} ", - Segment::new("go") - .set_value("🐹 v1.10") - .set_style(Color::Cyan.bold()) - ); - let actual = common::render_module("go", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_godeps() -> io::Result<()> { - let dir = TempDir::new()?; - let godeps = dir.path().join("Godeps"); - fs::create_dir_all(&godeps)?; - - let expected = format!( - "via {} ", - Segment::new("go") - .set_value("🐹 v1.10") - .set_style(Color::Cyan.bold()) - ); - let actual = common::render_module("go", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_glide_yaml() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("glide.yaml"))?; - - let expected = format!( - "via {} ", - Segment::new("go") - .set_value("🐹 v1.10") - .set_style(Color::Cyan.bold()) - ); - let actual = common::render_module("go", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_gopkg_yml() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("Gopkg.yml"))?; - - let expected = format!( - "via {} ", - Segment::new("go") - .set_value("🐹 v1.10") - .set_style(Color::Cyan.bold()) - ); - let actual = common::render_module("go", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_gopkg_lock() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("Gopkg.lock"))?; - - let expected = format!( - "via {} ", - Segment::new("go") - .set_value("🐹 v1.10") - .set_style(Color::Cyan.bold()) - ); - let actual = common::render_module("go", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} diff --git a/tests/nodejs.rs b/tests/nodejs.rs deleted file mode 100644 index 38bca73b..00000000 --- a/tests/nodejs.rs +++ /dev/null @@ -1,62 +0,0 @@ -use ansi_term::Color; -use starship::segment::Segment; -use std::fs::{self, File}; -use std::io; -use tempfile::TempDir; - -mod common; - -#[test] -#[ignore] -fn folder_with_package_json() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("package.json"))?; - - let expected = format!( - "via {} ", - Segment::new("node") - .set_value("⬢ v12.0.0") - .set_style(Color::Green.bold()) - ); - let actual = common::render_module("nodejs", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_js_file() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("index.js"))?; - - let expected = format!( - "via {} ", - Segment::new("node") - .set_value("⬢ v12.0.0") - .set_style(Color::Green.bold()) - ); - let actual = common::render_module("nodejs", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_node_modules() -> io::Result<()> { - let dir = TempDir::new()?; - let node_modules = dir.path().join("node_modules"); - fs::create_dir_all(&node_modules)?; - - let expected = format!( - "via {} ", - Segment::new("node") - .set_value("⬢ v12.0.0") - .set_style(Color::Green.bold()) - ); - let actual = common::render_module("nodejs", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} diff --git a/tests/python.rs b/tests/python.rs deleted file mode 100644 index 237c1f30..00000000 --- a/tests/python.rs +++ /dev/null @@ -1,79 +0,0 @@ -use ansi_term::Color; -use starship::segment::Segment; -use std::fs::File; -use std::io; -use tempfile::TempDir; - -mod common; - -#[test] -#[ignore] -fn folder_with_python_version() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join(".python-version"))?; - - let expected = format!( - "via {} ", - Segment::new("python") - .set_value("🐍 v3.6.8") - .set_style(Color::Yellow.bold()) - ); - let actual = common::render_module("python", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_requirements_txt() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("requirements.txt"))?; - - let expected = format!( - "via {} ", - Segment::new("python") - .set_value("🐍 v3.6.8") - .set_style(Color::Yellow.bold()) - ); - let actual = common::render_module("python", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_pyproject_toml() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("pyproject.toml"))?; - - let expected = format!( - "via {} ", - Segment::new("python") - .set_value("🐍 v3.6.8") - .set_style(Color::Yellow.bold()) - ); - let actual = common::render_module("python", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} - -#[test] -#[ignore] -fn folder_with_py_file() -> io::Result<()> { - let dir = TempDir::new()?; - File::create(dir.path().join("main.py"))?; - - let expected = format!( - "via {} ", - Segment::new("python") - .set_value("🐍 v3.6.8") - .set_style(Color::Yellow.bold()) - ); - let actual = common::render_module("python", &dir.path()); - assert_eq!(expected, actual); - - Ok(()) -} diff --git a/tests/testsuite/character.rs b/tests/testsuite/character.rs new file mode 100644 index 00000000..80a12bd3 --- /dev/null +++ b/tests/testsuite/character.rs @@ -0,0 +1,47 @@ +use ansi_term::Color; +use std::io; + +use crate::common; + +#[test] +fn char_module_success_status() -> io::Result<()> { + let expected = format!("{} ", Color::Green.bold().paint("➜")); + + // Status code 0 + let output = common::render_module("char").arg("--status=0").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + // No status code + let output = common::render_module("char").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +fn char_module_failure_status() -> io::Result<()> { + let expected = format!("{} ", Color::Red.bold().paint("➜")); + + // Error status code 1 + let output = common::render_module("char").arg("--status=1").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + // Random non-zero status code + let output = common::render_module("char") + .arg("--status=54321") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + // Negative status code!? + let output = common::render_module("char") + .arg("--status=-5000") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + Ok(()) +} diff --git a/tests/testsuite/common.rs b/tests/testsuite/common.rs new file mode 100644 index 00000000..45188028 --- /dev/null +++ b/tests/testsuite/common.rs @@ -0,0 +1,22 @@ +use std::{io, process}; + +pub fn render_prompt() -> process::Command { + let mut command = process::Command::new("./target/debug/starship"); + command.arg("prompt"); + + command +} + +pub fn render_module(module_name: &str) -> process::Command { + let mut command = process::Command::new("./target/debug/starship"); + command.arg("module").arg(module_name); + + command +} + +/// Create a temporary directory with full access permissions (rwxrwxrwt). +pub fn new_tempdir() -> io::Result { + // Using `tempfile::TempDir` directly creates files on macOS within + // "/var/folders", which provides us with restricted permissions (rwxr-xr-x) + tempfile::tempdir_in("/tmp") +} diff --git a/tests/testsuite/directory.rs b/tests/testsuite/directory.rs new file mode 100644 index 00000000..8835b844 --- /dev/null +++ b/tests/testsuite/directory.rs @@ -0,0 +1,158 @@ +use ansi_term::Color; +use dirs::home_dir; +use git2::Repository; +use std::fs; +use std::io; +use std::path::Path; +use tempfile::TempDir; + +use crate::common; + +#[test] +fn home_directory() -> io::Result<()> { + let output = common::render_module("dir").arg("--path=~").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("in {} ", Color::Cyan.bold().paint("~")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn directory_in_home() -> io::Result<()> { + let dir = home_dir().unwrap().join("starship/engine"); + fs::create_dir_all(&dir)?; + + let output = common::render_module("dir") + .arg("--path") + .arg(dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("in {} ", Color::Cyan.bold().paint("~/starship/engine")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn truncated_directory_in_home() -> io::Result<()> { + let dir = home_dir().unwrap().join("starship/engine/schematics"); + fs::create_dir_all(&dir)?; + + let output = common::render_module("dir") + .arg("--path") + .arg(dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!( + "in {} ", + Color::Cyan.bold().paint("starship/engine/schematics") + ); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn root_directory() -> io::Result<()> { + let output = common::render_module("dir").arg("--path=/").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("in {} ", Color::Cyan.bold().paint("/")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn directory_in_root() -> io::Result<()> { + let output = common::render_module("dir").arg("--path=/tmp").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("in {} ", Color::Cyan.bold().paint("/tmp")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn truncated_directory_in_root() -> io::Result<()> { + let dir = Path::new("/tmp/starship/thrusters/rocket"); + fs::create_dir_all(&dir)?; + + let output = common::render_module("dir") + .arg("--path") + .arg(dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!( + "in {} ", + Color::Cyan.bold().paint("starship/thrusters/rocket") + ); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn git_repo_root() -> io::Result<()> { + // TODO: Investigate why git repo related tests fail when the tempdir is within /tmp/... + // Temporarily making the tempdir within $HOME + // #[ignore] can be removed after this TODO is addressed + let tmp_dir = TempDir::new_in(dirs::home_dir().unwrap())?; + let repo_dir = tmp_dir.path().join("rocket-controls"); + fs::create_dir(&repo_dir)?; + Repository::init(&repo_dir).unwrap(); + + let output = common::render_module("dir") + .arg("--path") + .arg(repo_dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("in {} ", Color::Cyan.bold().paint("rocket-controls")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn directory_in_git_repo() -> io::Result<()> { + let tmp_dir = TempDir::new_in(dirs::home_dir().unwrap())?; + let repo_dir = tmp_dir.path().join("rocket-controls"); + let dir = repo_dir.join("src"); + fs::create_dir_all(&dir)?; + Repository::init(&repo_dir).unwrap(); + + let output = common::render_module("dir") + .arg("--path") + .arg(dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("in {} ", Color::Cyan.bold().paint("rocket-controls/src")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn truncated_directory_in_git_repo() -> io::Result<()> { + let tmp_dir = TempDir::new_in(dirs::home_dir().unwrap())?; + let repo_dir = tmp_dir.path().join("rocket-controls"); + let dir = repo_dir.join("src/meters/fuel-gauge"); + fs::create_dir_all(&dir)?; + Repository::init(&repo_dir).unwrap(); + + let output = common::render_module("dir") + .arg("--path") + .arg(dir) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("in {} ", Color::Cyan.bold().paint("src/meters/fuel-gauge")); + assert_eq!(expected, actual); + Ok(()) +} diff --git a/tests/testsuite/golang.rs b/tests/testsuite/golang.rs new file mode 100644 index 00000000..6419eefb --- /dev/null +++ b/tests/testsuite/golang.rs @@ -0,0 +1,140 @@ +use ansi_term::Color; +use std::fs::{self, File}; +use std::io; + +use crate::common; + +#[test] +fn folder_without_go_files() -> io::Result<()> { + let dir = common::new_tempdir()?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = ""; + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_go_file() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("main.go"))?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_go_mod() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("go.mod"))?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_go_sum() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("go.sum"))?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_godeps() -> io::Result<()> { + let dir = common::new_tempdir()?; + let godeps = dir.path().join("Godeps"); + fs::create_dir_all(&godeps)?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_glide_yaml() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("glide.yaml"))?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_gopkg_yml() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("Gopkg.yml"))?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_gopkg_lock() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("Gopkg.lock"))?; + + let output = common::render_module("golang") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10")); + assert_eq!(expected, actual); + Ok(()) +} diff --git a/tests/testsuite/line_break.rs b/tests/testsuite/line_break.rs new file mode 100644 index 00000000..5806ca11 --- /dev/null +++ b/tests/testsuite/line_break.rs @@ -0,0 +1,13 @@ +use std::io; + +use crate::common; + +#[test] +fn line_break_module() -> io::Result<()> { + let output = common::render_module("line_break").output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = "\n"; + assert_eq!(expected, actual); + Ok(()) +} diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs new file mode 100644 index 00000000..1705ae3a --- /dev/null +++ b/tests/testsuite/main.rs @@ -0,0 +1,8 @@ +mod character; +mod common; +mod directory; +mod golang; +mod line_break; +mod nodejs; +mod python; +mod username; diff --git a/tests/testsuite/nodejs.rs b/tests/testsuite/nodejs.rs new file mode 100644 index 00000000..33b0df2a --- /dev/null +++ b/tests/testsuite/nodejs.rs @@ -0,0 +1,72 @@ +use ansi_term::Color; +use std::fs::{self, File}; +use std::io; + +use crate::common; + +#[test] +fn folder_without_node_files() -> io::Result<()> { + let dir = common::new_tempdir()?; + + let output = common::render_module("nodejs") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = ""; + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_package_json() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("package.json"))?; + + let output = common::render_module("nodejs") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Green.bold().paint("⬢ v12.0.0")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_js_file() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("index.js"))?; + + let output = common::render_module("nodejs") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Green.bold().paint("⬢ v12.0.0")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_node_modules() -> io::Result<()> { + let dir = common::new_tempdir()?; + let node_modules = dir.path().join("node_modules"); + fs::create_dir_all(&node_modules)?; + + let output = common::render_module("nodejs") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Green.bold().paint("⬢ v12.0.0")); + assert_eq!(expected, actual); + Ok(()) +} diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs new file mode 100644 index 00000000..e69de29b diff --git a/tests/testsuite/python.rs b/tests/testsuite/python.rs new file mode 100644 index 00000000..7a68a916 --- /dev/null +++ b/tests/testsuite/python.rs @@ -0,0 +1,73 @@ +use ansi_term::Color; +use std::fs::File; +use std::io; + +use crate::common; + +#[test] +#[ignore] +fn folder_with_python_version() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join(".python-version"))?; + + let output = common::render_module("python") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.6.8")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_requirements_txt() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("requirements.txt"))?; + + let output = common::render_module("python") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.6.8")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_pyproject_toml() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("pyproject.toml"))?; + + let output = common::render_module("python") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.6.8")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +#[ignore] +fn folder_with_py_file() -> io::Result<()> { + let dir = common::new_tempdir()?; + File::create(dir.path().join("main.py"))?; + + let output = common::render_module("python") + .arg("--path") + .arg(dir.path()) + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.6.8")); + assert_eq!(expected, actual); + Ok(()) +} diff --git a/tests/testsuite/username.rs b/tests/testsuite/username.rs new file mode 100644 index 00000000..c046efef --- /dev/null +++ b/tests/testsuite/username.rs @@ -0,0 +1,64 @@ +use ansi_term::Color; +use std::io; + +use crate::common; + +// TODO: Add tests for if root user (UID == 0) +// Requires mocking + +#[test] +fn no_username_shown() -> io::Result<()> { + let expected = ""; + + // No environment variables + let output = common::render_module("username").env_clear().output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + // LOGNAME == USER + let output = common::render_module("username") + .env_clear() + .env("LOGNAME", "astronaut") + .env("USER", "astronaut") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + // SSH connection w/o username + let output = common::render_module("username") + .env_clear() + .env("SSH_CONNECTION", "192.168.223.17 36673 192.168.223.229 22") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + assert_eq!(expected, actual); + + Ok(()) +} + +#[test] +fn current_user_not_logname() -> io::Result<()> { + let output = common::render_module("username") + .env_clear() + .env("LOGNAME", "astronaut") + .env("USER", "cosmonaut") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Yellow.bold().paint("cosmonaut")); + assert_eq!(expected, actual); + Ok(()) +} + +#[test] +fn ssh_connection() -> io::Result<()> { + let output = common::render_module("username") + .env_clear() + .env("USER", "astronaut") + .env("SSH_CONNECTION", "192.168.223.17 36673 192.168.223.229 22") + .output()?; + let actual = String::from_utf8(output.stdout).unwrap(); + + let expected = format!("via {} ", Color::Yellow.bold().paint("astronaut")); + assert_eq!(expected, actual); + Ok(()) +}