<commit_before>use command::Parameters;
use error::{ErrorStatus, WebDriverError, WebDriverResult};
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use std::net::Ipv6Addr;
use url::Url;

pub type Capabilities = BTreeMap<String, Json>;

/// Trait for objects that can be used to inspect browser capabilities
///
/// The main methods in this trait are called with a Capabilites object
/// resulting from a full set of potential capabilites for the session.
/// Given those Capabilities they return a property of the browser instance
/// that would be initiated. In many cases this will be independent of the
/// input, but in the case of e.g. browser version, it might depend on a
/// path to the binary provided as a capability.
pub trait BrowserCapabilities {
    /// Set up the Capabilites object
    ///
    /// Typically used to create any internal caches
    fn init(&mut self, &Capabilities);

    /// Name of the browser
    fn browser_name(&mut self, &Capabilities) -> WebDriverResult<Option<String>>;
    /// Version number of the browser
    fn browser_version(&mut self, &Capabilities) -> WebDriverResult<Option<String>>;
    /// Compare actual browser version to that provided in a version specifier
    ///
    /// Parameters are the actual browser version and the comparison string,
    /// respectively. The format of the comparison string is implementation-defined.
    fn compare_browser_version(&mut self, version: &str, comparison: &str) -> WebDriverResult<bool>;
    /// Name of the platform/OS
    fn platform_name(&mut self, &Capabilities) -> WebDriverResult<Option<String>>;
    /// Whether insecure certificates are supported
    fn accept_insecure_certs(&mut self, &Capabilities) -> WebDriverResult<bool>;

    fn accept_proxy(&mut self, proxy_settings: &BTreeMap<String, Json>, &Capabilities) -> WebDriverResult<bool>;

    /// Type check custom properties
    ///
    /// Check that custom properties containing ":" have the correct data types.
    /// Properties that are unrecognised must be ignored i.e. return without
    /// error.
    fn validate_custom(&self, name: &str, value: &Json) -> WebDriverResult<()>;
    /// Check if custom properties are accepted capabilites
    ///
    /// Check that custom properties containing ":" are compatible with
    /// the implementation.
    fn accept_custom(&mut self, name: &str, value: &Json, merged: &Capabilities) -> WebDriverResult<bool>;
}

/// Trait to abstract over various version of the new session parameters
///
/// This trait is expected to be implemented on objects holding the capabilities
/// from a new session command.
pub trait CapabilitiesMatching {
    /// Match the BrowserCapabilities against some candidate capabilites
    ///
    /// Takes a BrowserCapabilites object and returns a set of capabilites that
    /// are valid for that browser, if any, or None if there are no matching
    /// capabilities.
    fn match_browser<T: BrowserCapabilities>(&self, browser_capabilities: &mut T)
                                             -> WebDriverResult<Option<Capabilities>>;
}

#[derive(Debug, PartialEq)]
pub struct SpecNewSessionParameters {
    pub alwaysMatch: Capabilities,
    pub firstMatch: Vec<Capabilities>,
}

impl SpecNewSessionParameters {
    fn validate<T: BrowserCapabilities>(&self,
                                        mut capabilities: Capabilities,
                                        browser_capabilities: &T) -> WebDriverResult<Capabilities> {
        // Filter out entries with the value `null`
        let null_entries = capabilities
            .iter()
            .filter(|&(_, ref value)| **value == Json::Null)
            .map(|(k, _)| k.clone())
            .collect::<Vec<String>>();
        for key in null_entries {
            capabilities.remove(&key);
        }

        for (key, value) in capabilities.iter() {
            match &**key {
                "acceptInsecureCerts" => if !value.is_boolean() {
                        return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                       "acceptInsecureCerts was not a boolean"))
                    },
                x @ "browserName" |
                x @ "browserVersion" |
                x @ "platformName" => if !value.is_string() {
                        return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                       format!("{} was not a boolean", x)))
                    },
                "pageLoadStrategy" => {
                    try!(SpecNewSessionParameters::validate_page_load_strategy(value))
                }
                "proxy" => {
                    try!(SpecNewSessionParameters::validate_proxy(value))
                },
                "timeouts" => {
                    try!(SpecNewSessionParameters::validate_timeouts(value))
                },
                "unhandledPromptBehavior" => {
                    try!(SpecNewSessionParameters::validate_unhandled_prompt_behaviour(value))
                }
                x => {
                    if !x.contains(":") {
                        return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                       format!("{} was not a the name of a known capability or a valid extension capability", x)))
                    } else {
                        try!(browser_capabilities.validate_custom(x, value));
                    }
                }
            }
        }
        Ok(capabilities)
    }

    fn validate_page_load_strategy(value: &Json) -> WebDriverResult<()> {
        match value {
            &Json::String(ref x) => {
                match &**x {
                    "normal" |
                    "eager" |
                    "none" => {},
                    x => {
                        return Err(WebDriverError::new(
                            ErrorStatus::InvalidArgument,
                            format!("\"{}\" not a valid page load strategy", x)))
                    }
                }
            }
            _ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                "pageLoadStrategy was not a string"))
        }
        Ok(())
    }

    fn validate_proxy(proxy_value: &Json) -> WebDriverResult<()> {
        let obj = try_opt!(proxy_value.as_object(),
                           ErrorStatus::InvalidArgument,
                           "proxy was not an object");
        for (key, value) in obj.iter() {
            match &**key {
                "proxyType" => match value.as_string() {
                    Some("pac") |
                    Some("noproxy") |
                    Some("autodetect") |
                    Some("system") |
                    Some("manual") => {},
                    Some(x) => return Err(WebDriverError::new(
                        ErrorStatus::InvalidArgument,
                        format!("{} was not a valid proxyType value", x))),
                    None => return Err(WebDriverError::new(
                        ErrorStatus::InvalidArgument,
                        "proxyType value was not a string")),<commit_msg>capabilities: use proxyType "direct" instead of "noproxy" (#107)<commit_after>use command::Parameters;
use error::{ErrorStatus, WebDriverError, WebDriverResult};
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
use std::net::Ipv6Addr;
use url::Url;

pub type Capabilities = BTreeMap<String, Json>;

/// Trait for objects that can be used to inspect browser capabilities
///
/// The main methods in this trait are called with a Capabilites object
/// resulting from a full set of potential capabilites for the session.
/// Given those Capabilities they return a property of the browser instance
/// that would be initiated. In many cases this will be independent of the
/// input, but in the case of e.g. browser version, it might depend on a
/// path to the binary provided as a capability.
pub trait BrowserCapabilities {
    /// Set up the Capabilites object
    ///
    /// Typically used to create any internal caches
    fn init(&mut self, &Capabilities);

    /// Name of the browser
    fn browser_name(&mut self, &Capabilities) -> WebDriverResult<Option<String>>;
    /// Version number of the browser
    fn browser_version(&mut self, &Capabilities) -> WebDriverResult<Option<String>>;
    /// Compare actual browser version to that provided in a version specifier
    ///
    /// Parameters are the actual browser version and the comparison string,
    /// respectively. The format of the comparison string is implementation-defined.
    fn compare_browser_version(&mut self, version: &str, comparison: &str) -> WebDriverResult<bool>;
    /// Name of the platform/OS
    fn platform_name(&mut self, &Capabilities) -> WebDriverResult<Option<String>>;
    /// Whether insecure certificates are supported
    fn accept_insecure_certs(&mut self, &Capabilities) -> WebDriverResult<bool>;

    fn accept_proxy(&mut self, proxy_settings: &BTreeMap<String, Json>, &Capabilities) -> WebDriverResult<bool>;

    /// Type check custom properties
    ///
    /// Check that custom properties containing ":" have the correct data types.
    /// Properties that are unrecognised must be ignored i.e. return without
    /// error.
    fn validate_custom(&self, name: &str, value: &Json) -> WebDriverResult<()>;
    /// Check if custom properties are accepted capabilites
    ///
    /// Check that custom properties containing ":" are compatible with
    /// the implementation.
    fn accept_custom(&mut self, name: &str, value: &Json, merged: &Capabilities) -> WebDriverResult<bool>;
}

/// Trait to abstract over various version of the new session parameters
///
/// This trait is expected to be implemented on objects holding the capabilities
/// from a new session command.
pub trait CapabilitiesMatching {
    /// Match the BrowserCapabilities against some candidate capabilites
    ///
    /// Takes a BrowserCapabilites object and returns a set of capabilites that
    /// are valid for that browser, if any, or None if there are no matching
    /// capabilities.
    fn match_browser<T: BrowserCapabilities>(&self, browser_capabilities: &mut T)
                                             -> WebDriverResult<Option<Capabilities>>;
}

#[derive(Debug, PartialEq)]
pub struct SpecNewSessionParameters {
    pub alwaysMatch: Capabilities,
    pub firstMatch: Vec<Capabilities>,
}

impl SpecNewSessionParameters {
    fn validate<T: BrowserCapabilities>(&self,
                                        mut capabilities: Capabilities,
                                        browser_capabilities: &T) -> WebDriverResult<Capabilities> {
        // Filter out entries with the value `null`
        let null_entries = capabilities
            .iter()
            .filter(|&(_, ref value)| **value == Json::Null)
            .map(|(k, _)| k.clone())
            .collect::<Vec<String>>();
        for key in null_entries {
            capabilities.remove(&key);
        }

        for (key, value) in capabilities.iter() {
            match &**key {
                "acceptInsecureCerts" => if !value.is_boolean() {
                        return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                       "acceptInsecureCerts was not a boolean"))
                    },
                x @ "browserName" |
                x @ "browserVersion" |
                x @ "platformName" => if !value.is_string() {
                        return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                       format!("{} was not a boolean", x)))
                    },
                "pageLoadStrategy" => {
                    try!(SpecNewSessionParameters::validate_page_load_strategy(value))
                }
                "proxy" => {
                    try!(SpecNewSessionParameters::validate_proxy(value))
                },
                "timeouts" => {
                    try!(SpecNewSessionParameters::validate_timeouts(value))
                },
                "unhandledPromptBehavior" => {
                    try!(SpecNewSessionParameters::validate_unhandled_prompt_behaviour(value))
                }
                x => {
                    if !x.contains(":") {
                        return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                       format!("{} was not a the name of a known capability or a valid extension capability", x)))
                    } else {
                        try!(browser_capabilities.validate_custom(x, value));
                    }
                }
            }
        }
        Ok(capabilities)
    }

    fn validate_page_load_strategy(value: &Json) -> WebDriverResult<()> {
        match value {
            &Json::String(ref x) => {
                match &**x {
                    "normal" |
                    "eager" |
                    "none" => {},
                    x => {
                        return Err(WebDriverError::new(
                            ErrorStatus::InvalidArgument,
                            format!("\"{}\" not a valid page load strategy", x)))
                    }
                }
            }
            _ => return Err(WebDriverError::new(ErrorStatus::InvalidArgument,
                                                "pageLoadStrategy was not a string"))
        }
        Ok(())
    }

    fn validate_proxy(proxy_value: &Json) -> WebDriverResult<()> {
        let obj = try_opt!(proxy_value.as_object(),
                           ErrorStatus::InvalidArgument,
                           "proxy was not an object");
        for (key, value) in obj.iter() {
            match &**key {
                "proxyType" => match value.as_string() {
                    Some("pac") |
                    Some("direct") |
                    Some("autodetect") |
                    Some("system") |
                    Some("manual") => {},
                    Some(x) => return Err(WebDriverError::new(
                        ErrorStatus::InvalidArgument,
                        format!("{} was not a valid proxyType value", x))),
                    None => return Err(WebDriverError::new(
                        ErrorStatus::InvalidArgument,
                        "proxyType value was not a string")),
{'fraction_non_alphanumeric': 0.10463192721257238, 'fraction_numerical': 0.00034463744141163496, 'mean_word_length': 1.807469040247678, 'pattern_counts': {'":': 6, '<': 49, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 26, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2182488', 'n_tokens_mistral': 3496, 'n_tokens_neox': 3373, 'n_words': 1062}