Import structopt-0.3.14

Change-Id: I03e7eaf9f442092701ce3175cb78c8ea2237f616
diff --git a/tests/argument_naming.rs b/tests/argument_naming.rs
new file mode 100644
index 0000000..e7fe3d5
--- /dev/null
+++ b/tests/argument_naming.rs
@@ -0,0 +1,311 @@
+use structopt::StructOpt;
+
+#[test]
+fn test_single_word_enum_variant_is_default_renamed_into_kebab_case() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    enum Opt {
+        Command { foo: u32 },
+    }
+
+    assert_eq!(
+        Opt::Command { foo: 0 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "command", "0"]))
+    );
+}
+
+#[test]
+fn test_multi_word_enum_variant_is_renamed() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    enum Opt {
+        FirstCommand { foo: u32 },
+    }
+
+    assert_eq!(
+        Opt::FirstCommand { foo: 0 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "first-command", "0"]))
+    );
+}
+
+#[test]
+fn test_standalone_long_generates_kebab_case() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[allow(non_snake_case)]
+    struct Opt {
+        #[structopt(long)]
+        FOO_OPTION: bool,
+    }
+
+    assert_eq!(
+        Opt { FOO_OPTION: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo-option"]))
+    );
+}
+
+#[test]
+fn test_custom_long_overwrites_default_name() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(long = "foo")]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"]))
+    );
+}
+
+#[test]
+fn test_standalone_long_uses_previous_defined_custom_name() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(name = "foo", long)]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"]))
+    );
+}
+
+#[test]
+fn test_standalone_long_ignores_afterwards_defined_custom_name() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(long, name = "foo")]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo-option"]))
+    );
+}
+
+#[test]
+fn test_standalone_short_generates_kebab_case() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[allow(non_snake_case)]
+    struct Opt {
+        #[structopt(short)]
+        FOO_OPTION: bool,
+    }
+
+    assert_eq!(
+        Opt { FOO_OPTION: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-f"]))
+    );
+}
+
+#[test]
+fn test_custom_short_overwrites_default_name() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(short = "o")]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-o"]))
+    );
+}
+
+#[test]
+fn test_standalone_short_uses_previous_defined_custom_name() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(name = "option", short)]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-o"]))
+    );
+}
+
+#[test]
+fn test_standalone_short_ignores_afterwards_defined_custom_name() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(short, name = "option")]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-f"]))
+    );
+}
+
+#[test]
+fn test_standalone_long_uses_previous_defined_casing() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(rename_all = "screaming_snake", long)]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--FOO_OPTION"]))
+    );
+}
+
+#[test]
+fn test_standalone_short_uses_previous_defined_casing() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(rename_all = "screaming_snake", short)]
+        foo_option: bool,
+    }
+
+    assert_eq!(
+        Opt { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-F"]))
+    );
+}
+
+#[test]
+fn test_standalone_long_works_with_verbatim_casing() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[allow(non_snake_case)]
+    struct Opt {
+        #[structopt(rename_all = "verbatim", long)]
+        _fOO_oPtiON: bool,
+    }
+
+    assert_eq!(
+        Opt { _fOO_oPtiON: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--_fOO_oPtiON"]))
+    );
+}
+
+#[test]
+fn test_standalone_short_works_with_verbatim_casing() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(rename_all = "verbatim", short)]
+        _foo: bool,
+    }
+
+    assert_eq!(
+        Opt { _foo: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-_"]))
+    );
+}
+
+#[test]
+fn test_rename_all_is_propagated_from_struct_to_fields() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[structopt(rename_all = "screaming_snake")]
+    struct Opt {
+        #[structopt(long)]
+        foo: bool,
+    }
+
+    assert_eq!(
+        Opt { foo: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--FOO"]))
+    );
+}
+
+#[test]
+fn test_rename_all_is_not_propagated_from_struct_into_flattened() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[structopt(rename_all = "screaming_snake")]
+    struct Opt {
+        #[structopt(flatten)]
+        foo: Foo,
+    }
+
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Foo {
+        #[structopt(long)]
+        foo: bool,
+    }
+
+    assert_eq!(
+        Opt {
+            foo: Foo { foo: true }
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--foo"]))
+    );
+}
+
+#[test]
+fn test_rename_all_is_not_propagated_from_struct_into_subcommand() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[structopt(rename_all = "screaming_snake")]
+    struct Opt {
+        #[structopt(subcommand)]
+        foo: Foo,
+    }
+
+    #[derive(StructOpt, Debug, PartialEq)]
+    enum Foo {
+        Command {
+            #[structopt(long)]
+            foo: bool,
+        },
+    }
+
+    assert_eq!(
+        Opt {
+            foo: Foo::Command { foo: true }
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "command", "--foo"]))
+    );
+}
+
+#[test]
+fn test_rename_all_is_propagated_from_enum_to_variants_and_their_fields() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[structopt(rename_all = "screaming_snake")]
+    enum Opt {
+        FirstVariant,
+        SecondVariant {
+            #[structopt(long)]
+            foo: bool,
+        },
+    }
+
+    assert_eq!(
+        Opt::FirstVariant,
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "FIRST_VARIANT"]))
+    );
+
+    assert_eq!(
+        Opt::SecondVariant { foo: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "SECOND_VARIANT", "--FOO"]))
+    );
+}
+
+#[test]
+fn test_rename_all_is_propagation_can_be_overridden() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[structopt(rename_all = "screaming_snake")]
+    enum Opt {
+        #[structopt(rename_all = "kebab_case")]
+        FirstVariant {
+            #[structopt(long)]
+            foo_option: bool,
+        },
+        SecondVariant {
+            #[structopt(rename_all = "kebab_case", long)]
+            foo_option: bool,
+        },
+    }
+
+    assert_eq!(
+        Opt::FirstVariant { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "first-variant", "--foo-option"]))
+    );
+
+    assert_eq!(
+        Opt::SecondVariant { foo_option: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "SECOND_VARIANT", "--foo-option"]))
+    );
+}
diff --git a/tests/arguments.rs b/tests/arguments.rs
new file mode 100644
index 0000000..96a0938
--- /dev/null
+++ b/tests/arguments.rs
@@ -0,0 +1,86 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::clap;
+use structopt::StructOpt;
+
+#[test]
+fn required_argument() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test", "42"]));
+    assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "42", "24"])
+        .is_err());
+}
+
+#[test]
+fn optional_argument() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        arg: Option<i32>,
+    }
+    assert_eq!(Opt { arg: Some(42) }, Opt::from_iter(&["test", "42"]));
+    assert_eq!(Opt { arg: None }, Opt::from_iter(&["test"]));
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "42", "24"])
+        .is_err());
+}
+
+#[test]
+fn argument_with_default() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(default_value = "42")]
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 24 }, Opt::from_iter(&["test", "24"]));
+    assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test"]));
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "42", "24"])
+        .is_err());
+}
+
+#[test]
+fn arguments() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        arg: Vec<i32>,
+    }
+    assert_eq!(Opt { arg: vec![24] }, Opt::from_iter(&["test", "24"]));
+    assert_eq!(Opt { arg: vec![] }, Opt::from_iter(&["test"]));
+    assert_eq!(
+        Opt { arg: vec![24, 42] },
+        Opt::from_iter(&["test", "24", "42"])
+    );
+}
+
+#[test]
+fn arguments_safe() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        arg: Vec<i32>,
+    }
+    assert_eq!(
+        Opt { arg: vec![24] },
+        Opt::from_iter_safe(&["test", "24"]).unwrap()
+    );
+    assert_eq!(Opt { arg: vec![] }, Opt::from_iter_safe(&["test"]).unwrap());
+    assert_eq!(
+        Opt { arg: vec![24, 42] },
+        Opt::from_iter_safe(&["test", "24", "42"]).unwrap()
+    );
+
+    assert_eq!(
+        clap::ErrorKind::ValueValidation,
+        Opt::from_iter_safe(&["test", "NOPE"]).err().unwrap().kind
+    );
+}
diff --git a/tests/author_version_about.rs b/tests/author_version_about.rs
new file mode 100644
index 0000000..0f1c8b5
--- /dev/null
+++ b/tests/author_version_about.rs
@@ -0,0 +1,58 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn no_author_version_about() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[structopt(name = "foo", no_version)]
+    struct Opt {}
+
+    let output = get_long_help::<Opt>();
+    assert!(output.starts_with("foo \n\nUSAGE:"));
+}
+
+#[test]
+fn use_env() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[structopt(author, about)]
+    struct Opt {}
+
+    let output = get_long_help::<Opt>();
+    assert!(output.starts_with("structopt 0."));
+    assert!(output.contains("Guillaume Pinot <texitoi@texitoi.eu>, others"));
+    assert!(output.contains("Parse command line argument by defining a struct."));
+}
+
+#[test]
+fn explicit_version_not_str() {
+    const VERSION: &str = "custom version";
+
+    #[derive(StructOpt)]
+    #[structopt(version = VERSION)]
+    pub struct Opt {}
+
+    let output = get_long_help::<Opt>();
+    assert!(output.contains("custom version"));
+}
+
+#[test]
+fn no_version_gets_propagated() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[structopt(no_version)]
+    enum Action {
+        Move,
+    }
+
+    let output = get_subcommand_long_help::<Action>("move");
+    assert_eq!(output.lines().next(), Some("test-move "));
+}
diff --git a/tests/custom-string-parsers.rs b/tests/custom-string-parsers.rs
new file mode 100644
index 0000000..89070ed
--- /dev/null
+++ b/tests/custom-string-parsers.rs
@@ -0,0 +1,306 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+use std::ffi::{CString, OsStr, OsString};
+use std::num::ParseIntError;
+use std::path::PathBuf;
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct PathOpt {
+    #[structopt(short, long, parse(from_os_str))]
+    path: PathBuf,
+
+    #[structopt(short, default_value = "../", parse(from_os_str))]
+    default_path: PathBuf,
+
+    #[structopt(short, parse(from_os_str))]
+    vector_path: Vec<PathBuf>,
+
+    #[structopt(short, parse(from_os_str))]
+    option_path_1: Option<PathBuf>,
+
+    #[structopt(short = "q", parse(from_os_str))]
+    option_path_2: Option<PathBuf>,
+}
+
+#[test]
+fn test_path_opt_simple() {
+    assert_eq!(
+        PathOpt {
+            path: PathBuf::from("/usr/bin"),
+            default_path: PathBuf::from("../"),
+            vector_path: vec![
+                PathBuf::from("/a/b/c"),
+                PathBuf::from("/d/e/f"),
+                PathBuf::from("/g/h/i"),
+            ],
+            option_path_1: None,
+            option_path_2: Some(PathBuf::from("j.zip")),
+        },
+        PathOpt::from_clap(&PathOpt::clap().get_matches_from(&[
+            "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q",
+            "j.zip",
+        ]))
+    );
+}
+
+fn parse_hex(input: &str) -> Result<u64, ParseIntError> {
+    u64::from_str_radix(input, 16)
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct HexOpt {
+    #[structopt(short, parse(try_from_str = parse_hex))]
+    number: u64,
+}
+
+#[test]
+#[allow(clippy::unreadable_literal)]
+fn test_parse_hex() {
+    assert_eq!(
+        HexOpt { number: 5 },
+        HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "5"]))
+    );
+    assert_eq!(
+        HexOpt { number: 0xabcdef },
+        HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"]))
+    );
+
+    let err = HexOpt::clap()
+        .get_matches_from_safe(&["test", "-n", "gg"])
+        .unwrap_err();
+    assert!(err.message.contains("invalid digit found in string"), err);
+}
+
+fn custom_parser_1(_: &str) -> &'static str {
+    "A"
+}
+fn custom_parser_2(_: &str) -> Result<&'static str, u32> {
+    Ok("B")
+}
+fn custom_parser_3(_: &OsStr) -> &'static str {
+    "C"
+}
+fn custom_parser_4(_: &OsStr) -> Result<&'static str, OsString> {
+    Ok("D")
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct NoOpOpt {
+    #[structopt(short, parse(from_str = custom_parser_1))]
+    a: &'static str,
+    #[structopt(short, parse(try_from_str = custom_parser_2))]
+    b: &'static str,
+    #[structopt(short, parse(from_os_str = custom_parser_3))]
+    c: &'static str,
+    #[structopt(short, parse(try_from_os_str = custom_parser_4))]
+    d: &'static str,
+}
+
+#[test]
+fn test_every_custom_parser() {
+    assert_eq!(
+        NoOpOpt {
+            a: "A",
+            b: "B",
+            c: "C",
+            d: "D"
+        },
+        NoOpOpt::from_clap(
+            &NoOpOpt::clap().get_matches_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?"])
+        )
+    );
+}
+
+// Note: can't use `Vec<u8>` directly, as structopt would instead look for
+// conversion function from `&str` to `u8`.
+type Bytes = Vec<u8>;
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct DefaultedOpt {
+    #[structopt(short, parse(from_str))]
+    bytes: Bytes,
+
+    #[structopt(short, parse(try_from_str))]
+    integer: u64,
+
+    #[structopt(short, parse(from_os_str))]
+    path: PathBuf,
+}
+
+#[test]
+fn test_parser_with_default_value() {
+    assert_eq!(
+        DefaultedOpt {
+            bytes: b"E\xc2\xb2=p\xc2\xb2c\xc2\xb2+m\xc2\xb2c\xe2\x81\xb4".to_vec(),
+            integer: 9000,
+            path: PathBuf::from("src/lib.rs"),
+        },
+        DefaultedOpt::from_clap(&DefaultedOpt::clap().get_matches_from(&[
+            "test",
+            "-b",
+            "E²=p²c²+m²c⁴",
+            "-i",
+            "9000",
+            "-p",
+            "src/lib.rs",
+        ]))
+    );
+}
+
+#[derive(PartialEq, Debug)]
+struct Foo(u8);
+
+fn foo(value: u64) -> Foo {
+    Foo(value as u8)
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Occurrences {
+    #[structopt(short, long, parse(from_occurrences))]
+    signed: i32,
+
+    #[structopt(short, parse(from_occurrences))]
+    little_signed: i8,
+
+    #[structopt(short, parse(from_occurrences))]
+    unsigned: usize,
+
+    #[structopt(short = "r", parse(from_occurrences))]
+    little_unsigned: u8,
+
+    #[structopt(short, long, parse(from_occurrences = foo))]
+    custom: Foo,
+}
+
+#[test]
+fn test_parser_occurrences() {
+    assert_eq!(
+        Occurrences {
+            signed: 3,
+            little_signed: 1,
+            unsigned: 0,
+            little_unsigned: 4,
+            custom: Foo(5),
+        },
+        Occurrences::from_clap(&Occurrences::clap().get_matches_from(&[
+            "test", "-s", "--signed", "--signed", "-l", "-rrrr", "-cccc", "--custom",
+        ]))
+    );
+}
+
+#[test]
+fn test_custom_bool() {
+    fn parse_bool(s: &str) -> Result<bool, String> {
+        match s {
+            "true" => Ok(true),
+            "false" => Ok(false),
+            _ => Err(format!("invalid bool {}", s)),
+        }
+    }
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, parse(try_from_str = parse_bool))]
+        debug: bool,
+        #[structopt(
+            short,
+            default_value = "false",
+            parse(try_from_str = parse_bool)
+        )]
+        verbose: bool,
+        #[structopt(short, parse(try_from_str = parse_bool))]
+        tribool: Option<bool>,
+        #[structopt(short, parse(try_from_str = parse_bool))]
+        bitset: Vec<bool>,
+    }
+
+    assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+    assert!(Opt::clap().get_matches_from_safe(&["test", "-d"]).is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-dfoo"])
+        .is_err());
+    assert_eq!(
+        Opt {
+            debug: false,
+            verbose: false,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::from_iter(&["test", "-dfalse"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::from_iter(&["test", "-dtrue"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::from_iter(&["test", "-dtrue", "-vfalse"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: true,
+            tribool: None,
+            bitset: vec![],
+        },
+        Opt::from_iter(&["test", "-dtrue", "-vtrue"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: Some(false),
+            bitset: vec![],
+        },
+        Opt::from_iter(&["test", "-dtrue", "-tfalse"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: Some(true),
+            bitset: vec![],
+        },
+        Opt::from_iter(&["test", "-dtrue", "-ttrue"])
+    );
+    assert_eq!(
+        Opt {
+            debug: true,
+            verbose: false,
+            tribool: None,
+            bitset: vec![false, true, false, false],
+        },
+        Opt::from_iter(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"])
+    );
+}
+
+#[test]
+fn test_cstring() {
+    #[derive(StructOpt)]
+    struct Opt {
+        #[structopt(parse(try_from_str = CString::new))]
+        c_string: CString,
+    }
+    assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+    assert_eq!(Opt::from_iter(&["test", "bla"]).c_string.to_bytes(), b"bla");
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "bla\0bla"])
+        .is_err());
+}
diff --git a/tests/default_value.rs b/tests/default_value.rs
new file mode 100644
index 0000000..383bd23
--- /dev/null
+++ b/tests/default_value.rs
@@ -0,0 +1,19 @@
+use structopt::StructOpt;
+
+mod utils;
+
+use utils::*;
+
+#[test]
+fn auto_default_value() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(default_value)]
+        arg: i32,
+    }
+    assert_eq!(Opt { arg: 0 }, Opt::from_iter(&["test"]));
+    assert_eq!(Opt { arg: 1 }, Opt::from_iter(&["test", "1"]));
+
+    let help = get_long_help::<Opt>();
+    assert!(help.contains("[default: 0]"));
+}
diff --git a/tests/deny-warnings.rs b/tests/deny-warnings.rs
new file mode 100644
index 0000000..721204a
--- /dev/null
+++ b/tests/deny-warnings.rs
@@ -0,0 +1,47 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(warnings)]
+
+use structopt::StructOpt;
+
+fn try_str(s: &str) -> Result<String, std::convert::Infallible> {
+    Ok(s.into())
+}
+
+#[test]
+fn warning_never_struct() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    struct Opt {
+        #[structopt(parse(try_from_str = try_str))]
+        s: String,
+    }
+    assert_eq!(
+        Opt {
+            s: "foo".to_string()
+        },
+        Opt::from_iter(&["test", "foo"])
+    );
+}
+
+#[test]
+fn warning_never_enum() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    enum Opt {
+        Foo {
+            #[structopt(parse(try_from_str = try_str))]
+            s: String,
+        },
+    }
+    assert_eq!(
+        Opt::Foo {
+            s: "foo".to_string()
+        },
+        Opt::from_iter(&["test", "foo", "foo"])
+    );
+}
diff --git a/tests/doc-comments-help.rs b/tests/doc-comments-help.rs
new file mode 100644
index 0000000..1d31683
--- /dev/null
+++ b/tests/doc-comments-help.rs
@@ -0,0 +1,185 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn doc_comments() {
+    /// Lorem ipsum
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct LoremIpsum {
+        /// Fooify a bar
+        /// and a baz
+        #[structopt(short, long)]
+        foo: bool,
+    }
+
+    let help = get_long_help::<LoremIpsum>();
+    assert!(help.contains("Lorem ipsum"));
+    assert!(help.contains("Fooify a bar and a baz"));
+}
+
+#[test]
+fn help_is_better_than_comments() {
+    /// Lorem ipsum
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")]
+    struct LoremIpsum {
+        /// Fooify a bar
+        #[structopt(short, long, help = "DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES")]
+        foo: bool,
+    }
+
+    let help = get_long_help::<LoremIpsum>();
+    assert!(help.contains("Dolor sit amet"));
+    assert!(!help.contains("Lorem ipsum"));
+    assert!(help.contains("DO NOT PASS A BAR"));
+}
+
+#[test]
+fn empty_line_in_doc_comment_is_double_linefeed() {
+    /// Foo.
+    ///
+    /// Bar
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[structopt(name = "lorem-ipsum", no_version)]
+    struct LoremIpsum {}
+
+    let help = get_long_help::<LoremIpsum>();
+    assert!(help.starts_with("lorem-ipsum \nFoo.\n\nBar\n\nUSAGE:"));
+}
+
+#[test]
+fn field_long_doc_comment_both_help_long_help() {
+    /// Lorem ipsumclap
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")]
+    struct LoremIpsum {
+        /// Dot is removed from multiline comments.
+        ///
+        /// Long help
+        #[structopt(long)]
+        foo: bool,
+
+        /// Dot is removed from one short comment.
+        #[structopt(long)]
+        bar: bool,
+    }
+
+    let short_help = get_help::<LoremIpsum>();
+    let long_help = get_long_help::<LoremIpsum>();
+
+    assert!(short_help.contains("Dot is removed from one short comment"));
+    assert!(!short_help.contains("Dot is removed from one short comment."));
+    assert!(short_help.contains("Dot is removed from multiline comments"));
+    assert!(!short_help.contains("Dot is removed from multiline comments."));
+    assert!(long_help.contains("Long help"));
+    assert!(!short_help.contains("Long help"));
+}
+
+#[test]
+fn top_long_doc_comment_both_help_long_help() {
+    /// Lorem ipsumclap
+    #[derive(StructOpt, Debug)]
+    #[structopt(name = "lorem-ipsum", about = "Dolor sit amet")]
+    struct LoremIpsum {
+        #[structopt(subcommand)]
+        foo: SubCommand,
+    }
+
+    #[derive(StructOpt, Debug)]
+    pub enum SubCommand {
+        /// DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES
+        ///
+        /// Or something else
+        Foo {
+            #[structopt(help = "foo")]
+            bars: Vec<String>,
+        },
+    }
+
+    let short_help = get_help::<LoremIpsum>();
+    let long_help = get_subcommand_long_help::<LoremIpsum>("foo");
+
+    assert!(!short_help.contains("Or something else"));
+    assert!(long_help.contains("DO NOT PASS A BAR UNDER ANY CIRCUMSTANCES"));
+    assert!(long_help.contains("Or something else"));
+}
+
+#[test]
+fn verbatim_doc_comment() {
+    /// DANCE!
+    ///
+    ///                    ()
+    ///                    |
+    ///               (   ()   )
+    ///     ) ________    //  )
+    ///  ()  |\       \  //
+    /// ( \\__ \ ______\//
+    ///    \__) |       |
+    ///      |  |       |
+    ///       \ |       |
+    ///        \|_______|
+    ///        //    \\
+    ///       ((     ||
+    ///        \\    ||
+    ///      ( ()    ||
+    ///       (      () ) )
+    #[derive(StructOpt, Debug)]
+    #[structopt(verbatim_doc_comment)]
+    struct SeeFigure1 {
+        #[structopt(long)]
+        foo: bool,
+    }
+
+    let help = get_long_help::<SeeFigure1>();
+    let sample = r#"
+                   ()
+                   |
+              (   ()   )
+    ) ________    //  )
+ ()  |\       \  //
+( \\__ \ ______\//
+   \__) |       |
+     |  |       |
+      \ |       |
+       \|_______|
+       //    \\
+      ((     ||
+       \\    ||
+     ( ()    ||
+      (      () ) )"#;
+
+    assert!(help.contains(sample))
+}
+
+#[test]
+fn verbatim_doc_comment_field() {
+    #[derive(StructOpt, Debug)]
+    struct App {
+        /// This help ends in a period.
+        #[structopt(long, verbatim_doc_comment)]
+        foo: bool,
+        /// This help does not end in a period.
+        #[structopt(long)]
+        bar: bool,
+    }
+
+    let help = get_long_help::<App>();
+    let sample = r#"
+        --bar        
+            This help does not end in a period
+
+        --foo        
+            This help ends in a period."#;
+
+    assert!(help.contains(sample))
+}
diff --git a/tests/explicit_name_no_renaming.rs b/tests/explicit_name_no_renaming.rs
new file mode 100644
index 0000000..eff7a86
--- /dev/null
+++ b/tests/explicit_name_no_renaming.rs
@@ -0,0 +1,32 @@
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn explicit_short_long_no_rename() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short = ".", long = ".foo")]
+        foo: Vec<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            foo: vec!["short".into(), "long".into()]
+        },
+        Opt::from_iter(&["test", "-.", "short", "--.foo", "long"])
+    );
+}
+
+#[test]
+fn explicit_name_no_rename() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(name = ".options")]
+        foo: Vec<String>,
+    }
+
+    let help = get_long_help::<Opt>();
+    assert!(help.contains("[.options]..."))
+}
diff --git a/tests/flags.rs b/tests/flags.rs
new file mode 100644
index 0000000..39a5dc3
--- /dev/null
+++ b/tests/flags.rs
@@ -0,0 +1,162 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn unique_flag() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, long)]
+        alice: bool,
+    }
+
+    assert_eq!(
+        Opt { alice: false },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert_eq!(
+        Opt { alice: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+    );
+    assert_eq!(
+        Opt { alice: true },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice"]))
+    );
+    assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a", "foo"])
+        .is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a", "-a"])
+        .is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a", "--alice"])
+        .is_err());
+}
+
+#[test]
+fn multiple_flag() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, long, parse(from_occurrences))]
+        alice: u64,
+        #[structopt(short, long, parse(from_occurrences))]
+        bob: u8,
+    }
+
+    assert_eq!(
+        Opt { alice: 0, bob: 0 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert_eq!(
+        Opt { alice: 1, bob: 0 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+    );
+    assert_eq!(
+        Opt { alice: 2, bob: 0 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"]))
+    );
+    assert_eq!(
+        Opt { alice: 2, bob: 2 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--alice", "-bb"]))
+    );
+    assert_eq!(
+        Opt { alice: 3, bob: 1 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-aaa", "--bob"]))
+    );
+    assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a", "foo"])
+        .is_err());
+}
+
+fn parse_from_flag(b: bool) -> std::sync::atomic::AtomicBool {
+    std::sync::atomic::AtomicBool::new(b)
+}
+
+#[test]
+fn non_bool_flags() {
+    #[derive(StructOpt, Debug)]
+    struct Opt {
+        #[structopt(short, long, parse(from_flag = parse_from_flag))]
+        alice: std::sync::atomic::AtomicBool,
+        #[structopt(short, long, parse(from_flag))]
+        bob: std::sync::atomic::AtomicBool,
+    }
+
+    let falsey = Opt::from_clap(&Opt::clap().get_matches_from(&["test"]));
+    assert!(!falsey.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(!falsey.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+    let alice = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]));
+    assert!(alice.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(!alice.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+    let bob = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"]));
+    assert!(!bob.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(bob.bob.load(std::sync::atomic::Ordering::Relaxed));
+
+    let both = Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b", "-a"]));
+    assert!(both.alice.load(std::sync::atomic::Ordering::Relaxed));
+    assert!(both.bob.load(std::sync::atomic::Ordering::Relaxed));
+}
+
+#[test]
+fn combined_flags() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, long)]
+        alice: bool,
+        #[structopt(short, long, parse(from_occurrences))]
+        bob: u64,
+    }
+
+    assert_eq!(
+        Opt {
+            alice: false,
+            bob: 0
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 0
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 0
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+    );
+    assert_eq!(
+        Opt {
+            alice: false,
+            bob: 1
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"]))
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 1
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice", "--bob"]))
+    );
+    assert_eq!(
+        Opt {
+            alice: true,
+            bob: 4
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-bb", "-a", "-bb"]))
+    );
+}
diff --git a/tests/flatten.rs b/tests/flatten.rs
new file mode 100644
index 0000000..f01e44e
--- /dev/null
+++ b/tests/flatten.rs
@@ -0,0 +1,129 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn flatten() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Common {
+        arg: i32,
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(flatten)]
+        common: Common,
+    }
+    assert_eq!(
+        Opt {
+            common: Common { arg: 42 }
+        },
+        Opt::from_iter(&["test", "42"])
+    );
+    assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "42", "24"])
+        .is_err());
+}
+
+#[test]
+#[should_panic]
+fn flatten_twice() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Common {
+        arg: i32,
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(flatten)]
+        c1: Common,
+        // Defines "arg" twice, so this should not work.
+        #[structopt(flatten)]
+        c2: Common,
+    }
+    Opt::from_iter(&["test", "42", "43"]);
+}
+
+#[test]
+fn flatten_in_subcommand() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Common {
+        arg: i32,
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Add {
+        #[structopt(short)]
+        interactive: bool,
+        #[structopt(flatten)]
+        common: Common,
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    enum Opt {
+        Fetch {
+            #[structopt(short)]
+            all: bool,
+            #[structopt(flatten)]
+            common: Common,
+        },
+
+        Add(Add),
+    }
+
+    assert_eq!(
+        Opt::Fetch {
+            all: false,
+            common: Common { arg: 42 }
+        },
+        Opt::from_iter(&["test", "fetch", "42"])
+    );
+    assert_eq!(
+        Opt::Add(Add {
+            interactive: true,
+            common: Common { arg: 43 }
+        }),
+        Opt::from_iter(&["test", "add", "-i", "43"])
+    );
+}
+
+#[test]
+fn merge_subcommands_with_flatten() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    enum BaseCli {
+        Command1(Command1),
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Command1 {
+        arg1: i32,
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Command2 {
+        arg2: i32,
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    enum Opt {
+        #[structopt(flatten)]
+        BaseCli(BaseCli),
+        Command2(Command2),
+    }
+
+    assert_eq!(
+        Opt::BaseCli(BaseCli::Command1(Command1 { arg1: 42 })),
+        Opt::from_iter(&["test", "command1", "42"])
+    );
+    assert_eq!(
+        Opt::Command2(Command2 { arg2: 43 }),
+        Opt::from_iter(&["test", "command2", "43"])
+    );
+}
diff --git a/tests/issues.rs b/tests/issues.rs
new file mode 100644
index 0000000..8b4ac4b
--- /dev/null
+++ b/tests/issues.rs
@@ -0,0 +1,117 @@
+// https://github.com/TeXitoi/structopt/issues/{NUMBER}
+
+mod utils;
+use utils::*;
+
+use structopt::StructOpt;
+
+#[test]
+fn issue_151() {
+    use structopt::{clap::ArgGroup, StructOpt};
+
+    #[derive(StructOpt, Debug)]
+    #[structopt(group = ArgGroup::with_name("verb").required(true).multiple(true))]
+    struct Opt {
+        #[structopt(long, group = "verb")]
+        foo: bool,
+        #[structopt(long, group = "verb")]
+        bar: bool,
+    }
+
+    #[derive(Debug, StructOpt)]
+    struct Cli {
+        #[structopt(flatten)]
+        a: Opt,
+    }
+
+    assert!(Cli::clap().get_matches_from_safe(&["test"]).is_err());
+    assert!(Cli::clap()
+        .get_matches_from_safe(&["test", "--foo"])
+        .is_ok());
+    assert!(Cli::clap()
+        .get_matches_from_safe(&["test", "--bar"])
+        .is_ok());
+    assert!(Cli::clap()
+        .get_matches_from_safe(&["test", "--zebra"])
+        .is_err());
+    assert!(Cli::clap()
+        .get_matches_from_safe(&["test", "--foo", "--bar"])
+        .is_ok());
+}
+
+#[test]
+fn issue_289() {
+    use structopt::{clap::AppSettings, StructOpt};
+
+    #[derive(StructOpt)]
+    #[structopt(setting = AppSettings::InferSubcommands)]
+    enum Args {
+        SomeCommand(SubSubCommand),
+        AnotherCommand,
+    }
+
+    #[derive(StructOpt)]
+    #[structopt(setting = AppSettings::InferSubcommands)]
+    enum SubSubCommand {
+        TestCommand,
+    }
+
+    assert!(Args::clap()
+        .get_matches_from_safe(&["test", "some-command", "test-command"])
+        .is_ok());
+    assert!(Args::clap()
+        .get_matches_from_safe(&["test", "some", "test-command"])
+        .is_ok());
+    assert!(Args::clap()
+        .get_matches_from_safe(&["test", "some-command", "test"])
+        .is_ok());
+    assert!(Args::clap()
+        .get_matches_from_safe(&["test", "some", "test"])
+        .is_ok());
+}
+
+#[test]
+fn issue_324() {
+    fn my_version() -> &'static str {
+        "MY_VERSION"
+    }
+
+    #[derive(StructOpt)]
+    #[structopt(version = my_version())]
+    struct Opt {
+        #[structopt(subcommand)]
+        _cmd: Option<SubCommand>,
+    }
+
+    #[derive(StructOpt)]
+    enum SubCommand {
+        Start,
+    }
+
+    let help = get_long_help::<Opt>();
+    assert!(help.contains("MY_VERSION"));
+}
+
+#[test]
+fn issue_359() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    struct Opt {
+        #[structopt(subcommand)]
+        sub: Subcommands,
+    }
+
+    #[derive(Debug, PartialEq, StructOpt)]
+    enum Subcommands {
+        Add,
+
+        #[structopt(external_subcommand)]
+        Other(Vec<String>),
+    }
+
+    assert_eq!(
+        Opt {
+            sub: Subcommands::Other(vec!["only_one_arg".into()])
+        },
+        Opt::from_iter(&["test", "only_one_arg"])
+    );
+}
diff --git a/tests/macro-errors.rs b/tests/macro-errors.rs
new file mode 100644
index 0000000..ae4f5a2
--- /dev/null
+++ b/tests/macro-errors.rs
@@ -0,0 +1,13 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+
+#[rustversion::attr(any(not(stable), before(1.39)), ignore)]
+#[test]
+fn ui() {
+    let t = trybuild::TestCases::new();
+    t.compile_fail("tests/ui/*.rs");
+}
diff --git a/tests/nested-subcommands.rs b/tests/nested-subcommands.rs
new file mode 100644
index 0000000..1fbd166
--- /dev/null
+++ b/tests/nested-subcommands.rs
@@ -0,0 +1,193 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Opt {
+    #[structopt(short, long)]
+    force: bool,
+    #[structopt(short, long, parse(from_occurrences))]
+    verbose: u64,
+    #[structopt(subcommand)]
+    cmd: Sub,
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Sub {
+    Fetch {},
+    Add {},
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Opt2 {
+    #[structopt(short, long)]
+    force: bool,
+    #[structopt(short, long, parse(from_occurrences))]
+    verbose: u64,
+    #[structopt(subcommand)]
+    cmd: Option<Sub>,
+}
+
+#[test]
+fn test_no_cmd() {
+    let result = Opt::clap().get_matches_from_safe(&["test"]);
+    assert!(result.is_err());
+
+    assert_eq!(
+        Opt2 {
+            force: false,
+            verbose: 0,
+            cmd: None
+        },
+        Opt2::from_clap(&Opt2::clap().get_matches_from(&["test"]))
+    );
+}
+
+#[test]
+fn test_fetch() {
+    assert_eq!(
+        Opt {
+            force: false,
+            verbose: 3,
+            cmd: Sub::Fetch {}
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vvv", "fetch"]))
+    );
+    assert_eq!(
+        Opt {
+            force: true,
+            verbose: 0,
+            cmd: Sub::Fetch {}
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--force", "fetch"]))
+    );
+}
+
+#[test]
+fn test_add() {
+    assert_eq!(
+        Opt {
+            force: false,
+            verbose: 0,
+            cmd: Sub::Add {}
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))
+    );
+    assert_eq!(
+        Opt {
+            force: false,
+            verbose: 2,
+            cmd: Sub::Add {}
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vv", "add"]))
+    );
+}
+
+#[test]
+fn test_badinput() {
+    let result = Opt::clap().get_matches_from_safe(&["test", "badcmd"]);
+    assert!(result.is_err());
+    let result = Opt::clap().get_matches_from_safe(&["test", "add", "--verbose"]);
+    assert!(result.is_err());
+    let result = Opt::clap().get_matches_from_safe(&["test", "--badopt", "add"]);
+    assert!(result.is_err());
+    let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badopt"]);
+    assert!(result.is_err());
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct Opt3 {
+    #[structopt(short, long)]
+    all: bool,
+    #[structopt(subcommand)]
+    cmd: Sub2,
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Sub2 {
+    Foo {
+        file: String,
+        #[structopt(subcommand)]
+        cmd: Sub3,
+    },
+    Bar {},
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Sub3 {
+    Baz {},
+    Quux {},
+}
+
+#[test]
+fn test_subsubcommand() {
+    assert_eq!(
+        Opt3 {
+            all: true,
+            cmd: Sub2::Foo {
+                file: "lib.rs".to_string(),
+                cmd: Sub3::Quux {}
+            }
+        },
+        Opt3::from_clap(
+            &Opt3::clap().get_matches_from(&["test", "--all", "foo", "lib.rs", "quux"])
+        )
+    );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum SubSubCmdWithOption {
+    Remote {
+        #[structopt(subcommand)]
+        cmd: Option<Remote>,
+    },
+    Stash {
+        #[structopt(subcommand)]
+        cmd: Stash,
+    },
+}
+#[derive(StructOpt, PartialEq, Debug)]
+enum Remote {
+    Add { name: String, url: String },
+    Remove { name: String },
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Stash {
+    Save,
+    Pop,
+}
+
+#[test]
+fn sub_sub_cmd_with_option() {
+    fn make(args: &[&str]) -> Option<SubSubCmdWithOption> {
+        SubSubCmdWithOption::clap()
+            .get_matches_from_safe(args)
+            .ok()
+            .map(|m| SubSubCmdWithOption::from_clap(&m))
+    }
+    assert_eq!(
+        Some(SubSubCmdWithOption::Remote { cmd: None }),
+        make(&["", "remote"])
+    );
+    assert_eq!(
+        Some(SubSubCmdWithOption::Remote {
+            cmd: Some(Remote::Add {
+                name: "origin".into(),
+                url: "http".into()
+            })
+        }),
+        make(&["", "remote", "add", "origin", "http"])
+    );
+    assert_eq!(
+        Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }),
+        make(&["", "stash", "save"])
+    );
+    assert_eq!(None, make(&["", "stash"]));
+}
diff --git a/tests/non_literal_attributes.rs b/tests/non_literal_attributes.rs
new file mode 100644
index 0000000..75b6b71
--- /dev/null
+++ b/tests/non_literal_attributes.rs
@@ -0,0 +1,147 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::clap::AppSettings;
+use structopt::StructOpt;
+
+pub const DISPLAY_ORDER: usize = 2;
+
+// Check if the global settings compile
+#[derive(StructOpt, Debug, PartialEq, Eq)]
+#[structopt(global_settings = &[AppSettings::ColoredHelp])]
+struct Opt {
+    #[structopt(
+        long = "x",
+        display_order = DISPLAY_ORDER,
+        next_line_help = true,
+        default_value = "0",
+        require_equals = true
+    )]
+    x: i32,
+
+    #[structopt(short = "l", long = "level", aliases = &["set-level", "lvl"])]
+    level: String,
+
+    #[structopt(long("values"))]
+    values: Vec<i32>,
+
+    #[structopt(name = "FILE", requires_if("FILE", "values"))]
+    files: Vec<String>,
+}
+
+#[test]
+fn test_slice() {
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1"]))
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--level", "1"]))
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--set-level", "1"]))
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: Vec::new(),
+            values: vec![],
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--lvl", "1"]))
+    );
+}
+
+#[test]
+fn test_multi_args() {
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: vec!["file".to_string()],
+            values: vec![],
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "file"]))
+    );
+    assert_eq!(
+        Opt {
+            x: 0,
+            level: "1".to_string(),
+            files: vec!["FILE".to_string()],
+            values: vec![1],
+        },
+        Opt::from_clap(
+            &Opt::clap().get_matches_from(&["test", "-l", "1", "--values", "1", "--", "FILE"]),
+        )
+    );
+}
+
+#[test]
+fn test_multi_args_fail() {
+    let result = Opt::clap().get_matches_from_safe(&["test", "-l", "1", "--", "FILE"]);
+    assert!(result.is_err());
+}
+
+#[test]
+fn test_bool() {
+    assert_eq!(
+        Opt {
+            x: 1,
+            level: "1".to_string(),
+            files: vec![],
+            values: vec![],
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "--x=1"]))
+    );
+    let result = Opt::clap().get_matches_from_safe(&["test", "-l", "1", "--x", "1"]);
+    assert!(result.is_err());
+}
+
+fn parse_hex(input: &str) -> Result<u64, std::num::ParseIntError> {
+    u64::from_str_radix(input, 16)
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+struct HexOpt {
+    #[structopt(short = "n", parse(try_from_str = parse_hex))]
+    number: u64,
+}
+
+#[test]
+fn test_parse_hex_function_path() {
+    assert_eq!(
+        HexOpt { number: 5 },
+        HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "5"]))
+    );
+    assert_eq!(
+        HexOpt { number: 0xabcdef },
+        HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"]))
+    );
+
+    let err = HexOpt::clap()
+        .get_matches_from_safe(&["test", "-n", "gg"])
+        .unwrap_err();
+    assert!(err.message.contains("invalid digit found in string"), err);
+}
diff --git a/tests/options.rs b/tests/options.rs
new file mode 100644
index 0000000..803abb4
--- /dev/null
+++ b/tests/options.rs
@@ -0,0 +1,336 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn required_option() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, long)]
+        arg: i32,
+    }
+    assert_eq!(
+        Opt { arg: 42 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))
+    );
+    assert_eq!(
+        Opt { arg: 42 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "42"]))
+    );
+    assert_eq!(
+        Opt { arg: 42 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--arg", "42"]))
+    );
+    assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err());
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a42", "-a24"])
+        .is_err());
+}
+
+#[test]
+fn optional_option() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short)]
+        arg: Option<i32>,
+    }
+    assert_eq!(
+        Opt { arg: Some(42) },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))
+    );
+    assert_eq!(
+        Opt { arg: None },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a42", "-a24"])
+        .is_err());
+}
+
+#[test]
+fn option_with_default() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, default_value = "42")]
+        arg: i32,
+    }
+    assert_eq!(
+        Opt { arg: 24 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))
+    );
+    assert_eq!(
+        Opt { arg: 42 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a42", "-a24"])
+        .is_err());
+}
+
+#[test]
+fn option_with_raw_default() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, default_value = "42")]
+        arg: i32,
+    }
+    assert_eq!(
+        Opt { arg: 24 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))
+    );
+    assert_eq!(
+        Opt { arg: 42 },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a42", "-a24"])
+        .is_err());
+}
+
+#[test]
+fn options() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, long)]
+        arg: Vec<i32>,
+    }
+    assert_eq!(
+        Opt { arg: vec![24] },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))
+    );
+    assert_eq!(
+        Opt { arg: vec![] },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert_eq!(
+        Opt { arg: vec![24, 42] },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24", "--arg", "42"]))
+    );
+}
+
+#[test]
+fn empy_default_value() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short, default_value = "")]
+        arg: String,
+    }
+    assert_eq!(Opt { arg: "".into() }, Opt::from_iter(&["test"]));
+    assert_eq!(
+        Opt { arg: "foo".into() },
+        Opt::from_iter(&["test", "-afoo"])
+    );
+}
+
+#[test]
+fn option_from_str() {
+    #[derive(Debug, PartialEq)]
+    struct A;
+
+    impl<'a> From<&'a str> for A {
+        fn from(_: &str) -> A {
+            A
+        }
+    }
+
+    #[derive(Debug, StructOpt, PartialEq)]
+    struct Opt {
+        #[structopt(parse(from_str))]
+        a: Option<A>,
+    }
+
+    assert_eq!(Opt { a: None }, Opt::from_iter(&["test"]));
+    assert_eq!(Opt { a: Some(A) }, Opt::from_iter(&["test", "foo"]));
+}
+
+#[test]
+fn optional_argument_for_optional_option() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short)]
+        #[allow(clippy::option_option)]
+        arg: Option<Option<i32>>,
+    }
+    assert_eq!(
+        Opt {
+            arg: Some(Some(42))
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))
+    );
+    assert_eq!(
+        Opt { arg: Some(None) },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+    );
+    assert_eq!(
+        Opt { arg: None },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+    assert!(Opt::clap()
+        .get_matches_from_safe(&["test", "-a42", "-a24"])
+        .is_err());
+}
+
+#[test]
+fn two_option_options() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    #[allow(clippy::option_option)]
+    struct Opt {
+        #[structopt(short)]
+        arg: Option<Option<i32>>,
+
+        #[structopt(long)]
+        field: Option<Option<String>>,
+    }
+    assert_eq!(
+        Opt {
+            arg: Some(Some(42)),
+            field: Some(Some("f".into()))
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42", "--field", "f"]))
+    );
+    assert_eq!(
+        Opt {
+            arg: Some(Some(42)),
+            field: Some(None)
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42", "--field"]))
+    );
+    assert_eq!(
+        Opt {
+            arg: Some(None),
+            field: Some(None)
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--field"]))
+    );
+    assert_eq!(
+        Opt {
+            arg: Some(None),
+            field: Some(Some("f".into()))
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--field", "f"]))
+    );
+    assert_eq!(
+        Opt {
+            arg: None,
+            field: Some(None)
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--field"]))
+    );
+    assert_eq!(
+        Opt {
+            arg: None,
+            field: None
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+}
+
+#[test]
+fn optional_vec() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short)]
+        arg: Option<Vec<i32>>,
+    }
+    assert_eq!(
+        Opt { arg: Some(vec![1]) },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1"]))
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2"]))
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2", "-a"]))
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a", "-a2"]))
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "2"]))
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2, 3])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "2", "-a", "3"]))
+    );
+
+    assert_eq!(
+        Opt { arg: Some(vec![]) },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))
+    );
+
+    assert_eq!(
+        Opt { arg: Some(vec![]) },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"]))
+    );
+
+    assert_eq!(
+        Opt { arg: None },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+}
+
+#[test]
+fn two_optional_vecs() {
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(short)]
+        arg: Option<Vec<i32>>,
+
+        #[structopt(short)]
+        b: Option<Vec<i32>>,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1]),
+            b: Some(vec![])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "1", "-b"]))
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1]),
+            b: Some(vec![])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-b", "-a1"]))
+    );
+
+    assert_eq!(
+        Opt {
+            arg: Some(vec![1, 2]),
+            b: Some(vec![1, 2])
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a1", "-a2", "-b1", "-b2"]))
+    );
+
+    assert_eq!(
+        Opt { arg: None, b: None },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))
+    );
+}
diff --git a/tests/privacy.rs b/tests/privacy.rs
new file mode 100644
index 0000000..730bbce
--- /dev/null
+++ b/tests/privacy.rs
@@ -0,0 +1,32 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+mod options {
+    use super::StructOpt;
+
+    #[derive(Debug, StructOpt)]
+    pub struct Options {
+        #[structopt(subcommand)]
+        pub subcommand: super::subcommands::SubCommand,
+    }
+}
+
+mod subcommands {
+    use super::StructOpt;
+
+    #[derive(Debug, StructOpt)]
+    pub enum SubCommand {
+        /// foo
+        Foo {
+            /// foo
+            bars: Vec<String>,
+        },
+    }
+}
diff --git a/tests/raw_bool_literal.rs b/tests/raw_bool_literal.rs
new file mode 100644
index 0000000..faf8628
--- /dev/null
+++ b/tests/raw_bool_literal.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn raw_bool_literal() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    #[structopt(no_version, name = "raw_bool")]
+    struct Opt {
+        #[structopt(raw(false))]
+        a: String,
+        #[structopt(raw(true))]
+        b: String,
+    }
+
+    assert_eq!(
+        Opt {
+            a: "one".into(),
+            b: "--help".into()
+        },
+        Opt::from_iter(&["test", "one", "--", "--help"])
+    );
+}
diff --git a/tests/raw_idents.rs b/tests/raw_idents.rs
new file mode 100644
index 0000000..c00ff66
--- /dev/null
+++ b/tests/raw_idents.rs
@@ -0,0 +1,17 @@
+use structopt::StructOpt;
+
+#[test]
+fn raw_idents() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(short, long)]
+        r#type: Vec<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            r#type: vec!["long".into(), "short".into()]
+        },
+        Opt::from_iter(&["test", "--type", "long", "-t", "short"])
+    );
+}
diff --git a/tests/rename_all_env.rs b/tests/rename_all_env.rs
new file mode 100644
index 0000000..1979e84
--- /dev/null
+++ b/tests/rename_all_env.rs
@@ -0,0 +1,46 @@
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[test]
+fn it_works() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    #[structopt(rename_all_env = "kebab")]
+    struct BehaviorModel {
+        #[structopt(env)]
+        be_nice: String,
+    }
+
+    let help = get_help::<BehaviorModel>();
+    assert!(help.contains("[env: be-nice=]"));
+}
+
+#[test]
+fn default_is_screaming() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    struct BehaviorModel {
+        #[structopt(env)]
+        be_nice: String,
+    }
+
+    let help = get_help::<BehaviorModel>();
+    assert!(help.contains("[env: BE_NICE=]"));
+}
+
+#[test]
+fn overridable() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    #[structopt(rename_all_env = "kebab")]
+    struct BehaviorModel {
+        #[structopt(env)]
+        be_nice: String,
+
+        #[structopt(rename_all_env = "pascal", env)]
+        be_agressive: String,
+    }
+
+    let help = get_help::<BehaviorModel>();
+    assert!(help.contains("[env: be-nice=]"));
+    assert!(help.contains("[env: BeAgressive=]"));
+}
diff --git a/tests/skip.rs b/tests/skip.rs
new file mode 100644
index 0000000..47682d8
--- /dev/null
+++ b/tests/skip.rs
@@ -0,0 +1,148 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[test]
+fn skip_1() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(short)]
+        x: u32,
+        #[structopt(skip)]
+        s: u32,
+    }
+
+    assert!(Opt::from_iter_safe(&["test", "-x", "10", "20"]).is_err());
+    assert_eq!(
+        Opt::from_iter(&["test", "-x", "10"]),
+        Opt {
+            x: 10,
+            s: 0, // default
+        }
+    );
+}
+
+#[test]
+fn skip_2() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(short)]
+        x: u32,
+        #[structopt(skip)]
+        ss: String,
+        #[structopt(skip)]
+        sn: u8,
+        y: u32,
+        #[structopt(skip)]
+        sz: u16,
+        t: u32,
+    }
+
+    assert_eq!(
+        Opt::from_iter(&["test", "-x", "10", "20", "30"]),
+        Opt {
+            x: 10,
+            ss: String::from(""),
+            sn: 0,
+            y: 20,
+            sz: 0,
+            t: 30,
+        }
+    );
+}
+
+#[test]
+fn skip_enum() {
+    #[derive(Debug, PartialEq)]
+    #[allow(unused)]
+    enum Kind {
+        A,
+        B,
+    }
+
+    impl Default for Kind {
+        fn default() -> Self {
+            return Kind::B;
+        }
+    }
+
+    #[derive(StructOpt, Debug, PartialEq)]
+    pub struct Opt {
+        #[structopt(long, short)]
+        number: u32,
+        #[structopt(skip)]
+        k: Kind,
+        #[structopt(skip)]
+        v: Vec<u32>,
+    }
+
+    assert_eq!(
+        Opt::from_iter(&["test", "-n", "10"]),
+        Opt {
+            number: 10,
+            k: Kind::B,
+            v: vec![],
+        }
+    );
+}
+
+#[test]
+fn skip_help_doc_comments() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    pub struct Opt {
+        #[structopt(skip, help = "internal_stuff")]
+        a: u32,
+
+        #[structopt(skip, long_help = "internal_stuff\ndo not touch")]
+        b: u32,
+
+        /// Not meant to be used by clap.
+        ///
+        /// I want a default here.
+        #[structopt(skip)]
+        c: u32,
+
+        #[structopt(short, parse(try_from_str))]
+        n: u32,
+    }
+
+    assert_eq!(
+        Opt::from_iter(&["test", "-n", "10"]),
+        Opt {
+            n: 10,
+            a: 0,
+            b: 0,
+            c: 0,
+        }
+    );
+}
+
+#[test]
+fn skip_val() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    pub struct Opt {
+        #[structopt(long, short)]
+        number: u32,
+
+        #[structopt(skip = "key")]
+        k: String,
+
+        #[structopt(skip = vec![1, 2, 3])]
+        v: Vec<u32>,
+    }
+
+    assert_eq!(
+        Opt::from_iter(&["test", "-n", "10"]),
+        Opt {
+            number: 10,
+            k: "key".into(),
+            v: vec![1, 2, 3]
+        }
+    );
+}
diff --git a/tests/special_types.rs b/tests/special_types.rs
new file mode 100644
index 0000000..ffed5e2
--- /dev/null
+++ b/tests/special_types.rs
@@ -0,0 +1,73 @@
+//! Checks that types like `::std::option::Option` are not special
+
+use structopt::StructOpt;
+
+#[rustversion::since(1.37)]
+#[test]
+fn special_types_bool() {
+    mod inner {
+        #[allow(non_camel_case_types)]
+        #[derive(PartialEq, Debug)]
+        pub struct bool(pub String);
+
+        impl std::str::FromStr for self::bool {
+            type Err = String;
+
+            fn from_str(s: &str) -> Result<Self, Self::Err> {
+                Ok(self::bool(s.into()))
+            }
+        }
+    };
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        arg: inner::bool,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: inner::bool("success".into())
+        },
+        Opt::from_iter(&["test", "success"])
+    );
+}
+
+#[test]
+fn special_types_option() {
+    fn parser(s: &str) -> Option<String> {
+        Some(s.to_string())
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(parse(from_str = parser))]
+        arg: ::std::option::Option<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: Some("success".into())
+        },
+        Opt::from_iter(&["test", "success"])
+    );
+}
+
+#[test]
+fn special_types_vec() {
+    fn parser(s: &str) -> Vec<String> {
+        vec![s.to_string()]
+    }
+
+    #[derive(StructOpt, PartialEq, Debug)]
+    struct Opt {
+        #[structopt(parse(from_str = parser))]
+        arg: ::std::vec::Vec<String>,
+    }
+
+    assert_eq!(
+        Opt {
+            arg: vec!["success".into()]
+        },
+        Opt::from_iter(&["test", "success"])
+    );
+}
diff --git a/tests/subcommands.rs b/tests/subcommands.rs
new file mode 100644
index 0000000..1fc8e76
--- /dev/null
+++ b/tests/subcommands.rs
@@ -0,0 +1,303 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod utils;
+
+use structopt::StructOpt;
+use utils::*;
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt {
+    /// Fetch stuff from GitHub
+    Fetch {
+        #[structopt(long)]
+        all: bool,
+        #[structopt(short, long)]
+        /// Overwrite local branches.
+        force: bool,
+        repo: String,
+    },
+
+    Add {
+        #[structopt(short, long)]
+        interactive: bool,
+        #[structopt(short, long)]
+        verbose: bool,
+    },
+}
+
+#[test]
+fn test_fetch() {
+    assert_eq!(
+        Opt::Fetch {
+            all: true,
+            force: false,
+            repo: "origin".to_string()
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "--all", "origin"]))
+    );
+    assert_eq!(
+        Opt::Fetch {
+            all: false,
+            force: true,
+            repo: "origin".to_string()
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "-f", "origin"]))
+    );
+}
+
+#[test]
+fn test_add() {
+    assert_eq!(
+        Opt::Add {
+            interactive: false,
+            verbose: false
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))
+    );
+    assert_eq!(
+        Opt::Add {
+            interactive: true,
+            verbose: true
+        },
+        Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add", "-i", "-v"]))
+    );
+}
+
+#[test]
+fn test_no_parse() {
+    let result = Opt::clap().get_matches_from_safe(&["test", "badcmd", "-i", "-v"]);
+    assert!(result.is_err());
+
+    let result = Opt::clap().get_matches_from_safe(&["test", "add", "--badoption"]);
+    assert!(result.is_err());
+
+    let result = Opt::clap().get_matches_from_safe(&["test"]);
+    assert!(result.is_err());
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt2 {
+    DoSomething { arg: String },
+}
+
+#[test]
+/// This test is specifically to make sure that hyphenated subcommands get
+/// processed correctly.
+fn test_hyphenated_subcommands() {
+    assert_eq!(
+        Opt2::DoSomething {
+            arg: "blah".to_string()
+        },
+        Opt2::from_clap(&Opt2::clap().get_matches_from(&["test", "do-something", "blah"]))
+    );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt3 {
+    Add,
+    Init,
+    Fetch,
+}
+
+#[test]
+fn test_null_commands() {
+    assert_eq!(
+        Opt3::Add,
+        Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "add"]))
+    );
+    assert_eq!(
+        Opt3::Init,
+        Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "init"]))
+    );
+    assert_eq!(
+        Opt3::Fetch,
+        Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "fetch"]))
+    );
+}
+
+#[derive(StructOpt, PartialEq, Debug)]
+#[structopt(about = "Not shown")]
+struct Add {
+    file: String,
+}
+/// Not shown
+#[derive(StructOpt, PartialEq, Debug)]
+struct Fetch {
+    remote: String,
+}
+#[derive(StructOpt, PartialEq, Debug)]
+enum Opt4 {
+    // Not shown
+    /// Add a file
+    Add(Add),
+    Init,
+    /// download history from remote
+    Fetch(Fetch),
+}
+
+#[test]
+fn test_tuple_commands() {
+    assert_eq!(
+        Opt4::Add(Add {
+            file: "f".to_string()
+        }),
+        Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "add", "f"]))
+    );
+    assert_eq!(
+        Opt4::Init,
+        Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "init"]))
+    );
+    assert_eq!(
+        Opt4::Fetch(Fetch {
+            remote: "origin".to_string()
+        }),
+        Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "fetch", "origin"]))
+    );
+
+    let output = get_long_help::<Opt4>();
+
+    assert!(output.contains("download history from remote"));
+    assert!(output.contains("Add a file"));
+    assert!(!output.contains("Not shown"));
+}
+
+#[test]
+fn enum_in_enum_subsubcommand() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    pub enum Opt {
+        Daemon(DaemonCommand),
+    }
+
+    #[derive(StructOpt, Debug, PartialEq)]
+    pub enum DaemonCommand {
+        Start,
+        Stop,
+    }
+
+    let result = Opt::clap().get_matches_from_safe(&["test"]);
+    assert!(result.is_err());
+
+    let result = Opt::clap().get_matches_from_safe(&["test", "daemon"]);
+    assert!(result.is_err());
+
+    let result = Opt::from_iter(&["test", "daemon", "start"]);
+    assert_eq!(Opt::Daemon(DaemonCommand::Start), result);
+}
+
+#[test]
+fn flatten_enum() {
+    #[derive(StructOpt, Debug, PartialEq)]
+    struct Opt {
+        #[structopt(flatten)]
+        sub_cmd: SubCmd,
+    }
+    #[derive(StructOpt, Debug, PartialEq)]
+    enum SubCmd {
+        Foo,
+        Bar,
+    }
+
+    assert!(Opt::from_iter_safe(&["test"]).is_err());
+    assert_eq!(
+        Opt::from_iter(&["test", "foo"]),
+        Opt {
+            sub_cmd: SubCmd::Foo
+        }
+    );
+}
+
+#[test]
+fn external_subcommand() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    struct Opt {
+        #[structopt(subcommand)]
+        sub: Subcommands,
+    }
+
+    #[derive(Debug, PartialEq, StructOpt)]
+    enum Subcommands {
+        Add,
+        Remove,
+        #[structopt(external_subcommand)]
+        Other(Vec<String>),
+    }
+
+    assert_eq!(
+        Opt::from_iter(&["test", "add"]),
+        Opt {
+            sub: Subcommands::Add
+        }
+    );
+
+    assert_eq!(
+        Opt::from_iter(&["test", "remove"]),
+        Opt {
+            sub: Subcommands::Remove
+        }
+    );
+
+    assert_eq!(
+        Opt::from_iter(&["test", "git", "status"]),
+        Opt {
+            sub: Subcommands::Other(vec!["git".into(), "status".into()])
+        }
+    );
+
+    assert!(Opt::from_iter_safe(&["test"]).is_err());
+}
+
+#[test]
+fn external_subcommand_os_string() {
+    use std::ffi::OsString;
+
+    #[derive(Debug, PartialEq, StructOpt)]
+    struct Opt {
+        #[structopt(subcommand)]
+        sub: Subcommands,
+    }
+
+    #[derive(Debug, PartialEq, StructOpt)]
+    enum Subcommands {
+        #[structopt(external_subcommand)]
+        Other(Vec<OsString>),
+    }
+
+    assert_eq!(
+        Opt::from_iter(&["test", "git", "status"]),
+        Opt {
+            sub: Subcommands::Other(vec!["git".into(), "status".into()])
+        }
+    );
+
+    assert!(Opt::from_iter_safe(&["test"]).is_err());
+}
+
+#[test]
+fn external_subcommand_optional() {
+    #[derive(Debug, PartialEq, StructOpt)]
+    struct Opt {
+        #[structopt(subcommand)]
+        sub: Option<Subcommands>,
+    }
+
+    #[derive(Debug, PartialEq, StructOpt)]
+    enum Subcommands {
+        #[structopt(external_subcommand)]
+        Other(Vec<String>),
+    }
+
+    assert_eq!(
+        Opt::from_iter(&["test", "git", "status"]),
+        Opt {
+            sub: Some(Subcommands::Other(vec!["git".into(), "status".into()]))
+        }
+    );
+
+    assert_eq!(Opt::from_iter(&["test"]), Opt { sub: None });
+}
diff --git a/tests/ui/bool_default_value.rs b/tests/ui/bool_default_value.rs
new file mode 100644
index 0000000..9bdb0c9
--- /dev/null
+++ b/tests/ui/bool_default_value.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(short, default_value = true)]
+    b: bool,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/bool_default_value.stderr b/tests/ui/bool_default_value.stderr
new file mode 100644
index 0000000..1e26a2d
--- /dev/null
+++ b/tests/ui/bool_default_value.stderr
@@ -0,0 +1,5 @@
+error: default_value is meaningless for bool
+  --> $DIR/bool_default_value.rs:14:24
+   |
+14 |     #[structopt(short, default_value = true)]
+   |                        ^^^^^^^^^^^^^
diff --git a/tests/ui/bool_required.rs b/tests/ui/bool_required.rs
new file mode 100644
index 0000000..018223c
--- /dev/null
+++ b/tests/ui/bool_required.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(short, required = true)]
+    b: bool,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/bool_required.stderr b/tests/ui/bool_required.stderr
new file mode 100644
index 0000000..0b80d48
--- /dev/null
+++ b/tests/ui/bool_required.stderr
@@ -0,0 +1,5 @@
+error: required is meaningless for bool
+  --> $DIR/bool_required.rs:14:24
+   |
+14 |     #[structopt(short, required = true)]
+   |                        ^^^^^^^^
diff --git a/tests/ui/enum_flatten.rs b/tests/ui/enum_flatten.rs
new file mode 100644
index 0000000..768de76
--- /dev/null
+++ b/tests/ui/enum_flatten.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+enum Opt {
+    #[structopt(flatten)]
+    Variant1,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/enum_flatten.stderr b/tests/ui/enum_flatten.stderr
new file mode 100644
index 0000000..d74fa85
--- /dev/null
+++ b/tests/ui/enum_flatten.stderr
@@ -0,0 +1,6 @@
+error: `flatten` is usable only with single-typed tuple variants
+  --> $DIR/enum_flatten.rs:14:5
+   |
+14 | /     #[structopt(flatten)]
+15 | |     Variant1,
+   | |____________^
diff --git a/tests/ui/external_subcommand_wrong_type.rs b/tests/ui/external_subcommand_wrong_type.rs
new file mode 100644
index 0000000..ad62e73
--- /dev/null
+++ b/tests/ui/external_subcommand_wrong_type.rs
@@ -0,0 +1,19 @@
+use structopt::StructOpt;
+use std::ffi::CString;
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+    #[structopt(subcommand)]
+    cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(external_subcommand)]
+    Other(Vec<CString>)
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
\ No newline at end of file
diff --git a/tests/ui/external_subcommand_wrong_type.stderr b/tests/ui/external_subcommand_wrong_type.stderr
new file mode 100644
index 0000000..1966225
--- /dev/null
+++ b/tests/ui/external_subcommand_wrong_type.stderr
@@ -0,0 +1,8 @@
+error[E0308]: mismatched types
+  --> $DIR/external_subcommand_wrong_type.rs:13:15
+   |
+13 |     Other(Vec<CString>)
+   |               ^^^^^^^ expected struct `std::ffi::CString`, found struct `std::ffi::OsString`
+   |
+   = note: expected struct `std::vec::Vec<std::ffi::CString>`
+              found struct `std::vec::Vec<std::ffi::OsString>`
diff --git a/tests/ui/flatten_and_doc.rs b/tests/ui/flatten_and_doc.rs
new file mode 100644
index 0000000..2dc154d
--- /dev/null
+++ b/tests/ui/flatten_and_doc.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct DaemonOpts {
+    #[structopt(short)]
+    user: String,
+    #[structopt(short)]
+    group: String,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    /// Opts.
+    #[structopt(flatten)]
+    opts: DaemonOpts,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/flatten_and_doc.stderr b/tests/ui/flatten_and_doc.stderr
new file mode 100644
index 0000000..2724dbb
--- /dev/null
+++ b/tests/ui/flatten_and_doc.stderr
@@ -0,0 +1,5 @@
+error: methods and doc comments are not allowed for flattened entry
+  --> $DIR/flatten_and_doc.rs:23:17
+   |
+23 |     #[structopt(flatten)]
+   |                 ^^^^^^^
diff --git a/tests/ui/flatten_and_methods.rs b/tests/ui/flatten_and_methods.rs
new file mode 100644
index 0000000..ff1af2e
--- /dev/null
+++ b/tests/ui/flatten_and_methods.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct DaemonOpts {
+    #[structopt(short)]
+    user: String,
+    #[structopt(short)]
+    group: String,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(short, flatten)]
+    opts: DaemonOpts,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/flatten_and_methods.stderr b/tests/ui/flatten_and_methods.stderr
new file mode 100644
index 0000000..f058eb3
--- /dev/null
+++ b/tests/ui/flatten_and_methods.stderr
@@ -0,0 +1,5 @@
+error: methods and doc comments are not allowed for flattened entry
+  --> $DIR/flatten_and_methods.rs:22:24
+   |
+22 |     #[structopt(short, flatten)]
+   |                        ^^^^^^^
diff --git a/tests/ui/flatten_and_parse.rs b/tests/ui/flatten_and_parse.rs
new file mode 100644
index 0000000..3317272
--- /dev/null
+++ b/tests/ui/flatten_and_parse.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct DaemonOpts {
+    #[structopt(short)]
+    user: String,
+    #[structopt(short)]
+    group: String,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(flatten, parse(from_occurrences))]
+    opts: DaemonOpts,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/flatten_and_parse.stderr b/tests/ui/flatten_and_parse.stderr
new file mode 100644
index 0000000..e217a84
--- /dev/null
+++ b/tests/ui/flatten_and_parse.stderr
@@ -0,0 +1,5 @@
+error: parse attribute is not allowed for flattened entry
+  --> $DIR/flatten_and_parse.rs:22:26
+   |
+22 |     #[structopt(flatten, parse(from_occurrences))]
+   |                          ^^^^^
diff --git a/tests/ui/multiple_external_subcommand.rs b/tests/ui/multiple_external_subcommand.rs
new file mode 100644
index 0000000..986261b
--- /dev/null
+++ b/tests/ui/multiple_external_subcommand.rs
@@ -0,0 +1,21 @@
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+    #[structopt(subcommand)]
+    cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(external_subcommand)]
+    Run(Vec<String>),
+
+    #[structopt(external_subcommand)]
+    Other(Vec<String>)
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/multiple_external_subcommand.stderr b/tests/ui/multiple_external_subcommand.stderr
new file mode 100644
index 0000000..0c80c2e
--- /dev/null
+++ b/tests/ui/multiple_external_subcommand.stderr
@@ -0,0 +1,5 @@
+error: Only one variant can be marked with `external_subcommand`, this is the second
+  --> $DIR/multiple_external_subcommand.rs:14:17
+   |
+14 |     #[structopt(external_subcommand)]
+   |                 ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/non_existent_attr.rs b/tests/ui/non_existent_attr.rs
new file mode 100644
index 0000000..96daf45
--- /dev/null
+++ b/tests/ui/non_existent_attr.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(short, non_existing_attribute = 1)]
+    debug: bool,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/non_existent_attr.stderr b/tests/ui/non_existent_attr.stderr
new file mode 100644
index 0000000..99dc781
--- /dev/null
+++ b/tests/ui/non_existent_attr.stderr
@@ -0,0 +1,5 @@
+error[E0599]: no method named `non_existing_attribute` found for struct `clap::args::arg::Arg<'_, '_>` in the current scope
+  --> $DIR/non_existent_attr.rs:14:24
+   |
+14 |     #[structopt(short, non_existing_attribute = 1)]
+   |                        ^^^^^^^^^^^^^^^^^^^^^^ method not found in `clap::args::arg::Arg<'_, '_>`
diff --git a/tests/ui/opt_opt_nonpositional.rs b/tests/ui/opt_opt_nonpositional.rs
new file mode 100644
index 0000000..2a08105
--- /dev/null
+++ b/tests/ui/opt_opt_nonpositional.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    n: Option<Option<u32>>,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/opt_opt_nonpositional.stderr b/tests/ui/opt_opt_nonpositional.stderr
new file mode 100644
index 0000000..cb9f172
--- /dev/null
+++ b/tests/ui/opt_opt_nonpositional.stderr
@@ -0,0 +1,5 @@
+error: Option<Option<T>> type is meaningless for positional argument
+  --> $DIR/opt_opt_nonpositional.rs:14:8
+   |
+14 |     n: Option<Option<u32>>,
+   |        ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/opt_vec_nonpositional.rs b/tests/ui/opt_vec_nonpositional.rs
new file mode 100644
index 0000000..0f6f078
--- /dev/null
+++ b/tests/ui/opt_vec_nonpositional.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    n: Option<Vec<u32>>,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/opt_vec_nonpositional.stderr b/tests/ui/opt_vec_nonpositional.stderr
new file mode 100644
index 0000000..c6b343f
--- /dev/null
+++ b/tests/ui/opt_vec_nonpositional.stderr
@@ -0,0 +1,5 @@
+error: Option<Vec<T>> type is meaningless for positional argument
+  --> $DIR/opt_vec_nonpositional.rs:14:8
+   |
+14 |     n: Option<Vec<u32>>,
+   |        ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/option_default_value.rs b/tests/ui/option_default_value.rs
new file mode 100644
index 0000000..a86bc0e
--- /dev/null
+++ b/tests/ui/option_default_value.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(short, default_value = 1)]
+    n: Option<u32>,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/option_default_value.stderr b/tests/ui/option_default_value.stderr
new file mode 100644
index 0000000..2215497
--- /dev/null
+++ b/tests/ui/option_default_value.stderr
@@ -0,0 +1,5 @@
+error: default_value is meaningless for Option
+  --> $DIR/option_default_value.rs:14:24
+   |
+14 |     #[structopt(short, default_value = 1)]
+   |                        ^^^^^^^^^^^^^
diff --git a/tests/ui/option_required.rs b/tests/ui/option_required.rs
new file mode 100644
index 0000000..d91afbf
--- /dev/null
+++ b/tests/ui/option_required.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(short, required = true)]
+    n: Option<u32>,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/option_required.stderr b/tests/ui/option_required.stderr
new file mode 100644
index 0000000..0230d57
--- /dev/null
+++ b/tests/ui/option_required.stderr
@@ -0,0 +1,5 @@
+error: required is meaningless for Option
+  --> $DIR/option_required.rs:14:24
+   |
+14 |     #[structopt(short, required = true)]
+   |                        ^^^^^^^^
diff --git a/tests/ui/parse_empty_try_from_os.rs b/tests/ui/parse_empty_try_from_os.rs
new file mode 100644
index 0000000..acfef0b
--- /dev/null
+++ b/tests/ui/parse_empty_try_from_os.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(parse(try_from_os_str))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/parse_empty_try_from_os.stderr b/tests/ui/parse_empty_try_from_os.stderr
new file mode 100644
index 0000000..3dc9f24
--- /dev/null
+++ b/tests/ui/parse_empty_try_from_os.stderr
@@ -0,0 +1,5 @@
+error: you must set parser for `try_from_os_str` explicitly
+  --> $DIR/parse_empty_try_from_os.rs:14:23
+   |
+14 |     #[structopt(parse(try_from_os_str))]
+   |                       ^^^^^^^^^^^^^^^
diff --git a/tests/ui/parse_function_is_not_path.rs b/tests/ui/parse_function_is_not_path.rs
new file mode 100644
index 0000000..5eebc57
--- /dev/null
+++ b/tests/ui/parse_function_is_not_path.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(parse(from_str = "2"))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/parse_function_is_not_path.stderr b/tests/ui/parse_function_is_not_path.stderr
new file mode 100644
index 0000000..7cf7444
--- /dev/null
+++ b/tests/ui/parse_function_is_not_path.stderr
@@ -0,0 +1,5 @@
+error: `parse` argument must be a function path
+  --> $DIR/parse_function_is_not_path.rs:14:34
+   |
+14 |     #[structopt(parse(from_str = "2"))]
+   |                                  ^^^
diff --git a/tests/ui/parse_literal_spec.rs b/tests/ui/parse_literal_spec.rs
new file mode 100644
index 0000000..b6f125a
--- /dev/null
+++ b/tests/ui/parse_literal_spec.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(parse("from_str"))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/parse_literal_spec.stderr b/tests/ui/parse_literal_spec.stderr
new file mode 100644
index 0000000..6e99e8b
--- /dev/null
+++ b/tests/ui/parse_literal_spec.stderr
@@ -0,0 +1,5 @@
+error: parser specification must start with identifier
+  --> $DIR/parse_literal_spec.rs:14:23
+   |
+14 |     #[structopt(parse("from_str"))]
+   |                       ^^^^^^^^^^
diff --git a/tests/ui/parse_not_zero_args.rs b/tests/ui/parse_not_zero_args.rs
new file mode 100644
index 0000000..8729178
--- /dev/null
+++ b/tests/ui/parse_not_zero_args.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt(parse(from_str, from_str))]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/parse_not_zero_args.stderr b/tests/ui/parse_not_zero_args.stderr
new file mode 100644
index 0000000..34b99a4
--- /dev/null
+++ b/tests/ui/parse_not_zero_args.stderr
@@ -0,0 +1,5 @@
+error: `parse` must have exactly one argument
+  --> $DIR/parse_not_zero_args.rs:14:17
+   |
+14 |     #[structopt(parse(from_str, from_str))]
+   |                 ^^^^^
diff --git a/tests/ui/positional_bool.rs b/tests/ui/positional_bool.rs
new file mode 100644
index 0000000..4dbf538
--- /dev/null
+++ b/tests/ui/positional_bool.rs
@@ -0,0 +1,10 @@
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+    verbose: bool,
+}
+
+fn main() {
+    Opt::from_args();
+}
\ No newline at end of file
diff --git a/tests/ui/positional_bool.stderr b/tests/ui/positional_bool.stderr
new file mode 100644
index 0000000..c3ed1ad
--- /dev/null
+++ b/tests/ui/positional_bool.stderr
@@ -0,0 +1,10 @@
+error: `bool` cannot be used as positional parameter with default parser
+
+  = help: if you want to create a flag add `long` or `short`
+  = help: If you really want a boolean parameter add an explicit parser, for example `parse(try_from_str)`
+  = note: see also https://github.com/TeXitoi/structopt/tree/master/examples/true_or_false.rs
+
+ --> $DIR/positional_bool.rs:5:14
+  |
+5 |     verbose: bool,
+  |              ^^^^
diff --git a/tests/ui/raw.rs b/tests/ui/raw.rs
new file mode 100644
index 0000000..b94f783
--- /dev/null
+++ b/tests/ui/raw.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+struct Opt {
+    #[structopt(raw(case_insensitive = "true"))]
+    s: String,
+}
+
+#[derive(StructOpt, Debug)]
+struct Opt2 {
+    #[structopt(raw(requires_if = r#""one", "two""#))]
+    s: String,
+}
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/raw.stderr b/tests/ui/raw.stderr
new file mode 100644
index 0000000..93b5e38
--- /dev/null
+++ b/tests/ui/raw.stderr
@@ -0,0 +1,19 @@
+error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods
+
+  = help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)`
+  = note: if you need to call `clap::Arg/App::case_insensitive` method you can do it like this: #[structopt(case_insensitive = true)]
+
+  --> $DIR/raw.rs:13:17
+   |
+13 |     #[structopt(raw(case_insensitive = "true"))]
+   |                 ^^^
+
+error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods
+
+  = help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)`
+  = note: if you need to call `clap::Arg/App::requires_if` method you can do it like this: #[structopt(requires_if("one", "two"))]
+
+  --> $DIR/raw.rs:19:17
+   |
+19 |     #[structopt(raw(requires_if = r#""one", "two""#))]
+   |                 ^^^
diff --git a/tests/ui/rename_all_wrong_casing.rs b/tests/ui/rename_all_wrong_casing.rs
new file mode 100644
index 0000000..4dabe14
--- /dev/null
+++ b/tests/ui/rename_all_wrong_casing.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic", rename_all = "fail")]
+struct Opt {
+    #[structopt(short)]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/rename_all_wrong_casing.stderr b/tests/ui/rename_all_wrong_casing.stderr
new file mode 100644
index 0000000..2a72080
--- /dev/null
+++ b/tests/ui/rename_all_wrong_casing.stderr
@@ -0,0 +1,5 @@
+error: unsupported casing: `fail`
+  --> $DIR/rename_all_wrong_casing.rs:12:42
+   |
+12 | #[structopt(name = "basic", rename_all = "fail")]
+   |                                          ^^^^^^
diff --git a/tests/ui/skip_flatten.rs b/tests/ui/skip_flatten.rs
new file mode 100644
index 0000000..8668ec2
--- /dev/null
+++ b/tests/ui/skip_flatten.rs
@@ -0,0 +1,42 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+    #[structopt(short)]
+    s: String,
+
+    #[structopt(skip, flatten)]
+    cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[structopt(short)]
+        color: String,
+    },
+}
+
+impl Default for Command {
+    fn default() -> Self {
+        Command::Pound { acorns: 0 }
+    }
+}
+
+fn main() {
+    let opt = MakeCookie::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/skip_flatten.stderr b/tests/ui/skip_flatten.stderr
new file mode 100644
index 0000000..76477a3
--- /dev/null
+++ b/tests/ui/skip_flatten.stderr
@@ -0,0 +1,5 @@
+error: subcommand, flatten and skip cannot be used together
+  --> $DIR/skip_flatten.rs:17:23
+   |
+17 |     #[structopt(skip, flatten)]
+   |                       ^^^^^^^
diff --git a/tests/ui/skip_subcommand.rs b/tests/ui/skip_subcommand.rs
new file mode 100644
index 0000000..5d21426
--- /dev/null
+++ b/tests/ui/skip_subcommand.rs
@@ -0,0 +1,42 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+    #[structopt(short)]
+    s: String,
+
+    #[structopt(subcommand, skip)]
+    cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[structopt(short)]
+        color: String,
+    },
+}
+
+impl Default for Command {
+    fn default() -> Self {
+        Command::Pound { acorns: 0 }
+    }
+}
+
+fn main() {
+    let opt = MakeCookie::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/skip_subcommand.stderr b/tests/ui/skip_subcommand.stderr
new file mode 100644
index 0000000..aba2d69
--- /dev/null
+++ b/tests/ui/skip_subcommand.stderr
@@ -0,0 +1,5 @@
+error: subcommand, flatten and skip cannot be used together
+  --> $DIR/skip_subcommand.rs:17:29
+   |
+17 |     #[structopt(subcommand, skip)]
+   |                             ^^^^
diff --git a/tests/ui/skip_with_other_options.rs b/tests/ui/skip_with_other_options.rs
new file mode 100644
index 0000000..73c5342
--- /dev/null
+++ b/tests/ui/skip_with_other_options.rs
@@ -0,0 +1,15 @@
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "test")]
+pub struct Opt {
+    #[structopt(long)]
+    a: u32,
+    #[structopt(skip, long)]
+    b: u32,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/skip_with_other_options.stderr b/tests/ui/skip_with_other_options.stderr
new file mode 100644
index 0000000..3345f92
--- /dev/null
+++ b/tests/ui/skip_with_other_options.stderr
@@ -0,0 +1,5 @@
+error: methods are not allowed for skipped fields
+ --> $DIR/skip_with_other_options.rs:8:17
+  |
+8 |     #[structopt(skip, long)]
+  |                 ^^^^
diff --git a/tests/ui/skip_without_default.rs b/tests/ui/skip_without_default.rs
new file mode 100644
index 0000000..bc47511
--- /dev/null
+++ b/tests/ui/skip_without_default.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(Debug)]
+enum Kind {
+    A,
+    B,
+}
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "test")]
+pub struct Opt {
+    #[structopt(short)]
+    number: u32,
+    #[structopt(skip)]
+    k: Kind,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/skip_without_default.stderr b/tests/ui/skip_without_default.stderr
new file mode 100644
index 0000000..330898f
--- /dev/null
+++ b/tests/ui/skip_without_default.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `Kind: std::default::Default` is not satisfied
+  --> $DIR/skip_without_default.rs:22:17
+   |
+22 |     #[structopt(skip)]
+   |                 ^^^^ the trait `std::default::Default` is not implemented for `Kind`
+   |
+   = note: required by `std::default::Default::default`
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/struct_parse.rs b/tests/ui/struct_parse.rs
new file mode 100644
index 0000000..e428b23
--- /dev/null
+++ b/tests/ui/struct_parse.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic", parse(from_str))]
+struct Opt {
+    #[structopt(short)]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/struct_parse.stderr b/tests/ui/struct_parse.stderr
new file mode 100644
index 0000000..5518214
--- /dev/null
+++ b/tests/ui/struct_parse.stderr
@@ -0,0 +1,5 @@
+error: `parse` attribute is only allowed on fields
+  --> $DIR/struct_parse.rs:12:29
+   |
+12 | #[structopt(name = "basic", parse(from_str))]
+   |                             ^^^^^
diff --git a/tests/ui/struct_subcommand.rs b/tests/ui/struct_subcommand.rs
new file mode 100644
index 0000000..ac0b145
--- /dev/null
+++ b/tests/ui/struct_subcommand.rs
@@ -0,0 +1,21 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic", subcommand)]
+struct Opt {
+    #[structopt(short)]
+    s: String,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/struct_subcommand.stderr b/tests/ui/struct_subcommand.stderr
new file mode 100644
index 0000000..438f6f8
--- /dev/null
+++ b/tests/ui/struct_subcommand.stderr
@@ -0,0 +1,5 @@
+error: subcommand is only allowed on fields
+  --> $DIR/struct_subcommand.rs:12:29
+   |
+12 | #[structopt(name = "basic", subcommand)]
+   |                             ^^^^^^^^^^
diff --git a/tests/ui/structopt_empty_attr.rs b/tests/ui/structopt_empty_attr.rs
new file mode 100644
index 0000000..a7fc0b9
--- /dev/null
+++ b/tests/ui/structopt_empty_attr.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt]
+    debug: bool,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
+
diff --git a/tests/ui/structopt_empty_attr.stderr b/tests/ui/structopt_empty_attr.stderr
new file mode 100644
index 0000000..bd3b3ed
--- /dev/null
+++ b/tests/ui/structopt_empty_attr.stderr
@@ -0,0 +1,5 @@
+error: expected attribute arguments in parentheses: #[structopt(...)]
+  --> $DIR/structopt_empty_attr.rs:14:5
+   |
+14 |     #[structopt]
+   |     ^^^^^^^^^^^^
diff --git a/tests/ui/structopt_name_value_attr.rs b/tests/ui/structopt_name_value_attr.rs
new file mode 100644
index 0000000..3d9388f
--- /dev/null
+++ b/tests/ui/structopt_name_value_attr.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt {
+    #[structopt = "short"]
+    debug: bool,
+}
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
+
diff --git a/tests/ui/structopt_name_value_attr.stderr b/tests/ui/structopt_name_value_attr.stderr
new file mode 100644
index 0000000..373a3b8
--- /dev/null
+++ b/tests/ui/structopt_name_value_attr.stderr
@@ -0,0 +1,5 @@
+error: expected parentheses: #[structopt(...)]
+  --> $DIR/structopt_name_value_attr.rs:14:17
+   |
+14 |     #[structopt = "short"]
+   |                 ^
diff --git a/tests/ui/subcommand_and_flatten.rs b/tests/ui/subcommand_and_flatten.rs
new file mode 100644
index 0000000..742ee6d
--- /dev/null
+++ b/tests/ui/subcommand_and_flatten.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+    #[structopt(short)]
+    s: String,
+
+    #[structopt(subcommand, flatten)]
+    cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[structopt(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/subcommand_and_flatten.stderr b/tests/ui/subcommand_and_flatten.stderr
new file mode 100644
index 0000000..cacea5e
--- /dev/null
+++ b/tests/ui/subcommand_and_flatten.stderr
@@ -0,0 +1,5 @@
+error: subcommand, flatten and skip cannot be used together
+  --> $DIR/subcommand_and_flatten.rs:17:29
+   |
+17 |     #[structopt(subcommand, flatten)]
+   |                             ^^^^^^^
diff --git a/tests/ui/subcommand_and_methods.rs b/tests/ui/subcommand_and_methods.rs
new file mode 100644
index 0000000..890f10c
--- /dev/null
+++ b/tests/ui/subcommand_and_methods.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+    #[structopt(short)]
+    s: String,
+
+    #[structopt(subcommand, long)]
+    cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[structopt(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/subcommand_and_methods.stderr b/tests/ui/subcommand_and_methods.stderr
new file mode 100644
index 0000000..ccaf28d
--- /dev/null
+++ b/tests/ui/subcommand_and_methods.stderr
@@ -0,0 +1,5 @@
+error: methods in attributes are not allowed for subcommand
+  --> $DIR/subcommand_and_methods.rs:17:17
+   |
+17 |     #[structopt(subcommand, long)]
+   |                 ^^^^^^^^^^
diff --git a/tests/ui/subcommand_and_parse.rs b/tests/ui/subcommand_and_parse.rs
new file mode 100644
index 0000000..f24e4bc
--- /dev/null
+++ b/tests/ui/subcommand_and_parse.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+    #[structopt(short)]
+    s: String,
+
+    #[structopt(subcommand, parse(from_occurrences))]
+    cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[structopt(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/subcommand_and_parse.stderr b/tests/ui/subcommand_and_parse.stderr
new file mode 100644
index 0000000..4070056
--- /dev/null
+++ b/tests/ui/subcommand_and_parse.stderr
@@ -0,0 +1,5 @@
+error: parse attribute is not allowed for subcommand
+  --> $DIR/subcommand_and_parse.rs:17:29
+   |
+17 |     #[structopt(subcommand, parse(from_occurrences))]
+   |                             ^^^^^
diff --git a/tests/ui/subcommand_opt_opt.rs b/tests/ui/subcommand_opt_opt.rs
new file mode 100644
index 0000000..1dd84e5
--- /dev/null
+++ b/tests/ui/subcommand_opt_opt.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+    #[structopt(short)]
+    s: String,
+
+    #[structopt(subcommand)]
+    cmd: Option<Option<Command>>,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[structopt(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/subcommand_opt_opt.stderr b/tests/ui/subcommand_opt_opt.stderr
new file mode 100644
index 0000000..25b37e5
--- /dev/null
+++ b/tests/ui/subcommand_opt_opt.stderr
@@ -0,0 +1,5 @@
+error: Option<Option<T>> type is not allowed for subcommand
+  --> $DIR/subcommand_opt_opt.rs:18:10
+   |
+18 |     cmd: Option<Option<Command>>,
+   |          ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/subcommand_opt_vec.rs b/tests/ui/subcommand_opt_vec.rs
new file mode 100644
index 0000000..17bffbf
--- /dev/null
+++ b/tests/ui/subcommand_opt_vec.rs
@@ -0,0 +1,36 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "make-cookie")]
+struct MakeCookie {
+    #[structopt(short)]
+    s: String,
+
+    #[structopt(subcommand)]
+    cmd: Option<Vec<Command>>,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+    #[structopt(name = "pound")]
+    /// Pound acorns into flour for cookie dough.
+    Pound { acorns: u32 },
+
+    Sparkle {
+        #[structopt(short)]
+        color: String,
+    },
+}
+
+fn main() {
+    let opt = MakeCookie::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/subcommand_opt_vec.stderr b/tests/ui/subcommand_opt_vec.stderr
new file mode 100644
index 0000000..a36071b
--- /dev/null
+++ b/tests/ui/subcommand_opt_vec.stderr
@@ -0,0 +1,5 @@
+error: Option<Vec<T>> type is not allowed for subcommand
+  --> $DIR/subcommand_opt_vec.rs:18:10
+   |
+18 |     cmd: Option<Vec<Command>>,
+   |          ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/tuple_struct.rs b/tests/ui/tuple_struct.rs
new file mode 100644
index 0000000..af9b1d5
--- /dev/null
+++ b/tests/ui/tuple_struct.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use structopt::StructOpt;
+
+#[derive(StructOpt, Debug)]
+#[structopt(name = "basic")]
+struct Opt(u32);
+
+fn main() {
+    let opt = Opt::from_args();
+    println!("{:?}", opt);
+}
diff --git a/tests/ui/tuple_struct.stderr b/tests/ui/tuple_struct.stderr
new file mode 100644
index 0000000..9f2876f
--- /dev/null
+++ b/tests/ui/tuple_struct.stderr
@@ -0,0 +1,5 @@
+error: structopt only supports non-tuple structs and enums
+  --> $DIR/tuple_struct.rs:11:10
+   |
+11 | #[derive(StructOpt, Debug)]
+   |          ^^^^^^^^^
diff --git a/tests/utils.rs b/tests/utils.rs
new file mode 100644
index 0000000..c0684a2
--- /dev/null
+++ b/tests/utils.rs
@@ -0,0 +1,45 @@
+#![allow(unused)]
+
+use structopt::StructOpt;
+
+pub fn get_help<T: StructOpt>() -> String {
+    let mut output = Vec::new();
+    <T as StructOpt>::clap().write_help(&mut output).unwrap();
+    let output = String::from_utf8(output).unwrap();
+
+    eprintln!("\n%%% HELP %%%:=====\n{}\n=====\n", output);
+    eprintln!("\n%%% HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output);
+
+    output
+}
+
+pub fn get_long_help<T: StructOpt>() -> String {
+    let mut output = Vec::new();
+    <T as StructOpt>::clap()
+        .write_long_help(&mut output)
+        .unwrap();
+    let output = String::from_utf8(output).unwrap();
+
+    eprintln!("\n%%% LONG_HELP %%%:=====\n{}\n=====\n", output);
+    eprintln!("\n%%% LONG_HELP (DEBUG) %%%:=====\n{:?}\n=====\n", output);
+
+    output
+}
+
+pub fn get_subcommand_long_help<T: StructOpt>(subcmd: &str) -> String {
+    let output = <T as StructOpt>::clap()
+        .get_matches_from_safe(vec!["test", subcmd, "--help"])
+        .expect_err("")
+        .message;
+
+    eprintln!(
+        "\n%%% SUBCOMMAND `{}` HELP %%%:=====\n{}\n=====\n",
+        subcmd, output
+    );
+    eprintln!(
+        "\n%%% SUBCOMMAND `{}` HELP (DEBUG) %%%:=====\n{:?}\n=====\n",
+        subcmd, output
+    );
+
+    output
+}
diff --git a/tests/we_need_syn_full.rs b/tests/we_need_syn_full.rs
new file mode 100644
index 0000000..cc6eca8
--- /dev/null
+++ b/tests/we_need_syn_full.rs
@@ -0,0 +1,19 @@
+// See https://github.com/TeXitoi/structopt/issues/354
+
+use structopt::StructOpt;
+
+#[test]
+fn we_need_syn_full() {
+    #[allow(unused)]
+    #[derive(Debug, StructOpt, Clone)]
+    struct Args {
+        #[structopt(
+            short = "c",
+            long = "colour",
+            help = "Output colouring",
+            default_value = "auto",
+            possible_values = &["always", "auto", "never"]
+        )]
+        colour: String,
+    }
+}