<commit_before>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(String, usize)>,
    pub error_matches: Vec<ErrorMatch>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub matched: String,
    pub revision: Option<String>,
    pub level: Option<Level>,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Self {
        if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().expect(
                "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N",
            );
            Condition::Bitwidth(bits)
        } else {
            Condition::Target(c.to_owned())
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    ///
    /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant)
    /// and ignore all others
    fn parse_checked(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        let mut fallthrough_to = None; // The line that a `|` will refer to.
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::parse_checked(path, content)?;
        if content.contains("//@") {
            // Migration mode: if new syntax is used, ignore all old syntax
            return Ok(this);
        }

        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            if let Some(revisions) = line.strip_prefix("// revisions:") {
                assert_eq!(
                    this.revisions,
                    None,
                    "{}:{l}, cannot specifiy revisions twice",
                    path.display()
                );
                this.revisions =
                    Some(revisions.split_whitespace().map(|s| s.to_string()).collect());
            }
            if let Some(s) = line.strip_prefix("// ignore-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.ignore.push(Condition::parse(s));
            }
            if let Some(s) = line.strip_prefix("// only-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.only.push(Condition::parse(s));
            }
            if line.starts_with("// stderr-per-bitwidth") {
                assert!(
                    !this.stderr_per_bitwidth,
                    "{}:{l}, cannot specifiy stderr-per-bitwidth twice",
                    path.display()
                );
                this.stderr_per_bitwidth = true;
            }
            if let Some(s) = line.strip_prefix("// compile-flags:") {
                this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string()));
            }
            if let Some(s) = line.strip_prefix("// rustc-env:") {
                for env in s.split_whitespace() {
                    if let Some((k, v)) = env.split_once('=') {
                        this.env_vars.push((k.to_string(), v.to_string()));
                    }
                }
            }
            if let Some(s) = line.strip_prefix("// normalize-stderr-test:") {
                let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`");
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).unwrap();
                this.normalize_stderr.push((from, to.to_string()));
            }
            if let Some(s) = line.strip_prefix("// error-pattern:") {
                assert_eq!(
                    this.error_pattern,
                    None,
                    "{}:{l}, cannot specifiy error_pattern twice",
                    path.display()
                );
                this.error_pattern = Some((s.trim().to_string(), l));
            }
        }
        Ok(this)
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    // Commands are separated from their arguments by ':' or ' '
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    let args = match next {
                        ':' | ' ' => args.as_str(),
                        _ => bail!("expected space or `:`, got `{next}`"),
                    };
                    (command, args)
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                let (from, to) = args
                    .split_once("->")
                    .ok_or_else(|| eyre!("normalize-stderr-test needs a `->`"))?;
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).ok().ok_or_else(|| eyre!("invalid regex"))?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((args.trim().to_string(), l));
            }
            "stderr-per-bitwidth" => {
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    self.ignore.push(Condition::parse(s));
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    self.only.push(Condition::parse(s));
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE)?:?(?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) {
            None => (None, pattern),
            Some((level, pattern_without_level)) =>
                match level.parse().ok() {
                    Some(level) => (Some(level), pattern_without_level),
                    None => (None, pattern),
                },
        };

        let matched = pattern.trim().to_string();

        ensure!(!matched.is_empty(), "no pattern specified");

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            matched,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}
<commit_msg>Create a proper normalization regex parser<commit_after>use std::path::Path;

use regex::Regex;

use crate::rustc_stderr::Level;

use color_eyre::eyre::{bail, ensure, eyre, Result};

#[cfg(test)]
mod tests;

/// This crate supports various magic comments that get parsed as file-specific
/// configuration values. This struct parses them all in one go and then they
/// get processed by their respective use sites.
#[derive(Default, Debug)]
pub(crate) struct Comments {
    /// List of revision names to execute. Can only be speicified once
    pub revisions: Option<Vec<String>>,
    /// Don't run this test if any of these filters apply
    pub ignore: Vec<Condition>,
    /// Only run this test if all of these filters apply
    pub only: Vec<Condition>,
    /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
    pub stderr_per_bitwidth: bool,
    /// Additional flags to pass to the executable
    pub compile_flags: Vec<String>,
    /// Additional env vars to set for the executable
    pub env_vars: Vec<(String, String)>,
    /// Normalizations to apply to the stderr output before emitting it to disk
    pub normalize_stderr: Vec<(Regex, String)>,
    /// An arbitrary pattern to look for in the stderr.
    pub error_pattern: Option<(String, usize)>,
    pub error_matches: Vec<ErrorMatch>,
}

/// The conditions used for "ignore" and "only" filters.
#[derive(Debug)]
pub(crate) enum Condition {
    /// The given string must appear in the target.
    Target(String),
    /// Tests that the bitwidth is the given one.
    Bitwidth(u8),
}

#[derive(Debug)]
pub(crate) struct ErrorMatch {
    pub matched: String,
    pub revision: Option<String>,
    pub level: Option<Level>,
    /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found).
    pub definition_line: usize,
    /// The line this pattern is expecting to find a message in.
    pub line: usize,
}

impl Condition {
    fn parse(c: &str) -> Self {
        if let Some(bits) = c.strip_suffix("bit") {
            let bits: u8 = bits.parse().expect(
                "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N",
            );
            Condition::Bitwidth(bits)
        } else {
            Condition::Target(c.to_owned())
        }
    }
}

impl Comments {
    pub(crate) fn parse_file(path: &Path) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Self::parse(path, &content)
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    ///
    /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant)
    /// and ignore all others
    fn parse_checked(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::default();

        let mut fallthrough_to = None; // The line that a `|` will refer to.
        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| {
                err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display()))
            })?;
        }
        Ok(this)
    }

    fn parse_checked_line(
        &mut self,
        l: usize,
        fallthrough_to: &mut Option<usize>,
        line: &str,
    ) -> Result<()> {
        if let Some((_, command)) = line.split_once("//@") {
            self.parse_command(command.trim(), l)
        } else if let Some((_, pattern)) = line.split_once("//~") {
            self.parse_pattern(pattern, fallthrough_to, l)
        } else if let Some((_, pattern)) = line.split_once("//[") {
            self.parse_revisioned_pattern(pattern, fallthrough_to, l)
        } else {
            *fallthrough_to = None;
            Ok(())
        }
    }

    /// Parse comments in `content`.
    /// `path` is only used to emit diagnostics if parsing fails.
    pub(crate) fn parse(path: &Path, content: &str) -> Result<Self> {
        let mut this = Self::parse_checked(path, content)?;
        if content.contains("//@") {
            // Migration mode: if new syntax is used, ignore all old syntax
            return Ok(this);
        }

        for (l, line) in content.lines().enumerate() {
            let l = l + 1; // enumerate starts at 0, but line numbers start at 1
            if let Some(revisions) = line.strip_prefix("// revisions:") {
                assert_eq!(
                    this.revisions,
                    None,
                    "{}:{l}, cannot specifiy revisions twice",
                    path.display()
                );
                this.revisions =
                    Some(revisions.split_whitespace().map(|s| s.to_string()).collect());
            }
            if let Some(s) = line.strip_prefix("// ignore-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.ignore.push(Condition::parse(s));
            }
            if let Some(s) = line.strip_prefix("// only-") {
                let s = s
                    .split_once(|c: char| c == ':' || c.is_whitespace())
                    .map(|(s, _)| s)
                    .unwrap_or(s);
                this.only.push(Condition::parse(s));
            }
            if line.starts_with("// stderr-per-bitwidth") {
                assert!(
                    !this.stderr_per_bitwidth,
                    "{}:{l}, cannot specifiy stderr-per-bitwidth twice",
                    path.display()
                );
                this.stderr_per_bitwidth = true;
            }
            if let Some(s) = line.strip_prefix("// compile-flags:") {
                this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string()));
            }
            if let Some(s) = line.strip_prefix("// rustc-env:") {
                for env in s.split_whitespace() {
                    if let Some((k, v)) = env.split_once('=') {
                        this.env_vars.push((k.to_string(), v.to_string()));
                    }
                }
            }
            if let Some(s) = line.strip_prefix("// normalize-stderr-test:") {
                let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`");
                let from = from.trim().trim_matches('"');
                let to = to.trim().trim_matches('"');
                let from = Regex::new(from).unwrap();
                this.normalize_stderr.push((from, to.to_string()));
            }
            if let Some(s) = line.strip_prefix("// error-pattern:") {
                assert_eq!(
                    this.error_pattern,
                    None,
                    "{}:{l}, cannot specifiy error_pattern twice",
                    path.display()
                );
                this.error_pattern = Some((s.trim().to_string(), l));
            }
        }
        Ok(this)
    }

    fn parse_command(&mut self, command: &str, l: usize) -> Result<()> {
        // Commands are letters or dashes, grab everything until the first character that is neither of those.
        let (command, args) =
            match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') {
                None => (command, ""),
                Some(i) => {
                    let (command, args) = command.split_at(i);
                    let mut args = args.chars();
                    // Commands are separated from their arguments by ':' or ' '
                    let next = args
                        .next()
                        .expect("the `position` above guarantees that there is at least one char");
                    let args = match next {
                        ':' | ' ' => args.as_str(),
                        _ => bail!("expected space or `:`, got `{next}`"),
                    };
                    (command, args.trim())
                }
            };

        match command {
            "revisions" => {
                ensure!(self.revisions.is_none(), "cannot specifiy revisions twice");
                self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
            }
            "compile-flags" => {
                self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string()));
            }
            "rustc-env" =>
                for env in args.split_whitespace() {
                    let (k, v) = env.split_once('=').ok_or_else(|| {
                        eyre!("environment variables must be key/value pairs separated by a `=`")
                    })?;
                    self.env_vars.push((k.to_string(), v.to_string()));
                },
            "normalize-stderr-test" => {
                fn parse_str(s: &str) -> Result<(&str, &str)> {
                    let mut chars = s.char_indices();
                    match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 {
                        '"' => {
                            let s = chars.as_str();
                            let mut escaped = false;
                            for (i, c) in chars {
                                if escaped {
                                    escaped = false;
                                } else if c == '"' {
                                    return Ok((&s[..(i - 1)], s[i..].trim_start()))
                                } else {
                                    escaped = c == '\\';
                                }
                            }
                            bail!("no closing quotes found for {s}")
                        }
                        c => bail!("expected '\"', got {c}"),
                    }
                }

                let (from, rest) = parse_str(args)?;

                let to = rest.strip_prefix("->").ok_or_else(|| {
                    eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`")
                })?.trim_start();
                let (to, rest) = parse_str(to)?;

                ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}");

                let from = Regex::new(from)?;
                self.normalize_stderr.push((from, to.to_string()));
            }
            "error-pattern" => {
                ensure!(
                    self.error_pattern.is_none(),
                    "cannot specifiy error_pattern twice, previous: {:?}",
                    self.error_pattern
                );
                self.error_pattern = Some((args.trim().to_string(), l));
            }
            "stderr-per-bitwidth" => {
                ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice");
                self.stderr_per_bitwidth = true;
            }
            command => {
                if let Some(s) = command.strip_prefix("ignore-") {
                    self.ignore.push(Condition::parse(s));
                    return Ok(());
                }

                if let Some(s) = command.strip_prefix("only-") {
                    self.only.push(Condition::parse(s));
                    return Ok(());
                }
                bail!("unknown command {command}");
            }
        }

        Ok(())
    }

    fn parse_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        self.parse_pattern_inner(pattern, fallthrough_to, None, l)
    }

    fn parse_revisioned_pattern(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        l: usize,
    ) -> Result<()> {
        let (revision, pattern) =
            pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?;
        if let Some(pattern) = pattern.strip_prefix('~') {
            self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l)
        } else {
            bail!("revisioned pattern must have `~` following the `]`");
        }
    }

    // parse something like (?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE)?:?(?P<text>.*)
    fn parse_pattern_inner(
        &mut self,
        pattern: &str,
        fallthrough_to: &mut Option<usize>,
        revision: Option<String>,
        l: usize,
    ) -> Result<()> {
        let (match_line, pattern) =
            match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? {
                '|' =>
                    (
                        *fallthrough_to
                            .as_mut()
                            .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?,
                        &pattern[1..],
                    ),
                '^' => {
                    let offset = pattern.chars().take_while(|&c| c == '^').count();
                    (l - offset, &pattern[offset..])
                }
                _ => (l, pattern),
            };

        let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) {
            None => (None, pattern),
            Some((level, pattern_without_level)) =>
                match level.parse().ok() {
                    Some(level) => (Some(level), pattern_without_level),
                    None => (None, pattern),
                },
        };

        let matched = pattern.trim().to_string();

        ensure!(!matched.is_empty(), "no pattern specified");

        *fallthrough_to = Some(match_line);

        self.error_matches.push(ErrorMatch {
            matched,
            revision,
            level,
            definition_line: l,
            line: match_line,
        });

        Ok(())
    }
}
<|endoftext|>


<commit_before>use ra_syntax::{ast::AstNode, SourceFile, SyntaxKind, TextSize, T};

// Feature: Matching Brace
//
// If the cursor is on any brace (`<>(){}[]`) which is a part of a brace-pair,
// moves cursor to the matching brace. It uses the actual parser to determine
// braces, so it won't confuse generics with comparisons.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Find matching brace**
// |===
pub fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
    const BRACES: &[SyntaxKind] =
        &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>]];
    let (brace_node, brace_idx) = file
        .syntax()
        .token_at_offset(offset)
        .filter_map(|node| {
            let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
            Some((node, idx))
        })
        .next()?;
    let parent = brace_node.parent();
    let matching_kind = BRACES[brace_idx ^ 1];
    let matching_node = parent.children_with_tokens().find(|node| node.kind() == matching_kind)?;
    Some(matching_node.text_range().start())
}

#[cfg(test)]
mod tests {
    use test_utils::{add_cursor, assert_eq_text, extract_offset};

    use super::*;

    #[test]
    fn test_matching_brace() {
        fn do_check(before: &str, after: &str) {
            let (pos, before) = extract_offset(before);
            let parse = SourceFile::parse(&before);
            let new_pos = match matching_brace(&parse.tree(), pos) {
                None => pos,
                Some(pos) => pos,
            };
            let actual = add_cursor(&before, new_pos);
            assert_eq_text!(after, &actual);
        }

        do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }");
    }
}
<commit_msg>matching brace works for | in lambdas<commit_after>use ra_syntax::{
    ast::{self, AstNode},
    SourceFile, SyntaxKind, TextSize, T,
};
use test_utils::mark;

// Feature: Matching Brace
//
// If the cursor is on any brace (`<>(){}[]||`) which is a part of a brace-pair,
// moves cursor to the matching brace. It uses the actual parser to determine
// braces, so it won't confuse generics with comparisons.
//
// |===
// | Editor  | Action Name
//
// | VS Code | **Rust Analyzer: Find matching brace**
// |===
pub fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
    const BRACES: &[SyntaxKind] =
        &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]];
    let (brace_token, brace_idx) = file
        .syntax()
        .token_at_offset(offset)
        .filter_map(|node| {
            let idx = BRACES.iter().position(|&brace| brace == node.kind())?;
            Some((node, idx))
        })
        .next()?;
    let parent = brace_token.parent();
    if brace_token.kind() == T![|] && !ast::ParamList::can_cast(parent.kind()) {
        mark::hit!(pipes_not_braces);
        return None;
    }
    let matching_kind = BRACES[brace_idx ^ 1];
    let matching_node = parent.children_with_tokens().find(|node| node.kind() == matching_kind)?;
    Some(matching_node.text_range().start())
}

#[cfg(test)]
mod tests {
    use test_utils::{add_cursor, assert_eq_text, extract_offset};

    use super::*;

    #[test]
    fn test_matching_brace() {
        fn do_check(before: &str, after: &str) {
            let (pos, before) = extract_offset(before);
            let parse = SourceFile::parse(&before);
            let new_pos = match matching_brace(&parse.tree(), pos) {
                None => pos,
                Some(pos) => pos,
            };
            let actual = add_cursor(&before, new_pos);
            assert_eq_text!(after, &actual);
        }

        do_check("struct Foo { a: i32, }<|>", "struct Foo <|>{ a: i32, }");
        do_check("fn main() { |x: i32|<|> x * 2;}", "fn main() { <|>|x: i32| x * 2;}");

        {
            mark::check!(pipes_not_braces);
            do_check(
                "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }",
                "fn main() { match 92 { 1 | 2 |<|> 3 => 92 } }",
            );
        }
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate hawk;
extern crate hyper;
extern crate hyper_hawk;
extern crate url;

use std::process::{Command, Child};
use hawk::{RequestBuilder, Credentials, Key, SHA256, PayloadHasher};
use std::io::Read;
use std::net::TcpListener;
use std::path::Path;
use hyper_hawk::{HawkScheme, ServerAuthorization};
use hyper::Client;
use hyper::header;
use std::str::FromStr;
use url::Url;

fn start_node_script(script: &str) -> (Child, u16) {
    let listener = TcpListener::bind(format!("127.0.0.1:{}", 0)).unwrap();
    let callback_port = listener.local_addr().unwrap().port();

    // check for `node_modules' first
    let path = Path::new("tests/node/node_modules");
    if !path.is_dir() {
        panic!("Run `yarn` or `npm install` in tests/node");
    }

    let child = Command::new("node")
        .arg(script)
        .arg(format!("{}", callback_port))
        .current_dir("tests/node")
        .spawn()
        .expect("node command failed to start");

    // wait until the process is ready, signalled by a connect to the callback port, and then
    // return the port it provides.
    for stream in listener.incoming() {
        let mut stream = stream.unwrap();

        let mut data: Vec<u8> = vec![];
        stream.read_to_end(&mut data).unwrap();
        let port = u16::from_str(std::str::from_utf8(&data).unwrap()).unwrap();

        drop(stream);
        return (child, port);
    }
    unreachable!();
}

fn make_credentials() -> Credentials {
    Credentials {
        id: "dh37fgj492je".to_string(),
        key: Key::new("werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn", &SHA256),
    }
}

#[test]
fn client_with_header() {
    let (mut child, port) = start_node_script("serve-one.js");

    let credentials = make_credentials();
    let url = Url::parse(&format!("http://localhost:{}/resource", port)).unwrap();
    let body = "foo=bar";

    let payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
    let request = RequestBuilder::from_url("POST", &url)
        .unwrap()
        .hash(&payload_hash[..])
        .ext("ext-content")
        .request();
    let mut headers = hyper::header::Headers::new();
    let header = request.make_header(&credentials).unwrap();
    headers.set(header::Authorization(HawkScheme(header.clone())));
    headers.set(header::ContentType::plaintext());

    let client = Client::new();
    let mut res = client
        .post(url.as_str())
        .headers(headers)
        .body(body)
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    assert!(res.status == hyper::Ok);
    assert!(body == "Hello Steve ext-content");

    // validate server's signature
    {
        let server_hdr: &ServerAuthorization<HawkScheme> = res.headers.get().unwrap();
        let payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
        let response = request
            .make_response_builder(&header)
            .hash(&payload_hash[..])
            .response();
        if !response.validate_header(&server_hdr, &credentials.key) {
            panic!("authentication of response header failed");
        }
    }

    drop(res);
    drop(client); // close the kept-alive connection

    child.wait().expect("Failure waiting for child");
}

#[test]
fn client_with_bewit() {
    let (mut child, port) = start_node_script("serve-one.js");

    let credentials = make_credentials();
    let url = Url::parse(&format!("http://localhost:{}/resource", port)).unwrap();
    let request = RequestBuilder::from_url("GET", &url)
        .unwrap()
        .ext("ext-content")
        .request();

    let bewit = request
        .make_bewit(&credentials, time::Duration::minutes(1))
        .unwrap();
    let mut url = url.clone();
    url.set_query(Some(&format!("bewit={}", bewit.to_str())));

    let client = Client::new();
    let mut res = client.get(url.as_str()).send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    assert!(res.status == hyper::Ok);
    assert!(body == "Hello Steve ext-content");

    drop(res);
    drop(client); // close the kept-alive connection

    child.wait().expect("Failure waiting for child");
}
<commit_msg>rename function<commit_after>extern crate time;
extern crate hawk;
extern crate hyper;
extern crate hyper_hawk;
extern crate url;

use std::process::{Command, Child};
use hawk::{RequestBuilder, Credentials, Key, SHA256, PayloadHasher};
use std::io::Read;
use std::net::TcpListener;
use std::path::Path;
use hyper_hawk::{HawkScheme, ServerAuthorization};
use hyper::Client;
use hyper::header;
use std::str::FromStr;
use url::Url;

fn start_node_server() -> (Child, u16) {
    let listener = TcpListener::bind(format!("127.0.0.1:{}", 0)).unwrap();
    let callback_port = listener.local_addr().unwrap().port();

    // check for `node_modules' first
    let path = Path::new("tests/node/node_modules");
    if !path.is_dir() {
        panic!("Run `yarn` or `npm install` in tests/node");
    }

    let child = Command::new("node")
        .arg("serve-one.js")
        .arg(format!("{}", callback_port))
        .current_dir("tests/node")
        .spawn()
        .expect("node command failed to start");

    // wait until the process is ready, signalled by a connect to the callback port, and then
    // return the port it provides.
    for stream in listener.incoming() {
        let mut stream = stream.unwrap();

        let mut data: Vec<u8> = vec![];
        stream.read_to_end(&mut data).unwrap();
        let port = u16::from_str(std::str::from_utf8(&data).unwrap()).unwrap();

        drop(stream);
        return (child, port);
    }
    unreachable!();
}

fn make_credentials() -> Credentials {
    Credentials {
        id: "dh37fgj492je".to_string(),
        key: Key::new("werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn", &SHA256),
    }
}

#[test]
fn client_with_header() {
    let (mut child, port) = start_node_server();

    let credentials = make_credentials();
    let url = Url::parse(&format!("http://localhost:{}/resource", port)).unwrap();
    let body = "foo=bar";

    let payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
    let request = RequestBuilder::from_url("POST", &url)
        .unwrap()
        .hash(&payload_hash[..])
        .ext("ext-content")
        .request();
    let mut headers = hyper::header::Headers::new();
    let header = request.make_header(&credentials).unwrap();
    headers.set(header::Authorization(HawkScheme(header.clone())));
    headers.set(header::ContentType::plaintext());

    let client = Client::new();
    let mut res = client
        .post(url.as_str())
        .headers(headers)
        .body(body)
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    assert!(res.status == hyper::Ok);
    assert!(body == "Hello Steve ext-content");

    // validate server's signature
    {
        let server_hdr: &ServerAuthorization<HawkScheme> = res.headers.get().unwrap();
        let payload_hash = PayloadHasher::hash("text/plain".as_bytes(), &SHA256, body.as_bytes());
        let response = request
            .make_response_builder(&header)
            .hash(&payload_hash[..])
            .response();
        if !response.validate_header(&server_hdr, &credentials.key) {
            panic!("authentication of response header failed");
        }
    }

    drop(res);
    drop(client); // close the kept-alive connection

    child.wait().expect("Failure waiting for child");
}

#[test]
fn client_with_bewit() {
    let (mut child, port) = start_node_server();

    let credentials = make_credentials();
    let url = Url::parse(&format!("http://localhost:{}/resource", port)).unwrap();
    let request = RequestBuilder::from_url("GET", &url)
        .unwrap()
        .ext("ext-content")
        .request();

    let bewit = request
        .make_bewit(&credentials, time::Duration::minutes(1))
        .unwrap();
    let mut url = url.clone();
    url.set_query(Some(&format!("bewit={}", bewit.to_str())));

    let client = Client::new();
    let mut res = client.get(url.as_str()).send().unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    assert!(res.status == hyper::Ok);
    assert!(body == "Hello Steve ext-content");

    drop(res);
    drop(client); // close the kept-alive connection

    child.wait().expect("Failure waiting for child");
}
<|endoftext|>


<commit_before>use crate::graphics::math::{pow, fastpow};

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum WorkingFloatspace {
    StandardRGB,
    LinearRGB,
    Gamma
}

// Gamma correction  http://www.4p8.com/eric.brasseur/gamma.html#formulas

#[derive(Copy, Clone)]
pub struct ColorContext {
    byte_to_float: [f32; 256],
    apply_srgb: bool,
    apply_gamma: bool,
    gamma: f32,
    gamma_inverse: f32,
}

impl ColorContext{

    pub fn new(space: WorkingFloatspace, gamma: f32) -> ColorContext{
        let mut c = ColorContext{
            apply_gamma: space == WorkingFloatspace::Gamma,
            apply_srgb: space == WorkingFloatspace::StandardRGB,
            gamma,
            gamma_inverse: (1.0f64 / gamma as f64) as f32,
            byte_to_float: [0f32;256]
        };
        for n in 0..256 {
            c.byte_to_float[n] =
                c.srgb_to_floatspace_uncached(n as u8);
        }
        c
    }

    #[inline]
    pub fn srgb_to_floatspace_uncached(&self, value: u8) -> f32{
        let mut v: f32 = value as f32 * (1.0f32 / 255.0f32);
        if self.apply_srgb {
            v = srgb_to_linear(v)
        } else if self.apply_gamma {
            v = self.remove_gamma(v)
        }
        return v;
    }

    #[inline]
    pub fn remove_gamma(&self, value: f32) -> f32{
        f32::powf(value, self.gamma)
    }
    #[inline]
    pub fn apply_gamma(&self, value: f32) -> f32{
        f32::powf(value, self.gamma_inverse)
    }

    #[inline]
    pub fn srgb_to_floatspace(&self, value: u8) -> f32{
        // Safe because array length is larger than u8 max value
        unsafe {
            *self.byte_to_float.get_unchecked(value as usize)
        }
    }
    #[inline]
    pub fn floatspace_to_srgb(&self, space_value: f32) -> u8{
        let v: f32 = space_value;
        if self.apply_gamma {
            return uchar_clamp_ff(self.apply_gamma(v) * 255.0f32);
        }
        if self.apply_srgb {
            return uchar_clamp_ff(linear_to_srgb(v));
        }
        return uchar_clamp_ff(255.0f32 * v);
    }

}

#[inline]
pub fn flow_colorcontext_floatspace_to_srgb(c: &ColorContext, space_value: f32) -> u8{
    c.floatspace_to_srgb(space_value)
}

#[inline]
pub fn flow_colorcontext_srgb_to_floatspace(c: &ColorContext, value: u8) -> f32{
    c.srgb_to_floatspace(value)
}

#[inline]
fn srgb_to_linear(s: f32) -> f32 {
    if s <= 0.04045f32 {
        s / 12.92f32
    } else {
        f32::powf(
            (s + 0.055f32) / (1 as i32 as f32 + 0.055f32),
            2.4f32,
        )
    }
}
#[inline]
fn linear_to_srgb(clr: f32) -> f32 {
    if clr <= 0.0031308f32 {
        12.92f32 * clr * 255.0f32
    }else {
        1.055f32 * 255.0f32 * unsafe{ fastpow(clr, 0.41666666f32)} - 14.025f32
    }
}
#[inline]
pub(crate) fn uchar_clamp_ff(clr: f32) -> u8 {
    let mut result: u16;
    result = (clr as f64 + 0.5f64) as i16 as u16;
    if result as i32 > 255 as i32 {
        result = if clr < 0 as i32 as f32 {
            0 as i32
        } else {
            255 as i32
        } as u16
    }
    return result as u8;
}

#[inline]
#[allow(non_snake_case)]
pub unsafe fn linear_to_luv(bgr: *mut f32) {
    let xn: f32 = 0.312713f32;
    let yn: f32 = 0.329016f32;
    let Yn: f32 = 1.0f32;
    let un: f32 =
        4 as i32 as f32 * xn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let vn: f32 =
        9 as i32 as f32 * yn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let y_split: f32 = 0.00885645f32;
    let y_adjust: f32 = 903.3f32;
    let R: f32 = *bgr.offset(2);
    let G: f32 = *bgr.offset(1);
    let B: f32 = *bgr.offset(0);
    if R == 0 as i32 as f32 && G == 0 as i32 as f32 && B == 0 as i32 as f32 {
        *bgr.offset(0) = 0 as i32 as f32;
        let ref mut fresh0 = *bgr.offset(2);
        *fresh0 = 100 as i32 as f32;
        *bgr.offset(1) = *fresh0;
        return;
    }
    let X: f32 = 0.412453f32 * R + 0.35758f32 * G + 0.180423f32 * B;
    let Y: f32 = 0.212671f32 * R + 0.71516f32 * G + 0.072169f32 * B;
    let Z: f32 = 0.019334f32 * R + 0.119193f32 * G + 0.950227f32 * B;
    let Yd: f32 = Y / Yn;
    let u: f32 = 4 as i32 as f32 * X / (X + 15 as i32 as f32 * Y + 3 as i32 as f32 * Z);
    let v: f32 = 9 as i32 as f32 * Y / (X + 15 as i32 as f32 * Y + 3 as i32 as f32 * Z);
    let ref mut fresh1 = *bgr.offset(0);
    *fresh1 = if Yd > y_split {
        (116 as i32 as f32 * pow(Yd as f64, (1.0f32 / 3.0f32) as f64) as f32) - 16 as i32 as f32
    } else {
        (y_adjust) * Yd
    };
    let L: f32 = *fresh1;
    *bgr.offset(1) = 13 as i32 as f32 * L * (u - un) + 100 as i32 as f32;
    *bgr.offset(2) = 13 as i32 as f32 * L * (v - vn) + 100 as i32 as f32;
}
#[inline]
#[allow(non_snake_case)]
pub unsafe fn luv_to_linear(luv: *mut f32) {
    let L: f32 = *luv.offset(0);
    let U: f32 = *luv.offset(1) - 100.0f32;
    let V: f32 = *luv.offset(2) - 100.0f32;
    if L == 0 as i32 as f32 {
        let ref mut fresh2 = *luv.offset(2);
        *fresh2 = 0 as i32 as f32;
        let ref mut fresh3 = *luv.offset(1);
        *fresh3 = *fresh2;
        *luv.offset(0) = *fresh3;
        return;
    }
    let xn: f32 = 0.312713f32;
    let yn: f32 = 0.329016f32;
    let Yn: f32 = 1.0f32;
    let un: f32 =
        4 as i32 as f32 * xn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let vn: f32 =
        9 as i32 as f32 * yn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let y_adjust_2: f32 = 0.00110705645f32;
    let u: f32 = U / (13 as i32 as f32 * L) + un;
    let v: f32 = V / (13 as i32 as f32 * L) + vn;
    let Y: f32 = if L > 8 as i32 as f32 {
        (Yn) * pow(
            ((L + 16 as i32 as f32) / 116 as i32 as f32) as f64,
            3 as i32 as f64,
        ) as f32
    } else {
        (Yn * L) * y_adjust_2
    };
    let X: f32 = 9 as i32 as f32 / 4.0f32 * Y * u / v;
    let Z: f32 = (9 as i32 as f32 * Y - 15 as i32 as f32 * v * Y - v * X) / (3 as i32 as f32 * v);
    let r: f32 = 3.240479f32 * X - 1.53715f32 * Y - 0.498535f32 * Z;
    let g: f32 = -0.969256f32 * X + 1.875991f32 * Y + 0.041556f32 * Z;
    let b: f32 = 0.055648f32 * X - 0.204043f32 * Y + 1.057311f32 * Z;
    *luv.offset(0) = b;
    *luv.offset(1) = g;
    *luv.offset(2) = r;
}<commit_msg>Fix swapped linear/srgb conversion in Rust 2d scaling code<commit_after>use crate::graphics::math::{pow, fastpow};

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum WorkingFloatspace {
    StandardRGB,
    LinearRGB,
    Gamma
}

// Gamma correction  http://www.4p8.com/eric.brasseur/gamma.html#formulas

#[derive(Copy, Clone)]
pub struct ColorContext {
    byte_to_float: [f32; 256],
    apply_srgb: bool,
    apply_gamma: bool,
    gamma: f32,
    gamma_inverse: f32,
}

impl ColorContext{

    pub fn new(space: WorkingFloatspace, gamma: f32) -> ColorContext{
        let mut c = ColorContext{
            apply_gamma: space == WorkingFloatspace::Gamma,
            apply_srgb: space == WorkingFloatspace::LinearRGB,
            gamma,
            gamma_inverse: (1.0f64 / gamma as f64) as f32,
            byte_to_float: [0f32;256]
        };
        for n in 0..256 {
            c.byte_to_float[n] =
                c.srgb_to_floatspace_uncached(n as u8);
        }
        c
    }

    #[inline]
    pub fn srgb_to_floatspace_uncached(&self, value: u8) -> f32{
        let mut v: f32 = value as f32 * (1.0f32 / 255.0f32);
        if self.apply_srgb {
            v = srgb_to_linear(v)
        } else if self.apply_gamma {
            v = self.remove_gamma(v)
        }
        return v;
    }

    #[inline]
    pub fn remove_gamma(&self, value: f32) -> f32{
        f32::powf(value, self.gamma)
    }
    #[inline]
    pub fn apply_gamma(&self, value: f32) -> f32{
        f32::powf(value, self.gamma_inverse)
    }

    #[inline]
    pub fn srgb_to_floatspace(&self, value: u8) -> f32{
        // Safe because array length is larger than u8 max value
        unsafe {
            *self.byte_to_float.get_unchecked(value as usize)
        }
    }
    #[inline]
    pub fn floatspace_to_srgb(&self, space_value: f32) -> u8{
        let v: f32 = space_value;
        if self.apply_gamma {
            return uchar_clamp_ff(self.apply_gamma(v) * 255.0f32);
        }
        if self.apply_srgb {
            return uchar_clamp_ff(linear_to_srgb(v));
        }
        return uchar_clamp_ff(255.0f32 * v);
    }

}

#[inline]
pub fn flow_colorcontext_floatspace_to_srgb(c: &ColorContext, space_value: f32) -> u8{
    c.floatspace_to_srgb(space_value)
}

#[inline]
pub fn flow_colorcontext_srgb_to_floatspace(c: &ColorContext, value: u8) -> f32{
    c.srgb_to_floatspace(value)
}

#[inline]
fn srgb_to_linear(s: f32) -> f32 {
    if s <= 0.04045f32 {
        s / 12.92f32
    } else {
        f32::powf(
            (s + 0.055f32) / (1 as i32 as f32 + 0.055f32),
            2.4f32,
        )
    }
}
#[inline]
fn linear_to_srgb(clr: f32) -> f32 {
    if clr <= 0.0031308f32 {
        12.92f32 * clr * 255.0f32
    }else {
        1.055f32 * 255.0f32 * unsafe{ fastpow(clr, 0.41666666f32)} - 14.025f32
    }
}
#[inline]
pub(crate) fn uchar_clamp_ff(clr: f32) -> u8 {
    let mut result: u16;
    result = (clr as f64 + 0.5f64) as i16 as u16;
    if result as i32 > 255 as i32 {
        result = if clr < 0 as i32 as f32 {
            0 as i32
        } else {
            255 as i32
        } as u16
    }
    return result as u8;
}

#[inline]
#[allow(non_snake_case)]
pub unsafe fn linear_to_luv(bgr: *mut f32) {
    let xn: f32 = 0.312713f32;
    let yn: f32 = 0.329016f32;
    let Yn: f32 = 1.0f32;
    let un: f32 =
        4 as i32 as f32 * xn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let vn: f32 =
        9 as i32 as f32 * yn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let y_split: f32 = 0.00885645f32;
    let y_adjust: f32 = 903.3f32;
    let R: f32 = *bgr.offset(2);
    let G: f32 = *bgr.offset(1);
    let B: f32 = *bgr.offset(0);
    if R == 0 as i32 as f32 && G == 0 as i32 as f32 && B == 0 as i32 as f32 {
        *bgr.offset(0) = 0 as i32 as f32;
        let ref mut fresh0 = *bgr.offset(2);
        *fresh0 = 100 as i32 as f32;
        *bgr.offset(1) = *fresh0;
        return;
    }
    let X: f32 = 0.412453f32 * R + 0.35758f32 * G + 0.180423f32 * B;
    let Y: f32 = 0.212671f32 * R + 0.71516f32 * G + 0.072169f32 * B;
    let Z: f32 = 0.019334f32 * R + 0.119193f32 * G + 0.950227f32 * B;
    let Yd: f32 = Y / Yn;
    let u: f32 = 4 as i32 as f32 * X / (X + 15 as i32 as f32 * Y + 3 as i32 as f32 * Z);
    let v: f32 = 9 as i32 as f32 * Y / (X + 15 as i32 as f32 * Y + 3 as i32 as f32 * Z);
    let ref mut fresh1 = *bgr.offset(0);
    *fresh1 = if Yd > y_split {
        (116 as i32 as f32 * pow(Yd as f64, (1.0f32 / 3.0f32) as f64) as f32) - 16 as i32 as f32
    } else {
        (y_adjust) * Yd
    };
    let L: f32 = *fresh1;
    *bgr.offset(1) = 13 as i32 as f32 * L * (u - un) + 100 as i32 as f32;
    *bgr.offset(2) = 13 as i32 as f32 * L * (v - vn) + 100 as i32 as f32;
}
#[inline]
#[allow(non_snake_case)]
pub unsafe fn luv_to_linear(luv: *mut f32) {
    let L: f32 = *luv.offset(0);
    let U: f32 = *luv.offset(1) - 100.0f32;
    let V: f32 = *luv.offset(2) - 100.0f32;
    if L == 0 as i32 as f32 {
        let ref mut fresh2 = *luv.offset(2);
        *fresh2 = 0 as i32 as f32;
        let ref mut fresh3 = *luv.offset(1);
        *fresh3 = *fresh2;
        *luv.offset(0) = *fresh3;
        return;
    }
    let xn: f32 = 0.312713f32;
    let yn: f32 = 0.329016f32;
    let Yn: f32 = 1.0f32;
    let un: f32 =
        4 as i32 as f32 * xn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let vn: f32 =
        9 as i32 as f32 * yn / (-(2 as i32) as f32 * xn + 12 as i32 as f32 * yn + 3 as i32 as f32);
    let y_adjust_2: f32 = 0.00110705645f32;
    let u: f32 = U / (13 as i32 as f32 * L) + un;
    let v: f32 = V / (13 as i32 as f32 * L) + vn;
    let Y: f32 = if L > 8 as i32 as f32 {
        (Yn) * pow(
            ((L + 16 as i32 as f32) / 116 as i32 as f32) as f64,
            3 as i32 as f64,
        ) as f32
    } else {
        (Yn * L) * y_adjust_2
    };
    let X: f32 = 9 as i32 as f32 / 4.0f32 * Y * u / v;
    let Z: f32 = (9 as i32 as f32 * Y - 15 as i32 as f32 * v * Y - v * X) / (3 as i32 as f32 * v);
    let r: f32 = 3.240479f32 * X - 1.53715f32 * Y - 0.498535f32 * Z;
    let g: f32 = -0.969256f32 * X + 1.875991f32 * Y + 0.041556f32 * Z;
    let b: f32 = 0.055648f32 * X - 0.204043f32 * Y + 1.057311f32 * Z;
    *luv.offset(0) = b;
    *luv.offset(1) = g;
    *luv.offset(2) = r;
}<|endoftext|>


<commit_before>extern crate core;

#[test]
fn main()
{
	let translator = core::Translator::new();

	assert_eq!("a", translator.translate("a").as_slice());
}
<commit_msg>Tests (incomplete) fixed<commit_after>extern crate core;

#[test]
fn characters()
{
	let translator = core::Translator::new();

	assert_eq!("а", translator.translate("a"));
}

#[test]
fn words()
{
}

<|endoftext|>


<commit_before>extern crate xattr;
extern crate tempfile;

use std::collections::BTreeSet;
use std::ffi::OsStr;
use xattr::FileExt;

use tempfile::{tempfile_in, NamedTempFile};

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_fd() {
    use std::os::unix::ffi::OsStrExt;
    // Only works on "real" filesystems.
    let tmp = tempfile_in("/var/tmp").unwrap();
    assert!(tmp.get_xattr("user.test").is_err());
    assert_eq!(tmp.list_xattr()
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);

    tmp.set_xattr("user.test", b"my test").unwrap();
    assert_eq!(tmp.get_xattr("user.test").unwrap(), b"my test");
    assert_eq!(tmp.list_xattr()
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .collect::<Vec<_>>(), vec![OsStr::new("user.test")]);

    tmp.remove_xattr("user.test").unwrap();
    assert!(tmp.get_xattr("user.test").is_err());
    assert_eq!(tmp.list_xattr()
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_path() {
    use std::os::unix::ffi::OsStrExt;
    // Only works on "real" filesystems.
    let tmp = NamedTempFile::new_in("/var/tmp").unwrap();
    assert!(xattr::get(tmp.path(), "user.test").is_err());
    assert_eq!(xattr::list(tmp.path())
               .unwrap()
               .map(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);

    xattr::set(tmp.path(), "user.test", b"my test").unwrap();
    assert_eq!(xattr::get(tmp.path(), "user.test").unwrap(), b"my test");
    assert_eq!(xattr::list(tmp.path())
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .collect::<Vec<_>>(), vec![OsStr::new("user.test")]);

    xattr::remove(tmp.path(), "user.test").unwrap();
    assert!(xattr::get(tmp.path(), "user.test").is_err());
    assert_eq!(xattr::list(tmp.path())
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_multi() {
    use std::os::unix::ffi::OsStrExt;
    // Only works on "real" filesystems.
    let tmp = tempfile_in("/var/tmp").unwrap();
    let mut items: BTreeSet<_> = [
        OsStr::new("user.test1"),
        OsStr::new("user.test2"),
        OsStr::new("user.test3")
    ].iter().cloned().collect();

    for it in &items {
        tmp.set_xattr(it, b"value").unwrap();
    }
    for it in tmp.list_xattr().unwrap()
        .filter(|x| x.as_bytes().starts_with(&*b"user.")) {
        assert!(items.remove(&*it));
    }
    assert!(items.is_empty());
}
<commit_msg>Really fix tests with selinux.<commit_after>extern crate xattr;
extern crate tempfile;

use std::collections::BTreeSet;
use std::ffi::OsStr;
use xattr::FileExt;

use tempfile::{tempfile_in, NamedTempFile};

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_fd() {
    use std::os::unix::ffi::OsStrExt;
    // Only works on "real" filesystems.
    let tmp = tempfile_in("/var/tmp").unwrap();
    assert!(tmp.get_xattr("user.test").is_err());
    assert_eq!(tmp.list_xattr()
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);

    tmp.set_xattr("user.test", b"my test").unwrap();
    assert_eq!(tmp.get_xattr("user.test").unwrap(), b"my test");
    assert_eq!(tmp.list_xattr()
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .collect::<Vec<_>>(), vec![OsStr::new("user.test")]);

    tmp.remove_xattr("user.test").unwrap();
    assert!(tmp.get_xattr("user.test").is_err());
    assert_eq!(tmp.list_xattr()
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_path() {
    use std::os::unix::ffi::OsStrExt;
    // Only works on "real" filesystems.
    let tmp = NamedTempFile::new_in("/var/tmp").unwrap();
    assert!(xattr::get(tmp.path(), "user.test").is_err());
    assert_eq!(xattr::list(tmp.path())
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);

    xattr::set(tmp.path(), "user.test", b"my test").unwrap();
    assert_eq!(xattr::get(tmp.path(), "user.test").unwrap(), b"my test");
    assert_eq!(xattr::list(tmp.path())
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .collect::<Vec<_>>(), vec![OsStr::new("user.test")]);

    xattr::remove(tmp.path(), "user.test").unwrap();
    assert!(xattr::get(tmp.path(), "user.test").is_err());
    assert_eq!(xattr::list(tmp.path())
               .unwrap()
               .filter(|x| x.as_bytes().starts_with(b"user."))
               .count(), 0);
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn test_multi() {
    use std::os::unix::ffi::OsStrExt;
    // Only works on "real" filesystems.
    let tmp = tempfile_in("/var/tmp").unwrap();
    let mut items: BTreeSet<_> = [
        OsStr::new("user.test1"),
        OsStr::new("user.test2"),
        OsStr::new("user.test3")
    ].iter().cloned().collect();

    for it in &items {
        tmp.set_xattr(it, b"value").unwrap();
    }
    for it in tmp.list_xattr().unwrap()
        .filter(|x| x.as_bytes().starts_with(&*b"user.")) {
        assert!(items.remove(&*it));
    }
    assert!(items.is_empty());
}
<|endoftext|>


<commit_before>extern crate desync;
extern crate futures;

use desync::*;
use futures::stream;
use futures::executor;
use futures::sync::mpsc;

use std::sync::*;
use std::thread;
use std::time::Duration;

#[test]
fn pipe_in_simple_stream() {
    // Create a stream
    let stream  = vec![1, 2, 3];
    let stream  = stream::iter_ok(stream);

    // Create an object for the stream to be piped into
    let obj     = Arc::new(Desync::new(vec![]));

    // Pipe the stream into the object
    pipe_in(Arc::clone(&obj), stream, |core: &mut Vec<Result<i32, ()>>, item| core.push(item));

    // Once the stream is drained, the core should contain Ok(1), Ok(2), Ok(3)
    assert!(obj.sync(|core| core.clone()) == vec![Ok(1), Ok(2), Ok(3)])
}

#[test]
fn pipe_in_mpsc_receiver() {
    // Create a channel to send to the object
    let (sender, receiver) = mpsc::channel(10);

    // Create an object
    let obj = Arc::new(Desync::new(vec![]));

    // Add anything received to the vector via a pipe
    pipe_in(Arc::clone(&obj), receiver, |core, item| core.push(item.unwrap()));

    // Initially empty
    assert!(obj.sync(|core| core.clone()) == vec![]);

    // Send some values
    let mut sender = executor::spawn(sender);
    sender.wait_send(1).unwrap();
    sender.wait_send(2).unwrap();

    // Should arrive after a short delay
    thread::sleep(Duration::from_millis(10));
    assert!(obj.sync(|core| core.clone()) == vec![1, 2]);
}

#[test]
fn pipe_through() {
    // Create a channel we'll use to send data to the pipe
    let (sender, receiver) = mpsc::channel(10);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Start things running
    let mut sender      = executor::spawn(sender);
    let mut pipe_out    = executor::spawn(pipe_out);

    // Sending a value should add whatever is in the desync object
    sender.wait_send(2).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(3)));

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(43)));

    // Changing the value should change the output
    obj.async(|core| *core = 2);

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(44)));
}

#[test]
fn pipe_through_stream_closes() {
    let mut pipe_out_with_closed_stream = {
        // Create a channel we'll use to send data to the pipe
        let (sender, receiver) = mpsc::channel(10);

        // Create an object to pipe through
        let obj = Arc::new(Desync::new(1));

        // Create a pipe that adds values from the stream to the value in the object
        let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

        // Start things running
        let mut sender      = executor::spawn(sender);
        let mut pipe_out    = executor::spawn(pipe_out);

        // Sending a value should add whatever is in the desync object
        sender.wait_send(2).unwrap();
        assert!(pipe_out.wait_stream() == Some(Ok(3)));

        pipe_out
    };

    // The sender is now closed (the sender and receiver are dropped after the block above), so the pipe should close too
    assert!(pipe_out_with_closed_stream.wait_stream() == None);
}

#[test]
fn pipe_through_produces_backpressure() {
    // Create a channel we'll use to send data to the pipe
    let (mut sender, receiver) = mpsc::channel(0);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let mut pipe_out    = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Set the backpressure depth to 3
    pipe_out.set_backpressure_depth(3);

    // Start things running. We never read from this pipe here
    let _pipe_out       = executor::spawn(pipe_out);

    // Send 3 events to the pipe. Wait a bit between them to allow for processing time
    for _x in 0..3 {
        assert!(sender.try_send(1) == Ok(()));

        // The wait here allows the message to flow through to the pipe (if we call try_send again before the pipe has a chance to accept the input)
        thread::sleep(Duration::from_millis(5));
    }

    // This will stick in the channel (pipe should not be accepting more input)
    assert!(sender.try_send(2) == Ok(()));
    thread::sleep(Duration::from_millis(5));

    // Channel will push back on this one
    let channel_full = sender.try_send(3);
    assert!(channel_full.is_err());
    assert!(channel_full.unwrap_err().is_full());
}<commit_msg>No longer need the thread::sleep - pipes will process data deterministically<commit_after>extern crate desync;
extern crate futures;

use desync::*;
use futures::stream;
use futures::executor;
use futures::sync::mpsc;

use std::sync::*;
use std::thread;
use std::time::Duration;

#[test]
fn pipe_in_simple_stream() {
    // Create a stream
    let stream  = vec![1, 2, 3];
    let stream  = stream::iter_ok(stream);

    // Create an object for the stream to be piped into
    let obj     = Arc::new(Desync::new(vec![]));

    // Pipe the stream into the object
    pipe_in(Arc::clone(&obj), stream, |core: &mut Vec<Result<i32, ()>>, item| core.push(item));

    // Once the stream is drained, the core should contain Ok(1), Ok(2), Ok(3)
    assert!(obj.sync(|core| core.clone()) == vec![Ok(1), Ok(2), Ok(3)])
}

#[test]
fn pipe_in_mpsc_receiver() {
    // Create a channel to send to the object
    let (sender, receiver) = mpsc::channel(10);

    // Create an object
    let obj = Arc::new(Desync::new(vec![]));

    // Add anything received to the vector via a pipe
    pipe_in(Arc::clone(&obj), receiver, |core, item| core.push(item.unwrap()));

    // Initially empty
    assert!(obj.sync(|core| core.clone()) == vec![]);

    // Send some values
    let mut sender = executor::spawn(sender);
    sender.wait_send(1).unwrap();
    sender.wait_send(2).unwrap();

    // Should be available on the core
    assert!(obj.sync(|core| core.clone()) == vec![1, 2]);
}

#[test]
fn pipe_through() {
    // Create a channel we'll use to send data to the pipe
    let (sender, receiver) = mpsc::channel(10);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Start things running
    let mut sender      = executor::spawn(sender);
    let mut pipe_out    = executor::spawn(pipe_out);

    // Sending a value should add whatever is in the desync object
    sender.wait_send(2).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(3)));

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(43)));

    // Changing the value should change the output
    obj.async(|core| *core = 2);

    sender.wait_send(42).unwrap();
    assert!(pipe_out.wait_stream() == Some(Ok(44)));
}

#[test]
fn pipe_through_stream_closes() {
    let mut pipe_out_with_closed_stream = {
        // Create a channel we'll use to send data to the pipe
        let (sender, receiver) = mpsc::channel(10);

        // Create an object to pipe through
        let obj = Arc::new(Desync::new(1));

        // Create a pipe that adds values from the stream to the value in the object
        let pipe_out = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

        // Start things running
        let mut sender      = executor::spawn(sender);
        let mut pipe_out    = executor::spawn(pipe_out);

        // Sending a value should add whatever is in the desync object
        sender.wait_send(2).unwrap();
        assert!(pipe_out.wait_stream() == Some(Ok(3)));

        pipe_out
    };

    // The sender is now closed (the sender and receiver are dropped after the block above), so the pipe should close too
    assert!(pipe_out_with_closed_stream.wait_stream() == None);
}

#[test]
fn pipe_through_produces_backpressure() {
    // Create a channel we'll use to send data to the pipe
    let (mut sender, receiver) = mpsc::channel(0);

    // Create an object to pipe through
    let obj = Arc::new(Desync::new(1));

    // Create a pipe that adds values from the stream to the value in the object
    let mut pipe_out    = pipe(Arc::clone(&obj), receiver, |core, item: Result<i32, ()>| item.map(|item| item + *core));

    // Set the backpressure depth to 3
    pipe_out.set_backpressure_depth(3);

    // Start things running. We never read from this pipe here
    let _pipe_out       = executor::spawn(pipe_out);

    // Send 3 events to the pipe. Wait a bit between them to allow for processing time
    for _x in 0..3 {
        assert!(sender.try_send(1) == Ok(()));

        // The wait here allows the message to flow through to the pipe (if we call try_send again before the pipe has a chance to accept the input)
        thread::sleep(Duration::from_millis(5));
    }

    // This will stick in the channel (pipe should not be accepting more input)
    assert!(sender.try_send(2) == Ok(()));
    thread::sleep(Duration::from_millis(5));

    // Channel will push back on this one
    let channel_full = sender.try_send(3);
    assert!(channel_full.is_err());
    assert!(channel_full.unwrap_err().is_full());
}<|endoftext|>


<commit_before>/*
Copyright ⓒ 2016 Daniel Keep.

Licensed under the MIT license (see LICENSE or <http://opensource.org
/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
files in the project carrying such notice may not be copied, modified,
or distributed except according to those terms.
*/
/*!
Demonstrates parsing the contents of `/proc/$PID/maps`.
*/
#[macro_use] extern crate bitflags;
#[macro_use] extern crate scan_rules;
#[macro_use] mod util;

use std::ops::Range;
use scan_rules::ScanErrorKind;
use scan_rules::scanner::ScanFromStr;
use scan_rules::scanner::Hex;

const MAP_FILE: &'static str = include_str!("data/maps");

#[derive(Debug)]
struct Entry<'a> {
    pub range: Range<u64>,
    pub perm: Permissions,
    pub offset: u64,
    pub dev: Device,
    pub inode: Option<u64>,
    pub pathname: Option<&'a str>,
}

bitflags! {
    flags Permissions: u8 {
        const PERM_R = 0b1000,
        const PERM_W = 0b0100,
        const PERM_X = 0b0010,
        const PERM_S = 0b0001,
    }
}

impl<'a> ScanFromStr<'a> for Permissions {
    type Output = Self;

    fn scan_from(s: &'a str) -> Result<(Self::Output, usize), ScanErrorKind> {
        let bs = s.as_bytes();

        if bs.len() < 4 {
            return Err(ScanErrorKind::Syntax("expected permissions"));
        }

        let mut r = Permissions::empty();

        match bs[0] {
            b'r' => r = r | PERM_R,
            b'-' => (),
            _ => return Err(ScanErrorKind::Syntax("expected `r` or `-`")),
        }
        match bs[1] {
            b'w' => r = r | PERM_W,
            b'-' => (),
            _ => return Err(ScanErrorKind::Syntax("expected `w` or `-`")),
        }
        match bs[2] {
            b'x' => r = r | PERM_X,
            b'-' => (),
            _ => return Err(ScanErrorKind::Syntax("expected `x` or `-`")),
        }
        match bs[3] {
            b's' => r = r | PERM_S,
            b'p' => (),
            _ => return Err(ScanErrorKind::Syntax("expected `p` or `s`")),
        }

        Ok((r, 4))
    }
}

#[derive(Debug)]
struct Device(u8, u8);

impl<'a> ScanFromStr<'a> for Device {
    type Output = Self;

    fn scan_from(s: &'a str) -> Result<(Self::Output, usize), ScanErrorKind> {
        scan!(s;
            (let major: Hex<u8>, ":", let minor: Hex<u8>, ^..tail) => {
                (Device(major, minor), tail.offset())
            }
        ).map_err(|e| e.kind)
    }
}

#[test]
fn test_maps() {
    let entries: Vec<_> = MAP_FILE.lines()
        .map(|line| scan!(line;
            (
                let min: Hex<u64>, "-", let max: Hex<u64>,
                let perm: Permissions,
                let offset: Hex<u64>,
                let dev: Device,
                let inode: u64,
                ..tail
            ) => {
                let inode = if inode == 0 {
                    None
                } else {
                    Some(inode)
                };

                let pathname = tail.trim();
                let pathname = if pathname == "" {
                    None
                } else {
                    Some(pathname)
                };

                Entry {
                    range: min..max,
                    perm: perm,
                    offset: offset,
                    dev: dev,
                    inode: inode,
                    pathname: pathname,
                }
            }
        ))
        .filter_map(|e| {
            // Throw away entries that didn't parse.
            e.ok()
        })
        .collect();

    assert_eq!(entries.len(), 49);

    // [0]: 00400000-004ef000 r-xp 00000000 08:01 1572870 /bin/bash
    assert_match!(
        &entries[0],
        &Entry {
            range: Range { start: 0x400000, end: 0x4ef000 },
            perm: Permissions { bits: 0b1010 },
            offset: 0x00000000,
            dev: Device(0x08, 0x01),
            inode: Some(1572870),
            pathname: Some("/bin/bash"),
        }
    );

    // [3]: 006f9000-006ff000 rw-p 00000000 00:00 0
    assert_match!(
        &entries[3],
        &Entry {
            range: Range { start: 0x6f9000, end: 0x6ff000 },
            perm: Permissions { bits: 0b1100 },
            offset: 0x00000000,
            dev: Device(0x00, 0x00),
            inode: None,
            pathname: None,
        }
    );

    // [33]: 7fba16472000-7fba16671000 ---p 00025000 08:01 2888164 /lib/x86_64-linux-gnu/libtinfo.so.5.9
    assert_match!(
        &entries[33],
        &Entry {
            range: Range { start: 0x7fba16472000, end: 0x7fba16671000 },
            perm: Permissions { bits: 0b0000 },
            offset: 0x00025000,
            dev: Device(0x08, 0x01),
            inode: Some(2888164),
            pathname: Some("/lib/x86_64-linux-gnu/libtinfo.so.5.9"),
        }
    );
}
<commit_msg>Fixed maps test.<commit_after>/*
Copyright ⓒ 2016 Daniel Keep.

Licensed under the MIT license (see LICENSE or <http://opensource.org
/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
files in the project carrying such notice may not be copied, modified,
or distributed except according to those terms.
*/
/*!
Demonstrates parsing the contents of `/proc/$PID/maps`.
*/
#[macro_use] extern crate bitflags;
#[macro_use] extern crate scan_rules;
#[macro_use] mod util;

use std::ops::Range;
use scan_rules::ScanError;
use scan_rules::input::{ScanCursor, ScanInput};
use scan_rules::scanner::ScanFromStr;
use scan_rules::scanner::Hex;

const MAP_FILE: &'static str = include_str!("data/maps");

#[derive(Debug)]
struct Entry<'a> {
    pub range: Range<u64>,
    pub perm: Permissions,
    pub offset: u64,
    pub dev: Device,
    pub inode: Option<u64>,
    pub pathname: Option<&'a str>,
}

bitflags! {
    flags Permissions: u8 {
        const PERM_R = 0b1000,
        const PERM_W = 0b0100,
        const PERM_X = 0b0010,
        const PERM_S = 0b0001,
    }
}

impl<'a> ScanFromStr<'a> for Permissions {
    type Output = Self;

    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        let bs = s.as_str().as_bytes();

        if bs.len() < 4 {
            return Err(ScanError::syntax("expected permissions"));
        }

        let mut r = Permissions::empty();

        match bs[0] {
            b'r' => r = r | PERM_R,
            b'-' => (),
            _ => return Err(ScanError::syntax("expected `r` or `-`")),
        }
        match bs[1] {
            b'w' => r = r | PERM_W,
            b'-' => (),
            _ => return Err(ScanError::syntax("expected `w` or `-`")),
        }
        match bs[2] {
            b'x' => r = r | PERM_X,
            b'-' => (),
            _ => return Err(ScanError::syntax("expected `x` or `-`")),
        }
        match bs[3] {
            b's' => r = r | PERM_S,
            b'p' => (),
            _ => return Err(ScanError::syntax("expected `p` or `s`")),
        }

        Ok((r, 4))
    }
}

#[derive(Debug)]
struct Device(u8, u8);

impl<'a> ScanFromStr<'a> for Device {
    type Output = Self;

    fn scan_from<I: ScanInput<'a>>(s: I) -> Result<(Self::Output, usize), ScanError> {
        scan!(s.to_cursor();
            (let major: Hex<u8>, ":", let minor: Hex<u8>, ^..tail) => {
                (Device(major, minor), tail.offset())
            }
        )
    }
}

#[test]
fn test_maps() {
    let entries: Vec<_> = MAP_FILE.lines()
        .map(|line| scan!(line;
            (
                let min: Hex<u64>, "-", let max: Hex<u64>,
                let perm: Permissions,
                let offset: Hex<u64>,
                let dev: Device,
                let inode: u64,
                ..tail
            ) => {
                let inode = if inode == 0 {
                    None
                } else {
                    Some(inode)
                };

                let pathname = tail.trim();
                let pathname = if pathname == "" {
                    None
                } else {
                    Some(pathname)
                };

                Entry {
                    range: min..max,
                    perm: perm,
                    offset: offset,
                    dev: dev,
                    inode: inode,
                    pathname: pathname,
                }
            }
        ))
        .filter_map(|e| {
            // Throw away entries that didn't parse.
            e.ok()
        })
        .collect();

    assert_eq!(entries.len(), 49);

    // [0]: 00400000-004ef000 r-xp 00000000 08:01 1572870 /bin/bash
    assert_match!(
        &entries[0],
        &Entry {
            range: Range { start: 0x400000, end: 0x4ef000 },
            perm: Permissions { bits: 0b1010 },
            offset: 0x00000000,
            dev: Device(0x08, 0x01),
            inode: Some(1572870),
            pathname: Some("/bin/bash"),
        }
    );

    // [3]: 006f9000-006ff000 rw-p 00000000 00:00 0
    assert_match!(
        &entries[3],
        &Entry {
            range: Range { start: 0x6f9000, end: 0x6ff000 },
            perm: Permissions { bits: 0b1100 },
            offset: 0x00000000,
            dev: Device(0x00, 0x00),
            inode: None,
            pathname: None,
        }
    );

    // [33]: 7fba16472000-7fba16671000 ---p 00025000 08:01 2888164 /lib/x86_64-linux-gnu/libtinfo.so.5.9
    assert_match!(
        &entries[33],
        &Entry {
            range: Range { start: 0x7fba16472000, end: 0x7fba16671000 },
            perm: Permissions { bits: 0b0000 },
            offset: 0x00025000,
            dev: Device(0x08, 0x01),
            inode: Some(2888164),
            pathname: Some("/lib/x86_64-linux-gnu/libtinfo.so.5.9"),
        }
    );
}
<|endoftext|>


<commit_before>use std::io::Write;

#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "tail";

static FOOBAR_TXT: &'static str = "foobar.txt";

#[test]
fn test_stdin_default() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.run_piped_stdin(at.read(FOOBAR_TXT));
    assert_eq!(result.stdout, at.read("foobar_stdin_default.expected"));
}

#[test]
fn test_single_default() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.arg(FOOBAR_TXT).run();
    assert_eq!(result.stdout, at.read("foobar_single_default.expected"));
}

#[test]
fn test_single_big_args() {
    const FILE: &'static str = "single_big_args.txt";
    const EXPECTED_FILE: &'static str = "single_big_args_expected.txt";
    const LINES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = testing(UTIL_NAME);

    let mut big_input = at.make_scoped_file(FILE);
    for i in 0..LINES {
        write!(&mut big_input, "Line {}\n", i).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_scoped_file(EXPECTED_FILE);
    for i in (LINES - N_ARG)..LINES {
        write!(&mut big_expected, "Line {}\n", i).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    let result = ucmd.arg(FILE).arg("-n").arg(format!("{}", N_ARG)).run();
    assert_eq!(result.stdout, at.read(EXPECTED_FILE));
}

#[test]
fn test_bytes_single() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.arg("-c").arg("10").arg(FOOBAR_TXT).run();
    assert_eq!(result.stdout, at.read("foobar_bytes_single.expected"));
}

#[test]
fn test_bytes_stdin() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.arg("-c").arg("13").run_piped_stdin(at.read(FOOBAR_TXT));
    assert_eq!(result.stdout, at.read("foobar_bytes_stdin.expected"));
}

#[test]
fn test_bytes_big() {
    const FILE: &'static str = "test_bytes_big.txt";
    const EXPECTED_FILE: &'static str = "test_bytes_big_expected.txt";
    const BYTES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = testing(UTIL_NAME);

    let mut big_input = at.make_scoped_file(FILE);
    for i in 0..BYTES {
        let digit = std::char::from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_input, "{}", digit).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_scoped_file(EXPECTED_FILE);
    for i in (BYTES - N_ARG)..BYTES {
        let digit = std::char::from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_expected, "{}", digit).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    let result = ucmd.arg(FILE).arg("-c").arg(format!("{}", N_ARG)).run().stdout;
    let expected = at.read(EXPECTED_FILE);

    assert_eq!(result.len(), expected.len());
    for (actual_char, expected_char) in result.chars().zip(expected.chars()) {
        assert_eq!(actual_char, expected_char);
    }
}
<commit_msg>tests/tail: Test when `-n` is larger than the number of lines in the file<commit_after>use std::io::Write;

#[macro_use]
mod common;

use common::util::*;

static UTIL_NAME: &'static str = "tail";

static FOOBAR_TXT: &'static str = "foobar.txt";

#[test]
fn test_stdin_default() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.run_piped_stdin(at.read(FOOBAR_TXT));
    assert_eq!(result.stdout, at.read("foobar_stdin_default.expected"));
}

#[test]
fn test_single_default() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.arg(FOOBAR_TXT).run();
    assert_eq!(result.stdout, at.read("foobar_single_default.expected"));
}

#[test]
fn test_n_greater_than_number_of_lines() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.arg("-n").arg("99999999").arg(FOOBAR_TXT).run();
    assert_eq!(result.stdout, at.read(FOOBAR_TXT));
}

#[test]
fn test_single_big_args() {
    const FILE: &'static str = "single_big_args.txt";
    const EXPECTED_FILE: &'static str = "single_big_args_expected.txt";
    const LINES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = testing(UTIL_NAME);

    let mut big_input = at.make_scoped_file(FILE);
    for i in 0..LINES {
        write!(&mut big_input, "Line {}\n", i).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_scoped_file(EXPECTED_FILE);
    for i in (LINES - N_ARG)..LINES {
        write!(&mut big_expected, "Line {}\n", i).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    let result = ucmd.arg(FILE).arg("-n").arg(format!("{}", N_ARG)).run();
    assert_eq!(result.stdout, at.read(EXPECTED_FILE));
}

#[test]
fn test_bytes_single() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.arg("-c").arg("10").arg(FOOBAR_TXT).run();
    assert_eq!(result.stdout, at.read("foobar_bytes_single.expected"));
}

#[test]
fn test_bytes_stdin() {
    let (at, mut ucmd) = testing(UTIL_NAME);
    let result = ucmd.arg("-c").arg("13").run_piped_stdin(at.read(FOOBAR_TXT));
    assert_eq!(result.stdout, at.read("foobar_bytes_stdin.expected"));
}

#[test]
fn test_bytes_big() {
    const FILE: &'static str = "test_bytes_big.txt";
    const EXPECTED_FILE: &'static str = "test_bytes_big_expected.txt";
    const BYTES: usize = 1_000_000;
    const N_ARG: usize = 100_000;

    let (at, mut ucmd) = testing(UTIL_NAME);

    let mut big_input = at.make_scoped_file(FILE);
    for i in 0..BYTES {
        let digit = std::char::from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_input, "{}", digit).expect("Could not write to FILE");
    }
    big_input.flush().expect("Could not flush FILE");

    let mut big_expected = at.make_scoped_file(EXPECTED_FILE);
    for i in (BYTES - N_ARG)..BYTES {
        let digit = std::char::from_digit((i % 10) as u32, 10).unwrap();
        write!(&mut big_expected, "{}", digit).expect("Could not write to EXPECTED_FILE");
    }
    big_expected.flush().expect("Could not flush EXPECTED_FILE");

    let result = ucmd.arg(FILE).arg("-c").arg(format!("{}", N_ARG)).run().stdout;
    let expected = at.read(EXPECTED_FILE);

    assert_eq!(result.len(), expected.len());
    for (actual_char, expected_char) in result.chars().zip(expected.chars()) {
        assert_eq!(actual_char, expected_char);
    }
}
<|endoftext|>