Add option to override single configuration lines for tests
This commit is contained in:
parent
2ef0b17955
commit
8e22a73cb7
|
@ -26,37 +26,56 @@ pub enum BlockIndentStyle {
|
||||||
|
|
||||||
impl_enum_decodable!(BlockIndentStyle, Inherit, Tabbed, Visual);
|
impl_enum_decodable!(BlockIndentStyle, Inherit, Tabbed, Visual);
|
||||||
|
|
||||||
#[derive(RustcDecodable, Clone)]
|
macro_rules! create_config {
|
||||||
pub struct Config {
|
($($i:ident: $ty:ty),+ $(,)*) => (
|
||||||
pub max_width: usize,
|
#[derive(RustcDecodable, Clone)]
|
||||||
pub ideal_width: usize,
|
pub struct Config {
|
||||||
pub leeway: usize,
|
$(pub $i: $ty),+
|
||||||
pub tab_spaces: usize,
|
}
|
||||||
pub newline_style: NewlineStyle,
|
|
||||||
pub fn_brace_style: BraceStyle,
|
|
||||||
pub fn_return_indent: ReturnIndent,
|
|
||||||
pub fn_args_paren_newline: bool,
|
|
||||||
pub struct_trailing_comma: SeparatorTactic,
|
|
||||||
pub struct_lit_trailing_comma: SeparatorTactic,
|
|
||||||
pub struct_lit_style: StructLitStyle,
|
|
||||||
pub enum_trailing_comma: bool,
|
|
||||||
pub report_todo: ReportTactic,
|
|
||||||
pub report_fixme: ReportTactic,
|
|
||||||
pub reorder_imports: bool, // Alphabetically, case sensitive.
|
|
||||||
pub expr_indent_style: BlockIndentStyle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn from_toml(toml: &str) -> Config {
|
pub fn from_toml(toml: &str) -> Config {
|
||||||
let parsed = toml.parse().unwrap();
|
let parsed = toml.parse().unwrap();
|
||||||
match toml::decode(parsed) {
|
match toml::decode(parsed) {
|
||||||
Some(decoded) => decoded,
|
Some(decoded) => decoded,
|
||||||
None => {
|
None => {
|
||||||
println!("Decoding config file failed. Config:\n{}", toml);
|
println!("Decoding config file failed. Config:\n{}", toml);
|
||||||
let parsed: toml::Value = toml.parse().unwrap();
|
let parsed: toml::Value = toml.parse().unwrap();
|
||||||
println!("\n\nParsed:\n{:?}", parsed);
|
println!("\n\nParsed:\n{:?}", parsed);
|
||||||
panic!();
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn override_value(&mut self, key: &str, val: &str) {
|
||||||
|
match key {
|
||||||
|
$(
|
||||||
|
stringify!($i) => {
|
||||||
|
self.$i = val.parse::<$ty>().unwrap();
|
||||||
|
}
|
||||||
|
)+
|
||||||
|
_ => panic!("Bad config key!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
create_config! {
|
||||||
|
max_width: usize,
|
||||||
|
ideal_width: usize,
|
||||||
|
leeway: usize,
|
||||||
|
tab_spaces: usize,
|
||||||
|
newline_style: NewlineStyle,
|
||||||
|
fn_brace_style: BraceStyle,
|
||||||
|
fn_return_indent: ReturnIndent,
|
||||||
|
fn_args_paren_newline: bool,
|
||||||
|
struct_trailing_comma: SeparatorTactic,
|
||||||
|
struct_lit_trailing_comma: SeparatorTactic,
|
||||||
|
struct_lit_style: StructLitStyle,
|
||||||
|
enum_trailing_comma: bool,
|
||||||
|
report_todo: ReportTactic,
|
||||||
|
report_fixme: ReportTactic,
|
||||||
|
reorder_imports: bool, // Alphabetically, case sensitive.
|
||||||
|
expr_indent_style: BlockIndentStyle,
|
||||||
}
|
}
|
||||||
|
|
|
@ -617,10 +617,8 @@ fn rewrite_binary_op(context: &RewriteContext,
|
||||||
let operator_str = context.codemap.span_to_snippet(op.span).unwrap();
|
let operator_str = context.codemap.span_to_snippet(op.span).unwrap();
|
||||||
|
|
||||||
// 1 = space between lhs expr and operator
|
// 1 = space between lhs expr and operator
|
||||||
let mut result =
|
let max_width = try_opt!(context.config.max_width.checked_sub(operator_str.len() + offset + 1));
|
||||||
try_opt!(lhs.rewrite(context,
|
let mut result = try_opt!(lhs.rewrite(context, max_width, offset));
|
||||||
context.config.max_width - offset - 1 - operator_str.len(),
|
|
||||||
offset));
|
|
||||||
|
|
||||||
result.push(' ');
|
result.push(' ');
|
||||||
result.push_str(&operator_str);
|
result.push_str(&operator_str);
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub enum WriteMode {
|
||||||
NewFile(&'static str),
|
NewFile(&'static str),
|
||||||
// Write the output to stdout.
|
// Write the output to stdout.
|
||||||
Display,
|
Display,
|
||||||
// Return the result as a mapping from filenames to StringBuffers.
|
// Return the result as a mapping from filenames to Strings.
|
||||||
Return(&'static Fn(HashMap<String, String>)),
|
Return(&'static Fn(HashMap<String, String>)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
src/utils.rs
13
src/utils.rs
|
@ -144,6 +144,19 @@ macro_rules! impl_enum_decodable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ::std::str::FromStr for $e {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match &*s {
|
||||||
|
$(
|
||||||
|
stringify!($x) => Ok($e::$x),
|
||||||
|
)*
|
||||||
|
_ => Err("Bad variant"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
max_width = 100
|
|
||||||
ideal_width = 80
|
|
||||||
leeway = 5
|
|
||||||
tab_spaces = 4
|
|
||||||
newline_style = "Unix"
|
|
||||||
fn_brace_style = "SameLineWhere"
|
|
||||||
fn_return_indent = "WithArgs"
|
|
||||||
fn_args_paren_newline = true
|
|
||||||
struct_trailing_comma = "Vertical"
|
|
||||||
struct_lit_style = "BlockIndent"
|
|
||||||
struct_lit_trailing_comma = "Vertical"
|
|
||||||
enum_trailing_comma = true
|
|
||||||
report_todo = "Always"
|
|
||||||
report_fixme = "Never"
|
|
||||||
reorder_imports = false
|
|
||||||
expr_indent_style = "Visual"
|
|
|
@ -1,16 +0,0 @@
|
||||||
max_width = 100
|
|
||||||
ideal_width = 80
|
|
||||||
leeway = 5
|
|
||||||
tab_spaces = 4
|
|
||||||
newline_style = "Unix"
|
|
||||||
fn_brace_style = "SameLineWhere"
|
|
||||||
fn_return_indent = "WithArgs"
|
|
||||||
fn_args_paren_newline = true
|
|
||||||
struct_trailing_comma = "Vertical"
|
|
||||||
struct_lit_trailing_comma = "Vertical"
|
|
||||||
struct_lit_style = "BlockIndent"
|
|
||||||
enum_trailing_comma = true
|
|
||||||
report_todo = "Always"
|
|
||||||
report_fixme = "Never"
|
|
||||||
reorder_imports = true
|
|
||||||
expr_indent_style = "Tabbed"
|
|
|
@ -1,16 +0,0 @@
|
||||||
max_width = 100
|
|
||||||
ideal_width = 80
|
|
||||||
leeway = 5
|
|
||||||
tab_spaces = 4
|
|
||||||
newline_style = "Unix"
|
|
||||||
fn_brace_style = "SameLineWhere"
|
|
||||||
fn_return_indent = "WithArgs"
|
|
||||||
fn_args_paren_newline = true
|
|
||||||
struct_trailing_comma = "Vertical"
|
|
||||||
struct_lit_style = "VisualIndent"
|
|
||||||
struct_lit_trailing_comma = "Vertical"
|
|
||||||
enum_trailing_comma = true
|
|
||||||
report_todo = "Always"
|
|
||||||
report_fixme = "Never"
|
|
||||||
reorder_imports = false
|
|
||||||
expr_indent_style = "Tabbed"
|
|
|
@ -1,4 +1,4 @@
|
||||||
// rustfmt-config: expr_visual_indent.toml
|
// rustfmt-expr_indent_style: Visual
|
||||||
|
|
||||||
// Visual level block indentation.
|
// Visual level block indentation.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// rustfmt-config: reorder_imports.toml
|
// rustfmt-reorder_imports: true
|
||||||
|
|
||||||
use path::{C,/*A*/ A, B /* B */, self /* self */};
|
use path::{C,/*A*/ A, B /* B */, self /* self */};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// rustfmt-config: visual_struct_lits.toml
|
// rustfmt-struct_lit_style: VisualIndent
|
||||||
|
|
||||||
// Struct literal expressions.
|
// Struct literal expressions.
|
||||||
|
|
||||||
|
|
|
@ -97,8 +97,16 @@ fn print_mismatches(result: HashMap<String, String>) {
|
||||||
static HANDLE_RESULT: &'static Fn(HashMap<String, String>) = &handle_result;
|
static HANDLE_RESULT: &'static Fn(HashMap<String, String>) = &handle_result;
|
||||||
|
|
||||||
pub fn idempotent_check(filename: String) -> Result<(), HashMap<String, String>> {
|
pub fn idempotent_check(filename: String) -> Result<(), HashMap<String, String>> {
|
||||||
let config = get_config(&filename);
|
let sig_comments = read_significant_comments(&filename);
|
||||||
|
let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));
|
||||||
let args = vec!["rustfmt".to_owned(), filename];
|
let args = vec!["rustfmt".to_owned(), filename];
|
||||||
|
|
||||||
|
for (key, val) in sig_comments {
|
||||||
|
if key != "target" && key != "config" {
|
||||||
|
config.override_value(&key, &val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// this thread is not used for concurrency, but rather to workaround the issue that the passed
|
// this thread is not used for concurrency, but rather to workaround the issue that the passed
|
||||||
// function handle needs to have static lifetime. Instead of using a global RefCell, we use
|
// function handle needs to have static lifetime. Instead of using a global RefCell, we use
|
||||||
// panic to return a result in case of failure. This has the advantage of smoothing the road to
|
// panic to return a result in case of failure. This has the advantage of smoothing the road to
|
||||||
|
@ -110,15 +118,15 @@ pub fn idempotent_check(filename: String) -> Result<(), HashMap<String, String>>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads test config file from comments and loads it
|
|
||||||
fn get_config(file_name: &str) -> Box<Config> {
|
// Reads test config file from comments and reads its contents.
|
||||||
let config_file_name = read_significant_comment(file_name, "config")
|
fn get_config(config_file: Option<&str>) -> Box<Config> {
|
||||||
.map(|file_name| {
|
let config_file_name = config_file.map(|file_name| {
|
||||||
let mut full_path = "tests/config/".to_owned();
|
let mut full_path = "tests/config/".to_owned();
|
||||||
full_path.push_str(&file_name);
|
full_path.push_str(&file_name);
|
||||||
full_path
|
full_path
|
||||||
})
|
})
|
||||||
.unwrap_or("default.toml".to_owned());
|
.unwrap_or("default.toml".to_owned());
|
||||||
|
|
||||||
let mut def_config_file = fs::File::open(config_file_name).ok().expect("Couldn't open config.");
|
let mut def_config_file = fs::File::open(config_file_name).ok().expect("Couldn't open config.");
|
||||||
let mut def_config = String::new();
|
let mut def_config = String::new();
|
||||||
|
@ -127,14 +135,16 @@ fn get_config(file_name: &str) -> Box<Config> {
|
||||||
Box::new(Config::from_toml(&def_config))
|
Box::new(Config::from_toml(&def_config))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_significant_comment(file_name: &str, option: &str) -> Option<String> {
|
// Reads significant comments of the form: // rustfmt-key: value
|
||||||
let file = fs::File::open(file_name).ok().expect("Couldn't read file for comment.");
|
// into a hash map.
|
||||||
|
fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
|
||||||
|
let file = fs::File::open(file_name).ok().expect(&format!("Couldn't read file {}.", file_name));
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
let pattern = format!("^\\s*//\\s*rustfmt-{}:\\s*(\\S+)", option);
|
let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
|
||||||
let regex = regex::Regex::new(&pattern).ok().expect("Failed creating pattern 1.");
|
let regex = regex::Regex::new(&pattern).ok().expect("Failed creating pattern 1.");
|
||||||
|
|
||||||
// matches exactly the lines containing significant comments or whitespace
|
// Matches lines containing significant comments or whitespace.
|
||||||
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[:alpha:]+:\s*\S+)")
|
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
|
||||||
.ok().expect("Failed creating pattern 2.");
|
.ok().expect("Failed creating pattern 2.");
|
||||||
|
|
||||||
reader.lines()
|
reader.lines()
|
||||||
|
@ -142,20 +152,26 @@ fn read_significant_comment(file_name: &str, option: &str) -> Option<String> {
|
||||||
.take_while(|line| line_regex.is_match(&line))
|
.take_while(|line| line_regex.is_match(&line))
|
||||||
.filter_map(|line| {
|
.filter_map(|line| {
|
||||||
regex.captures_iter(&line).next().map(|capture| {
|
regex.captures_iter(&line).next().map(|capture| {
|
||||||
capture.at(1).expect("Couldn't unwrap capture.").to_owned()
|
(capture.at(1).expect("Couldn't unwrap capture.").to_owned(),
|
||||||
|
capture.at(2).expect("Couldn't unwrap capture.").to_owned())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.next()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare output to input.
|
// Compare output to input.
|
||||||
|
// TODO: needs a better name, more explanation.
|
||||||
fn handle_result(result: HashMap<String, String>) {
|
fn handle_result(result: HashMap<String, String>) {
|
||||||
let mut failures = HashMap::new();
|
let mut failures = HashMap::new();
|
||||||
|
|
||||||
for (file_name, fmt_text) in result {
|
for (file_name, fmt_text) in result {
|
||||||
// If file is in tests/source, compare to file with same name in tests/target
|
// FIXME: reading significant comments again. Is there a way we can just
|
||||||
let target_file_name = get_target(&file_name);
|
// pass the target to this function?
|
||||||
let mut f = fs::File::open(&target_file_name).ok().expect("Couldn't open target.");
|
let sig_comments = read_significant_comments(&file_name);
|
||||||
|
|
||||||
|
// If file is in tests/source, compare to file with same name in tests/target.
|
||||||
|
let target = get_target(&file_name, sig_comments.get("target").map(|x| &(*x)[..]));
|
||||||
|
let mut f = fs::File::open(&target).ok().expect("Couldn't open target.");
|
||||||
|
|
||||||
let mut text = String::new();
|
let mut text = String::new();
|
||||||
// TODO: speedup by running through bytes iterator
|
// TODO: speedup by running through bytes iterator
|
||||||
|
@ -171,15 +187,11 @@ fn handle_result(result: HashMap<String, String>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map source file paths to their target paths.
|
// Map source file paths to their target paths.
|
||||||
fn get_target(file_name: &str) -> String {
|
fn get_target(file_name: &str, target: Option<&str>) -> String {
|
||||||
if file_name.starts_with("tests/source/") {
|
if file_name.starts_with("tests/source/") {
|
||||||
let target = read_significant_comment(file_name, "target");
|
let base = target.unwrap_or(file_name.trim_left_matches("tests/source/"));
|
||||||
let base = target.unwrap_or(file_name.trim_left_matches("tests/source/").to_owned());
|
|
||||||
|
|
||||||
let mut target_file = "tests/target/".to_owned();
|
format!("tests/target/{}", base)
|
||||||
target_file.push_str(&base);
|
|
||||||
|
|
||||||
target_file
|
|
||||||
} else {
|
} else {
|
||||||
file_name.to_owned()
|
file_name.to_owned()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// rustfmt-config: expr_visual_indent.toml
|
// rustfmt-expr_indent_style: Visual
|
||||||
|
|
||||||
// Visual level block indentation.
|
// Visual level block indentation.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// rustfmt-config: reorder_imports.toml
|
// rustfmt-reorder_imports: true
|
||||||
|
|
||||||
use path::{self /* self */, /* A */ A, B /* B */, C};
|
use path::{self /* self */, /* A */ A, B /* B */, C};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// rustfmt-config: visual_struct_lits.toml
|
// rustfmt-struct_lit_style: VisualIndent
|
||||||
|
|
||||||
// Struct literal expressions.
|
// Struct literal expressions.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue