<commit_before>use nom::{multispace, space};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, unsigned_number, statement_terminator, table_list};
use parser::ConditionExpression;

use condition::*;

#[derive(Clone, Debug, PartialEq)]
pub struct GroupByClause {
    columns: Vec<String>,
    having: String, // XXX(malte): should this be an arbitrary expr?
}

#[derive(Clone, Debug, PartialEq)]
pub struct LimitClause {
    limit: u64,
    offset: u64,
}

#[derive(Clone, Debug, PartialEq)]
pub enum OrderType {
    OrderAscending,
    OrderDescending,
}

#[derive(Clone, Debug, PartialEq)]
pub struct OrderClause {
    cols: Vec<String>, // TODO(malte): can this be an arbitrary expr?
    order: OrderType,
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct SelectStatement {
    pub tables: Vec<String>,
    pub distinct: bool,
    pub fields: Vec<String>,
    pub where_clause: Option<ConditionExpression>,
    pub group_by: Option<GroupByClause>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse LIMIT clause
named!(limit_clause<&[u8], LimitClause>,
    chain!(
        space ~
        caseless_tag!("limit") ~
        space ~
        limit_val: unsigned_number ~
        space? ~
        offset_val: opt!(chain!(
                caseless_tag!("offset") ~
                space ~
                val: unsigned_number,
                || { val }
            )
        ),
    || {
        LimitClause {
            limit: limit_val,
            offset: match offset_val {
                None => 0,
                Some(v) => v,
            },
        }
    })
);

named!(order_clause<&[u8], OrderClause>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("order by") ~
        multispace ~
        order_expr: field_list ~
        ordering: opt!(
            alt_complete!(
                  map!(caseless_tag!("desc"), |_| OrderType::OrderDescending)
                | map!(caseless_tag!("asc"), |_| OrderType::OrderAscending)
            )
        ),
    || {
        OrderClause {
            cols: order_expr.iter().map(|e| String::from(*e)).collect(),
            order: match ordering {
                None => OrderType::OrderAscending,
                Some(ref o) => o.clone(),
            },
        }
    })
));

/// Parse WHERE clause of a selection
named!(where_clause<&[u8], ConditionExpression>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("where") ~
        multispace ~
        cond: condition_expr,
        || { cond }
    )
));

/// Parse rule for a SQL selection query.
/// TODO(malte): support nested queries as selection targets
named!(pub selection<&[u8], SelectStatement>,
    chain!(
        caseless_tag!("select") ~
        space ~
        distinct: opt!(caseless_tag!("distinct")) ~
        space? ~
        fields: field_list ~
        delimited!(opt!(multispace), caseless_tag!("from"), opt!(multispace)) ~
        tables: table_list ~
        cond: opt!(where_clause) ~
        order: opt!(order_clause) ~
        limit: opt!(limit_clause) ~
        statement_terminator,
        || {
            SelectStatement {
                tables: tables.iter().map(|t| String::from(*t)).collect(),
                distinct: distinct.is_some(),
                fields: fields.iter().map(|s| String::from(*s)).collect(),
                where_clause: cond,
                group_by: None,
                order: order,
                limit: limit,
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use common::Operator;
    use parser::{ConditionBase, ConditionExpression, ConditionTree};

    #[test]
    fn simple_select() {
        let qstring = "SELECT id, name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn select_all() {
        let qstring = "SELECT * FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn spaces_optional() {
        let qstring = "SELECT id,name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn case_sensitivity() {
        let qstring_lc = "select id, name from users;";
        let qstring_uc = "SELECT id, name FROM users;";

        assert_eq!(selection(qstring_lc.as_bytes()).unwrap(),
                   selection(qstring_uc.as_bytes()).unwrap());
    }

    #[test]
    fn termination() {
        let qstring_sem = "select id, name from users;";
        let qstring_linebreak = "select id, name from users\n";

        assert_eq!(selection(qstring_sem.as_bytes()).unwrap(),
                   selection(qstring_linebreak.as_bytes()).unwrap());
    }

    #[test]
    fn where_clause() {
        let qstring = "select * from ContactInfo where email=?;";

        let res = selection(qstring.as_bytes());

        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("email"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("ContactInfo")],
                       fields: vec!["ALL".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn limit_clause() {
        let qstring1 = "select * from users limit 10\n";
        let qstring2 = "select * from users limit 10 offset 10\n";

        let expected_lim1 = LimitClause {
            limit: 10,
            offset: 0,
        };
        let expected_lim2 = LimitClause {
            limit: 10,
            offset: 10,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        assert_eq!(res1.unwrap().1.limit, Some(expected_lim1));
        assert_eq!(res2.unwrap().1.limit, Some(expected_lim2));
    }

    #[test]
    fn order_clause() {
        let qstring1 = "select * from users order by name desc\n";
        let qstring2 = "select * from users order by name, age desc\n";
        let qstring3 = "select * from users order by name\n";

        let expected_ord1 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord2 = OrderClause {
            cols: vec!["name".into(), "age".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord3 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderAscending,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        let res3 = selection(qstring3.as_bytes());
        assert_eq!(res1.unwrap().1.order, Some(expected_ord1));
        assert_eq!(res2.unwrap().1.order, Some(expected_ord2));
        assert_eq!(res3.unwrap().1.order, Some(expected_ord3));
    }

    #[test]
    fn table_alias() {
        let qstring1 = "select * from PaperTag as t;";
        // let qstring2 = "select * from PaperTag t;";

        let res1 = selection(qstring1.as_bytes());
        assert_eq!(res1.clone().unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperTag")],
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
        // let res2 = selection(qstring2.as_bytes());
        // assert_eq!(res1.unwrap().1, res2.unwrap().1);
    }

    #[test]
    fn distinct() {
        let qstring = "select distinct tag from PaperTag where paperId=?;";

        let res = selection(qstring.as_bytes());
        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperTag")],
                       distinct: true,
                       fields: vec!["tag".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn simple_condition_expr() {
        let qstring = "select infoJson from PaperStorage where paperId=? and paperStorageId=?;";

        let res = selection(qstring.as_bytes());

        let left_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        })));
        let right_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperStorageId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        })));
        let expected_where_cond = Some(ConditionExpression::LogicalOp(ConditionTree {
            left: left_comp,
            right: right_comp,
            operator: Operator::And,
        }));
        println!("res: {:#?}", res);
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperStorage")],
                       fields: vec!["infoJson".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }
}
<commit_msg>(Failing) test with both WHERE and LIMIT clause<commit_after>use nom::{multispace, space};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, unsigned_number, statement_terminator, table_list};
use parser::ConditionExpression;

use condition::*;

#[derive(Clone, Debug, PartialEq)]
pub struct GroupByClause {
    columns: Vec<String>,
    having: String, // XXX(malte): should this be an arbitrary expr?
}

#[derive(Clone, Debug, PartialEq)]
pub struct LimitClause {
    limit: u64,
    offset: u64,
}

#[derive(Clone, Debug, PartialEq)]
pub enum OrderType {
    OrderAscending,
    OrderDescending,
}

#[derive(Clone, Debug, PartialEq)]
pub struct OrderClause {
    cols: Vec<String>, // TODO(malte): can this be an arbitrary expr?
    order: OrderType,
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct SelectStatement {
    pub tables: Vec<String>,
    pub distinct: bool,
    pub fields: Vec<String>,
    pub where_clause: Option<ConditionExpression>,
    pub group_by: Option<GroupByClause>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse LIMIT clause
named!(limit_clause<&[u8], LimitClause>,
    chain!(
        space ~
        caseless_tag!("limit") ~
        space ~
        limit_val: unsigned_number ~
        space? ~
        offset_val: opt!(chain!(
                caseless_tag!("offset") ~
                space ~
                val: unsigned_number,
                || { val }
            )
        ),
    || {
        LimitClause {
            limit: limit_val,
            offset: match offset_val {
                None => 0,
                Some(v) => v,
            },
        }
    })
);

named!(order_clause<&[u8], OrderClause>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("order by") ~
        multispace ~
        order_expr: field_list ~
        ordering: opt!(
            alt_complete!(
                  map!(caseless_tag!("desc"), |_| OrderType::OrderDescending)
                | map!(caseless_tag!("asc"), |_| OrderType::OrderAscending)
            )
        ),
    || {
        OrderClause {
            cols: order_expr.iter().map(|e| String::from(*e)).collect(),
            order: match ordering {
                None => OrderType::OrderAscending,
                Some(ref o) => o.clone(),
            },
        }
    })
));

/// Parse WHERE clause of a selection
named!(where_clause<&[u8], ConditionExpression>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("where") ~
        multispace ~
        cond: condition_expr,
        || { cond }
    )
));

/// Parse rule for a SQL selection query.
/// TODO(malte): support nested queries as selection targets
named!(pub selection<&[u8], SelectStatement>,
    chain!(
        caseless_tag!("select") ~
        space ~
        distinct: opt!(caseless_tag!("distinct")) ~
        space? ~
        fields: field_list ~
        delimited!(opt!(multispace), caseless_tag!("from"), opt!(multispace)) ~
        tables: table_list ~
        cond: opt!(where_clause) ~
        order: opt!(order_clause) ~
        limit: opt!(limit_clause) ~
        statement_terminator,
        || {
            SelectStatement {
                tables: tables.iter().map(|t| String::from(*t)).collect(),
                distinct: distinct.is_some(),
                fields: fields.iter().map(|s| String::from(*s)).collect(),
                where_clause: cond,
                group_by: None,
                order: order,
                limit: limit,
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use common::Operator;
    use parser::{ConditionBase, ConditionExpression, ConditionTree};

    #[test]
    fn simple_select() {
        let qstring = "SELECT id, name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn select_all() {
        let qstring = "SELECT * FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn spaces_optional() {
        let qstring = "SELECT id,name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn case_sensitivity() {
        let qstring_lc = "select id, name from users;";
        let qstring_uc = "SELECT id, name FROM users;";

        assert_eq!(selection(qstring_lc.as_bytes()).unwrap(),
                   selection(qstring_uc.as_bytes()).unwrap());
    }

    #[test]
    fn termination() {
        let qstring_sem = "select id, name from users;";
        let qstring_linebreak = "select id, name from users\n";

        assert_eq!(selection(qstring_sem.as_bytes()).unwrap(),
                   selection(qstring_linebreak.as_bytes()).unwrap());
    }

    #[test]
    fn where_clause() {
        let qstring = "select * from ContactInfo where email=?;";

        let res = selection(qstring.as_bytes());

        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("email"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("ContactInfo")],
                       fields: vec!["ALL".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn limit_clause() {
        let qstring1 = "select * from users limit 10\n";
        let qstring2 = "select * from users limit 10 offset 10\n";

        let expected_lim1 = LimitClause {
            limit: 10,
            offset: 0,
        };
        let expected_lim2 = LimitClause {
            limit: 10,
            offset: 10,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        assert_eq!(res1.unwrap().1.limit, Some(expected_lim1));
        assert_eq!(res2.unwrap().1.limit, Some(expected_lim2));
    }

    #[test]
    fn order_clause() {
        let qstring1 = "select * from users order by name desc\n";
        let qstring2 = "select * from users order by name, age desc\n";
        let qstring3 = "select * from users order by name\n";

        let expected_ord1 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord2 = OrderClause {
            cols: vec!["name".into(), "age".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord3 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderAscending,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        let res3 = selection(qstring3.as_bytes());
        assert_eq!(res1.unwrap().1.order, Some(expected_ord1));
        assert_eq!(res2.unwrap().1.order, Some(expected_ord2));
        assert_eq!(res3.unwrap().1.order, Some(expected_ord3));
    }

    #[test]
    fn table_alias() {
        let qstring1 = "select * from PaperTag as t;";
        // let qstring2 = "select * from PaperTag t;";

        let res1 = selection(qstring1.as_bytes());
        assert_eq!(res1.clone().unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperTag")],
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
        // let res2 = selection(qstring2.as_bytes());
        // assert_eq!(res1.unwrap().1, res2.unwrap().1);
    }

    #[test]
    fn distinct() {
        let qstring = "select distinct tag from PaperTag where paperId=?;";

        let res = selection(qstring.as_bytes());
        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperTag")],
                       distinct: true,
                       fields: vec!["tag".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn simple_condition_expr() {
        let qstring = "select infoJson from PaperStorage where paperId=? and paperStorageId=?;";

        let res = selection(qstring.as_bytes());

        let left_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        })));
        let right_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperStorageId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        })));
        let expected_where_cond = Some(ConditionExpression::LogicalOp(ConditionTree {
            left: left_comp,
            right: right_comp,
            operator: Operator::And,
        }));
        println!("res: {:#?}", res);
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("PaperStorage")],
                       fields: vec!["infoJson".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn where_and_limit_clauses() {
        let qstring = "select * from users where id = ? limit 10\n";
        let res = selection(qstring.as_bytes());

        let expected_lim = Some(LimitClause {
            limit: 10,
            offset: 0,
        });
        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("id"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));

        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       tables: vec![String::from("users")],
                       fields: vec!["ALL".into()],
                       where_clause: expected_where_cond,
                       limit: expected_lim,
                       ..Default::default()
                   });
    }
}
<|endoftext|>


<commit_before>use regex;
use std;
use tempdir;

use error::Error;

/// RAII wrapper for a child process that kills the process when dropped.
struct AutoKillProcess(std::process::Child);

impl Drop for AutoKillProcess {
    fn drop(&mut self) {
        let AutoKillProcess(ref mut process) = *self;
        process.kill().unwrap();
        process.wait().unwrap();
    }
}

/// RAII wrapper for running a CouchDB server process.
///
/// # Remarks
///
/// The Server type is provided for testing purposes. The database persists to
/// the system's default temporary directory (e.g., `/tmp`) and is deleted when
/// the Server instance drops.
pub struct Server {
    // Rust drops structure fields in forward order, not reverse order. The child process must exit
    // before we remove the temporary directory.
    _process: AutoKillProcess,
    _tmp_root: tempdir::TempDir,
    uri: String,
}

impl Server {

    /// Spawn a CouchDB server process.
    pub fn new() -> Result<Server, Error> {

        let tmp_root = try!(
            tempdir::TempDir::new("couchdb_client_test")
            .or_else(|e| {
                Err(Error::Io {
                    description: "Failed to create temporary directory for CouchDB server",
                    cause: e,
                })
            })
        );

        {
            use std::io::Write;
            let path = tmp_root.path().join("couchdb.conf");
            let mut f = try!(
                std::fs::File::create(&path)
                .or_else(|e| {
                    Err(Error::Io {
                        description: "Failed to open CouchDB server configuration file",
                        cause: e,
                    })
                })
            );
            try!(f.write_all(b"[couchdb]\n\
                database_dir = var\n\
                uri_file = couchdb.uri\n\
                view_index_dir = view\n\
                \n\
                [log]\n\
                file = couchdb.log\n\
                \n\
                [httpd]\n\
                port = 0\n\
                ")
                .or_else(|e| {
                    Err(Error::Io {
                        description: "Failed to write CouchDB server configuration file",
                        cause: e,
                    })
                })
            );
        }

        let mut process = AutoKillProcess(
            try!(
                new_test_server_command(&tmp_root)
                .spawn()
                .or_else(|e| {
                    Err(Error::Io {
                        description: "Failed to spawn CouchDB server process",
                        cause: e
                    })
                })
            )
        );

        let (tx, rx) = std::sync::mpsc::channel();
        let mut process_out;
        {
            let AutoKillProcess(ref mut process) = process;
            let stdout = std::mem::replace(&mut process.stdout, None).unwrap();
            process_out = std::io::BufReader::new(stdout);
        }

        let t = std::thread::spawn(move || {

            let re = regex::Regex::new(r"Apache CouchDB has started on (http.*)").unwrap();
            let mut line = String::new();

            loop {
                use std::io::BufRead;
                line.clear();
                process_out.read_line(&mut line).unwrap();
                let line = line.trim_right();
                match re.captures(line) {
                    None => (),
                    Some(caps) => {
                        tx.send(caps.at(1).unwrap().to_string()).unwrap();
                        break;
                    }
                }
            }

            // Drain stdout.
            loop {
                use std::io::BufRead;
                line.clear();
                process_out.read_line(&mut line).unwrap();
            }
        });

        // Wait for CouchDB server to start its HTTP service.
        let uri = try!(
            rx.recv()
            .or_else(|e| {
                t.join().unwrap_err();
                Err(Error::ReceiveFromThread {
                    description: "Failed to extract URI from CouchDB server",
                    cause: e
                })
            })
        );

        Ok(Server {
            _process: process,
            _tmp_root: tmp_root,
            uri: uri,
        })
    }

    /// Get the CouchDB server URI.
    pub fn uri(&self) -> &str {
        &self.uri
    }
}

#[cfg(any(windows))]
fn new_test_server_command(tmp_root: &tempdir::TempDir)
    -> std::process::Command
{
    // Getting a one-shot CouchDB server running on Windows is tricky:
    // http://stackoverflow.com/questions/11812365/how-to-use-a-custom-couch-ini-on-windows
    //
    // TODO: Support CouchDB being installed in a non-default directory.

    let mut c = std::process::Command::new("erl");
    c.arg("-couch_ini");
    c.arg("c:/program files (x86)/apache software foundation/couchdb/etc/couchdb/default.ini");
    c.arg("c:/program files (x86)/apache software foundation/couchdb/etc/couchdb/local.ini");
    c.arg("couchdb.conf");
    c.arg("-s");
    c.arg("couch");
    c.current_dir(tmp_root.path());
    c.stdout(std::process::Stdio::piped());
    c
}

#[cfg(any(not(windows)))]
fn new_test_server_command(tmp_root: &tempdir::TempDir)
    -> std::process::Command
{
    let mut c = std::process::Command::new("couchdb");
    c.arg("-a");
    c.arg("couchdb.conf");
    c.current_dir(tmp_root.path());
    c.stdout(std::process::Stdio::piped());
    c
}
<commit_msg>Fix Server CPU spin on Windows<commit_after>use regex;
use std;
use tempdir;

use error::Error;

/// RAII wrapper for a child process that kills the process when dropped.
struct AutoKillProcess(std::process::Child);

impl Drop for AutoKillProcess {
    fn drop(&mut self) {
        let AutoKillProcess(ref mut process) = *self;
        process.kill().unwrap();
        process.wait().unwrap();
    }
}

/// RAII wrapper for running a CouchDB server process.
///
/// # Remarks
///
/// The Server type is provided for testing purposes. The database persists to
/// the system's default temporary directory (e.g., `/tmp`) and is deleted when
/// the Server instance drops.
pub struct Server {
    // Rust drops structure fields in forward order, not reverse order. The child process must exit
    // before we remove the temporary directory.
    _process: AutoKillProcess,
    _tmp_root: tempdir::TempDir,
    uri: String,
}

impl Server {

    /// Spawn a CouchDB server process.
    pub fn new() -> Result<Server, Error> {

        let tmp_root = try!(
            tempdir::TempDir::new("couchdb_client_test")
            .or_else(|e| {
                Err(Error::Io {
                    description: "Failed to create temporary directory for CouchDB server",
                    cause: e,
                })
            })
        );

        {
            use std::io::Write;
            let path = tmp_root.path().join("couchdb.conf");
            let mut f = try!(
                std::fs::File::create(&path)
                .or_else(|e| {
                    Err(Error::Io {
                        description: "Failed to open CouchDB server configuration file",
                        cause: e,
                    })
                })
            );
            try!(f.write_all(b"[couchdb]\n\
                database_dir = var\n\
                uri_file = couchdb.uri\n\
                view_index_dir = view\n\
                \n\
                [log]\n\
                file = couchdb.log\n\
                \n\
                [httpd]\n\
                port = 0\n\
                ")
                .or_else(|e| {
                    Err(Error::Io {
                        description: "Failed to write CouchDB server configuration file",
                        cause: e,
                    })
                })
            );
        }

        let mut process = AutoKillProcess(
            try!(
                new_test_server_command(&tmp_root)
                .spawn()
                .or_else(|e| {
                    Err(Error::Io {
                        description: "Failed to spawn CouchDB server process",
                        cause: e
                    })
                })
            )
        );

        let (tx, rx) = std::sync::mpsc::channel();
        let mut process_out;
        {
            let AutoKillProcess(ref mut process) = process;
            let stdout = std::mem::replace(&mut process.stdout, None).unwrap();
            process_out = std::io::BufReader::new(stdout);
        }

        let t = std::thread::spawn(move || {

            let re = regex::Regex::new(r"Apache CouchDB has started on (http.*)").unwrap();
            let mut line = String::new();

            loop {
                use std::io::BufRead;
                line.clear();
                process_out.read_line(&mut line).unwrap();
                let line = line.trim_right();
                match re.captures(line) {
                    None => (),
                    Some(caps) => {
                        tx.send(caps.at(1).unwrap().to_string()).unwrap();
                        break;
                    }
                }
            }

            // Drain stdout.
            loop {
                use std::io::BufRead;
                line.clear();
                process_out.read_line(&mut line).unwrap();
                if line.is_empty() {
                    break;
                }
            }
        });

        // Wait for CouchDB server to start its HTTP service.
        let uri = try!(
            rx.recv()
            .or_else(|e| {
                t.join().unwrap_err();
                Err(Error::ReceiveFromThread {
                    description: "Failed to extract URI from CouchDB server",
                    cause: e
                })
            })
        );

        Ok(Server {
            _process: process,
            _tmp_root: tmp_root,
            uri: uri,
        })
    }

    /// Get the CouchDB server URI.
    pub fn uri(&self) -> &str {
        &self.uri
    }
}

#[cfg(any(windows))]
fn new_test_server_command(tmp_root: &tempdir::TempDir)
    -> std::process::Command
{
    // Getting a one-shot CouchDB server running on Windows is tricky:
    // http://stackoverflow.com/questions/11812365/how-to-use-a-custom-couch-ini-on-windows
    //
    // TODO: Support CouchDB being installed in a non-default directory.

    let mut c = std::process::Command::new("erl");
    c.arg("-couch_ini");
    c.arg("c:/program files (x86)/apache software foundation/couchdb/etc/couchdb/default.ini");
    c.arg("c:/program files (x86)/apache software foundation/couchdb/etc/couchdb/local.ini");
    c.arg("couchdb.conf");
    c.arg("-s");
    c.arg("couch");
    c.current_dir(tmp_root.path());
    c.stdout(std::process::Stdio::piped());
    c
}

#[cfg(any(not(windows)))]
fn new_test_server_command(tmp_root: &tempdir::TempDir)
    -> std::process::Command
{
    let mut c = std::process::Command::new("couchdb");
    c.arg("-a");
    c.arg("couchdb.conf");
    c.current_dir(tmp_root.path());
    c.stdout(std::process::Stdio::piped());
    c
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::iter;
use std::mem;
use std::ptr;
use std::ffi::CString;
use cgmath::{Matrix4};
use gl;
use gl::types::{GLuint, GLint, GLenum, GLchar};
use zgl::{Zgl};
use core_types::{ZInt};
use visualizer_types::{ZFloat, Color4, ColorId, MatId, AttrId, ProgramId};

fn get_attr_location(program_id: &ProgramId, zgl: &Zgl, name: &str) -> AttrId {
    let name_c = CString::from_slice(name.as_bytes()).as_slice_with_nul().as_ptr();
    let attr_id = unsafe {
        zgl.gl.GetAttribLocation(program_id.id, name_c)
    };
    zgl.check();
    assert!(attr_id >= 0);
    AttrId{id: attr_id as GLuint}
}

fn get_uniform(program_id: &ProgramId, zgl: &Zgl, name: &str) -> GLuint {
    let name_c = CString::from_slice(name.as_bytes())
        .as_slice_with_nul().as_ptr();
    let id = unsafe {
        zgl.gl.GetUniformLocation(program_id.id, name_c) as GLuint
    };
    assert!(id != -1);
    zgl.check();
    id
}

pub struct Shader {
    program_id: ProgramId,
    mvp_uniform_location: MatId,
    position_attr_id: AttrId,
    color_attr_id: Option<AttrId>,
}

impl Shader {
    pub fn new(zgl: &Zgl, vs_src: &str, fs_src: &str) -> Shader {
        let vs = compile_shader(zgl, vs_src, gl::VERTEX_SHADER);
        let fs = compile_shader(zgl, fs_src, gl::FRAGMENT_SHADER);
        let program_id = link_program(zgl, vs, fs);
        let mvp_uniform_location = MatId {
            id: get_uniform(&program_id, zgl, "mvp_mat"),
        };
        let position_attr_id = get_attr_location(
            &program_id, zgl, "position");
        zgl.enable_vertex_attrib_array(&position_attr_id);
        Shader {
            program_id: program_id,
            mvp_uniform_location: mvp_uniform_location,
            position_attr_id: position_attr_id,
            color_attr_id: None,
        }
    }

    // TODO: Rename
    pub fn enable_color(&mut self, zgl: &Zgl) {
        let color_attr_id = get_attr_location(
            &self.program_id, zgl, "a_color");
        zgl.enable_vertex_attrib_array(&color_attr_id);
        self.color_attr_id = Some(color_attr_id);
    }

    pub fn enable_attr(&self, zgl: &Zgl, attr_id: &AttrId, components_count: ZInt) {
        let is_normalized = gl::FALSE;
        let stride = 0;
        unsafe {
            zgl.gl.VertexAttribPointer(
                attr_id.id,
                components_count,
                gl::FLOAT,
                is_normalized,
                stride,
                ptr::null_mut(),
            );
        }
        zgl.check();
    }

    pub fn activate(&self, zgl: &Zgl) {
        unsafe {
            assert!(zgl.gl.IsProgram(self.program_id.id) != gl::FALSE);
            zgl.gl.UseProgram(self.program_id.id);
        }
        zgl.check();
    }

    pub fn get_position_attr_id(&self) -> &AttrId {
        &self.position_attr_id
    }

    pub fn get_color_attr_id(&self) -> &AttrId {
        self.color_attr_id.as_ref().expect("Can`t get color vbo")
    }

    pub fn prepare_pos(&self, zgl: &Zgl) {
        self.enable_attr(zgl, self.get_position_attr_id(), 3);
    }

    pub fn prepare_color(&self, zgl: &Zgl) {
        self.enable_attr(zgl, self.get_color_attr_id(), 3);
    }

    pub fn set_uniform_mat4f(&self, zgl: &Zgl, mat_id: &MatId, mat: &Matrix4<ZFloat>) {
        let count = 1;
        let transpose = gl::FALSE;
        unsafe {
            let data_ptr = mem::transmute(mat);
            zgl.gl.UniformMatrix4fv(
                mat_id.id as ZInt, count, transpose, data_ptr);
        }
        zgl.check();
    }

    pub fn set_uniform_color(&self, zgl: &Zgl, color_id: &ColorId, color: &Color4) {
        unsafe {
            let data_ptr = mem::transmute(color);
            zgl.gl.Uniform4fv(color_id.id as ZInt, 1, data_ptr);
        }
        zgl.check();
    }

    pub fn get_uniform_color(&self, zgl: &Zgl, name: &str) -> ColorId {
        let id = get_uniform(&self.program_id, zgl, name);
        ColorId{id: id}
    }

    pub fn get_mvp_mat(&self) -> &MatId {
        &self.mvp_uniform_location
    }
}

fn compile_shader(zgl: &Zgl, src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = zgl.gl.CreateShader(ty);
        zgl.check();
        let src_c = CString::from_slice(src.as_bytes())
            .as_slice_with_nul().as_ptr();
        zgl.gl.ShaderSource(shader, 1, &src_c, ptr::null());
        zgl.check();
        zgl.gl.CompileShader(shader);
        zgl.check();
        let mut status = gl::FALSE as GLint;
        zgl.gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
        if status != gl::TRUE as GLint {
            let mut len = 0;
            zgl.gl.GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut err_log = String::with_capacity(len as usize);
            err_log.extend(iter::repeat('\0').take(len as usize));
            let raw_ptr = err_log.as_slice().as_ptr() as *mut GLchar;
            zgl.gl.GetShaderInfoLog(shader, len, &mut len, raw_ptr);
            err_log.truncate(len as usize);
            panic!("{}", err_log);
        }
    }
    shader
}

fn link_program(zgl: &Zgl, vs: GLuint, fs: GLuint) -> ProgramId {
    unsafe {
        let program = zgl.gl.CreateProgram(); // TODO: 'program' -> 'program_id'
        zgl.check();
        zgl.gl.AttachShader(program, vs);
        zgl.check();
        zgl.gl.AttachShader(program, fs);
        zgl.check();
        zgl.gl.LinkProgram(program);
        zgl.check();
        zgl.gl.DeleteShader(vs);
        zgl.check();
        zgl.gl.DeleteShader(fs);
        zgl.check();
        zgl.gl.UseProgram(program);
        zgl.check();
        // zgl.gl.DeleteProgram(program); // mark for deletion // TODO: d-tor?
        zgl.check();
        let mut status = gl::FALSE as GLint;
        zgl.gl.GetProgramiv(program, gl::LINK_STATUS, &mut status);
        if status != gl::TRUE as GLint {
            let mut len = 0;
            zgl.gl.GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut err_log = String::with_capacity(len as usize);
            err_log.extend(iter::repeat('\0').take(len as usize));
            let raw_ptr = err_log.as_slice().as_ptr() as *mut GLchar;
            zgl.gl.GetProgramInfoLog(program, len, &mut len, raw_ptr);
            err_log.truncate(len as usize);
            panic!("{}", err_log);
        }
        assert!(zgl.gl.IsProgram(program) != gl::FALSE);
        ProgramId{id: program}
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/shader.rs: link_program: 'program' -> 'program_id'<commit_after>// See LICENSE file for copyright and license details.

use std::iter;
use std::mem;
use std::ptr;
use std::ffi::CString;
use cgmath::{Matrix4};
use gl;
use gl::types::{GLuint, GLint, GLenum, GLchar};
use zgl::{Zgl};
use core_types::{ZInt};
use visualizer_types::{ZFloat, Color4, ColorId, MatId, AttrId, ProgramId};

fn get_attr_location(program_id: &ProgramId, zgl: &Zgl, name: &str) -> AttrId {
    let name_c = CString::from_slice(name.as_bytes()).as_slice_with_nul().as_ptr();
    let attr_id = unsafe {
        zgl.gl.GetAttribLocation(program_id.id, name_c)
    };
    zgl.check();
    assert!(attr_id >= 0);
    AttrId{id: attr_id as GLuint}
}

fn get_uniform(program_id: &ProgramId, zgl: &Zgl, name: &str) -> GLuint {
    let name_c = CString::from_slice(name.as_bytes())
        .as_slice_with_nul().as_ptr();
    let id = unsafe {
        zgl.gl.GetUniformLocation(program_id.id, name_c) as GLuint
    };
    assert!(id != -1);
    zgl.check();
    id
}

pub struct Shader {
    program_id: ProgramId,
    mvp_uniform_location: MatId,
    position_attr_id: AttrId,
    color_attr_id: Option<AttrId>,
}

impl Shader {
    pub fn new(zgl: &Zgl, vs_src: &str, fs_src: &str) -> Shader {
        let vs = compile_shader(zgl, vs_src, gl::VERTEX_SHADER);
        let fs = compile_shader(zgl, fs_src, gl::FRAGMENT_SHADER);
        let program_id = link_program(zgl, vs, fs);
        let mvp_uniform_location = MatId {
            id: get_uniform(&program_id, zgl, "mvp_mat"),
        };
        let position_attr_id = get_attr_location(
            &program_id, zgl, "position");
        zgl.enable_vertex_attrib_array(&position_attr_id);
        Shader {
            program_id: program_id,
            mvp_uniform_location: mvp_uniform_location,
            position_attr_id: position_attr_id,
            color_attr_id: None,
        }
    }

    // TODO: Rename
    pub fn enable_color(&mut self, zgl: &Zgl) {
        let color_attr_id = get_attr_location(
            &self.program_id, zgl, "a_color");
        zgl.enable_vertex_attrib_array(&color_attr_id);
        self.color_attr_id = Some(color_attr_id);
    }

    pub fn enable_attr(&self, zgl: &Zgl, attr_id: &AttrId, components_count: ZInt) {
        let is_normalized = gl::FALSE;
        let stride = 0;
        unsafe {
            zgl.gl.VertexAttribPointer(
                attr_id.id,
                components_count,
                gl::FLOAT,
                is_normalized,
                stride,
                ptr::null_mut(),
            );
        }
        zgl.check();
    }

    pub fn activate(&self, zgl: &Zgl) {
        unsafe {
            assert!(zgl.gl.IsProgram(self.program_id.id) != gl::FALSE);
            zgl.gl.UseProgram(self.program_id.id);
        }
        zgl.check();
    }

    pub fn get_position_attr_id(&self) -> &AttrId {
        &self.position_attr_id
    }

    pub fn get_color_attr_id(&self) -> &AttrId {
        self.color_attr_id.as_ref().expect("Can`t get color vbo")
    }

    pub fn prepare_pos(&self, zgl: &Zgl) {
        self.enable_attr(zgl, self.get_position_attr_id(), 3);
    }

    pub fn prepare_color(&self, zgl: &Zgl) {
        self.enable_attr(zgl, self.get_color_attr_id(), 3);
    }

    pub fn set_uniform_mat4f(&self, zgl: &Zgl, mat_id: &MatId, mat: &Matrix4<ZFloat>) {
        let count = 1;
        let transpose = gl::FALSE;
        unsafe {
            let data_ptr = mem::transmute(mat);
            zgl.gl.UniformMatrix4fv(
                mat_id.id as ZInt, count, transpose, data_ptr);
        }
        zgl.check();
    }

    pub fn set_uniform_color(&self, zgl: &Zgl, color_id: &ColorId, color: &Color4) {
        unsafe {
            let data_ptr = mem::transmute(color);
            zgl.gl.Uniform4fv(color_id.id as ZInt, 1, data_ptr);
        }
        zgl.check();
    }

    pub fn get_uniform_color(&self, zgl: &Zgl, name: &str) -> ColorId {
        let id = get_uniform(&self.program_id, zgl, name);
        ColorId{id: id}
    }

    pub fn get_mvp_mat(&self) -> &MatId {
        &self.mvp_uniform_location
    }
}

fn compile_shader(zgl: &Zgl, src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = zgl.gl.CreateShader(ty);
        zgl.check();
        let src_c = CString::from_slice(src.as_bytes())
            .as_slice_with_nul().as_ptr();
        zgl.gl.ShaderSource(shader, 1, &src_c, ptr::null());
        zgl.check();
        zgl.gl.CompileShader(shader);
        zgl.check();
        let mut status = gl::FALSE as GLint;
        zgl.gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
        if status != gl::TRUE as GLint {
            let mut len = 0;
            zgl.gl.GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut err_log = String::with_capacity(len as usize);
            err_log.extend(iter::repeat('\0').take(len as usize));
            let raw_ptr = err_log.as_slice().as_ptr() as *mut GLchar;
            zgl.gl.GetShaderInfoLog(shader, len, &mut len, raw_ptr);
            err_log.truncate(len as usize);
            panic!("{}", err_log);
        }
    }
    shader
}

fn link_program(zgl: &Zgl, vs: GLuint, fs: GLuint) -> ProgramId {
    unsafe {
        let program_id = zgl.gl.CreateProgram();
        zgl.check();
        zgl.gl.AttachShader(program_id, vs);
        zgl.check();
        zgl.gl.AttachShader(program_id, fs);
        zgl.check();
        zgl.gl.LinkProgram(program_id);
        zgl.check();
        zgl.gl.DeleteShader(vs);
        zgl.check();
        zgl.gl.DeleteShader(fs);
        zgl.check();
        zgl.gl.UseProgram(program_id);
        zgl.check();
        // zgl.gl.DeleteProgram(program_id); // mark for deletion // TODO: d-tor?
        zgl.check();
        let mut status = gl::FALSE as GLint;
        zgl.gl.GetProgramiv(program_id, gl::LINK_STATUS, &mut status);
        if status != gl::TRUE as GLint {
            let mut len = 0;
            zgl.gl.GetProgramiv(program_id, gl::INFO_LOG_LENGTH, &mut len);
            let mut err_log = String::with_capacity(len as usize);
            err_log.extend(iter::repeat('\0').take(len as usize));
            let raw_ptr = err_log.as_slice().as_ptr() as *mut GLchar;
            zgl.gl.GetProgramInfoLog(program_id, len, &mut len, raw_ptr);
            err_log.truncate(len as usize);
            panic!("{}", err_log);
        }
        assert!(zgl.gl.IsProgram(program_id) != gl::FALSE);
        ProgramId{id: program_id}
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use ::{Guard, Nav};
use ::util::{ChildIndex, SiblingIndex};

use std::cell::{Ref, RefCell};
use std::clone::Clone;
use std::mem;
use std::rc::Rc;

/// Heap-allocated, reference-counted trees that can be shared freely.

struct TreeInternal<T> {
    data: T, children: RefCell<Vec<Tree<T>>>,
}

/// Reference to a heap-allocated to a tree.
///
/// This tree structure has the same characteristics as
/// [owned::Tree](../owned/struct.Tree.html), except that a parent does not own
/// its children. Internally, this is achieved by storing trees in `std::rc::Rc`
/// wrappers. As a result, this type can be cloned and shared as the child of
/// multiple parents. This may be useful for saving memory.
pub struct Tree<T> {
    internal: Rc<TreeInternal<T>>,
}

impl<T> Tree<T> {
    pub fn new(data: T, children: Vec<Tree<T>>) -> Self {
        Tree { internal: Rc::new(TreeInternal { data: data, children: RefCell::new(children), }), }
    }

    pub fn leaf(data: T) -> Self {
        Tree { internal: Rc::new(TreeInternal { data: data, children: RefCell::new(Vec::new()), }), }
    }

    pub fn push_child(&mut self, child: Tree<T>) {
        self.internal.children.borrow_mut().push(child);
    }

    pub fn remove_child(&mut self, index: usize) {
        assert![index < self.internal.children.borrow().len(),
                "cannot remove child at index {} (only {} children)", index, self.internal.children.borrow().len()];
        self.internal.children.borrow_mut().remove(index);
    }

    pub fn insert_child(&mut self, index: usize, child: Tree<T>) {
        self.internal.children.borrow_mut().insert(index, child);
    }

    pub fn nav<'s>(&'s self) -> Navigator<'s, T> {
        Navigator::new(self)
    }
}

/// Creates a new reference to this tree, such that modifying the reference also
/// modifies the original tree.
impl<T> Clone for Tree<T> {
    fn clone(&self) -> Self {
        Tree { internal: self.internal.clone(), }
    }
}

pub struct DataGuard<T> {
    tree: Tree<T>,
}

impl<'a, T: 'a> Guard<'a, T> for DataGuard<T> {
    fn super_deref<'s>(&'s self) -> &'a T {
        unsafe {
            mem::transmute(&self.tree.internal.data)
        }
    }
}

pub struct Navigator<'a, T: 'a> {
    root: &'a Tree<T>,
    path: Vec<(Ref<'a, Vec<Tree<T>>>, usize)>,
}

impl<'a, T: 'a> Navigator<'a, T> {
    fn new(root: &'a Tree<T>) -> Self {
        Navigator { root: root, path: Vec::new(), }
    }

    fn here<'s>(&'s self) -> &'s Tree<T> {
        match self.path.last() {
            None => self.root,
            Some(&(ref siblings, ref index)) => &siblings[*index],
        }
    }
}

/// Due to the internal representation of the path back from the tree root, this
/// `Clone` implementation retraces the path from the root. This may be less
/// efficient than is desirable.
impl<'a, T: 'a> Clone for Navigator<'a, T> {
    fn clone(&self) -> Self {
        // We can't clone self.path directly, so we rebuild it by hand.
        let mut new_nav = Navigator { root: self.root, path: Vec::new(), };
        new_nav.path.reserve(self.path.len());
        for &(_, index) in &self.path {
            new_nav.seek_child(index);
        }
        return new_nav;
    }
}

impl<'a, T: 'a> Nav<'a> for Navigator<'a, T> {
    type Data = T;
    type DataGuard = DataGuard<T>;

    fn seek_sibling(&mut self, offset: isize) {
        let new_index =
            match self.path.last() {
                None => SiblingIndex::Root,
                Some(&(ref siblings, ref index)) =>
                    SiblingIndex::compute(siblings.len(), *index, offset),
            }.unwrap();
        let (siblings, _) = self.path.pop().unwrap();
        self.path.push((siblings, new_index));
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.here().internal.children.borrow().len(), index).unwrap();
        let children = unsafe {
            mem::transmute(self.here().internal.children.borrow())
        };
        self.path.push((children, new_index));
    }

    fn child_count(&self) -> usize {
        self.here().internal.children.borrow().len()
    }

    fn at_root(&self) -> bool {
        self.path.is_empty()
    }

    fn to_parent(&mut self) {
        self.path.pop().expect("already at root");
    }

    fn to_root(&mut self) {
        self.path.clear();
    }

    fn data(&self) -> DataGuard<T> {
        DataGuard { tree: self.here().clone(), }
    }
}
<commit_msg>Comment typo.<commit_after>use ::{Guard, Nav};
use ::util::{ChildIndex, SiblingIndex};

use std::cell::{Ref, RefCell};
use std::clone::Clone;
use std::mem;
use std::rc::Rc;

/// Heap-allocated, reference-counted trees that can be shared freely.

struct TreeInternal<T> {
    data: T, children: RefCell<Vec<Tree<T>>>,
}

/// Reference to a heap-allocated tree.
///
/// This tree structure has the same characteristics as
/// [owned::Tree](../owned/struct.Tree.html), except that a parent does not own
/// its children. Internally, this is achieved by storing trees in `std::rc::Rc`
/// wrappers. As a result, this type can be cloned and shared as the child of
/// multiple parents. This may be useful for saving memory.
pub struct Tree<T> {
    internal: Rc<TreeInternal<T>>,
}

impl<T> Tree<T> {
    pub fn new(data: T, children: Vec<Tree<T>>) -> Self {
        Tree { internal: Rc::new(TreeInternal { data: data, children: RefCell::new(children), }), }
    }

    pub fn leaf(data: T) -> Self {
        Tree { internal: Rc::new(TreeInternal { data: data, children: RefCell::new(Vec::new()), }), }
    }

    pub fn push_child(&mut self, child: Tree<T>) {
        self.internal.children.borrow_mut().push(child);
    }

    pub fn remove_child(&mut self, index: usize) {
        assert![index < self.internal.children.borrow().len(),
                "cannot remove child at index {} (only {} children)", index, self.internal.children.borrow().len()];
        self.internal.children.borrow_mut().remove(index);
    }

    pub fn insert_child(&mut self, index: usize, child: Tree<T>) {
        self.internal.children.borrow_mut().insert(index, child);
    }

    pub fn nav<'s>(&'s self) -> Navigator<'s, T> {
        Navigator::new(self)
    }
}

/// Creates a new reference to this tree, such that modifying the reference also
/// modifies the original tree.
impl<T> Clone for Tree<T> {
    fn clone(&self) -> Self {
        Tree { internal: self.internal.clone(), }
    }
}

pub struct DataGuard<T> {
    tree: Tree<T>,
}

impl<'a, T: 'a> Guard<'a, T> for DataGuard<T> {
    fn super_deref<'s>(&'s self) -> &'a T {
        unsafe {
            mem::transmute(&self.tree.internal.data)
        }
    }
}

pub struct Navigator<'a, T: 'a> {
    root: &'a Tree<T>,
    path: Vec<(Ref<'a, Vec<Tree<T>>>, usize)>,
}

impl<'a, T: 'a> Navigator<'a, T> {
    fn new(root: &'a Tree<T>) -> Self {
        Navigator { root: root, path: Vec::new(), }
    }

    fn here<'s>(&'s self) -> &'s Tree<T> {
        match self.path.last() {
            None => self.root,
            Some(&(ref siblings, ref index)) => &siblings[*index],
        }
    }
}

/// Due to the internal representation of the path back from the tree root, this
/// `Clone` implementation retraces the path from the root. This may be less
/// efficient than is desirable.
impl<'a, T: 'a> Clone for Navigator<'a, T> {
    fn clone(&self) -> Self {
        // We can't clone self.path directly, so we rebuild it by hand.
        let mut new_nav = Navigator { root: self.root, path: Vec::new(), };
        new_nav.path.reserve(self.path.len());
        for &(_, index) in &self.path {
            new_nav.seek_child(index);
        }
        return new_nav;
    }
}

impl<'a, T: 'a> Nav<'a> for Navigator<'a, T> {
    type Data = T;
    type DataGuard = DataGuard<T>;

    fn seek_sibling(&mut self, offset: isize) {
        let new_index =
            match self.path.last() {
                None => SiblingIndex::Root,
                Some(&(ref siblings, ref index)) =>
                    SiblingIndex::compute(siblings.len(), *index, offset),
            }.unwrap();
        let (siblings, _) = self.path.pop().unwrap();
        self.path.push((siblings, new_index));
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.here().internal.children.borrow().len(), index).unwrap();
        let children = unsafe {
            mem::transmute(self.here().internal.children.borrow())
        };
        self.path.push((children, new_index));
    }

    fn child_count(&self) -> usize {
        self.here().internal.children.borrow().len()
    }

    fn at_root(&self) -> bool {
        self.path.is_empty()
    }

    fn to_parent(&mut self) {
        self.path.pop().expect("already at root");
    }

    fn to_root(&mut self) {
        self.path.clear();
    }

    fn data(&self) -> DataGuard<T> {
        DataGuard { tree: self.here().clone(), }
    }
}
<|endoftext|>


<commit_before>use rustc::lint::{Context, LintPass, LintArray};
use syntax::ast::{Mod, Item_, ViewPath_};
use syntax::codemap::Span;
use syntax::print::pprust::path_to_string;

declare_lint!(SORTER, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorter;

impl LintPass for Sorter {
    fn get_lints(&self) -> LintArray {
        lint_array!(SORTER)
    }

    fn check_mod(&mut self, _cx: &Context, module: &Mod, _span: Span, _id: u32) {
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        // let mut mods = Vec::new();
        for item in &module.items {
            match item.node.clone() {
                Item_::ItemExternCrate(_) if item.ident.name.as_str() != "std" => {
                    extern_crates.push(item.ident.name.as_str());
                },
                Item_::ItemUse(spanned) => {
                    match spanned.node {
                        ViewPath_::ViewPathSimple(_, ref path) | ViewPath_::ViewPathList(ref path, _) => {
                            uses.push(path_to_string(&path));
                        },
                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path);
                            // we don't have any use statements like `use std::<something>::*`
                            // since it's done only by rustc, we can safely neglect those here
                            match path_str.starts_with("std::") {
                                true => continue,
                                false => uses.push(path_str),
                            }
                        },
                    }
                },
                _ => {},
            }
        }
    }
}
<commit_msg>initial display of sorted output<commit_after>use rustc::lint::{Context, LintPass, LintArray};
use syntax::ast::{Mod, Item_, ViewPath_};
use syntax::codemap::Span;
use syntax::print::pprust::path_to_string;

declare_lint!(SORTED_DECLARATIONS, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorter;

impl LintPass for Sorter {
    fn get_lints(&self) -> LintArray {
        lint_array!(SORTED_DECLARATIONS)
    }

    fn check_mod(&mut self, cx: &Context, module: &Mod, _span: Span, _id: u32) {
        let session_codemap = cx.tcx.sess.codemap();
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        let mut mods = Vec::new();
        for item in &module.items {
            let item_name = item.ident.name.as_str().to_owned();
            let item_span = item.span;
            match item.node.clone() {
                Item_::ItemExternCrate(_) if item_name != "std" => {
                    extern_crates.push((item_name, item_span));
                },
                Item_::ItemMod(module) => {
                    let mod_invoked_file = session_codemap.span_to_filename(item.span);
                    let mod_declared_file = session_codemap.span_to_filename(module.inner);
                    if mod_declared_file != mod_invoked_file {      // this ignores inline modules
                        mods.push((item_name, item_span));
                    }
                },
                Item_::ItemUse(spanned) => {
                    match spanned.node {
                        ViewPath_::ViewPathSimple(_, ref path) | ViewPath_::ViewPathList(ref path, _) => {
                            uses.push((path_to_string(&path), item_span));
                        },
                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path);
                            // we don't have any use statements like `use std::prelude::*`
                            // since it's done only by rustc, we can safely neglect those here
                            match path_str.starts_with("std::") {
                                true => continue,
                                false => uses.push((path_str, item_span)),
                            }
                        },
                    }
                },
                _ => {},
            }
        }

        check_sort(&extern_crates, cx);
        check_sort(&mods, cx);
        check_sort(&uses, cx);

        fn check_sort(old_slice: &Vec<(String, Span)>, cx: &Context) {
            let mut new_slice = old_slice
                                .iter()
                                .map(|&(ref string, _span)| string.clone())
                                .collect::<Vec<String>>();
            new_slice.sort();
            for i in 0..old_slice.len() {
                let (declaration, span) = (old_slice[i].0.clone(), old_slice[i].1);
                if declaration != new_slice[i] {
                    let suggestion = format!("\n\texpected: {}\n\tfound: {}", new_slice[i], declaration);
                    cx.span_lint(SORTED_DECLARATIONS, span, &suggestion);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::time::duration::Duration;
use std::str::FromStr;
use std::io::{standard_error, IoErrorKind};
use std::error::FromError;
use rustc_serialize::{Encoder, Encodable};

use error::MpdResult;
use songs::MpdQueuePlace;
use client::{MpdPair, ForceEncodable};

#[deriving(Show, Copy, RustcEncodable)]
pub struct AudioFormat {
    pub rate: u32,
    pub bits: u8,
    pub chans: u8
}

impl FromStr for AudioFormat {
    fn from_str(s: &str) -> Option<AudioFormat> {
        let mut it = s.split(':');
        if let (Some(rate), Some(bits), Some(chans)) = (
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse())) {
            Some(AudioFormat {
                rate: rate,
                bits: bits,
                chans: chans
            })
        } else {
            None
        }
    }
}

#[deriving(Show, Copy, RustcEncodable)]
pub enum MpdState {
    Stop,
    Play,
    Pause,
}

impl FromStr for MpdState {
    fn from_str(s: &str) -> Option<MpdState> {
        match s {
            "stop" => Some(MpdState::Stop),
            "play" => Some(MpdState::Play),
            "pause" => Some(MpdState::Pause),
            _ => None
        }
    }
}

#[deriving(Show, RustcEncodable)]
pub struct MpdStatus {
    volume: uint,
    repeat: bool,
    random: bool,
    single: bool,
    consume: bool,
    queue_version: uint,
    queue_len: uint,
    state: MpdState,
    song: Option<MpdQueuePlace>,
    nextsong: Option<MpdQueuePlace>,
    time: Option<Duration>,
    elapsed: Option<Duration>,
    duration: Option<Duration>,
    bitrate: Option<uint>,
    xfade: Option<u64>,
    mixrampdb: f32,
    mixrampdelay: Option<u64>,
    audio: Option<AudioFormat>,
    updating_db: Option<uint>,
    error: Option<String>
}

impl FromIterator<MpdResult<MpdPair>> for MpdResult<MpdStatus> {
    fn from_iter<T: Iterator<MpdResult<MpdPair>>>(iterator: T) -> MpdResult<MpdStatus> {
        let mut status = MpdStatus {
            volume: 0,
            repeat: false,
            random: false,
            single: false,
            consume: false,
            queue_version: 0,
            queue_len: 0,
            state: MpdState::Stop,
            song: None,
            nextsong: None,
            time: None,
            elapsed: None,
            duration: None,
            bitrate: None,
            xfade: None,
            mixrampdb: 0.0f32,
            mixrampdelay: None,
            audio: None,
            updating_db: None,
            error: None
        };

        let mut iter = iterator;
        let mut song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };
        let mut next_song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };

        for field in iter {
            let MpdPair(key, value) = try!(field);
            match key[] {
                "volume"         => status.volume = value.parse().unwrap_or(0),
                "repeat"         => status.repeat = value[] == "1",
                "random"         => status.random = value[] == "1",
                "single"         => status.single = value[] == "1",
                "consume"        => status.consume = value[] == "1",
                "playlist"       => status.queue_version = value.parse().unwrap_or(0),
                "playlistlength" => status.queue_len = value.parse().unwrap_or(0),
                "state"          => status.state = value.parse().unwrap_or(MpdState::Stop),
                "song"           => song_place.pos = value.parse().unwrap_or(0),
                "songid"         => song_place.id = value.parse().unwrap_or(0),
                "nextsong"       => next_song_place.pos = value.parse().unwrap_or(0),
                "nextsongid"     => next_song_place.id = value.parse().unwrap_or(0),
                "time"           => status.time = value.parse().map(Duration::seconds),
                "elapsed"        => status.elapsed = value.parse().map(Duration::seconds),
                "duration"       => status.duration = value.parse().map(Duration::seconds),
                "bitrate"        => status.bitrate = value.parse(),
                "xfade"          => status.xfade = value.parse(),
                "mixrampdb"      => status.mixrampdb = value.parse().unwrap_or(0f32),
                "mixrampdelay"   => status.mixrampdelay = value.parse(),
                "audio"          => status.audio = value.parse(),
                "updating_db"    => status.updating_db = value.parse(),
                "error"          => status.error = Some(value),
                _ => return Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput)))
            }
        }

        if song_place.id > 0 {
            status.song = Some(song_place);
        }
        if next_song_place.id > 0 {
            status.nextsong = Some(next_song_place);
        }

        Ok(status)
    }
}

<commit_msg>rename xfade field to crossfade<commit_after>use std::time::duration::Duration;
use std::str::FromStr;
use std::io::{standard_error, IoErrorKind};
use std::error::FromError;
use rustc_serialize::{Encoder, Encodable};

use error::MpdResult;
use songs::MpdQueuePlace;
use client::{MpdPair, ForceEncodable};

#[deriving(Show, Copy, RustcEncodable)]
pub struct AudioFormat {
    pub rate: u32,
    pub bits: u8,
    pub chans: u8
}

impl FromStr for AudioFormat {
    fn from_str(s: &str) -> Option<AudioFormat> {
        let mut it = s.split(':');
        if let (Some(rate), Some(bits), Some(chans)) = (
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse()),
            it.next().and_then(|v| v.parse())) {
            Some(AudioFormat {
                rate: rate,
                bits: bits,
                chans: chans
            })
        } else {
            None
        }
    }
}

#[deriving(Show, Copy, RustcEncodable)]
pub enum MpdState {
    Stop,
    Play,
    Pause,
}

impl FromStr for MpdState {
    fn from_str(s: &str) -> Option<MpdState> {
        match s {
            "stop" => Some(MpdState::Stop),
            "play" => Some(MpdState::Play),
            "pause" => Some(MpdState::Pause),
            _ => None
        }
    }
}

#[deriving(Show, RustcEncodable)]
pub struct MpdStatus {
    volume: uint,
    repeat: bool,
    random: bool,
    single: bool,
    consume: bool,
    queue_version: uint,
    queue_len: uint,
    state: MpdState,
    song: Option<MpdQueuePlace>,
    nextsong: Option<MpdQueuePlace>,
    time: Option<Duration>,
    elapsed: Option<Duration>,
    duration: Option<Duration>,
    bitrate: Option<uint>,
    crossfade: Option<u64>,
    mixrampdb: f32,
    mixrampdelay: Option<u64>,
    audio: Option<AudioFormat>,
    updating_db: Option<uint>,
    error: Option<String>
}

impl FromIterator<MpdResult<MpdPair>> for MpdResult<MpdStatus> {
    fn from_iter<T: Iterator<MpdResult<MpdPair>>>(iterator: T) -> MpdResult<MpdStatus> {
        let mut status = MpdStatus {
            volume: 0,
            repeat: false,
            random: false,
            single: false,
            consume: false,
            queue_version: 0,
            queue_len: 0,
            state: MpdState::Stop,
            song: None,
            nextsong: None,
            time: None,
            elapsed: None,
            duration: None,
            bitrate: None,
            xfade: None,
            mixrampdb: 0.0f32,
            mixrampdelay: None,
            audio: None,
            updating_db: None,
            error: None
        };

        let mut iter = iterator;
        let mut song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };
        let mut next_song_place = MpdQueuePlace { id: 0, pos: 0, prio: 0 };

        for field in iter {
            let MpdPair(key, value) = try!(field);
            match key[] {
                "volume"         => status.volume = value.parse().unwrap_or(0),
                "repeat"         => status.repeat = value[] == "1",
                "random"         => status.random = value[] == "1",
                "single"         => status.single = value[] == "1",
                "consume"        => status.consume = value[] == "1",
                "playlist"       => status.queue_version = value.parse().unwrap_or(0),
                "playlistlength" => status.queue_len = value.parse().unwrap_or(0),
                "state"          => status.state = value.parse().unwrap_or(MpdState::Stop),
                "song"           => song_place.pos = value.parse().unwrap_or(0),
                "songid"         => song_place.id = value.parse().unwrap_or(0),
                "nextsong"       => next_song_place.pos = value.parse().unwrap_or(0),
                "nextsongid"     => next_song_place.id = value.parse().unwrap_or(0),
                "time"           => status.time = value.parse().map(Duration::seconds),
                "elapsed"        => status.elapsed = value.parse().map(Duration::seconds),
                "duration"       => status.duration = value.parse().map(Duration::seconds),
                "bitrate"        => status.bitrate = value.parse(),
                "xfade"          => status.crossfade = value.parse(),
                "mixrampdb"      => status.mixrampdb = value.parse().unwrap_or(0f32),
                "mixrampdelay"   => status.mixrampdelay = value.parse(),
                "audio"          => status.audio = value.parse(),
                "updating_db"    => status.updating_db = value.parse(),
                "error"          => status.error = Some(value),
                _ => return Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput)))
            }
        }

        if song_place.id > 0 {
            status.song = Some(song_place);
        }
        if next_song_place.id > 0 {
            status.nextsong = Some(next_song_place);
        }

        Ok(status)
    }
}

<|endoftext|>


<commit_before>use rand;
use std::fmt::Debug;
use std::thread;
use super::{Arbitrary, Gen, StdGen};
use tester::Status::{Discard, Fail, Pass};

/// The main QuickCheck type for setting configuration and running QuickCheck.
pub struct QuickCheck<G> {
    tests: usize,
    max_tests: usize,
    gen: G,
}

impl QuickCheck<StdGen<rand::ThreadRng>> {
    /// Creates a new QuickCheck value.
    ///
    /// This can be used to run QuickCheck on things that implement
    /// `Testable`. You may also adjust the configuration, such as
    /// the number of tests to run.
    ///
    /// By default, the maximum number of passed tests is set to `100`,
    /// the max number of overall tests is set to `10000` and the generator
    /// is set to a `StdGen` with a default size of `100`.
    pub fn new() -> QuickCheck<StdGen<rand::ThreadRng>> {
        QuickCheck {
            tests: 100,
            max_tests: 10000,
            gen: StdGen::new(rand::thread_rng(), 100),
        }
    }
}

impl<G: Gen> QuickCheck<G> {
    /// Set the number of tests to run.
    ///
    /// This actually refers to the maximum number of *passed* tests that
    /// can occur. Namely, if a test causes a failure, future testing on that
    /// property stops. Additionally, if tests are discarded, there may be
    /// fewer than `tests` passed.
    pub fn tests(mut self, tests: usize) -> QuickCheck<G> {
        self.tests = tests;
        self
    }

    /// Set the maximum number of tests to run.
    ///
    /// The number of invocations of a property will never exceed this number.
    /// This is necessary to cap the number of tests because QuickCheck
    /// properties can discard tests.
    pub fn max_tests(mut self, max_tests: usize) -> QuickCheck<G> {
        self.max_tests = max_tests;
        self
    }

    /// Set the random number generator to be used by QuickCheck.
    pub fn gen(mut self, gen: G) -> QuickCheck<G> {
        self.gen = gen;
        self
    }

    /// Tests a property and returns the result.
    ///
    /// The result returned is either the number of tests passed or a witness
    /// of failure.
    ///
    /// (If you're using Rust's unit testing infrastructure, then you'll
    /// want to use the `quickcheck` method, which will `panic!` on failure.)
    pub fn quicktest<A>(&mut self, f: A) -> Result<usize, TestResult>
                    where A: Testable {
        let mut ntests: usize = 0;
        for _ in 0..self.max_tests {
            if ntests >= self.tests {
                break
            }
            match f.result(&mut self.gen) {
                TestResult { status: Pass, .. } => ntests += 1,
                TestResult { status: Discard, .. } => continue,
                r @ TestResult { status: Fail, .. } => return Err(r),
            }
        }
        Ok(ntests)
    }

    /// Tests a property and calls `panic!` on failure.
    ///
    /// The `panic!` message will include a (hopefully) minimal witness of
    /// failure.
    ///
    /// It is appropriate to use this method with Rust's unit testing
    /// infrastructure.
    ///
    /// Note that if the environment variable `RUST_LOG` is set to enable
    /// `info` level log messages for the `quickcheck` crate, then this will
    /// include output on how many QuickCheck tests were passed.
    ///
    /// # Example
    ///
    /// ```rust
    /// use quickcheck::QuickCheck;
    ///
    /// fn prop_reverse_reverse() {
    ///     fn revrev(xs: Vec<usize>) -> bool {
    ///         let rev: Vec<_> = xs.clone().into_iter().rev().collect();
    ///         let revrev: Vec<_> = rev.into_iter().rev().collect();
    ///         xs == revrev
    ///     }
    ///     QuickCheck::new().quickcheck(revrev as fn(Vec<usize>) -> bool);
    /// }
    /// ```
    pub fn quickcheck<A>(&mut self, f: A) where A: Testable {
        // Ignore log init failures, implying it has already been done.
        let _ = ::env_logger::init();

        match self.quicktest(f) {
            Ok(ntests) => info!("(Passed {} QuickCheck tests.)", ntests),
            Err(result) => panic!(result.failed_msg()),
        }
    }
}

/// Convenience function for running QuickCheck.
///
/// This is an alias for `QuickCheck::new().quickcheck(f)`.
pub fn quickcheck<A: Testable>(f: A) { QuickCheck::new().quickcheck(f) }

/// Describes the status of a single instance of a test.
///
/// All testable things must be capable of producing a `TestResult`.
#[derive(Clone, Debug)]
pub struct TestResult {
    status: Status,
    arguments: Vec<String>,
    err: Option<String>,
}

/// Whether a test has passed, failed or been discarded.
#[derive(Clone, Debug)]
enum Status { Pass, Fail, Discard }

impl TestResult {
    /// Produces a test result that indicates the current test has passed.
    pub fn passed() -> TestResult { TestResult::from_bool(true) }

    /// Produces a test result that indicates the current test has failed.
    pub fn failed() -> TestResult { TestResult::from_bool(false) }

    /// Produces a test result that indicates failure from a runtime error.
    pub fn error<S: Into<String>>(msg: S) -> TestResult {
        let mut r = TestResult::from_bool(false);
        r.err = Some(msg.into());
        r
    }

    /// Produces a test result that instructs `quickcheck` to ignore it.
    /// This is useful for restricting the domain of your properties.
    /// When a test is discarded, `quickcheck` will replace it with a
    /// fresh one (up to a certain limit).
    pub fn discard() -> TestResult {
        TestResult {
            status: Discard,
            arguments: vec![],
            err: None,
        }
    }

    /// Converts a `bool` to a `TestResult`. A `true` value indicates that
    /// the test has passed and a `false` value indicates that the test
    /// has failed.
    pub fn from_bool(b: bool) -> TestResult {
        TestResult {
            status: if b { Pass } else { Fail },
            arguments: vec![],
            err: None,
        }
    }

    /// Tests if a "procedure" fails when executed. The test passes only if
    /// `f` generates a task failure during its execution.
    pub fn must_fail<T, F>(f: F) -> TestResult
            where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
        TestResult::from_bool(
            thread::Builder::new()
                            .spawn(move || { let _ = f(); })
                            .unwrap()
                            .join()
                            .is_err())
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test.
    pub fn is_failure(&self) -> bool {
        match self.status {
            Fail => true,
            Pass|Discard => false,
        }
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test as a result of a run time error.
    pub fn is_error(&self) -> bool {
        self.is_failure() && self.err.is_some()
    }

    fn failed_msg(&self) -> String {
        match self.err {
            None => {
                format!("[quickcheck] TEST FAILED. Arguments: ({})",
                        self.arguments.connect(", "))
            }
            Some(ref err) => {
                format!("[quickcheck] TEST FAILED (runtime error). \
                         Arguments: ({})\nError: {}",
                        self.arguments.connect(", "), err)
            }
        }
    }
}

/// `Testable` describes types (e.g., a function) whose values can be
/// tested.
///
/// Anything that can be tested must be capable of producing a `TestResult`
/// given a random number generator. This is trivial for types like `bool`,
/// which are just converted to either a passing or failing test result.
///
/// For functions, an implementation must generate random arguments
/// and potentially shrink those arguments if they produce a failure.
///
/// It's unlikely that you'll have to implement this trait yourself.
pub trait Testable : Send + 'static {
    fn result<G: Gen>(&self, &mut G) -> TestResult;
}

impl Testable for bool {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::from_bool(*self)
    }
}

impl Testable for () {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::passed()
    }
}

impl Testable for TestResult {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult { self.clone() }
}

impl<A, E> Testable for Result<A, E>
        where A: Testable, E: Debug + Send + 'static {
    fn result<G: Gen>(&self, g: &mut G) -> TestResult {
        match *self {
            Ok(ref r) => r.result(g),
            Err(ref err) => TestResult::error(format!("{:?}", err)),
        }
    }
}

macro_rules! testable_fn {
    ($($name: ident),*) => {

impl<T: Testable,
     $($name: Arbitrary + Debug),*> Testable for fn($($name),*) -> T {
    #[allow(non_snake_case)]
    fn result<G_: Gen>(&self, g: &mut G_) -> TestResult {
        fn shrink_failure<T: Testable, G_: Gen, $($name: Arbitrary + Debug),*>(
                g: &mut G_, self_: fn($($name),*) -> T, a: ($($name,)*)) -> Option<TestResult> {
            for t in a.shrink() {
                let ($($name,)*) = t.clone();
                let mut r_new = safe(move || {self_($($name),*)}).result(g);
                if r_new.is_failure() {
                    let ($($name,)*) : ($($name,)*) = t.clone();
                    r_new.arguments = vec![$(format!("{:?}", $name),)*];

                    // The shrunk value *does* witness a failure, so keep trying
                    // to shrink it.
                    let shrunk = shrink_failure(g, self_, t);

                    // If we couldn't witness a failure on any shrunk value,
                    // then return the failure we already have.
                    return Some(shrunk.unwrap_or(r_new))
                }
            }
            None
        }

        let self_ = *self;
        let a: ($($name,)*) = Arbitrary::arbitrary(g);
        let ( $($name,)* ) = a.clone();
        let mut r = safe(move || {self_($($name),*)}).result(g);

        let ( $($name,)* ) = a.clone();
        r.arguments = vec![$(format!("{:?}", $name),)*];
        match r.status {
            Pass|Discard => r,
            Fail => {
                shrink_failure(g, self_, a).unwrap_or(r)
            }
        }
    }
}}}

testable_fn!();
testable_fn!(A);
testable_fn!(A, B);
testable_fn!(A, B, C);
testable_fn!(A, B, C, D);
testable_fn!(A, B, C, D, E);
testable_fn!(A, B, C, D, E, F);
testable_fn!(A, B, C, D, E, F, G);
testable_fn!(A, B, C, D, E, F, G, H);
testable_fn!(A, B, C, D, E, F, G, H, I);
testable_fn!(A, B, C, D, E, F, G, H, I, J);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K, L);

// TODO(burntsushi): Use `std::thread::catch_panic` once it stabilizes.
fn safe<T, F>(fun: F) -> Result<T, String>
        where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
    let t = ::std::thread::Builder::new().name("safe".into());
    t.spawn(fun).unwrap().join().map_err(|any_err| {
        // Extract common types of panic payload:
        // panic and assert produce &str or String
        if let Some(&s) = any_err.downcast_ref::<&str>() {
            s.to_owned()
        } else if let Some(s) = any_err.downcast_ref::<String>() {
            s.to_owned()
        } else {
            "UNABLE TO SHOW RESULT OF PANIC.".to_owned()
        }
    })
}

/// Convenient aliases.
trait AShow : Arbitrary + Debug {}
impl<A: Arbitrary + Debug> AShow for A {}

#[cfg(test)]
mod test {
    use QuickCheck;

    #[test]
    fn shrinking_regression_issue_126() {
        fn thetest(vals: Vec<bool>) -> bool {
            vals.iter().filter(|&v| *v).count() < 2
        }
        let failing_case = QuickCheck::new().quicktest(thetest as fn(vals: Vec<bool>) -> bool).unwrap_err();
        let expected_argument = format!("{:?}", [true, true]);
        assert_eq!(failing_case.arguments, vec![expected_argument]);
    }
}
<commit_msg>80 cols<commit_after>use rand;
use std::fmt::Debug;
use std::thread;
use super::{Arbitrary, Gen, StdGen};
use tester::Status::{Discard, Fail, Pass};

/// The main QuickCheck type for setting configuration and running QuickCheck.
pub struct QuickCheck<G> {
    tests: usize,
    max_tests: usize,
    gen: G,
}

impl QuickCheck<StdGen<rand::ThreadRng>> {
    /// Creates a new QuickCheck value.
    ///
    /// This can be used to run QuickCheck on things that implement
    /// `Testable`. You may also adjust the configuration, such as
    /// the number of tests to run.
    ///
    /// By default, the maximum number of passed tests is set to `100`,
    /// the max number of overall tests is set to `10000` and the generator
    /// is set to a `StdGen` with a default size of `100`.
    pub fn new() -> QuickCheck<StdGen<rand::ThreadRng>> {
        QuickCheck {
            tests: 100,
            max_tests: 10000,
            gen: StdGen::new(rand::thread_rng(), 100),
        }
    }
}

impl<G: Gen> QuickCheck<G> {
    /// Set the number of tests to run.
    ///
    /// This actually refers to the maximum number of *passed* tests that
    /// can occur. Namely, if a test causes a failure, future testing on that
    /// property stops. Additionally, if tests are discarded, there may be
    /// fewer than `tests` passed.
    pub fn tests(mut self, tests: usize) -> QuickCheck<G> {
        self.tests = tests;
        self
    }

    /// Set the maximum number of tests to run.
    ///
    /// The number of invocations of a property will never exceed this number.
    /// This is necessary to cap the number of tests because QuickCheck
    /// properties can discard tests.
    pub fn max_tests(mut self, max_tests: usize) -> QuickCheck<G> {
        self.max_tests = max_tests;
        self
    }

    /// Set the random number generator to be used by QuickCheck.
    pub fn gen(mut self, gen: G) -> QuickCheck<G> {
        self.gen = gen;
        self
    }

    /// Tests a property and returns the result.
    ///
    /// The result returned is either the number of tests passed or a witness
    /// of failure.
    ///
    /// (If you're using Rust's unit testing infrastructure, then you'll
    /// want to use the `quickcheck` method, which will `panic!` on failure.)
    pub fn quicktest<A>(&mut self, f: A) -> Result<usize, TestResult>
                    where A: Testable {
        let mut ntests: usize = 0;
        for _ in 0..self.max_tests {
            if ntests >= self.tests {
                break
            }
            match f.result(&mut self.gen) {
                TestResult { status: Pass, .. } => ntests += 1,
                TestResult { status: Discard, .. } => continue,
                r @ TestResult { status: Fail, .. } => return Err(r),
            }
        }
        Ok(ntests)
    }

    /// Tests a property and calls `panic!` on failure.
    ///
    /// The `panic!` message will include a (hopefully) minimal witness of
    /// failure.
    ///
    /// It is appropriate to use this method with Rust's unit testing
    /// infrastructure.
    ///
    /// Note that if the environment variable `RUST_LOG` is set to enable
    /// `info` level log messages for the `quickcheck` crate, then this will
    /// include output on how many QuickCheck tests were passed.
    ///
    /// # Example
    ///
    /// ```rust
    /// use quickcheck::QuickCheck;
    ///
    /// fn prop_reverse_reverse() {
    ///     fn revrev(xs: Vec<usize>) -> bool {
    ///         let rev: Vec<_> = xs.clone().into_iter().rev().collect();
    ///         let revrev: Vec<_> = rev.into_iter().rev().collect();
    ///         xs == revrev
    ///     }
    ///     QuickCheck::new().quickcheck(revrev as fn(Vec<usize>) -> bool);
    /// }
    /// ```
    pub fn quickcheck<A>(&mut self, f: A) where A: Testable {
        // Ignore log init failures, implying it has already been done.
        let _ = ::env_logger::init();

        match self.quicktest(f) {
            Ok(ntests) => info!("(Passed {} QuickCheck tests.)", ntests),
            Err(result) => panic!(result.failed_msg()),
        }
    }
}

/// Convenience function for running QuickCheck.
///
/// This is an alias for `QuickCheck::new().quickcheck(f)`.
pub fn quickcheck<A: Testable>(f: A) { QuickCheck::new().quickcheck(f) }

/// Describes the status of a single instance of a test.
///
/// All testable things must be capable of producing a `TestResult`.
#[derive(Clone, Debug)]
pub struct TestResult {
    status: Status,
    arguments: Vec<String>,
    err: Option<String>,
}

/// Whether a test has passed, failed or been discarded.
#[derive(Clone, Debug)]
enum Status { Pass, Fail, Discard }

impl TestResult {
    /// Produces a test result that indicates the current test has passed.
    pub fn passed() -> TestResult { TestResult::from_bool(true) }

    /// Produces a test result that indicates the current test has failed.
    pub fn failed() -> TestResult { TestResult::from_bool(false) }

    /// Produces a test result that indicates failure from a runtime error.
    pub fn error<S: Into<String>>(msg: S) -> TestResult {
        let mut r = TestResult::from_bool(false);
        r.err = Some(msg.into());
        r
    }

    /// Produces a test result that instructs `quickcheck` to ignore it.
    /// This is useful for restricting the domain of your properties.
    /// When a test is discarded, `quickcheck` will replace it with a
    /// fresh one (up to a certain limit).
    pub fn discard() -> TestResult {
        TestResult {
            status: Discard,
            arguments: vec![],
            err: None,
        }
    }

    /// Converts a `bool` to a `TestResult`. A `true` value indicates that
    /// the test has passed and a `false` value indicates that the test
    /// has failed.
    pub fn from_bool(b: bool) -> TestResult {
        TestResult {
            status: if b { Pass } else { Fail },
            arguments: vec![],
            err: None,
        }
    }

    /// Tests if a "procedure" fails when executed. The test passes only if
    /// `f` generates a task failure during its execution.
    pub fn must_fail<T, F>(f: F) -> TestResult
            where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
        TestResult::from_bool(
            thread::Builder::new()
                            .spawn(move || { let _ = f(); })
                            .unwrap()
                            .join()
                            .is_err())
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test.
    pub fn is_failure(&self) -> bool {
        match self.status {
            Fail => true,
            Pass|Discard => false,
        }
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test as a result of a run time error.
    pub fn is_error(&self) -> bool {
        self.is_failure() && self.err.is_some()
    }

    fn failed_msg(&self) -> String {
        match self.err {
            None => {
                format!("[quickcheck] TEST FAILED. Arguments: ({})",
                        self.arguments.connect(", "))
            }
            Some(ref err) => {
                format!("[quickcheck] TEST FAILED (runtime error). \
                         Arguments: ({})\nError: {}",
                        self.arguments.connect(", "), err)
            }
        }
    }
}

/// `Testable` describes types (e.g., a function) whose values can be
/// tested.
///
/// Anything that can be tested must be capable of producing a `TestResult`
/// given a random number generator. This is trivial for types like `bool`,
/// which are just converted to either a passing or failing test result.
///
/// For functions, an implementation must generate random arguments
/// and potentially shrink those arguments if they produce a failure.
///
/// It's unlikely that you'll have to implement this trait yourself.
pub trait Testable : Send + 'static {
    fn result<G: Gen>(&self, &mut G) -> TestResult;
}

impl Testable for bool {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::from_bool(*self)
    }
}

impl Testable for () {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::passed()
    }
}

impl Testable for TestResult {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult { self.clone() }
}

impl<A, E> Testable for Result<A, E>
        where A: Testable, E: Debug + Send + 'static {
    fn result<G: Gen>(&self, g: &mut G) -> TestResult {
        match *self {
            Ok(ref r) => r.result(g),
            Err(ref err) => TestResult::error(format!("{:?}", err)),
        }
    }
}

macro_rules! testable_fn {
    ($($name: ident),*) => {

impl<T: Testable,
     $($name: Arbitrary + Debug),*> Testable for fn($($name),*) -> T {
    #[allow(non_snake_case)]
    fn result<G_: Gen>(&self, g: &mut G_) -> TestResult {
        fn shrink_failure<T: Testable, G_: Gen, $($name: Arbitrary + Debug),*>(
            g: &mut G_,
            self_: fn($($name),*) -> T,
            a: ($($name,)*),
        ) -> Option<TestResult> {
            for t in a.shrink() {
                let ($($name,)*) = t.clone();
                let mut r_new = safe(move || {self_($($name),*)}).result(g);
                if r_new.is_failure() {
                    let ($($name,)*) : ($($name,)*) = t.clone();
                    r_new.arguments = vec![$(format!("{:?}", $name),)*];

                    // The shrunk value *does* witness a failure, so keep
                    // trying to shrink it.
                    let shrunk = shrink_failure(g, self_, t);

                    // If we couldn't witness a failure on any shrunk value,
                    // then return the failure we already have.
                    return Some(shrunk.unwrap_or(r_new))
                }
            }
            None
        }

        let self_ = *self;
        let a: ($($name,)*) = Arbitrary::arbitrary(g);
        let ( $($name,)* ) = a.clone();
        let mut r = safe(move || {self_($($name),*)}).result(g);

        let ( $($name,)* ) = a.clone();
        r.arguments = vec![$(format!("{:?}", $name),)*];
        match r.status {
            Pass|Discard => r,
            Fail => {
                shrink_failure(g, self_, a).unwrap_or(r)
            }
        }
    }
}}}

testable_fn!();
testable_fn!(A);
testable_fn!(A, B);
testable_fn!(A, B, C);
testable_fn!(A, B, C, D);
testable_fn!(A, B, C, D, E);
testable_fn!(A, B, C, D, E, F);
testable_fn!(A, B, C, D, E, F, G);
testable_fn!(A, B, C, D, E, F, G, H);
testable_fn!(A, B, C, D, E, F, G, H, I);
testable_fn!(A, B, C, D, E, F, G, H, I, J);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K, L);

// TODO(burntsushi): Use `std::thread::catch_panic` once it stabilizes.
fn safe<T, F>(fun: F) -> Result<T, String>
        where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
    let t = ::std::thread::Builder::new().name("safe".into());
    t.spawn(fun).unwrap().join().map_err(|any_err| {
        // Extract common types of panic payload:
        // panic and assert produce &str or String
        if let Some(&s) = any_err.downcast_ref::<&str>() {
            s.to_owned()
        } else if let Some(s) = any_err.downcast_ref::<String>() {
            s.to_owned()
        } else {
            "UNABLE TO SHOW RESULT OF PANIC.".to_owned()
        }
    })
}

/// Convenient aliases.
trait AShow : Arbitrary + Debug {}
impl<A: Arbitrary + Debug> AShow for A {}

#[cfg(test)]
mod test {
    use QuickCheck;

    #[test]
    fn shrinking_regression_issue_126() {
        fn thetest(vals: Vec<bool>) -> bool {
            vals.iter().filter(|&v| *v).count() < 2
        }
        let failing_case =
            QuickCheck::new()
            .quicktest(thetest as fn(vals: Vec<bool>) -> bool)
            .unwrap_err();
        let expected_argument = format!("{:?}", [true, true]);
        assert_eq!(failing_case.arguments, vec![expected_argument]);
    }
}
<|endoftext|>