<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryInto;

use seccomp::{
    allow_syscall, allow_syscall_if, BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen,
    SeccompCmpOp::Eq, SeccompCondition as Cond, SeccompError, SeccompFilter, SeccompLevel,
    SeccompRule,
};
use utils::signal::sigrtmin;

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
/// Any non-trivial modification to this allow list needs a proper comment to specify its source
/// or why the sycall/condition is needed.
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            // Called by the api thread to receive data on socket
            allow_syscall_if(
                libc::SYS_accept4,
                or![and![Cond::new(
                    3,
                    ArgLen::DWORD,
                    Eq,
                    libc::SOCK_CLOEXEC as u64
                )?],],
            ),
            // Called for expanding the heap
            allow_syscall(libc::SYS_brk),
            // Used for metrics, via the helpers in utils/src/time.rs
            allow_syscall_if(
                libc::SYS_clock_gettime,
                or![and![Cond::new(
                    0,
                    ArgLen::DWORD,
                    Eq,
                    libc::CLOCK_PROCESS_CPUTIME_ID as u64
                )?],],
            ),
            allow_syscall(libc::SYS_close),
            // Needed for vsock
            allow_syscall(libc::SYS_connect),
            allow_syscall(libc::SYS_epoll_ctl),
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(all(target_env = "gnu", target_arch = "x86_64"))]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            // Used by snapshotting, drive patching and rescanning
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, ArgLen::DWORD, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, ArgLen::DWORD, Eq, super::FCNTL_FD_CLOEXEC)?,
                ],],
            ),
            // Used for drive patching & rescanning
            allow_syscall(libc::SYS_fstat),
            // Used for snapshotting
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_ftruncate),
            // Used for synchronization
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_CMP_REQUEUE_PRIVATE
                    )?],
                ],
            ),
            // Used by glibc's tgkill
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_getpid),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            // Used by the block device
            allow_syscall(libc::SYS_lseek),
            // Triggered by musl for some customer workloads
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(
                    2,
                    ArgLen::DWORD,
                    Eq,
                    libc::MADV_DONTNEED as u64
                )?],],
            ),
            // Used for re-allocating large memory regions, for example vectors
            allow_syscall(libc::SYS_mremap),
            // Used for freeing memory
            allow_syscall(libc::SYS_munmap),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_open),
            #[cfg(target_arch = "aarch64")]
            allow_syscall(libc::SYS_openat),
            allow_syscall(libc::SYS_read),
            // Used by the API thread and vsock
            allow_syscall(libc::SYS_recvfrom),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            // Used by the API thread and vsock
            allow_syscall_if(
                libc::SYS_socket,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::AF_UNIX as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::SOCK_STREAM as u64) | (libc::SOCK_CLOEXEC as u64)
                    )?,
                    Cond::new(2, ArgLen::DWORD, Eq, 0u64)?
                ],],
            ),
            // Used to kick vcpus
            allow_syscall_if(
                libc::SYS_tkill,
                or![and![Cond::new(
                    1,
                    ArgLen::DWORD,
                    Eq,
                    (sigrtmin() + super::super::vstate::vcpu::VCPU_RTSIG_OFFSET) as u64
                )?]],
            ),
            // Used to kick vcpus, on gnu
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_tgkill),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_create,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::CLOCK_MONOTONIC as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::TFD_CLOEXEC as u64) | (libc::TFD_NONBLOCK as u64)
                    )?,
                ],],
            ),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_settime,
                or![and![Cond::new(1, ArgLen::DWORD, Eq, 0u64)?],],
            ),
            allow_syscall(libc::SYS_write),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}

/// Generate a BPF program based on a seccomp level value.
pub fn get_seccomp_filter(seccomp_level: SeccompLevel) -> Result<BpfProgram, SeccompError> {
    match seccomp_level {
        SeccompLevel::None => Ok(vec![]),
        SeccompLevel::Basic => default_filter()
            .and_then(|filter| Ok(filter.allow_all()))
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
        SeccompLevel::Advanced => default_filter()
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
    }
}

#[cfg(test)]
mod tests {
    use super::get_seccomp_filter;
    use seccomp::SeccompLevel;

    #[test]
    fn test_get_seccomp_filter() {
        assert!(get_seccomp_filter(SeccompLevel::None).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Basic).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Advanced).is_ok());
    }
}
<commit_msg>Add mmap with MAP_SHARED to allowlist<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryInto;

use seccomp::{
    allow_syscall, allow_syscall_if, BpfProgram, Error, SeccompAction, SeccompCmpArgLen as ArgLen,
    SeccompCmpOp::Eq, SeccompCondition as Cond, SeccompError, SeccompFilter, SeccompLevel,
    SeccompRule,
};
use utils::signal::sigrtmin;

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
/// Any non-trivial modification to this allow list needs a proper comment to specify its source
/// or why the sycall/condition is needed.
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            // Called by the api thread to receive data on socket
            allow_syscall_if(
                libc::SYS_accept4,
                or![and![Cond::new(
                    3,
                    ArgLen::DWORD,
                    Eq,
                    libc::SOCK_CLOEXEC as u64
                )?],],
            ),
            // Called for expanding the heap
            allow_syscall(libc::SYS_brk),
            // Used for metrics, via the helpers in utils/src/time.rs
            allow_syscall_if(
                libc::SYS_clock_gettime,
                or![and![Cond::new(
                    0,
                    ArgLen::DWORD,
                    Eq,
                    libc::CLOCK_PROCESS_CPUTIME_ID as u64
                )?],],
            ),
            allow_syscall(libc::SYS_close),
            // Needed for vsock
            allow_syscall(libc::SYS_connect),
            allow_syscall(libc::SYS_epoll_ctl),
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(all(target_env = "gnu", target_arch = "x86_64"))]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            // Used by snapshotting, drive patching and rescanning
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, ArgLen::DWORD, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, ArgLen::DWORD, Eq, super::FCNTL_FD_CLOEXEC)?,
                ],],
            ),
            // Used for drive patching & rescanning, for reading the local timezone
            allow_syscall(libc::SYS_fstat),
            // Used for snapshotting
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_ftruncate),
            // Used for synchronization
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, ArgLen::DWORD, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        super::FUTEX_CMP_REQUEUE_PRIVATE
                    )?],
                ],
            ),
            // Used by glibc's tgkill
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_getpid),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            // Used by the block device
            allow_syscall(libc::SYS_lseek),
            // Triggered by musl for some customer workloads
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(
                    2,
                    ArgLen::DWORD,
                    Eq,
                    libc::MADV_DONTNEED as u64
                )?],],
            ),
            // Used for re-allocating large memory regions, for example vectors
            allow_syscall(libc::SYS_mremap),
            // Used for freeing memory
            allow_syscall(libc::SYS_munmap),
            // Used for reading the timezone in LocalTime::now()
            allow_syscall_if(
                libc::SYS_mmap,
                or![and![Cond::new(
                    3,
                    ArgLen::DWORD,
                    Eq,
                    libc::MAP_SHARED as u64
                )?],],
            ),
            #[cfg(target_arch = "x86_64")]
            allow_syscall(libc::SYS_open),
            #[cfg(target_arch = "aarch64")]
            allow_syscall(libc::SYS_openat),
            allow_syscall(libc::SYS_read),
            // Used by the API thread and vsock
            allow_syscall(libc::SYS_recvfrom),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            // Used by the API thread and vsock
            allow_syscall_if(
                libc::SYS_socket,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::AF_UNIX as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::SOCK_STREAM as u64) | (libc::SOCK_CLOEXEC as u64)
                    )?,
                    Cond::new(2, ArgLen::DWORD, Eq, 0u64)?
                ],],
            ),
            // Used to kick vcpus
            allow_syscall_if(
                libc::SYS_tkill,
                or![and![Cond::new(
                    1,
                    ArgLen::DWORD,
                    Eq,
                    (sigrtmin() + super::super::vstate::vcpu::VCPU_RTSIG_OFFSET) as u64
                )?]],
            ),
            // Used to kick vcpus, on gnu
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_tgkill),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_create,
                or![and![
                    Cond::new(0, ArgLen::DWORD, Eq, libc::CLOCK_MONOTONIC as u64)?,
                    Cond::new(
                        1,
                        ArgLen::DWORD,
                        Eq,
                        (libc::TFD_CLOEXEC as u64) | (libc::TFD_NONBLOCK as u64)
                    )?,
                ],],
            ),
            // Needed for rate limiting
            allow_syscall_if(
                libc::SYS_timerfd_settime,
                or![and![Cond::new(1, ArgLen::DWORD, Eq, 0u64)?],],
            ),
            allow_syscall(libc::SYS_write),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}

/// Generate a BPF program based on a seccomp level value.
pub fn get_seccomp_filter(seccomp_level: SeccompLevel) -> Result<BpfProgram, SeccompError> {
    match seccomp_level {
        SeccompLevel::None => Ok(vec![]),
        SeccompLevel::Basic => default_filter()
            .and_then(|filter| Ok(filter.allow_all()))
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
        SeccompLevel::Advanced => default_filter()
            .and_then(|filter| filter.try_into())
            .map_err(SeccompError::SeccompFilter),
    }
}

#[cfg(test)]
mod tests {
    use super::get_seccomp_filter;
    use seccomp::SeccompLevel;

    #[test]
    fn test_get_seccomp_filter() {
        assert!(get_seccomp_filter(SeccompLevel::None).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Basic).is_ok());
        assert!(get_seccomp_filter(SeccompLevel::Advanced).is_ok());
    }
}
<|endoftext|>


<commit_before>extern crate difference;
extern crate file;

use std::path::{PathBuf, Path};
use std::fs::read_dir;

use difference::Changeset;

pub fn dir_tests<F>(
    paths: &[&str],
    f: F
)
where
    F: Fn(&str) -> String
{
    for path in collect_tests(paths) {
        let actual = {
            let text = file::get_text(&path).unwrap();
            f(&text)
        };
        let path = path.with_extension("txt");
        if !path.exists() {
            println!("\nfile: {}", path.display());
            println!("No .txt file with expected result, creating...");
            file::put_text(&path, actual).unwrap();
            panic!("No expected result")
        }
        let expected = file::get_text(&path).unwrap();
        let expected = expected.as_str();
        let actual = actual.as_str();
        assert_equal_text(expected, actual, &path);
    }
}

fn assert_equal_text(
    expected: &str,
    actual: &str,
    path: &Path
) {
    if expected != actual {
        print_difference(expected, actual, path)
    }
}

fn collect_tests(paths: &[&str]) -> Vec<PathBuf> {
    paths.iter().flat_map(|path|  {
        let path = test_data_dir().join(path);
        test_from_dir(&path).into_iter()
    }).collect()
}

fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
    let mut acc = Vec::new();
    for file in read_dir(&dir).unwrap() {
        let file = file.unwrap();
        let path = file.path();
        if path.extension().unwrap_or_default() == "rs" {
            acc.push(path);
        }
    }
    acc.sort();
    acc
}

fn print_difference(expected: &str, actual: &str, path: &Path) {
    let dir = project_dir();
    let path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
    println!("\nfile: {}", path.display());
    if expected.trim() == actual.trim() {
        println!("whitespace difference");
        println!("rewriting the file");
        file::put_text(path, actual).unwrap();
    } else {
        let changeset = Changeset::new(actual, expected, "\n");
        println!("{}", changeset);
    }
    panic!("Comparison failed")
}

fn project_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir)
        .parent().unwrap()
        .parent().unwrap()
        .to_owned()
}

fn test_data_dir() -> PathBuf {
    project_dir().join("tests/data")
}<commit_msg>Normalize test newlines<commit_after>extern crate difference;
extern crate file;

use std::path::{PathBuf, Path};
use std::fs::read_dir;

use difference::Changeset;

/// Read file and normalize newlines.
///
/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
///
/// ```
/// let s = "
/// ";
/// assert_eq!(s.as_bytes(), &[10]);
/// ```
///
/// so this should always be correct.
fn read_text(path: &Path) -> String {
    file::get_text(path).unwrap().replace("\r\n", "\n")
}

pub fn dir_tests<F>(
    paths: &[&str],
    f: F
)
where
    F: Fn(&str) -> String
{
    for path in collect_tests(paths) {
        let actual = {
            let text = read_text(&path);
            f(&text)
        };
        let path = path.with_extension("txt");
        if !path.exists() {
            println!("\nfile: {}", path.display());
            println!("No .txt file with expected result, creating...");
            file::put_text(&path, actual).unwrap();
            panic!("No expected result")
        }
        let expected = read_text(&path);
        let expected = expected.as_str();
        let actual = actual.as_str();
        assert_equal_text(expected, actual, &path);
    }
}

fn assert_equal_text(
    expected: &str,
    actual: &str,
    path: &Path
) {
    if expected != actual {
        print_difference(expected, actual, path)
    }
}

fn collect_tests(paths: &[&str]) -> Vec<PathBuf> {
    paths.iter().flat_map(|path|  {
        let path = test_data_dir().join(path);
        test_from_dir(&path).into_iter()
    }).collect()
}

fn test_from_dir(dir: &Path) -> Vec<PathBuf> {
    let mut acc = Vec::new();
    for file in read_dir(&dir).unwrap() {
        let file = file.unwrap();
        let path = file.path();
        if path.extension().unwrap_or_default() == "rs" {
            acc.push(path);
        }
    }
    acc.sort();
    acc
}

fn print_difference(expected: &str, actual: &str, path: &Path) {
    let dir = project_dir();
    let path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
    println!("\nfile: {}", path.display());
    if expected.trim() == actual.trim() {
        println!("whitespace difference");
        println!("rewriting the file");
        file::put_text(path, actual).unwrap();
    } else {
        let changeset = Changeset::new(actual, expected, "\n");
        println!("{}", changeset);
    }
    panic!("Comparison failed")
}

fn project_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir)
        .parent().unwrap()
        .parent().unwrap()
        .to_owned()
}

fn test_data_dir() -> PathBuf {
    project_dir().join("tests/data")
}<|endoftext|>


<commit_before>extern crate glutin;
#[macro_use]
extern crate glium;

use glium::{Texture, Surface};

mod support;

#[test]
fn texture_2d_read() {
    let display = support::build_display();

    // we use only powers of two, in order to avoid float rounding errors
    let texture = glium::texture::Texture2d::new(&display, vec![
        vec![(0u8, 1u8, 2u8), (4u8, 8u8, 16u8)],
        vec![(32u8, 64u8, 128u8), (32u8, 16u8, 4u8)],
    ]);

    let read_back: Vec<Vec<(u8, u8, u8)>> = texture.read();

    assert_eq!(read_back[0][0], (0, 1, 2));
    assert_eq!(read_back[0][1], (4, 8, 16));
    assert_eq!(read_back[1][0], (32, 64, 128));
    assert_eq!(read_back[1][1], (32, 16, 4));

    display.assert_no_error();
}

#[test]
#[should_fail]
fn empty_pixel_buffer() {
    let display = support::build_display();

    let pixel_buffer = glium::pixel_buffer::PixelBuffer::new_empty(&display, 128 * 128);
    display.assert_no_error();

    let _: Vec<Vec<(u8, u8, u8)>> = pixel_buffer.read_if_supported().unwrap();
}

#[test]
fn texture_2d_read_pixelbuffer() {
    let display = support::build_display();

    // we use only powers of two, in order to avoid float rounding errors
    let texture = glium::texture::Texture2d::new(&display, vec![
        vec![(0u8, 1u8, 2u8), (4u8, 8u8, 16u8)],
        vec![(32u8, 64u8, 128u8), (32u8, 16u8, 4u8)],
    ]);

    let read_back: Vec<Vec<(u8, u8, u8)>> = match texture.read_to_pixel_buffer()
                                                         .read_if_supported() {
        Some(d) => d,
        None => return
    };

    assert_eq!(read_back[0][0], (0, 1, 2));
    assert_eq!(read_back[0][1], (4, 8, 16));
    assert_eq!(read_back[1][0], (32, 64, 128));
    assert_eq!(read_back[1][1], (32, 16, 4));

    display.assert_no_error();
}
<commit_msg>Add texture reading tests<commit_after>extern crate glutin;
#[macro_use]
extern crate glium;

use glium::{Texture, Surface};

mod support;

#[test]
#[should_fail]
fn empty_pixel_buffer() {
    let display = support::build_display();

    let pixel_buffer = glium::pixel_buffer::PixelBuffer::new_empty(&display, 128 * 128);
    display.assert_no_error();

    let _: Vec<Vec<(u8, u8, u8)>> = pixel_buffer.read_if_supported().unwrap();
}

#[test]
fn texture_2d_read_pixelbuffer() {
    let display = support::build_display();

    // we use only powers of two, in order to avoid float rounding errors
    let texture = glium::texture::Texture2d::new(&display, vec![
        vec![(0u8, 1u8, 2u8), (4u8, 8u8, 16u8)],
        vec![(32u8, 64u8, 128u8), (32u8, 16u8, 4u8)],
    ]);

    let read_back: Vec<Vec<(u8, u8, u8)>> = match texture.read_to_pixel_buffer()
                                                         .read_if_supported() {
        Some(d) => d,
        None => return
    };

    assert_eq!(read_back[0][0], (0, 1, 2));
    assert_eq!(read_back[0][1], (4, 8, 16));
    assert_eq!(read_back[1][0], (32, 64, 128));
    assert_eq!(read_back[1][1], (32, 16, 4));

    display.assert_no_error();
}

macro_rules! read_texture_test {
    ($test_name:ident, $tex_ty:ident, $data_ty:ty, $data:expr) => (
        #[test]
        fn $test_name() {
            let display = support::build_display();

            let texture = glium::texture::$tex_ty::new(&display, $data);

            let read_back: Vec<Vec<$data_ty>> = texture.read();

            assert_eq!(read_back, $data);

            display.assert_no_error();
        }
    );

    ($test_name:ident, maybe $tex_ty:ident, $data_ty:ty, $data:expr) => (
        #[test]
        fn $test_name() {
            let display = support::build_display();

            let texture = match glium::texture::$tex_ty::new_if_supported(&display, $data) {
                Some(t) => t,
                None => return
            };

            let read_back: Vec<Vec<$data_ty>> = texture.read();

            assert_eq!(read_back, $data);

            display.assert_no_error();
        }
    );
}

/*read_texture_test!(read_compressedtexture1d, CompressedTexture1d, (u8, u8, u8, u8),
    vec![(0, 1, 2, 3), (4, 5, 6, 7)]);
read_texture_test!(read_compressedtexture1darray, CompressedTexture1dArray, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_compressedtexture2d, CompressedTexture2d, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_compressedtexture2darray, CompressedTexture2dArray, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_compressedtexture3d, CompressedTexture3d, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);*/
/*read_texture_test!(read_depthstenciltexture1d, maybe DepthStencilTexture1d, (u8, u8, u8, u8),
    vec![(0, 1, 2, 3), (4, 5, 6, 7)]);
read_texture_test!(read_depthstenciltexture1darray, maybe DepthStencilTexture1dArray, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_depthstenciltexture2d, maybe DepthStencilTexture2d, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_depthstenciltexture2darray, maybe DepthStencilTexture2dArray, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_depthstenciltexture3d, DepthStencilTexture3d, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);]*/
/*read_texture_test!(read_depthtexture1d, maybe DepthTexture1d, f32,
    vec![2.0, 3.0]);
read_texture_test!(read_depthtexture1darray, maybe DepthTexture1dArray, f32,
    vec![vec![2.0, 3.0], vec![16.0, 18.0]]);
read_texture_test!(read_depthtexture2d, maybe DepthTexture2d, f32,
    vec![vec![2.0, 3.0], vec![16.0, 18.0]]);
read_texture_test!(read_depthtexture2darray, maybe DepthTexture2dArray, f32,
    vec![vec![2.0, 3.0], vec![16.0, 18.0]]);
read_texture_test!(read_depthtexture3d, DepthTexture3d, f32,
    vec![vec![2.0, 3.0], vec![16.0, 18.0]]);
read_texture_test!(read_integraltexture1d, maybe IntegralTexture1d, (u8, u8, u8, u8),
    vec![(0, 1, 2, 3), (4, 5, 6, 7)]);
read_texture_test!(read_integraltexture1darray, maybe IntegralTexture1dArray, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_integraltexture2d, maybe IntegralTexture2d, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_integraltexture2darray, maybe IntegralTexture2dArray, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_integraltexture3d, maybe IntegralTexture3d, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_stenciltexture1d, maybe StencilTexture1d, (u8, u8, u8, u8),
    vec![(0, 1, 2, 3), (4, 5, 6, 7)]);
read_texture_test!(read_stenciltexture1darray, maybe StencilTexture1dArray, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_stenciltexture2d, maybe StencilTexture2d, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_stenciltexture2darray, maybe StencilTexture2dArray, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_stenciltexture3d, maybe StencilTexture3d, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_texture1d, Texture1d, (u8, u8, u8, u8),
    vec![(0, 1, 2, 3), (4, 5, 6, 7)]);
read_texture_test!(read_texture1darray, Texture1dArray, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);*/
read_texture_test!(read_texture2d, Texture2d, (u8, u8, u8, u8),
    vec![
        vec![(0u8, 1u8, 2u8, 3u8), (4u8, 5u8, 6u8, 7u8)],
        vec![(8u8, 9u8, 10u8, 11u8), (12u8, 13u8, 14u8, 15u8)]
    ]);
/*read_texture_test!(read_texture2darray, Texture2dArray, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_texture3d, Texture3d, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_unsignedtexture1d, maybe UnsignedTexture1d, (u8, u8, u8, u8),
    vec![(0, 1, 2, 3), (4, 5, 6, 7)]);
read_texture_test!(read_unsignedtexture1darray, maybe UnsignedTexture1dArray, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_unsignedtexture2d, maybe UnsignedTexture2d, (u8, u8, u8, u8),
    vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]);
read_texture_test!(read_unsignedtexture2darray, maybe UnsignedTexture2dArray, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);
read_texture_test!(read_unsignedtexture3d, maybe UnsignedTexture3d, (u8, u8, u8, u8),
    vec![vec![vec![(0, 1, 2, 3), (4, 5, 6, 7)], vec![(8, 9, 10, 11), (12, 13, 14, 15)]]]);*/
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};
use std::io;
use std::ptr;
use super::ipv4_header::IPv4Header;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};

struct IPv4PacketBuffer {
    buf: [u8; MAX_PACKET_LENGTH],
    head: usize,
}

impl IPv4PacketBuffer {
    fn new() -> IPv4PacketBuffer {
        IPv4PacketBuffer {
            buf: [0; MAX_PACKET_LENGTH],
            head: 0,
        }
    }

    fn read_from<R: io::Read>(&mut self, source: &mut R) -> io::Result<()> {
        let r = source.read(&mut self.buf[self.head..])?;
        self.head += r;
        Ok(())
    }

    fn get_available_packet_length(&self) -> Option<u16> {
        let length = IPv4Header::read_length(&self.buf);
        match length {
            // no packet
            None => None,
            // no full packet available
            Some(len) if len > self.head as u16 => None,
            // full packet available
            length => length
        }
    }

    pub fn as_ipv4_packet<'a>(&'a mut self) -> Option<IPv4Packet<'a>> {
        let length = self.get_available_packet_length();
        if let Some(len) = length {
            Some(IPv4Packet::new(&mut self.buf[..len as usize]))
        } else {
            None
        }
    }

    pub fn next(&mut self) {
        // remove the packet in front of the buffer
        let length = self.get_available_packet_length()
                .expect("next() called while there was no packet") as usize;
        self.head -= length;
        unsafe {
            let buf_ptr = self.buf.as_mut_ptr();
            // semantically equivalent to memmove()
            ptr::copy(buf_ptr.offset(length as isize), buf_ptr, length);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io;
    use byteorder::{BigEndian, WriteBytesExt};
    use ::relay::ipv4_header::Protocol;
    use ::relay::transport_header::TransportHeader;

    fn create_packet() -> Vec<u8> {
        let mut raw: Vec<u8> = vec![];
        raw.reserve(32);
        raw.write_u8(4u8 << 4 | 5).unwrap();
        raw.write_u8(0).unwrap(); // ToS
        raw.write_u16::<BigEndian>(32); // total length 20 + 8 + 4
        raw.write_u32::<BigEndian>(0); // id_flags_fragment_offset
        raw.write_u8(0).unwrap(); // TTL
        raw.write_u8(17).unwrap(); // protocol (UDP)
        raw.write_u16::<BigEndian>(0).unwrap(); // checksum
        raw.write_u32::<BigEndian>(0x12345678).unwrap(); // source address
        raw.write_u32::<BigEndian>(0x42424242).unwrap(); // destination address

        raw.write_u16::<BigEndian>(1234).unwrap(); // source port
        raw.write_u16::<BigEndian>(5678).unwrap(); // destination port
        raw.write_u16::<BigEndian>(12).unwrap(); // length
        raw.write_u16::<BigEndian>(0).unwrap(); // checksum

        raw.write_u32::<BigEndian>(0x11223344).unwrap(); // payload

        raw
    }

    fn check_packet_headers(ipv4_packet: &IPv4Packet) {
        let ipv4_header = &ipv4_packet.ipv4_header;
        assert_eq!(20, ipv4_header.header_length);
        assert_eq!(32, ipv4_header.total_length);
        assert_eq!(Protocol::UDP, ipv4_header.protocol);
        assert_eq!(0x12345678, ipv4_header.source);
        assert_eq!(0x42424242, ipv4_header.destination);

        if let Some(TransportHeader::UDP(ref udp_header)) = ipv4_packet.transport_header {
            assert_eq!(1234, udp_header.source_port);
            assert_eq!(5678, udp_header.destination_port);
        } else {
            panic!("No UDP transport header");
        }
    }

    #[test]
    fn parse_ipv4_packet_buffer() {
        let raw = create_packet();
        let mut packet_buffer = IPv4PacketBuffer::new();
        let mut cursor = io::Cursor::new(raw);

        packet_buffer.read_from(&mut cursor).unwrap();

        let packet = packet_buffer.as_ipv4_packet().unwrap();
        check_packet_headers(&packet);
    }

    #[test]
    fn parse_fragmented_ipv4_packet_buffer() {
        let raw = create_packet();
        let mut packet_buffer = IPv4PacketBuffer::new();

        let mut cursor = io::Cursor::new(&raw[..14]);
        packet_buffer.read_from(&mut cursor).unwrap();

        assert!(packet_buffer.as_ipv4_packet().is_none());

        let mut cursor = io::Cursor::new(&raw[14..]);
        packet_buffer.read_from(&mut cursor).unwrap();

        let packet = packet_buffer.as_ipv4_packet().unwrap();
        check_packet_headers(&packet);
    }
}
<commit_msg>More tests for IPv4PacketBuffer<commit_after>use byteorder::{BigEndian, ByteOrder};
use std::io;
use std::ptr;
use super::ipv4_header::IPv4Header;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};

struct IPv4PacketBuffer {
    buf: [u8; MAX_PACKET_LENGTH],
    head: usize,
}

impl IPv4PacketBuffer {
    fn new() -> IPv4PacketBuffer {
        IPv4PacketBuffer {
            buf: [0; MAX_PACKET_LENGTH],
            head: 0,
        }
    }

    fn read_from<R: io::Read>(&mut self, source: &mut R) -> io::Result<()> {
        let r = source.read(&mut self.buf[self.head..])?;
        self.head += r;
        Ok(())
    }

    fn get_available_packet_length(&self) -> Option<u16> {
        let length = IPv4Header::read_length(&self.buf);
        match length {
            // no packet
            None => None,
            // no full packet available
            Some(len) if len > self.head as u16 => None,
            // full packet available
            length => length
        }
    }

    pub fn as_ipv4_packet<'a>(&'a mut self) -> Option<IPv4Packet<'a>> {
        let length = self.get_available_packet_length();
        if let Some(len) = length {
            Some(IPv4Packet::new(&mut self.buf[..len as usize]))
        } else {
            None
        }
    }

    pub fn next(&mut self) {
        // remove the packet in front of the buffer
        let length = self.get_available_packet_length()
                .expect("next() called while there was no packet") as usize;
        self.head -= length;
        unsafe {
            let buf_ptr = self.buf.as_mut_ptr();
            // semantically equivalent to memmove()
            ptr::copy(buf_ptr.offset(length as isize), buf_ptr, length);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io;
    use byteorder::{BigEndian, WriteBytesExt};
    use ::relay::ipv4_header::Protocol;
    use ::relay::transport_header::TransportHeader;

    fn create_packet() -> Vec<u8> {
        let mut raw: Vec<u8> = vec![];
        write_packet_to(&mut raw);
        raw
    }

    fn write_packet_to(raw: &mut Vec<u8>) {
        raw.write_u8(4u8 << 4 | 5).unwrap();
        raw.write_u8(0).unwrap(); // ToS
        raw.write_u16::<BigEndian>(32); // total length 20 + 8 + 4
        raw.write_u32::<BigEndian>(0); // id_flags_fragment_offset
        raw.write_u8(0).unwrap(); // TTL
        raw.write_u8(17).unwrap(); // protocol (UDP)
        raw.write_u16::<BigEndian>(0).unwrap(); // checksum
        raw.write_u32::<BigEndian>(0x12345678).unwrap(); // source address
        raw.write_u32::<BigEndian>(0x42424242).unwrap(); // destination address

        raw.write_u16::<BigEndian>(1234).unwrap(); // source port
        raw.write_u16::<BigEndian>(5678).unwrap(); // destination port
        raw.write_u16::<BigEndian>(12).unwrap(); // length
        raw.write_u16::<BigEndian>(0).unwrap(); // checksum

        raw.write_u32::<BigEndian>(0x11223344).unwrap(); // payload
    }

    fn check_packet_headers(ipv4_packet: &IPv4Packet) {
        let ipv4_header = &ipv4_packet.ipv4_header;
        assert_eq!(20, ipv4_header.header_length);
        assert_eq!(32, ipv4_header.total_length);
        assert_eq!(Protocol::UDP, ipv4_header.protocol);
        assert_eq!(0x12345678, ipv4_header.source);
        assert_eq!(0x42424242, ipv4_header.destination);

        if let Some(TransportHeader::UDP(ref udp_header)) = ipv4_packet.transport_header {
            assert_eq!(1234, udp_header.source_port);
            assert_eq!(5678, udp_header.destination_port);
        } else {
            panic!("No UDP transport header");
        }
    }

    #[test]
    fn parse_ipv4_packet_buffer() {
        let raw = create_packet();
        let mut packet_buffer = IPv4PacketBuffer::new();

        let mut cursor = io::Cursor::new(raw);
        packet_buffer.read_from(&mut cursor).unwrap();

        let packet = packet_buffer.as_ipv4_packet().unwrap();
        check_packet_headers(&packet);
    }

    #[test]
    fn parse_fragmented_ipv4_packet_buffer() {
        let raw = create_packet();
        let mut packet_buffer = IPv4PacketBuffer::new();

        let mut cursor = io::Cursor::new(&raw[..14]);
        packet_buffer.read_from(&mut cursor).unwrap();

        assert!(packet_buffer.as_ipv4_packet().is_none());

        let mut cursor = io::Cursor::new(&raw[14..]);
        packet_buffer.read_from(&mut cursor).unwrap();

        let packet = packet_buffer.as_ipv4_packet().unwrap();
        check_packet_headers(&packet);
    }

    fn create_multi_packets() -> Vec<u8> {
        let mut raw: Vec<u8> = vec![];
        for i in 0..3 {
            write_packet_to(&mut raw);
        }
        raw
    }

    #[test]
    fn parse_multi_packets() {
        let raw = create_multi_packets();
        let mut packet_buffer = IPv4PacketBuffer::new();

        let mut cursor = io::Cursor::new(raw);
        packet_buffer.read_from(&mut cursor).unwrap();

        for i in 0..3 {
            {
                let packet = packet_buffer.as_ipv4_packet().unwrap();
                check_packet_headers(&packet);
            }
            packet_buffer.next();
        }

        assert!(packet_buffer.as_ipv4_packet().is_none());
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that we reliably check the value of the associated type.

#![crate_type = "lib"]
#![feature(associated_types)]
#![no_implicit_prelude]

use std::option::Option::{None, Some, mod};
use std::vec::Vec;

trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
}

fn is_iterator_of<A, I: Iterator<Item=A>>(_: &I) {}

struct Adapter<I> {
    iter: I,
    found_none: bool,
}

impl<T, I> Iterator for Adapter<I> where I: Iterator<Item=Option<T>> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        loop {}
    }
}

fn test_adapter<T, I: Iterator<Item=Option<T>>>(it: I) {
    is_iterator_of::<Option<T>, _>(&it);  // Sanity check
    let adapter = Adapter { iter: it, found_none: false };
    is_iterator_of::<T, _>(&adapter); // OK
    is_iterator_of::<Option<T>, _>(&adapter); //~ ERROR type mismatch
}
<commit_msg>Rebasing<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that we reliably check the value of the associated type.

#![crate_type = "lib"]
#![feature(associated_types)]
#![no_implicit_prelude]

use std::option::Option::{self, None, Some};
use std::vec::Vec;

trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
}

fn is_iterator_of<A, I: Iterator<Item=A>>(_: &I) {}

struct Adapter<I> {
    iter: I,
    found_none: bool,
}

impl<T, I> Iterator for Adapter<I> where I: Iterator<Item=Option<T>> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        loop {}
    }
}

fn test_adapter<T, I: Iterator<Item=Option<T>>>(it: I) {
    is_iterator_of::<Option<T>, _>(&it);  // Sanity check
    let adapter = Adapter { iter: it, found_none: false };
    is_iterator_of::<T, _>(&adapter); // OK
    is_iterator_of::<Option<T>, _>(&adapter); //~ ERROR type mismatch
}
<|endoftext|>


<commit_before>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_enum: fold_enum
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    ~{
        topmod: ~{
            name: option::from_maybe(doc.topmod.name, attrs.name)
            with *doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let source = "#[link(name = \"bond\")];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_crate(fold, doc);
    assert doc.topmod.name == "bond";
}

fn parse_item_attrs<T>(
    srv: astsrv::srv,
    id: doc::ast_id,
    parse_attrs: fn~([ast::attribute]) -> T) -> T {
    astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.ast_map.get(id) {
          ast_map::node_item(item) { item.attrs }
        };
        parse_attrs(attrs)
    }
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let srv = fold.ctxt;
    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_mod(ctxt.ast.node.attrs)
        }
    } else {
        parse_item_attrs(srv, doc.id, attr_parser::parse_mod)
    };
    let doc = fold::default_seq_fold_mod(fold, doc);
    ret merge_mod_attrs(doc, attrs);

    fn merge_mod_attrs(
        doc: doc::moddoc,
        attrs: attr_parser::mod_attrs
    ) -> doc::moddoc {
        ~{
            brief: attrs.brief,
            desc: attrs.desc
            with *doc
        }
    }
}

#[test]
fn fold_mod_should_extract_mod_attributes() {
    let source = "#[doc = \"test\"] mod a { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod.mods[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_mod_should_extract_top_mod_attributes() {
    let source = "#[doc = \"test\"];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod);
    assert doc.desc == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_fn);
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret ~{
            brief: attrs.brief,
            desc: attrs.desc,
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return),
            failure: attrs.failure
            with *doc
        };
    }

    fn merge_arg_attrs(
        docs: [doc::argdoc],
        attrs: [attr_parser::arg_attrs]
    ) -> [doc::argdoc] {
        vec::map(docs) {|doc|
            alt vec::find(attrs) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    ~{
                        desc: some(attr.desc)
                        with *doc
                    }
                }
                none { doc }
            }
        }
        // FIXME: Warning when documenting a non-existent arg
    }

    fn merge_ret_attrs(
        doc: doc::retdoc,
        attrs: option<str>
    ) -> doc::retdoc {
        {
            desc: attrs
            with doc
        }
    }
}

#[test]
fn fold_fn_should_extract_fn_attributes() {
    let source = "#[doc = \"test\"] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_fn_should_extract_arg_attributes() {
    let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.args[0].desc == some("b");
}

#[test]
fn fold_fn_should_extract_return_attributes() {
    let source = "#[doc(return = \"what\")] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.return.desc == some("what");
}

#[test]
fn fold_fn_should_preserve_sig() {
    let source = "fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.sig == some("fn a() -> int");
}

#[test]
fn fold_fn_should_extract_failure_conditions() {
    let source = "#[doc(failure = \"what\")] fn a() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.failure == some("what");
}

fn fold_const(
    fold: fold::fold<astsrv::srv>,
    doc: doc::constdoc
) -> doc::constdoc {
    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_mod);

    ~{
        brief: attrs.brief,
        desc: attrs.desc
        with *doc
    }
}

#[test]
fn fold_const_should_extract_docs() {
    let source = "#[doc(brief = \"foo\", desc = \"bar\")]\
                  const a: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_const(fold, doc.topmod.consts[0]);
    assert doc.brief == some("foo");
    assert doc.desc == some("bar");
}

fn fold_enum(
    fold: fold::fold<astsrv::srv>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_enum);

    ~{
        brief: attrs.brief,
        desc: attrs.desc,
        variants: vec::map(doc.variants) {|variant|
            let attrs = astsrv::exec(srv) {|ctxt|
                alt ctxt.ast_map.get(doc.id) {
                  ast_map::node_item(@{
                    node: ast::item_enum(ast_variants, _), _
                  }) {
                    let ast_variant = option::get(
                        vec::find(ast_variants) {|v|
                            v.node.name == variant.name
                        });

                    attr_parser::parse_variant(ast_variant.node.attrs)
                  }
                }
            };

            ~{
                desc: attrs.desc
                with *variant
            }
        }
        with *doc
    }
}

#[test]
fn fold_enum_should_extract_docs() {
    let source = "#[doc(brief = \"a\", desc = \"b\")]\
                  enum a { v }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_enum(fold, doc.topmod.enums[0]);
    assert doc.brief == some("a");
    assert doc.desc == some("b");
}

#[test]
fn fold_enum_should_extract_variant_docs() {
    let source = "enum a { #[doc = \"c\"] v }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_enum(fold, doc.topmod.enums[0]);
    assert doc.variants[0].desc == some("c");
}
<commit_msg>rustdoc: Add resource attribute docs to the doc tree<commit_after>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_mod: fold_mod,
        fold_fn: fold_fn,
        fold_const: fold_const,
        fold_enum: fold_enum,
        fold_res: fold_res
        with *fold::default_seq_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    ~{
        topmod: ~{
            name: option::from_maybe(doc.topmod.name, attrs.name)
            with *doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let source = "#[link(name = \"bond\")];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_crate(fold, doc);
    assert doc.topmod.name == "bond";
}

fn parse_item_attrs<T>(
    srv: astsrv::srv,
    id: doc::ast_id,
    parse_attrs: fn~([ast::attribute]) -> T) -> T {
    astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.ast_map.get(id) {
          ast_map::node_item(item) { item.attrs }
        };
        parse_attrs(attrs)
    }
}

fn fold_mod(fold: fold::fold<astsrv::srv>, doc: doc::moddoc) -> doc::moddoc {
    let srv = fold.ctxt;
    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_mod(ctxt.ast.node.attrs)
        }
    } else {
        parse_item_attrs(srv, doc.id, attr_parser::parse_mod)
    };
    let doc = fold::default_seq_fold_mod(fold, doc);
    ret merge_mod_attrs(doc, attrs);

    fn merge_mod_attrs(
        doc: doc::moddoc,
        attrs: attr_parser::mod_attrs
    ) -> doc::moddoc {
        ~{
            brief: attrs.brief,
            desc: attrs.desc
            with *doc
        }
    }
}

#[test]
fn fold_mod_should_extract_mod_attributes() {
    let source = "#[doc = \"test\"] mod a { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod.mods[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_mod_should_extract_top_mod_attributes() {
    let source = "#[doc = \"test\"];";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_mod(fold, doc.topmod);
    assert doc.desc == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_fn);
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret ~{
            brief: attrs.brief,
            desc: attrs.desc,
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return),
            failure: attrs.failure
            with *doc
        };
    }

    fn merge_arg_attrs(
        docs: [doc::argdoc],
        attrs: [attr_parser::arg_attrs]
    ) -> [doc::argdoc] {
        vec::map(docs) {|doc|
            alt vec::find(attrs) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    ~{
                        desc: some(attr.desc)
                        with *doc
                    }
                }
                none { doc }
            }
        }
        // FIXME: Warning when documenting a non-existent arg
    }

    fn merge_ret_attrs(
        doc: doc::retdoc,
        attrs: option<str>
    ) -> doc::retdoc {
        {
            desc: attrs
            with doc
        }
    }
}

#[test]
fn fold_fn_should_extract_fn_attributes() {
    let source = "#[doc = \"test\"] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.desc == some("test");
}

#[test]
fn fold_fn_should_extract_arg_attributes() {
    let source = "#[doc(args(a = \"b\"))] fn c(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.args[0].desc == some("b");
}

#[test]
fn fold_fn_should_extract_return_attributes() {
    let source = "#[doc(return = \"what\")] fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.return.desc == some("what");
}

#[test]
fn fold_fn_should_preserve_sig() {
    let source = "fn a() -> int { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let doc = tystr_pass::mk_pass()(srv, doc);
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.sig == some("fn a() -> int");
}

#[test]
fn fold_fn_should_extract_failure_conditions() {
    let source = "#[doc(failure = \"what\")] fn a() { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_fn(fold, doc.topmod.fns[0]);
    assert doc.failure == some("what");
}

fn fold_const(
    fold: fold::fold<astsrv::srv>,
    doc: doc::constdoc
) -> doc::constdoc {
    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_mod);

    ~{
        brief: attrs.brief,
        desc: attrs.desc
        with *doc
    }
}

#[test]
fn fold_const_should_extract_docs() {
    let source = "#[doc(brief = \"foo\", desc = \"bar\")]\
                  const a: bool = true;";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_const(fold, doc.topmod.consts[0]);
    assert doc.brief == some("foo");
    assert doc.desc == some("bar");
}

fn fold_enum(
    fold: fold::fold<astsrv::srv>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_enum);

    ~{
        brief: attrs.brief,
        desc: attrs.desc,
        variants: vec::map(doc.variants) {|variant|
            let attrs = astsrv::exec(srv) {|ctxt|
                alt ctxt.ast_map.get(doc.id) {
                  ast_map::node_item(@{
                    node: ast::item_enum(ast_variants, _), _
                  }) {
                    let ast_variant = option::get(
                        vec::find(ast_variants) {|v|
                            v.node.name == variant.name
                        });

                    attr_parser::parse_variant(ast_variant.node.attrs)
                  }
                }
            };

            ~{
                desc: attrs.desc
                with *variant
            }
        }
        with *doc
    }
}

#[test]
fn fold_enum_should_extract_docs() {
    let source = "#[doc(brief = \"a\", desc = \"b\")]\
                  enum a { v }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_enum(fold, doc.topmod.enums[0]);
    assert doc.brief == some("a");
    assert doc.desc == some("b");
}

#[test]
fn fold_enum_should_extract_variant_docs() {
    let source = "enum a { #[doc = \"c\"] v }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_enum(fold, doc.topmod.enums[0]);
    assert doc.variants[0].desc == some("c");
}

fn fold_res(
    fold: fold::fold<astsrv::srv>,
    doc: doc::resdoc
) -> doc::resdoc {

    let srv = fold.ctxt;
    let attrs = parse_item_attrs(srv, doc.id, attr_parser::parse_fn);

    ~{
        brief: attrs.brief,
        desc: attrs.desc,
        args: vec::map(attrs.args) {|attrs|
            ~{
                name: attrs.name,
                desc: some(attrs.desc),
                ty: none
            }
        }
        with *doc
    }
}

#[test]
fn fold_res_should_extract_docs() {
    let source = "#[doc(brief = \"a\", desc = \"b\")]\
                  resource r(b: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_res(fold, doc.topmod.resources[0]);
    assert doc.brief == some("a");
    assert doc.desc == some("b");
}

#[test]
fn fold_res_should_extract_arg_docs() {
    let source = "#[doc(args(a = \"b\"))]\
                  resource r(a: bool) { }";
    let srv = astsrv::mk_srv_from_str(source);
    let doc = extract::from_srv(srv, "");
    let fold = fold::default_seq_fold(srv);
    let doc = fold_res(fold, doc.topmod.resources[0]);
    assert doc.args[0].name == "a";
    assert doc.args[0].desc == some("b");
}<|endoftext|>


<commit_before>// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::*;

pub(crate) struct TerseFormatter<T> {
    out: OutputLocation<T>,
    use_color: bool,
    is_multithreaded: bool,
    /// Number of columns to fill when aligning names
    max_name_len: usize,

    test_count: usize,
}

impl<T: Write> TerseFormatter<T> {
    pub fn new(
        out: OutputLocation<T>,
        use_color: bool,
        max_name_len: usize,
        is_multithreaded: bool,
    ) -> Self {
        TerseFormatter {
            out,
            use_color,
            max_name_len,
            is_multithreaded,
            test_count: 0,
        }
    }

    pub fn write_ok(&mut self) -> io::Result<()> {
        self.write_short_result(".", term::color::GREEN)
    }

    pub fn write_failed(&mut self) -> io::Result<()> {
        self.write_short_result("F", term::color::RED)
    }

    pub fn write_ignored(&mut self) -> io::Result<()> {
        self.write_short_result("i", term::color::YELLOW)
    }

    pub fn write_allowed_fail(&mut self) -> io::Result<()> {
        self.write_short_result("a", term::color::YELLOW)
    }

    pub fn write_bench(&mut self) -> io::Result<()> {
        self.write_pretty("bench", term::color::CYAN)
    }

    pub fn write_short_result(
        &mut self,
        result: &str,
        color: term::color::Color,
    ) -> io::Result<()> {
        self.write_pretty(result, color)?;
        if self.test_count % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
            // we insert a new line every 100 dots in order to flush the
            // screen when dealing with line-buffered output (e.g. piping to
            // `stamp` in the rust CI).
            self.write_plain("\n")?;
        }

        self.test_count += 1;
        Ok(())
    }

    pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
        match self.out {
            Pretty(ref mut term) => {
                if self.use_color {
                    term.fg(color)?;
                }
                term.write_all(word.as_bytes())?;
                if self.use_color {
                    term.reset()?;
                }
                term.flush()
            }
            Raw(ref mut stdout) => {
                stdout.write_all(word.as_bytes())?;
                stdout.flush()
            }
        }
    }

    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
        let s = s.as_ref();
        self.out.write_all(s.as_bytes())?;
        self.out.flush()
    }

    pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
        self.write_plain("\nsuccesses:\n")?;
        let mut successes = Vec::new();
        let mut stdouts = String::new();
        for &(ref f, ref stdout) in &state.not_failures {
            successes.push(f.name.to_string());
            if !stdout.is_empty() {
                stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                let output = String::from_utf8_lossy(stdout);
                stdouts.push_str(&output);
                stdouts.push_str("\n");
            }
        }
        if !stdouts.is_empty() {
            self.write_plain("\n")?;
            self.write_plain(&stdouts)?;
        }

        self.write_plain("\nsuccesses:\n")?;
        successes.sort();
        for name in &successes {
            self.write_plain(&format!("    {}\n", name))?;
        }
        Ok(())
    }

    pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
        self.write_plain("\nfailures:\n")?;
        let mut failures = Vec::new();
        let mut fail_out = String::new();
        for &(ref f, ref stdout) in &state.failures {
            failures.push(f.name.to_string());
            if !stdout.is_empty() {
                fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
                let output = String::from_utf8_lossy(stdout);
                fail_out.push_str(&output);
                fail_out.push_str("\n");
            }
        }
        if !fail_out.is_empty() {
            self.write_plain("\n")?;
            self.write_plain(&fail_out)?;
        }

        self.write_plain("\nfailures:\n")?;
        failures.sort();
        for name in &failures {
            self.write_plain(&format!("    {}\n", name))?;
        }
        Ok(())
    }

    fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
        let name = desc.padded_name(self.max_name_len, desc.name.padding());
        self.write_plain(&format!("test {} ... ", name))?;

        Ok(())
    }
}

impl<T: Write> OutputFormatter for TerseFormatter<T> {
    fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
        let noun = if test_count != 1 { "tests" } else { "test" };
        self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
    }

    fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
        // Remnants from old libtest code that used the padding value
        // in order to indicate benchmarks.
        // When running benchmarks, terse-mode should still print their name as if
        // it is the Pretty formatter.
        if !self.is_multithreaded && desc.name.padding() == PadOnRight {
            self.write_test_name(desc)?;
        }

        Ok(())
    }

    fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
        match *result {
            TrOk => self.write_ok(),
            TrFailed | TrFailedMsg(_) => self.write_failed(),
            TrIgnored => self.write_ignored(),
            TrAllowedFail => self.write_allowed_fail(),
            TrBench(ref bs) => {
                if self.is_multithreaded {
                    self.write_test_name(desc)?;
                }
                self.write_bench()?;
                self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
            }
        }
    }

    fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
        self.write_plain(&format!(
            "test {} has been running for over {} seconds\n",
            desc.name, TEST_WARN_TIMEOUT_S
        ))
    }

    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
        if state.options.display_output {
            self.write_outputs(state)?;
        }
        let success = state.failed == 0;
        if !success {
            self.write_failures(state)?;
        }

        self.write_plain("\ntest result: ")?;

        if success {
            // There's no parallelism at this point so it's safe to use color
            self.write_pretty("ok", term::color::GREEN)?;
        } else {
            self.write_pretty("FAILED", term::color::RED)?;
        }

        let s = if state.allowed_fail > 0 {
            format!(
                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
                state.passed,
                state.failed + state.allowed_fail,
                state.allowed_fail,
                state.ignored,
                state.measured,
                state.filtered_out
            )
        } else {
            format!(
                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
                state.passed, state.failed, state.ignored, state.measured, state.filtered_out
            )
        };

        self.write_plain(&s)?;

        Ok(success)
    }
}
<commit_msg>libtest terse format: show how far in we are<commit_after>// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use super::*;

pub(crate) struct TerseFormatter<T> {
    out: OutputLocation<T>,
    use_color: bool,
    is_multithreaded: bool,
    /// Number of columns to fill when aligning names
    max_name_len: usize,

    test_count: usize,
    total_test_count: usize,
}

impl<T: Write> TerseFormatter<T> {
    pub fn new(
        out: OutputLocation<T>,
        use_color: bool,
        max_name_len: usize,
        is_multithreaded: bool,
    ) -> Self {
        TerseFormatter {
            out,
            use_color,
            max_name_len,
            is_multithreaded,
            test_count: 0,
            total_test_count: 0,
        }
    }

    pub fn write_ok(&mut self) -> io::Result<()> {
        self.write_short_result(".", term::color::GREEN)
    }

    pub fn write_failed(&mut self) -> io::Result<()> {
        self.write_short_result("F", term::color::RED)
    }

    pub fn write_ignored(&mut self) -> io::Result<()> {
        self.write_short_result("i", term::color::YELLOW)
    }

    pub fn write_allowed_fail(&mut self) -> io::Result<()> {
        self.write_short_result("a", term::color::YELLOW)
    }

    pub fn write_bench(&mut self) -> io::Result<()> {
        self.write_pretty("bench", term::color::CYAN)
    }

    pub fn write_short_result(
        &mut self,
        result: &str,
        color: term::color::Color,
    ) -> io::Result<()> {
        self.write_pretty(result, color)?;
        if self.test_count % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 {
            // we insert a new line every 100 dots in order to flush the
            // screen when dealing with line-buffered output (e.g. piping to
            // `stamp` in the rust CI).
            let out = format!(" {}/{}\n", self.test_count+1, self.total_test_count);
            self.write_plain(&out)?;
        }

        self.test_count += 1;
        Ok(())
    }

    pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> {
        match self.out {
            Pretty(ref mut term) => {
                if self.use_color {
                    term.fg(color)?;
                }
                term.write_all(word.as_bytes())?;
                if self.use_color {
                    term.reset()?;
                }
                term.flush()
            }
            Raw(ref mut stdout) => {
                stdout.write_all(word.as_bytes())?;
                stdout.flush()
            }
        }
    }

    pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> {
        let s = s.as_ref();
        self.out.write_all(s.as_bytes())?;
        self.out.flush()
    }

    pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> {
        self.write_plain("\nsuccesses:\n")?;
        let mut successes = Vec::new();
        let mut stdouts = String::new();
        for &(ref f, ref stdout) in &state.not_failures {
            successes.push(f.name.to_string());
            if !stdout.is_empty() {
                stdouts.push_str(&format!("---- {} stdout ----\n", f.name));
                let output = String::from_utf8_lossy(stdout);
                stdouts.push_str(&output);
                stdouts.push_str("\n");
            }
        }
        if !stdouts.is_empty() {
            self.write_plain("\n")?;
            self.write_plain(&stdouts)?;
        }

        self.write_plain("\nsuccesses:\n")?;
        successes.sort();
        for name in &successes {
            self.write_plain(&format!("    {}\n", name))?;
        }
        Ok(())
    }

    pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> {
        self.write_plain("\nfailures:\n")?;
        let mut failures = Vec::new();
        let mut fail_out = String::new();
        for &(ref f, ref stdout) in &state.failures {
            failures.push(f.name.to_string());
            if !stdout.is_empty() {
                fail_out.push_str(&format!("---- {} stdout ----\n", f.name));
                let output = String::from_utf8_lossy(stdout);
                fail_out.push_str(&output);
                fail_out.push_str("\n");
            }
        }
        if !fail_out.is_empty() {
            self.write_plain("\n")?;
            self.write_plain(&fail_out)?;
        }

        self.write_plain("\nfailures:\n")?;
        failures.sort();
        for name in &failures {
            self.write_plain(&format!("    {}\n", name))?;
        }
        Ok(())
    }

    fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> {
        let name = desc.padded_name(self.max_name_len, desc.name.padding());
        self.write_plain(&format!("test {} ... ", name))?;

        Ok(())
    }
}

impl<T: Write> OutputFormatter for TerseFormatter<T> {
    fn write_run_start(&mut self, test_count: usize) -> io::Result<()> {
        self.total_test_count = test_count;
        let noun = if test_count != 1 { "tests" } else { "test" };
        self.write_plain(&format!("\nrunning {} {}\n", test_count, noun))
    }

    fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> {
        // Remnants from old libtest code that used the padding value
        // in order to indicate benchmarks.
        // When running benchmarks, terse-mode should still print their name as if
        // it is the Pretty formatter.
        if !self.is_multithreaded && desc.name.padding() == PadOnRight {
            self.write_test_name(desc)?;
        }

        Ok(())
    }

    fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> {
        match *result {
            TrOk => self.write_ok(),
            TrFailed | TrFailedMsg(_) => self.write_failed(),
            TrIgnored => self.write_ignored(),
            TrAllowedFail => self.write_allowed_fail(),
            TrBench(ref bs) => {
                if self.is_multithreaded {
                    self.write_test_name(desc)?;
                }
                self.write_bench()?;
                self.write_plain(&format!(": {}\n", fmt_bench_samples(bs)))
            }
        }
    }

    fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> {
        self.write_plain(&format!(
            "test {} has been running for over {} seconds\n",
            desc.name, TEST_WARN_TIMEOUT_S
        ))
    }

    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
        if state.options.display_output {
            self.write_outputs(state)?;
        }
        let success = state.failed == 0;
        if !success {
            self.write_failures(state)?;
        }

        self.write_plain("\ntest result: ")?;

        if success {
            // There's no parallelism at this point so it's safe to use color
            self.write_pretty("ok", term::color::GREEN)?;
        } else {
            self.write_pretty("FAILED", term::color::RED)?;
        }

        let s = if state.allowed_fail > 0 {
            format!(
                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n",
                state.passed,
                state.failed + state.allowed_fail,
                state.allowed_fail,
                state.ignored,
                state.measured,
                state.filtered_out
            )
        } else {
            format!(
                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n",
                state.passed, state.failed, state.ignored, state.measured, state.filtered_out
            )
        };

        self.write_plain(&s)?;

        Ok(success)
    }
}
<|endoftext|>


<commit_before>use crate::utils::paths;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::utils::{get_trait_def_id, return_ty, span_lint_hir_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::HirIdSet;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Ty, TyS};
use rustc_session::{declare_tool_lint, impl_lint_pass};

declare_clippy_lint! {
    /// **What it does:** Checks for types with a `fn new() -> Self` method and no
    /// implementation of
    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
    ///
    /// **Why is this bad?** The user might expect to be able to use
    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
    /// type can be constructed without arguments.
    ///
    /// **Known problems:** Hopefully none.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// struct Foo(Bar);
    ///
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Foo(Bar::new())
    ///     }
    /// }
    /// ```
    ///
    /// To fix the lint, and a `Default` implementation that delegates to `new`:
    ///
    /// ```ignore
    /// struct Foo(Bar);
    ///
    /// impl Default for Foo {
    ///     fn default() -> Self {
    ///         Foo::new()
    ///     }
    /// }
    /// ```
    pub NEW_WITHOUT_DEFAULT,
    style,
    "`fn new() -> Self` method without `Default` implementation"
}

#[derive(Clone, Default)]
pub struct NewWithoutDefault {
    impling_types: Option<HirIdSet>,
}

impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
    #[allow(clippy::too_many_lines)]
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
        if let hir::ItemKind::Impl {
            of_trait: None, items, ..
        } = item.kind
        {
            for assoc_item in items {
                if let hir::AssocItemKind::Fn { has_self: false } = assoc_item.kind {
                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                    if in_external_macro(cx.sess(), impl_item.span) {
                        return;
                    }
                    if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
                        let name = impl_item.ident.name;
                        let id = impl_item.hir_id;
                        if sig.header.constness == hir::Constness::Const {
                            // can't be implemented by default
                            return;
                        }
                        if sig.header.unsafety == hir::Unsafety::Unsafe {
                            // can't be implemented for unsafe new
                            return;
                        }
                        if impl_item.generics.params.iter().any(|gen| match gen.kind {
                            hir::GenericParamKind::Type { .. } => true,
                            _ => false,
                        }) {
                            // when the result of `new()` depends on a type parameter we should not require
                            // an
                            // impl of `Default`
                            return;
                        }
                        if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) {
                            let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
                            let self_ty = cx.tcx.type_of(self_def_id);
                            if_chain! {
                                if TyS::same_type(self_ty, return_ty(cx, id));
                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
                                then {
                                    if self.impling_types.is_none() {
                                        let mut impls = HirIdSet::default();
                                        cx.tcx.for_each_impl(default_trait_id, |d| {
                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
                                                if let Some(local_def_id) = ty_def.did.as_local() {
                                                    impls.insert(cx.tcx.hir().as_local_hir_id(local_def_id));
                                                }
                                            }
                                        });
                                        self.impling_types = Some(impls);
                                    }

                                    // Check if a Default implementation exists for the Self type, regardless of
                                    // generics
                                    if_chain! {
                                        if let Some(ref impling_types) = self.impling_types;
                                        if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def();
                                        if let Some(self_local_did) = self_def.did.as_local();
                                        then {
                                            let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
                                            if impling_types.contains(&self_id) {
                                                return;
                                            }
                                        }
                                    }

                                    span_lint_hir_and_then(
                                        cx,
                                        NEW_WITHOUT_DEFAULT,
                                        id,
                                        impl_item.span,
                                        &format!(
                                            "you should consider adding a `Default` implementation for `{}`",
                                            self_ty
                                        ),
                                        |diag| {
                                            diag.suggest_prepend_item(
                                                cx,
                                                item.span,
                                                "try this",
                                                &create_new_without_default_suggest_msg(self_ty),
                                                Applicability::MaybeIncorrect,
                                            );
                                        },
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String {
    #[rustfmt::skip]
    format!(
"impl Default for {} {{
    fn default() -> Self {{
        Self::new()
    }}
}}", ty)
}
<commit_msg>Rollup merge of #5710 - lcnr:patch-1, r=flip1995<commit_after>use crate::utils::paths;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::utils::{get_trait_def_id, return_ty, span_lint_hir_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::HirIdSet;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Ty, TyS};
use rustc_session::{declare_tool_lint, impl_lint_pass};

declare_clippy_lint! {
    /// **What it does:** Checks for types with a `fn new() -> Self` method and no
    /// implementation of
    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
    ///
    /// **Why is this bad?** The user might expect to be able to use
    /// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
    /// type can be constructed without arguments.
    ///
    /// **Known problems:** Hopefully none.
    ///
    /// **Example:**
    ///
    /// ```ignore
    /// struct Foo(Bar);
    ///
    /// impl Foo {
    ///     fn new() -> Self {
    ///         Foo(Bar::new())
    ///     }
    /// }
    /// ```
    ///
    /// To fix the lint, add a `Default` implementation that delegates to `new`:
    ///
    /// ```ignore
    /// struct Foo(Bar);
    ///
    /// impl Default for Foo {
    ///     fn default() -> Self {
    ///         Foo::new()
    ///     }
    /// }
    /// ```
    pub NEW_WITHOUT_DEFAULT,
    style,
    "`fn new() -> Self` method without `Default` implementation"
}

#[derive(Clone, Default)]
pub struct NewWithoutDefault {
    impling_types: Option<HirIdSet>,
}

impl_lint_pass!(NewWithoutDefault => [NEW_WITHOUT_DEFAULT]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
    #[allow(clippy::too_many_lines)]
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
        if let hir::ItemKind::Impl {
            of_trait: None, items, ..
        } = item.kind
        {
            for assoc_item in items {
                if let hir::AssocItemKind::Fn { has_self: false } = assoc_item.kind {
                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                    if in_external_macro(cx.sess(), impl_item.span) {
                        return;
                    }
                    if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
                        let name = impl_item.ident.name;
                        let id = impl_item.hir_id;
                        if sig.header.constness == hir::Constness::Const {
                            // can't be implemented by default
                            return;
                        }
                        if sig.header.unsafety == hir::Unsafety::Unsafe {
                            // can't be implemented for unsafe new
                            return;
                        }
                        if impl_item.generics.params.iter().any(|gen| match gen.kind {
                            hir::GenericParamKind::Type { .. } => true,
                            _ => false,
                        }) {
                            // when the result of `new()` depends on a type parameter we should not require
                            // an
                            // impl of `Default`
                            return;
                        }
                        if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) {
                            let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
                            let self_ty = cx.tcx.type_of(self_def_id);
                            if_chain! {
                                if TyS::same_type(self_ty, return_ty(cx, id));
                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
                                then {
                                    if self.impling_types.is_none() {
                                        let mut impls = HirIdSet::default();
                                        cx.tcx.for_each_impl(default_trait_id, |d| {
                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
                                                if let Some(local_def_id) = ty_def.did.as_local() {
                                                    impls.insert(cx.tcx.hir().as_local_hir_id(local_def_id));
                                                }
                                            }
                                        });
                                        self.impling_types = Some(impls);
                                    }

                                    // Check if a Default implementation exists for the Self type, regardless of
                                    // generics
                                    if_chain! {
                                        if let Some(ref impling_types) = self.impling_types;
                                        if let Some(self_def) = cx.tcx.type_of(self_def_id).ty_adt_def();
                                        if let Some(self_local_did) = self_def.did.as_local();
                                        then {
                                            let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did);
                                            if impling_types.contains(&self_id) {
                                                return;
                                            }
                                        }
                                    }

                                    span_lint_hir_and_then(
                                        cx,
                                        NEW_WITHOUT_DEFAULT,
                                        id,
                                        impl_item.span,
                                        &format!(
                                            "you should consider adding a `Default` implementation for `{}`",
                                            self_ty
                                        ),
                                        |diag| {
                                            diag.suggest_prepend_item(
                                                cx,
                                                item.span,
                                                "try this",
                                                &create_new_without_default_suggest_msg(self_ty),
                                                Applicability::MaybeIncorrect,
                                            );
                                        },
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String {
    #[rustfmt::skip]
    format!(
"impl Default for {} {{
    fn default() -> Self {{
        Self::new()
    }}
}}", ty)
}
<|endoftext|>