diff --git a/Cargo.toml b/Cargo.toml index ac48f69..2efef92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ exclude = ["/.*"] [dependencies] anyhow = { version = "1.0.75", optional = true } -cfg-if = "1.0.0" json5 = { version = "0.4.1", optional = true } ron = { version = "0.8.1", optional = true } serde = "1.0.190" @@ -43,7 +42,6 @@ toml = ["dep:toml"] yaml = ["dep:serde_yaml"] [dev-dependencies] -assert_matches = "1.5.0" indoc = "2.0.4" pretty_assertions = "1.4.0" rstest = { version = "0.18.2", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 4e71846..5dae9fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,7 +80,6 @@ //! } //! ``` -use cfg_if::cfg_if; use serde::{de::DeserializeOwned, Serialize}; use std::fs::File; use std::io; @@ -91,11 +90,10 @@ use thiserror::Error; #[cfg(feature = "ron")] use ron::ser::PrettyConfig; -/// An enum of the file formats supported by `cfgurate`. +/// An enum of file formats supported by this build of `cfgurate`. /// -/// All variants are always present, even if support for a given format was -/// disabled at compile time. To test whether support for a format is enabled, -/// use the [Format::is_enabled] method. +/// Each variant is only present if the corresponding Cargo feature of +/// `cfgurate` was enabled at compile time. /// /// A Format can be [displayed][std::fmt::Display] as a string containing its /// name in all-uppercase, and a Format can be [parsed][std::str::FromStr] from @@ -104,11 +102,14 @@ use ron::ser::PrettyConfig; Clone, Copy, Debug, Display, EnumIter, EnumString, Eq, Hash, Ord, PartialEq, PartialOrd, )] #[strum(ascii_case_insensitive, serialize_all = "UPPERCASE")] +#[non_exhaustive] pub enum Format { /// The [JSON](https://www.json.org) format, (de)serialized with the /// [serde_json] crate. /// /// Serialization uses multiline/"pretty" format. + #[cfg(feature = "json")] + #[cfg_attr(docsrs, doc(cfg(feature = "json")))] Json, /// The [JSON5](https://json5.org) format, deserialized with the [json5] @@ -117,12 +118,16 @@ pub enum Format { /// Serialization uses multiline/"pretty" format, performed via serde_json, /// as json5's serialization (which also uses serde_json) is /// single-line/"non-pretty." + #[cfg(feature = "json5")] + #[cfg_attr(docsrs, doc(cfg(feature = "json5")))] Json5, /// The [RON](https://github.com/ron-rs/ron) format, (de)serialized with /// the [ron] crate. /// /// Serialization uses multiline/"pretty" format. + #[cfg(feature = "ron")] + #[cfg_attr(docsrs, doc(cfg(feature = "ron")))] Ron, /// The [TOML](https://toml.io) format, (de)serialized with the [toml] @@ -130,57 +135,51 @@ pub enum Format { /// /// Serialization uses "pretty" format, in which arrays are serialized on /// multiple lines. + #[cfg(feature = "toml")] + #[cfg_attr(docsrs, doc(cfg(feature = "toml")))] Toml, /// The [YAML](https://yaml.org) format, (de)serialized with the /// [serde_yaml] crate. + #[cfg(feature = "yaml")] + #[cfg_attr(docsrs, doc(cfg(feature = "yaml")))] Yaml, } impl Format { - /// Returns true iff support for the format was enabled at compile time via - /// the relevant Cargo feature - pub fn is_enabled(&self) -> bool { - match self { - Format::Json => cfg!(feature = "json"), - Format::Json5 => cfg!(feature = "json5"), - Format::Ron => cfg!(feature = "ron"), - Format::Toml => cfg!(feature = "toml"), - Format::Yaml => cfg!(feature = "yaml"), - } - } - /// Returns an iterator over all [Format] variants pub fn iter() -> FormatIter { // To avoid the need for users to import the trait ::iter() } - /// Returns an iterator over all [enabled][Format::is_enabled] [Format] - /// variants - pub fn enabled() -> EnabledFormatIter { - EnabledFormatIter::new() - } - /// Returns an array of the recognized file extensions for the file format. /// /// File extensions are lowercase and do not start with a period. - /// - /// # Example - /// - /// ``` - /// use cfgurate::Format; - /// - /// assert_eq!(Format::Json.extensions(), &["json"]); - /// assert_eq!(Format::Yaml.extensions(), &["yaml", "yml"]); - /// ``` + #[cfg_attr(all(feature = "json", feature = "yaml"), doc = concat!( + "# Example\n", + "\n", + "```\n", + "use cfgurate::Format;\n", + "\n", + "assert_eq!(Format::Json.extensions(), &[\"json\"]);\n", + "assert_eq!(Format::Yaml.extensions(), &[\"yaml\", \"yml\"]);\n", + "```\n", + ))] pub fn extensions(&self) -> &'static [&'static str] { match self { + #[cfg(feature = "json")] Format::Json => &["json"], + #[cfg(feature = "json5")] Format::Json5 => &["json5"], + #[cfg(feature = "ron")] Format::Ron => &["ron"], + #[cfg(feature = "toml")] Format::Toml => &["toml"], + #[cfg(feature = "yaml")] Format::Yaml => &["yaml", "yml"], + #[allow(unreachable_patterns)] + _ => unreachable!(), } } @@ -189,16 +188,17 @@ impl Format { /// File extensions are matched case-insensitively and may optionally start /// with a period. If the given file extension does not correspond to a /// known file format, `None` is returned. - /// - /// # Example - /// - /// ``` - /// use cfgurate::Format; - /// - /// assert_eq!(Format::from_extension(".json"), Some(Format::Json)); - /// assert_eq!(Format::from_extension("YML"), Some(Format::Yaml)); - /// assert_eq!(Format::from_extension("cfg"), None); - /// ``` + #[cfg_attr(all(feature = "json", feature = "yaml"), doc = concat!( + "# Example\n", + "\n", + "```\n", + "use cfgurate::Format;\n", + "\n", + "assert_eq!(Format::from_extension(\".json\"), Some(Format::Json));\n", + "assert_eq!(Format::from_extension(\"YML\"), Some(Format::Yaml));\n", + "assert_eq!(Format::from_extension(\"cfg\"), None);\n", + "```\n", + ))] pub fn from_extension(ext: &str) -> Option { let ext = ext.strip_prefix('.').unwrap_or(ext).to_ascii_lowercase(); let ext = &*ext; @@ -206,9 +206,6 @@ impl Format { } /// Determine the [Format] of a file path based on its file extension. - /// - /// Only [enabled][Format::is_enabled] formats are supported by this - /// method. #[cfg_attr(all(feature = "json", feature = "ron"), doc = concat!( "# Example\n", "\n", @@ -224,8 +221,8 @@ impl Format { /// # Errors /// /// Returns an error if the given file path does not have an extension, the - /// extension is not valid Unicode, the extension is unknown, or the - /// extension is for a disabled format. + /// extension is not valid Unicode, or the extension is unknown to this + /// build. pub fn identify>(path: P) -> Result { let Some(ext) = path.as_ref().extension() else { return Err(IdentifyError::NoExtension); @@ -233,69 +230,32 @@ impl Format { let Some(ext) = ext.to_str() else { return Err(IdentifyError::NotUnicode); }; - match Format::from_extension(ext) { - Some(f) if f.is_enabled() => Ok(f), - Some(f) => Err(IdentifyError::NotEnabled(f)), - _ => Err(IdentifyError::Unknown(ext.to_owned())), - } + Format::from_extension(ext).ok_or_else(|| IdentifyError::Unknown(ext.to_owned())) } /// Serialize a value to a string in this format /// /// # Errors /// - /// Returns an error if the format is not [enabled][Format::is_enabled] or - /// if the underlying serializer returns an error. + /// Returns an error if the underlying serializer returns an error. #[allow(unused)] pub fn dump_to_string(&self, value: &T) -> Result { match self { - Format::Json => { - cfg_if! { - if #[cfg(feature = "json")] { - serde_json::to_string_pretty(value).map_err(Into::into) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } - } + #[cfg(feature = "json")] + Format::Json => serde_json::to_string_pretty(value).map_err(Into::into), + #[cfg(feature = "json5")] Format::Json5 => { - cfg_if! { - if #[cfg(feature = "json5")] { - /// json5::to_string() just serializes as JSON, but - /// non-prettily. - serde_json::to_string_pretty(value).map_err(Into::into) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } - } - Format::Ron => { - cfg_if! { - if #[cfg(feature = "ron")] { - ron::ser::to_string_pretty(value, ron_config()).map_err(Into::into) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } - } - Format::Toml => { - cfg_if! { - if #[cfg(feature = "toml")] { - toml::to_string_pretty(value).map_err(Into::into) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } - } - Format::Yaml => { - cfg_if! { - if #[cfg(feature = "yaml")] { - serde_yaml::to_string(value).map_err(Into::into) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } + /// json5::to_string() just serializes as JSON, but + /// non-prettily. + serde_json::to_string_pretty(value).map_err(Into::into) } + #[cfg(feature = "ron")] + Format::Ron => ron::ser::to_string_pretty(value, ron_config()).map_err(Into::into), + #[cfg(feature = "toml")] + Format::Toml => toml::to_string_pretty(value).map_err(Into::into), + #[cfg(feature = "yaml")] + Format::Yaml => serde_yaml::to_string(value).map_err(Into::into), + _ => unreachable!(), } } @@ -303,56 +263,21 @@ impl Format { /// /// # Errors /// - /// Returns an error if the format is not [enabled][Format::is_enabled] or - /// if the underlying deserializer returns an error. + /// Returns an error if the underlying deserializer returns an error. #[allow(unused)] pub fn load_from_str(&self, s: &str) -> Result { match self { - Format::Json => { - cfg_if! { - if #[cfg(feature = "json")] { - serde_json::from_str(s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } - } - Format::Json5 => { - cfg_if! { - if #[cfg(feature = "json5")] { - json5::from_str(s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } - } - Format::Ron => { - cfg_if! { - if #[cfg(feature = "ron")] { - ron::from_str(s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } - } - Format::Toml => { - cfg_if! { - if #[cfg(feature = "toml")] { - toml::from_str(s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } - } - Format::Yaml => { - cfg_if! { - if #[cfg(feature = "yaml")] { - serde_yaml::from_str(s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } - } + #[cfg(feature = "json")] + Format::Json => serde_json::from_str(s).map_err(Into::into), + #[cfg(feature = "json5")] + Format::Json5 => json5::from_str(s).map_err(Into::into), + #[cfg(feature = "ron")] + Format::Ron => ron::from_str(s).map_err(Into::into), + #[cfg(feature = "toml")] + Format::Toml => toml::from_str(s).map_err(Into::into), + #[cfg(feature = "yaml")] + Format::Yaml => serde_yaml::from_str(s).map_err(Into::into), + _ => unreachable!(), } } @@ -364,8 +289,8 @@ impl Format { /// /// # Errors /// - /// Returns an error if the format is not [enabled][Format::is_enabled], if - /// an I/O error occurs, or if the underlying serializer returns an error. + /// Returns an error if an I/O error occurs or if the underlying serializer + /// returns an error. #[allow(unused)] pub fn dump_to_writer( &self, @@ -373,62 +298,36 @@ impl Format { value: &T, ) -> Result<(), SerializeError> { match self { + #[cfg(feature = "json")] Format::Json => { - cfg_if! { - if #[cfg(feature = "json")] { - serde_json::to_writer_pretty(&mut writer, value)?; - writer.write_all(b"\n")?; - Ok(()) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } + serde_json::to_writer_pretty(&mut writer, value)?; + writer.write_all(b"\n")?; + Ok(()) } + #[cfg(feature = "json5")] Format::Json5 => { - cfg_if! { - if #[cfg(feature = "json5")] { - // Serialize as JSON, as that's what json5 does, except - // the latter doesn't support serializing to a writer. - serde_json::to_writer_pretty(&mut writer, value)?; - writer.write_all(b"\n")?; - Ok(()) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } + // Serialize as JSON, as that's what json5 does, except the + // latter doesn't support serializing to a writer. + serde_json::to_writer_pretty(&mut writer, value)?; + writer.write_all(b"\n")?; + Ok(()) } + #[cfg(feature = "ron")] Format::Ron => { - cfg_if! { - if #[cfg(feature = "ron")] { - let mut ser = ron::Serializer::new(&mut writer, Some(ron_config()))?; - value.serialize(&mut ser)?; - writer.write_all(b"\n")?; - Ok(()) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } + let mut ser = ron::Serializer::new(&mut writer, Some(ron_config()))?; + value.serialize(&mut ser)?; + writer.write_all(b"\n")?; + Ok(()) } + #[cfg(feature = "toml")] Format::Toml => { - cfg_if! { - if #[cfg(feature = "toml")] { - let s = toml::to_string_pretty(value)?; - writer.write_all(s.as_bytes())?; - Ok(()) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } - } - Format::Yaml => { - cfg_if! { - if #[cfg(feature = "yaml")] { - serde_yaml::to_writer(writer, value).map_err(Into::into) - } else { - Err(SerializeError::NotEnabled(*self)) - } - } + let s = toml::to_string_pretty(value)?; + writer.write_all(s.as_bytes())?; + Ok(()) } + #[cfg(feature = "yaml")] + Format::Yaml => serde_yaml::to_writer(writer, value).map_err(Into::into), + _ => unreachable!(), } } @@ -436,63 +335,34 @@ impl Format { /// /// # Errors /// - /// Returns an error if the format is not [enabled][Format::is_enabled], if - /// an I/O error occurs, or if the underlying deserializer returns an - /// error. + /// Returns an error if an I/O error occurs or if the underlying + /// deserializer returns an error. #[allow(unused)] pub fn load_from_reader( &self, mut reader: R, ) -> Result { match self { - Format::Json => { - cfg_if! { - if #[cfg(feature = "json")] { - serde_json::from_reader(reader).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } - } + #[cfg(feature = "json")] + Format::Json => serde_json::from_reader(reader).map_err(Into::into), + #[cfg(feature = "json5")] Format::Json5 => { - cfg_if! { - if #[cfg(feature = "json5")] { - let s = io::read_to_string(reader)?; - json5::from_str(&s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } + let s = io::read_to_string(reader)?; + json5::from_str(&s).map_err(Into::into) } + #[cfg(feature = "ron")] Format::Ron => { - cfg_if! { - if #[cfg(feature = "ron")] { - let s = io::read_to_string(reader)?; - ron::from_str(&s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } + let s = io::read_to_string(reader)?; + ron::from_str(&s).map_err(Into::into) } + #[cfg(feature = "toml")] Format::Toml => { - cfg_if! { - if #[cfg(feature = "toml")] { - let s = io::read_to_string(reader)?; - toml::from_str(&s).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } - } - Format::Yaml => { - cfg_if! { - if #[cfg(feature = "yaml")] { - serde_yaml::from_reader(reader).map_err(Into::into) - } else { - Err(DeserializeError::NotEnabled(*self)) - } - } + let s = io::read_to_string(reader)?; + toml::from_str(&s).map_err(Into::into) } + #[cfg(feature = "yaml")] + Format::Yaml => serde_yaml::from_reader(reader).map_err(Into::into), + _ => unreachable!(), } } } @@ -510,8 +380,8 @@ fn ron_config() -> PrettyConfig { /// # Errors /// /// Returns an error if the format cannot be determined from the file -/// extension, if the format is not [enabled][Format::is_enabled], if an I/O -/// error occurs, or if the underlying deserializer returns an error. +/// extension, if an I/O error occurs, or if the underlying deserializer +/// returns an error. pub fn load>(path: P) -> Result { let fmt = Format::identify(&path)?; let fp = File::open(path).map_err(LoadError::Open)?; @@ -524,8 +394,8 @@ pub fn load>(path: P) -> Result>(value: &T, path: P) -> Result<(), DumpError> { let fmt = Format::identify(&path)?; let fp = File::create(path).map_err(DumpError::Open)?; @@ -535,15 +405,8 @@ pub fn dump>(value: &T, path: P) -> Result<(), Dump /// Error type returned by [Format::identify] #[derive(Clone, Debug, Eq, Error, PartialEq)] pub enum IdentifyError { - /// Returned if the file path's extension corresponded to a format that was - /// not [enabled][Format::is_enabled] - #[error("file extension indicates {0}, support for which is not enabled")] - NotEnabled( - /// The format in question - Format, - ), - /// Returned if the file path's extension did not correspond to a known - /// file format + /// Returned if the file path's extension did not correspond to a known & + /// enabled file format #[error("unknown file extension: {0:?}")] Unknown( /// The file extension (without leading period) @@ -565,10 +428,6 @@ pub enum IdentifyError { #[derive(Debug, Error)] #[non_exhaustive] pub enum SerializeError { - /// Returned if the format in question is not [enabled][Format::is_enabled] - #[error("serialization to {0} is not enabled")] - NotEnabled(Format), - /// Returned if an I/O error occurred while writing to a writer. /// /// Some serializers may catch & report such errors themselves. @@ -608,10 +467,6 @@ pub enum SerializeError { #[derive(Debug, Error)] #[non_exhaustive] pub enum DeserializeError { - /// Returned if the format in question is not [enabled][Format::is_enabled] - #[error("deserialization from {0} is not enabled")] - NotEnabled(Format), - /// Returned if an I/O error occurred while reading from a reader. /// /// Some deserializers may catch & report such errors themselves. @@ -653,7 +508,7 @@ pub enum DeserializeError { #[derive(Debug, Error)] pub enum LoadError { /// Returned if the file format could not be identified from the file - /// extension or if the format was not [enabled][Format::is_enabled] + /// extension #[error("failed to identify file format")] Identify(#[from] IdentifyError), @@ -670,7 +525,7 @@ pub enum LoadError { #[derive(Debug, Error)] pub enum DumpError { /// Returned if the file format could not be identified from the file - /// extension or if the format was not [enabled][Format::is_enabled] + /// extension #[error("failed to identify file format")] Identify(#[from] IdentifyError), @@ -683,56 +538,11 @@ pub enum DumpError { Serialize(#[from] SerializeError), } -/// An iterator over [enabled][Format::is_enabled] [Format] variants -#[derive(Clone, Debug)] -pub struct EnabledFormatIter(FormatIter); - -impl EnabledFormatIter { - pub fn new() -> EnabledFormatIter { - EnabledFormatIter(Format::iter()) - } -} - -impl Default for EnabledFormatIter { - fn default() -> Self { - Self::new() - } -} - -impl Iterator for EnabledFormatIter { - type Item = Format; - - fn next(&mut self) -> Option { - self.0.find(Format::is_enabled) - } - - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.0.size_hint(); - (0, upper) - } -} - -impl DoubleEndedIterator for EnabledFormatIter { - fn next_back(&mut self) -> Option { - self.0.rfind(Format::is_enabled) - } -} - -impl std::iter::FusedIterator for EnabledFormatIter {} - #[cfg(test)] mod tests { use super::*; use rstest::rstest; - fn in_iter(value: T, mut iter: I) -> bool - where - T: Eq, - I: Iterator, - { - iter.any(move |v| v == value) - } - #[rstest] #[case("file.ini", "ini")] #[case("file.xml", "xml")] @@ -766,6 +576,7 @@ mod tests { assert_eq!(Format::identify("file"), Err(IdentifyError::NoExtension)); } + #[cfg(feature = "json")] mod json { use super::*; @@ -777,23 +588,7 @@ mod tests { assert_eq!("json".parse::().unwrap(), f); assert_eq!("JSON".parse::().unwrap(), f); assert_eq!("Json".parse::().unwrap(), f); - assert!(in_iter(f, Format::iter())); - } - - #[cfg(feature = "json")] - #[test] - fn enabled() { - assert!(Format::Json.is_enabled()); - assert!(in_iter(Format::Json, Format::enabled())); - assert!(in_iter(Format::Json, Format::enabled().rev())); - } - - #[cfg(not(feature = "json"))] - #[test] - fn not_enabled() { - assert!(!Format::Json.is_enabled()); - assert!(!in_iter(Format::Json, Format::enabled())); - assert!(!in_iter(Format::Json, Format::enabled().rev())); + assert!(Format::iter().any(|f2| f == f2)); } #[rstest] @@ -805,7 +600,6 @@ mod tests { assert_eq!(Format::from_extension(ext).unwrap(), Format::Json); } - #[cfg(feature = "json")] #[rstest] #[case("file.json")] #[case("dir/file.JSON")] @@ -813,17 +607,27 @@ mod tests { fn identify(#[case] path: &str) { assert_eq!(Format::identify(path).unwrap(), Format::Json); } + } + + #[cfg(not(feature = "json"))] + mod not_json { + use super::*; - #[cfg(not(feature = "json"))] #[test] - fn identify_not_enabled() { + fn not_variant() { + assert!(!Format::iter().any(|f| f.to_string() == "JSON")); + } + + #[test] + fn identify() { assert_eq!( Format::identify("file.json"), - Err(IdentifyError::NotEnabled(Format::Json)) + Err(IdentifyError::Unknown(String::from("json"))) ); } } + #[cfg(feature = "json5")] mod json5 { use super::*; @@ -835,23 +639,7 @@ mod tests { assert_eq!("json5".parse::().unwrap(), f); assert_eq!("JSON5".parse::().unwrap(), f); assert_eq!("Json5".parse::().unwrap(), f); - assert!(in_iter(f, Format::iter())); - } - - #[cfg(feature = "json5")] - #[test] - fn enabled() { - assert!(Format::Json5.is_enabled()); - assert!(in_iter(Format::Json5, Format::enabled())); - assert!(in_iter(Format::Json5, Format::enabled().rev())); - } - - #[cfg(not(feature = "json5"))] - #[test] - fn not_enabled() { - assert!(!Format::Json5.is_enabled()); - assert!(!in_iter(Format::Json5, Format::enabled())); - assert!(!in_iter(Format::Json5, Format::enabled().rev())); + assert!(Format::iter().any(|f2| f == f2)); } #[rstest] @@ -863,7 +651,6 @@ mod tests { assert_eq!(Format::from_extension(ext).unwrap(), Format::Json5); } - #[cfg(feature = "json5")] #[rstest] #[case("file.json5")] #[case("dir/file.JSON5")] @@ -871,17 +658,27 @@ mod tests { fn identify(#[case] path: &str) { assert_eq!(Format::identify(path).unwrap(), Format::Json5); } + } + + #[cfg(not(feature = "json5"))] + mod not_json5 { + use super::*; - #[cfg(not(feature = "json5"))] #[test] - fn identify_not_enabled() { + fn not_variant() { + assert!(!Format::iter().any(|f| f.to_string() == "JSON5")); + } + + #[test] + fn identify() { assert_eq!( Format::identify("file.json5"), - Err(IdentifyError::NotEnabled(Format::Json5)) + Err(IdentifyError::Unknown(String::from("json5"))) ); } } + #[cfg(feature = "ron")] mod ron { use super::*; @@ -893,23 +690,7 @@ mod tests { assert_eq!("ron".parse::().unwrap(), f); assert_eq!("RON".parse::().unwrap(), f); assert_eq!("Ron".parse::().unwrap(), f); - assert!(in_iter(f, Format::iter())); - } - - #[cfg(feature = "ron")] - #[test] - fn enabled() { - assert!(Format::Ron.is_enabled()); - assert!(in_iter(Format::Ron, Format::enabled())); - assert!(in_iter(Format::Ron, Format::enabled().rev())); - } - - #[cfg(not(feature = "ron"))] - #[test] - fn not_enabled() { - assert!(!Format::Ron.is_enabled()); - assert!(!in_iter(Format::Ron, Format::enabled())); - assert!(!in_iter(Format::Ron, Format::enabled().rev())); + assert!(Format::iter().any(|f2| f == f2)); } #[rstest] @@ -921,7 +702,6 @@ mod tests { assert_eq!(Format::from_extension(ext).unwrap(), Format::Ron); } - #[cfg(feature = "ron")] #[rstest] #[case("file.ron")] #[case("dir/file.RON")] @@ -929,17 +709,27 @@ mod tests { fn identify(#[case] path: &str) { assert_eq!(Format::identify(path).unwrap(), Format::Ron); } + } + + #[cfg(not(feature = "ron"))] + mod not_ron { + use super::*; + + #[test] + fn not_variant() { + assert!(!Format::iter().any(|f| f.to_string() == "RON")); + } - #[cfg(not(feature = "ron"))] #[test] - fn identify_not_enabled() { + fn identify() { assert_eq!( Format::identify("file.ron"), - Err(IdentifyError::NotEnabled(Format::Ron)) + Err(IdentifyError::Unknown(String::from("ron"))) ); } } + #[cfg(feature = "toml")] mod toml { use super::*; @@ -951,23 +741,7 @@ mod tests { assert_eq!("toml".parse::().unwrap(), f); assert_eq!("TOML".parse::().unwrap(), f); assert_eq!("Toml".parse::().unwrap(), f); - assert!(in_iter(f, Format::iter())); - } - - #[cfg(feature = "toml")] - #[test] - fn enabled() { - assert!(Format::Toml.is_enabled()); - assert!(in_iter(Format::Toml, Format::enabled())); - assert!(in_iter(Format::Toml, Format::enabled().rev())); - } - - #[cfg(not(feature = "toml"))] - #[test] - fn not_enabled() { - assert!(!Format::Toml.is_enabled()); - assert!(!in_iter(Format::Toml, Format::enabled())); - assert!(!in_iter(Format::Toml, Format::enabled().rev())); + assert!(Format::iter().any(|f2| f == f2)); } #[rstest] @@ -979,7 +753,6 @@ mod tests { assert_eq!(Format::from_extension(ext).unwrap(), Format::Toml); } - #[cfg(feature = "toml")] #[rstest] #[case("file.toml")] #[case("dir/file.TOML")] @@ -987,17 +760,27 @@ mod tests { fn identify(#[case] path: &str) { assert_eq!(Format::identify(path).unwrap(), Format::Toml); } + } + + #[cfg(not(feature = "toml"))] + mod not_toml { + use super::*; + + #[test] + fn not_variant() { + assert!(!Format::iter().any(|f| f.to_string() == "TOML")); + } - #[cfg(not(feature = "toml"))] #[test] - fn identify_not_enabled() { + fn identify() { assert_eq!( Format::identify("file.toml"), - Err(IdentifyError::NotEnabled(Format::Toml)) + Err(IdentifyError::Unknown(String::from("toml"))) ); } } + #[cfg(feature = "yaml")] mod yaml { use super::*; @@ -1009,23 +792,7 @@ mod tests { assert_eq!("yaml".parse::().unwrap(), f); assert_eq!("YAML".parse::().unwrap(), f); assert_eq!("Yaml".parse::().unwrap(), f); - assert!(in_iter(f, Format::iter())); - } - - #[cfg(feature = "yaml")] - #[test] - fn enabled() { - assert!(Format::Yaml.is_enabled()); - assert!(in_iter(Format::Yaml, Format::enabled())); - assert!(in_iter(Format::Yaml, Format::enabled().rev())); - } - - #[cfg(not(feature = "yaml"))] - #[test] - fn not_enabled() { - assert!(!Format::Yaml.is_enabled()); - assert!(!in_iter(Format::Yaml, Format::enabled())); - assert!(!in_iter(Format::Yaml, Format::enabled().rev())); + assert!(Format::iter().any(|f2| f == f2)); } #[rstest] @@ -1041,7 +808,6 @@ mod tests { assert_eq!(Format::from_extension(ext).unwrap(), Format::Yaml); } - #[cfg(feature = "yaml")] #[rstest] #[case("file.yaml")] #[case("dir/file.YAML")] @@ -1052,13 +818,22 @@ mod tests { fn identify(#[case] path: &str) { assert_eq!(Format::identify(path).unwrap(), Format::Yaml); } + } + + #[cfg(not(feature = "yaml"))] + mod not_yaml { + use super::*; + + #[test] + fn not_variant() { + assert!(!Format::iter().any(|f| f.to_string() == "YAML")); + } - #[cfg(not(feature = "yaml"))] #[test] - fn identify_not_enabled() { + fn identify() { assert_eq!( Format::identify("file.yaml"), - Err(IdentifyError::NotEnabled(Format::Yaml)) + Err(IdentifyError::Unknown(String::from("yaml"))) ); } } diff --git a/tests/deser.rs b/tests/deser.rs index 9a42f22..f658797 100644 --- a/tests/deser.rs +++ b/tests/deser.rs @@ -1,3 +1,4 @@ +#![allow(unused)] mod formats; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; diff --git a/tests/formats/json.rs b/tests/formats/json.rs index 478f017..b523f6e 100644 --- a/tests/formats/json.rs +++ b/tests/formats/json.rs @@ -1,11 +1,9 @@ -#![allow(unused)] +#![cfg(feature = "json")] use crate::Config; -use assert_matches::assert_matches; -use cfg_if::cfg_if; use cfgurate::*; use indoc::indoc; use pretty_assertions::assert_eq; -use std::io::{read_to_string, Read, Seek, Write}; +use std::io::{read_to_string, Seek, Write}; use tempfile::{tempfile, Builder}; static JSON: &str = indoc! {r#" @@ -60,25 +58,13 @@ static JSON: &str = indoc! {r#" #[test] fn load_from_str() { let r = Format::Json.load_from_str::(JSON); - cfg_if! { - if #[cfg(feature = "json")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Json))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_string() { let r = Format::Json.dump_to_string(&Config::get()); - cfg_if! { - if #[cfg(feature = "json")] { - assert_eq!(r.unwrap(), JSON); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Json))); - } - } + assert_eq!(r.unwrap(), JSON); } #[test] @@ -88,31 +74,19 @@ fn load_from_reader() { file.flush().unwrap(); file.rewind().unwrap(); let r = Format::Json.load_from_reader::<_, Config>(file); - cfg_if! { - if #[cfg(feature = "json")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Json))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_writer() { let mut file = tempfile().unwrap(); let r = Format::Json.dump_to_writer(&file, &Config::get()); - cfg_if! { - if #[cfg(feature = "json")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, format!("{JSON}\n")); - assert!(s.ends_with("}\n")); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Json))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, format!("{JSON}\n")); + assert!(s.ends_with("}\n")); } #[test] @@ -122,29 +96,17 @@ fn load_from_file() { file.flush().unwrap(); file.rewind().unwrap(); let r = load::(file); - cfg_if! { - if #[cfg(feature = "json")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(LoadError::Identify(IdentifyError::NotEnabled(Format::Json)))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_file() { let mut file = Builder::new().suffix(".json").tempfile().unwrap(); let r = dump(&Config::get(), &file); - cfg_if! { - if #[cfg(feature = "json")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, format!("{JSON}\n")); - assert!(s.ends_with("}\n")); - } else { - assert_matches!(r, Err(DumpError::Identify(IdentifyError::NotEnabled(Format::Json)))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, format!("{JSON}\n")); + assert!(s.ends_with("}\n")); } diff --git a/tests/formats/json5.rs b/tests/formats/json5.rs index 26b6efd..0fc133e 100644 --- a/tests/formats/json5.rs +++ b/tests/formats/json5.rs @@ -1,11 +1,9 @@ -#![allow(unused)] +#![cfg(feature = "json5")] use crate::Config; -use assert_matches::assert_matches; -use cfg_if::cfg_if; use cfgurate::*; use indoc::indoc; use pretty_assertions::assert_eq; -use std::io::{read_to_string, Read, Seek, Write}; +use std::io::{read_to_string, Seek, Write}; use tempfile::{tempfile, Builder}; static JSON: &str = indoc! {r#" @@ -112,25 +110,13 @@ static JSON5: &str = indoc! {r#" #[test] fn load_from_str() { let r = Format::Json5.load_from_str::(JSON5); - cfg_if! { - if #[cfg(feature = "json5")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Json5))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_string() { let r = Format::Json5.dump_to_string(&Config::get()); - cfg_if! { - if #[cfg(feature = "json5")] { - assert_eq!(r.unwrap(), JSON); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Json5))); - } - } + assert_eq!(r.unwrap(), JSON); } #[test] @@ -140,31 +126,19 @@ fn load_from_reader() { file.flush().unwrap(); file.rewind().unwrap(); let r = Format::Json5.load_from_reader::<_, Config>(file); - cfg_if! { - if #[cfg(feature = "json5")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Json5))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_writer() { let mut file = tempfile().unwrap(); let r = Format::Json5.dump_to_writer(&file, &Config::get()); - cfg_if! { - if #[cfg(feature = "json5")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, format!("{JSON}\n")); - assert!(s.ends_with("}\n")); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Json5))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, format!("{JSON}\n")); + assert!(s.ends_with("}\n")); } #[test] @@ -174,29 +148,17 @@ fn load_from_file() { file.flush().unwrap(); file.rewind().unwrap(); let r = load::(file); - cfg_if! { - if #[cfg(feature = "json5")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(LoadError::Identify(IdentifyError::NotEnabled(Format::Json5)))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_file() { let mut file = Builder::new().suffix(".json5").tempfile().unwrap(); let r = dump(&Config::get(), &file); - cfg_if! { - if #[cfg(feature = "json5")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, format!("{JSON}\n")); - assert!(s.ends_with("}\n")); - } else { - assert_matches!(r, Err(DumpError::Identify(IdentifyError::NotEnabled(Format::Json5)))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, format!("{JSON}\n")); + assert!(s.ends_with("}\n")); } diff --git a/tests/formats/ron.rs b/tests/formats/ron.rs index 0b96dbb..79e251c 100644 --- a/tests/formats/ron.rs +++ b/tests/formats/ron.rs @@ -1,11 +1,9 @@ -#![allow(unused)] +#![cfg(feature = "ron")] use crate::RonConfig; -use assert_matches::assert_matches; -use cfg_if::cfg_if; use cfgurate::*; use indoc::indoc; use pretty_assertions::assert_eq; -use std::io::{read_to_string, Read, Seek, Write}; +use std::io::{read_to_string, Seek, Write}; use tempfile::{tempfile, Builder}; static RON: &str = indoc! {r#" @@ -59,25 +57,13 @@ static RON: &str = indoc! {r#" #[test] fn load_from_str() { let r = Format::Ron.load_from_str::(RON); - cfg_if! { - if #[cfg(feature = "ron")] { - assert_eq!(r.unwrap(), RonConfig::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Ron))); - } - } + assert_eq!(r.unwrap(), RonConfig::get()); } #[test] fn dump_to_string() { let r = Format::Ron.dump_to_string(&RonConfig::get()); - cfg_if! { - if #[cfg(feature = "ron")] { - assert_eq!(r.unwrap(), RON); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Ron))); - } - } + assert_eq!(r.unwrap(), RON); } #[test] @@ -87,31 +73,19 @@ fn load_from_reader() { file.flush().unwrap(); file.rewind().unwrap(); let r = Format::Ron.load_from_reader::<_, RonConfig>(file); - cfg_if! { - if #[cfg(feature = "ron")] { - assert_eq!(r.unwrap(), RonConfig::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Ron))); - } - } + assert_eq!(r.unwrap(), RonConfig::get()); } #[test] fn dump_to_writer() { let mut file = tempfile().unwrap(); let r = Format::Ron.dump_to_writer(&file, &RonConfig::get()); - cfg_if! { - if #[cfg(feature = "ron")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, format!("{RON}\n")); - assert!(s.ends_with(")\n")); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Ron))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, format!("{RON}\n")); + assert!(s.ends_with(")\n")); } #[test] @@ -121,29 +95,17 @@ fn load_from_file() { file.flush().unwrap(); file.rewind().unwrap(); let r = load::(file); - cfg_if! { - if #[cfg(feature = "ron")] { - assert_eq!(r.unwrap(), RonConfig::get()); - } else { - assert_matches!(r, Err(LoadError::Identify(IdentifyError::NotEnabled(Format::Ron)))); - } - } + assert_eq!(r.unwrap(), RonConfig::get()); } #[test] fn dump_to_file() { let mut file = Builder::new().suffix(".ron").tempfile().unwrap(); let r = dump(&RonConfig::get(), &file); - cfg_if! { - if #[cfg(feature = "ron")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, format!("{RON}\n")); - assert!(s.ends_with(")\n")); - } else { - assert_matches!(r, Err(DumpError::Identify(IdentifyError::NotEnabled(Format::Ron)))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, format!("{RON}\n")); + assert!(s.ends_with(")\n")); } diff --git a/tests/formats/toml.rs b/tests/formats/toml.rs index fd893bb..1ff8d46 100644 --- a/tests/formats/toml.rs +++ b/tests/formats/toml.rs @@ -1,11 +1,9 @@ -#![allow(unused)] +#![cfg(feature = "toml")] use crate::Config; -use assert_matches::assert_matches; -use cfg_if::cfg_if; use cfgurate::*; use indoc::indoc; use pretty_assertions::assert_eq; -use std::io::{read_to_string, Read, Seek, Write}; +use std::io::{read_to_string, Seek, Write}; use tempfile::{tempfile, Builder}; static TOML: &str = indoc! {r#" @@ -59,25 +57,13 @@ family_name = "McCharles" #[test] fn load_from_str() { let r = Format::Toml.load_from_str::(TOML); - cfg_if! { - if #[cfg(feature = "toml")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Toml))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_string() { let r = Format::Toml.dump_to_string(&Config::get()); - cfg_if! { - if #[cfg(feature = "toml")] { - assert_eq!(r.unwrap(), TOML); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Toml))); - } - } + assert_eq!(r.unwrap(), TOML); } #[test] @@ -87,31 +73,19 @@ fn load_from_reader() { file.flush().unwrap(); file.rewind().unwrap(); let r = Format::Toml.load_from_reader::<_, Config>(file); - cfg_if! { - if #[cfg(feature = "toml")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Toml))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_writer() { let mut file = tempfile().unwrap(); let r = Format::Toml.dump_to_writer(&file, &Config::get()); - cfg_if! { - if #[cfg(feature = "toml")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, TOML); - assert!(s.ends_with("\"\n")); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Toml))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, TOML); + assert!(s.ends_with("\"\n")); } #[test] @@ -121,29 +95,17 @@ fn load_from_file() { file.flush().unwrap(); file.rewind().unwrap(); let r = load::(file); - cfg_if! { - if #[cfg(feature = "toml")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(LoadError::Identify(IdentifyError::NotEnabled(Format::Toml)))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_file() { let mut file = Builder::new().suffix(".toml").tempfile().unwrap(); let r = dump(&Config::get(), &file); - cfg_if! { - if #[cfg(feature = "toml")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, TOML); - assert!(s.ends_with("\"\n")); - } else { - assert_matches!(r, Err(DumpError::Identify(IdentifyError::NotEnabled(Format::Toml)))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, TOML); + assert!(s.ends_with("\"\n")); } diff --git a/tests/formats/yaml.rs b/tests/formats/yaml.rs index 95cdece..1860747 100644 --- a/tests/formats/yaml.rs +++ b/tests/formats/yaml.rs @@ -1,11 +1,9 @@ -#![allow(unused)] +#![cfg(feature = "yaml")] use crate::Config; -use assert_matches::assert_matches; -use cfg_if::cfg_if; use cfgurate::*; use indoc::indoc; use pretty_assertions::assert_eq; -use std::io::{read_to_string, Read, Seek, Write}; +use std::io::{read_to_string, Seek, Write}; use tempfile::{tempfile, Builder}; static YAML: &str = indoc! {r#" @@ -47,25 +45,13 @@ people: #[test] fn load_from_str() { let r = Format::Yaml.load_from_str::(YAML); - cfg_if! { - if #[cfg(feature = "yaml")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Yaml))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_string() { let r = Format::Yaml.dump_to_string(&Config::get()); - cfg_if! { - if #[cfg(feature = "yaml")] { - assert_eq!(r.unwrap(), YAML); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Yaml))); - } - } + assert_eq!(r.unwrap(), YAML); } #[test] @@ -75,31 +61,19 @@ fn load_from_reader() { file.flush().unwrap(); file.rewind().unwrap(); let r = Format::Yaml.load_from_reader::<_, Config>(file); - cfg_if! { - if #[cfg(feature = "yaml")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(DeserializeError::NotEnabled(Format::Yaml))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_writer() { let mut file = tempfile().unwrap(); let r = Format::Yaml.dump_to_writer(&file, &Config::get()); - cfg_if! { - if #[cfg(feature = "yaml")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, YAML); - assert!(s.ends_with("McCharles\n")); - } else { - assert_matches!(r, Err(SerializeError::NotEnabled(Format::Yaml))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, YAML); + assert!(s.ends_with("McCharles\n")); } #[test] @@ -109,29 +83,17 @@ fn load_from_file() { file.flush().unwrap(); file.rewind().unwrap(); let r = load::(file); - cfg_if! { - if #[cfg(feature = "yaml")] { - assert_eq!(r.unwrap(), Config::get()); - } else { - assert_matches!(r, Err(LoadError::Identify(IdentifyError::NotEnabled(Format::Yaml)))); - } - } + assert_eq!(r.unwrap(), Config::get()); } #[test] fn dump_to_file() { let mut file = Builder::new().suffix(".yaml").tempfile().unwrap(); let r = dump(&Config::get(), &file); - cfg_if! { - if #[cfg(feature = "yaml")] { - assert!(r.is_ok()); - file.flush().unwrap(); - file.rewind().unwrap(); - let s = read_to_string(file).unwrap(); - assert_eq!(s, YAML); - assert!(s.ends_with("McCharles\n")); - } else { - assert_matches!(r, Err(DumpError::Identify(IdentifyError::NotEnabled(Format::Yaml)))); - } - } + assert!(r.is_ok()); + file.flush().unwrap(); + file.rewind().unwrap(); + let s = read_to_string(file).unwrap(); + assert_eq!(s, YAML); + assert!(s.ends_with("McCharles\n")); }