<commit_before>// This file is released under the same terms as Rust itself.

mod auth;

use crossbeam;
use db::{self, Db, DbBox, PendingEntry, QueueEntry, RunningEntry, Transaction};
use horrorshow::prelude::*;
use hyper::buffer::BufReader;
use hyper::header::{ContentType, Headers};
use hyper::net::{HttpListener, HttpStream, NetworkListener, NetworkStream};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;
use pipeline::{self, PipelineId};
use quickersort::sort_by;
use spmc;
use std::borrow::Cow;
use std::convert::AsRef;
use std::error::Error;
use std::fmt::{self, Formatter};
use std::io::{BufWriter, Write};
use std::marker::PhantomData;
use std::str::FromStr;
use std::sync::mpsc::{Receiver, Sender};
use ui::Pr;
use view::auth::AuthManager;

pub trait PipelinesConfig: Send + Sync + 'static {
    fn pipeline_by_name(&self, &str) -> Option<PipelineId>;
    fn all(&self) -> Vec<(Cow<str>, PipelineId)>;
}

pub use view::auth::{Auth, AuthRef};

const THREAD_COUNT: usize = 3;

pub struct Worker
 {
    listen: String,
    db_build: db::Builder,
    pipelines: Box<PipelinesConfig>,
    secret: String,
    auth: Auth,
    _pr: PhantomData
,
}

impl
 Worker

    where
::Err: Error,

::Err: Error,
{
    pub fn new(
        listen: String,
        db_build: db::Builder,
        pipelines: Box<PipelinesConfig>,
        secret: String,
        auth: Auth,
    ) -> Self {
        Worker {
            listen: listen,
            db_build: db_build,
            pipelines: pipelines,
            secret: secret,
            auth: auth.into(),
            _pr: PhantomData,
        }
    }
}

#[derive(Clone)]
pub enum Event {}

#[derive(Clone)]
pub enum Message {}

impl
 pipeline::Worker<Event, Message> for Worker

    where
::Err: Error,

::Err: Error,
{
    fn run(&self, _recv: Receiver<Message>, _send: Sender<Event>) {
        let listen: &str = self.listen.as_ref();
        let secret: &str = self.secret.as_ref();
        let auth: AuthRef = (&self.auth).into();
        let pipelines = &*self.pipelines;
        let db_build = &self.db_build;
        crossbeam::scope(|scope| {
            let mut threads = Vec::with_capacity(THREAD_COUNT);
            for _ in 0..THREAD_COUNT {
                let (send, recv) = spmc::channel();
                scope.spawn(move || {
                    let mut thread = Thread {
                        db: db_build.open()
                            .expect("opening DB to succeed"),
                        pipelines: pipelines,
                        auth_manager: AuthManager{
                            auth: auth,
                            secret: secret,
                        },
                        _pr: PhantomData::
,
                    };
                    thread.run(recv)
                });
                threads.push(send);
            }
            let mut listener = HttpListener::new(listen).expect("TCP socket");
            let mut i = 0;
            while let Ok(stream) = listener.accept() {
                threads[i].send(stream).unwrap();
                i += 1;
                i %= THREAD_COUNT;
            }
        });
    }
}

struct Thread<'a, P>
    where P: Pr
{
    db: DbBox
,
    pipelines: &'a PipelinesConfig,
    auth_manager: AuthManager<'a>,
    _pr: PhantomData
,
}

impl<'a, P: Pr> Thread<'a, P>
    where
::Err: Error,

::Err: Error,
{
    fn run(&mut self, recv: spmc::Receiver<HttpStream>) {
        while let Ok(mut stream) = recv.recv() {
            let addr = stream.peer_addr()
                .expect("view client address");
            let mut stream_clone = stream.clone();
            let mut buf_read = BufReader::new(
                &mut stream_clone as &mut NetworkStream
            );
            let mut buf_write = BufWriter::new(&mut stream);
            let req = match Request::new(&mut buf_read, addr) {
                Ok(req) => req,
                Err(e) => {
                    warn!("Invalid view HTTP: {:?}", e);
                    continue;
                }
            };
            let mut head = Headers::new();
            let res = Response::new(&mut buf_write, &mut head);
            match self.handle_req(req, res) {
                Ok(()) => (),
                Err(e) => {
                    warn!("Failed to handle view request: {:?}", e);
                }
            }
        }
    }
    fn handle_req(
        &mut self,
        req: Request,
        res: Response,
    ) -> Result<(), Box<Error>> {
        let (req, mut res) = match self.auth_manager.check(req, res) {
            auth::CheckResult::Authenticated(req, res) => (req, res),
            auth::CheckResult::Err(e) => return Err(Box::new(e)),
            auth::CheckResult::NotAuthenticated => return Ok(()),
        };
        let pipeline = if let RequestUri::AbsolutePath(ref path) = req.uri {
            let mut path = &path[..];
            if path == "/" {
                None
            } else {
                if path.as_bytes()[0] == b'/' {
                    path = &path[1..];
                }
                match self.pipelines.pipeline_by_name(path) {
                    Some(pipeline_id) => {
                        *res.status_mut() = StatusCode::Ok;
                        Some((path.to_owned(), pipeline_id))
                    }
                    None if path == "style.css" => {
                        res.headers_mut().set(ContentType(mime!(Text/Css)));
                        let mut res = try!(res.start());
                        try!(res.write_all(include_bytes!("style.css")));
                        return Ok(());
                    }
                    None => {
                        *res.status_mut() = StatusCode::NotFound;
                        return Ok(());
                    }
                }
            }
        } else {
            *res.status_mut() = StatusCode::BadRequest;
            return Ok(());
        };
        res.headers_mut().set(ContentType::html());
        let mut res = try!(res.start());
        try!(res.write_all(br##"<!DOCTYPE html>"##));
        if let Some((name, pipeline_id)) = pipeline {
            self.handle_pipeline_req(&name, pipeline_id, req, res)
        } else {
            self.handle_home_req(req, res)
        }
    }
    fn handle_pipeline_req(
        &mut self,
        name: &str,
        pipeline_id: PipelineId,
        _req: Request,
        mut res: Response<::hyper::net::Streaming>,
    ) -> Result<(), Box<Error>> {
        let (pending_entries, queued_entries, running_entry) =
            try!(self.db.transaction(InfoTransaction{
                pipeline_id: pipeline_id
            }).wc());
        let is_empty = pending_entries.is_empty();
        let mut running = None;
        let mut queued = Vec::new();
        let pending: Vec<_> = pending_entries.into_iter().filter_map(|entry| {
            if Some(&entry.pr) == running_entry.as_ref().map(|x| &x.pr) {
                running = Some(entry);
            } else if queued_entries.iter()
                    .filter(|q| q.pr == entry.pr)
                    .next().is_some() {
                queued.push(entry);
            } else {
                return Some(entry);
            }
            None
        }).collect();
        let html = html!{
            html {
                head {
                    title { : name }
                    link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.min.css");
                    link(rel="stylesheet", href="/style.css");
                }
                body {
                    h1 { : name }
                    table {
                        thead {
                            th { : "Status" }
                            th { : "PR#" }
                            th { : "Title" }
                        }
                        tbody {
                            |t| {
                                for entry in running {
                                    render_entry(State::Running, entry, t);
                                }
                                for entry in queued {
                                    render_entry(State::Queued, entry, t);
                                }
                                for entry in pending {
                                    render_entry(State::Pending, entry, t);
                                }
                                if is_empty {
                                    t << html!{
                                        td(colspan=3) {
                                            : "No opened pull requests"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        };
        try!(html.write_to_io(&mut res));
        try!(res.end());
        Ok(())
    }
    fn handle_home_req(
        &mut self,
        _req: Request,
        mut res: Response<::hyper::net::Streaming>,
    ) -> Result<(), Box<Error>> {
        let mut pipelines = self.pipelines.all();
        sort_by(&mut pipelines, &|a, b| a.0.cmp(&b.0));
        let html = html!{
            html {
                head {
                    title { : "Aelita" }
                    link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.min.css");
                    link(rel="stylesheet", href="/style.css");
                }
                body {
                    h1 { : "Pipelines" }
                    table {
                        thead {
                            th { : "Name" }
                            th { : "Running" }
                            th { : "In queue" }
                            th { : "In review" }
                            th { : "Opened" }
                        }
                        tbody {
                            @ for &(ref n, pid) in &pipelines { |t| {
                                let n = &**n;
                                let (opened, queue, running) =
                                    self.db.transaction(InfoTransaction{
                                        pipeline_id: pid
                                    }).unwrap_or((vec![], vec![], None));
                                let opened = opened.len();
                                let queue = queue.len();
                                let running = running.is_some();
                                let running = if running { 1 } else { 0 };
                                let review = opened - queue - running;
                                t << html!{
                                    tr {
                                        td(class="fill-link") {
                                            a(href=n) : { n }
                                        }
                                        td { : running }
                                        td { : queue }
                                        td { : review }
                                        td { : opened }
                                    }
                                }
                            }}
                            @ if pipelines.is_empty() {
                                td(colspan=5) {
                                    : "No configured repositories"
                                }
                            }
                        }
                    }
                    h2 { : "Github cheat sheet" }
                    p { : "To use the robot, say a command to it." }
                    dl {
                        dt { : raw!("r+") }
                        dd { : "Add the pull request to the merge queue." }
                        dt { : raw!("r=@username") }
                        dd { : "Add the pull request as \"username.\"" }
                        dt { : raw!("r-") }
                        dd { : "Cancel the pull request." }
                        dt { : raw!("try+") }
                        dd { : "Test the pull request without merging it." }
                        dt { : raw!("try-") }
                        dd { : "Cancel the pull request." }
                    }
                }
            }
        };
        try!(html.write_to_io(&mut res));
        try!(res.end());
        Ok(())
    }
}

struct InfoTransaction {
    pipeline_id: PipelineId,
}

impl
 Transaction
 for InfoTransaction {
    type Return = (
        Vec<PendingEntry
>,
        Vec<QueueEntry
>,
        Option<RunningEntry
>,
    );
    fn run<D: Db
>(
        self,
        db: &mut D
    ) -> Result<Self::Return, Box<Error + Send + Sync>> {
        retry!{{
            let pending_entries = retry_unwrap!(
                db.list_pending(self.pipeline_id)
            );
            let queued_entries = retry_unwrap!(
                db.list_queue(self.pipeline_id)
            );
            let running_entry = retry_unwrap!(
                db.peek_running(self.pipeline_id)
            );
            Ok((pending_entries, queued_entries, running_entry))
        }}
    }
}

/// Since there is no way to convert Box<Error+Send+Sync> to Box<Error>
/// without wrapping it, this is a hack to wrap it.
#[derive(Debug)]
struct WrapConvert (
    Box<Error + Send + Sync>,
);

impl Error for WrapConvert {
    fn description(&self) -> &str {
        self.0.description()
    }
    fn cause(&self) -> Option<&Error> {
        Some(&*self.0)
    }
}

impl fmt::Display for WrapConvert {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.0.fmt(fmt)
    }
}

trait WrapConvertable<T> {
    fn wc(self) -> Result<T, Box<Error>>;
}

impl<T> WrapConvertable<T> for Result<T, Box<Error + Send + Sync>> {
    fn wc(self) -> Result<T, Box<Error>> {
        self.map_err(|x| Box::new(WrapConvert(x)) as Box<Error>)
    }
}

enum State {
    Running,
    Queued,
    Pending,
}

fn render_entry
(
    state: State,
    entry: PendingEntry
,
    t: &mut TemplateBuffer,
) {
    t < "Running",
                    State::Queued => "In queue",
                    State::Pending => "In review",
                }
            }
            td(class="fill-link") {
                a(href=entry.url.to_string()) { : entry.pr.to_string() }
            }
            td { : &entry.title }
        }
    };
}
<commit_msg>Fix mobile view display<commit_after>// This file is released under the same terms as Rust itself.

mod auth;

use crossbeam;
use db::{self, Db, DbBox, PendingEntry, QueueEntry, RunningEntry, Transaction};
use horrorshow::prelude::*;
use hyper::buffer::BufReader;
use hyper::header::{ContentType, Headers};
use hyper::net::{HttpListener, HttpStream, NetworkListener, NetworkStream};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;
use pipeline::{self, PipelineId};
use quickersort::sort_by;
use spmc;
use std::borrow::Cow;
use std::convert::AsRef;
use std::error::Error;
use std::fmt::{self, Formatter};
use std::io::{BufWriter, Write};
use std::marker::PhantomData;
use std::str::FromStr;
use std::sync::mpsc::{Receiver, Sender};
use ui::Pr;
use view::auth::AuthManager;

pub trait PipelinesConfig: Send + Sync + 'static {
    fn pipeline_by_name(&self, &str) -> Option<PipelineId>;
    fn all(&self) -> Vec<(Cow<str>, PipelineId)>;
}

pub use view::auth::{Auth, AuthRef};

const THREAD_COUNT: usize = 3;

pub struct Worker
 {
    listen: String,
    db_build: db::Builder,
    pipelines: Box<PipelinesConfig>,
    secret: String,
    auth: Auth,
    _pr: PhantomData
,
}

impl
 Worker

    where
::Err: Error,

::Err: Error,
{
    pub fn new(
        listen: String,
        db_build: db::Builder,
        pipelines: Box<PipelinesConfig>,
        secret: String,
        auth: Auth,
    ) -> Self {
        Worker {
            listen: listen,
            db_build: db_build,
            pipelines: pipelines,
            secret: secret,
            auth: auth.into(),
            _pr: PhantomData,
        }
    }
}

#[derive(Clone)]
pub enum Event {}

#[derive(Clone)]
pub enum Message {}

impl
 pipeline::Worker<Event, Message> for Worker

    where
::Err: Error,

::Err: Error,
{
    fn run(&self, _recv: Receiver<Message>, _send: Sender<Event>) {
        let listen: &str = self.listen.as_ref();
        let secret: &str = self.secret.as_ref();
        let auth: AuthRef = (&self.auth).into();
        let pipelines = &*self.pipelines;
        let db_build = &self.db_build;
        crossbeam::scope(|scope| {
            let mut threads = Vec::with_capacity(THREAD_COUNT);
            for _ in 0..THREAD_COUNT {
                let (send, recv) = spmc::channel();
                scope.spawn(move || {
                    let mut thread = Thread {
                        db: db_build.open()
                            .expect("opening DB to succeed"),
                        pipelines: pipelines,
                        auth_manager: AuthManager{
                            auth: auth,
                            secret: secret,
                        },
                        _pr: PhantomData::
,
                    };
                    thread.run(recv)
                });
                threads.push(send);
            }
            let mut listener = HttpListener::new(listen).expect("TCP socket");
            let mut i = 0;
            while let Ok(stream) = listener.accept() {
                threads[i].send(stream).unwrap();
                i += 1;
                i %= THREAD_COUNT;
            }
        });
    }
}

struct Thread<'a, P>
    where P: Pr
{
    db: DbBox
,
    pipelines: &'a PipelinesConfig,
    auth_manager: AuthManager<'a>,
    _pr: PhantomData
,
}

impl<'a, P: Pr> Thread<'a, P>
    where
::Err: Error,

::Err: Error,
{
    fn run(&mut self, recv: spmc::Receiver<HttpStream>) {
        while let Ok(mut stream) = recv.recv() {
            let addr = stream.peer_addr()
                .expect("view client address");
            let mut stream_clone = stream.clone();
            let mut buf_read = BufReader::new(
                &mut stream_clone as &mut NetworkStream
            );
            let mut buf_write = BufWriter::new(&mut stream);
            let req = match Request::new(&mut buf_read, addr) {
                Ok(req) => req,
                Err(e) => {
                    warn!("Invalid view HTTP: {:?}", e);
                    continue;
                }
            };
            let mut head = Headers::new();
            let res = Response::new(&mut buf_write, &mut head);
            match self.handle_req(req, res) {
                Ok(()) => (),
                Err(e) => {
                    warn!("Failed to handle view request: {:?}", e);
                }
            }
        }
    }
    fn handle_req(
        &mut self,
        req: Request,
        res: Response,
    ) -> Result<(), Box<Error>> {
        let (req, mut res) = match self.auth_manager.check(req, res) {
            auth::CheckResult::Authenticated(req, res) => (req, res),
            auth::CheckResult::Err(e) => return Err(Box::new(e)),
            auth::CheckResult::NotAuthenticated => return Ok(()),
        };
        let pipeline = if let RequestUri::AbsolutePath(ref path) = req.uri {
            let mut path = &path[..];
            if path == "/" {
                None
            } else {
                if path.as_bytes()[0] == b'/' {
                    path = &path[1..];
                }
                match self.pipelines.pipeline_by_name(path) {
                    Some(pipeline_id) => {
                        *res.status_mut() = StatusCode::Ok;
                        Some((path.to_owned(), pipeline_id))
                    }
                    None if path == "style.css" => {
                        res.headers_mut().set(ContentType(mime!(Text/Css)));
                        let mut res = try!(res.start());
                        try!(res.write_all(include_bytes!("style.css")));
                        return Ok(());
                    }
                    None => {
                        *res.status_mut() = StatusCode::NotFound;
                        return Ok(());
                    }
                }
            }
        } else {
            *res.status_mut() = StatusCode::BadRequest;
            return Ok(());
        };
        res.headers_mut().set(ContentType::html());
        let mut res = try!(res.start());
        try!(res.write_all(br##"<!DOCTYPE html>"##));
        if let Some((name, pipeline_id)) = pipeline {
            self.handle_pipeline_req(&name, pipeline_id, req, res)
        } else {
            self.handle_home_req(req, res)
        }
    }
    fn handle_pipeline_req(
        &mut self,
        name: &str,
        pipeline_id: PipelineId,
        _req: Request,
        mut res: Response<::hyper::net::Streaming>,
    ) -> Result<(), Box<Error>> {
        let (pending_entries, queued_entries, running_entry) =
            try!(self.db.transaction(InfoTransaction{
                pipeline_id: pipeline_id
            }).wc());
        let is_empty = pending_entries.is_empty();
        let mut running = None;
        let mut queued = Vec::new();
        let pending: Vec<_> = pending_entries.into_iter().filter_map(|entry| {
            if Some(&entry.pr) == running_entry.as_ref().map(|x| &x.pr) {
                running = Some(entry);
            } else if queued_entries.iter()
                    .filter(|q| q.pr == entry.pr)
                    .next().is_some() {
                queued.push(entry);
            } else {
                return Some(entry);
            }
            None
        }).collect();
        let html = html!{
            html {
                head {
                    title { : name }
                    link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.min.css");
                    link(rel="stylesheet", href="/style.css");
                    meta(name="viewport", content="width=device-width");
                }
                body {
                    h1 { : name }
                    table {
                        thead {
                            th { : "Status" }
                            th { : "PR#" }
                            th { : "Title" }
                        }
                        tbody {
                            |t| {
                                for entry in running {
                                    render_entry(State::Running, entry, t);
                                }
                                for entry in queued {
                                    render_entry(State::Queued, entry, t);
                                }
                                for entry in pending {
                                    render_entry(State::Pending, entry, t);
                                }
                                if is_empty {
                                    t << html!{
                                        td(colspan=3) {
                                            : "No opened pull requests"
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        };
        try!(html.write_to_io(&mut res));
        try!(res.end());
        Ok(())
    }
    fn handle_home_req(
        &mut self,
        _req: Request,
        mut res: Response<::hyper::net::Streaming>,
    ) -> Result<(), Box<Error>> {
        let mut pipelines = self.pipelines.all();
        sort_by(&mut pipelines, &|a, b| a.0.cmp(&b.0));
        let html = html!{
            html {
                head {
                    title { : "Aelita" }
                    link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.1.1/normalize.min.css");
                    link(rel="stylesheet", href="/style.css");
                    meta(name="viewport", content="width=device-width");
                }
                body {
                    h1 { : "Repositories" }
                    table {
                        thead {
                            th { : "Name" }
                            th { : "Running" }
                            th { : "In queue" }
                            th { : "In review" }
                            th { : "Opened" }
                        }
                        tbody {
                            @ for &(ref n, pid) in &pipelines { |t| {
                                let n = &**n;
                                let (opened, queue, running) =
                                    self.db.transaction(InfoTransaction{
                                        pipeline_id: pid
                                    }).unwrap_or((vec![], vec![], None));
                                let opened = opened.len();
                                let queue = queue.len();
                                let running = running.is_some();
                                let running = if running { 1 } else { 0 };
                                let review = opened - queue - running;
                                t << html!{
                                    tr {
                                        td(class="fill-link") {
                                            a(href=n) : { n }
                                        }
                                        td { : running }
                                        td { : queue }
                                        td { : review }
                                        td { : opened }
                                    }
                                }
                            }}
                            @ if pipelines.is_empty() {
                                td(colspan=5) {
                                    : "No configured repositories"
                                }
                            }
                        }
                    }
                    h2 { : "Github cheat sheet" }
                    p { : "To use the robot, say a command to it." }
                    dl {
                        dt { : raw!("r+") }
                        dd { : "Add the pull request to the merge queue." }
                        dt { : raw!("r=@username") }
                        dd { : "Add the pull request as \"username.\"" }
                        dt { : raw!("r-") }
                        dd { : "Cancel the pull request." }
                    }
                }
            }
        };
        try!(html.write_to_io(&mut res));
        try!(res.end());
        Ok(())
    }
}

struct InfoTransaction {
    pipeline_id: PipelineId,
}

impl
 Transaction
 for InfoTransaction {
    type Return = (
        Vec<PendingEntry
>,
        Vec<QueueEntry
>,
        Option<RunningEntry
>,
    );
    fn run<D: Db
>(
        self,
        db: &mut D
    ) -> Result<Self::Return, Box<Error + Send + Sync>> {
        retry!{{
            let pending_entries = retry_unwrap!(
                db.list_pending(self.pipeline_id)
            );
            let queued_entries = retry_unwrap!(
                db.list_queue(self.pipeline_id)
            );
            let running_entry = retry_unwrap!(
                db.peek_running(self.pipeline_id)
            );
            Ok((pending_entries, queued_entries, running_entry))
        }}
    }
}

/// Since there is no way to convert Box<Error+Send+Sync> to Box<Error>
/// without wrapping it, this is a hack to wrap it.
#[derive(Debug)]
struct WrapConvert (
    Box<Error + Send + Sync>,
);

impl Error for WrapConvert {
    fn description(&self) -> &str {
        self.0.description()
    }
    fn cause(&self) -> Option<&Error> {
        Some(&*self.0)
    }
}

impl fmt::Display for WrapConvert {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.0.fmt(fmt)
    }
}

trait WrapConvertable<T> {
    fn wc(self) -> Result<T, Box<Error>>;
}

impl<T> WrapConvertable<T> for Result<T, Box<Error + Send + Sync>> {
    fn wc(self) -> Result<T, Box<Error>> {
        self.map_err(|x| Box::new(WrapConvert(x)) as Box<Error>)
    }
}

enum State {
    Running,
    Queued,
    Pending,
}

fn render_entry
(
    state: State,
    entry: PendingEntry
,
    t: &mut TemplateBuffer,
) {
    t < "Running",
                    State::Queued => "In queue",
                    State::Pending => "In review",
                }
            }
            td(class="fill-link") {
                a(href=entry.url.to_string()) { : entry.pr.to_string() }
            }
            td { : &entry.title }
        }
    };
}
<|endoftext|>


<commit_before>use chrono::{DateTime, Utc};
use feeds::Envelope;
use feeds::Message;
use types::ToIso8601;
use xmlhelper::encode;

#[derive(Debug, Serialize)]
pub struct OrderFulfillmentMessage {
  pub message_id: String,
  pub amazon_order_id: String,
  pub fulfillment_date: DateTime<Utc>,
  pub carrier_name: String,
  pub shipping_method: String,
  pub shipper_tracking_number: String,
  pub items: Vec<OrderFulfillmentItem>,
}

#[derive(Debug, Serialize)]
pub struct OrderFulfillmentItem {
  pub amazon_order_item_code: String,
  pub quantity: i32,
}

impl Message for OrderFulfillmentMessage {
  fn get_message_type() -> &'static str {
    "OrderFulfillment"
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<OrderFulfillmentMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      for message in self.messages.iter() {
        let fulfillment_date = message.data.fulfillment_date.to_iso8601();
        write_xml!(w,
          Message[][
            MessageID[][
              (&message.data.message_id)
            ]
            OperationType[][
              "Update"
            ]
            OrderFulfillment[][
              AmazonOrderID[][
                (&message.data.amazon_order_id)
              ]
              FulfillmentDate[][
                (&fulfillment_date)
              ]
              FulfillmentData[][
                CarrierName[][
                  (&message.data.carrier_name)
                ]
                ShippingMethod[][
                  (&message.data.shipping_method)
                ]
                ShipperTrackingNumber[][
                  (&message.data.shipper_tracking_number)
                ]
              ]
              [{
                for item in &message.data.items {
                  let quantity = item.quantity.to_string();
                  write_xml!(w,
                    Item[][
                      AmazonOrderItemCode[][
                        (&item.amazon_order_item_code)
                      ]
                      Quantity[][
                        (&quantity)
                      ]
                    ]
                  )?;
                }
                Ok(())
              }]
            ]
          ]
        )?;
      }
      Ok(())
    })
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use chrono::FixedOffset;
  use feeds::OperationType;
  use xmlhelper::encode::XmlWrite;
  use xmlhelper::encode::{EmitterConfig, EventWriter};

  #[test]
  fn test_order_fulfillment_feed() {
    let mut writer =
      EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<OrderFulfillmentMessage>::new("1234567890".to_owned());
      e.add_message(
        OrderFulfillmentMessage {
          message_id: "1".to_string(),
          amazon_order_id: "112-3739032-8075461".to_string(),
          fulfillment_date: DateTime::<FixedOffset>::parse_from_rfc3339(
            "2018-12-06T17:08:31.760132Z",
          )
          .unwrap()
          .with_timezone(&Utc),
          carrier_name: "UPS".to_string(),
          shipping_method: "Standard".to_string(),
          shipper_tracking_number: "1Z71178X0261236762".to_string(),
          items: vec![OrderFulfillmentItem {
            amazon_order_item_code: "56323517235162".to_string(),
            quantity: 1,
          }],
        },
        Some(OperationType::Update),
      );
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(
      xml,
      r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>OrderFulfillment</MessageType>
  <Message>
    <MessageID>1</MessageID>
    <OperationType>Update</OperationType>
    <OrderFulfillment>
      <AmazonOrderID>112-3739032-8075461</AmazonOrderID>
      <FulfillmentDate>2018-12-06T17:08:31Z</FulfillmentDate>
      <FulfillmentData>
        <CarrierName>UPS</CarrierName>
        <ShippingMethod>Standard</ShippingMethod>
        <ShipperTrackingNumber>1Z71178X0261236762</ShipperTrackingNumber>
      </FulfillmentData>
      <Item>
        <AmazonOrderItemCode>56323517235162</AmazonOrderItemCode>
        <Quantity>1</Quantity>
      </Item>
    </OrderFulfillment>
  </Message>
</AmazonEnvelope>"#
    );
  }
}
<commit_msg>add transparency_code to order fulfillment feed<commit_after>use chrono::{DateTime, Utc};
use feeds::Envelope;
use feeds::Message;
use types::ToIso8601;
use xmlhelper::encode;

#[derive(Debug, Serialize)]
pub struct OrderFulfillmentMessage {
  pub message_id: String,
  pub amazon_order_id: String,
  pub fulfillment_date: DateTime<Utc>,
  pub carrier_name: String,
  pub shipping_method: String,
  pub shipper_tracking_number: String,
  pub items: Vec<OrderFulfillmentItem>,
}

#[derive(Debug, Serialize)]
pub struct OrderFulfillmentItem {
  pub amazon_order_item_code: String,
  pub quantity: i32,
  pub transparency_code: Option<String>,
}

impl Message for OrderFulfillmentMessage {
  fn get_message_type() -> &'static str {
    "OrderFulfillment"
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<OrderFulfillmentMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      for message in self.messages.iter() {
        let fulfillment_date = message.data.fulfillment_date.to_iso8601();
        write_xml!(w,
          Message[][
            MessageID[][
              (&message.data.message_id)
            ]
            OperationType[][
              "Update"
            ]
            OrderFulfillment[][
              AmazonOrderID[][
                (&message.data.amazon_order_id)
              ]
              FulfillmentDate[][
                (&fulfillment_date)
              ]
              FulfillmentData[][
                CarrierName[][
                  (&message.data.carrier_name)
                ]
                ShippingMethod[][
                  (&message.data.shipping_method)
                ]
                ShipperTrackingNumber[][
                  (&message.data.shipper_tracking_number)
                ]
              ]
              [{
                for item in &message.data.items {
                  let quantity = item.quantity.to_string();
                  if let Some(tcode) = item.transparency_code.as_ref() {
                    write_xml!(w,
                      Item[][
                        AmazonOrderItemCode[][
                          (&item.amazon_order_item_code)
                        ]
                        Quantity[][
                          (&quantity)
                        ]
                        TransparencyCode[][
                          (tcode.as_str())
                        ]
                      ]
                    )?;
                  } else {
                    write_xml!(w,
                      Item[][
                        AmazonOrderItemCode[][
                          (&item.amazon_order_item_code)
                        ]
                        Quantity[][
                          (&quantity)
                        ]
                      ]
                    )?;
                  }
                }
                Ok(())
              }]
            ]
          ]
        )?;
      }
      Ok(())
    })
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use chrono::FixedOffset;
  use feeds::OperationType;
  use xmlhelper::encode::XmlWrite;
  use xmlhelper::encode::{EmitterConfig, EventWriter};

  #[test]
  fn test_order_fulfillment_feed() {
    let mut writer =
      EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<OrderFulfillmentMessage>::new("1234567890".to_owned());
      e.add_message(
        OrderFulfillmentMessage {
          message_id: "1".to_string(),
          amazon_order_id: "112-3739032-8075461".to_string(),
          fulfillment_date: DateTime::<FixedOffset>::parse_from_rfc3339(
            "2018-12-06T17:08:31.760132Z",
          )
          .unwrap()
          .with_timezone(&Utc),
          carrier_name: "UPS".to_string(),
          shipping_method: "Standard".to_string(),
          shipper_tracking_number: "1Z71178X0261236762".to_string(),
          items: vec![OrderFulfillmentItem {
            amazon_order_item_code: "56323517235162".to_string(),
            quantity: 1,
            transparency_code: None,
          }],
        },
        Some(OperationType::Update),
      );
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(
      xml,
      r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>OrderFulfillment</MessageType>
  <Message>
    <MessageID>1</MessageID>
    <OperationType>Update</OperationType>
    <OrderFulfillment>
      <AmazonOrderID>112-3739032-8075461</AmazonOrderID>
      <FulfillmentDate>2018-12-06T17:08:31Z</FulfillmentDate>
      <FulfillmentData>
        <CarrierName>UPS</CarrierName>
        <ShippingMethod>Standard</ShippingMethod>
        <ShipperTrackingNumber>1Z71178X0261236762</ShipperTrackingNumber>
      </FulfillmentData>
      <Item>
        <AmazonOrderItemCode>56323517235162</AmazonOrderItemCode>
        <Quantity>1</Quantity>
      </Item>
    </OrderFulfillment>
  </Message>
</AmazonEnvelope>"#
    );
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;

extern crate redis;
extern crate serde;
extern crate serde_bytes;
extern crate serde_redis;

use std::collections::HashMap;

use serde::Deserialize;
use serde_redis::{from_redis_value, Deserializer};

use redis::Value;

#[test]
fn deserialize_unit_struct_string() {
    let v = Value::Data(b"hello".to_vec());

    #[derive(Deserialize, Debug, PartialEq)]
    struct Unit(String);

    let de = Deserializer::new(v);
    let actual: Unit = Deserialize::deserialize(de).unwrap();

    let expected = Unit("hello".to_owned());
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_unit_struct_u8_redis_int() {
    let num = 5u8;
    let v = Value::Int(num as i64);

    #[derive(Deserialize, Debug, PartialEq)]
    struct IntUnit(u8);

    let de = Deserializer::new(v);
    let actual: IntUnit = Deserialize::deserialize(de).unwrap();

    let expected = IntUnit(num);
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_bool() {
    let v = vec![
        Value::Data(b"0".to_vec()),
        Value::Data(b"false".to_vec()),
        Value::Data(b"False".to_vec()),
        Value::Data(b"1".to_vec()),
        Value::Data(b"true".to_vec()),
        Value::Data(b"True".to_vec()),
    ];

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Vec<bool> = Deserialize::deserialize(de).unwrap();

    let expected = [false, false, false, true, true, true];
    assert_eq!(&expected, &actual[..]);
}

#[test]
fn deserialize_tuple() {
    let v = vec![Value::Int(5), Value::Data(b"hello".to_vec())];

    let de = Deserializer::new(Value::Bulk(v));
    let actual: (u8, String) = Deserialize::deserialize(de).unwrap();

    let expected = (5, "hello".to_owned());
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct() {
    let v = vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_hash_map_strings() {
    let v = vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ];

    let mut expected = HashMap::new();
    expected.insert("a".to_string(), "apple".to_string());
    expected.insert("b".to_string(), "banana".to_string());

    let de = Deserializer::new(Value::Bulk(v));
    let actual: HashMap<String, String> = Deserialize::deserialize(de).unwrap();

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_float() {
    let v = Value::Data(b"3.14159".to_vec());

    let expected = "3.14159".parse::<f32>().unwrap();

    let de = Deserializer::new(v);
    let actual: f32 = Deserialize::deserialize(de).unwrap();

    assert_eq!(actual, expected);
}

#[test]
fn deserialize_hash_map_string_u8() {
    let v = vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"1".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"2".to_vec()),
    ];

    let mut expected = HashMap::new();
    expected.insert("a".to_string(), 1);
    expected.insert("b".to_string(), 2);

    let de = Deserializer::new(Value::Bulk(v));
    let actual: HashMap<String, u8> = Deserialize::deserialize(de).unwrap();

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct_out_of_order() {
    let v = vec![
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct_extra_keys() {
    let v = vec![
        Value::Data(b"c".to_vec()),
        Value::Data(b"cranberry".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_enum() {
    let v = Value::Data(b"Orange".to_vec());

    #[derive(Debug, Deserialize, PartialEq)]
    enum Fruit {
        Orange,
        Apple,
    }

    let de = Deserializer::new(v);
    let actual: Fruit = Deserialize::deserialize(de).unwrap();

    assert_eq!(Fruit::Orange, actual);
}

#[test]
fn deserialize_option() {
    let de = Deserializer::new(Value::Nil);
    let actual: Option<u8> = Deserialize::deserialize(de).unwrap();

    assert_eq!(None, actual);
}

#[test]
fn deserialize_complex_struct() {
    let v = vec![
        Value::Data(b"num".to_vec()),
        Value::Data(b"10".to_vec()),
        Value::Data(b"opt".to_vec()),
        Value::Data(b"yes".to_vec()),
        Value::Data(b"s".to_vec()),
        Value::Data(b"yarn".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Complex {
        num: usize,
        opt: Option<String>,
        not_present: Option<String>,
        s: String,
    }

    let expected = Complex {
        num: 10,
        opt: Some("yes".to_owned()),
        not_present: None,
        s: "yarn".to_owned(),
    };

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Complex = Deserialize::deserialize(de).unwrap();

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_vec_of_strings() {
    let v = vec![
        Value::Data(b"first".to_vec()),
        Value::Data(b"second".to_vec()),
        Value::Data(b"third".to_vec()),
    ];

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Vec<String> = Deserialize::deserialize(de).unwrap();

    let expected = vec![
        "first".to_string(),
        "second".to_string(),
        "third".to_string(),
    ];
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_vec_of_newtype() {
    let v = vec![
        Value::Data(b"first".to_vec()),
        Value::Data(b"second".to_vec()),
        Value::Data(b"third".to_vec()),
    ];

    #[derive(Debug, PartialEq, Deserialize)]
    struct Rank(String);

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Vec<Rank> = Deserialize::deserialize(de).unwrap();

    let expected = vec![
        Rank("first".into()),
        Rank("second".into()),
        Rank("third".into()),
    ];

    assert_eq!(expected, actual);
}

/// Test for deserializing pipelined structs
///
/// In pipeline mode, there is nested bulk items that are returned. The original implementation did
/// not handle this.
#[test]
fn deserialize_pipelined_hmap() {
    let values = Value::Bulk(vec![
        Value::Bulk(vec![
            Value::Data(b"a".to_vec()),
            Value::Data(b"apple".to_vec()),
            Value::Data(b"b".to_vec()),
            Value::Data(b"banana".to_vec()),
        ]),
        Value::Bulk(vec![
            Value::Data(b"a".to_vec()),
            Value::Data(b"art".to_vec()),
            Value::Data(b"b".to_vec()),
            Value::Data(b"bold".to_vec()),
        ]),
    ]);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(values);
    let actual: Vec<Simple> = Deserialize::deserialize(de).unwrap();

    let expected = vec![
        Simple {
            a: "apple".to_owned(),
            b: "banana".to_owned(),
        },
        Simple {
            a: "art".to_owned(),
            b: "bold".to_owned(),
        },
    ];

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_pipelined_single_hmap() {
    let values = Value::Bulk(vec![Value::Bulk(vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ])]);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(values);
    let actual: Vec<Simple> = Deserialize::deserialize(de).unwrap();

    let expected = vec![Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    }];

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct_with_newtype_field() {
    let v = vec![
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Fruit(String);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: Fruit,
        b: Fruit,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: Fruit(String::from("apple")),
        b: Fruit(String::from("banana")),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_byte_buf() {
    let de = Deserializer::new(Value::Data(b"0000".to_vec()));
    let actual: serde_bytes::ByteBuf = Deserialize::deserialize(de).unwrap();

    let expected = b"0000";
    assert_eq!(expected, &actual[..]);
}

#[test]
fn deserialize_pipelined_single_hmap_newtype_fields() {
    #[derive(Debug, Deserialize, PartialEq)]
    struct Fruit(String);

    let values = Value::Bulk(vec![Value::Bulk(vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ])]);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: Fruit,
        b: Fruit,
    }

    let de = Deserializer::new(values);
    let actual: Vec<Simple> = Deserialize::deserialize(de).unwrap();

    let expected = vec![Simple {
        a: Fruit(String::from("apple")),
        b: Fruit(String::from("banana")),
    }];

    assert_eq!(expected, actual);
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Details {
    pub time: i64,
    pub count: u32,
    pub ids: Vec<String>,
}

type MapMapList = ::std::collections::HashMap<String, Details>;

#[test]
fn deserialize_nested_map_map_list() {
    let value = Value::Bulk(vec![
        Value::Data(b"key".to_vec()),
        Value::Bulk(vec![
            Value::Data(b"count".to_vec()),
            Value::Data(b"4".to_vec()),
            Value::Data(b"time".to_vec()),
            Value::Data(b"1473359995".to_vec()),
            Value::Data(b"ids".to_vec()),
            Value::Bulk(vec![
                Value::Data(b"00000000-0000-0000-0000-000000000000".to_vec()),
                Value::Data(b"00000000-0000-0000-0000-000000000001".to_vec()),
                Value::Data(b"00000000-0000-0000-0000-000000000002".to_vec()),
            ]),
        ]),
    ]);

    let de = Deserializer::new(value);
    let map: MapMapList = Deserialize::deserialize(de).unwrap();

    let nest = map.get("key").unwrap();
    assert_eq!(nest.count, 4);
    assert_eq!(nest.time, 1473359995);
    assert_eq!(
        &nest.ids[..],
        &[
            String::from("00000000-0000-0000-0000-000000000000"),
            String::from("00000000-0000-0000-0000-000000000001"),
            String::from("00000000-0000-0000-0000-000000000002")
        ]
    );
}

#[test]
#[should_panic]
fn deserialize_nested_item() {
    let value = Value::Bulk(vec![Value::Bulk(vec![Value::Data(b"hi".to_vec())])]);

    let de = Deserializer::new(value);
    let _hellos: Vec<String> = Deserialize::deserialize(de).unwrap();
}

#[test]
fn test_flatten_inner() {
    /*
    [INFO tarpaulin] Coverage Results:
    || Tested/Total Lines:
    || src/decode.rs: 39/187
    || src/lib.rs: 2/14
    || tests/de.rs: 6/250
    ||
    10.42% coverage, 47/451 lines covered
    */
    #[derive(Deserialize, Debug)]
    struct Foo {
        id: u32,
    }

    #[derive(Deserialize, Debug)]
    struct Wrapped {
        #[serde(flatten)]
        foo: Foo,
    }

    let value = Value::Bulk(vec![
        Value::Data(b"id".to_vec()),
        Value::Data(b"3".to_vec()),
    ]);

    let foo: Foo = from_redis_value(value).unwrap();
    dbg!(foo);
}

#[test]
fn test_flatten_outer() {
    /*
    [INFO tarpaulin] Coverage Results:
    || Tested/Total Lines:
    || src/decode.rs: 41/187
    || src/lib.rs: 2/14
    || tests/de.rs: 5/250
    ||
    10.64% coverage, 48/451 lines covered
    */
    #[derive(Deserialize, Debug)]
    struct Foo {
        id: u32,
    }

    #[derive(Deserialize, Debug)]
    struct Wrapped {
        #[serde(flatten)]
        foo: Foo,
    }

    let value = Value::Bulk(vec![
        Value::Data(b"id".to_vec()),
        Value::Data(b"3".to_vec()),
    ]);

    let foo: Wrapped = from_redis_value(value).unwrap();
    dbg!(foo);
}
<commit_msg>Remove flatten tests<commit_after>#[macro_use]
extern crate serde_derive;

extern crate redis;
extern crate serde;
extern crate serde_bytes;
extern crate serde_redis;

use std::collections::HashMap;

use serde::Deserialize;
use serde_redis::{from_redis_value, Deserializer};

use redis::Value;

#[test]
fn deserialize_unit_struct_string() {
    let v = Value::Data(b"hello".to_vec());

    #[derive(Deserialize, Debug, PartialEq)]
    struct Unit(String);

    let de = Deserializer::new(v);
    let actual: Unit = Deserialize::deserialize(de).unwrap();

    let expected = Unit("hello".to_owned());
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_unit_struct_u8_redis_int() {
    let num = 5u8;
    let v = Value::Int(num as i64);

    #[derive(Deserialize, Debug, PartialEq)]
    struct IntUnit(u8);

    let de = Deserializer::new(v);
    let actual: IntUnit = Deserialize::deserialize(de).unwrap();

    let expected = IntUnit(num);
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_bool() {
    let v = vec![
        Value::Data(b"0".to_vec()),
        Value::Data(b"false".to_vec()),
        Value::Data(b"False".to_vec()),
        Value::Data(b"1".to_vec()),
        Value::Data(b"true".to_vec()),
        Value::Data(b"True".to_vec()),
    ];

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Vec<bool> = Deserialize::deserialize(de).unwrap();

    let expected = [false, false, false, true, true, true];
    assert_eq!(&expected, &actual[..]);
}

#[test]
fn deserialize_tuple() {
    let v = vec![Value::Int(5), Value::Data(b"hello".to_vec())];

    let de = Deserializer::new(Value::Bulk(v));
    let actual: (u8, String) = Deserialize::deserialize(de).unwrap();

    let expected = (5, "hello".to_owned());
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct() {
    let v = vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_hash_map_strings() {
    let v = vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ];

    let mut expected = HashMap::new();
    expected.insert("a".to_string(), "apple".to_string());
    expected.insert("b".to_string(), "banana".to_string());

    let de = Deserializer::new(Value::Bulk(v));
    let actual: HashMap<String, String> = Deserialize::deserialize(de).unwrap();

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_float() {
    let v = Value::Data(b"3.14159".to_vec());

    let expected = "3.14159".parse::<f32>().unwrap();

    let de = Deserializer::new(v);
    let actual: f32 = Deserialize::deserialize(de).unwrap();

    assert_eq!(actual, expected);
}

#[test]
fn deserialize_hash_map_string_u8() {
    let v = vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"1".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"2".to_vec()),
    ];

    let mut expected = HashMap::new();
    expected.insert("a".to_string(), 1);
    expected.insert("b".to_string(), 2);

    let de = Deserializer::new(Value::Bulk(v));
    let actual: HashMap<String, u8> = Deserialize::deserialize(de).unwrap();

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct_out_of_order() {
    let v = vec![
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct_extra_keys() {
    let v = vec![
        Value::Data(b"c".to_vec()),
        Value::Data(b"cranberry".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_enum() {
    let v = Value::Data(b"Orange".to_vec());

    #[derive(Debug, Deserialize, PartialEq)]
    enum Fruit {
        Orange,
        Apple,
    }

    let de = Deserializer::new(v);
    let actual: Fruit = Deserialize::deserialize(de).unwrap();

    assert_eq!(Fruit::Orange, actual);
}

#[test]
fn deserialize_option() {
    let de = Deserializer::new(Value::Nil);
    let actual: Option<u8> = Deserialize::deserialize(de).unwrap();

    assert_eq!(None, actual);
}

#[test]
fn deserialize_complex_struct() {
    let v = vec![
        Value::Data(b"num".to_vec()),
        Value::Data(b"10".to_vec()),
        Value::Data(b"opt".to_vec()),
        Value::Data(b"yes".to_vec()),
        Value::Data(b"s".to_vec()),
        Value::Data(b"yarn".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Complex {
        num: usize,
        opt: Option<String>,
        not_present: Option<String>,
        s: String,
    }

    let expected = Complex {
        num: 10,
        opt: Some("yes".to_owned()),
        not_present: None,
        s: "yarn".to_owned(),
    };

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Complex = Deserialize::deserialize(de).unwrap();

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_vec_of_strings() {
    let v = vec![
        Value::Data(b"first".to_vec()),
        Value::Data(b"second".to_vec()),
        Value::Data(b"third".to_vec()),
    ];

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Vec<String> = Deserialize::deserialize(de).unwrap();

    let expected = vec![
        "first".to_string(),
        "second".to_string(),
        "third".to_string(),
    ];
    assert_eq!(expected, actual);
}

#[test]
fn deserialize_vec_of_newtype() {
    let v = vec![
        Value::Data(b"first".to_vec()),
        Value::Data(b"second".to_vec()),
        Value::Data(b"third".to_vec()),
    ];

    #[derive(Debug, PartialEq, Deserialize)]
    struct Rank(String);

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Vec<Rank> = Deserialize::deserialize(de).unwrap();

    let expected = vec![
        Rank("first".into()),
        Rank("second".into()),
        Rank("third".into()),
    ];

    assert_eq!(expected, actual);
}

/// Test for deserializing pipelined structs
///
/// In pipeline mode, there is nested bulk items that are returned. The original implementation did
/// not handle this.
#[test]
fn deserialize_pipelined_hmap() {
    let values = Value::Bulk(vec![
        Value::Bulk(vec![
            Value::Data(b"a".to_vec()),
            Value::Data(b"apple".to_vec()),
            Value::Data(b"b".to_vec()),
            Value::Data(b"banana".to_vec()),
        ]),
        Value::Bulk(vec![
            Value::Data(b"a".to_vec()),
            Value::Data(b"art".to_vec()),
            Value::Data(b"b".to_vec()),
            Value::Data(b"bold".to_vec()),
        ]),
    ]);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(values);
    let actual: Vec<Simple> = Deserialize::deserialize(de).unwrap();

    let expected = vec![
        Simple {
            a: "apple".to_owned(),
            b: "banana".to_owned(),
        },
        Simple {
            a: "art".to_owned(),
            b: "bold".to_owned(),
        },
    ];

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_pipelined_single_hmap() {
    let values = Value::Bulk(vec![Value::Bulk(vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ])]);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: String,
        b: String,
    }

    let de = Deserializer::new(values);
    let actual: Vec<Simple> = Deserialize::deserialize(de).unwrap();

    let expected = vec![Simple {
        a: "apple".to_owned(),
        b: "banana".to_owned(),
    }];

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_struct_with_newtype_field() {
    let v = vec![
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
    ];

    #[derive(Debug, Deserialize, PartialEq)]
    struct Fruit(String);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: Fruit,
        b: Fruit,
    }

    let de = Deserializer::new(Value::Bulk(v));
    let actual: Simple = Deserialize::deserialize(de).unwrap();

    let expected = Simple {
        a: Fruit(String::from("apple")),
        b: Fruit(String::from("banana")),
    };

    assert_eq!(expected, actual);
}

#[test]
fn deserialize_byte_buf() {
    let de = Deserializer::new(Value::Data(b"0000".to_vec()));
    let actual: serde_bytes::ByteBuf = Deserialize::deserialize(de).unwrap();

    let expected = b"0000";
    assert_eq!(expected, &actual[..]);
}

#[test]
fn deserialize_pipelined_single_hmap_newtype_fields() {
    #[derive(Debug, Deserialize, PartialEq)]
    struct Fruit(String);

    let values = Value::Bulk(vec![Value::Bulk(vec![
        Value::Data(b"a".to_vec()),
        Value::Data(b"apple".to_vec()),
        Value::Data(b"b".to_vec()),
        Value::Data(b"banana".to_vec()),
    ])]);

    #[derive(Debug, Deserialize, PartialEq)]
    struct Simple {
        a: Fruit,
        b: Fruit,
    }

    let de = Deserializer::new(values);
    let actual: Vec<Simple> = Deserialize::deserialize(de).unwrap();

    let expected = vec![Simple {
        a: Fruit(String::from("apple")),
        b: Fruit(String::from("banana")),
    }];

    assert_eq!(expected, actual);
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Details {
    pub time: i64,
    pub count: u32,
    pub ids: Vec<String>,
}

type MapMapList = ::std::collections::HashMap<String, Details>;

#[test]
fn deserialize_nested_map_map_list() {
    let value = Value::Bulk(vec![
        Value::Data(b"key".to_vec()),
        Value::Bulk(vec![
            Value::Data(b"count".to_vec()),
            Value::Data(b"4".to_vec()),
            Value::Data(b"time".to_vec()),
            Value::Data(b"1473359995".to_vec()),
            Value::Data(b"ids".to_vec()),
            Value::Bulk(vec![
                Value::Data(b"00000000-0000-0000-0000-000000000000".to_vec()),
                Value::Data(b"00000000-0000-0000-0000-000000000001".to_vec()),
                Value::Data(b"00000000-0000-0000-0000-000000000002".to_vec()),
            ]),
        ]),
    ]);

    let de = Deserializer::new(value);
    let map: MapMapList = Deserialize::deserialize(de).unwrap();

    let nest = map.get("key").unwrap();
    assert_eq!(nest.count, 4);
    assert_eq!(nest.time, 1473359995);
    assert_eq!(
        &nest.ids[..],
        &[
            String::from("00000000-0000-0000-0000-000000000000"),
            String::from("00000000-0000-0000-0000-000000000001"),
            String::from("00000000-0000-0000-0000-000000000002")
        ]
    );
}

#[test]
#[should_panic]
fn deserialize_nested_item() {
    let value = Value::Bulk(vec![Value::Bulk(vec![Value::Data(b"hi".to_vec())])]);

    let de = Deserializer::new(value);
    let _hellos: Vec<String> = Deserialize::deserialize(de).unwrap();
}
<|endoftext|>


<commit_before>// Copyright 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 config::{Color, Config, Verbosity};
use diff;
use std::collections::VecDeque;
use std::io;
use std::io::Write;

#[derive(Debug, PartialEq)]
pub enum DiffLine {
    Context(String),
    Expected(String),
    Resulting(String),
}

#[derive(Debug, PartialEq)]
pub struct Mismatch {
    /// The line number in the formatted version.
    pub line_number: u32,
    /// The line number in the original version.
    pub line_number_orig: u32,
    /// The set of lines (context and old/new) in the mismatch.
    pub lines: Vec<DiffLine>,
}

impl Mismatch {
    fn new(line_number: u32, line_number_orig: u32) -> Mismatch {
        Mismatch {
            line_number,
            line_number_orig,
            lines: Vec::new(),
        }
    }
}

// This struct handles writing output to stdout and abstracts away the logic
// of printing in color, if it's possible in the executing environment.
pub struct OutputWriter {
    terminal: Option<Box<term::Terminal<Output = io::Stdout>>>,
}

impl OutputWriter {
    // Create a new OutputWriter instance based on the caller's preference
    // for colorized output and the capabilities of the terminal.
    pub fn new(color: Color) -> Self {
        if let Some(t) = term::stdout() {
            if color.use_colored_tty() && t.supports_color() {
                return OutputWriter { terminal: Some(t) };
            }
        }
        OutputWriter { terminal: None }
    }

    // Write output in the optionally specified color. The output is written
    // in the specified color if this OutputWriter instance contains a
    // Terminal in its `terminal` field.
    pub fn writeln(&mut self, msg: &str, color: Option<term::color::Color>) {
        match &mut self.terminal {
            Some(ref mut t) => {
                if let Some(color) = color {
                    t.fg(color).unwrap();
                }
                writeln!(t, "{}", msg).unwrap();
                if color.is_some() {
                    t.reset().unwrap();
                }
            }
            None => println!("{}", msg),
        }
    }
}

// Produces a diff between the expected output and actual output of rustfmt.
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
    let mut line_number = 1;
    let mut line_number_orig = 1;
    let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
    let mut lines_since_mismatch = context_size + 1;
    let mut results = Vec::new();
    let mut mismatch = Mismatch::new(0, 0);

    for result in diff::lines(expected, actual) {
        match result {
            diff::Result::Left(str) => {
                if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
                    results.push(mismatch);
                    mismatch = Mismatch::new(
                        line_number - context_queue.len() as u32,
                        line_number_orig - context_queue.len() as u32,
                    );
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
                line_number_orig += 1;
                lines_since_mismatch = 0;
            }
            diff::Result::Right(str) => {
                if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
                    results.push(mismatch);
                    mismatch = Mismatch::new(
                        line_number - context_queue.len() as u32,
                        line_number_orig - context_queue.len() as u32,
                    );
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Expected(str.to_owned()));
                line_number += 1;
                lines_since_mismatch = 0;
            }
            diff::Result::Both(str, _) => {
                if context_queue.len() >= context_size {
                    let _ = context_queue.pop_front();
                }

                if lines_since_mismatch < context_size {
                    mismatch.lines.push(DiffLine::Context(str.to_owned()));
                } else if context_size > 0 {
                    context_queue.push_back(str);
                }

                line_number += 1;
                line_number_orig += 1;
                lines_since_mismatch += 1;
            }
        }
    }

    results.push(mismatch);
    results.remove(0);

    results
}

pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F, config: &Config)
where
    F: Fn(u32) -> String,
{
    let color = config.color();
    let line_terminator = if config.verbose() == Verbosity::Verbose {
        "⏎"
    } else {
        ""
    };

    let mut writer = OutputWriter::new(color);

    for mismatch in diff {
        let title = get_section_title(mismatch.line_number);
        writer.writeln(&title, None);

        for line in mismatch.lines {
            match line {
                DiffLine::Context(ref str) => {
                    writer.writeln(&format!(" {}{}", str, line_terminator), None)
                }
                DiffLine::Expected(ref str) => writer.writeln(
                    &format!("+{}{}", str, line_terminator),
                    Some(term::color::GREEN),
                ),
                DiffLine::Resulting(ref str) => writer.writeln(
                    &format!("-{}{}", str, line_terminator),
                    Some(term::color::RED),
                ),
            }
        }
    }
}

/// Convert a Mismatch into a serialised form which just includes
/// enough information to modify the original file.
/// Each section starts with a line with three integers, space separated:
///     lineno num_removed num_added
/// followed by (num_added) lines of added text.  The line numbers are
/// relative to the original file.
pub fn output_modified<W>(mut out: W, diff: Vec<Mismatch>)
where
    W: Write,
{
    for mismatch in diff {
        let (num_removed, num_added) =
            mismatch
                .lines
                .iter()
                .fold((0, 0), |(rem, add), line| match *line {
                    DiffLine::Context(_) => panic!("No Context expected"),
                    DiffLine::Expected(_) => (rem, add + 1),
                    DiffLine::Resulting(_) => (rem + 1, add),
                });
        // Write a header with enough information to separate the modified lines.
        writeln!(
            out,
            "{} {} {}",
            mismatch.line_number_orig, num_removed, num_added
        ).unwrap();

        for line in mismatch.lines {
            match line {
                DiffLine::Context(_) | DiffLine::Resulting(_) => (),
                DiffLine::Expected(ref str) => {
                    writeln!(out, "{}", str).unwrap();
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::DiffLine::*;
    use super::{make_diff, Mismatch};

    #[test]
    fn diff_simple() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest = "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(
            diff,
            vec![Mismatch {
                line_number: 2,
                line_number_orig: 2,
                lines: vec![
                    Context("two".to_owned()),
                    Resulting("three".to_owned()),
                    Expected("trois".to_owned()),
                    Context("four".to_owned()),
                ],
            }]
        );
    }

    #[test]
    fn diff_simple2() {
        let src = "one\ntwo\nthree\nfour\nfive\nsix\nseven\n";
        let dest = "one\ntwo\ntrois\nfour\ncinq\nsix\nseven\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(
            diff,
            vec![
                Mismatch {
                    line_number: 2,
                    line_number_orig: 2,
                    lines: vec![
                        Context("two".to_owned()),
                        Resulting("three".to_owned()),
                        Expected("trois".to_owned()),
                        Context("four".to_owned()),
                    ],
                },
                Mismatch {
                    line_number: 5,
                    line_number_orig: 5,
                    lines: vec![
                        Resulting("five".to_owned()),
                        Expected("cinq".to_owned()),
                        Context("six".to_owned()),
                    ],
                },
            ]
        );
    }

    #[test]
    fn diff_zerocontext() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest = "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 0);
        assert_eq!(
            diff,
            vec![Mismatch {
                line_number: 3,
                line_number_orig: 3,
                lines: vec![Resulting("three".to_owned()), Expected("trois".to_owned())],
            }]
        );
    }

    #[test]
    fn diff_trailing_newline() {
        let src = "one\ntwo\nthree\nfour\nfive";
        let dest = "one\ntwo\nthree\nfour\nfive\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(
            diff,
            vec![Mismatch {
                line_number: 5,
                line_number_orig: 5,
                lines: vec![Context("five".to_owned()), Expected("".to_owned())],
            }]
        );
    }
}
<commit_msg>Change `print_diff` to output the correct line number.<commit_after>// Copyright 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 config::{Color, Config, Verbosity};
use diff;
use std::collections::VecDeque;
use std::io;
use std::io::Write;

#[derive(Debug, PartialEq)]
pub enum DiffLine {
    Context(String),
    Expected(String),
    Resulting(String),
}

#[derive(Debug, PartialEq)]
pub struct Mismatch {
    /// The line number in the formatted version.
    pub line_number: u32,
    /// The line number in the original version.
    pub line_number_orig: u32,
    /// The set of lines (context and old/new) in the mismatch.
    pub lines: Vec<DiffLine>,
}

impl Mismatch {
    fn new(line_number: u32, line_number_orig: u32) -> Mismatch {
        Mismatch {
            line_number,
            line_number_orig,
            lines: Vec::new(),
        }
    }
}

// This struct handles writing output to stdout and abstracts away the logic
// of printing in color, if it's possible in the executing environment.
pub struct OutputWriter {
    terminal: Option<Box<term::Terminal<Output = io::Stdout>>>,
}

impl OutputWriter {
    // Create a new OutputWriter instance based on the caller's preference
    // for colorized output and the capabilities of the terminal.
    pub fn new(color: Color) -> Self {
        if let Some(t) = term::stdout() {
            if color.use_colored_tty() && t.supports_color() {
                return OutputWriter { terminal: Some(t) };
            }
        }
        OutputWriter { terminal: None }
    }

    // Write output in the optionally specified color. The output is written
    // in the specified color if this OutputWriter instance contains a
    // Terminal in its `terminal` field.
    pub fn writeln(&mut self, msg: &str, color: Option<term::color::Color>) {
        match &mut self.terminal {
            Some(ref mut t) => {
                if let Some(color) = color {
                    t.fg(color).unwrap();
                }
                writeln!(t, "{}", msg).unwrap();
                if color.is_some() {
                    t.reset().unwrap();
                }
            }
            None => println!("{}", msg),
        }
    }
}

// Produces a diff between the expected output and actual output of rustfmt.
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
    let mut line_number = 1;
    let mut line_number_orig = 1;
    let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
    let mut lines_since_mismatch = context_size + 1;
    let mut results = Vec::new();
    let mut mismatch = Mismatch::new(0, 0);

    for result in diff::lines(expected, actual) {
        match result {
            diff::Result::Left(str) => {
                if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
                    results.push(mismatch);
                    mismatch = Mismatch::new(
                        line_number - context_queue.len() as u32,
                        line_number_orig - context_queue.len() as u32,
                    );
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
                line_number_orig += 1;
                lines_since_mismatch = 0;
            }
            diff::Result::Right(str) => {
                if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
                    results.push(mismatch);
                    mismatch = Mismatch::new(
                        line_number - context_queue.len() as u32,
                        line_number_orig - context_queue.len() as u32,
                    );
                }

                while let Some(line) = context_queue.pop_front() {
                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
                }

                mismatch.lines.push(DiffLine::Expected(str.to_owned()));
                line_number += 1;
                lines_since_mismatch = 0;
            }
            diff::Result::Both(str, _) => {
                if context_queue.len() >= context_size {
                    let _ = context_queue.pop_front();
                }

                if lines_since_mismatch < context_size {
                    mismatch.lines.push(DiffLine::Context(str.to_owned()));
                } else if context_size > 0 {
                    context_queue.push_back(str);
                }

                line_number += 1;
                line_number_orig += 1;
                lines_since_mismatch += 1;
            }
        }
    }

    results.push(mismatch);
    results.remove(0);

    results
}

pub fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F, config: &Config)
where
    F: Fn(u32) -> String,
{
    let color = config.color();
    let line_terminator = if config.verbose() == Verbosity::Verbose {
        "⏎"
    } else {
        ""
    };

    let mut writer = OutputWriter::new(color);

    for mismatch in diff {
        let title = get_section_title(mismatch.line_number_orig);
        writer.writeln(&title, None);

        for line in mismatch.lines {
            match line {
                DiffLine::Context(ref str) => {
                    writer.writeln(&format!(" {}{}", str, line_terminator), None)
                }
                DiffLine::Expected(ref str) => writer.writeln(
                    &format!("+{}{}", str, line_terminator),
                    Some(term::color::GREEN),
                ),
                DiffLine::Resulting(ref str) => writer.writeln(
                    &format!("-{}{}", str, line_terminator),
                    Some(term::color::RED),
                ),
            }
        }
    }
}

/// Convert a Mismatch into a serialised form which just includes
/// enough information to modify the original file.
/// Each section starts with a line with three integers, space separated:
///     lineno num_removed num_added
/// followed by (num_added) lines of added text.  The line numbers are
/// relative to the original file.
pub fn output_modified<W>(mut out: W, diff: Vec<Mismatch>)
where
    W: Write,
{
    for mismatch in diff {
        let (num_removed, num_added) =
            mismatch
                .lines
                .iter()
                .fold((0, 0), |(rem, add), line| match *line {
                    DiffLine::Context(_) => panic!("No Context expected"),
                    DiffLine::Expected(_) => (rem, add + 1),
                    DiffLine::Resulting(_) => (rem + 1, add),
                });
        // Write a header with enough information to separate the modified lines.
        writeln!(
            out,
            "{} {} {}",
            mismatch.line_number_orig, num_removed, num_added
        ).unwrap();

        for line in mismatch.lines {
            match line {
                DiffLine::Context(_) | DiffLine::Resulting(_) => (),
                DiffLine::Expected(ref str) => {
                    writeln!(out, "{}", str).unwrap();
                }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::DiffLine::*;
    use super::{make_diff, Mismatch};

    #[test]
    fn diff_simple() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest = "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(
            diff,
            vec![Mismatch {
                line_number: 2,
                line_number_orig: 2,
                lines: vec![
                    Context("two".to_owned()),
                    Resulting("three".to_owned()),
                    Expected("trois".to_owned()),
                    Context("four".to_owned()),
                ],
            }]
        );
    }

    #[test]
    fn diff_simple2() {
        let src = "one\ntwo\nthree\nfour\nfive\nsix\nseven\n";
        let dest = "one\ntwo\ntrois\nfour\ncinq\nsix\nseven\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(
            diff,
            vec![
                Mismatch {
                    line_number: 2,
                    line_number_orig: 2,
                    lines: vec![
                        Context("two".to_owned()),
                        Resulting("three".to_owned()),
                        Expected("trois".to_owned()),
                        Context("four".to_owned()),
                    ],
                },
                Mismatch {
                    line_number: 5,
                    line_number_orig: 5,
                    lines: vec![
                        Resulting("five".to_owned()),
                        Expected("cinq".to_owned()),
                        Context("six".to_owned()),
                    ],
                },
            ]
        );
    }

    #[test]
    fn diff_zerocontext() {
        let src = "one\ntwo\nthree\nfour\nfive\n";
        let dest = "one\ntwo\ntrois\nfour\nfive\n";
        let diff = make_diff(src, dest, 0);
        assert_eq!(
            diff,
            vec![Mismatch {
                line_number: 3,
                line_number_orig: 3,
                lines: vec![Resulting("three".to_owned()), Expected("trois".to_owned())],
            }]
        );
    }

    #[test]
    fn diff_trailing_newline() {
        let src = "one\ntwo\nthree\nfour\nfive";
        let dest = "one\ntwo\nthree\nfour\nfive\n";
        let diff = make_diff(src, dest, 1);
        assert_eq!(
            diff,
            vec![Mismatch {
                line_number: 5,
                line_number_orig: 5,
                lines: vec![Context("five".to_owned()), Expected("".to_owned())],
            }]
        );
    }
}
<|endoftext|>


<commit_before>use crate::proto;
use crate::{AttributeDataType, CURRENT_VERSION};
use fnv::FnvHashMap;
use s2::cellid::CellID;
use std::collections::HashMap;
use std::convert::TryInto;

#[derive(Copy, Clone)]
pub struct S2CellMeta {
    pub num_points: u64,
}

pub struct S2Meta {
    pub cells: FnvHashMap<CellID, S2CellMeta>,
    pub attributes: HashMap<String, AttributeDataType>,
}

impl S2Meta {
    pub fn to_proto(&self) -> proto::Meta {
        let cell_protos = self
            .cells
            .iter()
            .map(|(cell_id, cell_meta)| {
                let mut meta = proto::S2Cell::new();
                meta.set_id(cell_id.0);
                meta.set_num_points(cell_meta.num_points.try_into().unwrap());
                meta
            })
            .collect();
        let mut meta = proto::Meta::new();
        meta.set_version(CURRENT_VERSION);
        let mut s2_meta = proto::S2Meta::new();
        s2_meta.set_cells(::protobuf::RepeatedField::<proto::S2Cell>::from_vec(
            cell_protos,
        ));
        let attributes_meta = self
            .attributes
            .iter()
            .map(|(name, attribute)| {
                let mut attr_meta = proto::Attribute::new();
                attr_meta.set_name(name.to_string());
                attr_meta.set_data_type(attribute.to_proto());
                attr_meta
            })
            .collect();
        s2_meta.set_attributes(::protobuf::RepeatedField::<proto::Attribute>::from_vec(
            attributes_meta,
        ));
        meta.set_s2(s2_meta);
        meta
    }
}
<commit_msg>s2 cell to proto (#338)<commit_after>use crate::proto;
use crate::{AttributeDataType, CURRENT_VERSION};
use fnv::FnvHashMap;
use s2::cellid::CellID;
use std::collections::HashMap;
use std::convert::TryInto;

#[derive(Copy, Clone)]
pub struct S2CellMeta {
    pub num_points: u64,
}

impl S2CellMeta {
    pub fn to_proto(self, cell_id: u64) -> proto::S2Cell {
        let mut meta = proto::S2Cell::new();
        meta.set_id(cell_id);
        meta.set_num_points(self.num_points.try_into().unwrap());
        meta
    }
}

pub struct S2Meta {
    pub cells: FnvHashMap<CellID, S2CellMeta>,
    pub attributes: HashMap<String, AttributeDataType>,
}

impl S2Meta {
    pub fn to_proto(&self) -> proto::Meta {
        let cell_protos = self
            .cells
            .iter()
            .map(|(cell_id, cell_meta)| cell_meta.to_proto(cell_id.0))
            .collect();
        let mut meta = proto::Meta::new();
        meta.set_version(CURRENT_VERSION);
        let mut s2_meta = proto::S2Meta::new();
        s2_meta.set_cells(::protobuf::RepeatedField::<proto::S2Cell>::from_vec(
            cell_protos,
        ));
        let attributes_meta = self
            .attributes
            .iter()
            .map(|(name, attribute)| {
                let mut attr_meta = proto::Attribute::new();
                attr_meta.set_name(name.to_string());
                attr_meta.set_data_type(attribute.to_proto());
                attr_meta
            })
            .collect();
        s2_meta.set_attributes(::protobuf::RepeatedField::<proto::Attribute>::from_vec(
            attributes_meta,
        ));
        meta.set_s2(s2_meta);
        meta
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

//! The frame module provides a structred way to send and receive
//! message through streams.
//!
//! ## Data Framing
//!
//! ```ignore
//! 0                   1                   2                   3
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | Frame Start   |  Payload Len                  |  Payload  |
//! +-----------------------------------------------------------+
//! |           Payload Data Continued          |   Frame End   |
//! +-----------------------------------------------------------+
//!
//! Start Frame:    8 bits (must be 0x01)
//! Payload Len:    16 bits
//! Payload Data:   Payload Len bytes
//! End Frame:      8 bits (must be 0x17)
//! ```

use std::mem;
use std::any::Any;
use std::default::Default;

use super::Frame;

bitflags! {
    flags FrameGuard: u8 {
        const START     = 0b0000_0001,
        const END       = 0b0001_0111
    }
}

#[derive(Clone)]
pub struct SimpleFrame {
    start_guard: FrameGuard,
    payload_len: u16,
    payload: Vec<u8>,
    end_guard: FrameGuard
}

impl Frame for SimpleFrame {

    #[allow(unused_variables)]
    fn new<T: Any>(buf: &[u8], args: &Vec<T>) -> Self {
        SimpleFrame {
            start_guard: START,
            payload_len: buf.len() as u16,
            payload: buf.to_vec(),
            end_guard: END
        }
    }

    fn to_bytes(&self) -> Vec<u8> {
        let payload_len = self.payload_len as u16;
        let len: usize = self.payload_len as usize + 4;
        let mut buf = Vec::<u8>::with_capacity(len);

        buf.push(self.start_guard.bits());
        buf.push((payload_len >> 8) as u8);
        buf.push(payload_len as u8);
        buf.extend_from_slice(&self.payload[..]);
        buf.push(self.end_guard.bits());

        buf
    }

    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Self>> {
        if buf.len() < 5 {
            return None;
        }

        let mut frame: SimpleFrame = Default::default();

        // Starting frame guard
        match FrameGuard::from_bits(buf[0]) {
            Some(start_guard) => {
                frame.start_guard = start_guard;
            }
            None => {
                error!("First byte was not expected start byte. Buffer corrupted?: {}", buf[0]);
            }
        }

        // Payload length
        let mask = 0xFFFFu16;
        let mut payload_len = ((buf[1] as u16) << 8) & mask;
        payload_len |= buf[2] as u16;
        frame.payload_len = payload_len;

        let payload_len = payload_len as usize;
        if buf.len() - 4 < payload_len {
            return None;
        }

        // Payload data
        frame.payload.extend_from_slice(&buf[3..(payload_len + 3)]);

        // Ending frame guard
        match FrameGuard::from_bits(buf[payload_len + 3]) {
            Some(end_guard) => {
                frame.end_guard = end_guard;
            }
            None => {
                error!("Last byte was not expected end byte. Buffer corrupted? {}",
                       buf[payload_len + 3]);
                return None;
            }
        }

        // Remove frame from buffer
        let mut remainder = Vec::<u8>::with_capacity(buf.len() - frame.len_as_vec());
        remainder.extend_from_slice(&buf[frame.len_as_vec()..buf.len()]);
        mem::swap(buf, &mut remainder);

        Some(Box::new(frame))
    }

    fn len_as_vec(&self) -> usize {
        self.payload_len as usize + 4
    }
}

impl Default for SimpleFrame {
    fn default() -> SimpleFrame {
        SimpleFrame {
            start_guard: START,
            payload_len: 0u16,
            payload: Vec::<u8>::new(),
            end_guard: END
        }
    }
}
<commit_msg>SimpleFrame::to_bytes is actually correct now.<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

//! The frame module provides a structred way to send and receive
//! message through streams.
//!
//! ## Data Framing
//!
//! ```ignore
//! 0                   1                   2                   3
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | Frame Start   |  Payload Len                  |  Payload  |
//! +-----------------------------------------------------------+
//! |           Payload Data Continued          |   Frame End   |
//! +-----------------------------------------------------------+
//!
//! Start Frame:    8 bits (must be 0x01)
//! Payload Len:    16 bits
//! Payload Data:   Payload Len bytes
//! End Frame:      8 bits (must be 0x17)
//! ```

use std::mem;
use std::any::Any;
use std::default::Default;

use super::Frame;

bitflags! {
    flags FrameGuard: u8 {
        const START     = 0b0000_0001,
        const END       = 0b0001_0111
    }
}

#[derive(Clone)]
pub struct SimpleFrame {
    start_guard: FrameGuard,
    payload_len: u16,
    payload: Vec<u8>,
    end_guard: FrameGuard
}

impl Frame for SimpleFrame {

    #[allow(unused_variables)]
    fn new<T: Any>(buf: &[u8], args: &Vec<T>) -> Self {
        SimpleFrame {
            start_guard: START,
            payload_len: buf.len() as u16,
            payload: buf.to_vec(),
            end_guard: END
        }
    }

    fn to_bytes(&self) -> Vec<u8> {
        self.payload.clone()
    }

    fn from_bytes(buf: &mut Vec<u8>) -> Option<Box<Self>> {
        if buf.len() < 5 {
            return None;
        }

        let mut frame: SimpleFrame = Default::default();

        // Starting frame guard
        match FrameGuard::from_bits(buf[0]) {
            Some(start_guard) => {
                frame.start_guard = start_guard;
            }
            None => {
                error!("First byte was not expected start byte. Buffer corrupted?: {}", buf[0]);
            }
        }

        // Payload length
        let mask = 0xFFFFu16;
        let mut payload_len = ((buf[1] as u16) << 8) & mask;
        payload_len |= buf[2] as u16;
        frame.payload_len = payload_len;

        let payload_len = payload_len as usize;
        if buf.len() - 4 < payload_len {
            return None;
        }

        // Payload data
        frame.payload.extend_from_slice(&buf[3..(payload_len + 3)]);

        // Ending frame guard
        match FrameGuard::from_bits(buf[payload_len + 3]) {
            Some(end_guard) => {
                frame.end_guard = end_guard;
            }
            None => {
                error!("Last byte was not expected end byte. Buffer corrupted? {}",
                       buf[payload_len + 3]);
                return None;
            }
        }

        // Remove frame from buffer
        let mut remainder = Vec::<u8>::with_capacity(buf.len() - frame.len_as_vec());
        remainder.extend_from_slice(&buf[frame.len_as_vec()..buf.len()]);
        mem::swap(buf, &mut remainder);

        Some(Box::new(frame))
    }

    fn len_as_vec(&self) -> usize {
        (self.payload_len + 4) as usize
    }
}

impl Default for SimpleFrame {
    fn default() -> SimpleFrame {
        SimpleFrame {
            start_guard: START,
            payload_len: 0u16,
            payload: Vec::<u8>::new(),
            end_guard: END
        }
    }
}
<|endoftext|>