frontend-utils: Made ParseResult return a DocumentHolder directly
This commit is contained in:
parent
2bd28c9c1c
commit
2b4cec664a
|
@ -48,12 +48,12 @@ impl GlobalPreferences {
|
||||||
let preferences = if preferences_path.exists() {
|
let preferences = if preferences_path.exists() {
|
||||||
let contents = std::fs::read_to_string(&preferences_path)
|
let contents = std::fs::read_to_string(&preferences_path)
|
||||||
.context("Failed to read saved preferences")?;
|
.context("Failed to read saved preferences")?;
|
||||||
let (result, document) = read_preferences(&contents);
|
let result = read_preferences(&contents);
|
||||||
for warning in result.warnings {
|
for warning in result.warnings {
|
||||||
// TODO: A way to display warnings to users, generally
|
// TODO: A way to display warnings to users, generally
|
||||||
tracing::warn!("{warning}");
|
tracing::warn!("{warning}");
|
||||||
}
|
}
|
||||||
DocumentHolder::new(result.result, document)
|
result.result
|
||||||
} else {
|
} else {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
|
@ -62,11 +62,11 @@ impl GlobalPreferences {
|
||||||
let bookmarks = if bookmarks_path.exists() {
|
let bookmarks = if bookmarks_path.exists() {
|
||||||
let contents = std::fs::read_to_string(&bookmarks_path)
|
let contents = std::fs::read_to_string(&bookmarks_path)
|
||||||
.context("Failed to read saved bookmarks")?;
|
.context("Failed to read saved bookmarks")?;
|
||||||
let (result, document) = read_bookmarks(&contents);
|
let result = read_bookmarks(&contents);
|
||||||
for warning in result.warnings {
|
for warning in result.warnings {
|
||||||
tracing::warn!("{warning}");
|
tracing::warn!("{warning}");
|
||||||
}
|
}
|
||||||
DocumentHolder::new(result.result, document)
|
result.result
|
||||||
} else {
|
} else {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::preferences::{Bookmark, SavedGlobalPreferences};
|
use crate::preferences::{Bookmark, SavedGlobalPreferences};
|
||||||
use ruffle_frontend_utils::parse::{ParseContext, ParseResult, ReadExt};
|
use ruffle_frontend_utils::parse::{DocumentHolder, ParseContext, ParseResult, ReadExt};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use toml_edit::DocumentMut;
|
use toml_edit::DocumentMut;
|
||||||
|
|
||||||
|
@ -12,74 +12,74 @@ use toml_edit::DocumentMut;
|
||||||
/// Default values are used wherever an unknown or invalid value is found;
|
/// Default values are used wherever an unknown or invalid value is found;
|
||||||
/// this is to support the case of, for example, a later version having different supported
|
/// this is to support the case of, for example, a later version having different supported
|
||||||
/// backends than an older version.
|
/// backends than an older version.
|
||||||
pub fn read_preferences(input: &str) -> (ParseResult<SavedGlobalPreferences>, DocumentMut) {
|
pub fn read_preferences(input: &str) -> ParseResult<SavedGlobalPreferences> {
|
||||||
let mut result = ParseResult {
|
|
||||||
result: Default::default(),
|
|
||||||
warnings: vec![],
|
|
||||||
};
|
|
||||||
let document = match input.parse::<DocumentMut>() {
|
let document = match input.parse::<DocumentMut>() {
|
||||||
Ok(document) => document,
|
Ok(document) => document,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
result.add_warning(format!("Invalid TOML: {e}"));
|
return ParseResult {
|
||||||
return (result, DocumentMut::default());
|
result: Default::default(),
|
||||||
|
warnings: vec![format!("Invalid TOML: {e}")],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut result = SavedGlobalPreferences::default();
|
||||||
let mut cx = ParseContext::default();
|
let mut cx = ParseContext::default();
|
||||||
|
|
||||||
if let Some(value) = document.parse_from_str(&mut cx, "graphics_backend") {
|
if let Some(value) = document.parse_from_str(&mut cx, "graphics_backend") {
|
||||||
result.result.graphics_backend = value;
|
result.graphics_backend = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(value) = document.parse_from_str(&mut cx, "graphics_power_preference") {
|
if let Some(value) = document.parse_from_str(&mut cx, "graphics_power_preference") {
|
||||||
result.result.graphics_power_preference = value;
|
result.graphics_power_preference = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(value) = document.parse_from_str(&mut cx, "language") {
|
if let Some(value) = document.parse_from_str(&mut cx, "language") {
|
||||||
result.result.language = value;
|
result.language = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(value) = document.parse_from_str(&mut cx, "output_device") {
|
if let Some(value) = document.parse_from_str(&mut cx, "output_device") {
|
||||||
result.result.output_device = Some(value);
|
result.output_device = Some(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(value) = document.get_float(&mut cx, "volume") {
|
if let Some(value) = document.get_float(&mut cx, "volume") {
|
||||||
result.result.volume = value.clamp(0.0, 1.0) as f32;
|
result.volume = value.clamp(0.0, 1.0) as f32;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(value) = document.get_bool(&mut cx, "mute") {
|
if let Some(value) = document.get_bool(&mut cx, "mute") {
|
||||||
result.result.mute = value;
|
result.mute = value;
|
||||||
};
|
};
|
||||||
|
|
||||||
document.get_table_like(&mut cx, "log", |cx, log| {
|
document.get_table_like(&mut cx, "log", |cx, log| {
|
||||||
if let Some(value) = log.parse_from_str(cx, "filename_pattern") {
|
if let Some(value) = log.parse_from_str(cx, "filename_pattern") {
|
||||||
result.result.log.filename_pattern = value;
|
result.log.filename_pattern = value;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
document.get_table_like(&mut cx, "storage", |cx, storage| {
|
document.get_table_like(&mut cx, "storage", |cx, storage| {
|
||||||
if let Some(value) = storage.parse_from_str(cx, "backend") {
|
if let Some(value) = storage.parse_from_str(cx, "backend") {
|
||||||
result.result.storage.backend = value;
|
result.storage.backend = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
result.warnings = cx.warnings;
|
ParseResult {
|
||||||
(result, document)
|
result: DocumentHolder::new(result, document),
|
||||||
|
warnings: cx.warnings,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_bookmarks(input: &str) -> (ParseResult<Vec<Bookmark>>, DocumentMut) {
|
pub fn read_bookmarks(input: &str) -> ParseResult<Vec<Bookmark>> {
|
||||||
let mut result = ParseResult {
|
|
||||||
result: Default::default(),
|
|
||||||
warnings: vec![],
|
|
||||||
};
|
|
||||||
let document = match input.parse::<DocumentMut>() {
|
let document = match input.parse::<DocumentMut>() {
|
||||||
Ok(document) => document,
|
Ok(document) => document,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
result.add_warning(format!("Invalid TOML: {e}"));
|
return ParseResult {
|
||||||
return (result, DocumentMut::default());
|
result: Default::default(),
|
||||||
|
warnings: vec![format!("Invalid TOML: {e}")],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut result = Vec::new();
|
||||||
let mut cx = ParseContext::default();
|
let mut cx = ParseContext::default();
|
||||||
|
|
||||||
document.get_array_of_tables(&mut cx, "bookmark", |cx, bookmarks| {
|
document.get_array_of_tables(&mut cx, "bookmark", |cx, bookmarks| {
|
||||||
|
@ -96,12 +96,14 @@ pub fn read_bookmarks(input: &str) -> (ParseResult<Vec<Bookmark>>, DocumentMut)
|
||||||
None => crate::util::url_to_readable_name(&url).into_owned(),
|
None => crate::util::url_to_readable_name(&url).into_owned(),
|
||||||
};
|
};
|
||||||
|
|
||||||
result.result.push(Bookmark { url, name });
|
result.push(Bookmark { url, name });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
result.warnings = cx.warnings;
|
ParseResult {
|
||||||
(result, document)
|
result: DocumentHolder::new(result, document),
|
||||||
|
warnings: cx.warnings,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
@ -116,473 +118,381 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_toml() {
|
fn invalid_toml() {
|
||||||
let result = read_preferences("~~INVALID~~").0;
|
let result = read_preferences("~~INVALID~~");
|
||||||
|
|
||||||
assert_eq!(ParseResult{result: Default::default(), warnings:
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
vec![
|
assert_eq!(vec!["Invalid TOML: TOML parse error at line 1, column 1\n |\n1 | ~~INVALID~~\n | ^\ninvalid key\n".to_string()], result.warnings);
|
||||||
"Invalid TOML: TOML parse error at line 1, column 1\n |\n1 | ~~INVALID~~\n | ^\ninvalid key\n".to_string()
|
|
||||||
]}, result
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_toml() {
|
fn empty_toml() {
|
||||||
let result = read_preferences("").0;
|
let result = read_preferences("");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
ParseResult {
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
result: Default::default(),
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
|
||||||
result
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_backend_type() {
|
fn invalid_backend_type() {
|
||||||
let result = read_preferences("graphics_backend = 5").0;
|
let result = read_preferences("graphics_backend = 5");
|
||||||
|
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid graphics_backend: expected string but found integer".to_string()],
|
||||||
result: Default::default(),
|
result.warnings
|
||||||
warnings: vec![
|
|
||||||
"Invalid graphics_backend: expected string but found integer".to_string()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
result
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_backend_value() {
|
fn invalid_backend_value() {
|
||||||
let result = read_preferences("graphics_backend = \"fast\"").0;
|
let result = read_preferences("graphics_backend = \"fast\"");
|
||||||
|
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid graphics_backend: unsupported value \"fast\"".to_string()],
|
||||||
result: Default::default(),
|
result.warnings
|
||||||
warnings: vec!["Invalid graphics_backend: unsupported value \"fast\"".to_string()]
|
|
||||||
},
|
|
||||||
result
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn correct_backend_value() {
|
fn correct_backend_value() {
|
||||||
let result = read_preferences("graphics_backend = \"vulkan\"").0;
|
let result = read_preferences("graphics_backend = \"vulkan\"");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
graphics_backend: GraphicsBackend::Vulkan,
|
||||||
graphics_backend: GraphicsBackend::Vulkan,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
result
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_power_type() {
|
fn invalid_power_type() {
|
||||||
let result = read_preferences("graphics_power_preference = 5").0;
|
let result = read_preferences("graphics_power_preference = 5");
|
||||||
|
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec![
|
||||||
result: Default::default(),
|
"Invalid graphics_power_preference: expected string but found integer".to_string()
|
||||||
warnings: vec![
|
],
|
||||||
"Invalid graphics_power_preference: expected string but found integer"
|
result.warnings
|
||||||
.to_string()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
result
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_power_value() {
|
fn invalid_power_value() {
|
||||||
let result = read_preferences("graphics_power_preference = \"fast\"").0;
|
let result = read_preferences("graphics_power_preference = \"fast\"");
|
||||||
|
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid graphics_power_preference: unsupported value \"fast\"".to_string()],
|
||||||
result: Default::default(),
|
result.warnings
|
||||||
warnings: vec![
|
|
||||||
"Invalid graphics_power_preference: unsupported value \"fast\"".to_string()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
result
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn correct_power_value() {
|
fn correct_power_value() {
|
||||||
let result = read_preferences("graphics_power_preference = \"low\"").0;
|
let result = read_preferences("graphics_power_preference = \"low\"");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
graphics_power_preference: PowerPreference::Low,
|
||||||
graphics_power_preference: PowerPreference::Low,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
result
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_language_value() {
|
fn invalid_language_value() {
|
||||||
let result = read_preferences("language = \"???\"").0;
|
let result = read_preferences("language = \"???\"");
|
||||||
|
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid language: unsupported value \"???\"".to_string()],
|
||||||
result: Default::default(),
|
result.warnings
|
||||||
warnings: vec!["Invalid language: unsupported value \"???\"".to_string()]
|
|
||||||
},
|
|
||||||
result
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn correct_language_value() {
|
fn correct_language_value() {
|
||||||
let result = read_preferences("language = \"en-US\"").0;
|
let result = read_preferences("language = \"en-US\"");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
language: langid!("en-US"),
|
||||||
language: langid!("en-US"),
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
result
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn correct_output_device() {
|
fn correct_output_device() {
|
||||||
let result = read_preferences("output_device = \"Speakers\"").0;
|
let result = read_preferences("output_device = \"Speakers\"");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
output_device: Some("Speakers".to_string()),
|
||||||
output_device: Some("Speakers".to_string()),
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
result
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_output_device() {
|
fn invalid_output_device() {
|
||||||
let result = read_preferences("output_device = 5").0;
|
let result = read_preferences("output_device = 5");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
output_device: None,
|
||||||
output_device: None,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![
|
|
||||||
"Invalid output_device: expected string but found integer".to_string()
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
result
|
result.values()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["Invalid output_device: expected string but found integer".to_string()],
|
||||||
|
result.warnings
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mute() {
|
fn mute() {
|
||||||
|
let result = read_preferences("mute = \"false\"");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
mute: false,
|
||||||
mute: false,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec!["Invalid mute: expected boolean but found string".to_string()]
|
|
||||||
},
|
},
|
||||||
read_preferences("mute = \"false\"").0
|
result.values()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["Invalid mute: expected boolean but found string".to_string()],
|
||||||
|
result.warnings
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let result = read_preferences("mute = true");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
mute: true,
|
||||||
mute: true,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
read_preferences("mute = true").0
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
|
|
||||||
|
let result = read_preferences("");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
mute: false,
|
||||||
mute: false,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
read_preferences("").0
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn volume() {
|
fn volume() {
|
||||||
|
let result = read_preferences("volume = \"0.5\"");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
volume: 1.0,
|
||||||
volume: 1.0,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec!["Invalid volume: expected float but found string".to_string()]
|
|
||||||
},
|
},
|
||||||
read_preferences("volume = \"0.5\"").0
|
result.values()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["Invalid volume: expected float but found string".to_string()],
|
||||||
|
result.warnings
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let result = read_preferences("volume = 0.5");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
volume: 0.5,
|
||||||
volume: 0.5,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
read_preferences("volume = 0.5").0
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
|
|
||||||
|
let result = read_preferences("volume = -1.0");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
volume: 0.0,
|
||||||
volume: 0.0,
|
..Default::default()
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![]
|
|
||||||
},
|
},
|
||||||
read_preferences("volume = -1.0").0
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn log_filename() {
|
fn log_filename() {
|
||||||
|
let result = read_preferences("log = {filename_pattern = 5}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
log: LogPreferences {
|
||||||
log: LogPreferences {
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
warnings: vec![
|
..Default::default()
|
||||||
"Invalid log.filename_pattern: expected string but found integer".to_string()
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
read_preferences("log = {filename_pattern = 5}").0
|
result.values()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["Invalid log.filename_pattern: expected string but found integer".to_string()],
|
||||||
|
result.warnings
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let result = read_preferences("log = {filename_pattern = \"???\"}");
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid log.filename_pattern: unsupported value \"???\"".to_string()],
|
||||||
result: SavedGlobalPreferences {
|
result.warnings
|
||||||
log: LogPreferences {
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![
|
|
||||||
"Invalid log.filename_pattern: unsupported value \"???\"".to_string()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
read_preferences("log = {filename_pattern = \"???\"}").0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let result = read_preferences("log = {filename_pattern = \"with_timestamp\"}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
log: LogPreferences {
|
||||||
log: LogPreferences {
|
filename_pattern: FilenamePattern::WithTimestamp,
|
||||||
filename_pattern: FilenamePattern::WithTimestamp,
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
warnings: vec![]
|
..Default::default()
|
||||||
},
|
},
|
||||||
read_preferences("log = {filename_pattern = \"with_timestamp\"}").0
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn log() {
|
fn log() {
|
||||||
|
let result = read_preferences("log = \"yes\"");
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid log: expected table but found string".to_string()],
|
||||||
result: SavedGlobalPreferences {
|
result.warnings
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec!["Invalid log: expected table but found string".to_string()]
|
|
||||||
},
|
|
||||||
read_preferences("log = \"yes\"").0
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn storage_backend() {
|
fn storage_backend() {
|
||||||
|
let result = read_preferences("storage = {backend = 5}");
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid storage.backend: expected string but found integer".to_string()],
|
||||||
result: SavedGlobalPreferences {
|
result.warnings
|
||||||
storage: StoragePreferences {
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec![
|
|
||||||
"Invalid storage.backend: expected string but found integer".to_string()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
read_preferences("storage = {backend = 5}").0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let result = read_preferences("storage = {backend = \"???\"}");
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid storage.backend: unsupported value \"???\"".to_string()],
|
||||||
result: SavedGlobalPreferences {
|
result.warnings
|
||||||
storage: StoragePreferences {
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec!["Invalid storage.backend: unsupported value \"???\"".to_string()]
|
|
||||||
},
|
|
||||||
read_preferences("storage = {backend = \"???\"}").0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let result = read_preferences("storage = {backend = \"memory\"}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&SavedGlobalPreferences {
|
||||||
result: SavedGlobalPreferences {
|
storage: StoragePreferences {
|
||||||
storage: StoragePreferences {
|
backend: StorageBackend::Memory,
|
||||||
backend: StorageBackend::Memory,
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
},
|
},
|
||||||
warnings: vec![]
|
..Default::default()
|
||||||
},
|
},
|
||||||
read_preferences("storage = {backend = \"memory\"}").0
|
result.values()
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn storage() {
|
fn storage() {
|
||||||
|
let result = read_preferences("storage = \"no\"");
|
||||||
|
assert_eq!(&SavedGlobalPreferences::default(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid storage: expected table but found string".to_string()],
|
||||||
result: SavedGlobalPreferences {
|
result.warnings
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
warnings: vec!["Invalid storage: expected table but found string".to_string()]
|
|
||||||
},
|
|
||||||
read_preferences("storage = \"no\"").0
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bookmark() {
|
fn bookmark() {
|
||||||
|
let result = read_bookmarks("[bookmark]");
|
||||||
|
assert_eq!(&Vec::<Bookmark>::new(), result.values());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
vec!["Invalid bookmark: expected array of tables but found table".to_string()],
|
||||||
result: vec![],
|
result.warnings
|
||||||
|
|
||||||
warnings: vec![
|
|
||||||
"Invalid bookmark: expected array of tables but found table".to_string()
|
|
||||||
]
|
|
||||||
},
|
|
||||||
read_bookmarks("[bookmark]").0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let result = read_bookmarks("[[bookmark]]");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&vec![Bookmark {
|
||||||
result: vec![Bookmark {
|
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
||||||
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
name: "".to_string(),
|
||||||
name: "".to_string(),
|
}],
|
||||||
}],
|
result.values()
|
||||||
warnings: vec![],
|
);
|
||||||
},
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
read_bookmarks("[[bookmark]]").0
|
|
||||||
|
let result = read_bookmarks("[[bookmark]]\nurl = \"invalid\"");
|
||||||
|
assert_eq!(
|
||||||
|
&vec![Bookmark {
|
||||||
|
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
||||||
|
name: "".to_string(),
|
||||||
|
}],
|
||||||
|
result.values()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["Invalid bookmark.url: unsupported value \"invalid\"".to_string()],
|
||||||
|
result.warnings
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
let result = read_bookmarks(
|
||||||
ParseResult {
|
"[[bookmark]]\nurl = \"https://ruffle.rs/logo-anim.swf\"\nname = \"Logo SWF\"",
|
||||||
result: vec![Bookmark {
|
|
||||||
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
|
||||||
name: "".to_string(),
|
|
||||||
}],
|
|
||||||
warnings: vec!["Invalid bookmark.url: unsupported value \"invalid\"".to_string()],
|
|
||||||
},
|
|
||||||
read_bookmarks("[[bookmark]]\nurl = \"invalid\"").0,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&vec![Bookmark {
|
||||||
result: vec![Bookmark {
|
url: Url::parse("https://ruffle.rs/logo-anim.swf").unwrap(),
|
||||||
url: Url::parse("https://ruffle.rs/logo-anim.swf").unwrap(),
|
name: "Logo SWF".to_string(),
|
||||||
name: "Logo SWF".to_string(),
|
}],
|
||||||
}],
|
result.values()
|
||||||
warnings: vec![],
|
|
||||||
},
|
|
||||||
read_bookmarks(
|
|
||||||
"[[bookmark]]\nurl = \"https://ruffle.rs/logo-anim.swf\"\nname = \"Logo SWF\""
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multiple_bookmarks() {
|
fn multiple_bookmarks() {
|
||||||
assert_eq!(
|
let result = read_bookmarks(
|
||||||
ParseResult {
|
r#"
|
||||||
result: vec![
|
|
||||||
Bookmark {
|
|
||||||
url: Url::from_str("file:///home/user/example.swf").unwrap(),
|
|
||||||
name: "example.swf".to_string(),
|
|
||||||
},
|
|
||||||
Bookmark {
|
|
||||||
url: Url::from_str("https://ruffle.rs/logo-anim.swf").unwrap(),
|
|
||||||
name: "logo-anim.swf".to_string(),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
warnings: vec![],
|
|
||||||
},
|
|
||||||
read_bookmarks(
|
|
||||||
r#"
|
|
||||||
[[bookmark]]
|
[[bookmark]]
|
||||||
url = "file:///home/user/example.swf"
|
url = "file:///home/user/example.swf"
|
||||||
|
|
||||||
[[bookmark]]
|
[[bookmark]]
|
||||||
url = "https://ruffle.rs/logo-anim.swf"
|
url = "https://ruffle.rs/logo-anim.swf"
|
||||||
"#
|
"#,
|
||||||
)
|
|
||||||
.0
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ParseResult {
|
&vec![
|
||||||
result: vec![
|
Bookmark {
|
||||||
Bookmark {
|
url: Url::from_str("file:///home/user/example.swf").unwrap(),
|
||||||
url: Url::from_str("file:///home/user/example.swf").unwrap(),
|
name: "example.swf".to_string(),
|
||||||
name: "example.swf".to_string(),
|
},
|
||||||
},
|
Bookmark {
|
||||||
Bookmark {
|
url: Url::from_str("https://ruffle.rs/logo-anim.swf").unwrap(),
|
||||||
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
name: "logo-anim.swf".to_string(),
|
||||||
name: "".to_string(),
|
}
|
||||||
},
|
],
|
||||||
Bookmark {
|
result.values()
|
||||||
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
);
|
||||||
name: "".to_string(),
|
assert_eq!(Vec::<String>::new(), result.warnings);
|
||||||
},
|
|
||||||
Bookmark {
|
|
||||||
url: Url::from_str("https://ruffle.rs/logo-anim.swf").unwrap(),
|
|
||||||
name: "logo-anim.swf".to_string(),
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
warnings: vec!["Invalid bookmark.url: unsupported value \"invalid\"".to_string(),],
|
let result = read_bookmarks(
|
||||||
},
|
r#"
|
||||||
read_bookmarks(
|
|
||||||
r#"
|
|
||||||
[[bookmark]]
|
[[bookmark]]
|
||||||
url = "file:///home/user/example.swf"
|
url = "file:///home/user/example.swf"
|
||||||
|
|
||||||
|
@ -593,9 +503,32 @@ mod tests {
|
||||||
|
|
||||||
[[bookmark]]
|
[[bookmark]]
|
||||||
url = "https://ruffle.rs/logo-anim.swf"
|
url = "https://ruffle.rs/logo-anim.swf"
|
||||||
"#
|
"#,
|
||||||
)
|
);
|
||||||
.0
|
assert_eq!(
|
||||||
|
&vec![
|
||||||
|
Bookmark {
|
||||||
|
url: Url::from_str("file:///home/user/example.swf").unwrap(),
|
||||||
|
name: "example.swf".to_string(),
|
||||||
|
},
|
||||||
|
Bookmark {
|
||||||
|
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
||||||
|
name: "".to_string(),
|
||||||
|
},
|
||||||
|
Bookmark {
|
||||||
|
url: Url::parse(crate::preferences::INVALID_URL).unwrap(),
|
||||||
|
name: "".to_string(),
|
||||||
|
},
|
||||||
|
Bookmark {
|
||||||
|
url: Url::from_str("https://ruffle.rs/logo-anim.swf").unwrap(),
|
||||||
|
name: "logo-anim.swf".to_string(),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
result.values()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec!["Invalid bookmark.url: unsupported value \"invalid\"".to_string()],
|
||||||
|
result.warnings
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,22 +155,17 @@ mod tests {
|
||||||
|
|
||||||
macro_rules! define_serialization_test_helpers {
|
macro_rules! define_serialization_test_helpers {
|
||||||
($read_method:ident, $doc_struct:ty, $writer:ident) => {
|
($read_method:ident, $doc_struct:ty, $writer:ident) => {
|
||||||
fn parse(input: &str) -> DocumentHolder<$doc_struct> {
|
|
||||||
let (result, document) = $read_method(input);
|
|
||||||
DocumentHolder::new(result.result, document)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_roundtrip(preferences: &DocumentHolder<$doc_struct>) {
|
fn check_roundtrip(preferences: &DocumentHolder<$doc_struct>) {
|
||||||
let read_result = $read_method(&preferences.serialize());
|
let read_result = $read_method(&preferences.serialize());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*preferences.deref(),
|
preferences.deref(),
|
||||||
read_result.0.result,
|
read_result.values(),
|
||||||
"roundtrip failed: expected != actual"
|
"roundtrip failed: expected != actual"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test(original: &str, fun: impl FnOnce(&mut $writer), expected: &str) {
|
fn test(original: &str, fun: impl FnOnce(&mut $writer), expected: &str) {
|
||||||
let mut preferences = parse(original);
|
let mut preferences = $read_method(original).result;
|
||||||
let mut writer = $writer::new(&mut preferences);
|
let mut writer = $writer::new(&mut preferences);
|
||||||
fun(&mut writer);
|
fun(&mut writer);
|
||||||
check_roundtrip(&preferences);
|
check_roundtrip(&preferences);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::fmt::Formatter;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use toml_edit::{ArrayOfTables, DocumentMut, Item, Table, TableLike};
|
use toml_edit::{ArrayOfTables, DocumentMut, Item, Table, TableLike};
|
||||||
|
@ -36,6 +37,14 @@ impl<T: Default> Default for DocumentHolder<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: fmt::Debug> fmt::Debug for DocumentHolder<T> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("DocumentHolder")
|
||||||
|
.field("inner", &self.inner)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> DocumentHolder<T> {
|
impl<T> DocumentHolder<T> {
|
||||||
pub fn new(values: T, document: DocumentMut) -> Self {
|
pub fn new(values: T, document: DocumentMut) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -64,16 +73,28 @@ impl<T> DocumentHolder<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
pub struct ParseResult<T> {
|
||||||
pub struct ParseResult<T: PartialEq + fmt::Debug> {
|
pub result: DocumentHolder<T>,
|
||||||
pub result: T,
|
|
||||||
pub warnings: Vec<String>,
|
pub warnings: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: fmt::Debug + PartialEq> ParseResult<T> {
|
impl<T: fmt::Debug> fmt::Debug for ParseResult<T> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ParseResult")
|
||||||
|
.field("result", &self.result)
|
||||||
|
.field("warnings", &self.warnings)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ParseResult<T> {
|
||||||
pub fn add_warning(&mut self, message: String) {
|
pub fn add_warning(&mut self, message: String) {
|
||||||
self.warnings.push(message);
|
self.warnings.push(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn values(&self) -> &T {
|
||||||
|
&self.result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
Loading…
Reference in New Issue