<commit_before>extern crate diesel;
extern crate dotenv;
extern crate kuchiki;
extern crate server;
extern crate serde_json;
use dotenv::dotenv;
use diesel::pg::PgConnection;
use diesel::dsl::{not, sql};
use diesel::sql_types::Bool;
use diesel::prelude::*;
use kuchiki::traits::*;
use server::models::{get_advertiser, get_targets, Ad, get_targetedness_score};
use server::targeting_parser::collect_targeting;
use server::start_logging;
use server::schema::ads::dsl::*;
use std::env;
use serde_json::Value;

fn get_all_targets(all_targetings: Option<Vec<String>>) -> Option<serde_json::Value> {
    match all_targetings {
        None => None,
        Some(all_targetings_vec) => {
            let old_targets : Vec<Value> = vec![];
            let mut all_targets = old_targets.clone();
            for one_targeting in all_targetings_vec.iter() {
                if let Some(new_targets) = get_targets(&Some(one_targeting.to_string())) {
                    let new_targets : Vec<Value> = collect_targeting(&one_targeting.clone()).unwrap_or(vec![])
                        .iter().map(|t| serde_json::to_value(t).unwrap()).collect();
                    all_targets.extend(&mut new_targets.iter().cloned());

                }
            }
            all_targets.sort_unstable_by(|x, y| x.to_string().cmp(&y.to_string()) );
            all_targets.dedup();
            serde_json::to_value(all_targets).ok()
        }
    }

}

fn main() {
    dotenv().ok();
    start_logging();

    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let conn = PgConnection::establish(&database_url).unwrap();
    let dbads: Vec<Ad> = ads.order(created_at.desc())
        .filter(political_probability.gt(0.70))
        .filter(lang.eq("en-US"))
        .filter(not(suppressed.eq(true)))
        .filter(sql::<Bool>("targeting is not null"))
        // .filter(sql::<Bool>("targeting ilike '%part of an audience%'"))
        .load::<Ad>(&conn)
        .unwrap();
    let mut total = 0;
    let mut still_parses_correctly = 0;
    let mut newly_parses_correctly = 0;
    let mut parse_failed = 0;
    let mut parse_got_worse = 0;
    let mut still_doesnt_parse = 0;
    for ad in dbads {
        total += 1;
        let document = kuchiki::parse_html().one(ad.html.clone());
        // find any cases where the revised targeting parser removes an element
        if let Some(ref old_targets) = ad.targets {
            // println!("{:?}",ad.targeting);

            if let Some(new_targets) = get_all_targets(ad.targetings.clone()) {
                if old_targets.to_string().len() > new_targets.to_string().len() {
                    // println!("lost target --> {:?}", ad.id);
                    // println!("{:?}", ad.targeting);
                    // println!("new: {:?}", new_targets);
                    // println!("old: {:?}", old_targets);
                    // println!("");
                    parse_got_worse += 1;
                } else {
                    still_parses_correctly += 1;
                }
            } else {
                if old_targets.as_array().unwrap().len() == 0 {
                    still_doesnt_parse += 1;
                    println!("failed: {:?}", ad.id);
                    println!("targts: {:?}", ad.targetings.clone());
                } else {
                    // println!("failed: {:?}", ad.id);
                    // println!("targts: {:?}", ad.targetings.clone());
                    parse_failed += 1;
                }
            }
        } else {
            if let Some(new_targets) = get_all_targets(ad.targetings.clone()) {
                if new_targets.as_array().unwrap().len() > 0 {
                    newly_parses_correctly += 1;
                    // println!("{:?}", new_targets.as_array().unwrap())
                // how to parse in Ruby.
                // output = open("targeting_output.txt", 'r').read.gsub("\n24865/24877 parse successfully\n1520/24877 now parse correctly\n0/24877 now parse worse than before\n0/24877 newly fail\n12/24877 still fail\n", "")
                // lines = output.gsub("Object(", "").gsub("String(", "").gsub('")', '"').gsub(')}', '').gsub("})", "}").gsub('\\\\"', '"').split("\n")
                // parsed_lines = lines.map{|line| JSON.parse(line)}
                } else {
                    still_doesnt_parse += 1;
                }
            } else {
                still_doesnt_parse += 1;
            }
        }

        diesel::update(ads.find(ad.id))
            .set((
                targets.eq(get_all_targets(ad.targetings.clone())),
                advertiser.eq(get_advertiser(&ad.targeting, &document)),
                targetedness.eq(get_targetedness_score(get_all_targets(ad.targetings.clone())))
            ))
            .execute(&conn)
            .unwrap();
    }
    println!(
        "{:?}/{:?} parse successfully",
        still_parses_correctly + newly_parses_correctly + parse_got_worse,
        total
    );
    println!(
        "{:?}/{:?} now parse correctly",
        newly_parses_correctly, total
    );
    println!(
        "{:?}/{:?} now parse worse than before",
        parse_got_worse, total
    );
    println!("{:?}/{:?} newly fail", parse_failed, total);
    println!("{:?}/{:?} still fail", still_doesnt_parse, total);
}
<commit_msg>print targeting strings that won't parse<commit_after>extern crate diesel;
extern crate dotenv;
extern crate kuchiki;
extern crate server;
extern crate serde_json;
use dotenv::dotenv;
use diesel::pg::PgConnection;
use diesel::dsl::{not, sql};
use diesel::sql_types::Bool;
use diesel::prelude::*;
use kuchiki::traits::*;
use server::models::{get_advertiser, get_targets, Ad, get_targetedness_score};
use server::targeting_parser::collect_targeting;
use server::start_logging;
use server::schema::ads::dsl::*;
use std::env;
use serde_json::Value;

fn get_all_targets(all_targetings: Option<Vec<String>>) -> Option<serde_json::Value> {
    match all_targetings {
        None => None,
        Some(all_targetings_vec) => {
            let old_targets : Vec<Value> = vec![];
            let mut all_targets = old_targets.clone();
            for one_targeting in all_targetings_vec.iter() {
                if let Some(new_targets) = get_targets(&Some(one_targeting.to_string())) {
                    let new_targets : Vec<Value> = collect_targeting(&one_targeting.clone()).unwrap_or(vec![])
                        .iter().map(|t| serde_json::to_value(t).unwrap()).collect();
                    all_targets.extend(&mut new_targets.iter().cloned());

                }
            }
            all_targets.sort_unstable_by(|x, y| x.to_string().cmp(&y.to_string()) );
            all_targets.dedup();
            serde_json::to_value(all_targets).ok()
        }
    }

}

fn main() {
    dotenv().ok();
    start_logging();

    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let conn = PgConnection::establish(&database_url).unwrap();
    let dbads: Vec<Ad> = ads.order(created_at.desc())
        .filter(political_probability.gt(0.70))
        .filter(lang.eq("en-US"))
        .filter(not(suppressed.eq(true)))
        .filter(sql::<Bool>("targeting is not null"))
        // .filter(sql::<Bool>("targeting ilike '%part of an audience%'"))
        .load::<Ad>(&conn)
        .unwrap();
    let mut total = 0;
    let mut still_parses_correctly = 0;
    let mut newly_parses_correctly = 0;
    let mut parse_failed = 0;
    let mut parse_got_worse = 0;
    let mut still_doesnt_parse = 0;
    for ad in dbads {
        total += 1;
        let document = kuchiki::parse_html().one(ad.html.clone());
        // find any cases where the revised targeting parser removes an element
        if let Some(ref old_targets) = ad.targets {
            // println!("{:?}",ad.targeting);

            if let Some(new_targets) = get_all_targets(ad.targetings.clone()) {
                if old_targets.to_string().len() > new_targets.to_string().len() {
                    // println!("lost target --> {:?}", ad.id);
                    // println!("{:?}", ad.targeting);
                    // println!("new: {:?}", new_targets);
                    // println!("old: {:?}", old_targets);
                    // println!("");
                    parse_got_worse += 1;
                } else {
                    still_parses_correctly += 1;
                }
            } else {
                if old_targets.as_array().unwrap().len() == 0 {
                    still_doesnt_parse += 1;
                    println!("failed: {:?}", ad.id);
                    println!("targts: {:?}", ad.targetings.clone());
                } else {
                    // println!("failed: {:?}", ad.id);
                    // println!("targts: {:?}", ad.targetings.clone());
                    parse_failed += 1;
                }
            }
        } else {
            if let Some(new_targets) = get_all_targets(ad.targetings.clone()) {
                if new_targets.as_array().unwrap().len() > 0 {
                    newly_parses_correctly += 1;
                    // println!("{:?}", new_targets.as_array().unwrap())
                // how to parse in Ruby.
                // output = open("targeting_output.txt", 'r').read.gsub("\n24865/24877 parse successfully\n1520/24877 now parse correctly\n0/24877 now parse worse than before\n0/24877 newly fail\n12/24877 still fail\n", "")
                // lines = output.gsub("Object(", "").gsub("String(", "").gsub('")', '"').gsub(')}', '').gsub("})", "}").gsub('\\\\"', '"').split("\n")
                // parsed_lines = lines.map{|line| JSON.parse(line)}
                } else {
                    still_doesnt_parse += 1;

                }
            } else {
                still_doesnt_parse += 1;
                println!("failed: {:?}", ad.id);
                println!("targts: {:?}", ad.targeting.clone());
                println!("targts: {:?}", ad.targetings.clone());
            }
        }

        diesel::update(ads.find(ad.id))
            .set((
                targets.eq(get_all_targets(ad.targetings.clone())),
                advertiser.eq(get_advertiser(&ad.targeting, &document)),
                targetedness.eq(get_targetedness_score(get_all_targets(ad.targetings.clone())))
            ))
            .execute(&conn)
            .unwrap();
    }
    println!(
        "{:?}/{:?} parse successfully",
        still_parses_correctly + newly_parses_correctly + parse_got_worse,
        total
    );
    println!(
        "{:?}/{:?} now parse correctly",
        newly_parses_correctly, total
    );
    println!(
        "{:?}/{:?} now parse worse than before",
        parse_got_worse, total
    );
    println!("{:?}/{:?} newly fail", parse_failed, total);
    println!("{:?}/{:?} still fail", still_doesnt_parse, total);
}
<|endoftext|>


<commit_before>use nix::sys::socket::{InetAddr, UnixAddr, getsockname};
use std::{mem, slice};
use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6};
use std::path::Path;
use std::str::FromStr;
use std::os::unix::io::RawFd;
use libc::c_char;

#[test]
pub fn test_inetv4_addr_to_sock_addr() {
    let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
    let addr = InetAddr::from_std(&actual);

    match addr {
        InetAddr::V4(addr) => {
            let ip: u32 = 0x7f000001;
            let port: u16 = 3000;

            assert_eq!(addr.sin_addr.s_addr, ip.to_be());
            assert_eq!(addr.sin_port, port.to_be());
        }
        _ => panic!("nope"),
    }

    assert_eq!(addr.to_str(), "127.0.0.1:3000");

    let inet = addr.to_std();
    assert_eq!(actual, inet);
}

#[test]
pub fn test_inetv6_addr_to_sock_addr() {
    let port: u16 = 3000;
    let flowinfo: u32 = 1;
    let scope_id: u32 = 2;
    let ip: Ipv6Addr = "fe80::1".parse().unwrap();

    let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
    let addr = InetAddr::from_std(&actual);

    match addr {
        InetAddr::V6(addr) => {
            assert_eq!(addr.sin6_port, port.to_be());
            assert_eq!(addr.sin6_flowinfo, flowinfo);
            assert_eq!(addr.sin6_scope_id, scope_id);
        }
        _ => panic!("nope"),
    }

    assert_eq!(actual, addr.to_std());
}

#[test]
pub fn test_path_to_sock_addr() {
    let path = "/foo/bar";
    let actual = Path::new(path);
    let addr = UnixAddr::new(actual).unwrap();

    let expect: &[c_char] = unsafe {
        slice::from_raw_parts(path.as_bytes().as_ptr() as *const c_char, path.len())
    };
    assert_eq!(&addr.0.sun_path[..8], expect);

    assert_eq!(addr.path(), Some(actual));
}

#[test]
pub fn test_getsockname() {
    use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
    use nix::sys::socket::{bind, SockAddr};
    use tempdir::TempDir;

    let tempdir = TempDir::new("test_getsockname").unwrap();
    let sockname = tempdir.path().join("sock");
    let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
               .expect("socket failed");
    let sockaddr = SockAddr::new_unix(&sockname).unwrap();
    bind(sock, &sockaddr).expect("bind failed");
    assert_eq!(sockaddr.to_str(),
               getsockname(sock).expect("getsockname failed").to_str());
}

#[test]
pub fn test_socketpair() {
    use nix::unistd::{read, write};
    use nix::sys::socket::{socketpair, AddressFamily, SockType, SockFlag};

    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
                     .unwrap();
    write(fd1, b"hello").unwrap();
    let mut buf = [0;5];
    read(fd2, &mut buf).unwrap();

    assert_eq!(&buf[..], b"hello");
}

#[test]
pub fn test_scm_rights() {
    use nix::sys::uio::IoVec;
    use nix::unistd::{pipe, read, write, close};
    use nix::sys::socket::{socketpair, sendmsg, recvmsg,
                           AddressFamily, SockType, SockFlag,
                           ControlMessage, CmsgSpace, MsgFlags,
                           MSG_TRUNC, MSG_CTRUNC};

    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
                     .unwrap();
    let (r, w) = pipe().unwrap();
    let mut received_r: Option<RawFd> = None;

    {
        let iov = [IoVec::from_slice(b"hello")];
        let fds = [r];
        let cmsg = ControlMessage::ScmRights(&fds);
        assert_eq!(sendmsg(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
        close(r).unwrap();
        close(fd1).unwrap();
    }

    {
        let mut buf = [0u8; 5];
        let iov = [IoVec::from_mut_slice(&mut buf[..])];
        let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new();
        let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();

        for cmsg in msg.cmsgs() {
            if let ControlMessage::ScmRights(fd) = cmsg {
                assert_eq!(received_r, None);
                assert_eq!(fd.len(), 1);
                received_r = Some(fd[0]);
            } else {
                panic!("unexpected cmsg");
            }
        }
        assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC));
        close(fd2).unwrap();
    }

    let received_r = received_r.expect("Did not receive passed fd");
    // Ensure that the received file descriptor works
    write(w, b"world").unwrap();
    let mut buf = [0u8; 5];
    read(received_r, &mut buf).unwrap();
    assert_eq!(&buf[..], b"world");
    close(received_r).unwrap();
    close(w).unwrap();
}

// Verify `sendmsg` builds a valid `msghdr` when passing an empty
// `cmsgs` argument.  This should result in a msghdr with a nullptr
// msg_control field and a msg_controllen of 0 when calling into the
// raw `sendmsg`.
#[test]
pub fn test_sendmsg_empty_cmsgs() {
    use nix::sys::uio::IoVec;
    use nix::unistd::close;
    use nix::sys::socket::{socketpair, sendmsg, recvmsg,
                           AddressFamily, SockType, SockFlag,
                           CmsgSpace, MsgFlags,
                           MSG_TRUNC, MSG_CTRUNC};

    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
                     .unwrap();

    {
        let iov = [IoVec::from_slice(b"hello")];
        assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5);
        close(fd1).unwrap();
    }

    {
        let mut buf = [0u8; 5];
        let iov = [IoVec::from_mut_slice(&mut buf[..])];
        let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new();
        let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();

        for _ in msg.cmsgs() {
            panic!("unexpected cmsg");
        }
        assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC));
        close(fd2).unwrap();
    }
}

// Test creating and using named unix domain sockets
#[test]
pub fn test_unixdomain() {
    use nix::sys::socket::{AddressFamily, SockType, SockFlag};
    use nix::sys::socket::{bind, socket, connect, listen, accept, SockAddr};
    use nix::unistd::{read, write, close};
    use std::thread;
    use tempdir::TempDir;

    let tempdir = TempDir::new("test_unixdomain").unwrap();
    let sockname = tempdir.path().join("sock");
    let s1 = socket(AddressFamily::Unix, SockType::Stream,
                    SockFlag::empty(), None).expect("socket failed");
    let sockaddr = SockAddr::new_unix(&sockname).unwrap();
    bind(s1, &sockaddr).expect("bind failed");
    listen(s1, 10).expect("listen failed");

    let thr = thread::spawn(move || {
        let s2 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
                 .expect("socket failed");
        connect(s2, &sockaddr).expect("connect failed");
        write(s2, b"hello").expect("write failed");
        close(s2).unwrap();
    });

    let s3 = accept(s1).expect("accept failed");

    let mut buf = [0;5];
    read(s3, &mut buf).unwrap();
    close(s3).unwrap();
    close(s1).unwrap();
    thr.join().unwrap();

    assert_eq!(&buf[..], b"hello");
}

// Test creating and using named system control sockets
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[test]
pub fn test_syscontrol() {
    use nix::{Errno, Error};
    use nix::sys::socket::{AddressFamily, socket, SockAddr, SockType, SockFlag, SockProtocol};

    let fd = socket(AddressFamily::System, SockType::Datagram,
                    SockFlag::empty(), SockProtocol::KextControl)
             .expect("socket failed");
    let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed");
    assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT)));

    // requires root privileges
    // connect(fd, &sockaddr).expect("connect failed");
}
<commit_msg>Fix unused variable in tests<commit_after>use nix::sys::socket::{InetAddr, UnixAddr, getsockname};
use std::slice;
use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6};
use std::path::Path;
use std::str::FromStr;
use std::os::unix::io::RawFd;
use libc::c_char;

#[test]
pub fn test_inetv4_addr_to_sock_addr() {
    let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
    let addr = InetAddr::from_std(&actual);

    match addr {
        InetAddr::V4(addr) => {
            let ip: u32 = 0x7f000001;
            let port: u16 = 3000;

            assert_eq!(addr.sin_addr.s_addr, ip.to_be());
            assert_eq!(addr.sin_port, port.to_be());
        }
        _ => panic!("nope"),
    }

    assert_eq!(addr.to_str(), "127.0.0.1:3000");

    let inet = addr.to_std();
    assert_eq!(actual, inet);
}

#[test]
pub fn test_inetv6_addr_to_sock_addr() {
    let port: u16 = 3000;
    let flowinfo: u32 = 1;
    let scope_id: u32 = 2;
    let ip: Ipv6Addr = "fe80::1".parse().unwrap();

    let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
    let addr = InetAddr::from_std(&actual);

    match addr {
        InetAddr::V6(addr) => {
            assert_eq!(addr.sin6_port, port.to_be());
            assert_eq!(addr.sin6_flowinfo, flowinfo);
            assert_eq!(addr.sin6_scope_id, scope_id);
        }
        _ => panic!("nope"),
    }

    assert_eq!(actual, addr.to_std());
}

#[test]
pub fn test_path_to_sock_addr() {
    let path = "/foo/bar";
    let actual = Path::new(path);
    let addr = UnixAddr::new(actual).unwrap();

    let expect: &[c_char] = unsafe {
        slice::from_raw_parts(path.as_bytes().as_ptr() as *const c_char, path.len())
    };
    assert_eq!(&addr.0.sun_path[..8], expect);

    assert_eq!(addr.path(), Some(actual));
}

#[test]
pub fn test_getsockname() {
    use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
    use nix::sys::socket::{bind, SockAddr};
    use tempdir::TempDir;

    let tempdir = TempDir::new("test_getsockname").unwrap();
    let sockname = tempdir.path().join("sock");
    let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
               .expect("socket failed");
    let sockaddr = SockAddr::new_unix(&sockname).unwrap();
    bind(sock, &sockaddr).expect("bind failed");
    assert_eq!(sockaddr.to_str(),
               getsockname(sock).expect("getsockname failed").to_str());
}

#[test]
pub fn test_socketpair() {
    use nix::unistd::{read, write};
    use nix::sys::socket::{socketpair, AddressFamily, SockType, SockFlag};

    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
                     .unwrap();
    write(fd1, b"hello").unwrap();
    let mut buf = [0;5];
    read(fd2, &mut buf).unwrap();

    assert_eq!(&buf[..], b"hello");
}

#[test]
pub fn test_scm_rights() {
    use nix::sys::uio::IoVec;
    use nix::unistd::{pipe, read, write, close};
    use nix::sys::socket::{socketpair, sendmsg, recvmsg,
                           AddressFamily, SockType, SockFlag,
                           ControlMessage, CmsgSpace, MsgFlags,
                           MSG_TRUNC, MSG_CTRUNC};

    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
                     .unwrap();
    let (r, w) = pipe().unwrap();
    let mut received_r: Option<RawFd> = None;

    {
        let iov = [IoVec::from_slice(b"hello")];
        let fds = [r];
        let cmsg = ControlMessage::ScmRights(&fds);
        assert_eq!(sendmsg(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
        close(r).unwrap();
        close(fd1).unwrap();
    }

    {
        let mut buf = [0u8; 5];
        let iov = [IoVec::from_mut_slice(&mut buf[..])];
        let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new();
        let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();

        for cmsg in msg.cmsgs() {
            if let ControlMessage::ScmRights(fd) = cmsg {
                assert_eq!(received_r, None);
                assert_eq!(fd.len(), 1);
                received_r = Some(fd[0]);
            } else {
                panic!("unexpected cmsg");
            }
        }
        assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC));
        close(fd2).unwrap();
    }

    let received_r = received_r.expect("Did not receive passed fd");
    // Ensure that the received file descriptor works
    write(w, b"world").unwrap();
    let mut buf = [0u8; 5];
    read(received_r, &mut buf).unwrap();
    assert_eq!(&buf[..], b"world");
    close(received_r).unwrap();
    close(w).unwrap();
}

// Verify `sendmsg` builds a valid `msghdr` when passing an empty
// `cmsgs` argument.  This should result in a msghdr with a nullptr
// msg_control field and a msg_controllen of 0 when calling into the
// raw `sendmsg`.
#[test]
pub fn test_sendmsg_empty_cmsgs() {
    use nix::sys::uio::IoVec;
    use nix::unistd::close;
    use nix::sys::socket::{socketpair, sendmsg, recvmsg,
                           AddressFamily, SockType, SockFlag,
                           CmsgSpace, MsgFlags,
                           MSG_TRUNC, MSG_CTRUNC};

    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
                     .unwrap();

    {
        let iov = [IoVec::from_slice(b"hello")];
        assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5);
        close(fd1).unwrap();
    }

    {
        let mut buf = [0u8; 5];
        let iov = [IoVec::from_mut_slice(&mut buf[..])];
        let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new();
        let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();

        for _ in msg.cmsgs() {
            panic!("unexpected cmsg");
        }
        assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC));
        close(fd2).unwrap();
    }
}

// Test creating and using named unix domain sockets
#[test]
pub fn test_unixdomain() {
    use nix::sys::socket::{AddressFamily, SockType, SockFlag};
    use nix::sys::socket::{bind, socket, connect, listen, accept, SockAddr};
    use nix::unistd::{read, write, close};
    use std::thread;
    use tempdir::TempDir;

    let tempdir = TempDir::new("test_unixdomain").unwrap();
    let sockname = tempdir.path().join("sock");
    let s1 = socket(AddressFamily::Unix, SockType::Stream,
                    SockFlag::empty(), None).expect("socket failed");
    let sockaddr = SockAddr::new_unix(&sockname).unwrap();
    bind(s1, &sockaddr).expect("bind failed");
    listen(s1, 10).expect("listen failed");

    let thr = thread::spawn(move || {
        let s2 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
                 .expect("socket failed");
        connect(s2, &sockaddr).expect("connect failed");
        write(s2, b"hello").expect("write failed");
        close(s2).unwrap();
    });

    let s3 = accept(s1).expect("accept failed");

    let mut buf = [0;5];
    read(s3, &mut buf).unwrap();
    close(s3).unwrap();
    close(s1).unwrap();
    thr.join().unwrap();

    assert_eq!(&buf[..], b"hello");
}

// Test creating and using named system control sockets
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[test]
pub fn test_syscontrol() {
    use nix::{Errno, Error};
    use nix::sys::socket::{AddressFamily, socket, SockAddr, SockType, SockFlag, SockProtocol};

    let fd = socket(AddressFamily::System, SockType::Datagram,
                    SockFlag::empty(), SockProtocol::KextControl)
             .expect("socket failed");
    let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed");
    assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT)));

    // requires root privileges
    // connect(fd, &sockaddr).expect("connect failed");
}
<|endoftext|>


<commit_before>
#![allow(unused_variables)]
#![allow(dead_code)]

/// Basic structure of a Monitor (aka Server App, aka wtttttt)
///
/// Monitors are designed so that the FoxBox can offer a simple
/// IFTTT-style Web UX to let users write their own scripts. More
/// complex monitors can installed from the web from a master device
/// (i.e. the user's cellphone or smart tv).

use dependencies::{DeviceKind, InputCapability, OutputCapability, Device, Range, Watcher, Witness};

use std::time::Duration;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

extern crate rustc_serialize;
use self::rustc_serialize::json::Json;

extern crate itertools;
use self::itertools::Zip;

/// A Monitor Application, i.e. an application (or a component of an
/// application) executed on the server.
///
/// Monitor applications are typically used for triggering an action
/// in reaction to an event: changing temperature when night falls,
/// ringing an alarm when a door is opened, etc.
///
/// Monitor applications are installed from a paired device. They may
/// either be part of a broader application (which can install them
/// through a web/REST API) or live on their own.
#[derive(Clone)]
struct MonitorApp {
    metadata: (), // FIXME: Authorizations, author, description, update url, version, ...

    /// `true` if the app is on, `false` otherwise.
    is_active: bool,

    /// Monitor applications have sets of requirements (e.g. "I need a
    /// camera"), which are allocated to actual resources through the
    /// UX. Re-allocating resources may be requested by the user, the
    /// foxbox, or an application, e.g. when replacing a device or
    /// upgrading the app.
    ///
    /// The position in the vector is important, as it is used to
    /// represent the instances of resources in the script.
    ///
    /// FIXME: Turn this `Vec` (and others) into a data structure in
    /// which this indexing property is built-in.
    requirements: Vec<Named<Requirement>>,

    /// For each requirement, the resources actually allocated to
    /// match the requirements. This may be 1 or more individual
    /// devices.
    ///
    /// Allocations can be done in several ways:
    ///
    /// - when entering the script through a UX (either the script or
    ///   the UX can suggest allocations);
    /// - when installing an application with a web front-end.
    allocations: Vec<Vec<Named<Arc<Device>>>>,

    code: Vec<Trigger>,

    is_running: bool,
}

struct ConditionState {
    are_conditions_met: bool
}

type InputState = Vec<Vec<Vec<Option<Json>>>>;
struct MonitorTask {
    watcher: Watcher,

    // Invariant: len() is the same as that of app.code
    trigger_condition_state: Vec<ConditionState>,

    /// For each device set allocated, for each individual device
    /// allocated, for each input watched by the app, the latest state
    /// received.
    // Invariant: outer len() is the same as that of self.requirements.
    // Invariant: inner len() is the same as number of input devices bound
    // to the corresponding requirement. May be empty.
    input_state: InputState,

    witnesses: Vec<Witness>,

    tx: Sender<MonitorOp>,
    rx: Receiver<MonitorOp>,

    app: MonitorApp,
}

impl MonitorTask {
    fn new(app: MonitorApp) -> Self {
        // Initialize condition state.
        let mut trigger_condition_state = Vec::with_capacity(app.code.len());
        for _ in &app.code {
            trigger_condition_state.push(ConditionState {
                are_conditions_met: false,
            });
        }
        assert_eq!(trigger_condition_state.len(), app.code.len());

        // Initialize input state.
        let mut full_input_state = Vec::with_capacity(app.requirements.len());
        for (req, allocation) in app.requirements.iter().zip(&app.allocations) {

            // State for this allocation. A single allocation may map
            // to a number of inputs (e.g. "all fire alarms").
            let mut allocation_state = Vec::with_capacity(allocation.len());
            for individual_device in allocation {
                let mut individual_device_state = Vec::with_capacity(req.data.inputs.len());
                for _ in 0 .. req.data.inputs.len() {
                    individual_device_state.push(None);
                }
                allocation_state.push(individual_device_state);
            }
            assert_eq!(allocation_state.len(), allocation.len());
            full_input_state.push(allocation_state);
        }
        assert_eq!(full_input_state.len(), app.requirements.len());

        // Start watching
        let mut watcher = Watcher::new();
        let mut witnesses = Vec::new();
        let (tx, rx) = channel();

        for (req, allocation, allocation_state, allocation_index) in Zip::new((&app.requirements, &app.allocations, &full_input_state, 0..)) {
            for (individual_device, individual_device_state, individual_device_index) in Zip::new((allocation, allocation_state, 0..)) {
                for (input, individual_input_state, individual_input_index) in Zip::new((&req.data.inputs, individual_device_state, 0..)) {
                    // FIXME: We currently use `Range::any()` for simplicity.
                    // However, in most cases, we should be able to look inside
                    // the condition to build a better `Range`.
                    witnesses.push(
                        watcher.add(
                            &individual_device.data,
                            &input.data,
                            &Range::any(),
                            |data| {
                                let _ = tx.send(MonitorOp::Update {
                                    data: data,
                                    allocation_index: allocation_index,
                                    individual_device_index: individual_device_index,
                                    individual_input_index: individual_input_index
                                }); // FIXME: Find a better structure than sending indices.
                                // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                            }));
                }
            }
        }

        MonitorTask {
            watcher: watcher,
            trigger_condition_state: trigger_condition_state,
            input_state: full_input_state,
            witnesses: witnesses,
            app: app,
            tx: tx,
            rx: rx,
        }
    }

    fn run(&mut self) {
        for msg in &self.rx {
            use self::MonitorOp::*;
            match msg {
                Update {
                    data,
                    allocation_index,
                    individual_device_index,
                    individual_input_index
                } => { // FIXME: Three raw indices make for a crappy data structure.
                    // Update the state
                    self.input_state[allocation_index][individual_device_index][individual_input_index] = Some(data);

                    // Find out if we should execute triggers.
                    // FIXME: We could optimize this by finding out which triggers
                    // are tainted by the update and only rechecking these.
                    for (trigger, trigger_condition_state) in Zip::new((&self.app.code, &mut self.trigger_condition_state)) {
                        if trigger.condition.is_met(&self.input_state) {
                            if !trigger_condition_state.are_conditions_met {
                                // Conditions were not met, now they are, so it is
                                // time to start executing. We copy the inputs
                                // and dispatch to a background thread

                                // FIXME: Handle cooldown.

                                trigger_condition_state.are_conditions_met = true;
                                let _ = self.tx.send(MonitorOp::Execute {
                                    state: self.input_state.clone(),
                                    commands: trigger.execute.clone()
                                }); // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                            }
                        } else {
                            trigger_condition_state.are_conditions_met = false;
                        }
                    }
                },
                Execute {..} => {
                    panic!("Not implemented");
                }
                Stop => {
                    // Clean up watcher, stop the thread.
                    self.witnesses.clear();
                    return;
                }
            }
        }
    }
}

enum MonitorOp {
    Update{data: Json, allocation_index: usize, individual_device_index: usize, individual_input_index: usize},
    Execute{state: InputState, commands: Vec<Command>},
    Stop
}

impl MonitorApp {
    pub fn start(&mut self) {
        if self.is_running {
            return;
        }
        self.is_running = true;

        let mut task = MonitorTask::new(self.clone());
        thread::spawn(move || {
            task.run();
        });
    }
}

/// Data labelled with a user-readable name.
#[derive(Clone)]
struct Named<T> {
    /// User-readable name.
    name: String,

    data: T,
}

/// A resource needed by this application. Typically, a definition of
/// device with some input our output capabilities.
#[derive(Clone)]
struct Requirement {
    /// The kind of resource, e.g. "a flashbulb".
    kind: DeviceKind,

    /// Input capabilities we need from the device, e.g. "the time of
    /// day", "the current temperature".
    inputs: Vec<Named<InputCapability>>,

    /// Output capabilities we need from the device, e.g. "play a
    /// sound", "set luminosity".
    outputs: Vec<Named<OutputCapability>>,

    /// Minimal number of resources required. If unspecified in the
    /// script, this is 1.
    min: u32,

    /// Maximal number of resources that may be handled. If
    /// unspecified in the script, this is the same as `min`.
    max: u32,

    // FIXME: We may need cooldown properties.
}

/// A single trigger, i.e. "when some condition becomes true, do
/// something".
#[derive(Clone)]
struct Trigger {
    /// The condition in which to execute the trigger.
    condition: Disjunction,

    /// Stuff to do once `condition` is met.
    execute: Vec<Command>,

    /// Minimal duration between two executions of the trigger.  If a
    /// duration was not picked by the developer, a reasonable default
    /// duration should be picked (e.g. 10 minutes).
    cooldown: Duration,
}

/// A disjunction (e.g. a "or") of conditions.
///
/// # Example
///
/// Door alarm #1 OR door alarm #2
#[derive(Clone)]
struct Disjunction {
    /// The disjunction is true iff any of the following conjunctions is true.
    any: Vec<Conjunction>
}

impl Disjunction {
    fn is_met(&self, input_state: &InputState) -> bool {
        panic!("Not implemented");
    }
}

/// A conjunction (e.g. a "and") of conditions.
#[derive(Clone)]
struct Conjunction {
    /// The conjunction is true iff all of the following expressions evaluate to true.
    all: Vec<Expression>
}

#[derive(Clone)]
enum Value {
    Json(Json),
    Blob{data: Arc<Vec<u8>>, mime_type: String},
}

/// An expression in the language.  Note that expressions may contain
/// inputs, which are typically asynchronous. Consequently,
/// expressions are evaluated asynchronously.
#[derive(Clone)]
enum Expression {
    Const {
        value: Value,

        /// We are dealing with real-world values, so physical units
        /// will prevent real-world accidents.
        unit: (), // FIXME: An actual unit

        /// The source for this value.  Used whenever we need to find
        /// out which sensor triggered the trigger (e.g. "where is the
        /// fire?").
        sources: Vec<usize>,
    },

    /// Dynamic values, including both actual sensors and higher-level values.
    ///
    /// # Example
    ///
    /// "Is there movement on motion detector" (may be true/false)
    ///
    /// # Example
    ///
    /// "Date of the latest motion on motion detector" (a Date)
    Input {
        /// A reference to the device used for input.
        /// This is an index in `requirements` and `allocations`.
        index: usize, // FIXME: We should use a custom type.

        /// A property to fetch (e.g. "luminosity" or "meta/latest-on").
        property: InputCapability,
    },

    /// Pure functions on values. The fact that they are pure
    /// functions is important, as it lets us find out automatically
    /// which subexpressions (including inputs) do not need to be
    /// re-evaluated.
    Function {
        function: Function,
        // FIXME: use a Box<> for now to avoid recursive type.
        arguments: Vec<Box<Expression>>
    },
}

#[derive(Clone)]
enum Function {
    // Operations on all values.
    InRange,
    OutOfRange,
    // Operations on strings
    Contains,
    NotContains,
}

/*
enum Function {
    // Operations on all values.
    Equals,
    NotEquals,

    // Operations on numbers, dates, durations.
    GreaterEq,
    Greater,
    LowerEq,
    Lower,
    Plus,
    Minus,

    // Operations on strings
    Contains,
    NotContains,

    // Etc.  FIXME: We'll need operations on dates, extracting name
    // from device, etc.
}
 */

/// Stuff to actually do. In practice, this is always a REST call.
// FIXME: Need to decide how much we wish to sandbox apps.
#[derive(Clone)]
struct Command {
    /// The resource to which this command applies,
    /// as an index in Trigger.requirements/allocations.
    destination: usize,  // FIXME: Use custom type.

    action: OutputCapability,

    arguments: HashMap<String, Option<Expression>>
}

<commit_msg>[fxbox/thinkerbell] Got rid of most uses of ugly unyped indices<commit_after>
#![allow(unused_variables)]
#![allow(dead_code)]

/// Basic structure of a Monitor (aka Server App, aka wtttttt)
///
/// Monitors are designed so that the FoxBox can offer a simple
/// IFTTT-style Web UX to let users write their own scripts. More
/// complex monitors can installed from the web from a master device
/// (i.e. the user's cellphone or smart tv).

use dependencies::{DeviceKind, InputCapability, OutputCapability, Device, Range, Watcher, Witness};

use std::time::Duration;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

extern crate rustc_serialize;
use self::rustc_serialize::json::Json;

extern crate itertools;
use self::itertools::Zip;

/// A Monitor Application, i.e. an application (or a component of an
/// application) executed on the server.
///
/// Monitor applications are typically used for triggering an action
/// in reaction to an event: changing temperature when night falls,
/// ringing an alarm when a door is opened, etc.
///
/// Monitor applications are installed from a paired device. They may
/// either be part of a broader application (which can install them
/// through a web/REST API) or live on their own.
#[derive(Clone)]
struct MonitorApp {
    metadata: (), // FIXME: Authorizations, author, description, update url, version, ...

    /// `true` if the app is on, `false` otherwise.
    is_active: bool,

    /// Monitor applications have sets of requirements (e.g. "I need a
    /// camera"), which are allocated to actual resources through the
    /// UX. Re-allocating resources may be requested by the user, the
    /// foxbox, or an application, e.g. when replacing a device or
    /// upgrading the app.
    ///
    /// The position in the vector is important, as it is used to
    /// represent the instances of resources in the script.
    ///
    /// FIXME: Turn this `Vec` (and others) into a data structure in
    /// which this indexing property is built-in.
    requirements: Vec<Named<Requirement>>,

    /// For each requirement, the resources actually allocated to
    /// match the requirements. This may be 1 or more individual
    /// devices.
    ///
    /// Allocations can be done in several ways:
    ///
    /// - when entering the script through a UX (either the script or
    ///   the UX can suggest allocations);
    /// - when installing an application with a web front-end.
    allocations: Vec<Vec<Named<Arc<Device>>>>,

    code: Vec<Trigger>,

    is_running: bool,
}

impl<'a> MonitorApp {
/*
    Ideally, I'd like something along these lines.
    But, as rustc kindly pointed out to me, that's pretty much unsafe.

    fn iter_state_index(&'a self) -> Box<Iterator<Item=InputIndex> + 'a>
    {
        Box::new(
            Zip::new((&self.requirements, &self.allocations, 0..)).
                flat_map(|(req, allocation, allocation_index)| {
                    let allocation_index_clone = allocation_index.clone();
                    Zip::new((allocation, 0..)).
                        flat_map(|(individual_device, individual_device_index)| {
                            Zip::new((&req.data.inputs, 0..)).
                                map(|(_, individual_input_index)| {
                                    InputIndex {
                                        allocation: allocation_index_clone,
                                        device: individual_device_index,
                                        input: individual_input_index
                                    }
                                })
                        })
                }))
}
     */
    fn iter_state_index(&'a self) -> Vec<InputIndex>
    {
        let mut vec = Vec::new();
        for (req, allocation, allocation_index) in Zip::new((&self.requirements, &self.allocations, 0..)) {
            for (individual_device, individual_device_index) in Zip::new((allocation, 0..)) {
                for (input, individual_input_index) in Zip::new((&req.data.inputs, 0..)) {
                    vec.push(InputIndex {
                        allocation: allocation_index,
                        device: individual_device_index,
                        input: individual_input_index
                    })
                }
            }
        }
        vec
    }

    fn get_individual_device(&self, index: &InputIndex) -> Arc<Device> {
        self.allocations[index.allocation][index.device].data.clone()
    }

    fn get_input(&self, index: &InputIndex) -> InputCapability {
        self.requirements[index.allocation].data.inputs[index.input].data.clone()
    }
}

struct InputIndex {
    allocation: usize,
    device: usize,
    input: usize,
}

struct ConditionState {
    are_conditions_met: bool
}

type InputState = Vec<Vec<Vec<Option<Json>>>>;
struct MonitorTaskState {
    // Invariant: len() is the same as that of app.code
    trigger_condition_state: Vec<ConditionState>,

    /// For each device set allocated, for each individual device
    /// allocated, for each input watched by the app, the latest state
    /// received.
    // Invariant: outer len() is the same as that of self.requirements.
    // Invariant: inner len() is the same as number of input devices bound
    // to the corresponding requirement. May be empty.
    input_state: InputState,

    witnesses: Vec<Witness>,

    app: MonitorApp,
}
impl MonitorTaskState {
    fn set_state(&mut self, index: &InputIndex, value: Option<Json>) {
        self.input_state[index.allocation][index.device][index.input] = value;
    }
}

struct MonitorComm {
    tx: Sender<MonitorOp>,
    rx: Receiver<MonitorOp>,
}
struct MonitorTask {
    state: MonitorTaskState,
    comm: MonitorComm,
}

impl MonitorTask {
    fn new(app: MonitorApp) -> Self {
        // Initialize condition state.
        let mut trigger_condition_state = Vec::with_capacity(app.code.len());
        for _ in &app.code {
            trigger_condition_state.push(ConditionState {
                are_conditions_met: false,
            });
        }
        assert_eq!(trigger_condition_state.len(), app.code.len());

        // Initialize input state.
        let mut full_input_state = Vec::with_capacity(app.requirements.len());
        for (req, allocation) in app.requirements.iter().zip(&app.allocations) {

            // State for this allocation. A single allocation may map
            // to a number of inputs (e.g. "all fire alarms").
            let mut allocation_state = Vec::with_capacity(allocation.len());
            for individual_device in allocation {
                let mut individual_device_state = Vec::with_capacity(req.data.inputs.len());
                for _ in 0 .. req.data.inputs.len() {
                    individual_device_state.push(None);
                }
                allocation_state.push(individual_device_state);
            }
            assert_eq!(allocation_state.len(), allocation.len());
            full_input_state.push(allocation_state);
        }
        assert_eq!(full_input_state.len(), app.requirements.len());

        // Start watching
        let mut watcher = Watcher::new();
        let mut witnesses = Vec::new();
        let (tx, rx) = channel();

        for state_index in app.iter_state_index() {
            // FIXME: We currently use `Range::any()` for simplicity.
            // However, in most cases, we should be able to look inside
            // the condition to build a better `Range`.
            witnesses.push(
                watcher.add(
                    &app.get_individual_device(&state_index), // FIXME: Implement
                    &app.get_input(&state_index), // FIXME: Implement
                    &Range::any(),
                    |data| {
                        let _ = tx.send(MonitorOp::Update {
                            data: data,
                            index: state_index,
                        });
                        // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                    }));
        }

        /*
        for (req, allocation, allocation_state, allocation_index) in Zip::new((&app.requirements, &app.allocations, &full_input_state, 0..)) {
            for (individual_device, individual_device_state, individual_device_index) in Zip::new((allocation, allocation_state, 0..)) {
                for (input, individual_input_state, individual_input_index) in Zip::new((&req.data.inputs, individual_device_state, 0..)) {
                    // FIXME: We currently use `Range::any()` for simplicity.
                    // However, in most cases, we should be able to look inside
                    // the condition to build a better `Range`.
                    witnesses.push(
                        watcher.add(
                            &individual_device.data,
                            &input.data,
                            &Range::any(),
                            |data| {
                                let _ = tx.send(MonitorOp::Update {
                                    data: data,
                                    allocation_index: allocation_index,
                                    individual_device_index: individual_device_index,
                                    individual_input_index: individual_input_index
                                }); // FIXME: Find a better structure than sending indices.
                                // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                            }));
                }
            }
        }
         */

        MonitorTask {
            state: MonitorTaskState {
                trigger_condition_state: trigger_condition_state,
                input_state: full_input_state,
                witnesses: witnesses,
                app: app,
            },
            comm: MonitorComm {
                tx: tx,
                rx: rx,
            }
        }
    }

    fn run(&mut self) {
        for msg in &self.comm.rx {
            use self::MonitorOp::*;
            match msg {
                Update {
                    data,
                    index,
                } => {
                    // Update the state
                    self.state.set_state(&index, Some(data));

                    // Find out if we should execute triggers.
                    // FIXME: We could optimize this by finding out which triggers
                    // are tainted by the update and only rechecking these.
                    for (trigger, trigger_condition_state) in Zip::new((&self.state.app.code, &mut self.state.trigger_condition_state)) {
                        if trigger.condition.is_met(&self.state.input_state) {
                            if !trigger_condition_state.are_conditions_met {
                                // Conditions were not met, now they are, so it is
                                // time to start executing. We copy the inputs
                                // and dispatch to a background thread

                                // FIXME: Handle cooldown.

                                trigger_condition_state.are_conditions_met = true;
                                let _ = self.comm.tx.send(MonitorOp::Execute {
                                    state: self.state.input_state.clone(),
                                    commands: trigger.execute.clone()
                                }); // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                            }
                        } else {
                            trigger_condition_state.are_conditions_met = false;
                        }
                    }
                },
                Execute {..} => {
                    panic!("Not implemented");
                }
                Stop => {
                    // Clean up watcher, stop the thread.
                    self.state.witnesses.clear();
                    return;
                }
            }
        }
    }
}

enum MonitorOp {
    Update{data: Json, index: InputIndex},
    Execute{state: InputState, commands: Vec<Command>},
    Stop
}

impl MonitorApp {
    pub fn start(&mut self) {
        if self.is_running {
            return;
        }
        self.is_running = true;

        let mut task = MonitorTask::new(self.clone());
        thread::spawn(move || {
            task.run();
        });
    }
}

/// Data labelled with a user-readable name.
#[derive(Clone)]
struct Named<T> {
    /// User-readable name.
    name: String,

    data: T,
}

/// A resource needed by this application. Typically, a definition of
/// device with some input our output capabilities.
#[derive(Clone)]
struct Requirement {
    /// The kind of resource, e.g. "a flashbulb".
    kind: DeviceKind,

    /// Input capabilities we need from the device, e.g. "the time of
    /// day", "the current temperature".
    inputs: Vec<Named<InputCapability>>,

    /// Output capabilities we need from the device, e.g. "play a
    /// sound", "set luminosity".
    outputs: Vec<Named<OutputCapability>>,

    /// Minimal number of resources required. If unspecified in the
    /// script, this is 1.
    min: u32,

    /// Maximal number of resources that may be handled. If
    /// unspecified in the script, this is the same as `min`.
    max: u32,

    // FIXME: We may need cooldown properties.
}

/// A single trigger, i.e. "when some condition becomes true, do
/// something".
#[derive(Clone)]
struct Trigger {
    /// The condition in which to execute the trigger.
    condition: Disjunction,

    /// Stuff to do once `condition` is met.
    execute: Vec<Command>,

    /// Minimal duration between two executions of the trigger.  If a
    /// duration was not picked by the developer, a reasonable default
    /// duration should be picked (e.g. 10 minutes).
    cooldown: Duration,
}

/// A disjunction (e.g. a "or") of conditions.
///
/// # Example
///
/// Door alarm #1 OR door alarm #2
#[derive(Clone)]
struct Disjunction {
    /// The disjunction is true iff any of the following conjunctions is true.
    any: Vec<Conjunction>
}

impl Disjunction {
    fn is_met(&self, input_state: &InputState) -> bool {
        panic!("Not implemented");
    }
}

/// A conjunction (e.g. a "and") of conditions.
#[derive(Clone)]
struct Conjunction {
    /// The conjunction is true iff all of the following expressions evaluate to true.
    all: Vec<Expression>
}

#[derive(Clone)]
enum Value {
    Json(Json),
    Blob{data: Arc<Vec<u8>>, mime_type: String},
}

/// An expression in the language.  Note that expressions may contain
/// inputs, which are typically asynchronous. Consequently,
/// expressions are evaluated asynchronously.
#[derive(Clone)]
enum Expression {
    Const {
        value: Value,

        /// We are dealing with real-world values, so physical units
        /// will prevent real-world accidents.
        unit: (), // FIXME: An actual unit

        /// The source for this value.  Used whenever we need to find
        /// out which sensor triggered the trigger (e.g. "where is the
        /// fire?").
        sources: Vec<usize>,
    },

    /// Dynamic values, including both actual sensors and higher-level values.
    ///
    /// # Example
    ///
    /// "Is there movement on motion detector" (may be true/false)
    ///
    /// # Example
    ///
    /// "Date of the latest motion on motion detector" (a Date)
    Input {
        /// A reference to the device used for input.
        /// This is an index in `requirements` and `allocations`.
        index: usize, // FIXME: We should use a custom type.

        /// A property to fetch (e.g. "luminosity" or "meta/latest-on").
        property: InputCapability,
    },

    /// Pure functions on values. The fact that they are pure
    /// functions is important, as it lets us find out automatically
    /// which subexpressions (including inputs) do not need to be
    /// re-evaluated.
    Function {
        function: Function,
        // FIXME: use a Box<> for now to avoid recursive type.
        arguments: Vec<Box<Expression>>
    },
}

#[derive(Clone)]
enum Function {
    // Operations on all values.
    InRange,
    OutOfRange,
    // Operations on strings
    Contains,
    NotContains,
}

/*
enum Function {
    // Operations on all values.
    Equals,
    NotEquals,

    // Operations on numbers, dates, durations.
    GreaterEq,
    Greater,
    LowerEq,
    Lower,
    Plus,
    Minus,

    // Operations on strings
    Contains,
    NotContains,

    // Etc.  FIXME: We'll need operations on dates, extracting name
    // from device, etc.
}
 */

/// Stuff to actually do. In practice, this is always a REST call.
// FIXME: Need to decide how much we wish to sandbox apps.
#[derive(Clone)]
struct Command {
    /// The resource to which this command applies,
    /// as an index in Trigger.requirements/allocations.
    destination: usize,  // FIXME: Use custom type.

    action: OutputCapability,

    arguments: HashMap<String, Option<Expression>>
}

<|endoftext|>


<commit_before>
use std::num::Float;
use sdl::video::{Surface};
use sdl::event::{Key};

use world::{World};
use math::{LineSeg, Vec2, Mat3};
use input::{InputState};

const SPEED: f32 = 0.4;
const TURN: f32 = 0.03;
const FOV_DIV: f32 = 500.0;
const WALL: f32 = 3000.0;

pub struct Game<'a> {
    pub pos: Vec2,
    pub face_angle: f32,
    pub world: &'a World,
    pub show_map: bool,
}

impl<'a> Game<'a> {
    pub fn step(&mut self, input: &InputState) {
        if input.has_key(Key::Left)  { self.face_angle -= TURN; }
        if input.has_key(Key::Right) { self.face_angle += TURN; }

        if input.has_key(Key::W) { self.do_move( 1.0,  0.0); }
        if input.has_key(Key::S) { self.do_move(-1.0,  0.0); }
        if input.has_key(Key::A) { self.do_move( 0.0, -1.0); }
        if input.has_key(Key::D) { self.do_move( 0.0,  1.0); }

        self.show_map = input.has_key(Key::Tab);
    }

    fn do_move(&mut self, para: f32, perp: f32) {
        let sin = SPEED*Float::sin(self.face_angle);
        let cos = SPEED*Float::cos(self.face_angle);
        self.pos.x +=  sin*para + cos*perp;
        self.pos.y += -cos*para + sin*perp;
    }

    pub fn render(&self, surf: &Surface) {
        if self.show_map {
            self.render_map(&surf);
        } else {
            self.render_game(&surf);
        }
    }

    fn render_map(&self, surf: &Surface) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos);

        surf.clear();
        for wall in self.world.walls.iter() {
            draw_seg(&surf, wall.transform(trans), 0xFF, 0x00, 0x00);
        }

        let w = surf.get_width() as usize;
        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;

            self.world.cast_ray(self.pos, self.face_angle + offset).map(|(_, pos, _)| {
                let draw_sg = LineSeg::new(self.pos.x, self.pos.y, pos.x, pos.y);
                draw_seg(&surf, draw_sg.transform(trans), 0x00, 0xFF, 0x00);
            });
        }
    }

    fn render_game(&self, surf: &Surface) {
        let w = surf.get_width() as usize;
        let h = surf.get_height() as usize;

        surf.clear();
        surf.with_lock(|pixels| {
            for x in 0..w {
                let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;

                let (top, bottom, along) = match self.world.cast_ray(self.pos, self.face_angle + offset) {
                    Some((dist, _, along)) => {
                        let px_height = (WALL / (dist * Float::cos(offset))) as usize;
                        let top = if h > px_height { (h - px_height) / 2 } else { 0 };
                        (top, h-top, along)
                    }
                    None => { (h/2, h/2, 0.0) }
                };

                for y in 0..top      { put_px(pixels, w, x, y,  0x00, 0x66, 0xFF); }
                for y in bottom..h   { put_px(pixels, w, x, y,  0x00, 0xBB, 0x00); }

                let brightness = ((0xFF - top) as f32) / 255.0;
                for y in top..bottom {
                    let tex_lookup = ((along * 36.0) as u8)
                                   ^ ((255.0*(((y-top)as f32)/(bottom-top)as f32)) as u8);
                    let color = ((tex_lookup as f32) * brightness) as u8;
                    put_px(pixels, w, x, y, color, 0x00, 0x00);
                }
            }
            true
        });
    }
}

fn put_px(pixels: &mut [u8], w: usize, x: usize, y: usize, r: u8, g: u8, b: u8) {
    pixels[3*(w*y+x) + 0] = b;
    pixels[3*(w*y+x) + 1] = g;
    pixels[3*(w*y+x) + 2] = r;
}

fn draw_seg(surf: &Surface, seg: LineSeg, r: u8, g: u8, b: u8) {
    let w = surf.get_width() as usize;
    let h = surf.get_height() as usize;
    let len = seg.get_length();

    surf.with_lock(|pixels| {
        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (w/2) as f32) as usize;
            let uy = (pt.y + (h/2) as f32) as usize;

            if ux < w && uy < h {
                put_px(pixels, w, ux, uy, r, g, b);
            }
        };
        true
    });
}
<commit_msg>Added floors<commit_after>
use std::num::Float;
use sdl::video::{Surface};
use sdl::event::{Key};

use world::{World};
use math::{LineSeg, Vec2, Mat3};
use input::{InputState};

const SPEED: f32 = 0.4;
const TURN: f32 = 0.03;

const FOV_DIV: f32 = 300.0;
const VISPLANE_DIST: f32 = 300.0;
const WALL_HEIGHT: f32 = 10.0;
const PERSON_HEIGHT: f32 = 5.0;

pub struct Game<'a> {
    pub pos: Vec2,
    pub face_angle: f32,
    pub world: &'a World,
    pub show_map: bool,
}

impl<'a> Game<'a> {
    pub fn step(&mut self, input: &InputState) {
        if input.has_key(Key::Left)  { self.face_angle -= TURN; }
        if input.has_key(Key::Right) { self.face_angle += TURN; }

        if input.has_key(Key::W) { self.do_move( 1.0,  0.0); }
        if input.has_key(Key::S) { self.do_move(-1.0,  0.0); }
        if input.has_key(Key::A) { self.do_move( 0.0, -1.0); }
        if input.has_key(Key::D) { self.do_move( 0.0,  1.0); }

        self.show_map = input.has_key(Key::Tab);
    }

    fn do_move(&mut self, para: f32, perp: f32) {
        let sin = SPEED*Float::sin(self.face_angle);
        let cos = SPEED*Float::cos(self.face_angle);
        self.pos.x +=  sin*para + cos*perp;
        self.pos.y += -cos*para + sin*perp;
    }

    pub fn render(&self, surf: &Surface) {
        if self.show_map {
            self.render_map(&surf);
        } else {
            self.render_game(&surf);
        }
    }

    fn render_map(&self, surf: &Surface) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos);

        surf.clear();
        for wall in self.world.walls.iter() {
            draw_seg(&surf, wall.transform(trans), 0xFF, 0x00, 0x00);
        }

        let w = surf.get_width() as usize;
        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;

            self.world.cast_ray(self.pos, self.face_angle + offset).map(|(_, pos, _)| {
                let draw_sg = LineSeg::new(self.pos.x, self.pos.y, pos.x, pos.y);
                draw_seg(&surf, draw_sg.transform(trans), 0x00, 0xFF, 0x00);
            });
        }
    }

    fn render_game(&self, surf: &Surface) {
        let w = surf.get_width() as usize;
        let h = surf.get_height() as usize;

        surf.clear();
        surf.with_lock(|pixels| {
            for x in 0..w {
                let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;

                let cast = self.world.cast_ray(self.pos, self.face_angle + offset);
                if !cast.is_some() { continue; }
                let (dist, hit_pos, along) = cast.unwrap();

                let cast_dist = dist * Float::cos(offset);
                let px_height = (VISPLANE_DIST * WALL_HEIGHT / cast_dist) as usize;
                let top = if h > px_height { (h - px_height) / 2 } else { 0 };
                let bottom = h - top;

                for y in 0..top { put_px(pixels, w, x, y,  0x00, 0x66, 0xFF); }

                let brightness = ((0xFF - top) as f32) / 255.0;
                for y in top..bottom {
                    let tex_lookup = ((along * 36.0) as u8)
                                   ^ ((255.0*(((y-top)as f32)/(bottom-top)as f32)) as u8);
                    let color = ((tex_lookup as f32) * brightness) as u8;
                    put_px(pixels, w, x, y, color, 0x00, 0x00);
                }

                for y in bottom..h {
                    let dist_floor = VISPLANE_DIST * PERSON_HEIGHT / ((y as f32) - (h as f32)/2.0);
                    let floor_pos = self.pos + (hit_pos - self.pos) * dist_floor / cast_dist;
                    let color = ((floor_pos.x * 10.0) as u8) ^ ((floor_pos.y * 10.0) as u8);
                    put_px(pixels, w, x, y, 0x00, color, 0x00);
                }
            }
            true
        });
    }
}

fn put_px(pixels: &mut [u8], w: usize, x: usize, y: usize, r: u8, g: u8, b: u8) {
    pixels[3*(w*y+x) + 0] = b;
    pixels[3*(w*y+x) + 1] = g;
    pixels[3*(w*y+x) + 2] = r;
}

fn draw_seg(surf: &Surface, seg: LineSeg, r: u8, g: u8, b: u8) {
    let w = surf.get_width() as usize;
    let h = surf.get_height() as usize;
    let len = seg.get_length();

    surf.with_lock(|pixels| {
        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (w/2) as f32) as usize;
            let uy = (pt.y + (h/2) as f32) as usize;

            if ux < w && uy < h {
                put_px(pixels, w, ux, uy, r, g, b);
            }
        };
        true
    });
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::collections::binary_heap::{Iter as BinaryHeapIter};

use collectors::{Collector, DocumentMatch};

/// An f64 that cannot be NaN.
/// We need to order documents by score but NaN cannot be ordered, so we convert all scores into
/// RealF64 first, handling any invalid values while doing that conversion
#[derive(Copy, Clone, PartialEq, PartialOrd)]
struct RealF64(f64);

impl RealF64 {
    fn new(val: f64) -> Option<RealF64> {
        if val.is_nan() {
            None
        } else {
            Some(RealF64(val))
        }
    }
}

impl Eq for RealF64 {}

impl Ord for RealF64 {
    fn cmp(&self, other: &RealF64) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
struct ScoredDocument {
    id: u64,
    score: RealF64,
}

impl Ord for ScoredDocument {
    fn cmp(&self, other: &ScoredDocument) -> Ordering {
        // Notice that the we flip the ordering here
        other.score.cmp(&self.score)
    }
}

impl PartialOrd for ScoredDocument {
    fn partial_cmp(&self, other: &ScoredDocument) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

pub struct TopScoreCollector {
    max_docs: usize,
    heap: BinaryHeap<ScoredDocument>,
}

impl TopScoreCollector {
    pub fn new(max_docs: usize) -> TopScoreCollector {
        TopScoreCollector {
            max_docs: max_docs,
            heap: BinaryHeap::with_capacity(max_docs + 1),
        }
    }

    pub fn iter<'a>(&'a mut self) -> Iter<'a> {
        Iter {
            heap_iter: self.heap.iter(),
        }
    }
}

impl Collector for TopScoreCollector {
    fn needs_score(&self) -> bool {
        true
    }

    fn collect(&mut self, doc: DocumentMatch) {
        let doc_id = doc.doc_id();
        let score = doc.score();

        // Build a ScoredDocument object, checking that the score is set and not NaN
        let scored_document = match score {
            Some(score) => {
                // Convert to RealF64 which is orderable but does not support NaN
                match RealF64::new(score) {
                    Some(real_score) => {
                        ScoredDocument {
                            id: doc_id,
                            score: real_score,
                        }
                    }
                    None => {
                        // Score was NaN
                        panic!("document with 'NaN' score was passed into TopScoreCollector");
                    }
                }
            }
            None => {
                panic!("unscored document was passed into TopScoreCollector");
            }
        };

        // Now insert the document into the heap
        self.heap.push(scored_document);

        // Now reduce the heap size if it's too big
        if self.heap.len() > self.max_docs {
            self.heap.pop();
        }
    }
}

pub struct Iter<'a> {
    heap_iter: BinaryHeapIter<'a, ScoredDocument>,
}

impl<'a> Iterator for Iter<'a> {
    type Item = DocumentMatch;

    fn next(&mut self) -> Option<DocumentMatch> {
        match self.heap_iter.next_back() {
            Some(scored_document) => {
                // Convert ScoredDocument back into DocumentMatch
                Some(DocumentMatch::new_scored(scored_document.id, scored_document.score.0))
            }
            None => None
        }
    }
}

#[cfg(test)]
mod tests {
    use collectors::{Collector, DocumentMatch};
    use super::TopScoreCollector;

    #[test]
    fn test_top_score_collector_inital_state() {
        let mut collector = TopScoreCollector::new(10);

        let docs = collector.iter().collect::<Vec<_>>();
        assert_eq!(docs.len(), 0);
    }

    #[test]
    fn test_top_score_collector_needs_score() {
        let collector = TopScoreCollector::new(10);

        assert_eq!(collector.needs_score(), true);
    }

    #[test]
    fn test_top_score_collector_collect() {
        let mut collector = TopScoreCollector::new(10);

        collector.collect(DocumentMatch::new_scored(0, 1.0f64));
        collector.collect(DocumentMatch::new_scored(1, 0.5f64));
        collector.collect(DocumentMatch::new_scored(2, 2.0f64));

        let docs = collector.iter().collect::<Vec<_>>();
        assert_eq!(docs.len(), 3);
        assert_eq!(docs[0].id, 2);
        assert_eq!(docs[1].id, 0);
        assert_eq!(docs[2].id, 1);
    }

    #[test]
    fn test_top_score_collector_truncate() {
        let mut collector = TopScoreCollector::new(2);

        collector.collect(DocumentMatch::new_scored(0, 1.0f64));
        collector.collect(DocumentMatch::new_scored(1, 0.5f64));
        collector.collect(DocumentMatch::new_scored(2, 2.0f64));

        let docs = collector.iter().collect::<Vec<_>>();
        assert_eq!(docs.len(), 2);
        assert_eq!(docs[0].id, 2);
        assert_eq!(docs[1].id, 0);
    }
}
<commit_msg>Fixed ordering returned by TopScoreCollector<commit_after>use std::cmp::Ordering;
use std::collections::BinaryHeap;

use collectors::{Collector, DocumentMatch};

/// An f64 that cannot be NaN.
/// We need to order documents by score but NaN cannot be ordered, so we convert all scores into
/// RealF64 first, handling any invalid values while doing that conversion
#[derive(Copy, Clone, PartialEq, PartialOrd)]
struct RealF64(f64);

impl RealF64 {
    fn new(val: f64) -> Option<RealF64> {
        if val.is_nan() {
            None
        } else {
            Some(RealF64(val))
        }
    }
}

impl Eq for RealF64 {}

impl Ord for RealF64 {
    fn cmp(&self, other: &RealF64) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
struct ScoredDocument {
    id: u64,
    score: RealF64,
}

impl Ord for ScoredDocument {
    fn cmp(&self, other: &ScoredDocument) -> Ordering {
        self.score.cmp(&other.score)
    }
}

impl PartialOrd for ScoredDocument {
    fn partial_cmp(&self, other: &ScoredDocument) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

pub struct TopScoreCollector {
    max_docs: usize,
    heap: BinaryHeap<ScoredDocument>,
}

impl TopScoreCollector {
    pub fn new(max_docs: usize) -> TopScoreCollector {
        TopScoreCollector {
            max_docs: max_docs,
            heap: BinaryHeap::with_capacity(max_docs + 1),
        }
    }

    pub fn into_sorted_vec(self) -> Vec<DocumentMatch> {
        self.heap.into_sorted_vec().iter()
            .map(|scored_document| {
                DocumentMatch::new_scored(scored_document.id, -scored_document.score.0)
            })
            .collect()
    }
}

impl Collector for TopScoreCollector {
    fn needs_score(&self) -> bool {
        true
    }

    fn collect(&mut self, doc: DocumentMatch) {
        let doc_id = doc.doc_id();
        let score = doc.score();

        // Build a ScoredDocument object, checking that the score is set and not NaN
        let scored_document = match score {
            Some(score) => {
                // Convert to RealF64 which is orderable but does not support NaN
                match RealF64::new(-score) {
                    Some(real_score) => {
                        ScoredDocument {
                            id: doc_id,
                            score: real_score,
                        }
                    }
                    None => {
                        // Score was NaN
                        panic!("document with 'NaN' score was passed into TopScoreCollector");
                    }
                }
            }
            None => {
                panic!("unscored document was passed into TopScoreCollector");
            }
        };

        // Now insert the document into the heap
        self.heap.push(scored_document);

        // Now reduce the heap size if it's too big
        if self.heap.len() > self.max_docs {
            self.heap.pop();
        }
    }
}

#[cfg(test)]
mod tests {
    use collectors::{Collector, DocumentMatch};
    use super::TopScoreCollector;

    #[test]
    fn test_top_score_collector_inital_state() {
        let collector = TopScoreCollector::new(10);

        let docs = collector.into_sorted_vec();
        assert_eq!(docs.len(), 0);
    }

    #[test]
    fn test_top_score_collector_needs_score() {
        let collector = TopScoreCollector::new(10);

        assert_eq!(collector.needs_score(), true);
    }

    #[test]
    fn test_top_score_collector_collect() {
        let mut collector = TopScoreCollector::new(10);

        collector.collect(DocumentMatch::new_scored(0, 1.0f64));
        collector.collect(DocumentMatch::new_scored(1, 0.5f64));
        collector.collect(DocumentMatch::new_scored(2, 2.0f64));
        collector.collect(DocumentMatch::new_scored(3, 1.5f64));

        let docs = collector.into_sorted_vec();
        assert_eq!(docs.len(), 4);
        assert_eq!(docs[0].id, 2);
        assert_eq!(docs[1].id, 3);
        assert_eq!(docs[2].id, 0);
        assert_eq!(docs[3].id, 1);
    }

    #[test]
    fn test_top_score_collector_truncate() {
        let mut collector = TopScoreCollector::new(2);

        collector.collect(DocumentMatch::new_scored(0, 1.0f64));
        collector.collect(DocumentMatch::new_scored(1, 0.5f64));
        collector.collect(DocumentMatch::new_scored(2, 2.0f64));

        let docs = collector.into_sorted_vec();
        assert_eq!(docs.len(), 2);
        assert_eq!(docs[0].id, 2);
        assert_eq!(docs[1].id, 0);
    }
}
<|endoftext|>


<commit_before><commit_msg>Beautify doc<commit_after><|endoftext|>


<commit_before><commit_msg>Fix clippy<commit_after><|endoftext|>


<commit_before><commit_msg>Force url to change to .parelease in refresh mode<commit_after><|endoftext|>


<commit_before><commit_msg>be cool<commit_after><|endoftext|>


<commit_before><commit_msg>Improve connection error message<commit_after><|endoftext|>


<commit_before><commit_msg>Happily humming along<commit_after><|endoftext|>


<commit_before><commit_msg>Update<commit_after><|endoftext|>


<commit_before><commit_msg>Massive speed boost to small insertions.<commit_after><|endoftext|>


<commit_before>// Copyright 2021 Chad Williamson
//
// Use of this source code is governed by an MIT-syle license that can be
// found in the LICENSE file or at https://opensource.org/licenses/MIT.

// This file contains integration tests for the find command.
//
// Note: the `serial` macro is used on tests that make assumptions about the
// working directory, since we have at least one test that needs to change it.

use assert_cmd::Command;
use predicates::prelude::*;
use serial_test::serial;
use std::env;
use std::fs::File;
use tempdir::TempDir;

#[serial(working_dir)]
#[test]
fn no_args() {
    Command::cargo_bin("find")
        .expect("found binary")
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("\n./test_data\n"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_both_match() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "d", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::similar("./test_data\n"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_one_matches() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "f", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());
}

#[test]
fn matcher_with_side_effects_at_end() {
    let temp_dir = TempDir::new("find_cmd_").expect("made temp dir");
    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-name", "test", "-delete"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(temp_dir.path().exists(), "temp dir should NOT be deleted");
}

#[test]
fn matcher_with_side_effects_in_front() {
    let temp_dir = TempDir::new("find_cmd_").expect("made temp dir");
    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-delete", "-name", "test"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(!temp_dir.path().exists(), "temp dir should also be deleted");
}

// This could be covered by a unit test in principle... in practice, changing
// the working dir can't be done safely in unit tests unless `--test-threads=1`
// or `serial` goes everywhere, and it doesn't seem possible to get an
// appropriate `walkdir::DirEntry` for "." without actually changing dirs
// (or risking deletion of the repo itself).
#[serial(working_dir)]
#[test]
fn delete_on_dot_dir() {
    let temp_dir = TempDir::new("find_cmd_").expect("made temp dir");
    let original_dir = env::current_dir().unwrap();
    env::set_current_dir(&temp_dir.path()).expect("working dir changed");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[".", "-delete"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    env::set_current_dir(original_dir).expect("restored original working dir");

    assert!(temp_dir.path().exists(), "temp dir should still exist");
}
<commit_msg>Fix integration tests on Windows<commit_after>// Copyright 2021 Chad Williamson
//
// Use of this source code is governed by an MIT-syle license that can be
// found in the LICENSE file or at https://opensource.org/licenses/MIT.

// This file contains integration tests for the find command.
//
// Note: the `serial` macro is used on tests that make assumptions about the
// working directory, since we have at least one test that needs to change it.

use assert_cmd::Command;
use predicates::prelude::*;
use serial_test::serial;
use std::env;
use std::fs::File;
use tempdir::TempDir;

#[serial(working_dir)]
#[test]
fn no_args() {
    Command::cargo_bin("find")
        .expect("found binary")
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("test_data"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_both_match() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "d", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::contains("test_data"));
}

#[serial(working_dir)]
#[test]
fn two_matchers_one_matches() {
    Command::cargo_bin("find")
        .expect("found binary")
        .args(&["-type", "f", "-name", "test_data"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());
}

#[test]
fn matcher_with_side_effects_at_end() {
    let temp_dir = TempDir::new("find_cmd_").expect("made temp dir");
    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-name", "test", "-delete"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(temp_dir.path().exists(), "temp dir should NOT be deleted");
}

#[test]
fn matcher_with_side_effects_in_front() {
    let temp_dir = TempDir::new("find_cmd_").expect("made temp dir");
    let temp_dir_path = temp_dir.path().to_string_lossy();
    let test_file = temp_dir.path().join("test");
    File::create(&test_file).expect("created test file");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[&temp_dir_path, "-delete", "-name", "test"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    assert!(!test_file.exists(), "test file should be deleted");
    assert!(!temp_dir.path().exists(), "temp dir should also be deleted");
}

// This could be covered by a unit test in principle... in practice, changing
// the working dir can't be done safely in unit tests unless `--test-threads=1`
// or `serial` goes everywhere, and it doesn't seem possible to get an
// appropriate `walkdir::DirEntry` for "." without actually changing dirs
// (or risking deletion of the repo itself).
#[serial(working_dir)]
#[test]
fn delete_on_dot_dir() {
    let temp_dir = TempDir::new("find_cmd_").expect("made temp dir");
    let original_dir = env::current_dir().unwrap();
    env::set_current_dir(&temp_dir.path()).expect("working dir changed");

    Command::cargo_bin("find")
        .expect("found binary")
        .args(&[".", "-delete"])
        .assert()
        .success()
        .stderr(predicate::str::is_empty())
        .stdout(predicate::str::is_empty());

    env::set_current_dir(original_dir).expect("restored original working dir");

    assert!(temp_dir.path().exists(), "temp dir should still exist");
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Read_a_file_line_by_line
use std::io::fs::File;
use std::io::BufferedReader;
use std::os::args;

fn main() {
    let filename = match args().len() {
        1 => fail!("You must enter a filename to read line by line"),
        _ => args()[1]
    };

    let file = File::open(&Path::new(filename));
    let mut reader = BufferedReader::new(file);

    for line in reader.lines() {
        print!("{:s}", line.unwrap());
    }

    println!("");
}
<commit_msg>Added error handling to read file by lines<commit_after>// Implements http://rosettacode.org/wiki/Read_a_file_line_by_line

use std::io::fs::File;
use std::io::BufferedReader;
use std::os::args;

fn main() {
    let filename = match args().len() {
        1 => fail!("You must enter a filename to read line by line"),
        _ => args()[1]
    };

    let file = File::open(&Path::new(filename));
    let mut reader = BufferedReader::new(file);

    for line in reader.lines() {
        // Handle any errors that may arise
        match line {
            Ok(ln) => print!("{}", ln),
            Err(msg) => print!("{}", msg)
        }
    }

    println!("");
}
<|endoftext|>