<commit_before>#![recursion_limit = "1000"]

#[macro_use]
extern crate error_chain;
extern crate lalrpop_util;
extern crate reproto_core as core;
extern crate num;

mod lexer;
mod utils;
pub mod ast;
pub mod errors;
#[allow(unused)]
mod parser;
mod token;

use core::Object;
use self::errors::*;
use std::io::Read;
use std::rc::Rc;

pub fn read_reader<'a, R>(mut reader: R) -> Result<String>
where
    R: AsMut<Read + 'a>,
{
    let mut content = String::new();
    reader.as_mut().read_to_string(&mut content)?;
    Ok(content)
}

pub fn parse_string<'input>(
    object: Rc<Box<Object>>,
    input: &'input str,
) -> Result<ast::File<'input>> {
    use self::ErrorKind::*;
    use lalrpop_util::ParseError::*;
    use self::token::Error::*;

    let lexer = lexer::lex(input);

    match parser::parse_File(&object, lexer) {
        Ok(file) => Ok(file),
        Err(e) => {
            match e {
                InvalidToken { location } => {
                    let pos = (object.clone(), location, location);
                    Err(Syntax(Some(pos.into()), vec![]).into())
                }
                UnrecognizedToken { token, expected } => {
                    let pos = token.map(|(start, _, end)| (object.clone(), start, end));
                    Err(Syntax(pos.map(Into::into), expected).into())
                }
                User { error } => {
                    match error {
                        UnterminatedString { start } => {
                            let pos = (object.clone(), start, start);
                            return Err(Parse("unterminated string", pos.into()).into());
                        }
                        UnterminatedEscape { start } => {
                            let pos = (object.clone(), start, start);
                            return Err(Parse("unterminated escape sequence", pos.into()).into());
                        }
                        InvalidEscape { pos, message } => {
                            let pos = (object.clone(), pos, pos);
                            return Err(Parse(message, pos.into()).into());
                        }
                        UnterminatedCodeBlock { start } => {
                            let pos = (object.clone(), start, start);
                            return Err(Parse("unterminated code block", pos.into()).into());
                        }
                        InvalidNumber { pos, message } => {
                            let pos = (object.clone(), pos, pos);
                            return Err(Parse(message, pos.into()).into());
                        }
                        Unexpected { pos } => {
                            let pos = (object.clone(), pos, pos);
                            return Err(Parse("unexpected input", pos.into()).into());
                        }
                        InvalidVersionReq { start, end } => {
                            let pos = (object.clone(), start, end);
                            return Err(Parse("invalid version requirement", pos.into()).into());
                        }
                    }
                }
                _ => Err("parse error".into()),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use core::*;
    use std::rc::Rc;
    use std::sync::Arc;
    use super::*;
    use super::ast::*;

    fn new_context() -> Rc<Box<Object>> {
        Rc::new(Box::new(
            BytesObject::new(String::from(""), Arc::new(vec![])),
        ))
    }

    /// Check that a parsed value equals expected.
    macro_rules! assert_value_eq {
        ($expected:expr, $input:expr) => {{
            let v = parser::parse_Value(&new_context(), parse($input)).unwrap();
            assert_eq!($expected, v);
        }}
    }

    macro_rules! assert_type_spec_eq {
        ($expected:expr, $input:expr) => {{
            let v = parser::parse_TypeSpec(&new_context(), parse($input)).unwrap();
            assert_eq!($expected, v);
        }}
    }

    const FILE1: &[u8] = include_bytes!("tests/file1.reproto");
    const INTERFACE1: &[u8] = include_bytes!("tests/interface1.reproto");

    fn parse(
        input: &'static str,
    ) -> Box<Iterator<Item = self::token::Result<(usize, token::Token<'static>, usize)>>> {
        Box::new(lexer::lex(input))
    }

    fn parse_file(input: &'static str) -> File {
        parser::parse_File(&new_context(), parse(input)).unwrap()
    }

    fn parse_member(input: &'static str) -> Member {
        parser::parse_Member(&new_context(), parse(input)).unwrap()
    }

    fn parse_type_spec(input: &'static str) -> Type {
        parser::parse_TypeSpec(&new_context(), parse(input)).unwrap()
    }

    #[test]
    fn test_file1() {
        let input = ::std::str::from_utf8(FILE1).unwrap();
        let _ = parse_file(input);
    }

    #[test]
    fn test_array() {
        let ty = parse_type_spec("[string]");

        if let Type::Array { inner } = ty {
            if let Type::String = *inner {
                return;
            }
        }

        panic!("Expected Type::Array(Type::String)");
    }

    #[test]
    fn test_map() {
        let ty = parse_type_spec("{string: unsigned/123}");

        // TODO: use #![feature(box_patterns)]:
        // if let Type::Map(box Type::String, box Type::Unsigned(size)) = ty {
        // }
        if let Type::Map { key, value } = ty {
            if let Type::String = *key {
                if let Type::Unsigned { size } = *value {
                    assert_eq!(Some(123usize), size);
                    return;
                }
            }
        }

        panic!("Expected Type::Array(Type::String)");
    }

    #[test]
    fn test_block_comment() {
        parse("/* hello \n world */");
    }

    #[test]
    fn test_line_comment() {
        parse("// hello world\n");
    }

    #[test]
    fn test_code() {
        parse_member("java{{\na { b { c } d } e\n}}");
    }

    #[test]
    fn test_interface() {
        let input = ::std::str::from_utf8(INTERFACE1).unwrap();
        let file = parse_file(input);
        assert_eq!(1, file.decls.len());
    }

    #[test]
    fn test_strings() {
        assert_value_eq!(Value::String("foo\nbar".to_owned()), "\"foo\\nbar\"");
    }

    #[test]
    fn test_numbers() {
        assert_value_eq!(Value::Number(1.into()), "1");

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: 125.into(),
                decimal: 2,
            }),
            "1.25"
        );

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: 12500.into(),
                decimal: 0,
            }),
            "1.25e4"
        );

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: (-12500).into(),
                decimal: 0,
            }),
            "-1.25e4"
        );

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: (1234).into(),
                decimal: 8,
            }),
            "0.00001234"
        );
    }

    #[test]
    fn test_type_spec() {
        let c = Name::Absolute {
            prefix: None,
            parts: vec!["Hello".to_owned(), "World".to_owned()],
        };

        assert_type_spec_eq!(Type::String, "string");
        assert_type_spec_eq!(Type::Name { name: c }, "Hello::World");
    }

    #[test]
    fn test_option_decl() {
        let member = parse_member("foo_bar_baz true;");

        if let Member::Option(option) = member {
            assert_eq!("foo_bar_baz", option.name);
            assert_eq!(Value::Boolean(true), *option.value.value());
            return;
        }

        panic!("option did not match");
    }
}
<commit_msg>[parser] fix test<commit_after>#![recursion_limit = "1000"]

#[macro_use]
extern crate error_chain;
extern crate lalrpop_util;
extern crate reproto_core as core;
extern crate num;

mod lexer;
mod utils;
pub mod ast;
pub mod errors;
#[allow(unused)]
mod parser;
mod token;

use core::Object;
use self::errors::*;
use std::io::Read;
use std::rc::Rc;

pub fn read_reader<'a, R>(mut reader: R) -> Result<String>
where
    R: AsMut<Read + 'a>,
{
    let mut content = String::new();
    reader.as_mut().read_to_string(&mut content)?;
    Ok(content)
}

pub fn parse_string<'input>(
    object: Rc<Box<Object>>,
    input: &'input str,
) -> Result<ast::File<'input>> {
    use self::ErrorKind::*;
    use lalrpop_util::ParseError::*;
    use self::token::Error::*;

    let lexer = lexer::lex(input);

    match parser::parse_File(&object, lexer) {
        Ok(file) => Ok(file),
        Err(e) => {
            match e {
                InvalidToken { location } => {
                    let pos = (object.clone(), location, location);
                    Err(Syntax(Some(pos.into()), vec![]).into())
                }
                UnrecognizedToken { token, expected } => {
                    let pos = token.map(|(start, _, end)| (object.clone(), start, end));
                    Err(Syntax(pos.map(Into::into), expected).into())
                }
                User { error } => {
                    match error {
                        UnterminatedString { start } => {
                            let pos = (object.clone(), start, start);
                            return Err(Parse("unterminated string", pos.into()).into());
                        }
                        UnterminatedEscape { start } => {
                            let pos = (object.clone(), start, start);
                            return Err(Parse("unterminated escape sequence", pos.into()).into());
                        }
                        InvalidEscape { pos, message } => {
                            let pos = (object.clone(), pos, pos);
                            return Err(Parse(message, pos.into()).into());
                        }
                        UnterminatedCodeBlock { start } => {
                            let pos = (object.clone(), start, start);
                            return Err(Parse("unterminated code block", pos.into()).into());
                        }
                        InvalidNumber { pos, message } => {
                            let pos = (object.clone(), pos, pos);
                            return Err(Parse(message, pos.into()).into());
                        }
                        Unexpected { pos } => {
                            let pos = (object.clone(), pos, pos);
                            return Err(Parse("unexpected input", pos.into()).into());
                        }
                        InvalidVersionReq { start, end } => {
                            let pos = (object.clone(), start, end);
                            return Err(Parse("invalid version requirement", pos.into()).into());
                        }
                    }
                }
                _ => Err("parse error".into()),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use core::*;
    use std::rc::Rc;
    use std::sync::Arc;
    use super::*;
    use super::ast::*;

    fn new_context() -> Rc<Box<Object>> {
        Rc::new(Box::new(
            BytesObject::new(String::from(""), Arc::new(vec![])),
        ))
    }

    /// Check that a parsed value equals expected.
    macro_rules! assert_value_eq {
        ($expected:expr, $input:expr) => {{
            let v = parser::parse_Value(&new_context(), parse($input)).unwrap();
            assert_eq!($expected, v);
        }}
    }

    macro_rules! assert_type_spec_eq {
        ($expected:expr, $input:expr) => {{
            let v = parser::parse_TypeSpec(&new_context(), parse($input)).unwrap();
            assert_eq!($expected, v);
        }}
    }

    const FILE1: &[u8] = include_bytes!("tests/file1.reproto");
    const INTERFACE1: &[u8] = include_bytes!("tests/interface1.reproto");

    fn parse(
        input: &'static str,
    ) -> Box<Iterator<Item = self::token::Result<(usize, token::Token<'static>, usize)>>> {
        Box::new(lexer::lex(input))
    }

    fn parse_file(input: &'static str) -> File {
        parser::parse_File(&new_context(), parse(input)).unwrap()
    }

    fn parse_member(input: &'static str) -> Loc<Member> {
        parser::parse_Member(&new_context(), parse(input)).unwrap()
    }

    fn parse_type_spec(input: &'static str) -> Type {
        parser::parse_TypeSpec(&new_context(), parse(input)).unwrap()
    }

    #[test]
    fn test_file1() {
        let input = ::std::str::from_utf8(FILE1).unwrap();
        let _ = parse_file(input);
    }

    #[test]
    fn test_array() {
        let ty = parse_type_spec("[string]");

        if let Type::Array { inner } = ty {
            if let Type::String = *inner {
                return;
            }
        }

        panic!("Expected Type::Array(Type::String)");
    }

    #[test]
    fn test_map() {
        let ty = parse_type_spec("{string: unsigned/123}");

        // TODO: use #![feature(box_patterns)]:
        // if let Type::Map(box Type::String, box Type::Unsigned(size)) = ty {
        // }
        if let Type::Map { key, value } = ty {
            if let Type::String = *key {
                if let Type::Unsigned { size } = *value {
                    assert_eq!(Some(123usize), size);
                    return;
                }
            }
        }

        panic!("Expected Type::Array(Type::String)");
    }

    #[test]
    fn test_block_comment() {
        parse("/* hello \n world */");
    }

    #[test]
    fn test_line_comment() {
        parse("// hello world\n");
    }

    #[test]
    fn test_code() {
        parse_member("java{{\na { b { c } d } e\n}}");
    }

    #[test]
    fn test_interface() {
        let input = ::std::str::from_utf8(INTERFACE1).unwrap();
        let file = parse_file(input);
        assert_eq!(1, file.decls.len());
    }

    #[test]
    fn test_strings() {
        assert_value_eq!(Value::String("foo\nbar".to_owned()), "\"foo\\nbar\"");
    }

    #[test]
    fn test_numbers() {
        assert_value_eq!(Value::Number(1.into()), "1");

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: 125.into(),
                decimal: 2,
            }),
            "1.25"
        );

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: 12500.into(),
                decimal: 0,
            }),
            "1.25e4"
        );

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: (-12500).into(),
                decimal: 0,
            }),
            "-1.25e4"
        );

        assert_value_eq!(
            Value::Number(RpNumber {
                digits: (1234).into(),
                decimal: 8,
            }),
            "0.00001234"
        );
    }

    #[test]
    fn test_type_spec() {
        let c = Name::Absolute {
            prefix: None,
            parts: vec!["Hello".to_owned(), "World".to_owned()],
        };

        assert_type_spec_eq!(Type::String, "string");
        assert_type_spec_eq!(Type::Name { name: c }, "Hello::World");
    }

    #[test]
    fn test_option_decl() {
        let member = parse_member("foo_bar_baz true;").take();

        if let Member::Option(option) = member {
            assert_eq!("foo_bar_baz", option.name);
            assert_eq!(Value::Boolean(true), *option.value.value());
            return;
        }

        panic!("option did not match");
    }
}
<|endoftext|>


<commit_before>use std::char;

// More details: http://en.wikipedia.org/wiki/UTF-8#Description
pub static UTF8_1BYTE_FOLLOWING: u8 = 0b11000000;
pub static UTF8_2BYTE_FOLLOWING: u8 = 0b11100000;
pub static UTF8_3BYTE_FOLLOWING: u8 = 0b11110000;

pub fn readCodepoint( input: &[u8] ) -> Option< char > {
  fn isContinuationByte( byte: u8 ) -> bool {
    byte & 0b11000000 == 0b10000000
  }

  fn codepointBitsFromLeadingByte( byte: u8 ) -> u32 {
    let good_bits =
      if isAscii( byte ) {
        byte
      } else if byte & 0b11100000 == UTF8_1BYTE_FOLLOWING {
        byte & 0b00011111
      } else if byte & 0b11110000 == UTF8_2BYTE_FOLLOWING {
        byte & 0b00001111
      } else {
        byte & 0b00000111
      };
    good_bits as u32
  }

  fn codepointBitsFromContinuationByte( byte: u8 ) -> u32 {
    ( byte & 0b00111111 ) as u32
  }

  match input.get( 0 ) {
    Some( first_byte ) => {
      match bytesFollowing( *first_byte ) {
        Some( num_following ) => {
          let mut codepoint: u32 =
            codepointBitsFromLeadingByte( *first_byte ) << 6 * num_following;
          for i in range( 1, num_following + 1 ) {
            match input.get( i ) {
              Some( byte ) if isContinuationByte( *byte ) => {
                codepoint |= codepointBitsFromContinuationByte( *byte ) <<
                  6 * ( num_following - i );
              }
              _ => return None
            }
          }
          char::from_u32( codepoint )
        }
        _ => None
      }
    }
    _ => None
  }
}

pub fn bytesFollowing( byte: u8 ) -> Option< uint > {
  if isAscii( byte ) {
    Some( 0 )
  } else if byte & 0b11100000 == UTF8_1BYTE_FOLLOWING {
    Some( 1 )
  } else if byte & 0b11110000 == UTF8_2BYTE_FOLLOWING {
    Some( 2 )
  } else if byte & 0b11111000 == UTF8_3BYTE_FOLLOWING {
    Some( 3 )
  } else {
    None
  }
}

pub fn isAscii( byte: u8 ) -> bool {
  return byte & 0b10000000 == 0;
}

pub fn charToUtf8( input: char ) -> Vec<u8> {
  let utf8chars: &mut [u8] = [0, ..4];
  let num_written = input.encode_utf8( utf8chars );
  let mut out = Vec::new();
  for i in range( 0, num_written ) {
    out.push( *utf8chars.get( i ).unwrap() );
  }
  out
}

#[cfg(test)]
mod tests {
  use super::{readCodepoint, charToUtf8, UTF8_1BYTE_FOLLOWING};

  #[test]
  fn readCodepoint_Roundtrip_SimpleAscii() {
    assert_eq!( 'a', readCodepoint( bytes!( 'a' ) ).unwrap() );
    assert_eq!( 'z', readCodepoint( bytes!( 'z' ) ).unwrap() );
    assert_eq!( 'A', readCodepoint( bytes!( 'A' ) ).unwrap() );
    assert_eq!( '9', readCodepoint( bytes!( '9' ) ).unwrap() );
    assert_eq!( '*', readCodepoint( bytes!( '*' ) ).unwrap() );
    assert_eq!( '\n', readCodepoint( bytes!( '\n' ) ).unwrap() );
    assert_eq!( '\0', readCodepoint( bytes!( '\0' ) ).unwrap() );
  }

  #[test]
  fn readCodepoint_Roundtrip_NonAscii() {
    // 2 UTF-8 bytes
    assert_eq!( '¢', readCodepoint( charToUtf8( '¢' ).as_slice() ).unwrap() );

    // 3 UTF-8 bytes
    assert_eq!( '€', readCodepoint( charToUtf8( '€' ).as_slice() ).unwrap() );

    // 4 UTF-8 bytes
    assert_eq!( '𤭢', readCodepoint( charToUtf8( '𤭢' ).as_slice() ).unwrap() );

    // Some extras
    assert_eq!( 'Ć', readCodepoint( charToUtf8( 'Ć' ).as_slice() ).unwrap() );
    assert_eq!( 'Ө', readCodepoint( charToUtf8( 'Ө' ).as_slice() ).unwrap() );
    assert_eq!( '自', readCodepoint( charToUtf8( '自' ).as_slice() ).unwrap() );
    assert_eq!( '由', readCodepoint( charToUtf8( '由' ).as_slice() ).unwrap() );
  }

  #[test]
  fn readCodepoint_FailsOnBadChars() {
    assert!( readCodepoint( [ 0b11111111 ] ).is_none() );
    assert!( readCodepoint( [ 0b10000000 ] ).is_none() );
    assert!( readCodepoint( [ UTF8_1BYTE_FOLLOWING, 0b11000000 ] ).is_none() );
  }
}
<commit_msg>Refactoring out unnecessary calls to charToUtf8<commit_after>use std::char;

// More details: http://en.wikipedia.org/wiki/UTF-8#Description
pub static UTF8_1BYTE_FOLLOWING: u8 = 0b11000000;
pub static UTF8_2BYTE_FOLLOWING: u8 = 0b11100000;
pub static UTF8_3BYTE_FOLLOWING: u8 = 0b11110000;

pub fn readCodepoint( input: &[u8] ) -> Option< char > {
  fn isContinuationByte( byte: u8 ) -> bool {
    byte & 0b11000000 == 0b10000000
  }

  fn codepointBitsFromLeadingByte( byte: u8 ) -> u32 {
    let good_bits =
      if isAscii( byte ) {
        byte
      } else if byte & 0b11100000 == UTF8_1BYTE_FOLLOWING {
        byte & 0b00011111
      } else if byte & 0b11110000 == UTF8_2BYTE_FOLLOWING {
        byte & 0b00001111
      } else {
        byte & 0b00000111
      };
    good_bits as u32
  }

  fn codepointBitsFromContinuationByte( byte: u8 ) -> u32 {
    ( byte & 0b00111111 ) as u32
  }

  match input.get( 0 ) {
    Some( first_byte ) => {
      match bytesFollowing( *first_byte ) {
        Some( num_following ) => {
          let mut codepoint: u32 =
            codepointBitsFromLeadingByte( *first_byte ) << 6 * num_following;
          for i in range( 1, num_following + 1 ) {
            match input.get( i ) {
              Some( byte ) if isContinuationByte( *byte ) => {
                codepoint |= codepointBitsFromContinuationByte( *byte ) <<
                  6 * ( num_following - i );
              }
              _ => return None
            }
          }
          char::from_u32( codepoint )
        }
        _ => None
      }
    }
    _ => None
  }
}

pub fn bytesFollowing( byte: u8 ) -> Option< uint > {
  if isAscii( byte ) {
    Some( 0 )
  } else if byte & 0b11100000 == UTF8_1BYTE_FOLLOWING {
    Some( 1 )
  } else if byte & 0b11110000 == UTF8_2BYTE_FOLLOWING {
    Some( 2 )
  } else if byte & 0b11111000 == UTF8_3BYTE_FOLLOWING {
    Some( 3 )
  } else {
    None
  }
}

pub fn isAscii( byte: u8 ) -> bool {
  return byte & 0b10000000 == 0;
}

// TODO: delete? Not used anymore, but might be useful in the future.
pub fn charToUtf8( input: char ) -> Vec<u8> {
  let utf8chars: &mut [u8] = [0, ..4];
  let num_written = input.encode_utf8( utf8chars );
  let mut out = Vec::new();
  for i in range( 0, num_written ) {
    out.push( *utf8chars.get( i ).unwrap() );
  }
  out
}

#[cfg(test)]
mod tests {
  use super::{readCodepoint, UTF8_1BYTE_FOLLOWING};

  #[test]
  fn readCodepoint_Roundtrip_SimpleAscii() {
    assert_eq!( 'a', readCodepoint( bytes!( 'a' ) ).unwrap() );
    assert_eq!( 'z', readCodepoint( bytes!( 'z' ) ).unwrap() );
    assert_eq!( 'A', readCodepoint( bytes!( 'A' ) ).unwrap() );
    assert_eq!( '9', readCodepoint( bytes!( '9' ) ).unwrap() );
    assert_eq!( '*', readCodepoint( bytes!( '*' ) ).unwrap() );
    assert_eq!( '\n', readCodepoint( bytes!( '\n' ) ).unwrap() );
    assert_eq!( '\0', readCodepoint( bytes!( '\0' ) ).unwrap() );
  }

  #[test]
  fn readCodepoint_Roundtrip_NonAscii() {
    // 2 UTF-8 bytes
    assert_eq!( '¢', readCodepoint( "¢".as_bytes() ).unwrap() );

    // 3 UTF-8 bytes
    assert_eq!( '€', readCodepoint( "€".as_bytes() ).unwrap() );

    // 4 UTF-8 bytes
    assert_eq!( '𤭢', readCodepoint( "𤭢".as_bytes() ).unwrap() );

    // Some extras
    assert_eq!( 'Ć', readCodepoint( "Ć".as_bytes() ).unwrap() );
    assert_eq!( 'Ө', readCodepoint( "Ө".as_bytes() ).unwrap() );
    assert_eq!( '自', readCodepoint( "自".as_bytes() ).unwrap() );
    assert_eq!( '由', readCodepoint( "由".as_bytes() ).unwrap() );
  }

  #[test]
  fn readCodepoint_FailsOnBadChars() {
    assert!( readCodepoint( [ 0b11111111 ] ).is_none() );
    assert!( readCodepoint( [ 0b10000000 ] ).is_none() );
    assert!( readCodepoint( [ UTF8_1BYTE_FOLLOWING, 0b11000000 ] ).is_none() );
  }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use support::{database, project};

#[test]
fn run_infer_schema_without_docs() {
    test_print_schema("print_schema_simple_without_docs", vec![]);
}

#[test]
fn run_infer_schema() {
    test_print_schema("print_schema_simple", vec!["--with-docs"]);
}

#[test]
fn run_infer_schema_include() {
    test_print_schema(
        "print_schema_only_tables",
        vec!["--with-docs", "-w", "users1"],
    );
}

#[test]
fn run_infer_schema_exclude() {
    test_print_schema(
        "print_schema_except_tables",
        vec!["--with-docs", "-b", "users1"],
    );
}

#[test]
fn run_infer_schema_order() {
    test_print_schema("print_schema_order", vec!["--with-docs"]);
}

#[test]
fn run_infer_schema_compound_primary_key() {
    test_print_schema("print_schema_compound_primary_key", vec!["--with-docs"]);
}

#[test]
#[cfg(feature = "postgres")]
fn print_schema_specifying_schema_name() {
    test_print_schema(
        "print_schema_specifying_schema_name",
        vec!["--with-docs", "--schema", "custom_schema"],
    )
}

#[test]
#[cfg(feature = "postgres")]
fn print_schema_specifying_schema_name_with_foreign_keys() {
    test_print_schema(
        "print_schema_specifying_schema_name_with_foreign_keys",
        vec!["--with-docs", "--schema", "custom_schema"],
    )
}

#[test]
#[cfg(feature = "postgres")]
fn print_schema_with_foreign_keys() {
    test_print_schema("print_schema_with_foreign_keys", vec!["--with-docs"]);
}

#[test]
fn print_schema_column_renaming() {
    test_print_schema("print_schema_column_renaming", vec!["--with-docs"]);
}

#[test]
#[cfg(feature = "mysql")]
fn print_schema_unsigned() {
    test_print_schema("print_schema_unsigned", vec!["--with-docs"]);
}

#[test]
fn print_schema_patch_file() {
    let path_to_patch_file = backend_file_path("print_schema_patch_file", "schema.patch");
    let path = path_to_patch_file.display().to_string();
    test_print_schema("print_schema_patch_file", vec!["--patch-file", &path]);
}

#[test]
fn print_schema_custom_types() {
    test_print_schema(
        "print_schema_custom_types",
        vec!["--import-types", "foo::*", "--import-types", "bar::*"],
    );
}

#[cfg(feature = "sqlite")]
const BACKEND: &str = "sqlite";
#[cfg(feature = "postgres")]
const BACKEND: &str = "postgres";
#[cfg(feature = "mysql")]
const BACKEND: &str = "mysql";

fn backend_file_path(test_name: &str, file: &str) -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("print_schema")
        .join(test_name)
        .join(BACKEND)
        .join(file)
}

fn test_print_schema(test_name: &str, args: Vec<&str>) {
    let test_path = Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("print_schema")
        .join(test_name);
    let p = project(test_name).build();
    let db = database(&p.database_url());

    p.command("setup").run();

    let schema = read_file(&backend_file_path(test_name, "schema.sql"));
    db.execute(&schema);

    let result = p.command("print-schema").args(args).run();

    assert!(result.is_success(), "Result was unsuccessful {:?}", result);
    let expected = read_file(&backend_file_path(test_name, "expected.rs"));

    assert_diff!(&expected, result.stdout(), "\n", 0);

    test_print_schema_config(test_name, &test_path, schema, expected);
}

fn test_print_schema_config(test_name: &str, test_path: &Path, schema: String, expected: String) {
    let config = read_file(&test_path.join("diesel.toml"));
    let mut p = project(&format!("{}_config", test_name)).file("diesel.toml", &config);

    let patch_file = backend_file_path(test_name, "schema.patch");
    if patch_file.exists() {
        let patch_contents = read_file(&patch_file);
        p = p.file("schema.patch", &patch_contents);
    }

    let p = p.build();

    p.command("setup").run();
    p.create_migration("12345_create_schema", &schema, "");

    let result = p.command("migration").arg("run").run();
    assert!(result.is_success(), "Result was unsuccessful {:?}", result);

    let schema = p.file_contents("src/schema.rs");
    assert_diff!(&expected, &schema, "\n", 0);

    let result = p.command("print-schema").run();
    assert!(result.is_success(), "Result was unsuccessful {:?}", result);

    assert_diff!(&expected, result.stdout(), "\n", 0);
}

fn read_file(path: &Path) -> String {
    let mut file = File::open(path).expect(&format!("Could not open {}", path.display()));
    let mut string = String::new();
    file.read_to_string(&mut string).unwrap();
    string
}
<commit_msg>Try to fix infer-schema tests on windows<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

use support::{database, project};

#[cfg(not(windows))]
const NEW_LINE: &'static str = "\n";

#[cfg(windows)]
const NEW_LINE: &'static str = "\n";

#[test]
fn run_infer_schema_without_docs() {
    test_print_schema("print_schema_simple_without_docs", vec![]);
}

#[test]
fn run_infer_schema() {
    test_print_schema("print_schema_simple", vec!["--with-docs"]);
}

#[test]
fn run_infer_schema_include() {
    test_print_schema(
        "print_schema_only_tables",
        vec!["--with-docs", "-w", "users1"],
    );
}

#[test]
fn run_infer_schema_exclude() {
    test_print_schema(
        "print_schema_except_tables",
        vec!["--with-docs", "-b", "users1"],
    );
}

#[test]
fn run_infer_schema_order() {
    test_print_schema("print_schema_order", vec!["--with-docs"]);
}

#[test]
fn run_infer_schema_compound_primary_key() {
    test_print_schema("print_schema_compound_primary_key", vec!["--with-docs"]);
}

#[test]
#[cfg(feature = "postgres")]
fn print_schema_specifying_schema_name() {
    test_print_schema(
        "print_schema_specifying_schema_name",
        vec!["--with-docs", "--schema", "custom_schema"],
    )
}

#[test]
#[cfg(feature = "postgres")]
fn print_schema_specifying_schema_name_with_foreign_keys() {
    test_print_schema(
        "print_schema_specifying_schema_name_with_foreign_keys",
        vec!["--with-docs", "--schema", "custom_schema"],
    )
}

#[test]
#[cfg(feature = "postgres")]
fn print_schema_with_foreign_keys() {
    test_print_schema("print_schema_with_foreign_keys", vec!["--with-docs"]);
}

#[test]
fn print_schema_column_renaming() {
    test_print_schema("print_schema_column_renaming", vec!["--with-docs"]);
}

#[test]
#[cfg(feature = "mysql")]
fn print_schema_unsigned() {
    test_print_schema("print_schema_unsigned", vec!["--with-docs"]);
}

#[test]
fn print_schema_patch_file() {
    let path_to_patch_file = backend_file_path("print_schema_patch_file", "schema.patch");
    let path = path_to_patch_file.display().to_string();
    test_print_schema("print_schema_patch_file", vec!["--patch-file", &path]);
}

#[test]
fn print_schema_custom_types() {
    test_print_schema(
        "print_schema_custom_types",
        vec!["--import-types", "foo::*", "--import-types", "bar::*"],
    );
}

#[cfg(feature = "sqlite")]
const BACKEND: &str = "sqlite";
#[cfg(feature = "postgres")]
const BACKEND: &str = "postgres";
#[cfg(feature = "mysql")]
const BACKEND: &str = "mysql";

fn backend_file_path(test_name: &str, file: &str) -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("print_schema")
        .join(test_name)
        .join(BACKEND)
        .join(file)
}

fn test_print_schema(test_name: &str, args: Vec<&str>) {
    let test_path = Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("print_schema")
        .join(test_name);
    let p = project(test_name).build();
    let db = database(&p.database_url());

    p.command("setup").run();

    let schema = read_file(&backend_file_path(test_name, "schema.sql"));
    db.execute(&schema);

    let result = p.command("print-schema").args(args).run();

    assert!(result.is_success(), "Result was unsuccessful {:?}", result);
    let expected = read_file(&backend_file_path(test_name, "expected.rs"));

    assert_diff!(&expected, result.stdout(), NEW_LINE, 0);

    test_print_schema_config(test_name, &test_path, schema, expected);
}

fn test_print_schema_config(test_name: &str, test_path: &Path, schema: String, expected: String) {
    let config = read_file(&test_path.join("diesel.toml"));
    let mut p = project(&format!("{}_config", test_name)).file("diesel.toml", &config);

    let patch_file = backend_file_path(test_name, "schema.patch");
    if patch_file.exists() {
        let patch_contents = read_file(&patch_file);
        p = p.file("schema.patch", &patch_contents);
    }

    let p = p.build();

    p.command("setup").run();
    p.create_migration("12345_create_schema", &schema, "");

    let result = p.command("migration").arg("run").run();
    assert!(result.is_success(), "Result was unsuccessful {:?}", result);

    let schema = p.file_contents("src/schema.rs");
    assert_diff!(&expected, &schema, NEW_LINE, 0);

    let result = p.command("print-schema").run();
    assert!(result.is_success(), "Result was unsuccessful {:?}", result);

    assert_diff!(&expected, result.stdout(), NEW_LINE, 0);
}

fn read_file(path: &Path) -> String {
    let mut file = File::open(path).expect(&format!("Could not open {}", path.display()));
    let mut string = String::new();
    file.read_to_string(&mut string).unwrap();
    string
}
<|endoftext|>


<commit_before>#![crate_id(name="uutils", vers="1.0.0", author="Michael Gehring")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate collections;
extern crate getopts;

extern crate base64;
extern crate basename;
extern crate cat;
extern crate cksum;
extern crate comm;
extern crate cp;
extern crate dirname;
extern crate du;
extern crate echo;
extern crate env;
extern crate fold;
extern crate groups;
extern crate head;
extern crate hostid;
extern crate hostname;
extern crate id;
extern crate kill;
extern crate logname;
extern crate mkdir;
extern crate paste;
extern crate printenv;
extern crate pwd;
extern crate rm;
extern crate rmdir;
extern crate seq;
extern crate sleep;
extern crate sum;
extern crate tac;
extern crate tee;
extern crate touch;
extern crate tr;
extern crate truncate;
extern crate tty;
extern crate uname;
extern crate unlink;
extern crate uptime;
extern crate users;
extern crate wc;
extern crate whoami;
extern crate yes;

use std::os;
use collections::hashmap::HashMap;

static NAME: &'static str = "uutils";
static VERSION: &'static str = "1.0.0";

fn util_map() -> HashMap<&str, fn(Vec<String>)> {
    fn uutrue(_: Vec<String>) { os::set_exit_status(0); }
    fn uufalse(_: Vec<String>) { os::set_exit_status(1); }

    let mut map = HashMap::new();
    map.insert("base64", base64::uumain);
    map.insert("basename", basename::uumain);
    map.insert("cat", cat::uumain);
    map.insert("cksum", cksum::uumain);
    map.insert("comm", comm::uumain);
    map.insert("cp", cp::uumain);
    map.insert("dirname", dirname::uumain);
    map.insert("du", du::uumain);
    map.insert("echo", echo::uumain);
    map.insert("env", env::uumain);
    map.insert("false", uufalse);
    map.insert("fold", fold::uumain);
    map.insert("groups", groups::uumain);
    map.insert("head", head::uumain);
    map.insert("hostid", hostid::uumain);
    map.insert("hostname", hostname::uumain);
    map.insert("id", id::uumain);
    map.insert("kill", kill::uumain);
    map.insert("logname", logname::uumain);
    map.insert("mkdir", mkdir::uumain);
    map.insert("paste", paste::uumain);
    map.insert("printenv", printenv::uumain);
    map.insert("pwd", pwd::uumain);
    map.insert("rm", rm::uumain);
    map.insert("rmdir", rmdir::uumain);
    map.insert("seq", seq::uumain);
    map.insert("sleep", sleep::uumain);
    map.insert("sum", sum::uumain);
    map.insert("tac", tac::uumain);
    map.insert("tee", tee::uumain);
    map.insert("touch", touch::uumain);
    map.insert("tr", tr::uumain);
    map.insert("true", uutrue);
    map.insert("truncate", truncate::uumain);
    map.insert("tty", tty::uumain);
    map.insert("uname", uname::uumain);
    map.insert("unlink", unlink::uumain);
    map.insert("uptime", uptime::uumain);
    map.insert("users", users::uumain);
    map.insert("wc", wc::uumain);
    map.insert("whoami", whoami::uumain);
    map.insert("yes", yes::uumain);
    map
}

fn usage(cmap: &HashMap<&str, fn(Vec<String>)>) {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [util [arguments...]", NAME);
        println!("Utils:");
        let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
        utils.sort();
        for util in utils.iter() {
            println!("\t{}", util);
        }
}

fn main() {
    let umap = util_map();
    let mut args = os::args();

    // try binary name as util name.
    let binary = Path::new(args.get(0).as_slice());
    let util = binary.filename_str().unwrap();
    if umap.contains_key(&util) {
        let &uumain = umap.get(&util);
        uumain(args);
        return
    }

    // try first arg as util name.
    if args.len() >= 2 {
        args.shift();
        let util = args.get(0).as_slice().clone();
        if umap.contains_key(&util) {
            let &uumain = umap.get(&util);
            uumain(args.clone());
            return
        }
    }

    usage(&umap);
    os::set_exit_status(1);
}
<commit_msg>Output list of uutils functions in a way that busybox's 'runtest' understands<commit_after>#![crate_id(name="uutils", vers="1.0.0", author="Michael Gehring")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate collections;
extern crate getopts;

extern crate base64;
extern crate basename;
extern crate cat;
extern crate cksum;
extern crate comm;
extern crate cp;
extern crate dirname;
extern crate du;
extern crate echo;
extern crate env;
extern crate fold;
extern crate groups;
extern crate head;
extern crate hostid;
extern crate hostname;
extern crate id;
extern crate kill;
extern crate logname;
extern crate mkdir;
extern crate paste;
extern crate printenv;
extern crate pwd;
extern crate rm;
extern crate rmdir;
extern crate seq;
extern crate sleep;
extern crate sum;
extern crate tac;
extern crate tee;
extern crate touch;
extern crate tr;
extern crate truncate;
extern crate tty;
extern crate uname;
extern crate unlink;
extern crate uptime;
extern crate users;
extern crate wc;
extern crate whoami;
extern crate yes;

use std::os;
use collections::hashmap::HashMap;

static NAME: &'static str = "uutils";
static VERSION: &'static str = "1.0.0";

fn util_map() -> HashMap<&str, fn(Vec<String>)> {
    fn uutrue(_: Vec<String>) { os::set_exit_status(0); }
    fn uufalse(_: Vec<String>) { os::set_exit_status(1); }

    let mut map = HashMap::new();
    map.insert("base64", base64::uumain);
    map.insert("basename", basename::uumain);
    map.insert("cat", cat::uumain);
    map.insert("cksum", cksum::uumain);
    map.insert("comm", comm::uumain);
    map.insert("cp", cp::uumain);
    map.insert("dirname", dirname::uumain);
    map.insert("du", du::uumain);
    map.insert("echo", echo::uumain);
    map.insert("env", env::uumain);
    map.insert("false", uufalse);
    map.insert("fold", fold::uumain);
    map.insert("groups", groups::uumain);
    map.insert("head", head::uumain);
    map.insert("hostid", hostid::uumain);
    map.insert("hostname", hostname::uumain);
    map.insert("id", id::uumain);
    map.insert("kill", kill::uumain);
    map.insert("logname", logname::uumain);
    map.insert("mkdir", mkdir::uumain);
    map.insert("paste", paste::uumain);
    map.insert("printenv", printenv::uumain);
    map.insert("pwd", pwd::uumain);
    map.insert("rm", rm::uumain);
    map.insert("rmdir", rmdir::uumain);
    map.insert("seq", seq::uumain);
    map.insert("sleep", sleep::uumain);
    map.insert("sum", sum::uumain);
    map.insert("tac", tac::uumain);
    map.insert("tee", tee::uumain);
    map.insert("touch", touch::uumain);
    map.insert("tr", tr::uumain);
    map.insert("true", uutrue);
    map.insert("truncate", truncate::uumain);
    map.insert("tty", tty::uumain);
    map.insert("uname", uname::uumain);
    map.insert("unlink", unlink::uumain);
    map.insert("uptime", uptime::uumain);
    map.insert("users", users::uumain);
    map.insert("wc", wc::uumain);
    map.insert("whoami", whoami::uumain);
    map.insert("yes", yes::uumain);
    map
}

fn usage(cmap: &HashMap<&str, fn(Vec<String>)>) {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [util [arguments...]", NAME);
        println!("Currently defined functions:");
        let mut utils: Vec<&str> = cmap.keys().map(|&s| s).collect();
        utils.sort();
        for util in utils.iter() {
            println!("\t{}", util);
        }
}

fn main() {
    let umap = util_map();
    let mut args = os::args();

    // try binary name as util name.
    let binary = Path::new(args.get(0).as_slice());
    let util = binary.filename_str().unwrap();
    if umap.contains_key(&util) {
        let &uumain = umap.get(&util);
        uumain(args);
        return
    }

    // try first arg as util name.
    if args.len() >= 2 {
        args.shift();
        let util = args.get(0).as_slice().clone();
        if umap.contains_key(&util) {
            let &uumain = umap.get(&util);
            uumain(args.clone());
            return
        }
    }

    usage(&umap);
    os::set_exit_status(1);
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#![crate_name="calculator"]
#![crate_type="bin"]

extern crate thrift;

use std::str::FromStr;
use std::net;
use std::io::BufStream;
use thrift::protocol::binary_protocol::BinaryProtocol;

mod tutorial;
mod shared;

fn run_client(client: &mut tutorial::CalculatorClient) {
    // Ping
    client.ping().ok().unwrap();
    println!("ping()");

    // Add
    println!("1 + 1 = {}", client.add(1, 1).ok().unwrap());

    // Work: divide
    let work = tutorial::Work {
      op: tutorial::Operation::DIVIDE,
      num1: 1,
      num2: 0,
      comment: None };

    match client.calculate(1, work) {
      Ok(_) => {
        println!("Whoa? We can divide by zero!");
      }
      Err(_) => {
        // FIXME: use thrift exceptions
        println!("Invalid operation")
      }
    }

    // Work: subtract
    let work = tutorial::Work {
        op: tutorial::Operation::SUBTRACT,
        num1: 15,
        num2: 10,
        comment: None };
    println!("15 - 10 = {}", client.calculate(2, work).ok().unwrap());

    let ss = client.getStruct(1).ok().unwrap();
    println!("Received log: {}", ss.value);

    println!("PASS");
}

pub fn main() {
    let addr: net::SocketAddr = FromStr::from_str("127.0.0.1:9090").ok()
        .expect("bad server address");
    let tcp = net::TcpStream::connect(addr).ok()
        .expect("failed to connect");
    let stream = BufStream::new(tcp);
    // FIXME: do we want tutorial::build_calculator_client(BinaryProtocol, tcp) here?
    let mut client = tutorial::CalculatorClientImpl::new(BinaryProtocol, stream);

    run_client(&mut client);
}
<commit_msg>Fix tutorial demo<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#![crate_name="calculator"]
#![crate_type="bin"]

extern crate thrift;

use std::str::FromStr;
use std::net;
use std::io::BufStream;
use thrift::protocol::binary_protocol::BinaryProtocol;

mod tutorial;
mod shared;

fn run_client(client: &mut tutorial::CalculatorClient) {
    // Ping
    client.ping().ok().unwrap();
    println!("ping()");

    // Add
    println!("1 + 1 = {}", client.add(1, 1).ok().unwrap());

    // Work: divide
    let work = tutorial::Work {
      op: tutorial::Operation::DIVIDE,
      num1: 1,
      num2: 0,
      comment: None };

    match client.calculate(1, work) {
      Ok(_) => {
        println!("Whoa? We can divide by zero!");
      }
      Err(_) => {
        // FIXME: use thrift exceptions
        println!("Invalid operation")
      }
    }

    // Work: subtract
    let work = tutorial::Work {
        op: tutorial::Operation::SUBTRACT,
        num1: 15,
        num2: 10,
        comment: None };
    println!("15 - 10 = {}", client.calculate(1, work).ok().unwrap());

    let ss = client.getStruct(1).ok().unwrap();
    println!("Received log: {}", ss.value);

    println!("PASS");
}

pub fn main() {
    let addr: net::SocketAddr = FromStr::from_str("127.0.0.1:9090").ok()
        .expect("bad server address");
    let tcp = net::TcpStream::connect(addr).ok()
        .expect("failed to connect");
    let stream = BufStream::new(tcp);
    // FIXME: do we want tutorial::build_calculator_client(BinaryProtocol, tcp) here?
    let mut client = tutorial::CalculatorClientImpl::new(BinaryProtocol, stream);

    run_client(&mut client);
}
<|endoftext|>


<commit_before>use std::io::Error as IoError;
use std::io::Read;

pub use parse::ParseError;

mod enums;
mod parse;

pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
    where R: Read
{
    let mut data = Vec::new();
    try!(spirv.read_to_end(&mut data));

    // now parsing the document
    let doc = try!(parse::parse_spirv(&data));

    let mut output = String::new();

    {
        // contains the data that was passed as input to this function
        let spirv_data = data.iter().map(|&byte| byte.to_string())
                             .collect::<Vec<String>>()
                             .join(", ");

        // writing the header
        output.push_str(&format!(r#"
pub struct {name} {{
    shader: ::std::sync::Arc<::vulkano::shader::ShaderModule>,
}}

impl {name} {{
    /// Loads the shader in Vulkan as a `ShaderModule`.
    #[inline]
    pub fn load(device: &::std::sync::Arc<::vulkano::Device>) -> {name} {{

        "#, name = name));

        // checking whether each required capability is supported by the vulkan implementation
        for i in doc.instructions.iter() {
            if let &parse::Instruction::Capability(ref cap) = i {
                output.push_str(&format!(r#"
                    if !device.is_capability_supported("{cap}") {{
                        return Err(CapabilityNotSupported);
                    }}"#, cap = capability_name(cap)));
            }
        }

        // follow-up of the header
        output.push_str(&format!(r#"
        unsafe {{
            let data = [{spirv_data}];

            {name} {{
                shader: ::vulkano::shader::ShaderModule::new(device, &data)
            }}
        }}
    }}

    /// Returns the module that was created.
    #[inline]
    pub fn module(&self) -> &::std::sync::Arc<::vulkano::shader::ShaderModule> {{
        &self.shader
    }}
        "#, name = name, spirv_data = spirv_data));

        // writing one method for each entry point of this module
        for instruction in doc.instructions.iter() {
            if let &parse::Instruction::EntryPoint { .. } = instruction {
                output.push_str(&write_entry_point(&doc, instruction));
            }
        }

        // footer
        output.push_str(&format!(r#"
}}
        "#));
    }

    // TODO: remove
    println!("{:#?}", doc);

    Ok(output)
}

#[derive(Debug)]
pub enum Error {
    IoError(IoError),
    ParseError(ParseError),
}

impl From<IoError> for Error {
    #[inline]
    fn from(err: IoError) -> Error {
        Error::IoError(err)
    }
}

impl From<ParseError> for Error {
    #[inline]
    fn from(err: ParseError) -> Error {
        Error::ParseError(err)
    }
}

fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
    let (execution, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
            (execution, name, interface)
        },
        _ => unreachable!()
    };

    let ty = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            format!("::vulkano::shader::VertexShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            format!("::vulkano::shader::TessControlShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            format!("::vulkano::shader::TessEvaluationShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            format!("::vulkano::shader::GeometryShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let mut output_types = Vec::new();

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassOutput, .. }
                                    if &result_id == interface =>
                        {
                            output_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            format!("::vulkano::shader::FragmentShaderEntryPoint<({output})>",
                    output = output_types.join(", ") + ",")
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            format!("::vulkano::shader::ComputeShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    format!(r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        self.shader.entry_point("{ep_name}")
    }}
            "#, ep_name = ep_name, ty = ty)
}

fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeVoid { result_id } if result_id == searched => {
                return "()".to_owned()
            },
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return "bool".to_owned()
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                return "i32".to_owned()
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                return "f32".to_owned()
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                let t = type_from_id(doc, component_id);
                return format!("[{}; {}]", t, count);
            },
            &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, depth, arrayed, ms, sampled, ref format, ref access } if result_id == searched => {
                return format!("{}{}Texture{:?}{}{:?}",
                    if ms { "Multisample" } else { "" },
                    if depth == Some(true) { "Depth" } else { "" },
                    dim,
                    if arrayed { "Array" } else { "" },
                    format);
            },
            &parse::Instruction::TypeSampledImage { result_id, image_type_id } if result_id == searched => {
                return type_from_id(doc, image_type_id);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                let len = doc.instructions.iter().filter_map(|e| {
                    match e { &parse::Instruction::Constant { result_id, ref data, .. } if result_id == length_id => Some(data.clone()), _ => None }
                }).next().expect("failed to find array length");
                let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
                return format!("[{}; {}]", t, len);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                return format!("[{}]", t);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = name_from_id(doc, result_id);
                let members = member_types.iter().enumerate().map(|(offset, &member)| {
                    let ty = type_from_id(doc, member);
                    let name = member_name_from_id(doc, result_id, offset as u32);
                    format!("\t{}: {}", name, ty)
                }).collect::<Vec<_>>();
                return format!("struct {} {{\n{}\n}}", name, members.join(",\n"));
            },
            &parse::Instruction::TypeOpaque { result_id, ref name } if result_id == searched => {
                return "<opaque>".to_owned();
            },
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == searched => {
                return type_from_id(doc, type_id);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}

fn name_from_id(doc: &parse::Spirv, searched: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::Name { target_id, ref name } = i {
            if target_id == searched {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::MemberName { target_id, member, ref name } = i {
            if target_id == searched && member == searched_member {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

// TODO: this function is a draft, as the actual names may not be the same
fn capability_name(cap: &enums::Capability) -> &'static str {
    match *cap {
        enums::Capability::CapabilityMatrix => "Matrix",
        enums::Capability::CapabilityShader => "Shader",
        enums::Capability::CapabilityGeometry => "Geometry",
        enums::Capability::CapabilityTessellation => "Tessellation",
        enums::Capability::CapabilityAddresses => "Addresses",
        enums::Capability::CapabilityLinkage => "Linkage",
        enums::Capability::CapabilityKernel => "Kernel",
        enums::Capability::CapabilityVector16 => "Vector16",
        enums::Capability::CapabilityFloat16Buffer => "Float16Buffer",
        enums::Capability::CapabilityFloat16 => "Float16",
        enums::Capability::CapabilityFloat64 => "Float64",
        enums::Capability::CapabilityInt64 => "Int64",
        enums::Capability::CapabilityInt64Atomics => "Int64Atomics",
        enums::Capability::CapabilityImageBasic => "ImageBasic",
        enums::Capability::CapabilityImageReadWrite => "ImageReadWrite",
        enums::Capability::CapabilityImageMipmap => "ImageMipmap",
        enums::Capability::CapabilityPipes => "Pipes",
        enums::Capability::CapabilityGroups => "Groups",
        enums::Capability::CapabilityDeviceEnqueue => "DeviceEnqueue",
        enums::Capability::CapabilityLiteralSampler => "LiteralSampler",
        enums::Capability::CapabilityAtomicStorage => "AtomicStorage",
        enums::Capability::CapabilityInt16 => "Int16",
        enums::Capability::CapabilityTessellationPointSize => "TessellationPointSize",
        enums::Capability::CapabilityGeometryPointSize => "GeometryPointSize",
        enums::Capability::CapabilityImageGatherExtended => "ImageGatherExtended",
        enums::Capability::CapabilityStorageImageMultisample => "StorageImageMultisample",
        enums::Capability::CapabilityUniformBufferArrayDynamicIndexing => "UniformBufferArrayDynamicIndexing",
        enums::Capability::CapabilitySampledImageArrayDynamicIndexing => "SampledImageArrayDynamicIndexing",
        enums::Capability::CapabilityStorageBufferArrayDynamicIndexing => "StorageBufferArrayDynamicIndexing",
        enums::Capability::CapabilityStorageImageArrayDynamicIndexing => "StorageImageArrayDynamicIndexing",
        enums::Capability::CapabilityClipDistance => "ClipDistance",
        enums::Capability::CapabilityCullDistance => "CullDistance",
        enums::Capability::CapabilityImageCubeArray => "ImageCubeArray",
        enums::Capability::CapabilitySampleRateShading => "SampleRateShading",
        enums::Capability::CapabilityImageRect => "ImageRect",
        enums::Capability::CapabilitySampledRect => "SampledRect",
        enums::Capability::CapabilityGenericPointer => "GenericPointer",
        enums::Capability::CapabilityInt8 => "Int8",
        enums::Capability::CapabilityInputAttachment => "InputAttachment",
        enums::Capability::CapabilitySparseResidency => "SparseResidency",
        enums::Capability::CapabilityMinLod => "MinLod",
        enums::Capability::CapabilitySampled1D => "Sampled1D",
        enums::Capability::CapabilityImage1D => "Image1D",
        enums::Capability::CapabilitySampledCubeArray => "SampledCubeArray",
        enums::Capability::CapabilitySampledBuffer => "SampledBuffer",
        enums::Capability::CapabilityImageBuffer => "ImageBuffer",
        enums::Capability::CapabilityImageMSArray => "ImageMSArray",
        enums::Capability::CapabilityStorageImageExtendedFormats => "StorageImageExtendedFormats",
        enums::Capability::CapabilityImageQuery => "ImageQuery",
        enums::Capability::CapabilityDerivativeControl => "DerivativeControl",
        enums::Capability::CapabilityInterpolationFunction => "InterpolationFunction",
        enums::Capability::CapabilityTransformFeedback => "TransformFeedback",
        enums::Capability::CapabilityGeometryStreams => "GeometryStreams",
        enums::Capability::CapabilityStorageImageReadWithoutFormat => "StorageImageReadWithoutFormat",
        enums::Capability::CapabilityStorageImageWriteWithoutFormat => "StorageImageWriteWithoutFormat",
    }
}
<commit_msg>Pass identifiers as CStrs<commit_after>use std::io::Error as IoError;
use std::io::Read;

pub use parse::ParseError;

mod enums;
mod parse;

pub fn reflect<R>(name: &str, mut spirv: R) -> Result<String, Error>
    where R: Read
{
    let mut data = Vec::new();
    try!(spirv.read_to_end(&mut data));

    // now parsing the document
    let doc = try!(parse::parse_spirv(&data));

    let mut output = String::new();

    {
        // contains the data that was passed as input to this function
        let spirv_data = data.iter().map(|&byte| byte.to_string())
                             .collect::<Vec<String>>()
                             .join(", ");

        // writing the header
        output.push_str(&format!(r#"
pub struct {name} {{
    shader: ::std::sync::Arc<::vulkano::shader::ShaderModule>,
}}

impl {name} {{
    /// Loads the shader in Vulkan as a `ShaderModule`.
    #[inline]
    pub fn load(device: &::std::sync::Arc<::vulkano::Device>) -> {name} {{

        "#, name = name));

        // checking whether each required capability is supported by the vulkan implementation
        for i in doc.instructions.iter() {
            if let &parse::Instruction::Capability(ref cap) = i {
                output.push_str(&format!(r#"
                    if !device.is_capability_supported("{cap}") {{
                        return Err(CapabilityNotSupported);
                    }}"#, cap = capability_name(cap)));
            }
        }

        // follow-up of the header
        output.push_str(&format!(r#"
        unsafe {{
            let data = [{spirv_data}];

            {name} {{
                shader: ::vulkano::shader::ShaderModule::new(device, &data)
            }}
        }}
    }}

    /// Returns the module that was created.
    #[inline]
    pub fn module(&self) -> &::std::sync::Arc<::vulkano::shader::ShaderModule> {{
        &self.shader
    }}
        "#, name = name, spirv_data = spirv_data));

        // writing one method for each entry point of this module
        for instruction in doc.instructions.iter() {
            if let &parse::Instruction::EntryPoint { .. } = instruction {
                output.push_str(&write_entry_point(&doc, instruction));
            }
        }

        // footer
        output.push_str(&format!(r#"
}}
        "#));
    }

    // TODO: remove
    println!("{:#?}", doc);

    Ok(output)
}

#[derive(Debug)]
pub enum Error {
    IoError(IoError),
    ParseError(ParseError),
}

impl From<IoError> for Error {
    #[inline]
    fn from(err: IoError) -> Error {
        Error::IoError(err)
    }
}

impl From<ParseError> for Error {
    #[inline]
    fn from(err: ParseError) -> Error {
        Error::ParseError(err)
    }
}

fn write_entry_point(doc: &parse::Spirv, instruction: &parse::Instruction) -> String {
    let (execution, ep_name, interface) = match instruction {
        &parse::Instruction::EntryPoint { ref execution, id, ref name, ref interface } => {
            (execution, name, interface)
        },
        _ => unreachable!()
    };

    let ty = match *execution {
        enums::ExecutionModel::ExecutionModelVertex => {
            format!("::vulkano::shader::VertexShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelTessellationControl => {
            format!("::vulkano::shader::TessControlShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelTessellationEvaluation => {
            format!("::vulkano::shader::TessEvaluationShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelGeometry => {
            format!("::vulkano::shader::GeometryShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelFragment => {
            let mut output_types = Vec::new();

            for interface in interface.iter() {
                for i in doc.instructions.iter() {
                    match i {
                        &parse::Instruction::Variable { result_type_id, result_id,
                                    storage_class: enums::StorageClass::StorageClassOutput, .. }
                                    if &result_id == interface =>
                        {
                            output_types.push(type_from_id(doc, result_type_id));
                        },
                        _ => ()
                    }
                }
            }

            format!("::vulkano::shader::FragmentShaderEntryPoint<({output})>",
                    output = output_types.join(", ") + ",")
        },

        enums::ExecutionModel::ExecutionModelGLCompute => {
            format!("::vulkano::shader::ComputeShaderEntryPoint")
        },

        enums::ExecutionModel::ExecutionModelKernel => panic!("Kernels are not supported"),
    };

    format!(r#"
    /// Returns a logical struct describing the entry point named `{ep_name}`.
    #[inline]
    pub fn {ep_name}_entry_point(&self) -> {ty} {{
        unsafe {{
            static NAME: [u8; {ep_name_lenp1}] = [{encoded_ep_name}, 0];
            self.shader.entry_point(::std::ffi::CStr::from_ptr(NAME.as_ptr() as *const _))
        }}
    }}
            "#, ep_name = ep_name, ep_name_lenp1 = ep_name.chars().count() + 1, ty = ty,
                encoded_ep_name = ep_name.chars().map(|c| (c as u32).to_string())
                                         .collect::<Vec<String>>().join(", "))
}

fn type_from_id(doc: &parse::Spirv, searched: u32) -> String {
    for instruction in doc.instructions.iter() {
        match instruction {
            &parse::Instruction::TypeVoid { result_id } if result_id == searched => {
                return "()".to_owned()
            },
            &parse::Instruction::TypeBool { result_id } if result_id == searched => {
                return "bool".to_owned()
            },
            &parse::Instruction::TypeInt { result_id, width, signedness } if result_id == searched => {
                return "i32".to_owned()
            },
            &parse::Instruction::TypeFloat { result_id, width } if result_id == searched => {
                return "f32".to_owned()
            },
            &parse::Instruction::TypeVector { result_id, component_id, count } if result_id == searched => {
                let t = type_from_id(doc, component_id);
                return format!("[{}; {}]", t, count);
            },
            &parse::Instruction::TypeImage { result_id, sampled_type_id, ref dim, depth, arrayed, ms, sampled, ref format, ref access } if result_id == searched => {
                return format!("{}{}Texture{:?}{}{:?}",
                    if ms { "Multisample" } else { "" },
                    if depth == Some(true) { "Depth" } else { "" },
                    dim,
                    if arrayed { "Array" } else { "" },
                    format);
            },
            &parse::Instruction::TypeSampledImage { result_id, image_type_id } if result_id == searched => {
                return type_from_id(doc, image_type_id);
            },
            &parse::Instruction::TypeArray { result_id, type_id, length_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                let len = doc.instructions.iter().filter_map(|e| {
                    match e { &parse::Instruction::Constant { result_id, ref data, .. } if result_id == length_id => Some(data.clone()), _ => None }
                }).next().expect("failed to find array length");
                let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64);
                return format!("[{}; {}]", t, len);       // FIXME:
            },
            &parse::Instruction::TypeRuntimeArray { result_id, type_id } if result_id == searched => {
                let t = type_from_id(doc, type_id);
                return format!("[{}]", t);
            },
            &parse::Instruction::TypeStruct { result_id, ref member_types } if result_id == searched => {
                let name = name_from_id(doc, result_id);
                let members = member_types.iter().enumerate().map(|(offset, &member)| {
                    let ty = type_from_id(doc, member);
                    let name = member_name_from_id(doc, result_id, offset as u32);
                    format!("\t{}: {}", name, ty)
                }).collect::<Vec<_>>();
                return format!("struct {} {{\n{}\n}}", name, members.join(",\n"));
            },
            &parse::Instruction::TypeOpaque { result_id, ref name } if result_id == searched => {
                return "<opaque>".to_owned();
            },
            &parse::Instruction::TypePointer { result_id, type_id, .. } if result_id == searched => {
                return type_from_id(doc, type_id);
            },
            _ => ()
        }
    }

    panic!("Type #{} not found", searched)
}

fn name_from_id(doc: &parse::Spirv, searched: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::Name { target_id, ref name } = i {
            if target_id == searched {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

fn member_name_from_id(doc: &parse::Spirv, searched: u32, searched_member: u32) -> String {
    doc.instructions.iter().filter_map(|i| {
        if let &parse::Instruction::MemberName { target_id, member, ref name } = i {
            if target_id == searched && member == searched_member {
                Some(name.clone())
            } else {
                None
            }
        } else {
            None
        }
    }).next().and_then(|n| if !n.is_empty() { Some(n) } else { None })
      .unwrap_or("__unnamed".to_owned())
}

// TODO: this function is a draft, as the actual names may not be the same
fn capability_name(cap: &enums::Capability) -> &'static str {
    match *cap {
        enums::Capability::CapabilityMatrix => "Matrix",
        enums::Capability::CapabilityShader => "Shader",
        enums::Capability::CapabilityGeometry => "Geometry",
        enums::Capability::CapabilityTessellation => "Tessellation",
        enums::Capability::CapabilityAddresses => "Addresses",
        enums::Capability::CapabilityLinkage => "Linkage",
        enums::Capability::CapabilityKernel => "Kernel",
        enums::Capability::CapabilityVector16 => "Vector16",
        enums::Capability::CapabilityFloat16Buffer => "Float16Buffer",
        enums::Capability::CapabilityFloat16 => "Float16",
        enums::Capability::CapabilityFloat64 => "Float64",
        enums::Capability::CapabilityInt64 => "Int64",
        enums::Capability::CapabilityInt64Atomics => "Int64Atomics",
        enums::Capability::CapabilityImageBasic => "ImageBasic",
        enums::Capability::CapabilityImageReadWrite => "ImageReadWrite",
        enums::Capability::CapabilityImageMipmap => "ImageMipmap",
        enums::Capability::CapabilityPipes => "Pipes",
        enums::Capability::CapabilityGroups => "Groups",
        enums::Capability::CapabilityDeviceEnqueue => "DeviceEnqueue",
        enums::Capability::CapabilityLiteralSampler => "LiteralSampler",
        enums::Capability::CapabilityAtomicStorage => "AtomicStorage",
        enums::Capability::CapabilityInt16 => "Int16",
        enums::Capability::CapabilityTessellationPointSize => "TessellationPointSize",
        enums::Capability::CapabilityGeometryPointSize => "GeometryPointSize",
        enums::Capability::CapabilityImageGatherExtended => "ImageGatherExtended",
        enums::Capability::CapabilityStorageImageMultisample => "StorageImageMultisample",
        enums::Capability::CapabilityUniformBufferArrayDynamicIndexing => "UniformBufferArrayDynamicIndexing",
        enums::Capability::CapabilitySampledImageArrayDynamicIndexing => "SampledImageArrayDynamicIndexing",
        enums::Capability::CapabilityStorageBufferArrayDynamicIndexing => "StorageBufferArrayDynamicIndexing",
        enums::Capability::CapabilityStorageImageArrayDynamicIndexing => "StorageImageArrayDynamicIndexing",
        enums::Capability::CapabilityClipDistance => "ClipDistance",
        enums::Capability::CapabilityCullDistance => "CullDistance",
        enums::Capability::CapabilityImageCubeArray => "ImageCubeArray",
        enums::Capability::CapabilitySampleRateShading => "SampleRateShading",
        enums::Capability::CapabilityImageRect => "ImageRect",
        enums::Capability::CapabilitySampledRect => "SampledRect",
        enums::Capability::CapabilityGenericPointer => "GenericPointer",
        enums::Capability::CapabilityInt8 => "Int8",
        enums::Capability::CapabilityInputAttachment => "InputAttachment",
        enums::Capability::CapabilitySparseResidency => "SparseResidency",
        enums::Capability::CapabilityMinLod => "MinLod",
        enums::Capability::CapabilitySampled1D => "Sampled1D",
        enums::Capability::CapabilityImage1D => "Image1D",
        enums::Capability::CapabilitySampledCubeArray => "SampledCubeArray",
        enums::Capability::CapabilitySampledBuffer => "SampledBuffer",
        enums::Capability::CapabilityImageBuffer => "ImageBuffer",
        enums::Capability::CapabilityImageMSArray => "ImageMSArray",
        enums::Capability::CapabilityStorageImageExtendedFormats => "StorageImageExtendedFormats",
        enums::Capability::CapabilityImageQuery => "ImageQuery",
        enums::Capability::CapabilityDerivativeControl => "DerivativeControl",
        enums::Capability::CapabilityInterpolationFunction => "InterpolationFunction",
        enums::Capability::CapabilityTransformFeedback => "TransformFeedback",
        enums::Capability::CapabilityGeometryStreams => "GeometryStreams",
        enums::Capability::CapabilityStorageImageReadWithoutFormat => "StorageImageReadWithoutFormat",
        enums::Capability::CapabilityStorageImageWriteWithoutFormat => "StorageImageWriteWithoutFormat",
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
#[macro_export]
macro_rules! assert_eq_printed {
    ($expected:expr, $got:expr, $($tt:tt)*) => {
        let expected = &*$expected;
        let got = &*$got;
        let label = format!($($tt)*);
        if expected != got {
            panic!("
printed outputs differ! (label: {})

expected:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

got:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
", label, expected, got);
        }
    }
}
<commit_msg>grep-searcher: add docs for assert_eq_printed<commit_after>/// Like assert_eq, but nicer output for long strings.
#[cfg(test)]
#[macro_export]
macro_rules! assert_eq_printed {
    ($expected:expr, $got:expr, $($tt:tt)*) => {
        let expected = &*$expected;
        let got = &*$got;
        let label = format!($($tt)*);
        if expected != got {
            panic!("
printed outputs differ! (label: {})

expected:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

got:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
", label, expected, got);
        }
    }
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
#![cfg(unix)]

use tokio::process::Command;
use tokio::runtime;

use futures::future::FutureExt;
use futures::stream::FuturesOrdered;
use std::process::Stdio;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;

fn run_test() {
    let finished = Arc::new(AtomicBool::new(false));
    let finished_clone = finished.clone();

    thread::spawn(move || {
        let mut rt = runtime::Builder::new()
            .basic_scheduler()
            .enable_all()
            .build()
            .unwrap();

        let mut futures = FuturesOrdered::new();
        rt.block_on(async {
            for i in 0..2 {
                futures.push(
                    Command::new("echo")
                        .arg(format!("I am spawned process #{}", i))
                        .stdin(Stdio::null())
                        .stdout(Stdio::null())
                        .stderr(Stdio::null())
                        .kill_on_drop(true)
                        .spawn()
                        .unwrap()
                        .boxed(),
                )
            }
        });

        drop(rt);
        finished_clone.store(true, Ordering::SeqCst);
    });

    thread::sleep(Duration::from_millis(1000));
    assert!(
        finished.load(Ordering::SeqCst),
        "FINISHED flag not set, maybe we deadlocked?"
    );
}

#[test]
fn issue_42() {
    let max = 10;
    for i in 0..max {
        println!("running {}/{}", i, max);
        run_test()
    }
}
<commit_msg>process: rewrite and simplify the issue_42 test (#1871)<commit_after>#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
#![cfg(unix)]

use futures::future::join_all;
use std::process::Stdio;
use tokio::process::Command;
use tokio::task;

#[tokio::test]
async fn issue_42() {
    // We spawn a many batches of processes which should exit at roughly the
    // same time (modulo OS scheduling delays), to make sure that consuming
    // a readiness event for one process doesn't inadvertently starve another.
    // We then do this many times (in parallel) in an effort to stress test the
    // implementation to ensure there are no race conditions.
    // See alexcrichton/tokio-process#42 for background
    let join_handles = (0..10usize).into_iter().map(|_| {
        task::spawn(async {
            let processes = (0..10usize).into_iter().map(|i| {
                Command::new("echo")
                    .arg(format!("I am spawned process #{}", i))
                    .stdin(Stdio::null())
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .kill_on_drop(true)
                    .spawn()
                    .unwrap()
            });

            join_all(processes).await;
        })
    });

    join_all(join_handles).await;
}
<|endoftext|>


<commit_before>mod utils;

use clap::{App, Arg, ErrorKind};

static VISIBLE_ALIAS_HELP: &str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help [aliases: dongle, done]";

static INVISIBLE_ALIAS_HELP: &str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help";

static SUBCMD_ALPHA_ORDER: &str = "test 1

USAGE:
    test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    a1      blah a1
    b1      blah b1
    help    Prints this message or the help of the given subcommand(s)";

static SUBCMD_DECL_ORDER: &str = "test 1

USAGE:
    test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    b1      blah b1
    a1      blah a1
    help    Prints this message or the help of the given subcommand(s)";

#[cfg(feature = "suggestions")]
static DYM_SUBCMD: &str = "error: The subcommand 'subcm' wasn't recognized

	Did you mean 'subcmd'?

If you believe you received this message in error, try re-running with 'dym -- subcm'

USAGE:
    dym [SUBCOMMAND]

For more information try --help";

#[cfg(feature = "suggestions")]
static DYM_SUBCMD_AMBIGUOUS: &str = "error: The subcommand 'te' wasn't recognized

	Did you mean 'test' or 'temp'?

If you believe you received this message in error, try re-running with 'dym -- te'

USAGE:
    dym [SUBCOMMAND]

For more information try --help";

#[cfg(feature = "suggestions")]
static DYM_ARG: &str =
    "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context

	Did you mean to put '--subcmdarg' after the subcommand 'subcmd'?

If you tried to supply `--subcm` as a PATTERN use `-- --subcm`

USAGE:
    dym [SUBCOMMAND]

For more information try --help";

#[test]
fn subcommand() {
    let m = App::new("test")
        .subcommand(
            App::new("some").arg(
                Arg::new("test")
                    .short('t')
                    .long("test")
                    .takes_value(true)
                    .about("testing testing"),
            ),
        )
        .arg(Arg::new("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn subcommand_none_given() {
    let m = App::new("test")
        .subcommand(
            App::new("some").arg(
                Arg::new("test")
                    .short('t')
                    .long("test")
                    .takes_value(true)
                    .about("testing testing"),
            ),
        )
        .arg(Arg::new("other").long("other"))
        .get_matches_from(vec![""]);

    assert!(m.subcommand_name().is_none());
}

#[test]
fn subcommand_multiple() {
    let m = App::new("test")
        .subcommands(vec![
            App::new("some").arg(
                Arg::new("test")
                    .short('t')
                    .long("test")
                    .takes_value(true)
                    .about("testing testing"),
            ),
            App::new("add").arg(Arg::new("roster").short('r')),
        ])
        .arg(Arg::new("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert!(m.subcommand_matches("some").is_some());
    assert!(m.subcommand_matches("add").is_none());
    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn subcommand_display_order() {
    let app_subcmd_alpha_order = App::new("test").version("1").subcommands(vec![
        App::new("b1")
            .about("blah b1")
            .arg(Arg::new("test").short('t')),
        App::new("a1")
            .about("blah a1")
            .arg(Arg::new("roster").short('r')),
    ]);

    assert!(utils::compare_output(
        app_subcmd_alpha_order,
        "test --help",
        SUBCMD_ALPHA_ORDER,
        false,
    ));

    let app_subcmd_decl_order = App::new("test")
        .version("1")
        .setting(clap::AppSettings::DeriveDisplayOrder)
        .subcommands(vec![
            App::new("b1")
                .about("blah b1")
                .arg(Arg::new("test").short('t')),
            App::new("a1")
                .about("blah a1")
                .arg(Arg::new("roster").short('r')),
        ]);

    assert!(utils::compare_output(
        app_subcmd_decl_order,
        "test --help",
        SUBCMD_DECL_ORDER,
        false,
    ));
}

#[test]
fn single_alias() {
    let m = App::new("myprog")
        .subcommand(App::new("test").alias("do-stuff"))
        .get_matches_from(vec!["myprog", "do-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
fn multiple_aliases() {
    let m = App::new("myprog")
        .subcommand(App::new("test").aliases(&["do-stuff", "test-stuff"]))
        .get_matches_from(vec!["myprog", "test-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output() {
    let app = App::new("dym").subcommand(App::new("subcmd"));
    assert!(utils::compare_output(app, "dym subcm", DYM_SUBCMD, true));
}

#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_ambiguous() {
    let app = App::new("dym")
        .subcommand(App::new("test"))
        .subcommand(App::new("temp"));
    assert!(utils::compare_output(
        app,
        "dym te",
        DYM_SUBCMD_AMBIGUOUS,
        true
    ));
}

#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_arg() {
    let app =
        App::new("dym").subcommand(App::new("subcmd").arg("-s --subcmdarg [subcmdarg] 'tests'"));
    assert!(utils::compare_output(app, "dym --subcm foo", DYM_ARG, true));
}

#[test]
fn alias_help() {
    let m = App::new("myprog")
        .subcommand(App::new("test").alias("do-stuff"))
        .try_get_matches_from(vec!["myprog", "help", "do-stuff"]);
    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn visible_aliases_help_output() {
    let app = App::new("clap-test").version("2.6").subcommand(
        App::new("test")
            .about("Some help")
            .alias("invisible")
            .visible_alias("dongle")
            .visible_alias("done"),
    );
    assert!(utils::compare_output(
        app,
        "clap-test --help",
        VISIBLE_ALIAS_HELP,
        false
    ));
}

#[test]
fn invisible_aliases_help_output() {
    let app = App::new("clap-test")
        .version("2.6")
        .subcommand(App::new("test").about("Some help").alias("invisible"));
    assert!(utils::compare_output(
        app,
        "clap-test --help",
        INVISIBLE_ALIAS_HELP,
        false
    ));
}

#[test]
fn replace() {
    let m = App::new("prog")
        .subcommand(App::new("module").subcommand(App::new("install").about("Install module")))
        .replace("install", &["module", "install"])
        .get_matches_from(vec!["prog", "install"]);

    assert_eq!(m.subcommand_name(), Some("module"));
    assert_eq!(
        m.subcommand_matches("module").unwrap().subcommand_name(),
        Some("install")
    );
}

#[test]
fn issue_1031_args_with_same_name() {
    let res = App::new("prog")
        .arg(Arg::from("--ui-path=<PATH>"))
        .subcommand(App::new("signer"))
        .try_get_matches_from(vec!["prog", "--ui-path", "signer"]);

    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
    let m = res.unwrap();
    assert_eq!(m.value_of("ui-path"), Some("signer"));
}

#[test]
fn issue_1031_args_with_same_name_no_more_vals() {
    let res = App::new("prog")
        .arg(Arg::from("--ui-path=<PATH>"))
        .subcommand(App::new("signer"))
        .try_get_matches_from(vec!["prog", "--ui-path", "value", "signer"]);

    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
    let m = res.unwrap();
    assert_eq!(m.value_of("ui-path"), Some("value"));
    assert_eq!(m.subcommand_name(), Some("signer"));
}

#[test]
fn issue_1161_multiple_hyphen_hyphen() {
    // from example 22
    let res = App::new("myprog")
        .arg(Arg::new("eff").short('f'))
        .arg(Arg::new("pea").short('p').takes_value(true))
        .arg(Arg::new("slop").multiple(true).last(true))
        .try_get_matches_from(vec![
            "-f",
            "-p=bob",
            "--",
            "sloppy",
            "slop",
            "-a",
            "--",
            "subprogram",
            "position",
            "args",
        ]);

    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
    let m = res.unwrap();

    let expected = Some(vec![
        "sloppy",
        "slop",
        "-a",
        "--",
        "subprogram",
        "position",
        "args",
    ]);
    let actual = m.values_of("slop").map(|vals| vals.collect::<Vec<_>>());

    assert_eq!(expected, actual);
}

#[test]
fn issue_1722_not_emit_error_when_arg_follows_similar_to_a_subcommand() {
    let m = App::new("myprog")
        .subcommand(App::new("subcommand"))
        .arg(Arg::new("argument"))
        .try_get_matches_from(vec!["myprog", "--", "subcommand"]);
    assert_eq!(m.unwrap().value_of("argument"), Some("subcommand"));
}
<commit_msg>Add test for custom subcommand placeholder text<commit_after>mod utils;

use clap::{App, Arg, ErrorKind};

static VISIBLE_ALIAS_HELP: &str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help [aliases: dongle, done]";

static INVISIBLE_ALIAS_HELP: &str = "clap-test 2.6

USAGE:
    clap-test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    help    Prints this message or the help of the given subcommand(s)
    test    Some help";

static SUBCMD_ALPHA_ORDER: &str = "test 1

USAGE:
    test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    a1      blah a1
    b1      blah b1
    help    Prints this message or the help of the given subcommand(s)";

static SUBCMD_DECL_ORDER: &str = "test 1

USAGE:
    test [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    b1      blah b1
    a1      blah a1
    help    Prints this message or the help of the given subcommand(s)";

#[cfg(feature = "suggestions")]
static DYM_SUBCMD: &str = "error: The subcommand 'subcm' wasn't recognized

	Did you mean 'subcmd'?

If you believe you received this message in error, try re-running with 'dym -- subcm'

USAGE:
    dym [SUBCOMMAND]

For more information try --help";

#[cfg(feature = "suggestions")]
static DYM_SUBCMD_AMBIGUOUS: &str = "error: The subcommand 'te' wasn't recognized

	Did you mean 'test' or 'temp'?

If you believe you received this message in error, try re-running with 'dym -- te'

USAGE:
    dym [SUBCOMMAND]

For more information try --help";

#[cfg(feature = "suggestions")]
static DYM_ARG: &str =
    "error: Found argument '--subcm' which wasn't expected, or isn't valid in this context

	Did you mean to put '--subcmdarg' after the subcommand 'subcmd'?

If you tried to supply `--subcm` as a PATTERN use `-- --subcm`

USAGE:
    dym [SUBCOMMAND]

For more information try --help";

#[test]
fn subcommand() {
    let m = App::new("test")
        .subcommand(
            App::new("some").arg(
                Arg::new("test")
                    .short('t')
                    .long("test")
                    .takes_value(true)
                    .about("testing testing"),
            ),
        )
        .arg(Arg::new("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn subcommand_none_given() {
    let m = App::new("test")
        .subcommand(
            App::new("some").arg(
                Arg::new("test")
                    .short('t')
                    .long("test")
                    .takes_value(true)
                    .about("testing testing"),
            ),
        )
        .arg(Arg::new("other").long("other"))
        .get_matches_from(vec![""]);

    assert!(m.subcommand_name().is_none());
}

#[test]
fn subcommand_multiple() {
    let m = App::new("test")
        .subcommands(vec![
            App::new("some").arg(
                Arg::new("test")
                    .short('t')
                    .long("test")
                    .takes_value(true)
                    .about("testing testing"),
            ),
            App::new("add").arg(Arg::new("roster").short('r')),
        ])
        .arg(Arg::new("other").long("other"))
        .get_matches_from(vec!["myprog", "some", "--test", "testing"]);

    assert!(m.subcommand_matches("some").is_some());
    assert!(m.subcommand_matches("add").is_none());
    assert_eq!(m.subcommand_name().unwrap(), "some");
    let sub_m = m.subcommand_matches("some").unwrap();
    assert!(sub_m.is_present("test"));
    assert_eq!(sub_m.value_of("test").unwrap(), "testing");
}

#[test]
fn subcommand_display_order() {
    let app_subcmd_alpha_order = App::new("test").version("1").subcommands(vec![
        App::new("b1")
            .about("blah b1")
            .arg(Arg::new("test").short('t')),
        App::new("a1")
            .about("blah a1")
            .arg(Arg::new("roster").short('r')),
    ]);

    assert!(utils::compare_output(
        app_subcmd_alpha_order,
        "test --help",
        SUBCMD_ALPHA_ORDER,
        false,
    ));

    let app_subcmd_decl_order = App::new("test")
        .version("1")
        .setting(clap::AppSettings::DeriveDisplayOrder)
        .subcommands(vec![
            App::new("b1")
                .about("blah b1")
                .arg(Arg::new("test").short('t')),
            App::new("a1")
                .about("blah a1")
                .arg(Arg::new("roster").short('r')),
        ]);

    assert!(utils::compare_output(
        app_subcmd_decl_order,
        "test --help",
        SUBCMD_DECL_ORDER,
        false,
    ));
}

#[test]
fn single_alias() {
    let m = App::new("myprog")
        .subcommand(App::new("test").alias("do-stuff"))
        .get_matches_from(vec!["myprog", "do-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
fn multiple_aliases() {
    let m = App::new("myprog")
        .subcommand(App::new("test").aliases(&["do-stuff", "test-stuff"]))
        .get_matches_from(vec!["myprog", "test-stuff"]);
    assert_eq!(m.subcommand_name(), Some("test"));
}

#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output() {
    let app = App::new("dym").subcommand(App::new("subcmd"));
    assert!(utils::compare_output(app, "dym subcm", DYM_SUBCMD, true));
}

#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_ambiguous() {
    let app = App::new("dym")
        .subcommand(App::new("test"))
        .subcommand(App::new("temp"));
    assert!(utils::compare_output(
        app,
        "dym te",
        DYM_SUBCMD_AMBIGUOUS,
        true
    ));
}

#[test]
#[cfg(feature = "suggestions")]
fn subcmd_did_you_mean_output_arg() {
    let app =
        App::new("dym").subcommand(App::new("subcmd").arg("-s --subcmdarg [subcmdarg] 'tests'"));
    assert!(utils::compare_output(app, "dym --subcm foo", DYM_ARG, true));
}

#[test]
fn alias_help() {
    let m = App::new("myprog")
        .subcommand(App::new("test").alias("do-stuff"))
        .try_get_matches_from(vec!["myprog", "help", "do-stuff"]);
    assert!(m.is_err());
    assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed);
}

#[test]
fn visible_aliases_help_output() {
    let app = App::new("clap-test").version("2.6").subcommand(
        App::new("test")
            .about("Some help")
            .alias("invisible")
            .visible_alias("dongle")
            .visible_alias("done"),
    );
    assert!(utils::compare_output(
        app,
        "clap-test --help",
        VISIBLE_ALIAS_HELP,
        false
    ));
}

#[test]
fn invisible_aliases_help_output() {
    let app = App::new("clap-test")
        .version("2.6")
        .subcommand(App::new("test").about("Some help").alias("invisible"));
    assert!(utils::compare_output(
        app,
        "clap-test --help",
        INVISIBLE_ALIAS_HELP,
        false
    ));
}

#[test]
fn replace() {
    let m = App::new("prog")
        .subcommand(App::new("module").subcommand(App::new("install").about("Install module")))
        .replace("install", &["module", "install"])
        .get_matches_from(vec!["prog", "install"]);

    assert_eq!(m.subcommand_name(), Some("module"));
    assert_eq!(
        m.subcommand_matches("module").unwrap().subcommand_name(),
        Some("install")
    );
}

#[test]
fn issue_1031_args_with_same_name() {
    let res = App::new("prog")
        .arg(Arg::from("--ui-path=<PATH>"))
        .subcommand(App::new("signer"))
        .try_get_matches_from(vec!["prog", "--ui-path", "signer"]);

    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
    let m = res.unwrap();
    assert_eq!(m.value_of("ui-path"), Some("signer"));
}

#[test]
fn issue_1031_args_with_same_name_no_more_vals() {
    let res = App::new("prog")
        .arg(Arg::from("--ui-path=<PATH>"))
        .subcommand(App::new("signer"))
        .try_get_matches_from(vec!["prog", "--ui-path", "value", "signer"]);

    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
    let m = res.unwrap();
    assert_eq!(m.value_of("ui-path"), Some("value"));
    assert_eq!(m.subcommand_name(), Some("signer"));
}

#[test]
fn issue_1161_multiple_hyphen_hyphen() {
    // from example 22
    let res = App::new("myprog")
        .arg(Arg::new("eff").short('f'))
        .arg(Arg::new("pea").short('p').takes_value(true))
        .arg(Arg::new("slop").multiple(true).last(true))
        .try_get_matches_from(vec![
            "-f",
            "-p=bob",
            "--",
            "sloppy",
            "slop",
            "-a",
            "--",
            "subprogram",
            "position",
            "args",
        ]);

    assert!(res.is_ok(), "{:?}", res.unwrap_err().kind);
    let m = res.unwrap();

    let expected = Some(vec![
        "sloppy",
        "slop",
        "-a",
        "--",
        "subprogram",
        "position",
        "args",
    ]);
    let actual = m.values_of("slop").map(|vals| vals.collect::<Vec<_>>());

    assert_eq!(expected, actual);
}

#[test]
fn issue_1722_not_emit_error_when_arg_follows_similar_to_a_subcommand() {
    let m = App::new("myprog")
        .subcommand(App::new("subcommand"))
        .arg(Arg::new("argument"))
        .try_get_matches_from(vec!["myprog", "--", "subcommand"]);
    assert_eq!(m.unwrap().value_of("argument"), Some("subcommand"));
}

#[test]
fn subcommand_placeholder_test() {
    let usage = App::new("myprog")
        .subcommand(App::new("subcommand"))
        .subcommand_placeholder("TEST_PLACEHOLDER")
        .generate_usage();

    assert_eq!(&usage, "USAGE:\n    myprog [TEST_PLACEHOLDER]");
}
<|endoftext|>