]> git.lizzy.rs Git - rust.git/blobdiff - src/test/mod.rs
Refactoring: summary
[rust.git] / src / test / mod.rs
index c58989508130355b7a90b2753aa7f3f9002eef4b..d670bc1d5dbf7f7a8989300464cf3a70ccdc7eda 100644 (file)
 
 extern crate assert_cli;
 
+use syntax;
+
 use std::collections::{HashMap, HashSet};
+use std::env;
 use std::fs;
-use std::io::{self, BufRead, BufReader, Read};
+use std::io::{self, BufRead, BufReader, Read, Write};
 use std::iter::{Enumerate, Peekable};
 use std::path::{Path, PathBuf};
 use std::str::Chars;
 
-use config::summary::Summary;
-use config::{Color, Config, ReportTactic};
-use filemap::write_system_newlines;
-use rustfmt_diff::*;
-use *;
+use config::{Color, Config, EmitMode, FileName, ReportTactic};
+use filemap;
+use formatting::{FileMap, ModifiedChunk, Summary};
+use rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, OutputWriter};
+use {FormatReport, Input, Session};
 
 const DIFF_CONTEXT_SIZE: usize = 3;
 const CONFIGURATIONS_FILE_NAME: &str = "Configurations.md";
@@ -111,7 +114,7 @@ fn write_message(msg: &str) {
 fn system_tests() {
     // Get all files in the tests/source directory.
     let files = get_test_files(Path::new("tests/source"), true);
-    let (_reports, count, fails) = check_files(files);
+    let (_reports, count, fails) = check_files(files, None);
 
     // Display results.
     println!("Ran {} system tests.", count);
@@ -123,7 +126,7 @@ fn system_tests() {
 #[test]
 fn coverage_tests() {
     let files = get_test_files(Path::new("tests/coverage/source"), true);
-    let (_reports, count, fails) = check_files(files);
+    let (_reports, count, fails) = check_files(files, None);
 
     println!("Ran {} tests in coverage mode.", count);
     assert_eq!(fails, 0, "{} tests failed", fails);
@@ -138,25 +141,56 @@ fn checkstyle_test() {
 
 #[test]
 fn modified_test() {
+    use std::io::BufRead;
+
     // Test "modified" output
     let filename = "tests/writemode/source/modified.rs";
-    let result = get_modified_lines(Input::File(filename.into()), &Config::default()).unwrap();
-    assert_eq!(
-        result.modified_lines,
-        ModifiedLines {
-            chunks: vec![
-                ModifiedChunk {
-                    line_number_orig: 4,
-                    lines_removed: 4,
-                    lines: vec!["fn blah() {}".into()],
-                },
-                ModifiedChunk {
-                    line_number_orig: 9,
-                    lines_removed: 6,
-                    lines: vec!["#[cfg(a, b)]".into(), "fn main() {}".into()],
-                },
-            ],
+    let mut data = Vec::new();
+    let mut config = Config::default();
+    config.set().emit_mode(::config::EmitMode::ModifiedLines);
+
+    {
+        let mut session = Session::new(config, Some(&mut data));
+        session.format(Input::File(filename.into())).unwrap();
+    }
+
+    let mut lines = data.lines();
+    let mut chunks = Vec::new();
+    while let Some(Ok(header)) = lines.next() {
+        // Parse the header line
+        let values: Vec<_> = header
+            .split(' ')
+            .map(|s| s.parse::<u32>().unwrap())
+            .collect();
+        assert_eq!(values.len(), 3);
+        let line_number_orig = values[0];
+        let lines_removed = values[1];
+        let num_added = values[2];
+        let mut added_lines = Vec::new();
+        for _ in 0..num_added {
+            added_lines.push(lines.next().unwrap().unwrap());
         }
+        chunks.push(ModifiedChunk {
+            line_number_orig,
+            lines_removed,
+            lines: added_lines,
+        });
+    }
+
+    assert_eq!(
+        chunks,
+        vec![
+            ModifiedChunk {
+                line_number_orig: 4,
+                lines_removed: 4,
+                lines: vec!["fn blah() {}".into()],
+            },
+            ModifiedChunk {
+                line_number_orig: 9,
+                lines_removed: 6,
+                lines: vec!["#[cfg(a, b)]".into(), "fn main() {}".into()],
+            },
+        ],
     );
 }
 
@@ -164,7 +198,7 @@ fn modified_test() {
 // to a known output file generated by one of the write modes.
 fn assert_output(source: &Path, expected_filename: &Path) {
     let config = read_config(source);
-    let (_error_summary, file_map, _report) = format_file(source, &config);
+    let (_, file_map, _) = format_file(source, config.clone());
 
     // Populate output by writing to a vec.
     let mut out = vec![];
@@ -190,9 +224,13 @@ fn assert_output(source: &Path, expected_filename: &Path) {
 // rustfmt.
 #[test]
 fn idempotence_tests() {
+    match option_env!("CFG_RELEASE_CHANNEL") {
+        None | Some("nightly") => {}
+        _ => return, // these tests require nightly
+    }
     // Get all files in the tests/target directory.
     let files = get_test_files(Path::new("tests/target"), true);
-    let (_reports, count, fails) = check_files(files);
+    let (_reports, count, fails) = check_files(files, None);
 
     // Display results.
     println!("Ran {} idempotent tests.", count);
@@ -213,7 +251,7 @@ fn self_tests() {
     }
     files.push(PathBuf::from("src/lib.rs"));
 
-    let (reports, count, fails) = check_files(files);
+    let (reports, count, fails) = check_files(files, Some(PathBuf::from("rustfmt.toml")));
     let mut warnings = 0;
 
     // Display results.
@@ -232,39 +270,22 @@ fn self_tests() {
     );
 }
 
-#[test]
-fn issue_2673_non_modrs_mods() {
-    match idempotent_check(&PathBuf::from("tests/issue-2673-nonmodrs-mods/lib.rs")) {
-        Ok(ref report) if report.has_warnings() => {
-            print!("{}", report);
-            panic!("had warnings");
-        }
-        Ok(_report) => {}
-        Err(err) => {
-            if let IdempotentCheckError::Mismatch(msg) = err {
-                print_mismatches_default_message(msg);
-            }
-            panic!("had errors");
-        }
-    }
-}
-
 #[test]
 fn stdin_formatting_smoke_test() {
     let input = Input::Text("fn main () {}".to_owned());
-    let config = Config::default();
-    let (error_summary, file_map, _report) =
-        format_input::<io::Stdout>(input, &config, None).unwrap();
-    assert!(error_summary.has_no_errors());
-    for &(ref file_name, ref text) in &file_map {
-        if let FileName::Custom(ref file_name) = *file_name {
-            if file_name == "stdin" {
-                assert_eq!(text.to_string(), "fn main() {}\n");
-                return;
-            }
-        }
+    let mut config = Config::default();
+    config.set().emit_mode(EmitMode::Stdout);
+    let mut buf: Vec<u8> = vec![];
+    {
+        let mut session = Session::new(config, Some(&mut buf));
+        session.format(input).unwrap();
+        assert!(session.summary.has_no_errors());
     }
-    panic!("no stdin");
+    //eprintln!("{:?}", );
+    #[cfg(not(windows))]
+    assert_eq!(buf, "fn main() {}\n".as_bytes());
+    #[cfg(windows)]
+    assert_eq!(buf, "fn main() {}\r\n".as_bytes());
 }
 
 // FIXME(#1990) restore this test
@@ -296,9 +317,9 @@ fn format_lines_errors_are_reported() {
     let input = Input::Text(format!("fn {}() {{}}", long_identifier));
     let mut config = Config::default();
     config.set().error_on_line_overflow(true);
-    let (error_summary, _file_map, _report) =
-        format_input::<io::Stdout>(input, &config, None).unwrap();
-    assert!(error_summary.has_formatting_errors());
+    let mut session = Session::<io::Stdout>::new(config, None);
+    session.format(input).unwrap();
+    assert!(session.summary.has_formatting_errors());
 }
 
 #[test]
@@ -308,14 +329,14 @@ fn format_lines_errors_are_reported_with_tabs() {
     let mut config = Config::default();
     config.set().error_on_line_overflow(true);
     config.set().hard_tabs(true);
-    let (error_summary, _file_map, _report) =
-        format_input::<io::Stdout>(input, &config, None).unwrap();
-    assert!(error_summary.has_formatting_errors());
+    let mut session = Session::<io::Stdout>::new(config, None);
+    session.format(input).unwrap();
+    assert!(session.summary.has_formatting_errors());
 }
 
 // For each file, run rustfmt and collect the output.
 // Returns the number of files checked and the number of failures.
-fn check_files(files: Vec<PathBuf>) -> (Vec<FormatReport>, u32, u32) {
+fn check_files(files: Vec<PathBuf>, opt_config: Option<PathBuf>) -> (Vec<FormatReport>, u32, u32) {
     let mut count = 0;
     let mut fails = 0;
     let mut reports = vec![];
@@ -323,7 +344,7 @@ fn check_files(files: Vec<PathBuf>) -> (Vec<FormatReport>, u32, u32) {
     for file_name in files {
         debug!("Testing '{}'...", file_name.display());
 
-        match idempotent_check(&file_name) {
+        match idempotent_check(&file_name, &opt_config) {
             Ok(ref report) if report.has_warnings() => {
                 print!("{}", report);
                 fails += 1;
@@ -382,6 +403,9 @@ fn read_config(filename: &Path) -> Config {
     for (key, val) in &sig_comments {
         if key != "target" && key != "config" {
             config.override_value(key, val);
+            if config.is_default(key) {
+                warn!("Default value {} used explicitly for {}", val, key);
+            }
         }
     }
 
@@ -391,34 +415,41 @@ fn read_config(filename: &Path) -> Config {
     config
 }
 
-fn format_file<P: Into<PathBuf>>(filepath: P, config: &Config) -> (Summary, FileMap, FormatReport) {
+fn format_file<P: Into<PathBuf>>(filepath: P, config: Config) -> (bool, FileMap, FormatReport) {
     let filepath = filepath.into();
     let input = Input::File(filepath);
-    format_input::<io::Stdout>(input, config, None).unwrap()
+    let mut session = Session::<io::Stdout>::new(config, None);
+    syntax::with_globals(|| {
+        let result = session.format_input_inner(input).unwrap();
+        let parsing_errors = session.summary.has_parsing_errors();
+        (parsing_errors, result.0, result.1)
+    })
 }
 
-pub enum IdempotentCheckError {
+enum IdempotentCheckError {
     Mismatch(HashMap<PathBuf, Vec<Mismatch>>),
     Parse,
 }
 
-pub fn idempotent_check(filename: &PathBuf) -> Result<FormatReport, IdempotentCheckError> {
+fn idempotent_check(
+    filename: &PathBuf,
+    opt_config: &Option<PathBuf>,
+) -> Result<FormatReport, IdempotentCheckError> {
     let sig_comments = read_significant_comments(filename);
-    let config = read_config(filename);
-    let (error_summary, file_map, format_report) = format_file(filename, &config);
-    if error_summary.has_parsing_errors() {
+    let config = if let Some(ref config_file_path) = opt_config {
+        Config::from_toml_path(config_file_path).expect("rustfmt.toml not found")
+    } else {
+        read_config(filename)
+    };
+    let (parsing_errors, file_map, format_report) = format_file(filename, config);
+    if parsing_errors {
         return Err(IdempotentCheckError::Parse);
     }
 
     let mut write_result = HashMap::new();
-    for &(ref filename, ref text) in &file_map {
-        let mut v = Vec::new();
-        // Won't panic, as we're not doing any IO.
-        write_system_newlines(&mut v, text, &config).unwrap();
-        // Won't panic, we are writing correct utf8.
-        let one_result = String::from_utf8(v).unwrap();
-        if let FileName::Real(ref filename) = *filename {
-            write_result.insert(filename.to_owned(), one_result);
+    for (filename, text) in file_map {
+        if let FileName::Real(ref filename) = filename {
+            write_result.insert(filename.to_owned(), text);
         }
     }
 
@@ -628,8 +659,9 @@ fn get_section<I: Iterator<Item = String>>(
         lazy_static! {
             static ref CONFIG_NAME_REGEX: regex::Regex =
                 regex::Regex::new(r"^## `([^`]+)`").expect("Failed creating configuration pattern");
-            static ref CONFIG_VALUE_REGEX: regex::Regex = regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#)
-                .expect("Failed creating configuration value pattern");
+            static ref CONFIG_VALUE_REGEX: regex::Regex =
+                regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#)
+                    .expect("Failed creating configuration value pattern");
         }
 
         loop {
@@ -637,7 +669,8 @@ fn get_section<I: Iterator<Item = String>>(
                 Some((i, line)) => {
                     if line.starts_with("```rust") {
                         // Get the lines of the code block.
-                        let lines: Vec<String> = file.map(|(_i, l)| l)
+                        let lines: Vec<String> = file
+                            .map(|(_i, l)| l)
                             .take_while(|l| !l.starts_with("```"))
                             .collect();
                         let block = format!("{}\n", lines.join("\n"));
@@ -707,13 +740,15 @@ fn code_block_valid(&self) -> bool {
         // We never expect to not have a code block.
         assert!(self.code_block.is_some() && self.code_block_start.is_some());
 
-        // See if code block begins with #![rustfmt_skip].
-        let fmt_skip = self.code_block
+        // See if code block begins with #![rustfmt::skip].
+        let fmt_skip = self
+            .code_block
             .as_ref()
             .unwrap()
             .split('\n')
             .nth(0)
-            .unwrap_or("") == "#![rustfmt_skip]";
+            .unwrap_or("")
+            == "#![rustfmt::skip]";
 
         if self.config_name.is_none() && !fmt_skip {
             write_message(&format!(
@@ -759,8 +794,7 @@ fn print_diff(&self, compare: Vec<Mismatch>) {
         });
     }
 
-    fn formatted_has_diff(&self, file_map: &FileMap) -> bool {
-        let &(ref _file_name, ref text) = file_map.first().unwrap();
+    fn formatted_has_diff(&self, text: &str) -> bool {
         let compare = make_diff(self.code_block.as_ref().unwrap(), text, DIFF_CONTEXT_SIZE);
         if !compare.is_empty() {
             self.print_diff(compare);
@@ -780,19 +814,26 @@ fn formatted_is_idempotent(&self) -> bool {
         }
 
         let input = Input::Text(self.code_block.as_ref().unwrap().to_owned());
-        let config = self.get_block_config();
+        let mut config = self.get_block_config();
+        config.set().emit_mode(EmitMode::Stdout);
+        let mut buf: Vec<u8> = vec![];
 
-        let (error_summary, file_map, _report) =
-            format_input::<io::Stdout>(input, &config, None).unwrap();
+        {
+            let mut session = Session::new(config, Some(&mut buf));
+            session.format(input).unwrap();
+            if self.has_parsing_errors(session.summary) {
+                return false;
+            }
+        }
 
-        !self.has_parsing_errors(error_summary) && !self.formatted_has_diff(&file_map)
+        !self.formatted_has_diff(&String::from_utf8(buf).unwrap())
     }
 
     // Extract a code block from the iterator. Behavior:
     // - Rust code blocks are identifed by lines beginning with "```rust".
     // - One explicit configuration setting is supported per code block.
     // - Rust code blocks with no configuration setting are illegal and cause an
-    //   assertion failure, unless the snippet begins with #![rustfmt_skip].
+    //   assertion failure, unless the snippet begins with #![rustfmt::skip].
     // - Configuration names in Configurations.md must be in the form of
     //   "## `NAME`".
     // - Configuration values in Configurations.md must be in the form of
@@ -901,29 +942,24 @@ fn drop(&mut self) {
     }
 }
 
-#[test]
-fn verify_check_works() {
-    let temp_file = make_temp_file("temp_check.rs");
-    assert_cli::Assert::command(&[
-        "cargo",
-        "run",
-        "--bin=rustfmt",
-        "--",
-        "--write-mode=check",
-        temp_file.path.to_str().unwrap(),
-    ]).succeeds()
-        .unwrap();
+fn rustfmt() -> PathBuf {
+    let mut me = env::current_exe().expect("failed to get current executable");
+    me.pop(); // chop of the test name
+    me.pop(); // chop off `deps`
+    me.push("rustfmt");
+    assert!(
+        me.is_file() || me.with_extension("exe").is_file(),
+        "no rustfmt bin, try running `cargo build` before testing"
+    );
+    return me;
 }
 
 #[test]
-fn verify_diff_works() {
-    let temp_file = make_temp_file("temp_diff.rs");
+fn verify_check_works() {
+    let temp_file = make_temp_file("temp_check.rs");
     assert_cli::Assert::command(&[
-        "cargo",
-        "run",
-        "--bin=rustfmt",
-        "--",
-        "--write-mode=diff",
+        rustfmt().to_str().unwrap(),
+        "--check",
         temp_file.path.to_str().unwrap(),
     ]).succeeds()
         .unwrap();