<commit_before>#![cfg_attr(thiserror_nightly_testing, feature(backtrace))]

use thiserror::Error;

#[derive(Error, Debug)]
#[error("...")]
pub struct Inner;

#[cfg(thiserror_nightly_testing)]
pub mod structs {
    use super::Inner;
    use std::backtrace::Backtrace;
    use std::error::Error;
    use std::sync::Arc;
    use thiserror::Error;

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct PlainBacktrace {
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct ExplicitBacktrace {
        #[backtrace]
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptBacktrace {
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct ArcBacktrace {
        #[backtrace]
        backtrace: Arc<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct BacktraceFrom {
        #[from]
        source: Inner,
        #[backtrace]
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptBacktraceFrom {
        #[from]
        source: Inner,
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct ArcBacktraceFrom {
        #[from]
        source: Inner,
        #[backtrace]
        backtrace: Arc<Backtrace>,
    }

    #[test]
    fn test_backtrace() {
        let error = PlainBacktrace {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = ExplicitBacktrace {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = OptBacktrace {
            backtrace: Some(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = ArcBacktrace {
            backtrace: Arc::new(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = BacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = OptBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = ArcBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());
    }
}

#[cfg(thiserror_nightly_testing)]
pub mod enums {
    use super::Inner;
    use std::backtrace::Backtrace;
    use std::error::Error;
    use std::sync::Arc;
    use thiserror::Error;

    #[derive(Error, Debug)]
    pub enum PlainBacktrace {
        #[error("...")]
        Test { backtrace: Backtrace },
    }

    #[derive(Error, Debug)]
    pub enum ExplicitBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Backtrace,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum ArcBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Arc<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum BacktraceFrom {
        #[error("...")]
        Test {
            #[from]
            source: Inner,
            #[backtrace]
            backtrace: Backtrace,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptBacktraceFrom {
        #[error("...")]
        Test {
            #[from]
            source: Inner,
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum ArcBacktraceFrom {
        #[error("...")]
        Test {
            #[from]
            source: Inner,
            #[backtrace]
            backtrace: Arc<Backtrace>,
        },
    }

    #[test]
    fn test_backtrace() {
        let error = PlainBacktrace::Test {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = ExplicitBacktrace::Test {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = OptBacktrace::Test {
            backtrace: Some(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = ArcBacktrace::Test {
            backtrace: Arc::new(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = BacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = OptBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = ArcBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());
    }
}

#[test]
#[cfg_attr(not(thiserror_nightly_testing), ignore)]
fn test_backtrace() {}
<commit_msg>test combined `#[from]` and `#[backtrace]`<commit_after>#![cfg_attr(thiserror_nightly_testing, feature(backtrace))]

use thiserror::Error;

#[derive(Error, Debug)]
#[error("...")]
pub struct Inner;

#[cfg(thiserror_nightly_testing)]
pub mod structs {
    use super::Inner;
    use std::backtrace::Backtrace;
    use std::error::Error;
    use std::sync::Arc;
    use thiserror::Error;

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct PlainBacktrace {
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct ExplicitBacktrace {
        #[backtrace]
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptBacktrace {
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct ArcBacktrace {
        #[backtrace]
        backtrace: Arc<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct BacktraceFrom {
        #[from]
        source: Inner,
        #[backtrace]
        backtrace: Backtrace,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct CombinedBacktraceFrom {
        #[from]
        #[backtrace]
        source: Inner,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct OptBacktraceFrom {
        #[from]
        source: Inner,
        #[backtrace]
        backtrace: Option<Backtrace>,
    }

    #[derive(Error, Debug)]
    #[error("...")]
    pub struct ArcBacktraceFrom {
        #[from]
        source: Inner,
        #[backtrace]
        backtrace: Arc<Backtrace>,
    }

    #[test]
    fn test_backtrace() {
        let error = PlainBacktrace {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = ExplicitBacktrace {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = OptBacktrace {
            backtrace: Some(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = ArcBacktrace {
            backtrace: Arc::new(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = BacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = CombinedBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = OptBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = ArcBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());
    }
}

#[cfg(thiserror_nightly_testing)]
pub mod enums {
    use super::Inner;
    use std::backtrace::Backtrace;
    use std::error::Error;
    use std::sync::Arc;
    use thiserror::Error;

    #[derive(Error, Debug)]
    pub enum PlainBacktrace {
        #[error("...")]
        Test { backtrace: Backtrace },
    }

    #[derive(Error, Debug)]
    pub enum ExplicitBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Backtrace,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum ArcBacktrace {
        #[error("...")]
        Test {
            #[backtrace]
            backtrace: Arc<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum BacktraceFrom {
        #[error("...")]
        Test {
            #[from]
            source: Inner,
            #[backtrace]
            backtrace: Backtrace,
        },
    }

    #[derive(Error, Debug)]
    pub enum CombinedBacktraceFrom {
        #[error("...")]
        Test {
            #[from]
            #[backtrace]
            source: Inner,
        },
    }

    #[derive(Error, Debug)]
    pub enum OptBacktraceFrom {
        #[error("...")]
        Test {
            #[from]
            source: Inner,
            #[backtrace]
            backtrace: Option<Backtrace>,
        },
    }

    #[derive(Error, Debug)]
    pub enum ArcBacktraceFrom {
        #[error("...")]
        Test {
            #[from]
            source: Inner,
            #[backtrace]
            backtrace: Arc<Backtrace>,
        },
    }

    #[test]
    fn test_backtrace() {
        let error = PlainBacktrace::Test {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = ExplicitBacktrace::Test {
            backtrace: Backtrace::capture(),
        };
        assert!(error.backtrace().is_some());

        let error = OptBacktrace::Test {
            backtrace: Some(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = ArcBacktrace::Test {
            backtrace: Arc::new(Backtrace::capture()),
        };
        assert!(error.backtrace().is_some());

        let error = BacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = CombinedBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = OptBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());

        let error = ArcBacktraceFrom::from(Inner);
        assert!(error.backtrace().is_some());
    }
}

#[test]
#[cfg_attr(not(thiserror_nightly_testing), ignore)]
fn test_backtrace() {}
<|endoftext|>


<commit_before>use std::fs::{self, File};
use std::io::prelude::*;
use std::env;
use tempdir::TempDir;

use support::{execs, paths, cargo_dir};
use hamcrest::{assert_that, existing_file, existing_dir, is_not};

use cargo::util::{process, ProcessBuilder};

fn setup() {
}

fn my_process(s: &str) -> ProcessBuilder {
    let mut p = process(s).unwrap();
    p.cwd(&paths::root()).env("HOME", &paths::home());
    return p;
}

fn cargo_process(s: &str) -> ProcessBuilder {
    let mut p = process(&cargo_dir().join("cargo")).unwrap();
    p.arg(s).cwd(&paths::root()).env("HOME", &paths::home());
    return p;
}

test!(simple_lib {
    assert_that(cargo_process("new").arg("foo").arg("--vcs").arg("none")
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.gitignore"), is_not(existing_file()));

    assert_that(cargo_process("build").cwd(&paths::root().join("foo")),
                execs().with_status(0));
});

test!(simple_bin {
    assert_that(cargo_process("new").arg("foo").arg("--bin")
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/main.rs"), existing_file());

    assert_that(cargo_process("build").cwd(&paths::root().join("foo")),
                execs().with_status(0));
    assert_that(&paths::root().join(&format!("foo/target/debug/foo{}",
                                             env::consts::EXE_SUFFIX)),
                existing_file());
});

test!(simple_git {
    let td = TempDir::new("cargo").unwrap();
    assert_that(cargo_process("new").arg("foo").cwd(td.path().clone())
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(td.path(), existing_dir());
    assert_that(&td.path().join("foo/Cargo.toml"), existing_file());
    assert_that(&td.path().join("foo/src/lib.rs"), existing_file());
    assert_that(&td.path().join("foo/.git"), existing_dir());
    assert_that(&td.path().join("foo/.gitignore"), existing_file());

    assert_that(cargo_process("build").cwd(&td.path().clone().join("foo")),
                execs().with_status(0));
});

test!(no_argument {
    assert_that(cargo_process("new"),
                execs().with_status(1)
                       .with_stderr("\
Invalid arguments.

Usage:
    cargo new [options] <path>
    cargo new -h | --help
"));
});

test!(existing {
    let dst = paths::root().join("foo");
    fs::create_dir(&dst).unwrap();
    assert_that(cargo_process("new").arg("foo"),
                execs().with_status(101)
                       .with_stderr(format!("Destination `{}` already exists\n",
                                            dst.display())));
});

test!(invalid_characters {
    assert_that(cargo_process("new").arg("foo.rs"),
                execs().with_status(101)
                       .with_stderr("Invalid character `.` in crate name: `foo.rs`"));
});

test!(finds_author_user {
    // Use a temp dir to make sure we don't pick up .cargo/config somewhere in
    // the hierarchy
    let td = TempDir::new("cargo").unwrap();
    assert_that(cargo_process("new").arg("foo").env("USER", "foo")
                                    .cwd(td.path().clone()),
                execs().with_status(0));

    let toml = td.path().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo"]"#));
});

test!(finds_author_username {
    // Use a temp dir to make sure we don't pick up .cargo/config somewhere in
    // the hierarchy
    let td = TempDir::new("cargo").unwrap();
    assert_that(cargo_process("new").arg("foo")
                                    .env_remove("USER")
                                    .env("USERNAME", "foo")
                                    .cwd(td.path().clone()),
                execs().with_status(0));

    let toml = td.path().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo"]"#));
});

test!(finds_author_git {
    my_process("git").args(&["config", "--global", "user.name", "bar"])
                     .exec().unwrap();
    my_process("git").args(&["config", "--global", "user.email", "baz"])
                     .exec().unwrap();
    assert_that(cargo_process("new").arg("foo").env("USER", "foo"),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["bar <baz>"]"#));
});

test!(author_prefers_cargo {
    my_process("git").args(&["config", "--global", "user.name", "bar"])
                     .exec().unwrap();
    my_process("git").args(&["config", "--global", "user.email", "baz"])
                     .exec().unwrap();
    let root = paths::root();
    fs::create_dir(&root.join(".cargo")).unwrap();
    File::create(&root.join(".cargo/config")).unwrap().write_all(br#"
        [cargo-new]
        name = "new-foo"
        email = "new-bar"
        git = false
    "#).unwrap();

    assert_that(cargo_process("new").arg("foo").env("USER", "foo"),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["new-foo <new-bar>"]"#));
    assert!(!root.join("foo/.gitignore").exists());
});

test!(git_prefers_command_line {
    let root = paths::root();
    let td = TempDir::new("cargo").unwrap();
    fs::create_dir(&root.join(".cargo")).unwrap();
    File::create(&root.join(".cargo/config")).unwrap().write_all(br#"
        [cargo-new]
        vcs = "none"
        name = "foo"
        email = "bar"
    "#).unwrap();

    assert_that(cargo_process("new").arg("foo").arg("--vcs").arg("git")
                                    .cwd(td.path())
                                    .env("USER", "foo"),
                execs().with_status(0));
    assert!(td.path().join("foo/.gitignore").exists());
});

test!(subpackage_no_git {
    assert_that(cargo_process("new").arg("foo").env("USER", "foo"),
                execs().with_status(0));

    let subpackage = paths::root().join("foo").join("components");
    fs::create_dir(&subpackage).unwrap();
    assert_that(cargo_process("new").arg("foo/components/subcomponent")
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo/components/subcomponent/.git"),
                 is_not(existing_file()));
    assert_that(&paths::root().join("foo/components/subcomponent/.gitignore"),
                 is_not(existing_file()));
});

test!(unknown_flags {
    assert_that(cargo_process("new").arg("foo").arg("--flag"),
                execs().with_status(1)
                       .with_stderr("\
Unknown flag: '--flag'

Usage:
    cargo new [..]
    cargo new [..]
"));
});
<commit_msg>Add integration tests<commit_after>use std::fs::{self, File};
use std::io::prelude::*;
use std::env;
use tempdir::TempDir;

use support::{execs, paths, cargo_dir};
use hamcrest::{assert_that, existing_file, existing_dir, is_not};

use cargo::util::{process, ProcessBuilder};

fn setup() {
}

fn my_process(s: &str) -> ProcessBuilder {
    let mut p = process(s).unwrap();
    p.cwd(&paths::root()).env("HOME", &paths::home());
    return p;
}

fn cargo_process(s: &str) -> ProcessBuilder {
    let mut p = process(&cargo_dir().join("cargo")).unwrap();
    p.arg(s).cwd(&paths::root()).env("HOME", &paths::home());
    return p;
}

test!(simple_lib {
    assert_that(cargo_process("new").arg("foo").arg("--vcs").arg("none")
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.gitignore"), is_not(existing_file()));

    assert_that(cargo_process("build").cwd(&paths::root().join("foo")),
                execs().with_status(0));
});

test!(simple_bin {
    assert_that(cargo_process("new").arg("foo").arg("--bin")
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/main.rs"), existing_file());

    assert_that(cargo_process("build").cwd(&paths::root().join("foo")),
                execs().with_status(0));
    assert_that(&paths::root().join(&format!("foo/target/debug/foo{}",
                                             env::consts::EXE_SUFFIX)),
                existing_file());
});

test!(simple_git {
    let td = TempDir::new("cargo").unwrap();
    assert_that(cargo_process("new").arg("foo").cwd(td.path().clone())
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(td.path(), existing_dir());
    assert_that(&td.path().join("foo/Cargo.toml"), existing_file());
    assert_that(&td.path().join("foo/src/lib.rs"), existing_file());
    assert_that(&td.path().join("foo/.git"), existing_dir());
    assert_that(&td.path().join("foo/.gitignore"), existing_file());

    assert_that(cargo_process("build").cwd(&td.path().clone().join("foo")),
                execs().with_status(0));
});

test!(no_argument {
    assert_that(cargo_process("new"),
                execs().with_status(1)
                       .with_stderr("\
Invalid arguments.

Usage:
    cargo new [options] <path>
    cargo new -h | --help
"));
});

test!(existing {
    let dst = paths::root().join("foo");
    fs::create_dir(&dst).unwrap();
    assert_that(cargo_process("new").arg("foo"),
                execs().with_status(101)
                       .with_stderr(format!("Destination `{}` already exists\n",
                                            dst.display())));
});

test!(invalid_characters {
    assert_that(cargo_process("new").arg("foo.rs"),
                execs().with_status(101)
                       .with_stderr("Invalid character `.` in crate name: `foo.rs`"));
});

test!(rust_prefix_stripped {
    assert_that(cargo_process("new").arg("rust-foo"),
                execs().with_status(0)
                       .with_stdout("Note: package will be named `foo`; use --name to override"));
    let toml = paths::root().join("rust-foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"name = "foo""#));
});

test!(bin_disables_stripping {
    assert_that(cargo_process("new").arg("rust-foo").arg("--bin"),
                execs().with_status(0));
    let toml = paths::root().join("rust-foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"name = "rust-foo""#));
});

test!(explicit_name_not_stripped {
    assert_that(cargo_process("new").arg("foo").arg("--name").arg("rust-bar"),
                execs().with_status(0));
    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"name = "rust-bar""#));
});

test!(finds_author_user {
    // Use a temp dir to make sure we don't pick up .cargo/config somewhere in
    // the hierarchy
    let td = TempDir::new("cargo").unwrap();
    assert_that(cargo_process("new").arg("foo").env("USER", "foo")
                                    .cwd(td.path().clone()),
                execs().with_status(0));

    let toml = td.path().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo"]"#));
});

test!(finds_author_username {
    // Use a temp dir to make sure we don't pick up .cargo/config somewhere in
    // the hierarchy
    let td = TempDir::new("cargo").unwrap();
    assert_that(cargo_process("new").arg("foo")
                                    .env_remove("USER")
                                    .env("USERNAME", "foo")
                                    .cwd(td.path().clone()),
                execs().with_status(0));

    let toml = td.path().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo"]"#));
});

test!(finds_author_git {
    my_process("git").args(&["config", "--global", "user.name", "bar"])
                     .exec().unwrap();
    my_process("git").args(&["config", "--global", "user.email", "baz"])
                     .exec().unwrap();
    assert_that(cargo_process("new").arg("foo").env("USER", "foo"),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["bar <baz>"]"#));
});

test!(author_prefers_cargo {
    my_process("git").args(&["config", "--global", "user.name", "bar"])
                     .exec().unwrap();
    my_process("git").args(&["config", "--global", "user.email", "baz"])
                     .exec().unwrap();
    let root = paths::root();
    fs::create_dir(&root.join(".cargo")).unwrap();
    File::create(&root.join(".cargo/config")).unwrap().write_all(br#"
        [cargo-new]
        name = "new-foo"
        email = "new-bar"
        git = false
    "#).unwrap();

    assert_that(cargo_process("new").arg("foo").env("USER", "foo"),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["new-foo <new-bar>"]"#));
    assert!(!root.join("foo/.gitignore").exists());
});

test!(git_prefers_command_line {
    let root = paths::root();
    let td = TempDir::new("cargo").unwrap();
    fs::create_dir(&root.join(".cargo")).unwrap();
    File::create(&root.join(".cargo/config")).unwrap().write_all(br#"
        [cargo-new]
        vcs = "none"
        name = "foo"
        email = "bar"
    "#).unwrap();

    assert_that(cargo_process("new").arg("foo").arg("--vcs").arg("git")
                                    .cwd(td.path())
                                    .env("USER", "foo"),
                execs().with_status(0));
    assert!(td.path().join("foo/.gitignore").exists());
});

test!(subpackage_no_git {
    assert_that(cargo_process("new").arg("foo").env("USER", "foo"),
                execs().with_status(0));

    let subpackage = paths::root().join("foo").join("components");
    fs::create_dir(&subpackage).unwrap();
    assert_that(cargo_process("new").arg("foo/components/subcomponent")
                                    .env("USER", "foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo/components/subcomponent/.git"),
                 is_not(existing_file()));
    assert_that(&paths::root().join("foo/components/subcomponent/.gitignore"),
                 is_not(existing_file()));
});

test!(unknown_flags {
    assert_that(cargo_process("new").arg("foo").arg("--flag"),
                execs().with_status(1)
                       .with_stderr("\
Unknown flag: '--flag'

Usage:
    cargo new [..]
    cargo new [..]
"));
});
<|endoftext|>


<commit_before>//! Cost calculation logic

use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::{M256, U256};

use std::cmp::max;
use vm::{Memory, Instruction};
use super::State;
use super::precompiled::is_precompiled;

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSIT: usize = 200;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_MEMORY: usize = 3;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn sstore_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let index = machine.stack.peek(0).unwrap();
    let value = machine.stack.peek(1).unwrap();
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage(address).unwrap().read(index).unwrap() == M256::zero() {
        G_SSET.into()
    } else {
        G_SRESET.into()
    }
}

fn call_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    extra_cost(machine)
}

fn extra_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    Gas::from(machine.patch.gas_call) + xfer_cost(machine) + new_cost(machine)
}

fn xfer_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let val = machine.stack.peek(2).unwrap();
    if val != M256::zero() {
        G_CALLVALUE.into()
    } else {
        Gas::zero()
    }
}

fn new_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let address: Address = machine.stack.peek(1).unwrap().into();
    if machine.account_state.balance(address).unwrap() == U256::zero() && machine.account_state.nonce(address).unwrap() == M256::zero() && machine.account_state.code(address).unwrap().len() == 0 && !is_precompiled(address) {
        G_NEWACCOUNT.into()
    } else {
        Gas::zero()
    }
}

fn suicide_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let address: Address = machine.stack.peek(0).unwrap().into();
    Gas::from(machine.patch.gas_suicide) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

/// Calculate code deposit cost for a ContractCreation transaction.
pub fn code_deposit_gas(len: usize) -> Gas {
    Gas::from(G_CODEDEPOSIT) * Gas::from(len)
}

/// Calculate the memory gas from the memory cost.
pub fn memory_gas(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

/// Calculate the memory cost. This is the same as the active memory
/// length in the Yellow Paper.
pub fn memory_cost<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    let ref stack = state.stack;

    let current = state.memory_cost;
    let next = match instruction {
        Instruction::SHA3 | Instruction::RETURN | Instruction::LOG(_) => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(1).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CODECOPY | Instruction::CALLDATACOPY => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::EXTCODECOPY => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(3).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::MLOAD | Instruction::MSTORE => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Instruction::MSTORE8 => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Instruction::CREATE => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CALL => {
            let in_from: U256 = stack.peek(3).unwrap().into();
            let in_len: U256 = stack.peek(4).unwrap().into();
            let out_from: U256 = stack.peek(5).unwrap().into();
            let out_len: U256 = stack.peek(6).unwrap().into();
            memory_expand(memory_expand(current, Gas::from(in_from), Gas::from(in_len)),
                          Gas::from(out_from), Gas::from(out_len))
        },
        _ => {
            current
        }
    };
    next
}

/// Calculate the gas cost.
pub fn gas_cost<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE |
        Instruction::DELEGATECALL => call_cost(state),
        Instruction::SUICIDE => suicide_cost(state),
        Instruction::SSTORE => sstore_cost(state),

        Instruction::SHA3 => {
            let len = state.stack.peek(1).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::LOG(v) => {
            let len = state.stack.peek(1).unwrap();
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Instruction::EXTCODECOPY => {
            let len = state.stack.peek(3).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(state.patch.gas_extcode) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::CALLDATACOPY | Instruction::CODECOPY => {
            let len = state.stack.peek(2).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::EXP => {
            if state.stack.peek(1).unwrap() == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(state.patch.gas_expbyte) * (Gas::from(1u64) + Gas::from(state.stack.peek(1).unwrap().log2floor()) / Gas::from(8u64))
            }
        }

        Instruction::CREATE => G_CREATE.into(),
        Instruction::JUMPDEST => G_JUMPDEST.into(),
        Instruction::SLOAD => state.patch.gas_sload.into(),

        // W_zero
        Instruction::STOP | Instruction::RETURN
            => G_ZERO.into(),

        // W_base
        Instruction::ADDRESS | Instruction::ORIGIN | Instruction::CALLER |
        Instruction::CALLVALUE | Instruction::CALLDATASIZE |
        Instruction::CODESIZE | Instruction::GASPRICE | Instruction::COINBASE |
        Instruction::TIMESTAMP | Instruction::NUMBER | Instruction::DIFFICULTY |
        Instruction::GASLIMIT | Instruction::POP | Instruction::PC |
        Instruction::MSIZE | Instruction::GAS
            => G_BASE.into(),

        // W_verylow
        Instruction::ADD | Instruction::SUB | Instruction::NOT | Instruction::LT |
        Instruction::GT | Instruction::SLT | Instruction::SGT | Instruction::EQ |
        Instruction::ISZERO | Instruction::AND | Instruction::OR | Instruction::XOR |
        Instruction::BYTE | Instruction::CALLDATALOAD | Instruction::MLOAD |
        Instruction::MSTORE | Instruction::MSTORE8 | Instruction::PUSH(_) |
        Instruction::DUP(_) | Instruction::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Instruction::MUL | Instruction::DIV | Instruction::SDIV | Instruction::MOD |
        Instruction::SMOD | Instruction::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Instruction::ADDMOD | Instruction::MULMOD | Instruction::JUMP
            => G_MID.into(),

        // W_high
        Instruction::JUMPI => G_HIGH.into(),

        // W_extcode
        Instruction::EXTCODESIZE => state.patch.gas_extcode.into(),
        Instruction::BALANCE => state.patch.gas_balance.into(),
        Instruction::BLOCKHASH => G_BLOCKHASH.into(),
    }
}

/// Raise gas stipend for CALL and CALLCODE instruction.
pub fn gas_stipend<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE => {
            let value = state.stack.peek(2).unwrap();

            if value != M256::zero() {
                G_CALLSTIPEND.into()
            } else {
                Gas::zero()
            }
        },
        _ => Gas::zero(),
    }
}

/// Calculate the refunded gas.
pub fn gas_refund<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    match instruction {
        Instruction::SSTORE => {
            let index = state.stack.peek(0).unwrap();
            let value = state.stack.peek(1).unwrap();
            let address = state.context.address;

            if value == M256::zero() && state.account_state.storage(address).unwrap().read(index).unwrap() != M256::zero() {
                Gas::from(R_SCLEAR)
            } else {
                Gas::zero()
            }
        },
        Instruction::SUICIDE => {
            let address: Address = state.stack.peek(0).unwrap().into();
            if state.account_state.is_removed(address) {
                Gas::zero()
            } else {
                Gas::from(R_SUICIDE)
            }
        },
        _ => Gas::zero()
    }
}
<commit_msg>MLOAD, MSTORE/8 memory expand gas cost fix<commit_after>//! Cost calculation logic

use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::{M256, U256};

use std::cmp::max;
use vm::{Memory, Instruction};
use super::State;
use super::precompiled::is_precompiled;

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSIT: usize = 200;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_MEMORY: usize = 3;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn sstore_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let index = machine.stack.peek(0).unwrap();
    let value = machine.stack.peek(1).unwrap();
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage(address).unwrap().read(index).unwrap() == M256::zero() {
        G_SSET.into()
    } else {
        G_SRESET.into()
    }
}

fn call_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    extra_cost(machine)
}

fn extra_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    Gas::from(machine.patch.gas_call) + xfer_cost(machine) + new_cost(machine)
}

fn xfer_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let val = machine.stack.peek(2).unwrap();
    if val != M256::zero() {
        G_CALLVALUE.into()
    } else {
        Gas::zero()
    }
}

fn new_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let address: Address = machine.stack.peek(1).unwrap().into();
    if machine.account_state.balance(address).unwrap() == U256::zero() && machine.account_state.nonce(address).unwrap() == M256::zero() && machine.account_state.code(address).unwrap().len() == 0 && !is_precompiled(address) {
        G_NEWACCOUNT.into()
    } else {
        Gas::zero()
    }
}

fn suicide_cost<M: Memory + Default>(machine: &State<M>) -> Gas {
    let address: Address = machine.stack.peek(0).unwrap().into();
    Gas::from(machine.patch.gas_suicide) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas, return_on_empty: bool) -> Gas {
    if len == Gas::zero() && return_on_empty {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

/// Calculate code deposit cost for a ContractCreation transaction.
pub fn code_deposit_gas(len: usize) -> Gas {
    Gas::from(G_CODEDEPOSIT) * Gas::from(len)
}

/// Calculate the memory gas from the memory cost.
pub fn memory_gas(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

/// Calculate the memory cost. This is the same as the active memory
/// length in the Yellow Paper.
pub fn memory_cost<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    let ref stack = state.stack;

    let current = state.memory_cost;
    let next = match instruction {
        Instruction::SHA3 | Instruction::RETURN | Instruction::LOG(_) => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(1).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len), true)
        },
        Instruction::CODECOPY | Instruction::CALLDATACOPY => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len), true)
        },
        Instruction::EXTCODECOPY => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(3).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len), true)
        },
        Instruction::MLOAD | Instruction::MSTORE => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(32u64), false)
        },
        Instruction::MSTORE8 => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(1u64), false)
        },
        Instruction::CREATE => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len), true)
        },
        Instruction::CALL => {
            let in_from: U256 = stack.peek(3).unwrap().into();
            let in_len: U256 = stack.peek(4).unwrap().into();
            let out_from: U256 = stack.peek(5).unwrap().into();
            let out_len: U256 = stack.peek(6).unwrap().into();
            memory_expand(memory_expand(current, Gas::from(in_from), Gas::from(in_len), true),
                          Gas::from(out_from), Gas::from(out_len), true)
        },
        _ => {
            current
        }
    };
    next
}

/// Calculate the gas cost.
pub fn gas_cost<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE |
        Instruction::DELEGATECALL => call_cost(state),
        Instruction::SUICIDE => suicide_cost(state),
        Instruction::SSTORE => sstore_cost(state),

        Instruction::SHA3 => {
            let len = state.stack.peek(1).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::LOG(v) => {
            let len = state.stack.peek(1).unwrap();
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Instruction::EXTCODECOPY => {
            let len = state.stack.peek(3).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(state.patch.gas_extcode) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::CALLDATACOPY | Instruction::CODECOPY => {
            let len = state.stack.peek(2).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Instruction::EXP => {
            if state.stack.peek(1).unwrap() == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(state.patch.gas_expbyte) * (Gas::from(1u64) + Gas::from(state.stack.peek(1).unwrap().log2floor()) / Gas::from(8u64))
            }
        }

        Instruction::CREATE => G_CREATE.into(),
        Instruction::JUMPDEST => G_JUMPDEST.into(),
        Instruction::SLOAD => state.patch.gas_sload.into(),

        // W_zero
        Instruction::STOP | Instruction::RETURN
            => G_ZERO.into(),

        // W_base
        Instruction::ADDRESS | Instruction::ORIGIN | Instruction::CALLER |
        Instruction::CALLVALUE | Instruction::CALLDATASIZE |
        Instruction::CODESIZE | Instruction::GASPRICE | Instruction::COINBASE |
        Instruction::TIMESTAMP | Instruction::NUMBER | Instruction::DIFFICULTY |
        Instruction::GASLIMIT | Instruction::POP | Instruction::PC |
        Instruction::MSIZE | Instruction::GAS
            => G_BASE.into(),

        // W_verylow
        Instruction::ADD | Instruction::SUB | Instruction::NOT | Instruction::LT |
        Instruction::GT | Instruction::SLT | Instruction::SGT | Instruction::EQ |
        Instruction::ISZERO | Instruction::AND | Instruction::OR | Instruction::XOR |
        Instruction::BYTE | Instruction::CALLDATALOAD | Instruction::MLOAD |
        Instruction::MSTORE | Instruction::MSTORE8 | Instruction::PUSH(_) |
        Instruction::DUP(_) | Instruction::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Instruction::MUL | Instruction::DIV | Instruction::SDIV | Instruction::MOD |
        Instruction::SMOD | Instruction::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Instruction::ADDMOD | Instruction::MULMOD | Instruction::JUMP
            => G_MID.into(),

        // W_high
        Instruction::JUMPI => G_HIGH.into(),

        // W_extcode
        Instruction::EXTCODESIZE => state.patch.gas_extcode.into(),
        Instruction::BALANCE => state.patch.gas_balance.into(),
        Instruction::BLOCKHASH => G_BLOCKHASH.into(),
    }
}

/// Raise gas stipend for CALL and CALLCODE instruction.
pub fn gas_stipend<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE => {
            let value = state.stack.peek(2).unwrap();

            if value != M256::zero() {
                G_CALLSTIPEND.into()
            } else {
                Gas::zero()
            }
        },
        _ => Gas::zero(),
    }
}

/// Calculate the refunded gas.
pub fn gas_refund<M: Memory + Default>(instruction: Instruction, state: &State<M>) -> Gas {
    match instruction {
        Instruction::SSTORE => {
            let index = state.stack.peek(0).unwrap();
            let value = state.stack.peek(1).unwrap();
            let address = state.context.address;

            if value == M256::zero() && state.account_state.storage(address).unwrap().read(index).unwrap() != M256::zero() {
                Gas::from(R_SCLEAR)
            } else {
                Gas::zero()
            }
        },
        Instruction::SUICIDE => {
            let address: Address = state.stack.peek(0).unwrap().into();
            if state.account_state.is_removed(address) {
                Gas::zero()
            } else {
                Gas::from(R_SUICIDE)
            }
        },
        _ => Gas::zero()
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::all)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_clone)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]

#[macro_use]
extern crate cargo_test_macro;

mod advanced_env;
mod alt_registry;
mod bad_config;
mod bad_manifest_path;
mod bench;
mod build;
mod build_plan;
mod build_script;
mod build_script_env;
mod build_script_extra_link_arg;
mod cache_messages;
mod cargo_alias_config;
mod cargo_command;
mod cargo_config;
mod cargo_env_config;
mod cargo_features;
mod cargo_targets;
mod cfg;
mod check;
mod clean;
mod collisions;
mod concurrent;
mod config;
mod config_cli;
mod config_include;
mod corrupt_git;
mod credential_process;
mod cross_compile;
mod cross_publish;
mod custom_target;
mod death;
mod dep_info;
mod directory;
mod doc;
mod edition;
mod error;
mod features;
mod features2;
mod features_namespaced;
mod fetch;
mod fix;
mod freshness;
mod future_incompat_report;
mod generate_lockfile;
mod git;
mod git_auth;
mod git_gc;
mod glob_targets;
mod help;
mod init;
mod install;
mod install_upgrade;
mod jobserver;
mod list_availables;
mod local_registry;
mod locate_project;
mod lockfile_compat;
mod login;
mod logout;
mod lto;
mod member_discovery;
mod member_errors;
mod message_format;
mod metabuild;
mod metadata;
mod minimal_versions;
mod multitarget;
mod net_config;
mod new;
mod offline;
mod old_cargos;
mod out_dir;
mod owner;
mod package;
mod package_features;
mod patch;
mod path;
mod paths;
mod pkgid;
mod plugins;
mod proc_macro;
mod profile_config;
mod profile_custom;
mod profile_overrides;
mod profile_targets;
mod profiles;
mod progress;
mod pub_priv;
mod publish;
mod publish_lockfile;
mod read_manifest;
mod registry;
mod rename_deps;
mod replace;
mod required_features;
mod run;
mod rust_version;
mod rustc;
mod rustc_info_cache;
mod rustdoc;
mod rustdoc_extern_html;
mod rustdocflags;
mod rustflags;
mod search;
mod shell_quoting;
mod standard_lib;
mod test;
mod timings;
mod tool_paths;
mod tree;
mod tree_graph_features;
mod unit_graph;
mod update;
mod vendor;
mod verify_project;
mod version;
mod warn_on_failure;
mod weak_dep_features;
mod workspaces;
mod yank;

#[cargo_test]
fn aaa_trigger_cross_compile_disabled_check() {
    // This triggers the cross compile disabled check to run ASAP, see #5141
    cargo_test_support::cross_compile::disabled();
}
<commit_msg>Update testsuite/main.rs lint comment.<commit_after>// See src/cargo/lib.rs for notes on these lint settings.
#![warn(rust_2018_idioms)]
#![allow(clippy::all)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_clone)]
#![cfg_attr(feature = "deny-warnings", deny(warnings))]

#[macro_use]
extern crate cargo_test_macro;

mod advanced_env;
mod alt_registry;
mod bad_config;
mod bad_manifest_path;
mod bench;
mod build;
mod build_plan;
mod build_script;
mod build_script_env;
mod build_script_extra_link_arg;
mod cache_messages;
mod cargo_alias_config;
mod cargo_command;
mod cargo_config;
mod cargo_env_config;
mod cargo_features;
mod cargo_targets;
mod cfg;
mod check;
mod clean;
mod collisions;
mod concurrent;
mod config;
mod config_cli;
mod config_include;
mod corrupt_git;
mod credential_process;
mod cross_compile;
mod cross_publish;
mod custom_target;
mod death;
mod dep_info;
mod directory;
mod doc;
mod edition;
mod error;
mod features;
mod features2;
mod features_namespaced;
mod fetch;
mod fix;
mod freshness;
mod future_incompat_report;
mod generate_lockfile;
mod git;
mod git_auth;
mod git_gc;
mod glob_targets;
mod help;
mod init;
mod install;
mod install_upgrade;
mod jobserver;
mod list_availables;
mod local_registry;
mod locate_project;
mod lockfile_compat;
mod login;
mod logout;
mod lto;
mod member_discovery;
mod member_errors;
mod message_format;
mod metabuild;
mod metadata;
mod minimal_versions;
mod multitarget;
mod net_config;
mod new;
mod offline;
mod old_cargos;
mod out_dir;
mod owner;
mod package;
mod package_features;
mod patch;
mod path;
mod paths;
mod pkgid;
mod plugins;
mod proc_macro;
mod profile_config;
mod profile_custom;
mod profile_overrides;
mod profile_targets;
mod profiles;
mod progress;
mod pub_priv;
mod publish;
mod publish_lockfile;
mod read_manifest;
mod registry;
mod rename_deps;
mod replace;
mod required_features;
mod run;
mod rust_version;
mod rustc;
mod rustc_info_cache;
mod rustdoc;
mod rustdoc_extern_html;
mod rustdocflags;
mod rustflags;
mod search;
mod shell_quoting;
mod standard_lib;
mod test;
mod timings;
mod tool_paths;
mod tree;
mod tree_graph_features;
mod unit_graph;
mod update;
mod vendor;
mod verify_project;
mod version;
mod warn_on_failure;
mod weak_dep_features;
mod workspaces;
mod yank;

#[cargo_test]
fn aaa_trigger_cross_compile_disabled_check() {
    // This triggers the cross compile disabled check to run ASAP, see #5141
    cargo_test_support::cross_compile::disabled();
}
<|endoftext|>


<commit_before>extern crate challenges;
use challenges::errors::ChallengeError;
use std::env;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

fn main() {
    let mut challenges = Vec::<fn() -> Result<()>>::new();
    challenges::set1::add_challenges(&mut challenges);
    challenges::set2::add_challenges(&mut challenges);
    challenges::set3::add_challenges(&mut challenges);
    challenges::set4::add_challenges(&mut challenges);
    challenges::set5::add_challenges(&mut challenges);
    challenges::set6::add_challenges(&mut challenges);

    let challenges_count = challenges.len();

    match challenge_indices(challenges_count) {
        Ok(indices) => {
            for i in indices {
                run_challenge(challenges[i - 1], i);
            }
        }
        Err(arg) => {
            println!(
                "Provided argument \"{}\" is invalid. Expected a number between 1 and {} ",
                arg, challenges_count
            );
        }
    }
}

fn run_challenge<F>(exercise: F, challenge_number: usize)
where
    F: Fn() -> Result<()>,
{
    match exercise() {
        Ok(_) => println!("Challenge {:02}: Success", challenge_number),
        Err(ref e) => {
            if e.downcast_ref::<ChallengeError>().is_some() {
                println!("Challenge {:02}: {}", challenge_number, e);
            } else {
                println!("Challenge {:02}: An error occured: {}", challenge_number, e);
                // TODO Does this work?
                while let Some(e) = e.source() {
                    println!("{: <4}caused by: {}", "", e);
                }
                // TODO
                //let backtrace = e.backtrace().to_string();
                //if !backtrace.is_empty() {
                //    println!("{: <4}{}", "", e.backtrace());
                //}
            }
        }
    };
}

fn challenge_indices(challenges_count: usize) -> std::result::Result<Vec<usize>, String> {
    let args = env::args();
    if args.len() <= 1 {
        return Ok((1..=challenges_count).collect());
    }

    let mut indices = Vec::new();
    for arg in args.skip(1) {
        if let Ok(index) = arg.parse::<usize>() {
            if index >= 1 && index <= challenges_count {
                indices.push(index);
                continue;
            }
        }
        return Err(arg);
    }
    Ok(indices)
}
<commit_msg>Fix recursion<commit_after>extern crate challenges;
use challenges::errors::ChallengeError;
use std::env;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

fn main() {
    let mut challenges = Vec::<fn() -> Result<()>>::new();
    challenges::set1::add_challenges(&mut challenges);
    challenges::set2::add_challenges(&mut challenges);
    challenges::set3::add_challenges(&mut challenges);
    challenges::set4::add_challenges(&mut challenges);
    challenges::set5::add_challenges(&mut challenges);
    challenges::set6::add_challenges(&mut challenges);

    let challenges_count = challenges.len();

    match challenge_indices(challenges_count) {
        Ok(indices) => {
            for i in indices {
                run_challenge(challenges[i - 1], i);
            }
        }
        Err(arg) => {
            println!(
                "Provided argument \"{}\" is invalid. Expected a number between 1 and {} ",
                arg, challenges_count
            );
        }
    }
}

fn run_challenge<F>(exercise: F, challenge_number: usize)
where
    F: Fn() -> Result<()>,
{
    match exercise() {
        Ok(_) => println!("Challenge {:02}: Success", challenge_number),
        Err(ref e) => {
            if e.downcast_ref::<ChallengeError>().is_some() {
                println!("Challenge {:02}: {}", challenge_number, e);
            } else {
                println!("Challenge {:02}: An error occured: {}", challenge_number, e);
                let mut source = e.source();
                while let Some(e) = source {
                    println!("{: <4}caused by: {}", "", e);
                    source = e.source();
                }
                // TODO
                //let backtrace = e.backtrace().to_string();
                //if !backtrace.is_empty() {
                //    println!("{: <4}{}", "", e.backtrace());
                //}
            }
        }
    };
}

fn challenge_indices(challenges_count: usize) -> std::result::Result<Vec<usize>, String> {
    let args = env::args();
    if args.len() <= 1 {
        return Ok((1..=challenges_count).collect());
    }

    let mut indices = Vec::new();
    for arg in args.skip(1) {
        if let Ok(index) = arg.parse::<usize>() {
            if index >= 1 && index <= challenges_count {
                indices.push(index);
                continue;
            }
        }
        return Err(arg);
    }
    Ok(indices)
}
<|endoftext|>


<commit_before>
use rocks_sys as ll;

use options::Options;

pub struct DbDumpTool {
    raw: *mut ll::rocks_dump_options_t,
}

impl DbDumpTool {
    pub fn new(db_path: &str, dump_location: &str) -> DbDumpTool {
        unsafe {
            let raw = ll::rocks_dump_options_create();
            ll::rocks_dump_options_set_db_path(raw,
                                               db_path.as_bytes().as_ptr() as *const _,
                                               db_path.as_bytes().len());
            ll::rocks_dump_options_set_dump_location(raw,
                                                     dump_location.as_bytes().as_ptr() as *const _,
                                                     dump_location.as_bytes().len());
            DbDumpTool {
                raw: raw
            }
        }
    }

    /// Dont include db information header in the dump
    ///
    /// DEFAULT: false
    pub fn anonymous(self, val: bool) -> Self {
        unsafe {
            ll::rocks_dump_options_set_anonymous(self.raw, val as u8);
        }
        self
    }

    pub fn run(self, options: &Options) -> bool {
        unsafe {
            ll::rocks_db_dump_tool_run(self.raw, options.raw()) != 0
        }
    }
}

pub struct DbUndumpTool {
    raw: *mut ll::rocks_undump_options_t,
}

impl DbUndumpTool {
    pub fn new(db_path: &str, dump_location: &str) -> DbUndumpTool {
        unsafe {
            let raw = ll::rocks_undump_options_create();
            ll::rocks_undump_options_set_db_path(raw,
                                               db_path.as_bytes().as_ptr() as *const _,
                                               db_path.as_bytes().len());
            ll::rocks_undump_options_set_dump_location(raw,
                                                       dump_location.as_bytes().as_ptr() as *const _,
                                                       dump_location.as_bytes().len());
            DbUndumpTool {
                raw: raw
            }
        }
    }

    /// Compact the db after loading the dumped file
    ///
    /// DEFAULT: false
    pub fn compact_db(self, val: bool) -> Self {
        unsafe {
            ll::rocks_undump_options_set_compact_db(self.raw, val as u8);
        }
        self
    }

    pub fn run(self, options: &Options) -> bool {
        unsafe {
            ll::rocks_db_undump_tool_run(self.raw, options.raw()) != 0
        }
    }
}

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

    // TODO: create a test db
    #[test]
    fn db_dump_and_undump() {
        let dump_ok = DbDumpTool::new("./data", "./output.dump")
            .run(&Options::default());

        assert!(dump_ok);

        let undump_ok = DbUndumpTool::new("./data2", "./output.dump")
            .run(&Options::default());

        assert!(undump_ok);
    }
}
<commit_msg>db_dump_tool: fix mem leak<commit_after>
use rocks_sys as ll;

use options::Options;

pub struct DbDumpTool {
    raw: *mut ll::rocks_dump_options_t,
}

impl Drop for DbDumpTool {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_dump_options_destroy(self.raw)
        }
    }
}

impl DbDumpTool {
    pub fn new(db_path: &str, dump_location: &str) -> DbDumpTool {
        unsafe {
            let raw = ll::rocks_dump_options_create();
            ll::rocks_dump_options_set_db_path(raw,
                                               db_path.as_bytes().as_ptr() as *const _,
                                               db_path.as_bytes().len());
            ll::rocks_dump_options_set_dump_location(raw,
                                                     dump_location.as_bytes().as_ptr() as *const _,
                                                     dump_location.as_bytes().len());
            DbDumpTool {
                raw: raw
            }
        }
    }

    /// Dont include db information header in the dump
    ///
    /// DEFAULT: false
    pub fn anonymous(self, val: bool) -> Self {
        unsafe {
            ll::rocks_dump_options_set_anonymous(self.raw, val as u8);
        }
        self
    }

    pub fn run(self, options: &Options) -> bool {
        unsafe {
            ll::rocks_db_dump_tool_run(self.raw, options.raw()) != 0
        }
    }
}

pub struct DbUndumpTool {
    raw: *mut ll::rocks_undump_options_t,
}

impl Drop for DbUndumpTool {
    fn drop(&mut self) {
        unsafe {
            ll::rocks_undump_options_destroy(self.raw)
        }
    }
}

impl DbUndumpTool {
    pub fn new(db_path: &str, dump_location: &str) -> DbUndumpTool {
        unsafe {
            let raw = ll::rocks_undump_options_create();
            ll::rocks_undump_options_set_db_path(raw,
                                               db_path.as_bytes().as_ptr() as *const _,
                                               db_path.as_bytes().len());
            ll::rocks_undump_options_set_dump_location(raw,
                                                       dump_location.as_bytes().as_ptr() as *const _,
                                                       dump_location.as_bytes().len());
            DbUndumpTool {
                raw: raw
            }
        }
    }

    /// Compact the db after loading the dumped file
    ///
    /// DEFAULT: false
    pub fn compact_db(self, val: bool) -> Self {
        unsafe {
            ll::rocks_undump_options_set_compact_db(self.raw, val as u8);
        }
        self
    }

    pub fn run(self, options: &Options) -> bool {
        unsafe {
            ll::rocks_db_undump_tool_run(self.raw, options.raw()) != 0
        }
    }
}

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

    // TODO: create a test db
    #[test]
    fn db_dump_and_undump() {
        let dump_ok = DbDumpTool::new("./data", "./output.dump")
            .run(&Options::default());

        assert!(dump_ok);

        let undump_ok = DbUndumpTool::new("./data2", "./output.dump")
            .run(&Options::default());

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


<commit_before>use actix_files as fs;
use actix_identity::Identity;
use actix_web::{error, get, web, Error, HttpResponse, Result};
use askama::Template;
use std::path::Path;

use crate::pictures::{ImageTypes, TypeParams};
use crate::DbPool;

use super::actions;
use crate::models::Deafie;
use crate::utils::deafie_image_base_path;

use crate::uri_helpers::*;
use crate::utils as filters;

#[derive(Template)]
#[template(path = "deafies/show.html.jinja")]
struct Show<'a> {
    lang: &'a str,
    title: Option<&'a str>,
    page_type: Option<&'a str>,
    page_image: Option<&'a str>,
    body_id: Option<&'a str>,
    logged_in: bool,

    deafie: &'a Deafie,
    index: bool,
    atom: bool,
}

#[get("/{year}/{month}/{slug}.{ext}")]
pub async fn show_img(
    ident: Identity,
    pool: web::Data<DbPool>,
    path: web::Path<(i32, String, String, String)>,
    pic_type: web::Query<TypeParams>,
) -> Result<fs::NamedFile, Error> {
    let logged_in = ident.identity().is_some();
    let (year, month, slug, _ext) = path.into_inner();
    let guid = format!("{}/{}/{}", year, month, slug);

    let pic_type = match pic_type.into_inner().pic_type {
        Some(val) => val,
        None => ImageTypes::Original,
    };

    let path_part = match pic_type {
        ImageTypes::Large => "large",
        ImageTypes::Original => "original",
        ImageTypes::Thumbnail => "thumbnail",
    };

    let deafie = web::block(move || {
        let conn = pool.get()?;
        actions::get_deafie_by_slug(&guid, !logged_in, &conn)
    })
    .await?
    .map_err(|e| error::ErrorInternalServerError(format!("Database error: {}", e)))?;

    let image_name = match deafie.image_name {
        Some(image_name) => Ok(image_name),
        None => Err(error::ErrorInternalServerError("article has no image")),
    }?;

    let mut path = format!(
        "{}/{}/{}/{}",
        deafie_image_base_path(),
        deafie.id,
        path_part,
        image_name
    );

    if !Path::new(&path).exists() {
        path = format!("{}/{}/original/{}", deafie_image_base_path(), deafie.id, image_name);
    }

    Ok(fs::NamedFile::open(path)?)
}

#[get("/{year}/{month}/{slug}")]
pub async fn show(
    ident: Identity,
    pool: web::Data<DbPool>,
    path: web::Path<(i32, String, String)>,
) -> Result<HttpResponse, Error> {
    let logged_in = ident.identity().is_some();
    let (year, month, slug) = path.into_inner();
    let guid = format!("{}/{}/{}", year, month, slug);

    let deafie = web::block(move || {
        let conn = pool.get()?;
        actions::get_deafie_by_slug(&guid, !logged_in, &conn)
    })
    .await?
    .map_err(|e| error::ErrorInternalServerError(format!("Database error: {}", e)))?;

    let s = Show {
        lang: "de",
        title: Some(&deafie.title.clone()),
        page_type: Some("blog"),
        page_image: None,
        body_id: None,
        logged_in,
        deafie: &deafie,
        index: false,
        atom: false,
    }
    .render()
    .unwrap();

    Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(s))
}
<commit_msg>article image is now set on og:image<commit_after>use actix_files as fs;
use actix_identity::Identity;
use actix_web::{error, get, web, Error, HttpResponse, Result};
use askama::Template;
use std::path::Path;

use crate::pictures::{ImageTypes, TypeParams};
use crate::DbPool;

use super::actions;
use crate::models::Deafie;
use crate::utils::deafie_image_base_path;

use crate::uri_helpers::*;
use crate::utils as filters;

#[derive(Template)]
#[template(path = "deafies/show.html.jinja")]
struct Show<'a> {
    lang: &'a str,
    title: Option<&'a str>,
    page_type: Option<&'a str>,
    page_image: Option<&'a str>,
    body_id: Option<&'a str>,
    logged_in: bool,

    deafie: &'a Deafie,
    index: bool,
    atom: bool,
}

#[get("/{year}/{month}/{slug}.{ext}")]
pub async fn show_img(
    ident: Identity,
    pool: web::Data<DbPool>,
    path: web::Path<(i32, String, String, String)>,
    pic_type: web::Query<TypeParams>,
) -> Result<fs::NamedFile, Error> {
    let logged_in = ident.identity().is_some();
    let (year, month, slug, _ext) = path.into_inner();
    let guid = format!("{}/{}/{}", year, month, slug);

    let pic_type = match pic_type.into_inner().pic_type {
        Some(val) => val,
        None => ImageTypes::Original,
    };

    let path_part = match pic_type {
        ImageTypes::Large => "large",
        ImageTypes::Original => "original",
        ImageTypes::Thumbnail => "thumbnail",
    };

    let deafie = web::block(move || {
        let conn = pool.get()?;
        actions::get_deafie_by_slug(&guid, !logged_in, &conn)
    })
    .await?
    .map_err(|e| error::ErrorInternalServerError(format!("Database error: {}", e)))?;

    let image_name = match deafie.image_name {
        Some(image_name) => Ok(image_name),
        None => Err(error::ErrorInternalServerError("article has no image")),
    }?;

    let mut path = format!(
        "{}/{}/{}/{}",
        deafie_image_base_path(),
        deafie.id,
        path_part,
        image_name
    );

    if !Path::new(&path).exists() {
        path = format!("{}/{}/original/{}", deafie_image_base_path(), deafie.id, image_name);
    }

    Ok(fs::NamedFile::open(path)?)
}

#[get("/{year}/{month}/{slug}")]
pub async fn show(
    ident: Identity,
    pool: web::Data<DbPool>,
    path: web::Path<(i32, String, String)>,
) -> Result<HttpResponse, Error> {
    let logged_in = ident.identity().is_some();
    let (year, month, slug) = path.into_inner();
    let guid = format!("{}/{}/{}", year, month, slug);

    let deafie = web::block(move || {
        let conn = pool.get()?;
        actions::get_deafie_by_slug(&guid, !logged_in, &conn)
    })
    .await?
    .map_err(|e| error::ErrorInternalServerError(format!("Database error: {}", e)))?;

    let uri = deafie_img_uri(&deafie, None);
    let page_image = match deafie.image_name {
        Some(_) => Some(uri.as_str()),
        None => None,
    };

    let s = Show {
        lang: "de",
        title: Some(&deafie.title.clone()),
        page_type: Some("blog"),
        page_image,
        body_id: None,
        logged_in,
        deafie: &deafie,
        index: false,
        atom: false,
    }
    .render()
    .unwrap();

    Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(s))
}
<|endoftext|>


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

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a, DfaType: 'a> {
    //
    // Would like to do this without the references and weird lifetime stuff. There's a bunch of limitations about what you can do
    // when calling references to traits vs concrete types that make designing rust code very annoying. However, if you have a struct
    // declared thusly: struct Foo<Bar, Quux: Baz<Bar>> and only use a field of type Quux then it'll moan that 'Bar' is unused, which
    // is incorrect (it's used wherever Quux is used by definition), so you have to declare Foo<Bar> and use a reference to Baz<Bar>
    // which means a lot of code won't work due to the whole mess around things needing to be sized.
    //
    // This basically means we can't declare ndfa or builder here using their real types. PhantomData also doesn't work because rust
    // isn't smart enough to work out that if it knows the type of the state machine it also knows what InputSymbol and OutputSymbol
    // are.
    //

    ndfa: &'a StateMachine<InputSymbol, OutputSymbol>,
    builder: &'a mut DfaBuilder<InputSymbol, OutputSymbol, DfaType>,
}

impl<'a, InputSymbol: PartialOrd+'a, OutputSymbol: 'a, DfaType: 'a> DfaCompiler<'a, InputSymbol, OutputSymbol, DfaType> {
    pub fn new(ndfa: &'a StateMachine<InputSymbol, OutputSymbol>, builder: &'a mut DfaBuilder<InputSymbol, OutputSymbol, DfaType>) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder }
    }
}
<commit_msg>OK, first attempt at getting the compiler to work<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: PartialOrd, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    ndfa: Ndfa,
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

impl<InputSymbol: PartialOrd, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;

    #[test]
    fn create_compiler() {
        let ndfa = "abc".into_pattern().to_ndfa("success");
        let builder = SymbolRangeDfaBuilder::new();

        let compiler = DfaCompiler::new(ndfa, builder);
    }
}<|endoftext|>


<commit_before>#![deny(bare_trait_objects)]

use failure::{bail, ensure, format_err, Error};
use libc::c_ulong;
use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region};
use lucet_wasi::host::__wasi_exitcode_t;
use lucet_wasi::{WasiCtx, WasiCtxBuilder};
use lucet_wasi_sdk::{CompileOpts, Link};
use lucetc::{Bindings, Lucetc, LucetcOpts};
use rand::prelude::random;
use rayon::prelude::*;
use regex::Regex;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::prelude::{FromRawFd, IntoRawFd, OpenOptionsExt};
use std::path::{Path, PathBuf};
use std::process::{exit, Command, Stdio};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use structopt::StructOpt;
use tempfile::TempDir;
use wait_timeout::ChildExt;

const LUCET_WASI_FUZZ_ROOT: &'static str = env!("CARGO_MANIFEST_DIR");

type Seed = c_ulong;

#[derive(StructOpt, Debug)]
#[structopt(name = "lucet-wasi-fuzz")]
enum Config {
    /// Test the Lucet toolchain against native code execution using Csmith
    #[structopt(name = "fuzz")]
    Fuzz {
        #[structopt(short = "n", long = "num-tests", default_value = "100")]
        /// The number of tests to run
        num_tests: usize,
    },

    /// Reduce a test case, starting from the given Csmith seed
    #[structopt(name = "creduce")]
    Creduce { seed: Seed },

    /// Creduce interestingness check (probably not useful directly)
    #[structopt(name = "creduce-interesting")]
    CreduceInteresting { creduce_src: PathBuf },

    /// Run a test case with the given Csmith seed
    #[structopt(name = "test-seed")]
    TestSeed { seed: Seed },
}

fn main() {
    lucet_runtime::lucet_internal_ensure_linked();

    match Config::from_args() {
        Config::Fuzz { num_tests } => run_many(num_tests),
        Config::Creduce { seed } => run_creduce_driver(seed),
        Config::CreduceInteresting { creduce_src } => run_creduce_interestingness(creduce_src),
        Config::TestSeed { seed } => run_one_seed(seed),
    }
}

fn run_creduce_driver(seed: Seed) {
    let tmpdir = TempDir::new().unwrap();

    // make the driver script

    let mut script = std::fs::OpenOptions::new()
        .create(true)
        .write(true)
        .mode(0o777)
        .open(tmpdir.path().join("script.sh"))
        .unwrap();

    let current_exe = std::env::current_exe().unwrap();

    write!(
        script,
        "{}",
        format!(
            "#!/usr/bin/env sh\n{} creduce-interesting gen.c",
            current_exe.display()
        ),
    )
    .unwrap();

    drop(script);

    // reproduce the generated program, and then preprocess it

    let st = Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(tmpdir.path().join("gen-original.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new("clang")
        .arg("-I/usr/include/csmith")
        .arg("-m32")
        .arg("-E")
        .arg("-P")
        .arg(tmpdir.path().join("gen-original.c"))
        .arg("-o")
        .arg(tmpdir.path().join("gen.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new("creduce")
        .current_dir(tmpdir.path())
        .arg("--n")
        .arg(format!("{}", std::cmp::max(1, num_cpus::get() - 1)))
        .arg("script.sh")
        .arg("gen.c")
        .status()
        .unwrap();
    assert!(st.success());

    print!(
        "{}",
        std::fs::read_to_string(tmpdir.path().join("gen.c")).unwrap()
    );
}

fn run_creduce_interestingness<P: AsRef<Path>>(src: P) {
    let tmpdir = TempDir::new().unwrap();

    match run_both(&tmpdir, src, None) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            let expected = String::from_utf8_lossy(&expected);
            let actual = String::from_utf8_lossy(&actual);
            println!("native: {}", &expected);
            println!("lucet-wasi: {}", &actual);

            let re = Regex::new(r"^checksum = ([[:xdigit:]]{8})").unwrap();

            // a coarse way to stop creduce from producing degenerate cases that happen to yield
            // different output

            let expected_checksum = if let Some(caps) = re.captures(&expected) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // not interesting: no checksum captured from native output
                    exit(1);
                }
            } else {
                // not interesting: no checksum captured from native output
                exit(1);
            };

            let actual_checksum = if let Some(caps) = re.captures(&actual) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // interesting: checksum captured from native output but not wasm
                    exit(0)
                }
            } else {
                // interesting: checksum captured from native output but not wasm
                exit(0)
            };

            if expected_checksum == actual_checksum {
                // they match; not interesting
                exit(1);
            } else {
                exit(0);
            }
        }
        Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error),
    }
    exit(1);
}

fn run_one_seed(seed: Seed) {
    match run_one(Some(seed)) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error),
    }
}

fn run_many(num_tests: usize) {
    let mut progress = progress::Bar::new();
    progress.set_job_title(&format!("Running {} tests", num_tests));

    let progress = Arc::new(Mutex::new(progress));
    let num_finished = Arc::new(Mutex::new(0));

    let res = (0..num_tests)
        .into_par_iter()
        .try_for_each(|_| match run_one(None) {
            Ok(TestResult::Passed) | Ok(TestResult::Ignored) => {
                let mut num_finished = num_finished.lock().unwrap();
                *num_finished += 1;
                let percentage = (*num_finished as f32 / num_tests as f32) * 100.0;
                progress
                    .lock()
                    .unwrap()
                    .reach_percent(percentage.floor() as i32);
                Ok(())
            }
            Ok(fail) => Err(fail),
            Err(error) => Err(TestResult::Errored { error }),
        });

    progress.lock().unwrap().jobs_done();

    match res {
        Err(TestResult::Failed {
            seed,
            expected,
            actual,
        }) => {
            println!("test failed with seed {}\n", seed.unwrap());
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Err(TestResult::Errored { error }) => println!("test errored: {}", error),
        Err(_) => unreachable!(),
        Ok(()) => println!("all tests passed"),
    }
}

fn gen_c<P: AsRef<Path>>(gen_c_path: P, seed: Seed) -> Result<(), Error> {
    Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(gen_c_path.as_ref())
        .status()?;
    Ok(())
}

fn run_both<P: AsRef<Path>>(
    tmpdir: &TempDir,
    src: P,
    seed: Option<Seed>,
) -> Result<TestResult, Error> {
    let native_stdout = if let Some(stdout) = run_native(&tmpdir, src.as_ref())? {
        stdout
    } else {
        return Ok(TestResult::Ignored);
    };

    let (exitcode, wasm_stdout) = run_with_stdout(&tmpdir, src.as_ref())?;

    assert_eq!(exitcode, 0);

    if &wasm_stdout != &native_stdout {
        Ok(TestResult::Failed {
            seed,
            expected: native_stdout,
            actual: wasm_stdout,
        })
    } else {
        Ok(TestResult::Passed)
    }
}

fn run_native<P: AsRef<Path>>(tmpdir: &TempDir, gen_c_path: P) -> Result<Option<Vec<u8>>, Error> {
    let gen_path = tmpdir.path().join("gen");

    let res = Command::new("clang")
        .arg("-m32")
        .arg("-std=c11")
        .arg("-Werror=format")
        .arg("-Werror=uninitialized")
        .arg("-Werror=conditional-uninitialized")
        .arg("-I/usr/include/csmith")
        .arg(gen_c_path.as_ref())
        .arg("-o")
        .arg(&gen_path)
        .output()?;
    ensure!(res.status.success(), "native C compilation failed");

    if String::from_utf8_lossy(&res.stderr).contains("too few arguments in call") {
        bail!("saw \"too few arguments in call\" warning");
    }

    let mut native_child = Command::new(&gen_path).stdout(Stdio::piped()).spawn()?;

    let exitcode = match native_child.wait_timeout(Duration::from_millis(1000))? {
        Some(status) => status.code(),
        None => {
            native_child.kill()?;
            native_child.wait()?.code()
        }
    };

    match exitcode {
        None => {
            // native code diverged or took too long, so was killed by the timeout
            return Ok(None);
        }
        Some(0) => (),
        Some(code) => {
            println!("native code returned non-zero exit code: {}", code);
            return Ok(None);
        }
    }

    let mut native_stdout = vec![];
    native_child
        .stdout
        .ok_or(format_err!("couldn't get stdout"))?
        .read_to_end(&mut native_stdout)?;

    Ok(Some(native_stdout))
}

enum TestResult {
    Passed,
    Ignored,
    Failed {
        seed: Option<Seed>,
        expected: Vec<u8>,
        actual: Vec<u8>,
    },
    Errored {
        error: Error,
    },
}

fn run_one(seed: Option<Seed>) -> Result<TestResult, Error> {
    let tmpdir = TempDir::new().unwrap();

    let gen_c_path = tmpdir.path().join("gen.c");

    let seed = seed.unwrap_or(random::<Seed>());
    gen_c(&gen_c_path, seed)?;

    run_both(&tmpdir, &gen_c_path, Some(seed))
}

fn run_with_stdout<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
) -> Result<(__wasi_exitcode_t, Vec<u8>), Error> {
    let ctx = WasiCtxBuilder::new().args(&["gen"]);

    let (pipe_out, pipe_in) = nix::unistd::pipe()?;

    let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?;

    let exitcode = run(tmpdir, path, ctx)?;

    let mut stdout_file = unsafe { File::from_raw_fd(pipe_out) };
    let mut stdout = vec![];
    stdout_file.read_to_end(&mut stdout)?;
    nix::unistd::close(stdout_file.into_raw_fd())?;

    Ok((exitcode, stdout))
}

fn run<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
    ctx: WasiCtx,
) -> Result<__wasi_exitcode_t, Error> {
    let region = MmapRegion::create(1, &Limits::default())?;
    let module = wasi_test(tmpdir, path)?;

    let mut inst = region
        .new_instance_builder(module)
        .with_embed_ctx(ctx)
        .build()?;

    match inst.run("_start", &[]) {
        // normal termination implies 0 exit code
        Ok(_) => Ok(0),
        Err(lucet_runtime::Error::RuntimeTerminated(
            lucet_runtime::TerminationDetails::Provided(any),
        )) => Ok(*any
            .downcast_ref::<__wasi_exitcode_t>()
            .expect("termination yields an exitcode")),
        Err(e) => bail!("runtime error: {}", e),
    }
}

fn wasi_test<P: AsRef<Path>>(tmpdir: &TempDir, c_file: P) -> Result<Arc<dyn Module>, Error> {
    let wasm_build = Link::new(&[c_file]).with_cflag("-I/usr/include/csmith");

    let wasm_file = tmpdir.path().join("out.wasm");

    wasm_build.link(wasm_file.clone())?;

    let bindings = Bindings::from_file(
        Path::new(LUCET_WASI_FUZZ_ROOT)
            .parent()
            .unwrap()
            .join("lucet-wasi")
            .join("bindings.json"),
    )?;

    let native_build = Lucetc::new(wasm_file).with_bindings(bindings);

    let so_file = tmpdir.path().join("out.so");

    native_build.shared_object_file(so_file.clone())?;

    let dlmodule = DlModule::load(so_file)?;

    Ok(dlmodule as Arc<dyn Module>)
}
<commit_msg>lucet-wasi-fuzz: ensure lucet_wasi hostcalls linked<commit_after>#![deny(bare_trait_objects)]

use failure::{bail, ensure, format_err, Error};
use libc::c_ulong;
use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region};
use lucet_wasi::host::__wasi_exitcode_t;
use lucet_wasi::{WasiCtx, WasiCtxBuilder};
use lucet_wasi_sdk::{CompileOpts, Link};
use lucetc::{Bindings, Lucetc, LucetcOpts};
use rand::prelude::random;
use rayon::prelude::*;
use regex::Regex;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::prelude::{FromRawFd, IntoRawFd, OpenOptionsExt};
use std::path::{Path, PathBuf};
use std::process::{exit, Command, Stdio};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use structopt::StructOpt;
use tempfile::TempDir;
use wait_timeout::ChildExt;

const LUCET_WASI_FUZZ_ROOT: &'static str = env!("CARGO_MANIFEST_DIR");

type Seed = c_ulong;

#[derive(StructOpt, Debug)]
#[structopt(name = "lucet-wasi-fuzz")]
enum Config {
    /// Test the Lucet toolchain against native code execution using Csmith
    #[structopt(name = "fuzz")]
    Fuzz {
        #[structopt(short = "n", long = "num-tests", default_value = "100")]
        /// The number of tests to run
        num_tests: usize,
    },

    /// Reduce a test case, starting from the given Csmith seed
    #[structopt(name = "creduce")]
    Creduce { seed: Seed },

    /// Creduce interestingness check (probably not useful directly)
    #[structopt(name = "creduce-interesting")]
    CreduceInteresting { creduce_src: PathBuf },

    /// Run a test case with the given Csmith seed
    #[structopt(name = "test-seed")]
    TestSeed { seed: Seed },
}

fn main() {
    lucet_runtime::lucet_internal_ensure_linked();
    lucet_wasi::hostcalls::ensure_linked();

    match Config::from_args() {
        Config::Fuzz { num_tests } => run_many(num_tests),
        Config::Creduce { seed } => run_creduce_driver(seed),
        Config::CreduceInteresting { creduce_src } => run_creduce_interestingness(creduce_src),
        Config::TestSeed { seed } => run_one_seed(seed),
    }
}

fn run_creduce_driver(seed: Seed) {
    let tmpdir = TempDir::new().unwrap();

    // make the driver script

    let mut script = std::fs::OpenOptions::new()
        .create(true)
        .write(true)
        .mode(0o777)
        .open(tmpdir.path().join("script.sh"))
        .unwrap();

    let current_exe = std::env::current_exe().unwrap();

    write!(
        script,
        "{}",
        format!(
            "#!/usr/bin/env sh\n{} creduce-interesting gen.c",
            current_exe.display()
        ),
    )
    .unwrap();

    drop(script);

    // reproduce the generated program, and then preprocess it

    let st = Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(tmpdir.path().join("gen-original.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new("clang")
        .arg("-I/usr/include/csmith")
        .arg("-m32")
        .arg("-E")
        .arg("-P")
        .arg(tmpdir.path().join("gen-original.c"))
        .arg("-o")
        .arg(tmpdir.path().join("gen.c"))
        .status()
        .unwrap();
    assert!(st.success());

    let st = Command::new("creduce")
        .current_dir(tmpdir.path())
        .arg("--n")
        .arg(format!("{}", std::cmp::max(1, num_cpus::get() - 1)))
        .arg("script.sh")
        .arg("gen.c")
        .status()
        .unwrap();
    assert!(st.success());

    print!(
        "{}",
        std::fs::read_to_string(tmpdir.path().join("gen.c")).unwrap()
    );
}

fn run_creduce_interestingness<P: AsRef<Path>>(src: P) {
    let tmpdir = TempDir::new().unwrap();

    match run_both(&tmpdir, src, None) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            let expected = String::from_utf8_lossy(&expected);
            let actual = String::from_utf8_lossy(&actual);
            println!("native: {}", &expected);
            println!("lucet-wasi: {}", &actual);

            let re = Regex::new(r"^checksum = ([[:xdigit:]]{8})").unwrap();

            // a coarse way to stop creduce from producing degenerate cases that happen to yield
            // different output

            let expected_checksum = if let Some(caps) = re.captures(&expected) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // not interesting: no checksum captured from native output
                    exit(1);
                }
            } else {
                // not interesting: no checksum captured from native output
                exit(1);
            };

            let actual_checksum = if let Some(caps) = re.captures(&actual) {
                if let Some(cap) = caps.get(1) {
                    cap.as_str().to_owned()
                } else {
                    // interesting: checksum captured from native output but not wasm
                    exit(0)
                }
            } else {
                // interesting: checksum captured from native output but not wasm
                exit(0)
            };

            if expected_checksum == actual_checksum {
                // they match; not interesting
                exit(1);
            } else {
                exit(0);
            }
        }
        Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error),
    }
    exit(1);
}

fn run_one_seed(seed: Seed) {
    match run_one(Some(seed)) {
        Ok(TestResult::Passed) => println!("test passed"),
        Ok(TestResult::Ignored) => println!("native build/execution failed"),
        Ok(TestResult::Failed {
            expected, actual, ..
        }) => {
            println!("test failed:\n");
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Ok(TestResult::Errored { error }) | Err(error) => println!("test errored: {}", error),
    }
}

fn run_many(num_tests: usize) {
    let mut progress = progress::Bar::new();
    progress.set_job_title(&format!("Running {} tests", num_tests));

    let progress = Arc::new(Mutex::new(progress));
    let num_finished = Arc::new(Mutex::new(0));

    let res = (0..num_tests)
        .into_par_iter()
        .try_for_each(|_| match run_one(None) {
            Ok(TestResult::Passed) | Ok(TestResult::Ignored) => {
                let mut num_finished = num_finished.lock().unwrap();
                *num_finished += 1;
                let percentage = (*num_finished as f32 / num_tests as f32) * 100.0;
                progress
                    .lock()
                    .unwrap()
                    .reach_percent(percentage.floor() as i32);
                Ok(())
            }
            Ok(fail) => Err(fail),
            Err(error) => Err(TestResult::Errored { error }),
        });

    progress.lock().unwrap().jobs_done();

    match res {
        Err(TestResult::Failed {
            seed,
            expected,
            actual,
        }) => {
            println!("test failed with seed {}\n", seed.unwrap());
            println!("native: {}", String::from_utf8_lossy(&expected));
            println!("lucet-wasi: {}", String::from_utf8_lossy(&actual));
            exit(1);
        }
        Err(TestResult::Errored { error }) => println!("test errored: {}", error),
        Err(_) => unreachable!(),
        Ok(()) => println!("all tests passed"),
    }
}

fn gen_c<P: AsRef<Path>>(gen_c_path: P, seed: Seed) -> Result<(), Error> {
    Command::new("csmith")
        .arg("-s")
        .arg(format!("{}", seed))
        .arg("-o")
        .arg(gen_c_path.as_ref())
        .status()?;
    Ok(())
}

fn run_both<P: AsRef<Path>>(
    tmpdir: &TempDir,
    src: P,
    seed: Option<Seed>,
) -> Result<TestResult, Error> {
    let native_stdout = if let Some(stdout) = run_native(&tmpdir, src.as_ref())? {
        stdout
    } else {
        return Ok(TestResult::Ignored);
    };

    let (exitcode, wasm_stdout) = run_with_stdout(&tmpdir, src.as_ref())?;

    assert_eq!(exitcode, 0);

    if &wasm_stdout != &native_stdout {
        Ok(TestResult::Failed {
            seed,
            expected: native_stdout,
            actual: wasm_stdout,
        })
    } else {
        Ok(TestResult::Passed)
    }
}

fn run_native<P: AsRef<Path>>(tmpdir: &TempDir, gen_c_path: P) -> Result<Option<Vec<u8>>, Error> {
    let gen_path = tmpdir.path().join("gen");

    let res = Command::new("clang")
        .arg("-m32")
        .arg("-std=c11")
        .arg("-Werror=format")
        .arg("-Werror=uninitialized")
        .arg("-Werror=conditional-uninitialized")
        .arg("-I/usr/include/csmith")
        .arg(gen_c_path.as_ref())
        .arg("-o")
        .arg(&gen_path)
        .output()?;
    ensure!(res.status.success(), "native C compilation failed");

    if String::from_utf8_lossy(&res.stderr).contains("too few arguments in call") {
        bail!("saw \"too few arguments in call\" warning");
    }

    let mut native_child = Command::new(&gen_path).stdout(Stdio::piped()).spawn()?;

    let exitcode = match native_child.wait_timeout(Duration::from_millis(1000))? {
        Some(status) => status.code(),
        None => {
            native_child.kill()?;
            native_child.wait()?.code()
        }
    };

    match exitcode {
        None => {
            // native code diverged or took too long, so was killed by the timeout
            return Ok(None);
        }
        Some(0) => (),
        Some(code) => {
            println!("native code returned non-zero exit code: {}", code);
            return Ok(None);
        }
    }

    let mut native_stdout = vec![];
    native_child
        .stdout
        .ok_or(format_err!("couldn't get stdout"))?
        .read_to_end(&mut native_stdout)?;

    Ok(Some(native_stdout))
}

enum TestResult {
    Passed,
    Ignored,
    Failed {
        seed: Option<Seed>,
        expected: Vec<u8>,
        actual: Vec<u8>,
    },
    Errored {
        error: Error,
    },
}

fn run_one(seed: Option<Seed>) -> Result<TestResult, Error> {
    let tmpdir = TempDir::new().unwrap();

    let gen_c_path = tmpdir.path().join("gen.c");

    let seed = seed.unwrap_or(random::<Seed>());
    gen_c(&gen_c_path, seed)?;

    run_both(&tmpdir, &gen_c_path, Some(seed))
}

fn run_with_stdout<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
) -> Result<(__wasi_exitcode_t, Vec<u8>), Error> {
    let ctx = WasiCtxBuilder::new().args(&["gen"]);

    let (pipe_out, pipe_in) = nix::unistd::pipe()?;

    let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?;

    let exitcode = run(tmpdir, path, ctx)?;

    let mut stdout_file = unsafe { File::from_raw_fd(pipe_out) };
    let mut stdout = vec![];
    stdout_file.read_to_end(&mut stdout)?;
    nix::unistd::close(stdout_file.into_raw_fd())?;

    Ok((exitcode, stdout))
}

fn run<P: AsRef<Path>>(
    tmpdir: &TempDir,
    path: P,
    ctx: WasiCtx,
) -> Result<__wasi_exitcode_t, Error> {
    let region = MmapRegion::create(1, &Limits::default())?;
    let module = wasi_test(tmpdir, path)?;

    let mut inst = region
        .new_instance_builder(module)
        .with_embed_ctx(ctx)
        .build()?;

    match inst.run("_start", &[]) {
        // normal termination implies 0 exit code
        Ok(_) => Ok(0),
        Err(lucet_runtime::Error::RuntimeTerminated(
            lucet_runtime::TerminationDetails::Provided(any),
        )) => Ok(*any
            .downcast_ref::<__wasi_exitcode_t>()
            .expect("termination yields an exitcode")),
        Err(e) => bail!("runtime error: {}", e),
    }
}

fn wasi_test<P: AsRef<Path>>(tmpdir: &TempDir, c_file: P) -> Result<Arc<dyn Module>, Error> {
    let wasm_build = Link::new(&[c_file]).with_cflag("-I/usr/include/csmith");

    let wasm_file = tmpdir.path().join("out.wasm");

    wasm_build.link(wasm_file.clone())?;

    let bindings = Bindings::from_file(
        Path::new(LUCET_WASI_FUZZ_ROOT)
            .parent()
            .unwrap()
            .join("lucet-wasi")
            .join("bindings.json"),
    )?;

    let native_build = Lucetc::new(wasm_file).with_bindings(bindings);

    let so_file = tmpdir.path().join("out.so");

    native_build.shared_object_file(so_file.clone())?;

    let dlmodule = DlModule::load(so_file)?;

    Ok(dlmodule as Arc<dyn Module>)
}
<|endoftext|>