| use libc; |
| use std::ffi::CString; |
| use std::marker; |
| use std::path::{Path, PathBuf}; |
| use std::ptr; |
| use std::str; |
| |
| use crate::util::{self, Binding}; |
| use crate::{raw, Buf, ConfigLevel, Error, IntoCString}; |
| |
| /// A structure representing a git configuration key/value store |
| pub struct Config { |
| raw: *mut raw::git_config, |
| } |
| |
| /// A struct representing a certain entry owned by a `Config` instance. |
| /// |
| /// An entry has a name, a value, and a level it applies to. |
| pub struct ConfigEntry<'cfg> { |
| raw: *mut raw::git_config_entry, |
| _marker: marker::PhantomData<&'cfg Config>, |
| owned: bool, |
| } |
| |
| /// An iterator over the `ConfigEntry` values of a `Config` structure. |
| pub struct ConfigEntries<'cfg> { |
| raw: *mut raw::git_config_iterator, |
| _marker: marker::PhantomData<&'cfg Config>, |
| } |
| |
| impl Config { |
| /// Allocate a new configuration object |
| /// |
| /// This object is empty, so you have to add a file to it before you can do |
| /// anything with it. |
| pub fn new() -> Result<Config, Error> { |
| crate::init(); |
| let mut raw = ptr::null_mut(); |
| unsafe { |
| try_call!(raw::git_config_new(&mut raw)); |
| Ok(Binding::from_raw(raw)) |
| } |
| } |
| |
| /// Create a new config instance containing a single on-disk file |
| pub fn open(path: &Path) -> Result<Config, Error> { |
| crate::init(); |
| let mut raw = ptr::null_mut(); |
| // Normal file path OK (does not need Windows conversion). |
| let path = path.into_c_string()?; |
| unsafe { |
| try_call!(raw::git_config_open_ondisk(&mut raw, path)); |
| Ok(Binding::from_raw(raw)) |
| } |
| } |
| |
| /// Open the global, XDG and system configuration files |
| /// |
| /// Utility wrapper that finds the global, XDG and system configuration |
| /// files and opens them into a single prioritized config object that can |
| /// be used when accessing default config data outside a repository. |
| pub fn open_default() -> Result<Config, Error> { |
| crate::init(); |
| let mut raw = ptr::null_mut(); |
| unsafe { |
| try_call!(raw::git_config_open_default(&mut raw)); |
| Ok(Binding::from_raw(raw)) |
| } |
| } |
| |
| /// Locate the path to the global configuration file |
| /// |
| /// The user or global configuration file is usually located in |
| /// `$HOME/.gitconfig`. |
| /// |
| /// This method will try to guess the full path to that file, if the file |
| /// exists. The returned path may be used on any method call to load |
| /// the global configuration file. |
| /// |
| /// This method will not guess the path to the xdg compatible config file |
| /// (`.config/git/config`). |
| pub fn find_global() -> Result<PathBuf, Error> { |
| crate::init(); |
| let buf = Buf::new(); |
| unsafe { |
| try_call!(raw::git_config_find_global(buf.raw())); |
| } |
| Ok(util::bytes2path(&buf).to_path_buf()) |
| } |
| |
| /// Locate the path to the system configuration file |
| /// |
| /// If /etc/gitconfig doesn't exist, it will look for %PROGRAMFILES% |
| pub fn find_system() -> Result<PathBuf, Error> { |
| crate::init(); |
| let buf = Buf::new(); |
| unsafe { |
| try_call!(raw::git_config_find_system(buf.raw())); |
| } |
| Ok(util::bytes2path(&buf).to_path_buf()) |
| } |
| |
| /// Locate the path to the global xdg compatible configuration file |
| /// |
| /// The xdg compatible configuration file is usually located in |
| /// `$HOME/.config/git/config`. |
| pub fn find_xdg() -> Result<PathBuf, Error> { |
| crate::init(); |
| let buf = Buf::new(); |
| unsafe { |
| try_call!(raw::git_config_find_xdg(buf.raw())); |
| } |
| Ok(util::bytes2path(&buf).to_path_buf()) |
| } |
| |
| /// Add an on-disk config file instance to an existing config |
| /// |
| /// The on-disk file pointed at by path will be opened and parsed; it's |
| /// expected to be a native Git config file following the default Git config |
| /// syntax (see man git-config). |
| /// |
| /// Further queries on this config object will access each of the config |
| /// file instances in order (instances with a higher priority level will be |
| /// accessed first). |
| pub fn add_file(&mut self, path: &Path, level: ConfigLevel, force: bool) -> Result<(), Error> { |
| // Normal file path OK (does not need Windows conversion). |
| let path = path.into_c_string()?; |
| unsafe { |
| try_call!(raw::git_config_add_file_ondisk( |
| self.raw, |
| path, |
| level, |
| ptr::null(), |
| force |
| )); |
| Ok(()) |
| } |
| } |
| |
| /// Delete a config variable from the config file with the highest level |
| /// (usually the local one). |
| pub fn remove(&mut self, name: &str) -> Result<(), Error> { |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_delete_entry(self.raw, name)); |
| Ok(()) |
| } |
| } |
| |
| /// Remove multivar config variables in the config file with the highest level (usually the |
| /// local one). |
| /// |
| /// The regular expression is applied case-sensitively on the value. |
| pub fn remove_multivar(&mut self, name: &str, regexp: &str) -> Result<(), Error> { |
| let name = CString::new(name)?; |
| let regexp = CString::new(regexp)?; |
| unsafe { |
| try_call!(raw::git_config_delete_multivar(self.raw, name, regexp)); |
| } |
| Ok(()) |
| } |
| |
| /// Get the value of a boolean config variable. |
| /// |
| /// All config files will be looked into, in the order of their defined |
| /// level. A higher level means a higher priority. The first occurrence of |
| /// the variable will be returned here. |
| pub fn get_bool(&self, name: &str) -> Result<bool, Error> { |
| let mut out = 0 as libc::c_int; |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_get_bool(&mut out, &*self.raw, name)); |
| } |
| Ok(out != 0) |
| } |
| |
| /// Get the value of an integer config variable. |
| /// |
| /// All config files will be looked into, in the order of their defined |
| /// level. A higher level means a higher priority. The first occurrence of |
| /// the variable will be returned here. |
| pub fn get_i32(&self, name: &str) -> Result<i32, Error> { |
| let mut out = 0i32; |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_get_int32(&mut out, &*self.raw, name)); |
| } |
| Ok(out) |
| } |
| |
| /// Get the value of an integer config variable. |
| /// |
| /// All config files will be looked into, in the order of their defined |
| /// level. A higher level means a higher priority. The first occurrence of |
| /// the variable will be returned here. |
| pub fn get_i64(&self, name: &str) -> Result<i64, Error> { |
| let mut out = 0i64; |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_get_int64(&mut out, &*self.raw, name)); |
| } |
| Ok(out) |
| } |
| |
| /// Get the value of a string config variable. |
| /// |
| /// This is the same as `get_bytes` except that it may return `Err` if |
| /// the bytes are not valid utf-8. |
| /// |
| /// This method will return an error if this `Config` is not a snapshot. |
| pub fn get_str(&self, name: &str) -> Result<&str, Error> { |
| str::from_utf8(self.get_bytes(name)?) |
| .map_err(|_| Error::from_str("configuration value is not valid utf8")) |
| } |
| |
| /// Get the value of a string config variable as a byte slice. |
| /// |
| /// This method will return an error if this `Config` is not a snapshot. |
| pub fn get_bytes(&self, name: &str) -> Result<&[u8], Error> { |
| let mut ret = ptr::null(); |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_get_string(&mut ret, &*self.raw, name)); |
| Ok(crate::opt_bytes(self, ret).unwrap()) |
| } |
| } |
| |
| /// Get the value of a string config variable as an owned string. |
| /// |
| /// All config files will be looked into, in the order of their |
| /// defined level. A higher level means a higher priority. The |
| /// first occurrence of the variable will be returned here. |
| /// |
| /// An error will be returned if the config value is not valid utf-8. |
| pub fn get_string(&self, name: &str) -> Result<String, Error> { |
| let ret = Buf::new(); |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_get_string_buf(ret.raw(), self.raw, name)); |
| } |
| str::from_utf8(&ret) |
| .map(|s| s.to_string()) |
| .map_err(|_| Error::from_str("configuration value is not valid utf8")) |
| } |
| |
| /// Get the value of a path config variable as an owned `PathBuf`. |
| /// |
| /// A leading '~' will be expanded to the global search path (which |
| /// defaults to the user's home directory but can be overridden via |
| /// [`raw::git_libgit2_opts`]. |
| /// |
| /// All config files will be looked into, in the order of their |
| /// defined level. A higher level means a higher priority. The |
| /// first occurrence of the variable will be returned here. |
| pub fn get_path(&self, name: &str) -> Result<PathBuf, Error> { |
| let ret = Buf::new(); |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_get_path(ret.raw(), self.raw, name)); |
| } |
| Ok(crate::util::bytes2path(&ret).to_path_buf()) |
| } |
| |
| /// Get the ConfigEntry for a config variable. |
| pub fn get_entry(&self, name: &str) -> Result<ConfigEntry<'_>, Error> { |
| let mut ret = ptr::null_mut(); |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_get_entry(&mut ret, self.raw, name)); |
| Ok(Binding::from_raw(ret)) |
| } |
| } |
| |
| /// Iterate over all the config variables |
| /// |
| /// If `glob` is `Some`, then the iterator will only iterate over all |
| /// variables whose name matches the pattern. |
| /// |
| /// The regular expression is applied case-sensitively on the normalized form of |
| /// the variable name: the section and variable parts are lower-cased. The |
| /// subsection is left unchanged. |
| /// |
| /// # Example |
| /// |
| /// ``` |
| /// # #![allow(unstable)] |
| /// use git2::Config; |
| /// |
| /// let cfg = Config::new().unwrap(); |
| /// |
| /// for entry in &cfg.entries(None).unwrap() { |
| /// let entry = entry.unwrap(); |
| /// println!("{} => {}", entry.name().unwrap(), entry.value().unwrap()); |
| /// } |
| /// ``` |
| pub fn entries(&self, glob: Option<&str>) -> Result<ConfigEntries<'_>, Error> { |
| let mut ret = ptr::null_mut(); |
| unsafe { |
| match glob { |
| Some(s) => { |
| let s = CString::new(s)?; |
| try_call!(raw::git_config_iterator_glob_new(&mut ret, &*self.raw, s)); |
| } |
| None => { |
| try_call!(raw::git_config_iterator_new(&mut ret, &*self.raw)); |
| } |
| } |
| Ok(Binding::from_raw(ret)) |
| } |
| } |
| |
| /// Iterate over the values of a multivar |
| /// |
| /// If `regexp` is `Some`, then the iterator will only iterate over all |
| /// values which match the pattern. |
| /// |
| /// The regular expression is applied case-sensitively on the normalized form of |
| /// the variable name: the section and variable parts are lower-cased. The |
| /// subsection is left unchanged. |
| pub fn multivar(&self, name: &str, regexp: Option<&str>) -> Result<ConfigEntries<'_>, Error> { |
| let mut ret = ptr::null_mut(); |
| let name = CString::new(name)?; |
| let regexp = regexp.map(CString::new).transpose()?; |
| unsafe { |
| try_call!(raw::git_config_multivar_iterator_new( |
| &mut ret, &*self.raw, name, regexp |
| )); |
| Ok(Binding::from_raw(ret)) |
| } |
| } |
| |
| /// Open the global/XDG configuration file according to git's rules |
| /// |
| /// Git allows you to store your global configuration at `$HOME/.config` or |
| /// `$XDG_CONFIG_HOME/git/config`. For backwards compatability, the XDG file |
| /// shouldn't be used unless the use has created it explicitly. With this |
| /// function you'll open the correct one to write to. |
| pub fn open_global(&mut self) -> Result<Config, Error> { |
| let mut raw = ptr::null_mut(); |
| unsafe { |
| try_call!(raw::git_config_open_global(&mut raw, self.raw)); |
| Ok(Binding::from_raw(raw)) |
| } |
| } |
| |
| /// Build a single-level focused config object from a multi-level one. |
| /// |
| /// The returned config object can be used to perform get/set/delete |
| /// operations on a single specific level. |
| pub fn open_level(&self, level: ConfigLevel) -> Result<Config, Error> { |
| let mut raw = ptr::null_mut(); |
| unsafe { |
| try_call!(raw::git_config_open_level(&mut raw, &*self.raw, level)); |
| Ok(Binding::from_raw(raw)) |
| } |
| } |
| |
| /// Set the value of a boolean config variable in the config file with the |
| /// highest level (usually the local one). |
| pub fn set_bool(&mut self, name: &str, value: bool) -> Result<(), Error> { |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_set_bool(self.raw, name, value)); |
| } |
| Ok(()) |
| } |
| |
| /// Set the value of an integer config variable in the config file with the |
| /// highest level (usually the local one). |
| pub fn set_i32(&mut self, name: &str, value: i32) -> Result<(), Error> { |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_set_int32(self.raw, name, value)); |
| } |
| Ok(()) |
| } |
| |
| /// Set the value of an integer config variable in the config file with the |
| /// highest level (usually the local one). |
| pub fn set_i64(&mut self, name: &str, value: i64) -> Result<(), Error> { |
| let name = CString::new(name)?; |
| unsafe { |
| try_call!(raw::git_config_set_int64(self.raw, name, value)); |
| } |
| Ok(()) |
| } |
| |
| /// Set the value of an multivar config variable in the config file with the |
| /// highest level (usually the local one). |
| /// |
| /// The regular expression is applied case-sensitively on the value. |
| pub fn set_multivar(&mut self, name: &str, regexp: &str, value: &str) -> Result<(), Error> { |
| let name = CString::new(name)?; |
| let regexp = CString::new(regexp)?; |
| let value = CString::new(value)?; |
| unsafe { |
| try_call!(raw::git_config_set_multivar(self.raw, name, regexp, value)); |
| } |
| Ok(()) |
| } |
| |
| /// Set the value of a string config variable in the config file with the |
| /// highest level (usually the local one). |
| pub fn set_str(&mut self, name: &str, value: &str) -> Result<(), Error> { |
| let name = CString::new(name)?; |
| let value = CString::new(value)?; |
| unsafe { |
| try_call!(raw::git_config_set_string(self.raw, name, value)); |
| } |
| Ok(()) |
| } |
| |
| /// Create a snapshot of the configuration |
| /// |
| /// Create a snapshot of the current state of a configuration, which allows |
| /// you to look into a consistent view of the configuration for looking up |
| /// complex values (e.g. a remote, submodule). |
| pub fn snapshot(&mut self) -> Result<Config, Error> { |
| let mut ret = ptr::null_mut(); |
| unsafe { |
| try_call!(raw::git_config_snapshot(&mut ret, self.raw)); |
| Ok(Binding::from_raw(ret)) |
| } |
| } |
| |
| /// Parse a string as a bool. |
| /// |
| /// Interprets "true", "yes", "on", 1, or any non-zero number as true. |
| /// Interprets "false", "no", "off", 0, or an empty string as false. |
| pub fn parse_bool<S: IntoCString>(s: S) -> Result<bool, Error> { |
| let s = s.into_c_string()?; |
| let mut out = 0; |
| crate::init(); |
| unsafe { |
| try_call!(raw::git_config_parse_bool(&mut out, s)); |
| } |
| Ok(out != 0) |
| } |
| |
| /// Parse a string as an i32; handles suffixes like k, M, or G, and |
| /// multiplies by the appropriate power of 1024. |
| pub fn parse_i32<S: IntoCString>(s: S) -> Result<i32, Error> { |
| let s = s.into_c_string()?; |
| let mut out = 0; |
| crate::init(); |
| unsafe { |
| try_call!(raw::git_config_parse_int32(&mut out, s)); |
| } |
| Ok(out) |
| } |
| |
| /// Parse a string as an i64; handles suffixes like k, M, or G, and |
| /// multiplies by the appropriate power of 1024. |
| pub fn parse_i64<S: IntoCString>(s: S) -> Result<i64, Error> { |
| let s = s.into_c_string()?; |
| let mut out = 0; |
| crate::init(); |
| unsafe { |
| try_call!(raw::git_config_parse_int64(&mut out, s)); |
| } |
| Ok(out) |
| } |
| } |
| |
| impl Binding for Config { |
| type Raw = *mut raw::git_config; |
| unsafe fn from_raw(raw: *mut raw::git_config) -> Config { |
| Config { raw } |
| } |
| fn raw(&self) -> *mut raw::git_config { |
| self.raw |
| } |
| } |
| |
| impl Drop for Config { |
| fn drop(&mut self) { |
| unsafe { raw::git_config_free(self.raw) } |
| } |
| } |
| |
| impl<'cfg> ConfigEntry<'cfg> { |
| /// Gets the name of this entry. |
| /// |
| /// May return `None` if the name is not valid utf-8 |
| pub fn name(&self) -> Option<&str> { |
| str::from_utf8(self.name_bytes()).ok() |
| } |
| |
| /// Gets the name of this entry as a byte slice. |
| pub fn name_bytes(&self) -> &[u8] { |
| unsafe { crate::opt_bytes(self, (*self.raw).name).unwrap() } |
| } |
| |
| /// Gets the value of this entry. |
| /// |
| /// May return `None` if the value is not valid utf-8 |
| /// |
| /// # Panics |
| /// |
| /// Panics when no value is defined. |
| pub fn value(&self) -> Option<&str> { |
| str::from_utf8(self.value_bytes()).ok() |
| } |
| |
| /// Gets the value of this entry as a byte slice. |
| /// |
| /// # Panics |
| /// |
| /// Panics when no value is defined. |
| pub fn value_bytes(&self) -> &[u8] { |
| unsafe { crate::opt_bytes(self, (*self.raw).value).unwrap() } |
| } |
| |
| /// Returns `true` when a value is defined otherwise `false`. |
| /// |
| /// No value defined is a short-hand to represent a Boolean `true`. |
| pub fn has_value(&self) -> bool { |
| unsafe { !(*self.raw).value.is_null() } |
| } |
| |
| /// Gets the configuration level of this entry. |
| pub fn level(&self) -> ConfigLevel { |
| unsafe { ConfigLevel::from_raw((*self.raw).level) } |
| } |
| |
| /// Depth of includes where this variable was found |
| pub fn include_depth(&self) -> u32 { |
| unsafe { (*self.raw).include_depth as u32 } |
| } |
| } |
| |
| impl<'cfg> Binding for ConfigEntry<'cfg> { |
| type Raw = *mut raw::git_config_entry; |
| |
| unsafe fn from_raw(raw: *mut raw::git_config_entry) -> ConfigEntry<'cfg> { |
| ConfigEntry { |
| raw, |
| _marker: marker::PhantomData, |
| owned: true, |
| } |
| } |
| fn raw(&self) -> *mut raw::git_config_entry { |
| self.raw |
| } |
| } |
| |
| impl<'cfg> Binding for ConfigEntries<'cfg> { |
| type Raw = *mut raw::git_config_iterator; |
| |
| unsafe fn from_raw(raw: *mut raw::git_config_iterator) -> ConfigEntries<'cfg> { |
| ConfigEntries { |
| raw, |
| _marker: marker::PhantomData, |
| } |
| } |
| fn raw(&self) -> *mut raw::git_config_iterator { |
| self.raw |
| } |
| } |
| |
| // entries are only valid until the iterator is freed, so this impl is for |
| // `&'b T` instead of `T` to have a lifetime to tie them to. |
| // |
| // It's also not implemented for `&'b mut T` so we can have multiple entries |
| // (ok). |
| impl<'cfg, 'b> Iterator for &'b ConfigEntries<'cfg> { |
| type Item = Result<ConfigEntry<'b>, Error>; |
| fn next(&mut self) -> Option<Result<ConfigEntry<'b>, Error>> { |
| let mut raw = ptr::null_mut(); |
| unsafe { |
| try_call_iter!(raw::git_config_next(&mut raw, self.raw)); |
| Some(Ok(ConfigEntry { |
| owned: false, |
| raw, |
| _marker: marker::PhantomData, |
| })) |
| } |
| } |
| } |
| |
| impl<'cfg> Drop for ConfigEntries<'cfg> { |
| fn drop(&mut self) { |
| unsafe { raw::git_config_iterator_free(self.raw) } |
| } |
| } |
| |
| impl<'cfg> Drop for ConfigEntry<'cfg> { |
| fn drop(&mut self) { |
| if self.owned { |
| unsafe { raw::git_config_entry_free(self.raw) } |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use std::fs::File; |
| use tempfile::TempDir; |
| |
| use crate::Config; |
| |
| #[test] |
| fn smoke() { |
| let _cfg = Config::new().unwrap(); |
| let _ = Config::find_global(); |
| let _ = Config::find_system(); |
| let _ = Config::find_xdg(); |
| } |
| |
| #[test] |
| fn persisted() { |
| let td = TempDir::new().unwrap(); |
| let path = td.path().join("foo"); |
| File::create(&path).unwrap(); |
| |
| let mut cfg = Config::open(&path).unwrap(); |
| assert!(cfg.get_bool("foo.bar").is_err()); |
| cfg.set_bool("foo.k1", true).unwrap(); |
| cfg.set_i32("foo.k2", 1).unwrap(); |
| cfg.set_i64("foo.k3", 2).unwrap(); |
| cfg.set_str("foo.k4", "bar").unwrap(); |
| cfg.snapshot().unwrap(); |
| drop(cfg); |
| |
| let cfg = Config::open(&path).unwrap().snapshot().unwrap(); |
| assert_eq!(cfg.get_bool("foo.k1").unwrap(), true); |
| assert_eq!(cfg.get_i32("foo.k2").unwrap(), 1); |
| assert_eq!(cfg.get_i64("foo.k3").unwrap(), 2); |
| assert_eq!(cfg.get_str("foo.k4").unwrap(), "bar"); |
| |
| for entry in &cfg.entries(None).unwrap() { |
| let entry = entry.unwrap(); |
| entry.name(); |
| entry.value(); |
| entry.level(); |
| } |
| } |
| |
| #[test] |
| fn multivar() { |
| let td = TempDir::new().unwrap(); |
| let path = td.path().join("foo"); |
| File::create(&path).unwrap(); |
| |
| let mut cfg = Config::open(&path).unwrap(); |
| cfg.set_multivar("foo.bar", "^$", "baz").unwrap(); |
| cfg.set_multivar("foo.bar", "^$", "qux").unwrap(); |
| cfg.set_multivar("foo.bar", "^$", "quux").unwrap(); |
| cfg.set_multivar("foo.baz", "^$", "oki").unwrap(); |
| |
| // `entries` filters by name |
| let mut entries: Vec<String> = cfg |
| .entries(Some("foo.bar")) |
| .unwrap() |
| .into_iter() |
| .map(|entry| entry.unwrap().value().unwrap().into()) |
| .collect(); |
| entries.sort(); |
| assert_eq!(entries, ["baz", "quux", "qux"]); |
| |
| // which is the same as `multivar` without a regex |
| let mut multivals: Vec<String> = cfg |
| .multivar("foo.bar", None) |
| .unwrap() |
| .into_iter() |
| .map(|entry| entry.unwrap().value().unwrap().into()) |
| .collect(); |
| multivals.sort(); |
| assert_eq!(multivals, entries); |
| |
| // yet _with_ a regex, `multivar` filters by value |
| let mut quxish: Vec<String> = cfg |
| .multivar("foo.bar", Some("qu.*x")) |
| .unwrap() |
| .into_iter() |
| .map(|entry| entry.unwrap().value().unwrap().into()) |
| .collect(); |
| quxish.sort(); |
| assert_eq!(quxish, ["quux", "qux"]); |
| |
| cfg.remove_multivar("foo.bar", ".*").unwrap(); |
| |
| assert_eq!(cfg.entries(Some("foo.bar")).unwrap().count(), 0); |
| assert_eq!(cfg.multivar("foo.bar", None).unwrap().count(), 0); |
| } |
| |
| #[test] |
| fn parse() { |
| assert_eq!(Config::parse_bool("").unwrap(), false); |
| assert_eq!(Config::parse_bool("false").unwrap(), false); |
| assert_eq!(Config::parse_bool("no").unwrap(), false); |
| assert_eq!(Config::parse_bool("off").unwrap(), false); |
| assert_eq!(Config::parse_bool("0").unwrap(), false); |
| |
| assert_eq!(Config::parse_bool("true").unwrap(), true); |
| assert_eq!(Config::parse_bool("yes").unwrap(), true); |
| assert_eq!(Config::parse_bool("on").unwrap(), true); |
| assert_eq!(Config::parse_bool("1").unwrap(), true); |
| assert_eq!(Config::parse_bool("42").unwrap(), true); |
| |
| assert!(Config::parse_bool(" ").is_err()); |
| assert!(Config::parse_bool("some-string").is_err()); |
| assert!(Config::parse_bool("-").is_err()); |
| |
| assert_eq!(Config::parse_i32("0").unwrap(), 0); |
| assert_eq!(Config::parse_i32("1").unwrap(), 1); |
| assert_eq!(Config::parse_i32("100").unwrap(), 100); |
| assert_eq!(Config::parse_i32("-1").unwrap(), -1); |
| assert_eq!(Config::parse_i32("-100").unwrap(), -100); |
| assert_eq!(Config::parse_i32("1k").unwrap(), 1024); |
| assert_eq!(Config::parse_i32("4k").unwrap(), 4096); |
| assert_eq!(Config::parse_i32("1M").unwrap(), 1048576); |
| assert_eq!(Config::parse_i32("1G").unwrap(), 1024 * 1024 * 1024); |
| |
| assert_eq!(Config::parse_i64("0").unwrap(), 0); |
| assert_eq!(Config::parse_i64("1").unwrap(), 1); |
| assert_eq!(Config::parse_i64("100").unwrap(), 100); |
| assert_eq!(Config::parse_i64("-1").unwrap(), -1); |
| assert_eq!(Config::parse_i64("-100").unwrap(), -100); |
| assert_eq!(Config::parse_i64("1k").unwrap(), 1024); |
| assert_eq!(Config::parse_i64("4k").unwrap(), 4096); |
| assert_eq!(Config::parse_i64("1M").unwrap(), 1048576); |
| assert_eq!(Config::parse_i64("1G").unwrap(), 1024 * 1024 * 1024); |
| assert_eq!(Config::parse_i64("100G").unwrap(), 100 * 1024 * 1024 * 1024); |
| } |
| } |