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);
|
||||
|
||||
#[derive(RustcDecodable, Clone)]
|
||||
pub struct Config {
|
||||
pub max_width: usize,
|
||||
pub ideal_width: usize,
|
||||
pub leeway: usize,
|
||||
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,
|
||||
}
|
||||
macro_rules! create_config {
|
||||
($($i:ident: $ty:ty),+ $(,)*) => (
|
||||
#[derive(RustcDecodable, Clone)]
|
||||
pub struct Config {
|
||||
$(pub $i: $ty),+
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_toml(toml: &str) -> Config {
|
||||
let parsed = toml.parse().unwrap();
|
||||
match toml::decode(parsed) {
|
||||
Some(decoded) => decoded,
|
||||
None => {
|
||||
println!("Decoding config file failed. Config:\n{}", toml);
|
||||
let parsed: toml::Value = toml.parse().unwrap();
|
||||
println!("\n\nParsed:\n{:?}", parsed);
|
||||
panic!();
|
||||
impl Config {
|
||||
pub fn from_toml(toml: &str) -> Config {
|
||||
let parsed = toml.parse().unwrap();
|
||||
match toml::decode(parsed) {
|
||||
Some(decoded) => decoded,
|
||||
None => {
|
||||
println!("Decoding config file failed. Config:\n{}", toml);
|
||||
let parsed: toml::Value = toml.parse().unwrap();
|
||||
println!("\n\nParsed:\n{:?}", parsed);
|
||||
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();
|
||||
|
||||
// 1 = space between lhs expr and operator
|
||||
let mut result =
|
||||
try_opt!(lhs.rewrite(context,
|
||||
context.config.max_width - offset - 1 - operator_str.len(),
|
||||
offset));
|
||||
let max_width = try_opt!(context.config.max_width.checked_sub(operator_str.len() + offset + 1));
|
||||
let mut result = try_opt!(lhs.rewrite(context, max_width, offset));
|
||||
|
||||
result.push(' ');
|
||||
result.push_str(&operator_str);
|
||||
|
@ -80,7 +80,7 @@ pub enum WriteMode {
|
||||
NewFile(&'static str),
|
||||
// Write the output to stdout.
|
||||
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>)),
|
||||
}
|
||||
|
||||
|
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.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// rustfmt-config: reorder_imports.toml
|
||||
// rustfmt-reorder_imports: true
|
||||
|
||||
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.
|
||||
|
||||
|
@ -97,8 +97,16 @@ fn print_mismatches(result: HashMap<String, String>) {
|
||||
static HANDLE_RESULT: &'static Fn(HashMap<String, String>) = &handle_result;
|
||||
|
||||
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];
|
||||
|
||||
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
|
||||
// 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
|
||||
@ -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> {
|
||||
let config_file_name = read_significant_comment(file_name, "config")
|
||||
.map(|file_name| {
|
||||
let mut full_path = "tests/config/".to_owned();
|
||||
full_path.push_str(&file_name);
|
||||
full_path
|
||||
})
|
||||
.unwrap_or("default.toml".to_owned());
|
||||
|
||||
// Reads test config file from comments and reads its contents.
|
||||
fn get_config(config_file: Option<&str>) -> Box<Config> {
|
||||
let config_file_name = config_file.map(|file_name| {
|
||||
let mut full_path = "tests/config/".to_owned();
|
||||
full_path.push_str(&file_name);
|
||||
full_path
|
||||
})
|
||||
.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 = String::new();
|
||||
@ -127,14 +135,16 @@ fn get_config(file_name: &str) -> Box<Config> {
|
||||
Box::new(Config::from_toml(&def_config))
|
||||
}
|
||||
|
||||
fn read_significant_comment(file_name: &str, option: &str) -> Option<String> {
|
||||
let file = fs::File::open(file_name).ok().expect("Couldn't read file for comment.");
|
||||
// Reads significant comments of the form: // rustfmt-key: value
|
||||
// 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 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.");
|
||||
|
||||
// matches exactly the lines containing significant comments or whitespace
|
||||
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[:alpha:]+:\s*\S+)")
|
||||
// Matches lines containing significant comments or whitespace.
|
||||
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
|
||||
.ok().expect("Failed creating pattern 2.");
|
||||
|
||||
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))
|
||||
.filter_map(|line| {
|
||||
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.
|
||||
// TODO: needs a better name, more explanation.
|
||||
fn handle_result(result: HashMap<String, String>) {
|
||||
let mut failures = HashMap::new();
|
||||
|
||||
for (file_name, fmt_text) in result {
|
||||
// If file is in tests/source, compare to file with same name in tests/target
|
||||
let target_file_name = get_target(&file_name);
|
||||
let mut f = fs::File::open(&target_file_name).ok().expect("Couldn't open target.");
|
||||
// FIXME: reading significant comments again. Is there a way we can just
|
||||
// pass the target to this function?
|
||||
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();
|
||||
// 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.
|
||||
fn get_target(file_name: &str) -> String {
|
||||
fn get_target(file_name: &str, target: Option<&str>) -> String {
|
||||
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/").to_owned());
|
||||
let base = target.unwrap_or(file_name.trim_left_matches("tests/source/"));
|
||||
|
||||
let mut target_file = "tests/target/".to_owned();
|
||||
target_file.push_str(&base);
|
||||
|
||||
target_file
|
||||
format!("tests/target/{}", base)
|
||||
} else {
|
||||
file_name.to_owned()
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// rustfmt-config: expr_visual_indent.toml
|
||||
// rustfmt-expr_indent_style: Visual
|
||||
|
||||
// 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};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// rustfmt-config: visual_struct_lits.toml
|
||||
// rustfmt-struct_lit_style: VisualIndent
|
||||
|
||||
// Struct literal expressions.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user