<commit_before>#![feature(slicing_syntax, globs)]

use std::error::FromError;

use std::str::Utf8Error;
use std::string::FromUtf8Error;

use std::io::{Reader, BufReader, IoError};
use std::io::net::ip::IpAddr;

#[derive(Show)]
pub enum Error {
    Io(IoError),
    FormatError(FormatError)
}

#[derive(Show, Copy)]
pub enum FormatError {
    UnknownBlock(u32),
    UnknownOption(u16),
    Utf8Error(Utf8Error)
}

impl FromError<IoError> for Error {
    fn from_error(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl FromError<FromUtf8Error> for Error {
    fn from_error(err: FromUtf8Error) -> Error {
        Error::FormatError(FormatError::Utf8Error(err.utf8_error()))
    }
}

impl FromError<FormatError> for Error {
    fn from_error(err: FormatError) -> Error {
        Error::FormatError(err)
    }
}

#[derive(Show)]
pub enum Block {
    SectionHeader(SectionHeaderBlock),
    InterfaceDescription(InterfaceDescriptionBlock),
    InterfaceStatistics(InterfaceStatisticsBlock),
    EnhancedPacket(EnhancedPacketBlock)
}

#[derive(Show)]
pub struct SectionHeaderBlock {
    /// Magic number equal to 0x1A2B3C4D. This field can be used to detect
    /// sections saved on systems with different endianness.
    pub magic: u32,

    pub major_version: u16,
    pub minor_version: u16,

    /// Length in bytes of the following section excluding this block.
    ///
    /// This block can be used to skip the section for faster navigation in
    /// large files. Length of -1u64 means that the length is unspecified.
    pub section_length: u64,
    pub options: Vec<SectionHeaderOption>
}

#[derive(Show)]
pub enum SectionHeaderOption {
    /// Comment associated with the current block
    Comment(String),

    /// Description of the hardware used to create this section
    Hardware(String),

    /// Name of the operating system used to create this section
    OS(String),

    /// Name of the application used to create this section
    UserApplication(String)
}

/// Block type 1
#[derive(Show)]
pub struct InterfaceDescriptionBlock {
    /// Link layer type of the interface
    pub link_type: u16,

    /// Maximum number of bytes stored from each packet
    pub snap_len: u32,

    pub options: Vec<InterfaceDescriptionOption>
}

#[derive(Show)]
pub enum InterfaceDescriptionOption {
    /// Comment associated with the current block
    Comment(String),

    /// Name of the device used to capture data
    Name(String),

    /// Description of the device used to capture data
    Description(String),

    /// IPv4 interface address and netmask
    Ipv4Addr(u32, u32),

    /// IPv6 interface address and prefix length
    Ipv6Addr(IpAddr, u8),

    /// Hardware MAC address (48 bits)
    MacAddr(u64),

    /// Hardware EUI address
    EuiAddr(u64),

    /// Interface speed in bps
    Speed(u64),

    /// Resolution of timestamps.
    ///
    /// If the MSB is equal to zero, the remaining bits indicate the resolution
    /// as a negative power of 10 (e.g. 6 means microsecond resolution,
    /// timestamps are teh number of microseconds since 1/1/1970).
    ///
    /// If the MSB is equal to one, the remaining bits indicate the resolution
    /// as a negative power of 2 (e.g. 10 means 1/1024 of a second).
    ///
    /// If this options is not present, microsecond resolution is assumed.
    TsResolution(u8),

    /// Timezone for GMT support (?)
    Timezone(u32),

    /// The filter used to capture traffic. The first byte specifies the type
    /// of filter used (e.g. libpcap string, BPF bytecode, etc)
    Filter(u8, Vec<u8>),

    /// Operating system of the machine in which this interface is installed.
    /// This can be different from the Section Header Block if the capture
    /// was done remotely.
    OS(String),

    /// Length of Frame Check Sequence in bits for this interface. For link
    /// layers whose FCS length can change during time, the Packet Block
    /// flags be used.
    FcsLen(u8),

    /// Offset pf the timestamp in seconds
    TsOffset(u64)
}

/// Block type 5
#[derive(Show)]
pub struct InterfaceStatisticsBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    pub options: Vec<InterfaceStatisticsOption>
}

#[derive(Show)]
pub enum InterfaceStatisticsOption {
    /// Comment associated with the current block
    Comment(String),

    /// Time when capture started
    StartTime(u64),

    /// Time when capture ended
    EndTime(u64),

    /// Number of packets received from the physical interface
    Received(u64),

    /// Number of packets dropped by the interface due to the lack of resources
    Dropped(u64),

    /// Number of packets accepted by the filter
    FilterAccepted(u64),

    /// Number of packets dropped by the operating system
    OSDropped(u64),

    /// Number of packets delivered to the user starting. The value in this
    /// field can be different from 'Accepted - Dropped' because some packets
    /// could still be in the OS buffers when the capture ended.
    Delivered(u64)
}

#[derive(Show)]
pub struct EnhancedPacketBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    /// Number of bytes captured from the packet
    pub captured_len: u32,

    /// Actual length of the packet when it was transmitted on the network
    pub len: u32,

    pub data: Vec<u8>,
    pub options: Vec<EnhancedPacketBlockOption>
}

#[derive(Show)]
pub enum EnhancedPacketBlockOption {
    Comment(String),
    Flags(u32),
    Hash,

    /// Number of packets lost between the last packet
    DropCount(u64)
}

#[inline(always)]
fn dword_aligned(n: uint) -> uint {
    (n + 3) & !3
}

pub fn read_raw_block(r: &mut Reader) -> Result<(u32, Vec<u8>), IoError> {
    let block_type = try!(r.read_le_u32());

    let total_len = try!(r.read_le_u32());
    let data_len = total_len - 12; // 12 = type + 2*length

    let mut data = try!(r.read_exact(dword_aligned(data_len as uint)));
    data.truncate(data_len as uint);

    assert!(total_len == try!(r.read_le_u32()));

    Ok((block_type, data))
}

fn read_option(r: &mut Reader) -> Result<(u16, Vec<u8>), IoError> {
    let code = try!(r.read_le_u16());
    let len = try!(r.read_le_u16()) as uint;

    let mut data = try!(r.read_exact(dword_aligned(len)));
    data.truncate(len as uint);

    Ok((code, data))
}

pub fn read_block(r: &mut Reader) -> Result<Block, Error> {
    use Block::*;

    let (block_type, data) = try!(read_raw_block(r));
    let mut r = BufReader::new(&*data);

    let r = match block_type {
        0x0A0D0D0A => SectionHeader(try!(SectionHeaderBlock::read(&mut r))),
        1 => InterfaceDescription(try!(InterfaceDescriptionBlock::read(&mut r))),
        5 => InterfaceStatistics(try!(InterfaceStatisticsBlock::read(&mut r))),
        6 => EnhancedPacket(try!(EnhancedPacketBlock::read(&mut r))),
        _ => return Err(FromError::from_error(FormatError::UnknownBlock(block_type)))
    };

    Ok(r)
}

pub struct BlockIter<'a> {
    r: &'a mut (Reader + 'a)
}

pub struct PacketIter<'a> {
    r: &'a mut SimpleReader<'a>
}

pub struct SimpleReader<'a> {
    r: &'a mut (Reader + 'a),

    pub interfaces: Vec<InterfaceDescriptionBlock>
}

impl<'a> Iterator<Block> for BlockIter<'a> {
    fn next(&mut self) -> Option<Block> {
        match read_block(self.r) {
            Ok(block) => Some(block),
            Err(_) => None
        }
    }
}

impl<'a> Iterator<EnhancedPacketBlock> for PacketIter<'a> {
    fn next(&mut self) -> Option<EnhancedPacketBlock> {
        while let Ok(block) = read_block(self.r.r) {
            match block {
                Block::SectionHeader(_) => self.r.interfaces.clear(),
                Block::InterfaceDescription(id) => self.r.interfaces.push(id),
                Block::EnhancedPacket(ep) => return Some(ep),
                _ => {}
            }
        }

        None
    }
}

impl<'a> SimpleReader<'a> {
    pub fn new(r: &mut Reader) -> SimpleReader {
        SimpleReader { r: r, interfaces: Vec::new() }
    }

    pub fn blocks(&mut self) -> BlockIter {
        BlockIter { r: self.r }
    }

    pub fn packets(&'a mut self) -> PacketIter<'a> {
        PacketIter { r: self }
    }
}

impl SectionHeaderBlock {
    pub fn read(r: &mut BufReader) -> Result<SectionHeaderBlock, Error> {
        let magic = try!(r.read_le_u32());

        assert!(magic == 0x1A2B3C4D, "unsupported endianness");

        let major_version = try!(r.read_le_u16());
        let minor_version = try!(r.read_le_u16());
        let section_length = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use SectionHeaderOption::*;

                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,

                    1...4 => {
                        let s = try!(String::from_utf8(data));

                        match code {
                            1 => Comment(s),
                            2 => Hardware(s),
                            3 => OS(s),
                            4 => UserApplication(s),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(SectionHeaderBlock {
            magic: magic,
            major_version: major_version,
            minor_version: minor_version,
            section_length: section_length,

            options: options
        })
    }
}

impl InterfaceDescriptionBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceDescriptionBlock, Error> {
        let link_type = try!(r.read_le_u16());
        try!(r.read_le_u16()); // reserved
        let snap_len = try!(r.read_le_u32());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceDescriptionOption::*;
                let (code, data) = try!(read_option(r));

                let mut d = &*data;

                let opt = match code {
                    0 => break,
                    1...3 | 12 => {
                        let s = try!(String::from_utf8(data.clone()));

                        match code {
                            1 => Comment(s),
                            2 => Name(s),
                            3 => Description(s),
                            12 => OS(s),
                            _ => unreachable!()
                        }
                    }

                    4 => {
                        let ip = try!(d.read_le_u32());
                        let mask = try!(d.read_le_u32());

                        Ipv4Addr(ip, mask)
                    }

                    6 => MacAddr(try!(d.read_le_uint_n(6))),
                    9 => TsResolution(try!(d.read_byte())),

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceDescriptionBlock {
            link_type: link_type,
            snap_len: snap_len,
            options: options
        })
    }
}

impl EnhancedPacketBlock {
    pub fn read(r: &mut BufReader) -> Result<EnhancedPacketBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());
        let cap_len = try!(r.read_le_u32());
        let len = try!(r.read_le_u32());

        let aligned_len = dword_aligned(cap_len as uint);

        let mut packet_data = try!(r.read_exact(aligned_len));
        packet_data.truncate(cap_len as uint);

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use EnhancedPacketBlockOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    // TODO: rest of the options
                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(EnhancedPacketBlock {
            interface_id: interface_id,
            timestamp: ts,
            captured_len: cap_len,
            len: len,
            data: packet_data,
            options: options
        })
    }
}

impl InterfaceStatisticsBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceStatisticsBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceStatisticsOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    2...8 => {
                        let data = try!((&*data).read_le_u64());

                        match code {
                            2 => StartTime(data),
                            3 => EndTime(data),
                            4 => Received(data),
                            5 => Dropped(data),
                            6 => FilterAccepted(data),
                            7 => OSDropped(data),
                            8 => Delivered(data),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceStatisticsBlock {
            interface_id: interface_id,
            timestamp: ts,
            options: options
        })
    }
}
<commit_msg>Remove redundant field<commit_after>#![feature(slicing_syntax, globs)]

use std::error::FromError;

use std::str::Utf8Error;
use std::string::FromUtf8Error;

use std::io::{Reader, BufReader, IoError};
use std::io::net::ip::IpAddr;

#[derive(Show)]
pub enum Error {
    Io(IoError),
    FormatError(FormatError)
}

#[derive(Show, Copy)]
pub enum FormatError {
    UnknownBlock(u32),
    UnknownOption(u16),
    Utf8Error(Utf8Error)
}

impl FromError<IoError> for Error {
    fn from_error(err: IoError) -> Error {
        Error::Io(err)
    }
}

impl FromError<FromUtf8Error> for Error {
    fn from_error(err: FromUtf8Error) -> Error {
        Error::FormatError(FormatError::Utf8Error(err.utf8_error()))
    }
}

impl FromError<FormatError> for Error {
    fn from_error(err: FormatError) -> Error {
        Error::FormatError(err)
    }
}

#[derive(Show)]
pub enum Block {
    SectionHeader(SectionHeaderBlock),
    InterfaceDescription(InterfaceDescriptionBlock),
    InterfaceStatistics(InterfaceStatisticsBlock),
    EnhancedPacket(EnhancedPacketBlock)
}

#[derive(Show)]
pub struct SectionHeaderBlock {
    /// Magic number equal to 0x1A2B3C4D. This field can be used to detect
    /// sections saved on systems with different endianness.
    pub magic: u32,

    pub major_version: u16,
    pub minor_version: u16,

    /// Length in bytes of the following section excluding this block.
    ///
    /// This block can be used to skip the section for faster navigation in
    /// large files. Length of -1u64 means that the length is unspecified.
    pub section_length: u64,
    pub options: Vec<SectionHeaderOption>
}

#[derive(Show)]
pub enum SectionHeaderOption {
    /// Comment associated with the current block
    Comment(String),

    /// Description of the hardware used to create this section
    Hardware(String),

    /// Name of the operating system used to create this section
    OS(String),

    /// Name of the application used to create this section
    UserApplication(String)
}

/// Block type 1
#[derive(Show)]
pub struct InterfaceDescriptionBlock {
    /// Link layer type of the interface
    pub link_type: u16,

    /// Maximum number of bytes stored from each packet
    pub snap_len: u32,

    pub options: Vec<InterfaceDescriptionOption>
}

#[derive(Show)]
pub enum InterfaceDescriptionOption {
    /// Comment associated with the current block
    Comment(String),

    /// Name of the device used to capture data
    Name(String),

    /// Description of the device used to capture data
    Description(String),

    /// IPv4 interface address and netmask
    Ipv4Addr(u32, u32),

    /// IPv6 interface address and prefix length
    Ipv6Addr(IpAddr, u8),

    /// Hardware MAC address (48 bits)
    MacAddr(u64),

    /// Hardware EUI address
    EuiAddr(u64),

    /// Interface speed in bps
    Speed(u64),

    /// Resolution of timestamps.
    ///
    /// If the MSB is equal to zero, the remaining bits indicate the resolution
    /// as a negative power of 10 (e.g. 6 means microsecond resolution,
    /// timestamps are teh number of microseconds since 1/1/1970).
    ///
    /// If the MSB is equal to one, the remaining bits indicate the resolution
    /// as a negative power of 2 (e.g. 10 means 1/1024 of a second).
    ///
    /// If this options is not present, microsecond resolution is assumed.
    TsResolution(u8),

    /// Timezone for GMT support (?)
    Timezone(u32),

    /// The filter used to capture traffic. The first byte specifies the type
    /// of filter used (e.g. libpcap string, BPF bytecode, etc)
    Filter(u8, Vec<u8>),

    /// Operating system of the machine in which this interface is installed.
    /// This can be different from the Section Header Block if the capture
    /// was done remotely.
    OS(String),

    /// Length of Frame Check Sequence in bits for this interface. For link
    /// layers whose FCS length can change during time, the Packet Block
    /// flags be used.
    FcsLen(u8),

    /// Offset pf the timestamp in seconds
    TsOffset(u64)
}

/// Block type 5
#[derive(Show)]
pub struct InterfaceStatisticsBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    pub options: Vec<InterfaceStatisticsOption>
}

#[derive(Show)]
pub enum InterfaceStatisticsOption {
    /// Comment associated with the current block
    Comment(String),

    /// Time when capture started
    StartTime(u64),

    /// Time when capture ended
    EndTime(u64),

    /// Number of packets received from the physical interface
    Received(u64),

    /// Number of packets dropped by the interface due to the lack of resources
    Dropped(u64),

    /// Number of packets accepted by the filter
    FilterAccepted(u64),

    /// Number of packets dropped by the operating system
    OSDropped(u64),

    /// Number of packets delivered to the user starting. The value in this
    /// field can be different from 'Accepted - Dropped' because some packets
    /// could still be in the OS buffers when the capture ended.
    Delivered(u64)
}

#[derive(Show)]
pub struct EnhancedPacketBlock {
    pub interface_id: u32,
    pub timestamp: u64,

    /// Actual length of the packet when it was transmitted on the network
    pub len: u32,

    pub data: Vec<u8>,
    pub options: Vec<EnhancedPacketBlockOption>
}

#[derive(Show)]
pub enum EnhancedPacketBlockOption {
    Comment(String),
    Flags(u32),
    Hash,

    /// Number of packets lost between the last packet
    DropCount(u64)
}

#[inline(always)]
fn dword_aligned(n: uint) -> uint {
    (n + 3) & !3
}

pub fn read_raw_block(r: &mut Reader) -> Result<(u32, Vec<u8>), IoError> {
    let block_type = try!(r.read_le_u32());

    let total_len = try!(r.read_le_u32());
    let data_len = total_len - 12; // 12 = type + 2*length

    let mut data = try!(r.read_exact(dword_aligned(data_len as uint)));
    data.truncate(data_len as uint);

    assert!(total_len == try!(r.read_le_u32()));

    Ok((block_type, data))
}

fn read_option(r: &mut Reader) -> Result<(u16, Vec<u8>), IoError> {
    let code = try!(r.read_le_u16());
    let len = try!(r.read_le_u16()) as uint;

    let mut data = try!(r.read_exact(dword_aligned(len)));
    data.truncate(len as uint);

    Ok((code, data))
}

pub fn read_block(r: &mut Reader) -> Result<Block, Error> {
    use Block::*;

    let (block_type, data) = try!(read_raw_block(r));
    let mut r = BufReader::new(&*data);

    let r = match block_type {
        0x0A0D0D0A => SectionHeader(try!(SectionHeaderBlock::read(&mut r))),
        1 => InterfaceDescription(try!(InterfaceDescriptionBlock::read(&mut r))),
        5 => InterfaceStatistics(try!(InterfaceStatisticsBlock::read(&mut r))),
        6 => EnhancedPacket(try!(EnhancedPacketBlock::read(&mut r))),
        _ => return Err(FromError::from_error(FormatError::UnknownBlock(block_type)))
    };

    Ok(r)
}

pub struct BlockIter<'a> {
    r: &'a mut (Reader + 'a)
}

pub struct PacketIter<'a> {
    r: &'a mut SimpleReader<'a>
}

pub struct SimpleReader<'a> {
    r: &'a mut (Reader + 'a),

    pub interfaces: Vec<InterfaceDescriptionBlock>
}

impl<'a> Iterator<Block> for BlockIter<'a> {
    fn next(&mut self) -> Option<Block> {
        match read_block(self.r) {
            Ok(block) => Some(block),
            Err(_) => None
        }
    }
}

impl<'a> Iterator<EnhancedPacketBlock> for PacketIter<'a> {
    fn next(&mut self) -> Option<EnhancedPacketBlock> {
        while let Ok(block) = read_block(self.r.r) {
            match block {
                Block::SectionHeader(_) => self.r.interfaces.clear(),
                Block::InterfaceDescription(id) => self.r.interfaces.push(id),
                Block::EnhancedPacket(ep) => return Some(ep),
                _ => {}
            }
        }

        None
    }
}

impl<'a> SimpleReader<'a> {
    pub fn new(r: &mut Reader) -> SimpleReader {
        SimpleReader { r: r, interfaces: Vec::new() }
    }

    pub fn blocks(&mut self) -> BlockIter {
        BlockIter { r: self.r }
    }

    pub fn packets(&'a mut self) -> PacketIter<'a> {
        PacketIter { r: self }
    }
}

impl SectionHeaderBlock {
    pub fn read(r: &mut BufReader) -> Result<SectionHeaderBlock, Error> {
        let magic = try!(r.read_le_u32());

        assert!(magic == 0x1A2B3C4D, "unsupported endianness");

        let major_version = try!(r.read_le_u16());
        let minor_version = try!(r.read_le_u16());
        let section_length = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use SectionHeaderOption::*;

                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,

                    1...4 => {
                        let s = try!(String::from_utf8(data));

                        match code {
                            1 => Comment(s),
                            2 => Hardware(s),
                            3 => OS(s),
                            4 => UserApplication(s),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(SectionHeaderBlock {
            magic: magic,
            major_version: major_version,
            minor_version: minor_version,
            section_length: section_length,

            options: options
        })
    }
}

impl InterfaceDescriptionBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceDescriptionBlock, Error> {
        let link_type = try!(r.read_le_u16());
        try!(r.read_le_u16()); // reserved
        let snap_len = try!(r.read_le_u32());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceDescriptionOption::*;
                let (code, data) = try!(read_option(r));

                let mut d = &*data;

                let opt = match code {
                    0 => break,
                    1...3 | 12 => {
                        let s = try!(String::from_utf8(data.clone()));

                        match code {
                            1 => Comment(s),
                            2 => Name(s),
                            3 => Description(s),
                            12 => OS(s),
                            _ => unreachable!()
                        }
                    }

                    4 => {
                        let ip = try!(d.read_le_u32());
                        let mask = try!(d.read_le_u32());

                        Ipv4Addr(ip, mask)
                    }

                    6 => MacAddr(try!(d.read_le_uint_n(6))),
                    9 => TsResolution(try!(d.read_byte())),

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceDescriptionBlock {
            link_type: link_type,
            snap_len: snap_len,
            options: options
        })
    }
}

impl EnhancedPacketBlock {
    pub fn read(r: &mut BufReader) -> Result<EnhancedPacketBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());
        let cap_len = try!(r.read_le_u32());
        let len = try!(r.read_le_u32());

        let aligned_len = dword_aligned(cap_len as uint);

        let mut packet_data = try!(r.read_exact(aligned_len));
        packet_data.truncate(cap_len as uint);

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use EnhancedPacketBlockOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    // TODO: rest of the options
                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(EnhancedPacketBlock {
            interface_id: interface_id,
            timestamp: ts,
            len: len,
            data: packet_data,
            options: options
        })
    }
}

impl InterfaceStatisticsBlock {
    pub fn read(r: &mut BufReader) -> Result<InterfaceStatisticsBlock, Error> {
        let interface_id = try!(r.read_le_u32());
        let ts = try!(r.read_le_u64());

        let mut options = Vec::new();

        if !r.eof() {
            loop {
                use InterfaceStatisticsOption::*;
                let (code, data) = try!(read_option(r));

                let opt = match code {
                    0 => break,
                    1 => {
                        match String::from_utf8(data.clone()) {
                            Ok(r) => Comment(r),
                            Err(err) => return Err(FromError::from_error(err))
                        }
                    }

                    2...8 => {
                        let data = try!((&*data).read_le_u64());

                        match code {
                            2 => StartTime(data),
                            3 => EndTime(data),
                            4 => Received(data),
                            5 => Dropped(data),
                            6 => FilterAccepted(data),
                            7 => OSDropped(data),
                            8 => Delivered(data),
                            _ => unreachable!()
                        }
                    }

                    _ => return Err(FromError::from_error(FormatError::UnknownOption(code)))
                };

                options.push(opt);
            }
        }

        Ok(InterfaceStatisticsBlock {
            interface_id: interface_id,
            timestamp: ts,
            options: options
        })
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Valentin Vasilyev.
//
// 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.

/*!

Heliotrope is a Solr client for the [Rust](http://rust-lang.org/) programming language.

It builds with [Cargo](http://crates.io/).
To use it in your project, add this to your `Cargo.toml` file:

```Cargo
[dependencies.heliotrope]
git = "https://github.com/Valve/heliotrope"
```

## Indexing

### Adding new document to solr

```ignore
use url::Url;
use heliotrope::{Solr, SolrDocument};

fn main(){
    let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
    let solr = Solr::new(url);
    let mut document = SolrDocument::new();
    document.add_field("id", "1".to_string());
    document.add_field("type", "Book".to_string());
    document.add_field("title", "How to train your dragon".to_string());
    document.add_field("body", "Vala Morgulis".to_string());
    match solr.add(&document) {
        Ok(solr_response) => println!("{:?}", solr_response),
        Err(solr_error) => println!("{:?}", solr_error)
    }
    match solr.commit() {
        Ok(solr_response) => println!("{:?}", solr_response),
        Err(solr_error) => println!("{:?}", solr_error)
    }
}
```

### Add and commit in one step

```ignore
use url::{Url};
use heliotrope::{Solr, SolrDocument};

fn main(){
    let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
    let solr = Solr::new(url);
    let mut document = SolrDocument::new();
    document.add_field("id", "2".to_string());
    document.add_field("type", "Book".to_string());
    document.add_field("title", "The Great Gatsby".to_string());
    document.add_field("body", "In my younger and more vulnerable years..".to_string());
    match solr.add_and_commit(&document) {
        Ok(solr_response) => println!("{:?}", solr_response),
        Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
    }
}
```

### Adding multiple document at once

```ignore
use url::{Url};
use heliotrope::{Solr, SolrDocument};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let mut document1 = SolrDocument::new();
document1.add_field("id", "3".to_string());
document1.add_field("type", "Book".to_string());
document1.add_field("title", "The Great Gatsby".to_string());
document1.add_field("body", "In my younger and more vulnerable years".to_string());

let mut document2 = SolrDocument::new();
document1.add_field("id", "4".to_string());
document1.add_field("type", "Book".to_string());
document2.add_field("title", "Moby Dick".to_string());
document2.add_field("body", "Call me Ishmael".to_string());

match solr.add_many_and_commit(vec!(&document1, &document2)) {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```

## Querying

```ignore
extern crate url;
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrQuery, Descending};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let query = SolrQuery::new("*:*").add_sort("year", Descending);
match solr.query(&query) {
    Ok(solr_response) => {
        println!("Status: {}", solr_response.status);
        println!("Time: {}", solr_response.time);
        println!("Total rows found: {}", solr_response.total);
        println!("Offset: {}", solr_response.start);
        for item in solr_response.items.iter() {
            println!("{}", item);
        }
    }
    Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```

### Query options chaining

```ignore
let query = SolrQuery::new("*:*")
    .add_field("score")
    .add_field("*")
    .add_sort("age", Descending)
    .add_filter("type:Person");
```

#### Replacing arguments
Each `add_*` method on SolrQuery, that accepts a single argument, has a corresponding
`set_*` method which accepts a slice of arguments and replaces existing ones.

```ignore
let query = SolrQuery::new("*:*")
    .set_fields(["id", "title", "score"])
    .set_filters(["type:Person", "class:AR"]);
```

### Pagination

```ignore
// getting third page of size 50
let query = SolrQuery::new("manufacturer:Sony").start(100).rows(50);
```
*/

#![crate_name="heliotrope"]

extern crate serialize;
extern crate url;
extern crate http;

use std::io::IoResult;
use url::{Url, UrlParser};
use serialize::{json};
use http_utils::HttpResponse;

pub use document::{SolrValue, SolrField, SolrDocument};
pub use response::{SolrError, SolrUpdateResult, SolrQueryResult, SolrUpdateResponse, SolrQueryResponse};
pub use query::{SolrQuery, SortOrder, SortClause};

mod http_utils;
mod document;
mod query;
mod response;

/// Represents your API connection to Solr.
/// You will use this struct to perform operations on Solr.
pub struct Solr {
    /// Base URL to connect to Solr. Should include the core.
    /// For example http://localhost:8983/solr/production/
    pub base_url: Url,
    select_url: Url,
    update_url: Url,
    commit_url: Url
}

impl Solr {

    fn build_update_url(url: &Url) -> Url{
        let mut url_parser = UrlParser::new();
        url_parser.base_url(url).parse("./update").unwrap()
    }

    fn build_select_url(url: &Url) -> Url {
        let mut url_parser = UrlParser::new();
        url_parser.base_url(url).parse("./select").unwrap()
    }

    fn build_commit_url(url: &Url) -> Url {
        let mut url_parser = UrlParser::new();
        url_parser.base_url(url).parse("./update?commit=true").unwrap()
    }

    /// Creates a new instance of Solr.
    pub fn new(url: &Url) -> Solr {
        Solr {base_url: url.clone(),
            select_url: Solr::build_select_url(url),
            update_url: Solr::build_update_url(url),
            commit_url: Solr::build_commit_url(url)}
    }

    /// Adds new document to Solr, without committing
    pub fn add(&self, document: &SolrDocument) -> SolrUpdateResult {
        self.add_many([document])
    }

    /// Adds new document to Solr and commits it
    pub fn add_and_commit(&self, document: &SolrDocument) -> SolrUpdateResult {
        self.add_many_and_commit([document])
    }

    /// Adds multiple documents to Solr, without committing it
    pub fn add_many(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
        let raw_json = json::encode(&documents);
        let http_result =  http_utils::post_json(&self.update_url, raw_json.as_slice());
        handle_http_update_result(http_result)
    }

    /// Ads multiple documents to Solr and commits them
    pub fn add_many_and_commit(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
        let raw_json = json::encode(&documents);
        println!("{}", raw_json);
        let http_result =  http_utils::post_json(&self.commit_url, raw_json.as_slice());
        handle_http_update_result(http_result)
    }

    /// Performs Solr commit
    pub fn commit(&self) -> SolrUpdateResult {
        let http_result = http_utils::post(&self.commit_url);
        handle_http_update_result(http_result)
    }

    /// Performs Solr query
    pub fn query(&self, query: &SolrQuery) -> SolrQueryResult {
        let mut query_url = self.select_url.clone();
        query_url.set_query_from_pairs(query.to_pairs().iter().map(|&(ref k, ref v)| (k.as_slice(),v.as_slice())));
        let http_result = http_utils::get(&query_url);
        handle_http_result(http_result, |http_response| {
            match SolrQueryResponse::from_json_str(http_response.body_str().unwrap()) {
                Ok(sqr) => Ok(sqr),
                // TODO: insert actual builder_error inside solr_error
                Err(_) => Err(SolrError{status: 0, time: 0, message: "Error parsing query response JSON".to_string()})
            }
        })
    }
}

fn handle_http_update_result(http_result: IoResult<HttpResponse>) -> SolrUpdateResult {
    handle_http_result(http_result, |http_response| {
        match json::decode::<SolrUpdateResponse>(http_response.body_str().unwrap()) {
            Ok(sur) => Ok(sur),
            // TODO: insert actual parse_error inside solr_error
            Err(_) => Err(SolrError{status: 0, time: 0, message: "Error parsing query response JSON".to_string()})
        }
    })

}

fn handle_http_result<R>(result: IoResult<HttpResponse>, f: |&HttpResponse| ->  Result<R, SolrError>) -> Result<R, SolrError> {
    match result {
        Ok(http_response) => {
            match http_response.code {
                200 => {
                    match f(&http_response) {
                        Ok(response) => Ok(response),
                        Err(e) => Err(e)
                    }
                },
                _ => {
                    let error: SolrError = json::decode(http_response.body_str().unwrap()).unwrap();
                    Err(error)
                }
            }
        },
        Err(err) => {
            Err(SolrError{status: 0, time: 0, message: err.desc.to_string()})
        }
    }
}
<commit_msg>Fix arrays not being implicitly converted to slices<commit_after>// Copyright 2014 Valentin Vasilyev.
//
// 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.

/*!

Heliotrope is a Solr client for the [Rust](http://rust-lang.org/) programming language.

It builds with [Cargo](http://crates.io/).
To use it in your project, add this to your `Cargo.toml` file:

```Cargo
[dependencies.heliotrope]
git = "https://github.com/Valve/heliotrope"
```

## Indexing

### Adding new document to solr

```ignore
use url::Url;
use heliotrope::{Solr, SolrDocument};

fn main(){
    let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
    let solr = Solr::new(url);
    let mut document = SolrDocument::new();
    document.add_field("id", "1".to_string());
    document.add_field("type", "Book".to_string());
    document.add_field("title", "How to train your dragon".to_string());
    document.add_field("body", "Vala Morgulis".to_string());
    match solr.add(&document) {
        Ok(solr_response) => println!("{:?}", solr_response),
        Err(solr_error) => println!("{:?}", solr_error)
    }
    match solr.commit() {
        Ok(solr_response) => println!("{:?}", solr_response),
        Err(solr_error) => println!("{:?}", solr_error)
    }
}
```

### Add and commit in one step

```ignore
use url::{Url};
use heliotrope::{Solr, SolrDocument};

fn main(){
    let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
    let solr = Solr::new(url);
    let mut document = SolrDocument::new();
    document.add_field("id", "2".to_string());
    document.add_field("type", "Book".to_string());
    document.add_field("title", "The Great Gatsby".to_string());
    document.add_field("body", "In my younger and more vulnerable years..".to_string());
    match solr.add_and_commit(&document) {
        Ok(solr_response) => println!("{:?}", solr_response),
        Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
    }
}
```

### Adding multiple document at once

```ignore
use url::{Url};
use heliotrope::{Solr, SolrDocument};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let mut document1 = SolrDocument::new();
document1.add_field("id", "3".to_string());
document1.add_field("type", "Book".to_string());
document1.add_field("title", "The Great Gatsby".to_string());
document1.add_field("body", "In my younger and more vulnerable years".to_string());

let mut document2 = SolrDocument::new();
document1.add_field("id", "4".to_string());
document1.add_field("type", "Book".to_string());
document2.add_field("title", "Moby Dick".to_string());
document2.add_field("body", "Call me Ishmael".to_string());

match solr.add_many_and_commit(vec!(&document1, &document2)) {
    Ok(solr_response) => println!("{:?}", solr_response),
    Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```

## Querying

```ignore
extern crate url;
use url::{Url};
use heliotrope::{Solr, SolrDocument, SolrQuery, Descending};

let url = Url::parse("http://localhost:8983/solr/test/").unwrap();
let solr = Solr::new(url);
let query = SolrQuery::new("*:*").add_sort("year", Descending);
match solr.query(&query) {
    Ok(solr_response) => {
        println!("Status: {}", solr_response.status);
        println!("Time: {}", solr_response.time);
        println!("Total rows found: {}", solr_response.total);
        println!("Offset: {}", solr_response.start);
        for item in solr_response.items.iter() {
            println!("{}", item);
        }
    }
    Err(solr_error) => println!("Status: {}, Message: {}", solr_error.status, solr_error.message)
}
```

### Query options chaining

```ignore
let query = SolrQuery::new("*:*")
    .add_field("score")
    .add_field("*")
    .add_sort("age", Descending)
    .add_filter("type:Person");
```

#### Replacing arguments
Each `add_*` method on SolrQuery, that accepts a single argument, has a corresponding
`set_*` method which accepts a slice of arguments and replaces existing ones.

```ignore
let query = SolrQuery::new("*:*")
    .set_fields(["id", "title", "score"])
    .set_filters(["type:Person", "class:AR"]);
```

### Pagination

```ignore
// getting third page of size 50
let query = SolrQuery::new("manufacturer:Sony").start(100).rows(50);
```
*/

#![crate_name="heliotrope"]

extern crate serialize;
extern crate url;
extern crate http;

use std::io::IoResult;
use url::{Url, UrlParser};
use serialize::{json};
use http_utils::HttpResponse;

pub use document::{SolrValue, SolrField, SolrDocument};
pub use response::{SolrError, SolrUpdateResult, SolrQueryResult, SolrUpdateResponse, SolrQueryResponse};
pub use query::{SolrQuery, SortOrder, SortClause};

mod http_utils;
mod document;
mod query;
mod response;

/// Represents your API connection to Solr.
/// You will use this struct to perform operations on Solr.
pub struct Solr {
    /// Base URL to connect to Solr. Should include the core.
    /// For example http://localhost:8983/solr/production/
    pub base_url: Url,
    select_url: Url,
    update_url: Url,
    commit_url: Url
}

impl Solr {

    fn build_update_url(url: &Url) -> Url{
        let mut url_parser = UrlParser::new();
        url_parser.base_url(url).parse("./update").unwrap()
    }

    fn build_select_url(url: &Url) -> Url {
        let mut url_parser = UrlParser::new();
        url_parser.base_url(url).parse("./select").unwrap()
    }

    fn build_commit_url(url: &Url) -> Url {
        let mut url_parser = UrlParser::new();
        url_parser.base_url(url).parse("./update?commit=true").unwrap()
    }

    /// Creates a new instance of Solr.
    pub fn new(url: &Url) -> Solr {
        Solr {base_url: url.clone(),
            select_url: Solr::build_select_url(url),
            update_url: Solr::build_update_url(url),
            commit_url: Solr::build_commit_url(url)}
    }

    /// Adds new document to Solr, without committing
    pub fn add(&self, document: &SolrDocument) -> SolrUpdateResult {
        self.add_many(&[document])
    }

    /// Adds new document to Solr and commits it
    pub fn add_and_commit(&self, document: &SolrDocument) -> SolrUpdateResult {
        self.add_many_and_commit(&[document])
    }

    /// Adds multiple documents to Solr, without committing it
    pub fn add_many(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
        let raw_json = json::encode(&documents);
        let http_result =  http_utils::post_json(&self.update_url, raw_json.as_slice());
        handle_http_update_result(http_result)
    }

    /// Ads multiple documents to Solr and commits them
    pub fn add_many_and_commit(&self, documents: &[&SolrDocument]) -> SolrUpdateResult {
        let raw_json = json::encode(&documents);
        println!("{}", raw_json);
        let http_result =  http_utils::post_json(&self.commit_url, raw_json.as_slice());
        handle_http_update_result(http_result)
    }

    /// Performs Solr commit
    pub fn commit(&self) -> SolrUpdateResult {
        let http_result = http_utils::post(&self.commit_url);
        handle_http_update_result(http_result)
    }

    /// Performs Solr query
    pub fn query(&self, query: &SolrQuery) -> SolrQueryResult {
        let mut query_url = self.select_url.clone();
        query_url.set_query_from_pairs(query.to_pairs().iter().map(|&(ref k, ref v)| (k.as_slice(),v.as_slice())));
        let http_result = http_utils::get(&query_url);
        handle_http_result(http_result, |http_response| {
            match SolrQueryResponse::from_json_str(http_response.body_str().unwrap()) {
                Ok(sqr) => Ok(sqr),
                // TODO: insert actual builder_error inside solr_error
                Err(_) => Err(SolrError{status: 0, time: 0, message: "Error parsing query response JSON".to_string()})
            }
        })
    }
}

fn handle_http_update_result(http_result: IoResult<HttpResponse>) -> SolrUpdateResult {
    handle_http_result(http_result, |http_response| {
        match json::decode::<SolrUpdateResponse>(http_response.body_str().unwrap()) {
            Ok(sur) => Ok(sur),
            // TODO: insert actual parse_error inside solr_error
            Err(_) => Err(SolrError{status: 0, time: 0, message: "Error parsing query response JSON".to_string()})
        }
    })

}

fn handle_http_result<R>(result: IoResult<HttpResponse>, f: |&HttpResponse| ->  Result<R, SolrError>) -> Result<R, SolrError> {
    match result {
        Ok(http_response) => {
            match http_response.code {
                200 => {
                    match f(&http_response) {
                        Ok(response) => Ok(response),
                        Err(e) => Err(e)
                    }
                },
                _ => {
                    let error: SolrError = json::decode(http_response.body_str().unwrap()).unwrap();
                    Err(error)
                }
            }
        },
        Err(err) => {
            Err(SolrError{status: 0, time: 0, message: err.desc.to_string()})
        }
    }
}
<|endoftext|>


<commit_before>extern crate tempfile;
use tempfile::{NamedTempFile, NamedTempFileOptions};
use std::env;
use std::io::{Write, Read, Seek, SeekFrom};
use std::fs::File;
use std::path::Path;

fn exists<P: AsRef<Path>>(path: P) -> bool {
    std::fs::metadata(path.as_ref()).is_ok()
}

#[test]
fn test_basic() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_deleted() {
    let tmpfile = NamedTempFile::new().unwrap();
    let path = tmpfile.path().to_path_buf();
    assert!(exists(&path));
    drop(tmpfile);
    assert!(!exists(&path));
}

#[test]
fn test_persist() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_path = env::temp_dir().join("persisted_temporary_file");
    write!(tmpfile, "abcde").unwrap();
    {
        assert!(exists(&old_path));
        let mut f = tmpfile.persist(&persist_path).unwrap();
        assert!(!exists(&old_path));

        // Check original file
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }

    {
        // Try opening it at the new path.
        let mut f = File::open(&persist_path).unwrap();
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_persist_noclobber() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_target = NamedTempFile::new().unwrap();
    let persist_path = persist_target.path().to_path_buf();
    write!(tmpfile, "abcde").unwrap();
    assert!(exists(&old_path));
    {
        tmpfile = tmpfile.persist_noclobber(&persist_path).unwrap_err().into();
        assert!(exists(&old_path));
        std::fs::remove_file(&persist_path).unwrap();
        drop(persist_target);
    }
    tmpfile.persist_noclobber(&persist_path).unwrap();
    // Try opening it at the new path.
    let mut f = File::open(&persist_path).unwrap();
    f.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    f.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_customnamed() {
    let tmpfile = NamedTempFileOptions::new()
                      .prefix("tmp")
                      .suffix(&".rs".to_string())
                      .rand_bytes(12)
                      .create()
                      .unwrap();
    let name = tmpfile.path().file_name().unwrap().to_str().unwrap();
    assert!(name.starts_with("tmp"));
    assert!(name.ends_with(".rs"));
    assert_eq!(name.len(), 18);
}

#[test]
fn test_reopen() {
    let source = NamedTempFile::new().unwrap();
    let mut first = source.reopen().unwrap();
    let mut second = source.reopen().unwrap();
    drop(source);

    write!(first, "abcde").expect("write failed");
    let mut buf = String::new();
    second.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_to_file() {
    let mut file = NamedTempFile::new().unwrap();
    let path = file.path().to_owned();
    write!(file, "abcde").expect("write failed");

    assert!(path.exists());
    let mut file: File = file.into();
    assert!(!path.exists());

    file.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    file.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_immut() {
    let tmpfile = NamedTempFile::new().unwrap();
    (&tmpfile).write_all(b"abcde").unwrap();
    (&tmpfile).seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    (&tmpfile).read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}
<commit_msg>rustfmt<commit_after>extern crate tempfile;
use tempfile::{NamedTempFile, NamedTempFileOptions};
use std::env;
use std::io::{Write, Read, Seek, SeekFrom};
use std::fs::File;
use std::path::Path;

fn exists<P: AsRef<Path>>(path: P) -> bool {
    std::fs::metadata(path.as_ref()).is_ok()
}

#[test]
fn test_basic() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    write!(tmpfile, "abcde").unwrap();
    tmpfile.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    tmpfile.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_deleted() {
    let tmpfile = NamedTempFile::new().unwrap();
    let path = tmpfile.path().to_path_buf();
    assert!(exists(&path));
    drop(tmpfile);
    assert!(!exists(&path));
}

#[test]
fn test_persist() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_path = env::temp_dir().join("persisted_temporary_file");
    write!(tmpfile, "abcde").unwrap();
    {
        assert!(exists(&old_path));
        let mut f = tmpfile.persist(&persist_path).unwrap();
        assert!(!exists(&old_path));

        // Check original file
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }

    {
        // Try opening it at the new path.
        let mut f = File::open(&persist_path).unwrap();
        f.seek(SeekFrom::Start(0)).unwrap();
        let mut buf = String::new();
        f.read_to_string(&mut buf).unwrap();
        assert_eq!("abcde", buf);
    }
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_persist_noclobber() {
    let mut tmpfile = NamedTempFile::new().unwrap();
    let old_path = tmpfile.path().to_path_buf();
    let persist_target = NamedTempFile::new().unwrap();
    let persist_path = persist_target.path().to_path_buf();
    write!(tmpfile, "abcde").unwrap();
    assert!(exists(&old_path));
    {
        tmpfile = tmpfile.persist_noclobber(&persist_path).unwrap_err().into();
        assert!(exists(&old_path));
        std::fs::remove_file(&persist_path).unwrap();
        drop(persist_target);
    }
    tmpfile.persist_noclobber(&persist_path).unwrap();
    // Try opening it at the new path.
    let mut f = File::open(&persist_path).unwrap();
    f.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    f.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
    std::fs::remove_file(&persist_path).unwrap();
}

#[test]
fn test_customnamed() {
    let tmpfile = NamedTempFileOptions::new()
        .prefix("tmp")
        .suffix(&".rs".to_string())
        .rand_bytes(12)
        .create()
        .unwrap();
    let name = tmpfile.path().file_name().unwrap().to_str().unwrap();
    assert!(name.starts_with("tmp"));
    assert!(name.ends_with(".rs"));
    assert_eq!(name.len(), 18);
}

#[test]
fn test_reopen() {
    let source = NamedTempFile::new().unwrap();
    let mut first = source.reopen().unwrap();
    let mut second = source.reopen().unwrap();
    drop(source);

    write!(first, "abcde").expect("write failed");
    let mut buf = String::new();
    second.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_to_file() {
    let mut file = NamedTempFile::new().unwrap();
    let path = file.path().to_owned();
    write!(file, "abcde").expect("write failed");

    assert!(path.exists());
    let mut file: File = file.into();
    assert!(!path.exists());

    file.seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    file.read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}

#[test]
fn test_immut() {
    let tmpfile = NamedTempFile::new().unwrap();
    (&tmpfile).write_all(b"abcde").unwrap();
    (&tmpfile).seek(SeekFrom::Start(0)).unwrap();
    let mut buf = String::new();
    (&tmpfile).read_to_string(&mut buf).unwrap();
    assert_eq!("abcde", buf);
}
<|endoftext|>


<commit_before>extern crate redis;

use std::time::Duration;

use redis::{Connection, RedisError, cmd};

fn duration_to_millis(d: &Duration) -> u64 {
    (d.subsec_nanos() / 1_000_000) as u64 + d.as_secs()
}

macro_rules! option_arg {
    ($disque: expr, $name: expr, $param: expr) => (
        match $param {
            Some(u) => $disque.arg($name).arg(u),
            None => &mut $disque,
        };
    )
}
pub struct Disque {
    connection: Connection,
}

impl Disque {
    pub fn open(url: &str) -> Result<Disque, RedisError> {
        let client = try!(redis::Client::open(url));
        let connection = try!(client.get_connection());
        Ok(Disque { connection: connection })
    }

    pub fn hello(&self) -> Result<Vec<Vec<u8>>, RedisError> {
        cmd("HELLO").query(&self.connection)
    }

    pub fn addjob(&self, queue_name: &[u8], job: &[u8], timeout: Duration,
            replicate: Option<usize>, delay: Option<Duration>,
            retry: Option<Duration>, ttl: Option<Duration>,
            maxlen: Option<usize>, async: bool,
            ) -> Result<String, RedisError> {
        let mut c = cmd("ADDJOB");
        c
            .arg(queue_name)
            .arg(job)
            .arg(duration_to_millis(&timeout));
        option_arg!(c, "REPLICATE", replicate);
        option_arg!(c, "DELAY", delay.map(|x| x.as_secs()));
        option_arg!(c, "RETRY", retry.map(|x| x.as_secs()));
        option_arg!(c, "TTL", ttl.map(|x| x.as_secs()));
        option_arg!(c, "MAXLEN", maxlen);
        if async { c.arg("ASYNC"); }
        c.query(&self.connection)
    }

    pub fn getjob_count(&self, nohang: bool, timeout: Option<Duration>,
            count: usize, withcounters: bool, queues: &[&[u8]]
            ) -> Result<Vec<Vec<Vec<u8>>>, RedisError> {
        let mut c = cmd("GETJOB");
        if nohang { c.arg("NOHANG"); }
        option_arg!(c, "TIMEOUT", timeout.map(|t| duration_to_millis(&t)));
        c.arg("COUNT").arg(count);
        if withcounters { c.arg("WITHCOUNTERS"); }
        c.arg("FROM");
        for queue in queues { c.arg(*queue); }
        c.query(&self.connection)
    }

    pub fn getjob(&self, nohang: bool, timeout: Option<Duration>,
            withcounters: bool, queues: &[&[u8]]
            ) -> Result<Option<Vec<Vec<u8>>>, RedisError> {
        let mut jobs = try!(self.getjob_count(nohang, timeout, 1, withcounters,
                    queues));
        Ok(jobs.pop())
    }

    pub fn ackjob(&self, jobids: &[&[u8]]) -> Result<bool, RedisError> {
        let mut c = cmd("ACKJOB");
        for jobid in jobids { c.arg(*jobid); }
        c.query(&self.connection)
    }

    pub fn fastack(&self, jobids: &[&[u8]]) -> Result<bool, RedisError> {
        let mut c = cmd("FASTACK");
        for jobid in jobids { c.arg(*jobid); }
        c.query(&self.connection)
    }

    pub fn working(&self, jobid: &[u8]) -> Result<Duration, RedisError> {
        let retry = try!(cmd("WORKING").arg(jobid).query(&self.connection));
        Ok(Duration::from_secs(retry))
    }
}

#[cfg(test)]
fn conn() -> Disque {
    Disque::open("redis://127.0.0.1:7711/").unwrap()
}

#[test]
fn can_connect() {
    conn();
}

#[test]
fn hello() {
    let disque = conn();
    disque.hello().unwrap();
}

#[test]
fn addjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue", b"job", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert_eq!(jobid.len(), 48);
    assert_eq!(&jobid[..2], "DI");
    assert_eq!(&jobid[46..], "SQ");
}

#[test]
fn getjob_count() {
    let disque = conn();
    let j1 = disque.addjob(b"queue1", b"job1", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let j2 = disque.addjob(b"queue2", b"job2", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    disque.addjob(b"queue3", b"job3", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let jobs = disque.getjob_count(false, None, 3, true, &[b"queue1", b"queue2"]).unwrap();
    assert_eq!(jobs.len(), 2);
    assert_eq!(jobs[0][0], b"queue1");
    assert_eq!(jobs[0][1], j1.into_bytes());
    assert_eq!(jobs[0][2], b"job1");
    assert_eq!(jobs[1][0], b"queue2");
    assert_eq!(jobs[1][1], j2.into_bytes());
    assert_eq!(jobs[1][2], b"job2");
}

#[test]
fn getjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue4", b"job4", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let job = disque.getjob(false, None, true, &[b"queue4", b"queue5"]).unwrap().unwrap();
    assert_eq!(job[0], b"queue4");
    assert_eq!(job[1], jobid.into_bytes());
    assert_eq!(job[2], b"job4");
}

#[test]
fn ackjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue6", b"job6", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert!(disque.ackjob(&[jobid.as_bytes()]).unwrap());
    assert!(!disque.ackjob(&[jobid.as_bytes()]).unwrap());
    assert!(!disque.ackjob(&[jobid.as_bytes()]).unwrap());
}

#[test]
fn fastack() {
    let disque = conn();
    let jobid = disque.addjob(b"queue7", b"job7", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert!(disque.fastack(&[jobid.as_bytes()]).unwrap());
    assert!(!disque.fastack(&[jobid.as_bytes()]).unwrap());
    assert!(!disque.fastack(&[jobid.as_bytes()]).unwrap());
}

#[test]
fn working() {
    let disque = conn();
    let jobid = disque.addjob(b"queue8", b"job8", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert!(disque.working(jobid.as_bytes()).unwrap().as_secs() > 0);
}
<commit_msg>Use usize instead of bool for variadic job command<commit_after>extern crate redis;

use std::time::Duration;

use redis::{Connection, RedisError, cmd};

fn duration_to_millis(d: &Duration) -> u64 {
    (d.subsec_nanos() / 1_000_000) as u64 + d.as_secs()
}

macro_rules! option_arg {
    ($disque: expr, $name: expr, $param: expr) => (
        match $param {
            Some(u) => $disque.arg($name).arg(u),
            None => &mut $disque,
        };
    )
}
pub struct Disque {
    connection: Connection,
}

impl Disque {
    pub fn open(url: &str) -> Result<Disque, RedisError> {
        let client = try!(redis::Client::open(url));
        let connection = try!(client.get_connection());
        Ok(Disque { connection: connection })
    }

    pub fn hello(&self) -> Result<Vec<Vec<u8>>, RedisError> {
        cmd("HELLO").query(&self.connection)
    }

    pub fn addjob(&self, queue_name: &[u8], job: &[u8], timeout: Duration,
            replicate: Option<usize>, delay: Option<Duration>,
            retry: Option<Duration>, ttl: Option<Duration>,
            maxlen: Option<usize>, async: bool,
            ) -> Result<String, RedisError> {
        let mut c = cmd("ADDJOB");
        c
            .arg(queue_name)
            .arg(job)
            .arg(duration_to_millis(&timeout));
        option_arg!(c, "REPLICATE", replicate);
        option_arg!(c, "DELAY", delay.map(|x| x.as_secs()));
        option_arg!(c, "RETRY", retry.map(|x| x.as_secs()));
        option_arg!(c, "TTL", ttl.map(|x| x.as_secs()));
        option_arg!(c, "MAXLEN", maxlen);
        if async { c.arg("ASYNC"); }
        c.query(&self.connection)
    }

    pub fn getjob_count(&self, nohang: bool, timeout: Option<Duration>,
            count: usize, withcounters: bool, queues: &[&[u8]]
            ) -> Result<Vec<Vec<Vec<u8>>>, RedisError> {
        let mut c = cmd("GETJOB");
        if nohang { c.arg("NOHANG"); }
        option_arg!(c, "TIMEOUT", timeout.map(|t| duration_to_millis(&t)));
        c.arg("COUNT").arg(count);
        if withcounters { c.arg("WITHCOUNTERS"); }
        c.arg("FROM");
        for queue in queues { c.arg(*queue); }
        c.query(&self.connection)
    }

    pub fn getjob(&self, nohang: bool, timeout: Option<Duration>,
            withcounters: bool, queues: &[&[u8]]
            ) -> Result<Option<Vec<Vec<u8>>>, RedisError> {
        let mut jobs = try!(self.getjob_count(nohang, timeout, 1, withcounters,
                    queues));
        Ok(jobs.pop())
    }

    pub fn ackjob(&self, jobids: &[&[u8]]) -> Result<bool, RedisError> {
        let mut c = cmd("ACKJOB");
        for jobid in jobids { c.arg(*jobid); }
        c.query(&self.connection)
    }

    pub fn fastack(&self, jobids: &[&[u8]]) -> Result<usize, RedisError> {
        let mut c = cmd("FASTACK");
        for jobid in jobids { c.arg(*jobid); }
        c.query(&self.connection)
    }

    pub fn working(&self, jobid: &[u8]) -> Result<Duration, RedisError> {
        let retry = try!(cmd("WORKING").arg(jobid).query(&self.connection));
        Ok(Duration::from_secs(retry))
    }
}

#[cfg(test)]
fn conn() -> Disque {
    Disque::open("redis://127.0.0.1:7711/").unwrap()
}

#[test]
fn can_connect() {
    conn();
}

#[test]
fn hello() {
    let disque = conn();
    disque.hello().unwrap();
}

#[test]
fn addjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue", b"job", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert_eq!(jobid.len(), 48);
    assert_eq!(&jobid[..2], "DI");
    assert_eq!(&jobid[46..], "SQ");
}

#[test]
fn getjob_count() {
    let disque = conn();
    let j1 = disque.addjob(b"queue1", b"job1", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let j2 = disque.addjob(b"queue2", b"job2", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    disque.addjob(b"queue3", b"job3", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let jobs = disque.getjob_count(false, None, 3, true, &[b"queue1", b"queue2"]).unwrap();
    assert_eq!(jobs.len(), 2);
    assert_eq!(jobs[0][0], b"queue1");
    assert_eq!(jobs[0][1], j1.into_bytes());
    assert_eq!(jobs[0][2], b"job1");
    assert_eq!(jobs[1][0], b"queue2");
    assert_eq!(jobs[1][1], j2.into_bytes());
    assert_eq!(jobs[1][2], b"job2");
}

#[test]
fn getjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue4", b"job4", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    let job = disque.getjob(false, None, true, &[b"queue4", b"queue5"]).unwrap().unwrap();
    assert_eq!(job[0], b"queue4");
    assert_eq!(job[1], jobid.into_bytes());
    assert_eq!(job[2], b"job4");
}

#[test]
fn ackjob() {
    let disque = conn();
    let jobid = disque.addjob(b"queue6", b"job6", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert!(disque.ackjob(&[jobid.as_bytes()]).unwrap());
    assert!(!disque.ackjob(&[jobid.as_bytes()]).unwrap());
    assert!(!disque.ackjob(&[jobid.as_bytes()]).unwrap());
}

#[test]
fn fastack() {
    let disque = conn();
    let jobid = disque.addjob(b"queue7", b"job7", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert!(disque.fastack(&[jobid.as_bytes()]).unwrap() == 1);
    assert!(disque.fastack(&[jobid.as_bytes()]).unwrap() == 0);
    assert!(disque.fastack(&[jobid.as_bytes()]).unwrap() == 0);
}

#[test]
fn working() {
    let disque = conn();
    let jobid = disque.addjob(b"queue8", b"job8", Duration::from_secs(10), None, None, None, None, None, false).unwrap();
    assert!(disque.working(jobid.as_bytes()).unwrap().as_secs() > 0);
}
<|endoftext|>


<commit_before>/// for HTTPS
extern crate hyper;
/// to decode JSON data
extern crate rustc_serialize;

use std::fmt;
use std::io::Read;
use std::result::{Result};
use rustc_serialize::json::Json;
use hyper::{Client, Url};

static TESTAPIKEY: &'static str = "YOUR API KEY FROM themoviedb.org";

/// the struct to keep
pub struct TheMovieDB {
	/// the all mighty api key we need for each request
	api_key: &'static str,
	/// the base url for themoviedb.org
	base_url: &'static str,
	/// the base url for all images, comes from the /configuration URL
	image_base_url: String,
	/// the HTTPS client we use for getting data from the API
	http_client: Client,
}

impl fmt::Debug for TheMovieDB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TheMovieDB => ApiKey: {}, BaseURL: {}, ImageBaseURL: {}",
		 self.api_key,
		 self.base_url,
		 self.image_base_url)
    }
}

impl TheMovieDB {
	/// Constructs a new TheMovieDB instance.
	///
	/// # Examples
	///
	/// ```
	/// use std::rc::Rc;
	///
	/// let five = Rc::new(5);
	/// ```
	fn new(themoviedb_api_key: &'static str) -> Result<TheMovieDB, String> {
		let mut new_instance = TheMovieDB{api_key: themoviedb_api_key,
			base_url: "https://api.themoviedb.org/3",
			image_base_url: "".to_string(),
			http_client: Client::new()};

		let configuration_data = match new_instance.get_json_data_for("/configuration") {
			Ok(c) => c,
			Err(error_string) => return Err(error_string)
		};

		let json_obj = match configuration_data.as_object() {
			Some(o) => o,
			None => return Err("Error while getting JSON object".to_string())
		};

		new_instance.image_base_url = json_obj.get("images").unwrap().as_object().unwrap().get("secure_base_url").unwrap().to_string();

		Ok(new_instance)
	}

	fn search(& self, search_term: &'static str) -> Result<String, String> {
		let search_data = match self.get_json_data_for(search_term) {
			Ok(d) => d,
			Err(error_string) => return Err(error_string)
		};

		println!("{:?}", search_data);

		Err("FAILED".to_string())
	}

	/// Returns a URL as String for the given API method
	///
	/// It also automatically adds the api key
	fn get_url_for(& self, url_string: &'static str) -> Result<Url, String> {
//		if url_string.contains("?") {
			let result_url = match Url::parse(&format!("{}{}&api_key={}", self.base_url, url_string, self.api_key)) {
				Ok(u) => u,
				Err(_) => return Err(format!("Error buildign URL"))
			};
			Ok(result_url)
		// } else {
		// 	format!("{}{}?api_key={}", self.base_url, url_string, self.api_key)
//		}
	}

	/// Returns the data for a given API method or an error string if something has failed
	fn get_json_data_for(& self, url_string: &'static str) -> Result<Json, String> {
		let call_url = match self.get_url_for(url_string) {
			Ok(u) => u,
			Err(error_string) => return Err(error_string)
		};

		let call_url_string = format!("{}", call_url);
		let mut response = match self.http_client.get(call_url).send() {
			Ok(r) => r,
			Err(_) => {
				return Err(format!("Error during HTTPS request with URL {}", call_url_string));
			}
 		};

		if hyper::Ok != response.status {
			return Err(format!("No HTTPS Status 200 (OK) for url: {}", call_url_string));
		}

		let mut result = String::new();
		if response.read_to_string(& mut result).is_err() {
			return Err("Error reading response".to_string());
		}

		let json_data = match Json::from_str(&result) {
			Ok(d) => d,
			Err(_) => return Err("Error while readin JSON data".to_string())
		};

		Ok(json_data)
	}
}

#[test]
fn initialization_test() {
	TheMovieDB::new(TESTAPIKEY).unwrap();
}

#[test]
fn search_test() {
	let themoviedb = TheMovieDB::new(TESTAPIKEY).unwrap();
	let search_result = themoviedb.search("The Avengers").unwrap();
}
<commit_msg>Fixed get_url method and added first test for search method (not working!)<commit_after>/// for HTTPS
extern crate hyper;
/// to decode JSON data
extern crate rustc_serialize;

use std::fmt;
use std::io::Read;
use std::result::{Result};
use rustc_serialize::json::Json;
use hyper::{Client, Url};

static TESTAPIKEY: &'static str = "YOUR API KEY FROM themoviedb.org";

/// the struct to keep
pub struct TheMovieDB {
	/// the all mighty api key we need for each request
	api_key: &'static str,
	/// the base url for themoviedb.org
	base_url: &'static str,
	/// the base url for all images, comes from the /configuration URL
	image_base_url: String,
	/// the HTTPS client we use for getting data from the API
	http_client: Client,
}

impl fmt::Debug for TheMovieDB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "TheMovieDB => ApiKey: {}, BaseURL: {}, ImageBaseURL: {}",
		 self.api_key,
		 self.base_url,
		 self.image_base_url)
    }
}

impl TheMovieDB {
	/// Constructs a new TheMovieDB instance.
	///
	/// # Examples
	///
	/// ```
	/// use std::rc::Rc;
	///
	/// let five = Rc::new(5);
	/// ```
	fn new(themoviedb_api_key: &'static str) -> Result<TheMovieDB, String> {
		let mut new_instance = TheMovieDB{api_key: themoviedb_api_key,
			base_url: "https://api.themoviedb.org/3",
			image_base_url: "".to_string(),
			http_client: Client::new()};

		let configuration_data = match new_instance.get_json_data_for("/configuration".to_string()) {
			Ok(c) => c,
			Err(error_string) => return Err(error_string)
		};

		let json_obj = match configuration_data.as_object() {
			Some(o) => o,
			None => return Err("Error while getting JSON object".to_string())
		};

		new_instance.image_base_url = json_obj.get("images").unwrap().as_object().unwrap().get("secure_base_url").unwrap().to_string();

		Ok(new_instance)
	}

	fn search(& self, search_term: &'static str) -> Result<String, String> {
		let search_data = match self.get_json_data_for(format!("/search/multi?query={}", search_term)) {
			Ok(d) => d,
			Err(error_string) => return Err(error_string)
		};

		Ok("TEST".to_string())
	}

	/// Returns a URL as String for the given API method
	///
	/// It also automatically adds the api key
	fn get_url_for(& self, url_string: String) -> Result<Url, String> {
		if url_string.contains("?") {
			let result_url = match Url::parse(&format!("{}{}&api_key={}", self.base_url, url_string, self.api_key)) {
				Ok(u) => u,
				Err(_) => return Err(format!("Error buildign URL"))
			};
			Ok(result_url)
		 } else {
			 let result_url = match Url::parse(&format!("{}{}?api_key={}", self.base_url, url_string, self.api_key)) {
 				Ok(u) => u,
 				Err(_) => return Err(format!("Error buildign URL"))
 			};
 			Ok(result_url)
		}
	}

	/// Returns the data for a given API method or an error string if something has failed
	fn get_json_data_for(& self, url_string: String) -> Result<Json, String> {
		let call_url = match self.get_url_for(url_string) {
			Ok(u) => u,
			Err(error_string) => return Err(error_string)
		};

		let call_url_string = format!("{}", call_url);
		let mut response = match self.http_client.get(call_url).send() {
			Ok(r) => r,
			Err(_) => {
				return Err(format!("Error during HTTPS request with URL {}", call_url_string));
			}
 		};

		if hyper::Ok != response.status {
			return Err(format!("No HTTPS Status 200 (OK) for url: {}", call_url_string));
		}

		let mut result = String::new();
		if response.read_to_string(& mut result).is_err() {
			return Err("Error reading response".to_string());
		}

		let json_data = match Json::from_str(&result) {
			Ok(d) => d,
			Err(_) => return Err("Error while readin JSON data".to_string())
		};

		Ok(json_data)
	}
}

#[test]
fn initialization_test() {
	TheMovieDB::new(TESTAPIKEY).unwrap();
}

#[test]
fn search_test() {
	let themoviedb = TheMovieDB::new(TESTAPIKEY).unwrap();
	let search_result = themoviedb.search("The Avengers").unwrap();
}
<|endoftext|>