-
Notifications
You must be signed in to change notification settings - Fork 62
Refactor tests to use explicit fixtures #44
Changes from all commits
c649f6e
926fc5d
f1ce4fb
9353527
2396ea5
7dc1352
2e2e26a
16a25ba
6fab747
4ca7457
2ff9e32
3c61332
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +0,0 @@ | ||
[submodule "tests/fixtures/libui-rs"] | ||
path = tests/crates/libui-rs | ||
url = https://github.com/pcwalton/libui-rs.git | ||
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
#[macro_use] extern crate duct; | ||
#[macro_use] extern crate pretty_assertions; | ||
extern crate tempdir; | ||
#[macro_use] extern crate log; | ||
extern crate env_logger; | ||
extern crate serde_json; | ||
extern crate rustfix; | ||
|
||
use std::fs; | ||
use std::error::Error; | ||
use std::path::{Path, PathBuf}; | ||
use std::collections::HashSet; | ||
use tempdir::TempDir; | ||
|
||
use rustfix::Replacement; | ||
|
||
fn compile_and_get_json_errors(file: &Path) -> Result<String, Box<Error>> { | ||
let tmp = TempDir::new("rustfix-tests")?; | ||
let better_call_clippy = cmd!( | ||
"clippy-driver", "rustc", file, | ||
"--error-format=json", "--emit=metadata", | ||
"--out-dir", tmp.path() | ||
); | ||
let res = better_call_clippy | ||
.stdout_capture() | ||
.stderr_capture() | ||
.unchecked() | ||
.run()?; | ||
let stderr = String::from_utf8(res.stderr)?; | ||
|
||
use std::io::{Error, ErrorKind}; | ||
match res.status.code() { | ||
Some(0) | Some(1) => Ok(stderr), | ||
_ => Err(Box::new(Error::new( | ||
ErrorKind::Other, | ||
format!("failed with status {:?}: {}", res.status.code(), stderr), | ||
))) | ||
} | ||
} | ||
|
||
fn read_file(path: &Path) -> Result<String, Box<Error>> { | ||
use std::io::Read; | ||
|
||
let mut buffer = String::new(); | ||
let mut file = fs::File::open(path)?; | ||
file.read_to_string(&mut buffer)?; | ||
Ok(buffer) | ||
} | ||
|
||
fn apply_suggestion(file_content: &mut String, suggestion: &Replacement) -> Result<String, Box<Error>> { | ||
use std::cmp::max; | ||
|
||
let mut new_content = String::new(); | ||
|
||
// Add the lines before the section we want to replace | ||
new_content.push_str(&file_content.lines() | ||
.take(max(suggestion.snippet.line_range.start.line - 1, 0) as usize) | ||
.collect::<Vec<_>>() | ||
.join("\n")); | ||
new_content.push_str("\n"); | ||
|
||
// Parts of line before replacement | ||
new_content.push_str(&file_content.lines() | ||
.nth(suggestion.snippet.line_range.start.line - 1) | ||
.unwrap_or("") | ||
.chars() | ||
.take(suggestion.snippet.line_range.start.column - 1) | ||
.collect::<String>()); | ||
|
||
// Insert new content! Finally! | ||
new_content.push_str(&suggestion.replacement); | ||
|
||
// Parts of line after replacement | ||
new_content.push_str(&file_content.lines() | ||
.nth(suggestion.snippet.line_range.end.line - 1) | ||
.unwrap_or("") | ||
.chars() | ||
.skip(suggestion.snippet.line_range.end.column - 1) | ||
.collect::<String>()); | ||
|
||
// Add the lines after the section we want to replace | ||
new_content.push_str("\n"); | ||
new_content.push_str(&file_content.lines() | ||
.skip(suggestion.snippet.line_range.end.line as usize) | ||
.collect::<Vec<_>>() | ||
.join("\n")); | ||
new_content.push_str("\n"); | ||
|
||
Ok(new_content) | ||
} | ||
|
||
fn test_rustfix_with_file<P: AsRef<Path>>(file: P) -> Result<(), Box<Error>> { | ||
let file: &Path = file.as_ref(); | ||
debug!("{:?}", file); | ||
let code = read_file(&file)?; | ||
let errors = compile_and_get_json_errors(file)?; | ||
|
||
if std::env::var("RUSTFIX_TEST_RECORD_JSON").is_ok() { | ||
use std::io::Write; | ||
let mut recorded_json = fs::File::create(&file.with_extension("recorded.json"))?; | ||
recorded_json.write_all(errors.as_bytes())?; | ||
} | ||
|
||
let expected_json = read_file(&file.with_extension("json"))?; | ||
|
||
assert_eq!( | ||
errors.trim(), | ||
expected_json.trim(), | ||
"got unexpected json from clippy" | ||
); | ||
|
||
let suggestions = rustfix::get_suggestions_from_json(&errors, &HashSet::new()); | ||
let mut fixed = code.clone(); | ||
|
||
for sug in suggestions { | ||
trace!("{:?}", sug); | ||
for sol in sug.solutions { | ||
trace!("{:?}", sol); | ||
for r in sol.replacements { | ||
info!("replaced."); | ||
trace!("{:?}", r); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Useful for debugging: |
||
fixed = apply_suggestion(&mut fixed, &r)?; | ||
} | ||
} | ||
} | ||
|
||
let expected_fixed = read_file(&file.with_extension("fixed.rs"))?; | ||
assert_eq!(fixed.trim(), expected_fixed.trim(), "file doesn't look fixed"); | ||
Ok(()) | ||
} | ||
|
||
fn get_fixture_files() -> Result<Vec<PathBuf>, Box<Error>> { | ||
Ok(fs::read_dir("./tests/fixtures")? | ||
.into_iter() | ||
.map(|e| e.unwrap().path()) | ||
.filter(|p| p.is_file()) | ||
.filter(|p| { | ||
let x = p.to_string_lossy(); | ||
x.ends_with(".rs") && !x.ends_with(".fixed.rs") | ||
}) | ||
.collect()) | ||
} | ||
|
||
#[test] | ||
fn fixtures() { | ||
let _ = env_logger::try_init(); | ||
|
||
for file in &get_fixture_files().unwrap() { | ||
test_rustfix_with_file(file).unwrap(); | ||
info!("passed: {:?}", file); | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.recorded.json |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
trait Foo {} | ||
|
||
struct Bar<'a> { | ||
w: &'a (Foo + Copy), | ||
} | ||
|
||
fn main() { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"message":"expected a path on the left-hand side of `+`, not `&'a Foo`","code":{"code":"E0178","explanation":"\nIn types, the `+` type operator has low precedence, so it is often necessary\nto use parentheses.\n\nFor example:\n\n```compile_fail,E0178\ntrait Foo {}\n\nstruct Bar<'a> {\n w: &'a Foo + Copy, // error, use &'a (Foo + Copy)\n x: &'a Foo + 'a, // error, use &'a (Foo + 'a)\n y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)\n z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)\n}\n```\n\nMore details can be found in [RFC 438].\n\n[RFC 438]: https://github.com/rust-lang/rfcs/pull/438\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/E0178.rs","byte_start":38,"byte_end":52,"line_start":4,"line_end":4,"column_start":8,"column_end":22,"is_primary":true,"text":[{"text":" w: &'a Foo + Copy,","highlight_start":8,"highlight_end":22}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"try adding parentheses","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/E0178.rs","byte_start":38,"byte_end":52,"line_start":4,"line_end":4,"column_start":8,"column_end":22,"is_primary":true,"text":[{"text":" w: &'a Foo + Copy,","highlight_start":8,"highlight_end":22}],"label":null,"suggested_replacement":"&'a (Foo + Copy)","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`\n --> ./tests/fixtures/E0178.rs:4:8\n |\n4 | w: &'a Foo + Copy,\n | ^^^^^^^^^^^^^^ help: try adding parentheses: `&'a (Foo + Copy)`\n\n"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
trait Foo {} | ||
|
||
struct Bar<'a> { | ||
w: &'a Foo + Copy, | ||
} | ||
|
||
fn main() { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// Point at the captured immutable outer variable | ||
|
||
fn foo(mut f: Box<FnMut()>) { | ||
f(); | ||
} | ||
|
||
fn main() { | ||
let mut y = true; | ||
foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"message":"cannot assign to captured outer variable in an `FnMut` closure","code":{"code":"E0594","explanation":null},"level":"error","spans":[{"file_name":"./tests/fixtures/closure-immutable-outer-variable.rs","byte_start":615,"byte_end":624,"line_start":19,"line_end":19,"column_start":26,"column_end":35,"is_primary":true,"text":[{"text":" foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable","highlight_start":26,"highlight_end":35}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"consider making `y` mutable","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/closure-immutable-outer-variable.rs","byte_start":580,"byte_end":581,"line_start":18,"line_end":18,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":" let y = true;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"mut y","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0594]: cannot assign to captured outer variable in an `FnMut` closure\n --> ./tests/fixtures/closure-immutable-outer-variable.rs:19:26\n |\n18 | let y = true;\n | - help: consider making `y` mutable: `mut y`\n19 | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable\n | ^^^^^^^^^\n\n"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// Point at the captured immutable outer variable | ||
|
||
fn foo(mut f: Box<FnMut()>) { | ||
f(); | ||
} | ||
|
||
fn main() { | ||
let y = true; | ||
foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
let _x: &i32 = &&&&&5; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"message":"this expression borrows a reference that is immediately dereferenced by the compiler","code":{"code":"needless_borrow","explanation":null},"level":"warning","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(needless_borrow)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"change this to","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/needless_borrow.rs","byte_start":31,"byte_end":38,"line_start":2,"line_end":2,"column_start":20,"column_end":27,"is_primary":true,"text":[{"text":" let _x: &i32 = &&&&&&5;","highlight_start":20,"highlight_end":27}],"label":null,"suggested_replacement":"&&&&&5","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: this expression borrows a reference that is immediately dereferenced by the compiler\n --> ./tests/fixtures/needless_borrow.rs:2:20\n |\n2 | let _x: &i32 = &&&&&&5;\n | ^^^^^^^ help: change this to: `&&&&&5`\n |\n = note: #[warn(needless_borrow)] on by default\n = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.177/index.html#needless_borrow\n\n"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
let _x: &i32 = &&&&&&5; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
|
||
fn main() { | ||
let x: &[u8] = b"foo"; //~ ERROR mismatched types | ||
let y: &[u8; 4] = b"baaa"; //~ ERROR mismatched types | ||
let z: &str = "foo"; //~ ERROR mismatched types | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":"expected slice, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":499,"byte_end":504,"line_start":13,"line_end":13,"column_start":20,"column_end":25,"is_primary":true,"text":[{"text":" let x: &[u8] = \"foo\"; //~ ERROR mismatched types","highlight_start":20,"highlight_end":25}],"label":null,"suggested_replacement":"b\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:13:20\n |\n13 | let x: &[u8] = \"foo\"; //~ ERROR mismatched types\n | ^^^^^\n | |\n | expected slice, found str\n | help: consider adding a leading `b`: `b\"foo\"`\n |\n = note: expected type `&[u8]`\n found type `&'static str`\n\n"} | ||
{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":"expected array of 4 elements, found str","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&[u8; 4]`\n found type `&'static str`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider adding a leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":555,"byte_end":561,"line_start":14,"line_end":14,"column_start":23,"column_end":29,"is_primary":true,"text":[{"text":" let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types","highlight_start":23,"highlight_end":29}],"label":null,"suggested_replacement":"b\"baaa\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:14:23\n |\n14 | let y: &[u8; 4] = \"baaa\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected array of 4 elements, found str\n | help: consider adding a leading `b`: `b\"baaa\"`\n |\n = note: expected type `&[u8; 4]`\n found type `&'static str`\n\n"} | ||
{"message":"mismatched types","code":{"code":"E0308","explanation":"\nThis error occurs when the compiler was unable to infer the concrete type of a\nvariable. It can occur for several cases, the most common of which is a\nmismatch in the expected type that the compiler inferred for a variable's\ninitializing expression, and the actual type explicitly assigned to the\nvariable.\n\nFor example:\n\n```compile_fail,E0308\nlet x: i32 = \"I am not a number!\";\n// ~~~ ~~~~~~~~~~~~~~~~~~~~\n// | |\n// | initializing expression;\n// | compiler infers type `&str`\n// |\n// type `i32` assigned to variable `x`\n```\n"},"level":"error","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":"expected str, found array of 3 elements","suggested_replacement":null,"expansion":null}],"children":[{"message":"expected type `&str`\n found type `&'static [u8; 3]`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"consider removing the leading `b`","code":null,"level":"help","spans":[{"file_name":"./tests/fixtures/str-lit-type-mismatch.rs","byte_start":608,"byte_end":614,"line_start":15,"line_end":15,"column_start":19,"column_end":25,"is_primary":true,"text":[{"text":" let z: &str = b\"foo\"; //~ ERROR mismatched types","highlight_start":19,"highlight_end":25}],"label":null,"suggested_replacement":"\"foo\"","expansion":null}],"children":[],"rendered":null}],"rendered":"error[E0308]: mismatched types\n --> ./tests/fixtures/str-lit-type-mismatch.rs:15:19\n |\n15 | let z: &str = b\"foo\"; //~ ERROR mismatched types\n | ^^^^^^\n | |\n | expected str, found array of 3 elements\n | help: consider removing the leading `b`: `\"foo\"`\n |\n = note: expected type `&str`\n found type `&'static [u8; 3]`\n\n"} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
|
||
fn main() { | ||
let x: &[u8] = "foo"; //~ ERROR mismatched types | ||
let y: &[u8; 4] = "baaa"; //~ ERROR mismatched types | ||
let z: &str = b"foo"; //~ ERROR mismatched types | ||
} |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should note that this expects rustc's JSON output. Cargo puts each document in a
{"message": rustc_doc}
wrapper