<commit_before>//! Configuration for the zwreec compiler.
//!
//! Uses the `getopts` library to append a `getopts::Options` with compiler
//! specific flags and then creates a `Config` struct from `getopts::Matches`.
//!
//! # Usage
//!
//! This module depends on the [getopts](http://doc.rust-lang.org/getopts/getopts/index.html)
//! crate. To use it, you need to add `getopts` to your project. Read getopts'
//! [Usage](http://doc.rust-lang.org/getopts/getopts/index.html#usage) for more information.
//!
//! # Example
//!
//! The following example shows how to generate a `Config` struct from an empty
//! `getopts::Options`.
//!
//! ```
//! extern crate zwreec;
//! extern crate getopts;
//!
//! use zwreec::config;
//! use zwreec::config::Config;
//!
//!
//! fn main() {
//!     let args: Vec<String> = std::env::args().collect();
//!     let opts = config::zwreec_options(getopts::Options::new());
//!
//!     let matches = match opts.parse(&args[1..]) {
//!         Ok(m) => m,
//!         Err(f) => { panic!(f.to_string()) }
//!     };
//!
//!     let cfg = Config::from_matches(&matches);
//! }
//! ```
//!
//! # Appending this module (Development)
//!
//! To add new compiler flags for the compiler, you need to change three parts
//! in this module.
//!
//! 1. Appending the Struct
//!
//!     To store your new setting, you need to add it as a field to the `Config` struct. Here we
//!     add a new boolean `pub italics: bool` to control *italics*. Always add a field-comment.
//!
//!     ```ignore
//!     pub struct Config {
//!         /// Add easter egg to compiler
//!         pub easter_egg: bool,
//!         /// Instruct compiler to run these test-cases
//!         pub test_cases: Vec<TestCase>,
//!         /// Enables or disalbes Italics
//!         pub italics: bool,
//!     }
//!     ```
//!
//!     Now you also need to change `Config::default_config()` to provide the
//!     default value for your new field:
//!
//!     ```ignore
//!     pub fn default_config() -> Config {
//!         Config{
//!             easter_egg: true,
//!             test_cases: Vec::new(),
//!             italics: true,
//!         }
//!     }
//!     ```
//!
//! 2. Parse your flag in `from_matches()`
//!
//!     `from_matches` uses the Options `-F` and `-N` to enable or disable boolean flags.
//!     Therefore, if you added a new boolean flag, you can now simply add it to the match
//!     statement.
//!
//!     ```ignore
//!     for s in matches.opt_strs("F") {
//!         match s.as_ref() {
//!             "easter-egg" => {
//!                  cfg.easter_egg = true;
//!                  debug!("enabled easter-egg");
//!             },
//!             "italics" => {
//!                 cfg.italics = true;
//!                 debug!("enabbled italics");
//!             },
//!             _ => {
//!                 error!("Cannot enable feature {} - feature not known.", s);
//!             }
//!         }
//!     }
//!
//!     for s in matches.opt_strs("N") {
//!         match s.as_ref() {
//!             "easter-egg" => {
//!                 cfg.easter_egg = false;
//!                 debug!("disabled easter-egg");
//!             },
//!             "italics" => {
//!                 cfg.italics = false;
//!                 debug:("disalbed italics");
//!             }
//!             _ => {
//!                 error!("Cannot disable feature {} - feature not known.", s);
//!             }
//!         }
//!     }
//!     ```
//!
//! 3. Adding something that is not a boolean
//!
//!     If you need to add an option that is *not* a boolean, you will need to append the struct
//!     and `default_config()` accordingly (e.g. `pub notaflag: String,`). Then you need to add a new
//!     `getopts::Option` to `zwreec_options()`:
//!
//!     ```ignore
//! pub fn zwreec_options(mut opts: getopts::Options) -> getopts::Options {
//!     opts.optmulti("F", "feature", "", "FEAT");
//!     opts.optmulti("N", "no-feature", "enable or disable a feature (can occur multiple times).
//!                         List of supported features (default):
//!                             easter-egg (enabled)", "FEAT");
//!     opts.optflag("e", "generate-sample-zcode", "writes out a sample zcode file, input file is not used and can be omitted");
//!
//!     opts.optopt("n", "notaflag", "notaflag", "SOMETHING");
//!
//!     opts
//! }
//!     ```
//!
//!     Now you can append `Config::from_matches()` to analyse the provided matches for your new
//!     option and set the `Config` accordingly:
//!
//!     ```ignore
//!     if let s = matches.opt_str("n") {
//!         cfg.notaflag = s;
//!     }
//!     ```
//!
//! 4. Now you can use the new flag inside the compiler.
use getopts;

use std::vec::Vec;

/// Represents the configuration for the compiler.
///
/// This struct is created using either `config::default_config()` or
/// `config::parse_matches(matches: &getopts::Matches)`. It contains a series
/// of fields that can be used to control the behaviour of the compiler.
///
/// # Example Usage inside the compiler
///
/// ```
/// # use zwreec::config;
/// let cfg = config::Config::default_config();
///
/// if cfg.easter_egg {
///     println!("Egg!");
/// }
/// ```
#[derive(Clone)]
pub struct Config {
    /// Force compilation despite errors
    pub force: bool,
    /// Add easter egg to compiler
    pub easter_egg: bool,
    pub force_unicode: bool,
    pub no_colours: bool,
    pub half_memory: bool,
    /// Instruct compiler to run these test-cases
    pub test_cases: Vec<TestCase>,
}

impl Config {
    /// Returns a `Config` struct with preset defaults
    ///
    /// # Example
    ///
    /// ```
    /// use zwreec::config::Config;
    /// let cfg = Config::default_config();
    /// ```
    pub fn default_config() -> Config {
        Config{
            force: false,
            easter_egg: true,
            force_unicode: false,
            no_colours: false,
            half_memory: false,
            test_cases: Vec::new(),
        }
    }

    /// Returns a `Config` struct by using `getopts::Matches` to set the fields.
    ///
    /// This method analyses a `getopts::Matches` for fields provided by
    /// `zwreec_options()`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate getopts;
    /// # extern crate zwreec;
    /// let args: Vec<String> = std::env::args().collect();
    /// let opts = zwreec::config::zwreec_options(getopts::Options::new());
    ///
    /// let matches = match opts.parse(&args[1..]) {
    ///     Ok(m) => m,
    ///     Err(f) => { panic!(f.to_string()) }
    /// };
    ///
    /// let cfg = zwreec::config::Config::from_matches(&matches);
    /// ```
    pub fn from_matches(matches: &getopts::Matches) -> Config {
        // load defaults
        let mut cfg = Config::default_config();

        if matches.opt_present("generate-sample-zcode") {
            cfg.test_cases.push(TestCase::ZcodeBackend);
        }

        if matches.opt_present("f") {
            cfg.force = true;
        }

        // TODO: Find a way to make these two loops somewhat less.. repetitive
        for s in matches.opt_strs("F") {
            match s.as_ref() {
                "easter-egg" => {
                     cfg.easter_egg = true;
                     debug!("enabled easter-egg");
                },
                "force-unicode" => {
                     cfg.force_unicode = true;
                     debug!("enabled force-unicode");
                },
                "no-colours" => {
                     cfg.no_colours = true;
                     debug!("enabled no-colours");
                },
                "half-memory" => {
                     cfg.half_memory = true;
                     debug!("enabled half-memory");
                },
                _ => {
                    error!("Cannot enable feature {} - feature not known.", s);
                }
            }
        }

        for s in matches.opt_strs("N") {
            match s.as_ref() {
                "easter-egg" => {
                    cfg.easter_egg = false;
                    debug!("disabled easter-egg");
                },
                "force-unicode" => {
                     cfg.force_unicode = false;
                     debug!("disabled force-unicode");
                },
                "no-colours" => {
                     cfg.no_colours = false;
                     debug!("disabled no-colours");
                },
                "half-memory" => {
                     cfg.half_memory = false;
                     debug!("disabled half-memory");
                },
                _ => {
                    error!("Cannot disable feature {} - feature not known.", s);
                }
            }
        }

        cfg
    }
}

// TODO: If this stays only one Test Case, enum should be removed
/// The Type used to define backend tests for the compiler
#[derive(PartialEq,Clone)]
pub enum TestCase {
    /// Skips the normal compiler chain and builds an example zcode file by
    /// using every opcode.
    ZcodeBackend,
}

/// Appends a `getopts::Options` with compiler specific flags
///
/// The method `Config::from_matches()` looks for very specific `getopts::Matches`.
/// This function takes an `getopts::Options` to append it with Options required
/// by `from_matches`. It currently adds three fields:
///
/// ```ignore
/// opts.optmulti("F", "feature", "", "FEAT");
/// opts.optmulti("N", "no-feature", "enable or disable a feature (can occur multiple times).
///                     List of supported features (default):
///                         easter-egg (enabled)", "FEAT");
/// opts.optflag("e", "generate-sample-zcode", "writes out a sample zcode file, input file is not used and can be omitted");
/// ```
///
/// # Example
///
/// You can use this function to append your `getopts::Options`.
///
/// ```
/// # extern crate getopts;
/// # extern crate zwreec;
///
/// let mut opts = getopts::Options::new();
/// opts.optflag("h", "help", "print this message");
///
/// let opts = zwreec::config::zwreec_options(opts);
/// ```
///
/// Another useful example is to use it to gernerate a more compact usage by
/// having a function that only returns your options.
///
/// ```
/// # extern crate getopts;
/// # extern crate zwreec;
///
/// fn options() -> getopts::Options {
///     let mut opts = getopts::Options::new();
///     opts.optflag("h", "help", "display this help and exit");
///     opts.optflag("V", "version", "display version");
///
///     opts
/// }
///
/// fn print_usage(program: &str, verbose: bool) {
///     let brief = format!("Usage: {} [options]", program);
///
///     let opts = if verbose {
///         zwreec::config::zwreec_options(options())
///     } else {
///         options()
///     };
///
///     print!("{}", opts.usage(&brief));
/// }
/// ```
/// As you can see, `options()` returns your own command line options, which are then conditionally
/// expanded by using `zwreec_options()`.
pub fn zwreec_options(mut opts: getopts::Options) -> getopts::Options {
    opts.optflag("f", "force", "Try ignoring any errors that may occur and generate Z-Code anyways.
        This feature is highly unstable and may lead to corrupt output files.");
    opts.optmulti("F", "feature", "", "FEAT");
    opts.optmulti("N", "no-feature", "Enable or disable a feature (can occur multiple times).
        For more information about the supported features run --help with -v and see the feature
        list at the end of the output", "FEAT");
    opts.optflag("e", "generate-sample-zcode", "Write out a sample zcode file, input file is not used and can be omitted");

    opts
}

/// Prints a usage
///
/// This takes your options and prints a usage for those options.
/// It also includes zwreec_options and a feature list if a verbose usage was requested.
pub fn zwreec_usage(verbose: bool, mut opts: getopts::Options, brief: &str) -> String {
    use std::fmt::format;

    if verbose {
        opts = zwreec_options(opts);
    }

    let options_usage = opts.usage(brief);

    let features_usage = if verbose {
        "List of supported features (default value in parenthesis)
    easter-egg (enabled)
        Enables the generation of easter egg code. Enter the secret combination
        in your Z-Machine interpreter to activate the easter egg
    force-unicode (disabled)
        Force the generation of unicode print opcodes every time a unicode
        character is encountered. This disables the generation of the unicode
        translation table
    no-colours (disabled)
        Suppress generation of set_colour and set_text_style opcodes and disable
        the colour bit in the second byte of the header
    half-memory (disabled)
        Cut down space for static variable strings and heap in order to have
        binaries smaller than 64kB"
    } else {
        "Additional help:
    --help -v           Print the full set of options zwreec accepts"
    };

    format(format_args!("{}\n{}\n", options_usage, features_usage.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use getopts;

    fn config_from_args(args: Vec<String>) -> Config {
        let opts = zwreec_options(getopts::Options::new());

        match opts.parse(&args) {
            Ok(m) => Config::from_matches(&m),
            Err(f) => { panic!(f.to_string()) }
        }
    }

    #[test]
    fn test_feature_easter_egg_true() {
        let cfg = config_from_args(vec!["-F".to_string(), "easter-egg".to_string()]);

        assert_eq!(cfg.easter_egg, true);
    }

    #[test]
    fn test_feature_easter_egg_false() {
        let cfg = config_from_args(vec!["-N".to_string(), "easter-egg".to_string()]);

        assert_eq!(cfg.easter_egg, false);
    }

    #[test]
    fn test_feature_easter_egg_both() {
        let cfg = config_from_args(vec![
                                   "-N".to_string(),
                                   "easter-egg".to_string(),
                                   "-F".to_string(),
                                   "easter-egg".to_string()]);

        assert_eq!(cfg.easter_egg, false);
    }

    #[test]
    fn test_generate_sample_zcode() {
        let cfg = config_from_args(vec!["-e".to_string()]);

        assert_eq!(cfg.test_cases.is_empty(), false);

        let mut contains = false;
        for tc in cfg.test_cases {
            if tc == TestCase::ZcodeBackend {
                contains = true;
            }
        }

        assert!(contains);
    }
}
<commit_msg>add more info to feature descriptions<commit_after>//! Configuration for the zwreec compiler.
//!
//! Uses the `getopts` library to append a `getopts::Options` with compiler
//! specific flags and then creates a `Config` struct from `getopts::Matches`.
//!
//! # Usage
//!
//! This module depends on the [getopts](http://doc.rust-lang.org/getopts/getopts/index.html)
//! crate. To use it, you need to add `getopts` to your project. Read getopts'
//! [Usage](http://doc.rust-lang.org/getopts/getopts/index.html#usage) for more information.
//!
//! # Example
//!
//! The following example shows how to generate a `Config` struct from an empty
//! `getopts::Options`.
//!
//! ```
//! extern crate zwreec;
//! extern crate getopts;
//!
//! use zwreec::config;
//! use zwreec::config::Config;
//!
//!
//! fn main() {
//!     let args: Vec<String> = std::env::args().collect();
//!     let opts = config::zwreec_options(getopts::Options::new());
//!
//!     let matches = match opts.parse(&args[1..]) {
//!         Ok(m) => m,
//!         Err(f) => { panic!(f.to_string()) }
//!     };
//!
//!     let cfg = Config::from_matches(&matches);
//! }
//! ```
//!
//! # Appending this module (Development)
//!
//! To add new compiler flags for the compiler, you need to change three parts
//! in this module.
//!
//! 1. Appending the Struct
//!
//!     To store your new setting, you need to add it as a field to the `Config` struct. Here we
//!     add a new boolean `pub italics: bool` to control *italics*. Always add a field-comment.
//!
//!     ```ignore
//!     pub struct Config {
//!         /// Add easter egg to compiler
//!         pub easter_egg: bool,
//!         /// Instruct compiler to run these test-cases
//!         pub test_cases: Vec<TestCase>,
//!         /// Enables or disalbes Italics
//!         pub italics: bool,
//!     }
//!     ```
//!
//!     Now you also need to change `Config::default_config()` to provide the
//!     default value for your new field:
//!
//!     ```ignore
//!     pub fn default_config() -> Config {
//!         Config{
//!             easter_egg: true,
//!             test_cases: Vec::new(),
//!             italics: true,
//!         }
//!     }
//!     ```
//!
//! 2. Parse your flag in `from_matches()`
//!
//!     `from_matches` uses the Options `-F` and `-N` to enable or disable boolean flags.
//!     Therefore, if you added a new boolean flag, you can now simply add it to the match
//!     statement.
//!
//!     ```ignore
//!     for s in matches.opt_strs("F") {
//!         match s.as_ref() {
//!             "easter-egg" => {
//!                  cfg.easter_egg = true;
//!                  debug!("enabled easter-egg");
//!             },
//!             "italics" => {
//!                 cfg.italics = true;
//!                 debug!("enabbled italics");
//!             },
//!             _ => {
//!                 error!("Cannot enable feature {} - feature not known.", s);
//!             }
//!         }
//!     }
//!
//!     for s in matches.opt_strs("N") {
//!         match s.as_ref() {
//!             "easter-egg" => {
//!                 cfg.easter_egg = false;
//!                 debug!("disabled easter-egg");
//!             },
//!             "italics" => {
//!                 cfg.italics = false;
//!                 debug:("disalbed italics");
//!             }
//!             _ => {
//!                 error!("Cannot disable feature {} - feature not known.", s);
//!             }
//!         }
//!     }
//!     ```
//!
//! 3. Adding something that is not a boolean
//!
//!     If you need to add an option that is *not* a boolean, you will need to append the struct
//!     and `default_config()` accordingly (e.g. `pub notaflag: String,`). Then you need to add a new
//!     `getopts::Option` to `zwreec_options()`:
//!
//!     ```ignore
//! pub fn zwreec_options(mut opts: getopts::Options) -> getopts::Options {
//!     opts.optmulti("F", "feature", "", "FEAT");
//!     opts.optmulti("N", "no-feature", "enable or disable a feature (can occur multiple times).
//!                         List of supported features (default):
//!                             easter-egg (enabled)", "FEAT");
//!     opts.optflag("e", "generate-sample-zcode", "writes out a sample zcode file, input file is not used and can be omitted");
//!
//!     opts.optopt("n", "notaflag", "notaflag", "SOMETHING");
//!
//!     opts
//! }
//!     ```
//!
//!     Now you can append `Config::from_matches()` to analyse the provided matches for your new
//!     option and set the `Config` accordingly:
//!
//!     ```ignore
//!     if let s = matches.opt_str("n") {
//!         cfg.notaflag = s;
//!     }
//!     ```
//!
//! 4. Now you can use the new flag inside the compiler.
use getopts;

use std::vec::Vec;

/// Represents the configuration for the compiler.
///
/// This struct is created using either `config::default_config()` or
/// `config::parse_matches(matches: &getopts::Matches)`. It contains a series
/// of fields that can be used to control the behaviour of the compiler.
///
/// # Example Usage inside the compiler
///
/// ```
/// # use zwreec::config;
/// let cfg = config::Config::default_config();
///
/// if cfg.easter_egg {
///     println!("Egg!");
/// }
/// ```
#[derive(Clone)]
pub struct Config {
    /// Force compilation despite errors
    pub force: bool,
    /// Add easter egg to compiler
    pub easter_egg: bool,
    pub force_unicode: bool,
    pub no_colours: bool,
    pub half_memory: bool,
    /// Instruct compiler to run these test-cases
    pub test_cases: Vec<TestCase>,
}

impl Config {
    /// Returns a `Config` struct with preset defaults
    ///
    /// # Example
    ///
    /// ```
    /// use zwreec::config::Config;
    /// let cfg = Config::default_config();
    /// ```
    pub fn default_config() -> Config {
        Config{
            force: false,
            easter_egg: true,
            force_unicode: false,
            no_colours: false,
            half_memory: false,
            test_cases: Vec::new(),
        }
    }

    /// Returns a `Config` struct by using `getopts::Matches` to set the fields.
    ///
    /// This method analyses a `getopts::Matches` for fields provided by
    /// `zwreec_options()`.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate getopts;
    /// # extern crate zwreec;
    /// let args: Vec<String> = std::env::args().collect();
    /// let opts = zwreec::config::zwreec_options(getopts::Options::new());
    ///
    /// let matches = match opts.parse(&args[1..]) {
    ///     Ok(m) => m,
    ///     Err(f) => { panic!(f.to_string()) }
    /// };
    ///
    /// let cfg = zwreec::config::Config::from_matches(&matches);
    /// ```
    pub fn from_matches(matches: &getopts::Matches) -> Config {
        // load defaults
        let mut cfg = Config::default_config();

        if matches.opt_present("generate-sample-zcode") {
            cfg.test_cases.push(TestCase::ZcodeBackend);
        }

        if matches.opt_present("f") {
            cfg.force = true;
        }

        // TODO: Find a way to make these two loops somewhat less.. repetitive
        for s in matches.opt_strs("F") {
            match s.as_ref() {
                "easter-egg" => {
                     cfg.easter_egg = true;
                     debug!("enabled easter-egg");
                },
                "force-unicode" => {
                     cfg.force_unicode = true;
                     debug!("enabled force-unicode");
                },
                "no-colours" => {
                     cfg.no_colours = true;
                     debug!("enabled no-colours");
                },
                "half-memory" => {
                     cfg.half_memory = true;
                     debug!("enabled half-memory");
                },
                _ => {
                    error!("Cannot enable feature {} - feature not known.", s);
                }
            }
        }

        for s in matches.opt_strs("N") {
            match s.as_ref() {
                "easter-egg" => {
                    cfg.easter_egg = false;
                    debug!("disabled easter-egg");
                },
                "force-unicode" => {
                     cfg.force_unicode = false;
                     debug!("disabled force-unicode");
                },
                "no-colours" => {
                     cfg.no_colours = false;
                     debug!("disabled no-colours");
                },
                "half-memory" => {
                     cfg.half_memory = false;
                     debug!("disabled half-memory");
                },
                _ => {
                    error!("Cannot disable feature {} - feature not known.", s);
                }
            }
        }

        cfg
    }
}

// TODO: If this stays only one Test Case, enum should be removed
/// The Type used to define backend tests for the compiler
#[derive(PartialEq,Clone)]
pub enum TestCase {
    /// Skips the normal compiler chain and builds an example zcode file by
    /// using every opcode.
    ZcodeBackend,
}

/// Appends a `getopts::Options` with compiler specific flags
///
/// The method `Config::from_matches()` looks for very specific `getopts::Matches`.
/// This function takes an `getopts::Options` to append it with Options required
/// by `from_matches`. It currently adds three fields:
///
/// ```ignore
/// opts.optmulti("F", "feature", "", "FEAT");
/// opts.optmulti("N", "no-feature", "enable or disable a feature (can occur multiple times).
///                     List of supported features (default):
///                         easter-egg (enabled)", "FEAT");
/// opts.optflag("e", "generate-sample-zcode", "writes out a sample zcode file, input file is not used and can be omitted");
/// ```
///
/// # Example
///
/// You can use this function to append your `getopts::Options`.
///
/// ```
/// # extern crate getopts;
/// # extern crate zwreec;
///
/// let mut opts = getopts::Options::new();
/// opts.optflag("h", "help", "print this message");
///
/// let opts = zwreec::config::zwreec_options(opts);
/// ```
///
/// Another useful example is to use it to gernerate a more compact usage by
/// having a function that only returns your options.
///
/// ```
/// # extern crate getopts;
/// # extern crate zwreec;
///
/// fn options() -> getopts::Options {
///     let mut opts = getopts::Options::new();
///     opts.optflag("h", "help", "display this help and exit");
///     opts.optflag("V", "version", "display version");
///
///     opts
/// }
///
/// fn print_usage(program: &str, verbose: bool) {
///     let brief = format!("Usage: {} [options]", program);
///
///     let opts = if verbose {
///         zwreec::config::zwreec_options(options())
///     } else {
///         options()
///     };
///
///     print!("{}", opts.usage(&brief));
/// }
/// ```
/// As you can see, `options()` returns your own command line options, which are then conditionally
/// expanded by using `zwreec_options()`.
pub fn zwreec_options(mut opts: getopts::Options) -> getopts::Options {
    opts.optflag("f", "force", "Try ignoring any errors that may occur and generate Z-Code anyways.
        This feature is highly unstable and may lead to corrupt output files.");
    opts.optmulti("F", "feature", "", "FEAT");
    opts.optmulti("N", "no-feature", "Enable or disable a feature (can occur multiple times).
        For more information about the supported features run --help with -v and see the feature
        list at the end of the output", "FEAT");
    opts.optflag("e", "generate-sample-zcode", "Write out a sample zcode file, input file is not used and can be omitted");

    opts
}

/// Prints a usage
///
/// This takes your options and prints a usage for those options.
/// It also includes zwreec_options and a feature list if a verbose usage was requested.
pub fn zwreec_usage(verbose: bool, mut opts: getopts::Options, brief: &str) -> String {
    use std::fmt::format;

    if verbose {
        opts = zwreec_options(opts);
    }

    let options_usage = opts.usage(brief);

    let features_usage = if verbose {
        "List of supported features (default value in parenthesis)
    easter-egg (enabled)
        Enables the generation of easter egg code. Enter the secret combination
        in your Z-Machine interpreter to activate the easter egg
    force-unicode (disabled)
        Force the generation of unicode print opcodes every time a unicode
        character is encountered. This disables the generation of the unicode
        translation table
    no-colours (disabled)
        Suppress generation of set_colour and set_text_style opcodes and disable the
        colour bit in the second byte of the header - needed for DZIP on DOS/Atari
    half-memory (disabled)
        Cut down space for static variable strings and heap in order to have
        binaries probably smaller than 64kB as only DZIP32.exe on DOS can handle
        larger files, but DZIP.exe has a limit on 64kB"
    } else {
        "Additional help:
    --help -v           Print the full set of options zwreec accepts"
    };

    format(format_args!("{}\n{}\n", options_usage, features_usage.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use getopts;

    fn config_from_args(args: Vec<String>) -> Config {
        let opts = zwreec_options(getopts::Options::new());

        match opts.parse(&args) {
            Ok(m) => Config::from_matches(&m),
            Err(f) => { panic!(f.to_string()) }
        }
    }

    #[test]
    fn test_feature_easter_egg_true() {
        let cfg = config_from_args(vec!["-F".to_string(), "easter-egg".to_string()]);

        assert_eq!(cfg.easter_egg, true);
    }

    #[test]
    fn test_feature_easter_egg_false() {
        let cfg = config_from_args(vec!["-N".to_string(), "easter-egg".to_string()]);

        assert_eq!(cfg.easter_egg, false);
    }

    #[test]
    fn test_feature_easter_egg_both() {
        let cfg = config_from_args(vec![
                                   "-N".to_string(),
                                   "easter-egg".to_string(),
                                   "-F".to_string(),
                                   "easter-egg".to_string()]);

        assert_eq!(cfg.easter_egg, false);
    }

    #[test]
    fn test_generate_sample_zcode() {
        let cfg = config_from_args(vec!["-e".to_string()]);

        assert_eq!(cfg.test_cases.is_empty(), false);

        let mut contains = false;
        for tc in cfg.test_cases {
            if tc == TestCase::ZcodeBackend {
                contains = true;
            }
        }

        assert!(contains);
    }
}
<|endoftext|>


<commit_before>use std::ptr;
use std::mem;
use std::vec::Vec;

/// Implementation of insertion sort.
/// CLRS pg 18. `O(n^2)`.
fn insertion_sort<T: Ord>(mut a: Vec<T>) -> Vec<T> {
    // Break it apart so we can do tricky memory things.
    let len = a.len();
    let cap = a.capacity();
    let p = a.as_mut_ptr();
    unsafe {
        // Stop the memory manager from calling the destructor.
        mem::forget(a);
        for j in range(1, len as int) {
            let key_offset = p.offset(j) as *const T;
            let key = ptr::read(key_offset);
            let mut i = j - 1;
            while i > -1 && *p.offset(i) > key {
                let other_offset = p.offset(i) as *const T;
                ptr::write(p.offset(i + 1), ptr::read(other_offset));
                i = i - 1;
            }
            ptr::write(p.offset(i+1), key);
        }
        Vec::from_raw_parts(len, cap, p)
    }
}

#[cfg(test)]
mod tests {
    use sorting;

    #[test]
    fn test_insertion_sort_example() {
        // Example from CLRS pg 18.
        let mut sorted = vec!(5i32, 2, 4, 6, 1, 3);
        sorted = sorting::insertion_sort(sorted);
        assert_eq!(sorted, vec!(1i32, 2, 3, 4, 5, 6));
    }

    #[test]
    fn test_insertion_sort_duplicates() {
        let mut sorted = vec!(5i32, 5, 4);
        sorted = sorting::insertion_sort(sorted);
        assert_eq!(sorted, vec!(4, 5, 5));
    }

    #[test]
    fn test_insertion_sort_single_element() {
        let mut sorted = vec!(0i32);
        sorted = sorting::insertion_sort(sorted);
        assert_eq!(sorted, vec!(0));
    }

    #[test]
    fn test_insertion_sort_empty() {
        let mut sorted = vec!();
        sorted = sorting::insertion_sort::<i32>(sorted);
        assert_eq!(sorted, vec!());
    }
}
<commit_msg>selection sort: implement<commit_after>use std::ptr;
use std::mem;
use std::vec::Vec;

/// Implementation of insertion sort.
/// CLRS pg 18. `O(n^2)`.
fn insertion_sort<T: Ord>(mut a: Vec<T>) -> Vec<T> {
    // Break it apart so we can do tricky memory things.
    let len = a.len();
    let cap = a.capacity();
    let p = a.as_mut_ptr();
    unsafe {
        // Stop the memory manager from calling the destructor.
        mem::forget(a);
        for j in range(1, len as int) {
            let key_offset = p.offset(j) as *const T;
            let key = ptr::read(key_offset);
            let mut i = j - 1;
            while i > -1 && *p.offset(i) > key {
                let other_offset = p.offset(i) as *const T;
                ptr::write(p.offset(i + 1), ptr::read(other_offset));
                i = i - 1;
            }
            ptr::write(p.offset(i+1), key);
        }
        Vec::from_raw_parts(len, cap, p)
    }
}

/// Implementation of selection sort.
/// CLRS pg 29. `O(n^2)`.
fn selection_sort<T: Ord>(mut a: Vec<T>) -> Vec<T> {
    let len = a.len();
    let cap = a.capacity();
    let p = a.as_mut_ptr();
    unsafe {
        mem::forget(a);
        for j in range(0, (len - 1) as int) {
            let mut smallest = j;
            for i in range(j + 1, (len) as int) {
                let elem = ptr::read(p.offset(i) as *const T);
                let smallest_elem = ptr::read(p.offset(smallest) as *const T);
                if elem < smallest_elem {
                    smallest = i;
                }
            }
            if smallest != j {
                ptr::swap(p.offset(smallest), p.offset(j));
            }
        }
        Vec::from_raw_parts(len, cap, p)
    }
}

#[cfg(test)]
mod tests {
    use sorting;

    #[test]
    fn test_insertion_sort_example() {
        // Example from CLRS pg 18.
        let mut sorted = vec!(5i32, 2, 4, 6, 1, 3);
        sorted = sorting::insertion_sort(sorted);
        assert_eq!(sorted, vec!(1i32, 2, 3, 4, 5, 6));
    }

    #[test]
    fn test_insertion_sort_duplicates() {
        let mut sorted = vec!(5i32, 5, 4);
        sorted = sorting::insertion_sort(sorted);
        assert_eq!(sorted, vec!(4, 5, 5));
    }

    #[test]
    fn test_insertion_sort_single_element() {
        let mut sorted = vec!(0i32);
        sorted = sorting::insertion_sort(sorted);
        assert_eq!(sorted, vec!(0));
    }

    #[test]
    fn test_insertion_sort_empty() {
        let mut sorted = vec!();
        sorted = sorting::insertion_sort::<i32>(sorted);
        assert_eq!(sorted, vec!());
    }

    #[test]
    fn test_selection_sort_example() {
        // Example from CLRS pg 18 (originally for insertion sort).
        let mut sorted = vec!(5i32, 2, 4, 6, 1, 3);
        sorted = sorting::selection_sort(sorted);
        assert_eq!(sorted, vec!(1i32, 2, 3, 4, 5, 6));
    }

    #[test]
    fn test_selection_sort_duplicates() {
        let mut sorted = vec!(5i32, 5, 4);
        sorted = sorting::selection_sort(sorted);
        assert_eq!(sorted, vec!(4, 5, 5));
    }

    #[test]
    fn test_selection_sort_single_element() {
        let mut sorted = vec!(0i32);
        sorted = sorting::selection_sort(sorted);
        assert_eq!(sorted, vec!(0));
    }

    #[test]
    fn test_selection_sort_empty() {
        let mut sorted = vec!();
        sorted = sorting::selection_sort::<i32>(sorted);
        assert_eq!(sorted, vec!());
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Gomez Guillaume
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate stripper_lib;
extern crate tempdir;

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use tempdir::TempDir;

const BASIC : &'static str = r#"/// struct Foo comment
struct Foo {
    /// Foo comment
    /// fn some_func(a: u32,
    ///              b: u32) {}
    A: u32,
}

mod Bar {
    test! {
        /// struct inside macro
        struct SuperFoo;
        sub_test! {
            /// and another one!
            struct FooFoo {
                x: u32,
            }
        }
    }
}
"#;

const BASIC_STRIPPED : &'static str = r#"struct Foo {
    A: u32,
}

mod Bar {
    test! {
        struct SuperFoo;
        sub_test! {
            struct FooFoo {
                x: u32,
            }
        }
    }
}
"#;

fn get_basic_md(file: &str) -> String {
    format!(r#"<!-- file {} -->
<!-- struct Foo -->
 struct Foo comment
<!-- struct Foo§variant A -->
 Foo comment
 fn some_func(a: u32,
              b: u32) {{}}
<!-- mod Bar§macro test!§struct SuperFoo -->
 struct inside macro
<!-- mod Bar§macro test!§macro sub_test!§struct FooFoo -->
 and another one!
"#, file)
}

const BASIC2 : &'static str = r#"
use Bin;
use Box;
use Buildable;
use Container;
use Widget;
use Window;
use ffi;
use glib::object::Downcast;
use glib::object::IsA;
use glib::translate::*;

glib_wrapper! {
    /// Dialog boxes are a convenient way to prompt the user for a small amount
    /// of input, e.g. to display a message, ask a question, or anything else
    /// that does not require extensive effort on the user’s part.
    ///
    /// ```
    /// {
    ///  dialog = gtk_dialog_new_with_buttons ("Message",
    ///                                        parent,
    ///                                        flags,
    ///                                        _("_OK"),
    ///                                        GTK_RESPONSE_NONE,
    ///                                        NULL);
    /// }
    /// ```
    pub struct Dialog(Object<ffi::GtkDialog>): Widget, Container, Bin, Window, Buildable;

    match fn {
        get_type => || ffi::gtk_dialog_get_type(),
    }
}

impl Dialog {
    /// Creates a new dialog box.
    ///
    /// Widgets should not be packed into this `Window`
    /// directly, but into the `vbox` and `action_area`, as described above.
    ///
    /// # Returns
    ///
    /// the new dialog as a `Widget`
    pub fn new() -> Dialog {
        assert_initialized_main_thread!();
        unsafe {
            Widget::from_glib_none(ffi::gtk_dialog_new()).downcast_unchecked()
        }
    }

    //pub fn new_with_buttons<T: IsA<Window>>(title: Option<&str>, parent: Option<&T>, flags: DialogFlags, first_button_text: Option<&str>, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Dialog {
    //    unsafe { TODO: call ffi::gtk_dialog_new_with_buttons() }
    //}
}

/// Trait containing all `Dialog` methods.
pub trait DialogExt {
    /// Adds an activatable widget to the action area of a `Dialog`,
    /// connecting a signal handler that will emit the `Dialog::response`
    /// signal on the dialog when the widget is activated. The widget is
    /// appended to the end of the dialog’s action area. If you want to add a
    /// non-activatable widget, simply pack it into the `action_area` field
    /// of the `Dialog` struct.
    fn add_action_widget<T: IsA<Widget>>(&self, child: &T, response_id: i32);

    /// Adds a button with the given text
    fn add_button(&self, button_text: &str, response_id: i32) -> Widget;
}
"#;

const BASIC2_STRIPPED : &'static str = r#"
use Bin;
use Box;
use Buildable;
use Container;
use Widget;
use Window;
use ffi;
use glib::object::Downcast;
use glib::object::IsA;
use glib::translate::*;

glib_wrapper! {
    pub struct Dialog(Object<ffi::GtkDialog>): Widget, Container, Bin, Window, Buildable;

    match fn {
        get_type => || ffi::gtk_dialog_get_type(),
    }
}

impl Dialog {
    pub fn new() -> Dialog {
        assert_initialized_main_thread!();
        unsafe {
            Widget::from_glib_none(ffi::gtk_dialog_new()).downcast_unchecked()
        }
    }

    //pub fn new_with_buttons<T: IsA<Window>>(title: Option<&str>, parent: Option<&T>, flags: DialogFlags, first_button_text: Option<&str>, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Dialog {
    //    unsafe { TODO: call ffi::gtk_dialog_new_with_buttons() }
    //}
}

pub trait DialogExt {
    fn add_action_widget<T: IsA<Widget>>(&self, child: &T, response_id: i32);

    fn add_button(&self, button_text: &str, response_id: i32) -> Widget;
}
"#;

fn get_basic2_md(file: &str) -> String {
    format!(r#"<!-- file {} -->
<!-- struct Dialog -->
 Dialog boxes are a convenient way to prompt the user for a small amount
 of input, e.g. to display a message, ask a question, or anything else
 that does not require extensive effort on the user’s part.

 ```
 {{
  dialog = gtk_dialog_new_with_buttons ("Message",
                                        parent,
                                        flags,
                                        _("_OK"),
                                        GTK_RESPONSE_NONE,
                                        NULL);
 }}
 ```
<!-- impl Dialog§fn new -->
 Creates a new dialog box.

 Widgets should not be packed into this `Window`
 directly, but into the `vbox` and `action_area`, as described above.

 # Returns

 the new dialog as a `Widget`
<!-- trait DialogExt -->
 Trait containing all `Dialog` methods.
<!-- trait DialogExt§fn add_action_widget -->
 Adds an activatable widget to the action area of a `Dialog`,
 connecting a signal handler that will emit the `Dialog::response`
 signal on the dialog when the widget is activated. The widget is
 appended to the end of the dialog’s action area. If you want to add a
 non-activatable widget, simply pack it into the `action_area` field
 of the `Dialog` struct.
<!-- trait DialogExt§fn add_button -->
 Adds a button with the given text
"#, file)
}

const BASIC2_MD: &'static str = r#"<!-- file * -->
<!-- struct Dialog -->
 Dialog boxes are a convenient way to prompt the user for a small amount
 of input, e.g. to display a message, ask a question, or anything else
 that does not require extensive effort on the user’s part.

 ```
 {
  dialog = gtk_dialog_new_with_buttons ("Message",
                                        parent,
                                        flags,
                                        _("_OK"),
                                        GTK_RESPONSE_NONE,
                                        NULL);
 }
 ```
<!-- impl Dialog§fn new -->
 Creates a new dialog box.

 Widgets should not be packed into this `Window`
 directly, but into the `vbox` and `action_area`, as described above.

 # Returns

 the new dialog as a `Widget`
<!-- impl Dialog§fn new_with_buttons -->
 Creates a new `Dialog` with title `title` (or `None` for the default
 title; see `Window::set_title`) and transient parent `parent` (or
 `None` for none; see `Window::set_transient_for`).
<!-- trait DialogExt -->
 Trait containing all `Dialog` methods.
<!-- trait DialogExt§fn add_action_widget -->
 Adds an activatable widget to the action area of a `Dialog`,
 connecting a signal handler that will emit the `Dialog::response`
 signal on the dialog when the widget is activated. The widget is
 appended to the end of the dialog’s action area. If you want to add a
 non-activatable widget, simply pack it into the `action_area` field
 of the `Dialog` struct.
<!-- trait DialogExt§fn add_button -->
 Adds a button with the given text
"#;

const BASIC3 : &'static str = r#"///struct Foo comment
struct Foo;
"#;

const BASIC3_STRIPPED : &'static str = r#"struct Foo;
"#;

fn get_basic3_md(file: &str) -> String {
    format!(r#"<!-- file {} -->
<!-- struct Foo -->
struct Foo comment
"#, file)
}

fn gen_file(temp_dir: &TempDir, filename: &str, content: &str) -> File {
    let mut f = File::create(temp_dir.path().join(filename)).expect("gen_file");
    write!(f, "{}", content).unwrap();
    f
}

fn compare_files(expected_content: &str, file: &Path) {
    let mut f = File::open(file).expect("compare_files '{}'");
    let mut buf = String::new();
    f.read_to_string(&mut buf).unwrap();
    println!("");
    for (l, r) in expected_content.lines().zip(buf.lines()) {
        assert_eq!(l, r);
        println!("{}", l);
    }
    assert!(expected_content == &buf);
}

#[allow(unused_must_use)]
#[test]
fn test_strip() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC);
    {
        let mut f = gen_file(&temp_dir, comment_file, "");
        stripper_lib::strip_comments(temp_dir.path(), test_file, &mut f, false);
    }
    compare_files(&get_basic_md(test_file), &temp_dir.path().join(comment_file));
    compare_files(BASIC_STRIPPED, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test_regeneration() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC_STRIPPED);
    gen_file(&temp_dir, comment_file, &get_basic_md(test_file));
    stripper_lib::regenerate_doc_comments(temp_dir.path().to_str().unwrap(), false,
                                          &temp_dir.path().join(comment_file).to_str().unwrap(),
                                          false);
    compare_files(BASIC, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test2_strip() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC2);
    {
        let mut f = gen_file(&temp_dir, comment_file, "");
        stripper_lib::strip_comments(temp_dir.path(), test_file, &mut f, true);
    }
    compare_files(&get_basic2_md(test_file), &temp_dir.path().join(comment_file));
    compare_files(BASIC2_STRIPPED, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test2_regeneration() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC2_STRIPPED);
    gen_file(&temp_dir, comment_file, BASIC2_MD);
    stripper_lib::regenerate_doc_comments(temp_dir.path().to_str().unwrap(), false,
                                          &temp_dir.path().join(comment_file).to_str().unwrap(),
                                          true);
    compare_files(BASIC2, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test3_strip() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC3);
    {
        let mut f = gen_file(&temp_dir, comment_file, "");
        stripper_lib::strip_comments(temp_dir.path(), test_file, &mut f, false);
    }
    compare_files(&get_basic3_md(test_file), &temp_dir.path().join(comment_file));
    compare_files(BASIC3_STRIPPED, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test3_regeneration() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC3_STRIPPED);
    gen_file(&temp_dir, comment_file, &get_basic3_md(test_file));
    stripper_lib::regenerate_doc_comments(temp_dir.path().to_str().unwrap(), false,
                                          &temp_dir.path().join(comment_file).to_str().unwrap(),
                                          false);
    compare_files(BASIC3, &temp_dir.path().join(test_file));
}
<commit_msg>Update tests<commit_after>// Copyright 2016 Gomez Guillaume
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate stripper_lib;
extern crate tempdir;

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use tempdir::TempDir;

const BASIC : &'static str = r#"/// struct Foo comment
struct Foo {
    /// Foo comment
    /// fn some_func(a: u32,
    ///              b: u32) {}
    A: u32,
}

mod Bar {
    test! {
        /// struct inside macro
        struct SuperFoo;
        sub_test! {
            /// and another one!
            struct FooFoo {
                x: u32,
            }
        }
    }
}
"#;

const BASIC_STRIPPED : &'static str = r#"struct Foo {
    A: u32,
}

mod Bar {
    test! {
        struct SuperFoo;
        sub_test! {
            struct FooFoo {
                x: u32,
            }
        }
    }
}
"#;

fn get_basic_md(file: &str) -> String {
    format!(r#"<!-- file {} -->
<!-- struct Foo -->
struct Foo comment
<!-- struct Foo§variant A -->
Foo comment
fn some_func(a: u32,
             b: u32) {{}}
<!-- mod Bar§macro test!§struct SuperFoo -->
struct inside macro
<!-- mod Bar§macro test!§macro sub_test!§struct FooFoo -->
and another one!
"#, file)
}

const BASIC2 : &'static str = r#"
use Bin;
use Box;
use Buildable;
use Container;
use Widget;
use Window;
use ffi;
use glib::object::Downcast;
use glib::object::IsA;
use glib::translate::*;

glib_wrapper! {
    /// Dialog boxes are a convenient way to prompt the user for a small amount
    /// of input, e.g. to display a message, ask a question, or anything else
    /// that does not require extensive effort on the user’s part.
    ///
    /// ```
    /// {
    ///  dialog = gtk_dialog_new_with_buttons ("Message",
    ///                                        parent,
    ///                                        flags,
    ///                                        _("_OK"),
    ///                                        GTK_RESPONSE_NONE,
    ///                                        NULL);
    /// }
    /// ```
    pub struct Dialog(Object<ffi::GtkDialog>): Widget, Container, Bin, Window, Buildable;

    match fn {
        get_type => || ffi::gtk_dialog_get_type(),
    }
}

impl Dialog {
    /// Creates a new dialog box.
    ///
    /// Widgets should not be packed into this `Window`
    /// directly, but into the `vbox` and `action_area`, as described above.
    ///
    /// # Returns
    ///
    /// the new dialog as a `Widget`
    pub fn new() -> Dialog {
        assert_initialized_main_thread!();
        unsafe {
            Widget::from_glib_none(ffi::gtk_dialog_new()).downcast_unchecked()
        }
    }

    //pub fn new_with_buttons<T: IsA<Window>>(title: Option<&str>, parent: Option<&T>, flags: DialogFlags, first_button_text: Option<&str>, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Dialog {
    //    unsafe { TODO: call ffi::gtk_dialog_new_with_buttons() }
    //}
}

/// Trait containing all `Dialog` methods.
pub trait DialogExt {
    /// Adds an activatable widget to the action area of a `Dialog`,
    /// connecting a signal handler that will emit the `Dialog::response`
    /// signal on the dialog when the widget is activated. The widget is
    /// appended to the end of the dialog’s action area. If you want to add a
    /// non-activatable widget, simply pack it into the `action_area` field
    /// of the `Dialog` struct.
    fn add_action_widget<T: IsA<Widget>>(&self, child: &T, response_id: i32);

    /// Adds a button with the given text
    fn add_button(&self, button_text: &str, response_id: i32) -> Widget;
}
"#;

const BASIC2_STRIPPED : &'static str = r#"
use Bin;
use Box;
use Buildable;
use Container;
use Widget;
use Window;
use ffi;
use glib::object::Downcast;
use glib::object::IsA;
use glib::translate::*;

glib_wrapper! {
    pub struct Dialog(Object<ffi::GtkDialog>): Widget, Container, Bin, Window, Buildable;

    match fn {
        get_type => || ffi::gtk_dialog_get_type(),
    }
}

impl Dialog {
    pub fn new() -> Dialog {
        assert_initialized_main_thread!();
        unsafe {
            Widget::from_glib_none(ffi::gtk_dialog_new()).downcast_unchecked()
        }
    }

    //pub fn new_with_buttons<T: IsA<Window>>(title: Option<&str>, parent: Option<&T>, flags: DialogFlags, first_button_text: Option<&str>, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) -> Dialog {
    //    unsafe { TODO: call ffi::gtk_dialog_new_with_buttons() }
    //}
}

pub trait DialogExt {
    fn add_action_widget<T: IsA<Widget>>(&self, child: &T, response_id: i32);

    fn add_button(&self, button_text: &str, response_id: i32) -> Widget;
}
"#;

fn get_basic2_md(file: &str) -> String {
    format!(r#"<!-- file {} -->
<!-- struct Dialog -->
Dialog boxes are a convenient way to prompt the user for a small amount
of input, e.g. to display a message, ask a question, or anything else
that does not require extensive effort on the user’s part.

```
{{
 dialog = gtk_dialog_new_with_buttons ("Message",
                                       parent,
                                       flags,
                                       _("_OK"),
                                       GTK_RESPONSE_NONE,
                                       NULL);
}}
```
<!-- impl Dialog§fn new -->
Creates a new dialog box.

Widgets should not be packed into this `Window`
directly, but into the `vbox` and `action_area`, as described above.

# Returns

the new dialog as a `Widget`
<!-- trait DialogExt -->
Trait containing all `Dialog` methods.
<!-- trait DialogExt§fn add_action_widget -->
Adds an activatable widget to the action area of a `Dialog`,
connecting a signal handler that will emit the `Dialog::response`
signal on the dialog when the widget is activated. The widget is
appended to the end of the dialog’s action area. If you want to add a
non-activatable widget, simply pack it into the `action_area` field
of the `Dialog` struct.
<!-- trait DialogExt§fn add_button -->
Adds a button with the given text
"#, file)
}

const BASIC2_MD: &'static str = r#"<!-- file * -->
<!-- struct Dialog -->
Dialog boxes are a convenient way to prompt the user for a small amount
of input, e.g. to display a message, ask a question, or anything else
that does not require extensive effort on the user’s part.

```
{
 dialog = gtk_dialog_new_with_buttons ("Message",
                                       parent,
                                       flags,
                                       _("_OK"),
                                       GTK_RESPONSE_NONE,
                                       NULL);
}
```
<!-- impl Dialog§fn new -->
Creates a new dialog box.

Widgets should not be packed into this `Window`
directly, but into the `vbox` and `action_area`, as described above.

# Returns

the new dialog as a `Widget`
<!-- impl Dialog§fn new_with_buttons -->
Creates a new `Dialog` with title `title` (or `None` for the default
title; see `Window::set_title`) and transient parent `parent` (or
`None` for none; see `Window::set_transient_for`).
<!-- trait DialogExt -->
Trait containing all `Dialog` methods.
<!-- trait DialogExt§fn add_action_widget -->
Adds an activatable widget to the action area of a `Dialog`,
connecting a signal handler that will emit the `Dialog::response`
signal on the dialog when the widget is activated. The widget is
appended to the end of the dialog’s action area. If you want to add a
non-activatable widget, simply pack it into the `action_area` field
of the `Dialog` struct.
<!-- trait DialogExt§fn add_button -->
Adds a button with the given text
"#;

const BASIC3 : &'static str = r#"///struct Foo comment
struct Foo;
"#;

const BASIC3_STRIPPED : &'static str = r#"struct Foo;
"#;

const BASIC3_REGEN : &'static str = r#"/// struct Foo comment
struct Foo;
"#;

fn get_basic3_md(file: &str) -> String {
    format!(r#"<!-- file {} -->
<!-- struct Foo -->
struct Foo comment
"#, file)
}

fn gen_file(temp_dir: &TempDir, filename: &str, content: &str) -> File {
    let mut f = File::create(temp_dir.path().join(filename)).expect("gen_file");
    write!(f, "{}", content).unwrap();
    f
}

fn compare_files(expected_content: &str, file: &Path) {
    let mut f = File::open(file).expect("compare_files '{}'");
    let mut buf = String::new();
    f.read_to_string(&mut buf).unwrap();
    println!("");
    for (l, r) in expected_content.lines().zip(buf.lines()) {
        assert_eq!(l, r);
        println!("{}", l);
    }
    assert!(expected_content == &buf);
}

#[allow(unused_must_use)]
#[test]
fn test_strip() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC);
    {
        let mut f = gen_file(&temp_dir, comment_file, "");
        stripper_lib::strip_comments(temp_dir.path(), test_file, &mut f, false);
    }
    compare_files(&get_basic_md(test_file), &temp_dir.path().join(comment_file));
    compare_files(BASIC_STRIPPED, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test_regeneration() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC_STRIPPED);
    gen_file(&temp_dir, comment_file, &get_basic_md(test_file));
    stripper_lib::regenerate_doc_comments(temp_dir.path().to_str().unwrap(), false,
                                          &temp_dir.path().join(comment_file).to_str().unwrap(),
                                          false);
    compare_files(BASIC, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test2_strip() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC2);
    {
        let mut f = gen_file(&temp_dir, comment_file, "");
        stripper_lib::strip_comments(temp_dir.path(), test_file, &mut f, true);
    }
    compare_files(&get_basic2_md(test_file), &temp_dir.path().join(comment_file));
    compare_files(BASIC2_STRIPPED, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test2_regeneration() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC2_STRIPPED);
    gen_file(&temp_dir, comment_file, BASIC2_MD);
    stripper_lib::regenerate_doc_comments(temp_dir.path().to_str().unwrap(), false,
                                          &temp_dir.path().join(comment_file).to_str().unwrap(),
                                          true);
    compare_files(BASIC2, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test3_strip() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC3);
    {
        let mut f = gen_file(&temp_dir, comment_file, "");
        stripper_lib::strip_comments(temp_dir.path(), test_file, &mut f, false);
    }
    compare_files(&get_basic3_md(test_file), &temp_dir.path().join(comment_file));
    compare_files(BASIC3_STRIPPED, &temp_dir.path().join(test_file));
}

#[allow(unused_must_use)]
#[test]
fn test3_regeneration() {
    let test_file = "basic.rs";
    let comment_file = "basic.md";
    let temp_dir = TempDir::new("").unwrap();
    gen_file(&temp_dir, test_file, BASIC3_STRIPPED);
    gen_file(&temp_dir, comment_file, &get_basic3_md(test_file));
    stripper_lib::regenerate_doc_comments(temp_dir.path().to_str().unwrap(), false,
                                          &temp_dir.path().join(comment_file).to_str().unwrap(),
                                          false);
    compare_files(BASIC3_REGEN, &temp_dir.path().join(test_file));
}
<|endoftext|>


<commit_before>extern crate arrayvec;
#[macro_use] extern crate matches;

use arrayvec::ArrayVec;
use arrayvec::ArrayString;
use std::mem;
use arrayvec::errors::CapacityError;

use std::collections::HashMap;

#[test]
fn test_simple() {
    use std::ops::Add;

    let mut vec: ArrayVec<[Vec<i32>; 3]> = ArrayVec::new();

    vec.push(vec![1, 2, 3, 4]);
    vec.push(vec![10]);
    vec.push(vec![-1, 13, -2]);

    for elt in &vec {
        assert_eq!(elt.iter().fold(0, Add::add), 10);
    }

    let sum_len = vec.into_iter().map(|x| x.len()).fold(0, Add::add);
    assert_eq!(sum_len, 8);
}

#[test]
fn test_u16_index() {
    const N: usize = 4096;
    let mut vec: ArrayVec<[_; N]> = ArrayVec::new();
    for _ in 0..N {
        assert!(vec.try_push(1u8).is_ok());
    }
    assert!(vec.try_push(0).is_err());
    assert_eq!(vec.len(), N);
}

#[test]
fn test_iter() {
    let mut iter = ArrayVec::from([1, 2, 3]).into_iter();
    assert_eq!(iter.size_hint(), (3, Some(3)));
    assert_eq!(iter.next_back(), Some(3));
    assert_eq!(iter.next(), Some(1));
    assert_eq!(iter.next_back(), Some(2));
    assert_eq!(iter.size_hint(), (0, Some(0)));
    assert_eq!(iter.next_back(), None);
}

#[test]
fn test_drop() {
    use std::cell::Cell;

    let flag = &Cell::new(0);

    struct Bump<'a>(&'a Cell<i32>);

    impl<'a> Drop for Bump<'a> {
        fn drop(&mut self) {
            let n = self.0.get();
            self.0.set(n + 1);
        }
    }

    {
        let mut array = ArrayVec::<[Bump; 128]>::new();
        array.push(Bump(flag));
        array.push(Bump(flag));
    }
    assert_eq!(flag.get(), 2);

    // test something with the nullable pointer optimization
    flag.set(0);

    {
        let mut array = ArrayVec::<[_; 3]>::new();
        array.push(vec![Bump(flag)]);
        array.push(vec![Bump(flag), Bump(flag)]);
        array.push(vec![]);
        let push4 = array.try_push(vec![Bump(flag)]);
        assert_eq!(flag.get(), 0);
        drop(push4);
        assert_eq!(flag.get(), 1);
        drop(array.pop());
        assert_eq!(flag.get(), 1);
        drop(array.pop());
        assert_eq!(flag.get(), 3);
    }

    assert_eq!(flag.get(), 4);

    // test into_inner
    flag.set(0);
    {
        let mut array = ArrayVec::<[_; 3]>::new();
        array.push(Bump(flag));
        array.push(Bump(flag));
        array.push(Bump(flag));
        let inner = array.into_inner();
        assert!(inner.is_ok());
        assert_eq!(flag.get(), 0);
        drop(inner);
        assert_eq!(flag.get(), 3);
    }

}

#[test]
fn test_extend() {
    let mut range = 0..10;

    let mut array: ArrayVec<[_; 5]> = range.by_ref().collect();
    assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
    assert_eq!(range.next(), Some(5));

    array.extend(range.by_ref());
    assert_eq!(range.next(), Some(6));

    let mut array: ArrayVec<[_; 10]> = (0..3).collect();
    assert_eq!(&array[..], &[0, 1, 2]);
    array.extend(3..5);
    assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
}

#[test]
fn test_is_send_sync() {
    let data = ArrayVec::<[Vec<i32>; 5]>::new();
    &data as &Send;
    &data as &Sync;
}

#[test]
fn test_compact_size() {
    // Future rust will kill these drop flags!
    // 4 elements size + 1 len + 1 enum tag + [1 drop flag]
    type ByteArray = ArrayVec<[u8; 4]>;
    println!("{}", mem::size_of::<ByteArray>());
    assert!(mem::size_of::<ByteArray>() <= 8);

    // 12 element size + 1 enum tag + 3 padding + 1 len + 1 drop flag + 2 padding
    type QuadArray = ArrayVec<[u32; 3]>;
    println!("{}", mem::size_of::<QuadArray>());
    assert!(mem::size_of::<QuadArray>() <= 24);
}

#[test]
fn test_drain() {
    let mut v = ArrayVec::from([0; 8]);
    v.pop();
    v.drain(0..7);
    assert_eq!(&v[..], &[]);

    v.extend(0..);
    v.drain(1..4);
    assert_eq!(&v[..], &[0, 4, 5, 6, 7]);
    let u: ArrayVec<[_; 3]> = v.drain(1..4).rev().collect();
    assert_eq!(&u[..], &[6, 5, 4]);
    assert_eq!(&v[..], &[0, 7]);
    v.drain(..);
    assert_eq!(&v[..], &[]);
}

#[test]
fn test_retain() {
    let mut v = ArrayVec::from([0; 8]);
    for (i, elt) in v.iter_mut().enumerate() {
        *elt = i;
    }
    v.retain(|_| true);
    assert_eq!(&v[..], &[0, 1, 2, 3, 4, 5, 6, 7]);
    v.retain(|elt| {
        *elt /= 2;
        *elt % 2 == 0
    });
    assert_eq!(&v[..], &[0, 0, 2, 2]);
    v.retain(|_| false);
    assert_eq!(&v[..], &[]);
}

#[test]
#[should_panic]
fn test_drain_oob() {
    let mut v = ArrayVec::from([0; 8]);
    v.pop();
    v.drain(0..8);
}

#[test]
#[should_panic]
fn test_drop_panic() {
    struct DropPanic;

    impl Drop for DropPanic {
        fn drop(&mut self) {
            panic!("drop");
        }
    }

    let mut array = ArrayVec::<[DropPanic; 1]>::new();
    array.push(DropPanic);
}

#[test]
#[should_panic]
fn test_drop_panic_into_iter() {
    struct DropPanic;

    impl Drop for DropPanic {
        fn drop(&mut self) {
            panic!("drop");
        }
    }

    let mut array = ArrayVec::<[DropPanic; 1]>::new();
    array.push(DropPanic);
    array.into_iter();
}

#[test]
fn test_insert() {
    let mut v = ArrayVec::from([]);
    assert_matches!(v.try_push(1), Err(_));

    let mut v = ArrayVec::<[_; 3]>::new();
    v.insert(0, 0);
    v.insert(1, 1);
    //let ret1 = v.try_insert(3, 3);
    //assert_matches!(ret1, Err(InsertError::OutOfBounds(_)));
    assert_eq!(&v[..], &[0, 1]);
    v.insert(2, 2);
    assert_eq!(&v[..], &[0, 1, 2]);

    let ret2 = v.try_insert(1, 9);
    assert_eq!(&v[..], &[0, 1, 2]);
    assert_matches!(ret2, Err(_));

    let mut v = ArrayVec::from([2]);
    assert_matches!(v.try_insert(0, 1), Err(CapacityError { .. }));
    assert_matches!(v.try_insert(1, 1), Err(CapacityError { .. }));
    //assert_matches!(v.try_insert(2, 1), Err(CapacityError { .. }));
}

#[test]
fn test_into_inner_1() {
    let mut v = ArrayVec::from([1, 2]);
    v.pop();
    let u = v.clone();
    assert_eq!(v.into_inner(), Err(u));
}

#[test]
fn test_into_inner_2() {
    let mut v = ArrayVec::<[String; 4]>::new();
    v.push("a".into());
    v.push("b".into());
    v.push("c".into());
    v.push("d".into());
    assert_eq!(v.into_inner().unwrap(), ["a", "b", "c", "d"]);
}

#[test]
fn test_into_inner_3_() {
    let mut v = ArrayVec::<[i32; 4]>::new();
    v.extend(1..);
    assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]);
}

#[test]
fn test_write() {
    use std::io::Write;
    let mut v = ArrayVec::<[_; 8]>::new();
    write!(&mut v, "\x01\x02\x03").unwrap();
    assert_eq!(&v[..], &[1, 2, 3]);
    let r = v.write(&[9; 16]).unwrap();
    assert_eq!(r, 5);
    assert_eq!(&v[..], &[1, 2, 3, 9, 9, 9, 9, 9]);
}

#[test]
fn array_clone_from() {
    let mut v = ArrayVec::<[_; 4]>::new();
    v.push(vec![1, 2]);
    v.push(vec![3, 4, 5]);
    v.push(vec![6]);
    let reference = v.to_vec();
    let mut u = ArrayVec::<[_; 4]>::new();
    u.clone_from(&v);
    assert_eq!(&u, &reference[..]);

    let mut t = ArrayVec::<[_; 4]>::new();
    t.push(vec![97]);
    t.push(vec![]);
    t.push(vec![5, 6, 2]);
    t.push(vec![2]);
    t.clone_from(&v);
    assert_eq!(&t, &reference[..]);
    t.clear();
    t.clone_from(&v);
    assert_eq!(&t, &reference[..]);
}

#[test]
fn test_string() {
    use std::error::Error;

    let text = "hello world";
    let mut s = ArrayString::<[_; 16]>::new();
    s.try_push_str(text).unwrap();
    assert_eq!(&s, text);
    assert_eq!(text, &s);

    // Make sure Hash / Eq / Borrow match up so we can use HashMap
    let mut map = HashMap::new();
    map.insert(s, 1);
    assert_eq!(map[text], 1);

    let mut t = ArrayString::<[_; 2]>::new();
    assert!(t.try_push_str(text).is_err());
    assert_eq!(&t, "");

    t.push_str("ab");
    // DerefMut
    let tmut: &mut str = &mut t;
    assert_eq!(tmut, "ab");

    // Test Error trait / try
    let t = || -> Result<(), Box<Error>> {
        let mut t = ArrayString::<[_; 2]>::new();
        try!(t.try_push_str(text));
        Ok(())
    }();
    assert!(t.is_err());
}

#[test]
fn test_string_from() {
    let text = "hello world";
	// Test `from` constructor
    let u = ArrayString::<[_; 11]>::from(text).unwrap();
    assert_eq!(&u, text);
    assert_eq!(u.len(), text.len());
}

#[test]
fn test_string_from_bytes() {
    let text = "hello world";
    let u = ArrayString::from_byte_string(b"hello world").unwrap();
    assert_eq!(&u, text);
    assert_eq!(u.len(), text.len());
}

#[test]
fn test_string_clone() {
    let text = "hi";
    let mut s = ArrayString::<[_; 4]>::new();
    s.push_str("abcd");
    let t = ArrayString::<[_; 4]>::from(text).unwrap();
    s.clone_from(&t);
    assert_eq!(&t, &s);
}

#[test]
fn test_string_push() {
    let text = "abcαβγ";
    let mut s = ArrayString::<[_; 8]>::new();
    for c in text.chars() {
        if let Err(_) = s.try_push(c) {
            break;
        }
    }
    assert_eq!("abcαβ", &s[..]);
    s.push('x');
    assert_eq!("abcαβx", &s[..]);
    assert!(s.try_push('x').is_err());
}

#[test]
fn test_insert_at_length() {
    let mut v = ArrayVec::<[_; 8]>::new();
    let result1 = v.try_insert(0, "a");
    let result2 = v.try_insert(1, "b");
    assert!(result1.is_ok() && result2.is_ok());
    assert_eq!(&v[..], &["a", "b"]);
}

#[should_panic]
#[test]
fn test_insert_out_of_bounds() {
    let mut v = ArrayVec::<[_; 8]>::new();
    let _ = v.try_insert(1, "test");
}

/*
 * insert that pushes out the last
    let mut u = ArrayVec::from([1, 2, 3, 4]);
    let ret = u.try_insert(3, 99);
    assert_eq!(&u[..], &[1, 2, 3, 99]);
    assert_matches!(ret, Err(_));
    let ret = u.try_insert(4, 77);
    assert_eq!(&u[..], &[1, 2, 3, 99]);
    assert_matches!(ret, Err(_));
*/

#[test]
fn test_drop_in_insert() {
    use std::cell::Cell;

    let flag = &Cell::new(0);

    struct Bump<'a>(&'a Cell<i32>);

    impl<'a> Drop for Bump<'a> {
        fn drop(&mut self) {
            let n = self.0.get();
            self.0.set(n + 1);
        }
    }

    flag.set(0);

    {
        let mut array = ArrayVec::<[_; 2]>::new();
        array.push(Bump(flag));
        array.insert(0, Bump(flag));
        assert_eq!(flag.get(), 0);
        let ret = array.try_insert(1, Bump(flag));
        assert_eq!(flag.get(), 0);
        assert_matches!(ret, Err(_));
        drop(ret);
        assert_eq!(flag.get(), 1);
    }
    assert_eq!(flag.get(), 3);
}
<commit_msg>BUG: Fix import of CapacityError in tests<commit_after>extern crate arrayvec;
#[macro_use] extern crate matches;

use arrayvec::ArrayVec;
use arrayvec::ArrayString;
use std::mem;
use arrayvec::CapacityError;

use std::collections::HashMap;

#[test]
fn test_simple() {
    use std::ops::Add;

    let mut vec: ArrayVec<[Vec<i32>; 3]> = ArrayVec::new();

    vec.push(vec![1, 2, 3, 4]);
    vec.push(vec![10]);
    vec.push(vec![-1, 13, -2]);

    for elt in &vec {
        assert_eq!(elt.iter().fold(0, Add::add), 10);
    }

    let sum_len = vec.into_iter().map(|x| x.len()).fold(0, Add::add);
    assert_eq!(sum_len, 8);
}

#[test]
fn test_u16_index() {
    const N: usize = 4096;
    let mut vec: ArrayVec<[_; N]> = ArrayVec::new();
    for _ in 0..N {
        assert!(vec.try_push(1u8).is_ok());
    }
    assert!(vec.try_push(0).is_err());
    assert_eq!(vec.len(), N);
}

#[test]
fn test_iter() {
    let mut iter = ArrayVec::from([1, 2, 3]).into_iter();
    assert_eq!(iter.size_hint(), (3, Some(3)));
    assert_eq!(iter.next_back(), Some(3));
    assert_eq!(iter.next(), Some(1));
    assert_eq!(iter.next_back(), Some(2));
    assert_eq!(iter.size_hint(), (0, Some(0)));
    assert_eq!(iter.next_back(), None);
}

#[test]
fn test_drop() {
    use std::cell::Cell;

    let flag = &Cell::new(0);

    struct Bump<'a>(&'a Cell<i32>);

    impl<'a> Drop for Bump<'a> {
        fn drop(&mut self) {
            let n = self.0.get();
            self.0.set(n + 1);
        }
    }

    {
        let mut array = ArrayVec::<[Bump; 128]>::new();
        array.push(Bump(flag));
        array.push(Bump(flag));
    }
    assert_eq!(flag.get(), 2);

    // test something with the nullable pointer optimization
    flag.set(0);

    {
        let mut array = ArrayVec::<[_; 3]>::new();
        array.push(vec![Bump(flag)]);
        array.push(vec![Bump(flag), Bump(flag)]);
        array.push(vec![]);
        let push4 = array.try_push(vec![Bump(flag)]);
        assert_eq!(flag.get(), 0);
        drop(push4);
        assert_eq!(flag.get(), 1);
        drop(array.pop());
        assert_eq!(flag.get(), 1);
        drop(array.pop());
        assert_eq!(flag.get(), 3);
    }

    assert_eq!(flag.get(), 4);

    // test into_inner
    flag.set(0);
    {
        let mut array = ArrayVec::<[_; 3]>::new();
        array.push(Bump(flag));
        array.push(Bump(flag));
        array.push(Bump(flag));
        let inner = array.into_inner();
        assert!(inner.is_ok());
        assert_eq!(flag.get(), 0);
        drop(inner);
        assert_eq!(flag.get(), 3);
    }

}

#[test]
fn test_extend() {
    let mut range = 0..10;

    let mut array: ArrayVec<[_; 5]> = range.by_ref().collect();
    assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
    assert_eq!(range.next(), Some(5));

    array.extend(range.by_ref());
    assert_eq!(range.next(), Some(6));

    let mut array: ArrayVec<[_; 10]> = (0..3).collect();
    assert_eq!(&array[..], &[0, 1, 2]);
    array.extend(3..5);
    assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
}

#[test]
fn test_is_send_sync() {
    let data = ArrayVec::<[Vec<i32>; 5]>::new();
    &data as &Send;
    &data as &Sync;
}

#[test]
fn test_compact_size() {
    // Future rust will kill these drop flags!
    // 4 elements size + 1 len + 1 enum tag + [1 drop flag]
    type ByteArray = ArrayVec<[u8; 4]>;
    println!("{}", mem::size_of::<ByteArray>());
    assert!(mem::size_of::<ByteArray>() <= 8);

    // 12 element size + 1 enum tag + 3 padding + 1 len + 1 drop flag + 2 padding
    type QuadArray = ArrayVec<[u32; 3]>;
    println!("{}", mem::size_of::<QuadArray>());
    assert!(mem::size_of::<QuadArray>() <= 24);
}

#[test]
fn test_drain() {
    let mut v = ArrayVec::from([0; 8]);
    v.pop();
    v.drain(0..7);
    assert_eq!(&v[..], &[]);

    v.extend(0..);
    v.drain(1..4);
    assert_eq!(&v[..], &[0, 4, 5, 6, 7]);
    let u: ArrayVec<[_; 3]> = v.drain(1..4).rev().collect();
    assert_eq!(&u[..], &[6, 5, 4]);
    assert_eq!(&v[..], &[0, 7]);
    v.drain(..);
    assert_eq!(&v[..], &[]);
}

#[test]
fn test_retain() {
    let mut v = ArrayVec::from([0; 8]);
    for (i, elt) in v.iter_mut().enumerate() {
        *elt = i;
    }
    v.retain(|_| true);
    assert_eq!(&v[..], &[0, 1, 2, 3, 4, 5, 6, 7]);
    v.retain(|elt| {
        *elt /= 2;
        *elt % 2 == 0
    });
    assert_eq!(&v[..], &[0, 0, 2, 2]);
    v.retain(|_| false);
    assert_eq!(&v[..], &[]);
}

#[test]
#[should_panic]
fn test_drain_oob() {
    let mut v = ArrayVec::from([0; 8]);
    v.pop();
    v.drain(0..8);
}

#[test]
#[should_panic]
fn test_drop_panic() {
    struct DropPanic;

    impl Drop for DropPanic {
        fn drop(&mut self) {
            panic!("drop");
        }
    }

    let mut array = ArrayVec::<[DropPanic; 1]>::new();
    array.push(DropPanic);
}

#[test]
#[should_panic]
fn test_drop_panic_into_iter() {
    struct DropPanic;

    impl Drop for DropPanic {
        fn drop(&mut self) {
            panic!("drop");
        }
    }

    let mut array = ArrayVec::<[DropPanic; 1]>::new();
    array.push(DropPanic);
    array.into_iter();
}

#[test]
fn test_insert() {
    let mut v = ArrayVec::from([]);
    assert_matches!(v.try_push(1), Err(_));

    let mut v = ArrayVec::<[_; 3]>::new();
    v.insert(0, 0);
    v.insert(1, 1);
    //let ret1 = v.try_insert(3, 3);
    //assert_matches!(ret1, Err(InsertError::OutOfBounds(_)));
    assert_eq!(&v[..], &[0, 1]);
    v.insert(2, 2);
    assert_eq!(&v[..], &[0, 1, 2]);

    let ret2 = v.try_insert(1, 9);
    assert_eq!(&v[..], &[0, 1, 2]);
    assert_matches!(ret2, Err(_));

    let mut v = ArrayVec::from([2]);
    assert_matches!(v.try_insert(0, 1), Err(CapacityError { .. }));
    assert_matches!(v.try_insert(1, 1), Err(CapacityError { .. }));
    //assert_matches!(v.try_insert(2, 1), Err(CapacityError { .. }));
}

#[test]
fn test_into_inner_1() {
    let mut v = ArrayVec::from([1, 2]);
    v.pop();
    let u = v.clone();
    assert_eq!(v.into_inner(), Err(u));
}

#[test]
fn test_into_inner_2() {
    let mut v = ArrayVec::<[String; 4]>::new();
    v.push("a".into());
    v.push("b".into());
    v.push("c".into());
    v.push("d".into());
    assert_eq!(v.into_inner().unwrap(), ["a", "b", "c", "d"]);
}

#[test]
fn test_into_inner_3_() {
    let mut v = ArrayVec::<[i32; 4]>::new();
    v.extend(1..);
    assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]);
}

#[test]
fn test_write() {
    use std::io::Write;
    let mut v = ArrayVec::<[_; 8]>::new();
    write!(&mut v, "\x01\x02\x03").unwrap();
    assert_eq!(&v[..], &[1, 2, 3]);
    let r = v.write(&[9; 16]).unwrap();
    assert_eq!(r, 5);
    assert_eq!(&v[..], &[1, 2, 3, 9, 9, 9, 9, 9]);
}

#[test]
fn array_clone_from() {
    let mut v = ArrayVec::<[_; 4]>::new();
    v.push(vec![1, 2]);
    v.push(vec![3, 4, 5]);
    v.push(vec![6]);
    let reference = v.to_vec();
    let mut u = ArrayVec::<[_; 4]>::new();
    u.clone_from(&v);
    assert_eq!(&u, &reference[..]);

    let mut t = ArrayVec::<[_; 4]>::new();
    t.push(vec![97]);
    t.push(vec![]);
    t.push(vec![5, 6, 2]);
    t.push(vec![2]);
    t.clone_from(&v);
    assert_eq!(&t, &reference[..]);
    t.clear();
    t.clone_from(&v);
    assert_eq!(&t, &reference[..]);
}

#[test]
fn test_string() {
    use std::error::Error;

    let text = "hello world";
    let mut s = ArrayString::<[_; 16]>::new();
    s.try_push_str(text).unwrap();
    assert_eq!(&s, text);
    assert_eq!(text, &s);

    // Make sure Hash / Eq / Borrow match up so we can use HashMap
    let mut map = HashMap::new();
    map.insert(s, 1);
    assert_eq!(map[text], 1);

    let mut t = ArrayString::<[_; 2]>::new();
    assert!(t.try_push_str(text).is_err());
    assert_eq!(&t, "");

    t.push_str("ab");
    // DerefMut
    let tmut: &mut str = &mut t;
    assert_eq!(tmut, "ab");

    // Test Error trait / try
    let t = || -> Result<(), Box<Error>> {
        let mut t = ArrayString::<[_; 2]>::new();
        try!(t.try_push_str(text));
        Ok(())
    }();
    assert!(t.is_err());
}

#[test]
fn test_string_from() {
    let text = "hello world";
	// Test `from` constructor
    let u = ArrayString::<[_; 11]>::from(text).unwrap();
    assert_eq!(&u, text);
    assert_eq!(u.len(), text.len());
}

#[test]
fn test_string_from_bytes() {
    let text = "hello world";
    let u = ArrayString::from_byte_string(b"hello world").unwrap();
    assert_eq!(&u, text);
    assert_eq!(u.len(), text.len());
}

#[test]
fn test_string_clone() {
    let text = "hi";
    let mut s = ArrayString::<[_; 4]>::new();
    s.push_str("abcd");
    let t = ArrayString::<[_; 4]>::from(text).unwrap();
    s.clone_from(&t);
    assert_eq!(&t, &s);
}

#[test]
fn test_string_push() {
    let text = "abcαβγ";
    let mut s = ArrayString::<[_; 8]>::new();
    for c in text.chars() {
        if let Err(_) = s.try_push(c) {
            break;
        }
    }
    assert_eq!("abcαβ", &s[..]);
    s.push('x');
    assert_eq!("abcαβx", &s[..]);
    assert!(s.try_push('x').is_err());
}

#[test]
fn test_insert_at_length() {
    let mut v = ArrayVec::<[_; 8]>::new();
    let result1 = v.try_insert(0, "a");
    let result2 = v.try_insert(1, "b");
    assert!(result1.is_ok() && result2.is_ok());
    assert_eq!(&v[..], &["a", "b"]);
}

#[should_panic]
#[test]
fn test_insert_out_of_bounds() {
    let mut v = ArrayVec::<[_; 8]>::new();
    let _ = v.try_insert(1, "test");
}

/*
 * insert that pushes out the last
    let mut u = ArrayVec::from([1, 2, 3, 4]);
    let ret = u.try_insert(3, 99);
    assert_eq!(&u[..], &[1, 2, 3, 99]);
    assert_matches!(ret, Err(_));
    let ret = u.try_insert(4, 77);
    assert_eq!(&u[..], &[1, 2, 3, 99]);
    assert_matches!(ret, Err(_));
*/

#[test]
fn test_drop_in_insert() {
    use std::cell::Cell;

    let flag = &Cell::new(0);

    struct Bump<'a>(&'a Cell<i32>);

    impl<'a> Drop for Bump<'a> {
        fn drop(&mut self) {
            let n = self.0.get();
            self.0.set(n + 1);
        }
    }

    flag.set(0);

    {
        let mut array = ArrayVec::<[_; 2]>::new();
        array.push(Bump(flag));
        array.insert(0, Bump(flag));
        assert_eq!(flag.get(), 0);
        let ret = array.try_insert(1, Bump(flag));
        assert_eq!(flag.get(), 0);
        assert_matches!(ret, Err(_));
        drop(ret);
        assert_eq!(flag.get(), 1);
    }
    assert_eq!(flag.get(), 3);
}
<|endoftext|>


<commit_before>#![cfg_attr(test, allow(dead_code))]

#![feature(collections)]

extern crate document;
extern crate xpath;
extern crate getopts;

use std::cmp::min;
use std::borrow::ToOwned;
use std::env;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self,Read};

use document::parser::Parser;

use xpath::{EvaluationContext,Factory,Expression,Value};

use getopts::Options;

fn print_usage(program: &str, opts: &Options) {
    let brief = format!("Usage: {} [options] FILE...", program);
    print!("{}", opts.usage(&brief));
}

fn pretty_error(xml: &str, position: usize) -> &str {
    let s = &xml[position..];
    let l = s.chars().count();
    s.slice_chars(0, min(l, 15))
}

fn build_xpath(xpath_str: &str) -> Box<Expression> {
    let factory = Factory::new();

    match factory.build(xpath_str) {
        Err(x) => panic!("Unable to compile XPath: {:?}", x),
        Ok(None) => panic!("Unable to compile XPath"),
        Ok(Some(x)) => x,
    }
}

fn load_xml<R>(input: R) -> document::Package
    where R: Read
{
    let mut input = input;
    let mut data = String::new();

    if let Err(x) = input.read_to_string(&mut data) {
        panic!("Can't read: {}", x);
    }

    let p = Parser::new();

    match p.parse(&data) {
        Ok(d) => d,
        Err((point, _)) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    }
}

fn argument_name_value(s: &str, delim: char) -> Option<(&str, &str)> {
    let parts: Vec<_> = s.splitn(2, delim).collect();
    if parts.len() < 2 {
        None
    } else {
        Some((parts[0], parts[1]))
    }
}

fn build_functions() -> xpath::Functions {
    let mut functions = HashMap::new();
    xpath::function::register_core_functions(&mut functions);
    functions
}

fn build_variables<'a>(arguments: &getopts::Matches) -> xpath::Variables<'a> {
    let mut vars = HashMap::new();

    for boolean in arguments.opt_strs("boolean") {
        match argument_name_value(&boolean, '=') {
            Some((name, "true")) => { vars.insert(name.to_owned(), Value::Boolean(true)); },
            Some((name, "false")) => { vars.insert(name.to_owned(), Value::Boolean(false)); },
            Some((_, val)) => panic!("Unknown boolean value '{}'", val),
            None => panic!("boolean argument '{}' is malformed", boolean),
        }
    }

    for number in arguments.opt_strs("number") {
        match argument_name_value(&number, '=') {
            Some((name, val)) => {
                match val.parse() {
                    Ok(val) => { vars.insert(name.to_owned(), Value::Number(val)); },
                    Err(e) => panic!("Unknown numeric value '{}': {}", val, e),
                }
            },
            None => panic!("number argument '{}' is malformed", number),
        }
    }

    for string in arguments.opt_strs("string") {
        match argument_name_value(&string, '=') {
            Some((name, val)) => { vars.insert(name.to_owned(), Value::String(val.to_owned())); },
            None => panic!("string argument '{}' is malformed", string),
        }
    }

    vars
}

fn build_namespaces(arguments: &getopts::Matches) -> xpath::Namespaces {
    let mut namespaces = HashMap::new();

    for ns_defn in arguments.opt_strs("namespace") {
        match argument_name_value(&ns_defn, ':') {
            Some((prefix, uri)) => { namespaces.insert(prefix.to_owned(), uri.to_owned()); },
            None => panic!("Namespace definition '{}' is malformed", ns_defn),
        }
    }

    namespaces
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let program_name = &args[0];

    let mut opts = Options::new();

    opts.reqopt("", "xpath", "The XPath to execute", "XPATH");
    opts.optmulti("", "namespace", "set namespace prefix", "PREFIX:URI");
    opts.optmulti("", "string", "set string variable", "NAME=VALUE");
    opts.optmulti("", "number", "set number variable", "NAME=VALUE");
    opts.optmulti("", "boolean", "set boolean variable", "NAME=VALUE");

    let arguments = match opts.parse(args.tail()) {
        Ok(x) => x,
        Err(x) => {
            println!("{}", x);
            print_usage(program_name, &opts);
            return;
        },
    };

    let xpath_str = arguments.opt_str("xpath").unwrap();
    let xpath = build_xpath(&xpath_str);

    for filename in &arguments.free {
        let package = if *filename == "-" {
            load_xml(io::stdin())
        } else {
            let file = File::open(filename).unwrap();
            load_xml(file)
        };

        let doc = package.as_document();

        let functions = build_functions();
        let variables = build_variables(&arguments);
        let namespaces = build_namespaces(&arguments);

        let context = EvaluationContext::new(
            doc.root(),
            &functions,
            &variables,
            &namespaces,
        );

        let res = xpath.evaluate(&context);

        println!("{:?}", res);
    }
}
<commit_msg>Remove use of unstable slice_char<commit_after>#![cfg_attr(test, allow(dead_code))]

extern crate document;
extern crate xpath;
extern crate getopts;

use std::borrow::ToOwned;
use std::env;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self,Read};

use document::parser::Parser;

use xpath::{EvaluationContext,Factory,Expression,Value};

use getopts::Options;

fn print_usage(program: &str, opts: &Options) {
    let brief = format!("Usage: {} [options] FILE...", program);
    print!("{}", opts.usage(&brief));
}

fn pretty_error(xml: &str, position: usize) -> String {
    let s = &xml[position..];
    s.chars().take(15).collect()
}

fn build_xpath(xpath_str: &str) -> Box<Expression> {
    let factory = Factory::new();

    match factory.build(xpath_str) {
        Err(x) => panic!("Unable to compile XPath: {:?}", x),
        Ok(None) => panic!("Unable to compile XPath"),
        Ok(Some(x)) => x,
    }
}

fn load_xml<R>(input: R) -> document::Package
    where R: Read
{
    let mut input = input;
    let mut data = String::new();

    if let Err(x) = input.read_to_string(&mut data) {
        panic!("Can't read: {}", x);
    }

    let p = Parser::new();

    match p.parse(&data) {
        Ok(d) => d,
        Err((point, _)) => panic!("Unable to parse: {}", pretty_error(&data, point)),
    }
}

fn argument_name_value(s: &str, delim: char) -> Option<(&str, &str)> {
    let parts: Vec<_> = s.splitn(2, delim).collect();
    if parts.len() < 2 {
        None
    } else {
        Some((parts[0], parts[1]))
    }
}

fn build_functions() -> xpath::Functions {
    let mut functions = HashMap::new();
    xpath::function::register_core_functions(&mut functions);
    functions
}

fn build_variables<'a>(arguments: &getopts::Matches) -> xpath::Variables<'a> {
    let mut vars = HashMap::new();

    for boolean in arguments.opt_strs("boolean") {
        match argument_name_value(&boolean, '=') {
            Some((name, "true")) => { vars.insert(name.to_owned(), Value::Boolean(true)); },
            Some((name, "false")) => { vars.insert(name.to_owned(), Value::Boolean(false)); },
            Some((_, val)) => panic!("Unknown boolean value '{}'", val),
            None => panic!("boolean argument '{}' is malformed", boolean),
        }
    }

    for number in arguments.opt_strs("number") {
        match argument_name_value(&number, '=') {
            Some((name, val)) => {
                match val.parse() {
                    Ok(val) => { vars.insert(name.to_owned(), Value::Number(val)); },
                    Err(e) => panic!("Unknown numeric value '{}': {}", val, e),
                }
            },
            None => panic!("number argument '{}' is malformed", number),
        }
    }

    for string in arguments.opt_strs("string") {
        match argument_name_value(&string, '=') {
            Some((name, val)) => { vars.insert(name.to_owned(), Value::String(val.to_owned())); },
            None => panic!("string argument '{}' is malformed", string),
        }
    }

    vars
}

fn build_namespaces(arguments: &getopts::Matches) -> xpath::Namespaces {
    let mut namespaces = HashMap::new();

    for ns_defn in arguments.opt_strs("namespace") {
        match argument_name_value(&ns_defn, ':') {
            Some((prefix, uri)) => { namespaces.insert(prefix.to_owned(), uri.to_owned()); },
            None => panic!("Namespace definition '{}' is malformed", ns_defn),
        }
    }

    namespaces
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let program_name = &args[0];

    let mut opts = Options::new();

    opts.reqopt("", "xpath", "The XPath to execute", "XPATH");
    opts.optmulti("", "namespace", "set namespace prefix", "PREFIX:URI");
    opts.optmulti("", "string", "set string variable", "NAME=VALUE");
    opts.optmulti("", "number", "set number variable", "NAME=VALUE");
    opts.optmulti("", "boolean", "set boolean variable", "NAME=VALUE");

    let arguments = match opts.parse(&args[1..]) {
        Ok(x) => x,
        Err(x) => {
            println!("{}", x);
            print_usage(program_name, &opts);
            return;
        },
    };

    let xpath_str = arguments.opt_str("xpath").unwrap();
    let xpath = build_xpath(&xpath_str);

    for filename in &arguments.free {
        let package = if *filename == "-" {
            load_xml(io::stdin())
        } else {
            let file = File::open(filename).unwrap();
            load_xml(file)
        };

        let doc = package.as_document();

        let functions = build_functions();
        let variables = build_variables(&arguments);
        let namespaces = build_namespaces(&arguments);

        let context = EvaluationContext::new(
            doc.root(),
            &functions,
            &variables,
            &namespaces,
        );

        let res = xpath.evaluate(&context);

        println!("{:?}", res);
    }
}
<|endoftext|>