Update configuration tests

This commit adds following functionalities to `configuration_snippet_tests`:

1. Error if there is an unknown configuration option in Configuration.md.
2. Error if there are multiple guides for the same configuration option in
   Configuration.md.
3. Error if an user-facing configuration option does not have its guide in
   Configuration.md.

We will be able to catch outdated Configuration.md. Should prevent issues
like #2459.
This commit is contained in:
topecongiro 2018-02-23 21:54:59 +09:00
parent cc2c7433e2
commit 5f49587a2c
2 changed files with 50 additions and 13 deletions

View File

@ -74,6 +74,8 @@ macro_rules! is_nightly_channel {
macro_rules! create_config {
($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
use std::collections::HashSet;
#[derive(Clone)]
pub struct Config {
// For each config item, we store a bool indicating whether it has
@ -190,6 +192,24 @@ macro_rules! create_config {
self
}
/// Returns a hash set initialized with every user-facing config option name.
pub fn hash_set() -> HashSet<String> {
let mut hash_set = HashSet::new();
$(
hash_set.insert(stringify!($i).to_owned());
)+
hash_set
}
pub fn is_valid_name(name: &str) -> bool {
match name {
$(
stringify!($i) => true,
)+
_ => false,
}
}
pub fn from_toml(toml: &str) -> Result<Config, String> {
let parsed: toml::Value =
toml.parse().map_err(|e| format!("Could not parse TOML: {}", e))?;
@ -199,15 +219,9 @@ macro_rules! create_config {
.as_table()
.ok_or(String::from("Parsed config was not table"))?;
for key in table.keys() {
match &**key {
$(
stringify!($i) => (),
)+
_ => {
let msg =
&format!("Warning: Unknown configuration option `{}`\n", key);
err.push_str(msg)
}
if !Config::is_valid_name(key) {
let msg = &format!("Warning: Unknown configuration option `{}`\n", key);
err.push_str(msg)
}
}
}
@ -324,10 +338,13 @@ macro_rules! create_config {
}
}
pub fn is_hidden_option(name: &str) -> bool {
const HIDE_OPTIONS: [&str; 3] = ["verbose", "file_lines", "width_heuristics"];
HIDE_OPTIONS.contains(&name)
}
pub fn print_docs() {
use std::cmp;
const HIDE_OPTIONS: [&str; 3] = ["verbose", "file_lines", "width_heuristics"];
let max = 0;
$( let max = cmp::max(max, stringify!($i).len()+1); )+
let mut space_str = String::with_capacity(max);
@ -338,7 +355,7 @@ macro_rules! create_config {
$(
let name_raw = stringify!($i);
if !HIDE_OPTIONS.contains(&name_raw) {
if !Config::is_hidden_option(name_raw) {
let mut name_out = String::with_capacity(max);
for _ in name_raw.len()..max-1 {
name_out.push(' ')

View File

@ -17,7 +17,7 @@ extern crate rustfmt_config as config;
extern crate rustfmt_core as rustfmt;
extern crate term;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::io::{self, BufRead, BufReader, Read};
use std::iter::{Enumerate, Peekable};
@ -795,6 +795,7 @@ impl ConfigCodeBlock {
fn extract<I: Iterator<Item = String>>(
file: &mut Enumerate<I>,
prev: Option<&ConfigCodeBlock>,
hash_set: &mut HashSet<String>,
) -> Option<ConfigCodeBlock> {
let mut code_block = ConfigCodeBlock::new();
code_block.config_name = prev.and_then(|cb| cb.config_name.clone());
@ -806,6 +807,16 @@ impl ConfigCodeBlock {
break;
}
Some(ConfigurationSection::ConfigName(name)) => {
assert!(
Config::is_valid_name(&name),
"an unknown configuration option was found: {}",
name
);
assert!(
hash_set.remove(&name),
"multiple configuration guides found for option {}",
name
);
code_block.set_config_name(Some(name));
}
Some(ConfigurationSection::ConfigValue(value)) => {
@ -831,11 +842,20 @@ fn configuration_snippet_tests() {
.map(|l| l.unwrap())
.enumerate();
let mut code_blocks: Vec<ConfigCodeBlock> = Vec::new();
let mut hash_set = Config::hash_set();
while let Some(cb) = ConfigCodeBlock::extract(&mut file_iter, code_blocks.last()) {
while let Some(cb) =
ConfigCodeBlock::extract(&mut file_iter, code_blocks.last(), &mut hash_set)
{
code_blocks.push(cb);
}
for name in hash_set {
if !Config::is_hidden_option(&name) {
panic!("{} does not have a configuration guide", name);
}
}
code_blocks
}