Merge pull request #280 from alexcrichton/fix-duplicate

Fix disallowing duplicate table headers
This commit is contained in:
Eric Huss 2019-01-07 18:52:28 -08:00 committed by GitHub
commit 59d250e309
5 changed files with 66 additions and 7 deletions

View file

@ -15,6 +15,9 @@ facilitate deserializing and serializing Rust structures.
"""
categories = ["config", "encoding", "parser-implementations"]
[workspace]
members = ['test-suite']
[badges]
travis-ci = { repository = "alexcrichton/toml-rs" }

View file

@ -197,6 +197,7 @@ enum ErrorKind {
/// Deserialization implementation for TOML.
pub struct Deserializer<'a> {
require_newline_after_table: bool,
allow_duplciate_after_longer_table: bool,
input: &'a str,
tokens: Tokenizer<'a>,
}
@ -335,12 +336,24 @@ impl<'de, 'b> de::MapAccess<'de> for MapVisitor<'de, 'b> {
// Test to see if we're duplicating our parent's table, and if so
// then this is an error in the toml format
if self.cur_parent != pos
&& self.tables[self.cur_parent].header == self.tables[pos].header
{
let at = self.tables[pos].at;
let name = self.tables[pos].header.join(".");
return Err(self.de.error(at, ErrorKind::DuplicateTable(name)));
if self.cur_parent != pos {
if self.tables[self.cur_parent].header == self.tables[pos].header {
let at = self.tables[pos].at;
let name = self.tables[pos].header.join(".");
return Err(self.de.error(at, ErrorKind::DuplicateTable(name)));
}
// If we're here we know we should share the same prefix, and if
// the longer table was defined first then we want to narrow
// down our parent's length if possible to ensure that we catch
// duplicate tables defined afterwards.
if !self.de.allow_duplciate_after_longer_table {
let parent_len = self.tables[self.cur_parent].header.len();
let cur_len = self.tables[pos].header.len();
if cur_len < parent_len {
self.cur_parent = pos;
}
}
}
let table = &mut self.tables[pos];
@ -965,6 +978,7 @@ impl<'a> Deserializer<'a> {
tokens: Tokenizer::new(input),
input: input,
require_newline_after_table: true,
allow_duplciate_after_longer_table: false,
}
}
@ -986,6 +1000,16 @@ impl<'a> Deserializer<'a> {
self.require_newline_after_table = require;
}
/// Historical versions of toml-rs accidentally allowed a duplicate table
/// header after a longer table header was previously defined. This is
/// invalid according to the TOML spec, however.
///
/// This option can be set to `true` (the default is `false`) to emulate
/// this behavior for backwards compatibility with older toml-rs versions.
pub fn set_allow_duplicate_after_longer_table(&mut self, allow: bool) {
self.allow_duplciate_after_longer_table = allow;
}
fn tables(&mut self) -> Result<Vec<Table<'a>>, Error> {
let mut tables = Vec::new();
let mut cur_table = Table {

View file

@ -4,7 +4,7 @@ extern crate serde;
use serde::de::Deserialize;
#[test]
fn main() {
fn newlines_after_tables() {
let s = "
[a] foo = 1
[[b]] foo = 1
@ -17,3 +17,25 @@ fn main() {
assert_eq!(value["a"]["foo"].as_integer(), Some(1));
assert_eq!(value["b"][0]["foo"].as_integer(), Some(1));
}
#[test]
fn allow_duplicate_after_longer() {
let s = "
[dependencies.openssl-sys]
version = 1
[dependencies]
libc = 1
[dependencies]
bitflags = 1
";
assert!(s.parse::<toml::Value>().is_err());
let mut d = toml::de::Deserializer::new(s);
d.set_allow_duplicate_after_longer_table(true);
let value = toml::Value::deserialize(&mut d).unwrap();
assert_eq!(value["dependencies"]["openssl-sys"]["version"].as_integer(), Some(1));
assert_eq!(value["dependencies"]["libc"].as_integer(), Some(1));
assert_eq!(value["dependencies"]["bitflags"].as_integer(), Some(1));
}

View file

@ -96,3 +96,5 @@ test!(text_before_array_separator,
include_str!("invalid/text-before-array-separator.toml"));
test!(text_in_array,
include_str!("invalid/text-in-array.toml"));
test!(duplicate_table,
include_str!("invalid/duplicate-table.toml"));

View file

@ -0,0 +1,8 @@
[dependencies.openssl-sys]
version = "0.5.2"
[dependencies]
libc = "0.1"
[dependencies]
bitflags = "0.1.1"