gitlab_clippy 1.0.1

Convert clippy warnings into GitLab Code Quality report
Documentation
extern crate assert_cmd;
extern crate predicates;
extern crate tempfile;

use assert_cmd::Command;
use predicates::path;
use predicates::prelude::*;
use predicates::str;
use std::path::Path;
use tempfile::Builder;

struct GitlabClippy {}

impl GitlabClippy {
    fn new() -> Command {
        let mut command = Command::cargo_bin("gitlab-clippy").unwrap();
        command.env_clear();
        command
    }

    fn new_with_input<P>(file: P) -> Command
    where
        P: AsRef<Path>,
    {
        let mut command = GitlabClippy::new();
        match command.pipe_stdin(&file) {
            Ok(_) => command,
            Err(e) => panic!(
                "Error opening file input {}: {}",
                file.as_ref().display(),
                e
            ),
        }
    }

    fn new_from_clippy(file: &str) -> Command {
        let mut command = Command::cargo_bin("gitlab-clippy").unwrap();
        let clippy = Command::new("cargo")
            .args(&["clippy", "--example", file, "--message-format=json"])
            .output()
            .unwrap();
        command.write_stdin(clippy.stdout);
        command.env_clear();
        command
    }
}

#[test]
fn converts_valid_input_from_stdin() {
    let expected_output = path::eq_file("tests/fixtures/valid.json");
    GitlabClippy::new_with_input("tests/fixtures/valid.txt")
        .assert()
        .success()
        .stderr(str::is_empty())
        .stdout(expected_output);
}

#[test]
fn converts_valid_input_file() {
    let expected_output = path::eq_file("tests/fixtures/valid.json");
    GitlabClippy::new()
        .arg("tests/fixtures/valid.txt")
        .assert()
        .success()
        .stderr(str::is_empty())
        .stdout(expected_output);
}

#[test]
fn converts_valid_input_to_file() {
    let output = {
        let tempfile = Builder::new().suffix(".json").tempfile().unwrap();
        tempfile.path().to_path_buf()
    };
    assert!(path::is_file().not().eval(&output));

    GitlabClippy::new_with_input("tests/fixtures/valid.txt")
        .arg("-o")
        .arg(&output)
        .assert()
        .success()
        .stderr(str::is_empty())
        .stdout(str::is_empty());

    let expected = path::eq_file("tests/fixtures/valid.json");
    assert!(expected.eval(output.as_path()));

    std::fs::remove_file(&output).unwrap();
}

#[test]
fn chokes_on_invalid_input() {
    GitlabClippy::new_with_input("tests/fixtures/invalid.txt")
        .assert()
        .failure()
        .stderr(str::contains("Error"))
        .stdout(str::is_empty());
}

#[test]
fn accepts_version_option() {
    let expected_output = format!("gitlab-clippy {}", env!("CARGO_PKG_VERSION"));
    GitlabClippy::new()
        .arg("--version")
        .assert()
        .success()
        .stderr(str::is_empty())
        .stdout(str::similar(expected_output).trim());
}

#[test]
fn converts_warnings_from_pipe() {
    let two_occurences = str::contains("examples/warn.rs").count(2);
    let redundant_field_names = str::contains("redundant field names in struct initialization");
    let blacklisted_placeholder = str::contains("use of a blacklisted/placeholder name `foo`");

    GitlabClippy::new_from_clippy("warn")
        .assert()
        .success()
        .stderr(str::is_empty())
        .stdout(
            two_occurences
                .and(redundant_field_names)
                .and(blacklisted_placeholder),
        );
}

#[test]
fn converts_error_from_pipe() {
    GitlabClippy::new_from_clippy("error")
        .assert()
        .success()
        .stderr(str::is_empty())
        .stdout(str::contains(
            "doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead",
        ));
}