X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flib.rs;h=1045841ad0d9003cf31e838556c5e2b1e402c15f;hb=51f566062fefc2262dd3b56f7e385f1dd749bd8b;hp=858a273a1e5e3e96a87ee7b801760f800834ef27;hpb=2eebe614c7ce829cf158e33ca4cce7c7cdda2217;p=rust.git diff --git a/src/lib.rs b/src/lib.rs index 858a273a1e5..1045841ad0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,18 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(custom_attribute)] +#![feature(tool_attributes)] #![feature(decl_macro)] -#![feature(match_default_bindings)] +#![allow(unused_attributes)] #![feature(type_ascription)] +#![feature(unicode_internals)] #[macro_use] extern crate derive_new; extern crate diff; #[macro_use] +extern crate failure; +extern crate getopts; +extern crate itertools; +#[cfg(test)] +#[macro_use] +extern crate lazy_static; +#[macro_use] extern crate log; extern crate regex; -extern crate rustc_errors as errors; +extern crate rustc_target; extern crate serde; #[macro_use] extern crate serde_derive; @@ -31,99 +39,96 @@ use std::collections::HashMap; use std::fmt; -use std::io::{self, stdout, BufRead, Write}; -use std::iter::repeat; +use std::io::{self, stdout, Write}; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::path::PathBuf; use std::rc::Rc; use std::time::Duration; -use errors::{DiagnosticBuilder, Handler}; -use errors::emitter::{ColorConfig, EmitterWriter}; use syntax::ast; -use syntax::codemap::{CodeMap, FilePathMapping}; pub use syntax::codemap::FileName; +use syntax::codemap::{CodeMap, FilePathMapping}; +use syntax::errors::emitter::{ColorConfig, EmitterWriter}; +use syntax::errors::{DiagnosticBuilder, Handler}; use syntax::parse::{self, ParseSess}; -use regex::{Regex, RegexBuilder}; -use checkstyle::{output_footer, output_header}; -use comment::{CharClasses, FullCodeCharKind}; +use comment::{CharClasses, FullCodeCharKind, LineClasses}; +use failure::Fail; use issues::{BadIssueSeeker, Issue}; use shape::Indent; use utils::use_colored_tty; use visitor::{FmtVisitor, SnippetProvider}; -pub use config::Config; +pub use config::options::CliOptions; pub use config::summary::Summary; +pub use config::{file_lines, load_config, Config, Verbosity, WriteMode}; + +pub type FmtResult = std::result::Result; #[macro_use] mod utils; mod attr; mod chains; -mod checkstyle; +pub(crate) mod checkstyle; mod closures; -pub mod codemap; +pub(crate) mod codemap; mod comment; -pub mod config; +pub(crate) mod config; mod expr; -pub mod filemap; +pub(crate) mod filemap; mod imports; mod issues; mod items; mod lists; mod macros; +mod matches; mod missed_spans; -pub mod modules; +pub(crate) mod modules; +mod overflow; mod patterns; mod reorder; mod rewrite; -pub mod rustfmt_diff; +pub(crate) mod rustfmt_diff; mod shape; mod spanned; mod string; +#[cfg(test)] +mod test; mod types; mod vertical; -pub mod visitor; +pub(crate) mod visitor; const STDIN: &str = ""; // A map of the files of a crate, with their new content -pub type FileMap = Vec; +pub(crate) type FileMap = Vec; -pub type FileRecord = (FileName, String); +pub(crate) type FileRecord = (FileName, String); -#[derive(Clone, Copy)] +#[derive(Fail, Debug, Clone, Copy)] pub enum ErrorKind { // Line has exceeded character limit (found, maximum) + #[fail( + display = "line formatted, but exceeded maximum width \ + (maximum: {} (see `max_width` option), found: {})", + _0, + _1 + )] LineOverflow(usize, usize), // Line ends in whitespace + #[fail(display = "left behind trailing whitespace")] TrailingWhitespace, - // TO-DO or FIX-ME item without an issue number + // TODO or FIXME item without an issue number + #[fail(display = "found {}", _0)] BadIssue(Issue), // License check has failed + #[fail(display = "license check failed")] LicenseCheck, - // License template could not be parsed - ParsingLicense, -} - -impl fmt::Display for ErrorKind { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - ErrorKind::LineOverflow(found, maximum) => write!( - fmt, - "line exceeded maximum width (maximum: {}, found: {})", - maximum, found - ), - ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"), - ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue), - ErrorKind::LicenseCheck => write!(fmt, "license check failed"), - ErrorKind::ParsingLicense => write!(fmt, "parsing regex in license template failed"), - } - } } // Formatting errors that are identified *after* rustfmt has run. -pub struct FormattingError { +struct FormattingError { line: usize, kind: ErrorKind, is_comment: bool, @@ -134,11 +139,9 @@ pub struct FormattingError { impl FormattingError { fn msg_prefix(&self) -> &str { match self.kind { - ErrorKind::LineOverflow(..) - | ErrorKind::TrailingWhitespace - | ErrorKind::LicenseCheck - | ErrorKind::ParsingLicense => "error:", - ErrorKind::BadIssue(_) => "WARNING:", + ErrorKind::LineOverflow(..) | ErrorKind::TrailingWhitespace => "internal error:", + ErrorKind::LicenseCheck => "error:", + ErrorKind::BadIssue(_) => "warning:", } } @@ -152,16 +155,19 @@ fn msg_suffix(&self) -> &str { } // (space, target) - pub fn format_len(&self) -> (usize, usize) { + fn format_len(&self) -> (usize, usize) { match self.kind { ErrorKind::LineOverflow(found, max) => (max, found - max), ErrorKind::TrailingWhitespace => { - let trailing_ws_len = self.line_buffer - .chars() - .rev() - .take_while(|c| c.is_whitespace()) - .count(); - (self.line_buffer.len() - trailing_ws_len, trailing_ws_len) + let trailing_ws_start = self + .line_buffer + .rfind(|c: char| !c.is_whitespace()) + .map(|pos| pos + 1) + .unwrap_or(0); + ( + trailing_ws_start, + self.line_buffer.len() - trailing_ws_start, + ) } _ => unreachable!(), } @@ -180,25 +186,25 @@ fn new() -> FormatReport { } } - pub fn warning_count(&self) -> usize { + fn warning_count(&self) -> usize { self.file_error_map .iter() .map(|(_, errors)| errors.len()) .sum() } - pub fn has_warnings(&self) -> bool { + fn has_warnings(&self) -> bool { self.warning_count() > 0 } - pub fn print_warnings_fancy( + fn print_warnings_fancy( &self, mut t: Box>, ) -> Result<(), term::Error> { for (file, errors) in &self.file_error_map { for error in errors { let prefix_space_len = error.line.to_string().len(); - let prefix_spaces: String = repeat(" ").take(1 + prefix_space_len).collect(); + let prefix_spaces = " ".repeat(1 + prefix_space_len); // First line: the overview of error t.fg(term::color::RED)?; @@ -206,12 +212,12 @@ pub fn print_warnings_fancy( write!(t, "{} ", error.msg_prefix())?; t.reset()?; t.attr(term::Attr::Bold)?; - write!(t, "{}\n", error.kind)?; + writeln!(t, "{}", error.kind)?; // Second line: file info write!(t, "{}--> ", &prefix_spaces[1..])?; t.reset()?; - write!(t, "{}:{}\n", file, error.line)?; + writeln!(t, "{}:{}", file, error.line)?; // Third to fifth lines: show the line which triggered error, if available. if !error.line_buffer.is_empty() { @@ -219,11 +225,11 @@ pub fn print_warnings_fancy( t.attr(term::Attr::Bold)?; write!(t, "{}|\n{} | ", prefix_spaces, error.line)?; t.reset()?; - write!(t, "{}\n", error.line_buffer)?; + writeln!(t, "{}", error.line_buffer)?; t.attr(term::Attr::Bold)?; write!(t, "{}| ", prefix_spaces)?; t.fg(term::color::RED)?; - write!(t, "{}\n", target_str(space_len, target_len))?; + writeln!(t, "{}", target_str(space_len, target_len))?; t.reset()?; } @@ -233,9 +239,9 @@ pub fn print_warnings_fancy( t.attr(term::Attr::Bold)?; write!(t, "{}= note: ", prefix_spaces)?; t.reset()?; - write!(t, "{}\n", error.msg_suffix())?; + writeln!(t, "{}", error.msg_suffix())?; } else { - write!(t, "\n")?; + writeln!(t)?; } t.reset()?; } @@ -257,8 +263,8 @@ pub fn print_warnings_fancy( } fn target_str(space_len: usize, target_len: usize) -> String { - let empty_line: String = repeat(" ").take(space_len).collect(); - let overflowed: String = repeat("^").take(target_len).collect(); + let empty_line = " ".repeat(space_len); + let overflowed = "^".repeat(target_len); empty_line + &overflowed } @@ -268,7 +274,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { for (file, errors) in &self.file_error_map { for error in errors { let prefix_space_len = error.line.to_string().len(); - let prefix_spaces: String = repeat(" ").take(1 + prefix_space_len).collect(); + let prefix_spaces = " ".repeat(1 + prefix_space_len); let error_line_buffer = if error.line_buffer.is_empty() { String::from(" ") @@ -293,9 +299,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { format!("{}note= ", prefix_spaces) }; - write!( + writeln!( fmt, - "{}\n{}\n{}\n{}{}\n", + "{}\n{}\n{}\n{}{}", error_info, file_info, error_line_buffer, @@ -305,9 +311,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { } } if !self.file_error_map.is_empty() { - write!( + writeln!( fmt, - "warning: rustfmt may have failed to format. See previous {} errors.\n", + "warning: rustfmt may have failed to format. See previous {} errors.", self.warning_count(), )?; } @@ -319,7 +325,7 @@ fn should_emit_verbose(path: &FileName, config: &Config, f: F) where F: Fn(), { - if config.verbose() && path.to_string() != STDIN { + if config.verbose() == Verbosity::Verbose && path.to_string() != STDIN { f(); } } @@ -339,11 +345,9 @@ fn format_ast( // diff mode: check if any files are differing let mut has_diff = false; - // We always skip children for the "Plain" write mode, since there is - // nothing to distinguish the nested module contents. - let skip_children = config.skip_children() || config.write_mode() == config::WriteMode::Plain; + let skip_children = config.skip_children(); for (path, module) in modules::list_files(krate, parse_session.codemap())? { - if skip_children && path != *main_file { + if (skip_children && path != *main_file) || config.ignore().skip_file(&path) { continue; } should_emit_verbose(&path, config, || println!("Formatting {}", path)); @@ -370,7 +374,7 @@ fn format_ast( debug_assert_eq!( visitor.line_number, - ::utils::count_newlines(&format!("{}", visitor.buffer)) + ::utils::count_newlines(&visitor.buffer) ); let filename = path.clone(); @@ -389,7 +393,7 @@ fn format_ast( Ok((result, has_diff)) } -/// Returns true if the line with the given line number was skipped by `#[rustfmt_skip]`. +/// Returns true if the line with the given line number was skipped by `#[rustfmt::skip]`. fn is_skipped_line(line_number: usize, skipped_range: &[(usize, usize)]) -> bool { skipped_range .iter() @@ -415,38 +419,6 @@ fn should_report_error( } } -fn check_license(text: &str, license_template: &str) -> Result { - let mut template_re = String::from("^"); - // the template is parsed as a series of pairs of capture groups of (1) lazy whatever, which - // will be matched literally, followed by (2) a {}-delimited block, which will be matched as a - // regex - let template_parser = RegexBuilder::new(r"(.*?)\{(.*?)\}") - .dot_matches_new_line(true) - .build() - .unwrap(); - // keep track of the last matched offset and ultimately append the tail of the template (if any) - // after the last {} block - let mut last_matched_offset = 0; - for caps in template_parser.captures_iter(license_template) { - if let Some(mat) = caps.get(0) { - last_matched_offset = mat.end() - } - if let Some(mat) = caps.get(1) { - template_re.push_str(®ex::escape(mat.as_str())) - } - if let Some(mat) = caps.get(2) { - let mut re = mat.as_str(); - if re.is_empty() { - re = ".*?"; - } - template_re.push_str(re) - } - } - template_re.push_str(®ex::escape(&license_template[last_matched_offset..])); - let template_re = Regex::new(&template_re)?; - Ok(template_re.is_match(text)) -} - // Formatting done on a char by char or line by line basis. // FIXME(#20) other stuff for parity with make tidy fn format_lines( @@ -469,28 +441,15 @@ fn format_lines( let allow_issue_seek = !issue_seeker.is_disabled(); // Check license. - if config.was_set().license_template() { - match check_license(text, &config.license_template()) { - Ok(check) => { - if !check { - errors.push(FormattingError { - line: cur_line, - kind: ErrorKind::LicenseCheck, - is_comment: false, - is_string: false, - line_buffer: String::new(), - }); - } - } - Err(_) => { - errors.push(FormattingError { - line: cur_line, - kind: ErrorKind::ParsingLicense, - is_comment: false, - is_string: false, - line_buffer: String::new(), - }); - } + if let Some(ref license_template) = config.license_template { + if !license_template.is_match(text) { + errors.push(FormattingError { + line: cur_line, + kind: ErrorKind::LicenseCheck, + is_comment: false, + is_string: false, + line_buffer: String::new(), + }); } } @@ -525,7 +484,8 @@ fn format_lines( // Check for any line width errors we couldn't correct. let error_kind = ErrorKind::LineOverflow(line_len, config.max_width()); - if line_len > config.max_width() && !is_skipped_line(cur_line, skipped_range) + if line_len > config.max_width() + && !is_skipped_line(cur_line, skipped_range) && should_report_error(config, kind, is_string, error_kind) { errors.push(FormattingError { @@ -587,50 +547,56 @@ fn parse_input<'sess>( input: Input, parse_session: &'sess ParseSess, config: &Config, -) -> Result>> { - let result = match input { - Input::File(file) => { - let mut parser = parse::new_parser_from_file(parse_session, &file); - parser.cfg_mods = false; - if config.skip_children() { - parser.recurse_into_file_modules = false; - } - parser.parse_crate_mod() - } - Input::Text(text) => { - let mut parser = parse::new_parser_from_source_str( - parse_session, - FileName::Custom("stdin".to_owned()), - text, - ); - parser.cfg_mods = false; - if config.skip_children() { - parser.recurse_into_file_modules = false; - } - parser.parse_crate_mod() - } +) -> Result> { + let mut parser = match input { + Input::File(file) => parse::new_parser_from_file(parse_session, &file), + Input::Text(text) => parse::new_parser_from_source_str( + parse_session, + FileName::Custom("stdin".to_owned()), + text, + ), }; + parser.cfg_mods = false; + if config.skip_children() { + parser.recurse_into_file_modules = false; + } + + let mut parser = AssertUnwindSafe(parser); + let result = catch_unwind(move || parser.0.parse_crate_mod()); + match result { - Ok(c) => { + Ok(Ok(c)) => { if parse_session.span_diagnostic.has_errors() { // Bail out if the parser recovered from an error. - Err(None) + Err(ParseError::Recovered) } else { Ok(c) } } - Err(e) => Err(Some(e)), + Ok(Err(e)) => Err(ParseError::Error(e)), + Err(_) => Err(ParseError::Panic), } } +/// All the ways that parsing can fail. +enum ParseError<'sess> { + /// There was an error, but the parser recovered. + Recovered, + /// There was an error (supplied) and parsing failed. + Error(DiagnosticBuilder<'sess>), + /// The parser panicked. + Panic, +} + /// Format the given snippet. The snippet is expected to be *complete* code. /// When we cannot parse the given snippet, this function returns `None`. pub fn format_snippet(snippet: &str, config: &Config) -> Option { let mut out: Vec = Vec::with_capacity(snippet.len() * 2); let input = Input::Text(snippet.into()); let mut config = config.clone(); - config.set().write_mode(config::WriteMode::Plain); + config.set().write_mode(config::WriteMode::Display); + config.set().verbose(Verbosity::Quiet); config.set().hide_parse_errors(true); match format_input(input, &config, Some(&mut out)) { // `format_input()` returns an empty string on parsing error. @@ -640,14 +606,32 @@ pub fn format_snippet(snippet: &str, config: &Config) -> Option { } } +const FN_MAIN_PREFIX: &str = "fn main() {\n"; + +fn enclose_in_main_block(s: &str, config: &Config) -> String { + let indent = Indent::from_width(config, config.tab_spaces()); + let mut result = String::with_capacity(s.len() * 2); + result.push_str(FN_MAIN_PREFIX); + let mut need_indent = true; + for (kind, line) in LineClasses::new(s) { + if need_indent { + result.push_str(&indent.to_string(config)); + } + result.push_str(&line); + result.push('\n'); + need_indent = !kind.is_string() || line.ends_with('\\'); + } + result.push('}'); + result +} + /// Format the given code block. Mainly targeted for code block in comment. /// The code block may be incomplete (i.e. parser may be unable to parse it). /// To avoid panic in parser, we wrap the code block with a dummy function. /// The returned code block does *not* end with newline. pub fn format_code_block(code_snippet: &str, config: &Config) -> Option { // Wrap the given code block with `fn main()` if it does not have one. - let fn_main_prefix = "fn main() {\n"; - let snippet = fn_main_prefix.to_owned() + code_snippet + "\n}"; + let snippet = enclose_in_main_block(code_snippet, config); let mut result = String::with_capacity(snippet.len()); let mut is_first = true; @@ -655,14 +639,17 @@ pub fn format_code_block(code_snippet: &str, config: &Config) -> Option // then unindent the whole code block. let formatted = format_snippet(&snippet, config)?; // 2 = "}\n" - let block_len = formatted.len().checked_sub(2).unwrap_or(0); - for line in formatted[fn_main_prefix.len()..block_len].lines() { + let block_len = formatted.rfind('}').unwrap_or(formatted.len()); + let mut is_indented = true; + for (kind, ref line) in LineClasses::new(&formatted[FN_MAIN_PREFIX.len()..block_len]) { if !is_first { result.push('\n'); } else { is_first = false; } - let trimmed_line = if line.len() > config.max_width() { + let trimmed_line = if !is_indented { + line + } else if line.len() > config.max_width() { // If there are lines that are larger than max width, we cannot tell // whether we have succeeded but have some comments or strings that // are too long, or we have failed to format code block. We will be @@ -685,11 +672,20 @@ pub fn format_code_block(code_snippet: &str, config: &Config) -> Option line }; result.push_str(trimmed_line); + is_indented = !kind.is_string() || line.ends_with('\\'); } Some(result) } pub fn format_input( + input: Input, + config: &Config, + out: Option<&mut T>, +) -> Result<(Summary, FileMap, FormatReport), (io::Error, Summary)> { + syntax::with_globals(|| format_input_inner(input, config, out)) +} + +fn format_input_inner( input: Input, config: &Config, mut out: Option<&mut T>, @@ -732,9 +728,18 @@ pub fn format_input( let krate = match parse_input(input, &parse_session, config) { Ok(krate) => krate, - Err(diagnostic) => { - if let Some(mut diagnostic) = diagnostic { - diagnostic.emit(); + Err(err) => { + match err { + ParseError::Error(mut diagnostic) => diagnostic.emit(), + ParseError::Panic => { + // Note that if you see this message and want more information, + // then go to `parse_input` and run the parse function without + // `catch_unwind` so rustfmt panics and you can get a backtrace. + should_emit_verbose(&main_file, config, || { + println!("The Rust parser panicked") + }); + } + ParseError::Recovered => {} } summary.add_parsing_error(); return Ok((summary, FileMap::new(), FormatReport::new())); @@ -743,10 +748,6 @@ pub fn format_input( summary.mark_parse_time(); - if parse_session.span_diagnostic.has_errors() { - summary.add_parsing_error(); - } - // Suppress error output after parsing. let silent_emitter = Box::new(EmitterWriter::new( Box::new(Vec::new()), @@ -810,7 +811,7 @@ fn duration_to_f32(d: Duration) -> f32 { /// A single span of changed lines, with 0 or more removed lines /// and a vector of 0 or more inserted lines. #[derive(Debug, PartialEq, Eq)] -pub struct ModifiedChunk { +struct ModifiedChunk { /// The first to be removed from the original text pub line_number_orig: u32, /// The number of lines which have been replaced @@ -821,13 +822,14 @@ pub struct ModifiedChunk { /// Set of changed sections of a file. #[derive(Debug, PartialEq, Eq)] -pub struct ModifiedLines { +struct ModifiedLines { /// The set of changed chunks. pub chunks: Vec, } /// The successful result of formatting via `get_modified_lines()`. -pub struct ModifiedLinesResult { +#[cfg(test)] +struct ModifiedLinesResult { /// The high level summary details pub summary: Summary, /// The result Filemap @@ -840,15 +842,18 @@ pub struct ModifiedLinesResult { /// Format a file and return a `ModifiedLines` data structure describing /// the changed ranges of lines. -pub fn get_modified_lines( +#[cfg(test)] +fn get_modified_lines( input: Input, config: &Config, ) -> Result { + use std::io::BufRead; + let mut data = Vec::new(); let mut config = config.clone(); config.set().write_mode(config::WriteMode::Modified); - let (summary, filemap, formatreport) = format_input(input, &config, Some(&mut data))?; + let (summary, filemap, report) = format_input(input, &config, Some(&mut data))?; let mut lines = data.lines(); let mut chunks = Vec::new(); @@ -873,9 +878,9 @@ pub fn get_modified_lines( }); } Ok(ModifiedLinesResult { - summary: summary, - filemap: filemap, - report: formatreport, + summary, + filemap, + report, modified_lines: ModifiedLines { chunks }, }) } @@ -886,17 +891,18 @@ pub enum Input { Text(String), } -pub fn run(input: Input, config: &Config) -> Summary { +pub fn format_and_emit_report(input: Input, config: &Config) -> FmtResult { + if !config.version_meets_requirement() { + return Err(format_err!("Version mismatch")); + } let out = &mut stdout(); - output_header(out, config.write_mode()).ok(); match format_input(input, config, Some(out)) { Ok((summary, _, report)) => { - output_footer(out, config.write_mode()).ok(); - if report.has_warnings() { match term::stderr() { Some(ref t) - if use_colored_tty(config.color()) && t.supports_color() + if use_colored_tty(config.color()) + && t.supports_color() && t.supports_attr(term::Attr::Bold) => { match report.print_warnings_fancy(term::stderr().unwrap()) { @@ -904,23 +910,39 @@ pub fn run(input: Input, config: &Config) -> Summary { Err(..) => panic!("Unable to write to stderr: {}", report), } } - _ => msg!("{}", report), + _ => eprintln!("{}", report), } } - summary + Ok(summary) } Err((msg, mut summary)) => { - msg!("Error writing files: {}", msg); + eprintln!("Error writing files: {}", msg); summary.add_operational_error(); - summary + Ok(summary) } } } +pub fn emit_pre_matter(config: &Config) -> FmtResult<()> { + if config.write_mode() == WriteMode::Checkstyle { + let mut out = &mut stdout(); + checkstyle::output_header(&mut out)?; + } + Ok(()) +} + +pub fn emit_post_matter(config: &Config) -> FmtResult<()> { + if config.write_mode() == WriteMode::Checkstyle { + let mut out = &mut stdout(); + checkstyle::output_footer(&mut out)?; + } + Ok(()) +} + #[cfg(test)] -mod test { - use super::{check_license, format_code_block, format_snippet, Config}; +mod unit_tests { + use super::{format_code_block, format_snippet, Config}; #[test] fn test_no_panic_on_format_snippet_and_format_code_block() { @@ -950,7 +972,7 @@ fn test_format_snippet() { #[test] fn test_format_code_block_fail() { - #[rustfmt_skip] + #[rustfmt::skip] let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);"; assert!(format_code_block(code_block, &Config::default()).is_none()); } @@ -1006,38 +1028,4 @@ fn test_format_code_block() { };"; assert!(test_format_inner(format_code_block, code_block, expected)); } - - #[test] - fn test_check_license() { - assert!(check_license("literal matching", "literal matching").unwrap()); - assert!(!check_license("literal no match", "literal matching").unwrap()); - assert!( - check_license( - "Regex start and end: 2018", - r"{[Rr]egex} start {} end: {\d+}" - ).unwrap() - ); - assert!(!check_license( - "Regex start and end no match: 2018", - r"{[Rr]egex} start {} end: {\d+}" - ).unwrap()); - assert!( - check_license( - "Regex in the middle: 2018 (tm)", - r"Regex {} middle: {\d+} (tm)" - ).unwrap() - ); - assert!(!check_license( - "Regex in the middle no match: 2018 (tm)", - r"Regex {} middle: {\d+} (tm)" - ).unwrap()); - assert!(!check_license("default doesn't match\nacross lines", "default {} lines").unwrap()); - assert!(check_license("", "this is not a valid {[regex}").is_err()); - assert!( - check_license( - "can't parse nested delimiters with regex", - r"can't parse nested delimiters with regex{\.{3}}" - ).is_err() - ); - } }