<commit_before>use std::convert::From;
use std::iter::Iterator;
use std::mem;
use timeclock::direction::Direction;
use timeclock::timeentry::TimeEntry;

/// Option-like enclosure for TimeEntrys
#[derive(Debug,PartialEq)]
pub enum TimeEntryOpt {
    In(TimeEntry),
    Out(TimeEntry),
    Invalid,
}

impl TimeEntryOpt {
    /// Take the TimeEntry variant and leave Invalid in it's place
    pub fn take(&mut self) -> TimeEntryOpt {
        mem::replace(self, TimeEntryOpt::Invalid)
    }
}

impl From<Option<TimeEntry>> for TimeEntryOpt {
    fn from(opt: Option<TimeEntry>) -> Self {
        let te = match opt {
            Some(te) => te,
            None => {
                return TimeEntryOpt::Invalid;
            }
        };
        match te.dir {
            Direction::In => TimeEntryOpt::In(te),
            Direction::Out => TimeEntryOpt::Out(te),
        }
    }
}

impl From<TimeEntry> for TimeEntryOpt {
    fn from(te: TimeEntry) -> Self {
        match te.dir {
            Direction::In => TimeEntryOpt::In(te),
            Direction::Out => TimeEntryOpt::Out(te),
        }
    }
}

#[derive(Debug,PartialEq)]
pub struct TimeEntryPair {
    start: TimeEntry,
    end: TimeEntry,
}

impl TimeEntryPair {
    pub fn new(s: TimeEntry, e: TimeEntry) -> Self {
        TimeEntryPair { start: s, end: e }
    }

    pub fn start(&self) -> &TimeEntry {
        &self.start
    }

    pub fn end(&self) -> &TimeEntry {
        &self.end
    }
}

/// Iterator to create TimeEntryPairs from TimeEntrys
pub struct TimeEntryPairsIter<I> {
    buf: TimeEntryOpt,
    v: I,
}

/// Constructor for TimeEntryPairsIter
pub fn timeentry_pairs<I>(entries: I) -> TimeEntryPairsIter<I>
    where I: Iterator<Item = TimeEntry>
{
    TimeEntryPairsIter {
        buf: TimeEntryOpt::Invalid,
        v: entries.into_iter(),
    }
}

impl<I> Iterator for TimeEntryPairsIter<I>
    where I: Iterator<Item = TimeEntry>
{
    type Item = TimeEntryPair;
    fn next(&mut self) -> Option<TimeEntryPair> {
        if self.buf == TimeEntryOpt::Invalid {
            self.buf = TimeEntryOpt::from(self.v.next());
        }

        let nxt = TimeEntryOpt::from(self.v.next());
        match (self.buf.take(), nxt) {
            (TimeEntryOpt::In(start), TimeEntryOpt::In(saved)) => {
                let mut end = start.clone();
                end.dir = Direction::Out;
                end.memo = String::from("Missing clock out.");
                self.buf = TimeEntryOpt::from(saved);
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::In(start), TimeEntryOpt::Invalid) => {
                let mut end = start.clone();
                end.dir = Direction::Out;
                end.memo = String::from("Missing clock out.");
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::In(start), TimeEntryOpt::Out(end)) => {
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Out(end), TimeEntryOpt::Out(saved)) => {
                let mut start = end.clone();
                start.dir = Direction::In;
                start.memo = String::from("Missing clock in.");
                self.buf = TimeEntryOpt::from(saved);
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Out(end), TimeEntryOpt::In(saved)) => {
                let mut start = end.clone();
                start.dir = Direction::In;
                start.memo = String::from("Missing clock in.");
                self.buf = TimeEntryOpt::from(saved);
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Out(end), TimeEntryOpt::Invalid) => {
                let mut start = end.clone();
                start.dir = Direction::In;
                start.memo = String::from("Missing clock in.");
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Invalid, TimeEntryOpt::Out(_)) => unreachable!(),
            (TimeEntryOpt::Invalid, TimeEntryOpt::In(_)) => unreachable!(),
            (TimeEntryOpt::Invalid, TimeEntryOpt::Invalid) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use timeclock::direction::Direction;
    use timeclock::now;
    use timeclock::timeentry::TimeEntry;

    #[test]
    fn iter_in_in_test() {
        let a = TimeEntry::new(Direction::In, now(), "In");
        let b = TimeEntry::new(Direction::In, now(), "In");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 2);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_in_invalid_test() {
        let a = TimeEntry::new(Direction::In, now(), "In");
        let v = vec![a];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 1);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_in_out_test() {
        let a = TimeEntry::new(Direction::In, now(), "In");
        let b = TimeEntry::new(Direction::Out, now(), "Out");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 1);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_out_out_test() {
        let a = TimeEntry::new(Direction::Out, now(), "Out");
        let b = TimeEntry::new(Direction::Out, now(), "Out");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 2);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_out_in_test() {
        let a = TimeEntry::new(Direction::Out, now(), "Out");
        let b = TimeEntry::new(Direction::In, now(), "In");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 2);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_out_invalid_test() {
        let a = TimeEntry::new(Direction::Out, now(), "Out");
        let v = vec![a];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 1);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_invalid_invalid_test() {
        let v: Vec<TimeEntry> = Vec::with_capacity(0);
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 0);
    }

}<commit_msg>Make TimeEntryOpt enum private<commit_after>use std::convert::From;
use std::iter::Iterator;
use std::mem;
use timeclock::direction::Direction;
use timeclock::timeentry::TimeEntry;

/// Option-like enclosure for TimeEntrys
#[derive(Debug,PartialEq)]
enum TimeEntryOpt {
    In(TimeEntry),
    Out(TimeEntry),
    Invalid,
}

impl TimeEntryOpt {
    /// Take the TimeEntry variant and leave Invalid in it's place
    pub fn take(&mut self) -> TimeEntryOpt {
        mem::replace(self, TimeEntryOpt::Invalid)
    }
}

impl From<Option<TimeEntry>> for TimeEntryOpt {
    fn from(opt: Option<TimeEntry>) -> Self {
        let te = match opt {
            Some(te) => te,
            None => {
                return TimeEntryOpt::Invalid;
            }
        };
        match te.dir {
            Direction::In => TimeEntryOpt::In(te),
            Direction::Out => TimeEntryOpt::Out(te),
        }
    }
}

impl From<TimeEntry> for TimeEntryOpt {
    fn from(te: TimeEntry) -> Self {
        match te.dir {
            Direction::In => TimeEntryOpt::In(te),
            Direction::Out => TimeEntryOpt::Out(te),
        }
    }
}

#[derive(Debug,PartialEq)]
pub struct TimeEntryPair {
    start: TimeEntry,
    end: TimeEntry,
}

impl TimeEntryPair {
    pub fn new(s: TimeEntry, e: TimeEntry) -> Self {
        TimeEntryPair { start: s, end: e }
    }

    pub fn start(&self) -> &TimeEntry {
        &self.start
    }

    pub fn end(&self) -> &TimeEntry {
        &self.end
    }
}

/// Iterator to create TimeEntryPairs from TimeEntrys
pub struct TimeEntryPairsIter<I> {
    buf: TimeEntryOpt,
    v: I,
}

/// Constructor for TimeEntryPairsIter
pub fn timeentry_pairs<I>(entries: I) -> TimeEntryPairsIter<I>
    where I: Iterator<Item = TimeEntry>
{
    TimeEntryPairsIter {
        buf: TimeEntryOpt::Invalid,
        v: entries.into_iter(),
    }
}

impl<I> Iterator for TimeEntryPairsIter<I>
    where I: Iterator<Item = TimeEntry>
{
    type Item = TimeEntryPair;
    fn next(&mut self) -> Option<TimeEntryPair> {
        if self.buf == TimeEntryOpt::Invalid {
            self.buf = TimeEntryOpt::from(self.v.next());
        }

        let nxt = TimeEntryOpt::from(self.v.next());
        match (self.buf.take(), nxt) {
            (TimeEntryOpt::In(start), TimeEntryOpt::In(saved)) => {
                let mut end = start.clone();
                end.dir = Direction::Out;
                end.memo = String::from("Missing clock out.");
                self.buf = TimeEntryOpt::from(saved);
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::In(start), TimeEntryOpt::Invalid) => {
                let mut end = start.clone();
                end.dir = Direction::Out;
                end.memo = String::from("Missing clock out.");
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::In(start), TimeEntryOpt::Out(end)) => {
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Out(end), TimeEntryOpt::Out(saved)) => {
                let mut start = end.clone();
                start.dir = Direction::In;
                start.memo = String::from("Missing clock in.");
                self.buf = TimeEntryOpt::from(saved);
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Out(end), TimeEntryOpt::In(saved)) => {
                let mut start = end.clone();
                start.dir = Direction::In;
                start.memo = String::from("Missing clock in.");
                self.buf = TimeEntryOpt::from(saved);
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Out(end), TimeEntryOpt::Invalid) => {
                let mut start = end.clone();
                start.dir = Direction::In;
                start.memo = String::from("Missing clock in.");
                Some(TimeEntryPair::new(start, end))
            }
            (TimeEntryOpt::Invalid, TimeEntryOpt::Out(_)) => unreachable!(),
            (TimeEntryOpt::Invalid, TimeEntryOpt::In(_)) => unreachable!(),
            (TimeEntryOpt::Invalid, TimeEntryOpt::Invalid) => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use timeclock::direction::Direction;
    use timeclock::now;
    use timeclock::timeentry::TimeEntry;

    #[test]
    fn iter_in_in_test() {
        let a = TimeEntry::new(Direction::In, now(), "In");
        let b = TimeEntry::new(Direction::In, now(), "In");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 2);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_in_invalid_test() {
        let a = TimeEntry::new(Direction::In, now(), "In");
        let v = vec![a];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 1);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_in_out_test() {
        let a = TimeEntry::new(Direction::In, now(), "In");
        let b = TimeEntry::new(Direction::Out, now(), "Out");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 1);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_out_out_test() {
        let a = TimeEntry::new(Direction::Out, now(), "Out");
        let b = TimeEntry::new(Direction::Out, now(), "Out");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 2);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_out_in_test() {
        let a = TimeEntry::new(Direction::Out, now(), "Out");
        let b = TimeEntry::new(Direction::In, now(), "In");
        let v = vec![a, b];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 2);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_out_invalid_test() {
        let a = TimeEntry::new(Direction::Out, now(), "Out");
        let v = vec![a];
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 1);

        for pair in y {
            let (s, e) = (pair.start(), pair.end());
            assert_eq!(s.dir, Direction::In);
            assert_eq!(e.dir, Direction::Out);
        }
    }

    #[test]
    fn iter_invalid_invalid_test() {
        let v: Vec<TimeEntry> = Vec::with_capacity(0);
        let y = timeentry_pairs(v.into_iter()).collect::<Vec<TimeEntryPair>>();

        assert_eq!(y.len(), 0);
    }

}<|endoftext|>


<commit_before>use super::job_queue::*;

use futures::prelude::*;
use futures::channel::oneshot;
use futures::task;

use std::sync::*;
use std::pin::{Pin};

///
/// Signalling structure used to return the result of a scheduler future
///
struct SchedulerFutureResult<T> {
    /// The result of the future, or None if it has not been generated yet
    result: Option<Result<T, oneshot::Canceled>>,

    /// The waker to be called when the future is available
    waker: Option<task::Waker>
}

///
/// Wrapper that cancels the future if it is dropped before it is signalled
///
pub (super) struct SchedulerFutureSignaller<T>(Arc<Mutex<SchedulerFutureResult<T>>>);

///
/// Future representing a task pending on a scheduler
///
/// If polled when no threads are available, this future will run synchronously on the current thread
/// (stealing its execution time rather than blocking)
///
pub struct SchedulerFuture<T> {
    /// The queue which will eventually evaluate the result of this future
    queue: Arc<JobQueue>,

    /// A container for the result of this scheduler future
    result: Arc<Mutex<SchedulerFutureResult<T>>>
}

impl<T> SchedulerFuture<T> {
    ///
    /// Creates a new scheduler future and the result needed to signal it
    ///
    pub (super) fn new(queue: &Arc<JobQueue>) -> (SchedulerFuture<T>, SchedulerFutureSignaller<T>) {
        // Create an unfinished result
        let result = SchedulerFutureResult {
            result: None,
            waker:  None
        };
        let result = Arc::new(Mutex::new(result));

        // Insert into a future
        let future = SchedulerFuture {
            queue:  Arc::clone(queue),
            result: Arc::clone(&result)
        };

        (future, SchedulerFutureSignaller(result))
    }
}

impl<T> Drop for SchedulerFutureSignaller<T> {
    fn drop(&mut self) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // If no result has been generated
            if future_result.result.is_none() {
                // Mark the future as canceled
                future_result.result = Some(Err(oneshot::Canceled));

                // Wake up anything that was polling it
                let waker = future_result.waker.take();
                waker
            } else {
                // Result is already set, so don't wake anything up
                None
            }
        };

        // If we need to wake the future, then do so here (note that we're outside of the lock when we do this)
        waker.map(|waker| waker.wake());
    }
}

impl<T> SchedulerFutureSignaller<T> {
    ///
    /// Signals that the result of the calculation is available
    ///
    pub (super) fn signal(self, result: T) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // Set the result
            future_result.result = Some(Ok(result));

            // Retrieve the waker
            future_result.waker.take()
        };

        // If we retrieved a waker from the result, wake it up
        waker.map(|waker| waker.wake());
    }
}
impl<T> Future for SchedulerFuture<T> {
    type Output = Result<T, oneshot::Canceled>;

    ///
    /// Polls this future
    ///
    fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
        unimplemented!()
    }
}
<commit_msg>Add the implementation for 'running in a different thread' so we get back to where we were with the tests<commit_after>use super::job_queue::*;

use futures::prelude::*;
use futures::channel::oneshot;
use futures::task;

use std::mem;
use std::sync::*;
use std::pin::{Pin};

///
/// The possible states of a future result
///
enum FutureResultState<T> {
    None,
    Some(T),
    ReturnedViaFuture
}

///
/// Signalling structure used to return the result of a scheduler future
///
struct SchedulerFutureResult<T> {
    /// The result of the future, or None if it has not been generated yet
    result: FutureResultState<Result<T, oneshot::Canceled>>,

    /// The waker to be called when the future is available
    waker: Option<task::Waker>
}

///
/// Wrapper that cancels the future if it is dropped before it is signalled
///
pub (super) struct SchedulerFutureSignaller<T>(Arc<Mutex<SchedulerFutureResult<T>>>);

///
/// Future representing a task pending on a scheduler
///
/// If polled when no threads are available, this future will run synchronously on the current thread
/// (stealing its execution time rather than blocking)
///
pub struct SchedulerFuture<T> {
    /// The queue which will eventually evaluate the result of this future
    queue: Arc<JobQueue>,

    /// A container for the result of this scheduler future
    result: Arc<Mutex<SchedulerFutureResult<T>>>
}

impl<T> SchedulerFuture<T> {
    ///
    /// Creates a new scheduler future and the result needed to signal it
    ///
    pub (super) fn new(queue: &Arc<JobQueue>) -> (SchedulerFuture<T>, SchedulerFutureSignaller<T>) {
        // Create an unfinished result
        let result = SchedulerFutureResult {
            result: FutureResultState::None,
            waker:  None
        };
        let result = Arc::new(Mutex::new(result));

        // Insert into a future
        let future = SchedulerFuture {
            queue:  Arc::clone(queue),
            result: Arc::clone(&result)
        };

        (future, SchedulerFutureSignaller(result))
    }
}

impl<T> FutureResultState<T> {
    ///
    /// Returns true if no result has ever been generated for this future
    ///
    fn is_none(&self) -> bool {
        match self {
            FutureResultState::None                 => true,
            FutureResultState::Some(_)              => false,
            FutureResultState::ReturnedViaFuture    => false
        }
    }

    ///
    /// If a result has been generated by this future and has not previously been taken, returns it
    ///
    fn take(&mut self) -> Option<T> {
        // Move the value out of this object
        let mut new_value = FutureResultState::ReturnedViaFuture;
        mem::swap(self, &mut new_value);

        // Return it if it contains a value
        match new_value {
            FutureResultState::None                 => { *self = FutureResultState::None; None },
            FutureResultState::ReturnedViaFuture    => { *self = FutureResultState::ReturnedViaFuture; None },
            FutureResultState::Some(value)          => { Some(value) }
        }
    }
}

impl<T> Drop for SchedulerFutureSignaller<T> {
    fn drop(&mut self) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // If no result has been generated, then mark the future as canceled
            if future_result.result.is_none() {
                // Mark the future as canceled
                future_result.result = FutureResultState::Some(Err(oneshot::Canceled));

                // Wake up anything that was polling it
                let waker = future_result.waker.take();
                waker
            } else {
                // Result is already set, so don't wake anything up
                None
            }
        };

        // If we need to wake the future, then do so here (note that we're outside of the lock when we do this)
        waker.map(|waker| waker.wake());
    }
}

impl<T> SchedulerFutureSignaller<T> {
    ///
    /// Signals that the result of the calculation is available
    ///
    pub (super) fn signal(self, result: T) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // Set the result
            future_result.result = FutureResultState::Some(Ok(result));

            // Retrieve the waker
            future_result.waker.take()
        };

        // If we retrieved a waker from the result, wake it up
        waker.map(|waker| waker.wake());
    }
}

///
/// Possible actions we can take based on the state of the signal for the future
///
enum SchedulerAction<T> {
    /// Queue is running elsewhere: we should wait for it to reach the point where the future's result is available
    WaitForCompletion,

    /// Future has already completed: we should return the value to sender
    ReturnValue(T)
}

impl<T> Future for SchedulerFuture<T> {
    type Output = Result<T, oneshot::Canceled>;

    ///
    /// Polls this future
    ///
    fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
        // Lock the result and determine which action to take
        let next_action = {
            let mut future_result = self.result.lock().unwrap();

            if let Some(result) = future_result.result.take() {
                // The result is available: we should return it immediately
                SchedulerAction::ReturnValue(result)
            } else {
                // Wake us up when the future is available
                future_result.waker = Some(context.waker().clone());

                SchedulerAction::WaitForCompletion
            }
        };

        match next_action {
            SchedulerAction::WaitForCompletion  => task::Poll::Pending,
            SchedulerAction::ReturnValue(value) => task::Poll::Ready(value)
        }
    }
}
<|endoftext|>


<commit_before>use colored::*;
use regex::Regex;
use std::path::{Path, PathBuf};
use std::{env, process::Command};
use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling};

fn miri_path() -> PathBuf {
    PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri")))
}

// Build the shared object file for testing external C function calls.
fn build_so_for_c_ffi_tests() -> PathBuf {
    let cc = option_env!("CC").unwrap_or("cc");
    // Target directory that we can write to.
    let so_target_dir = Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-extern-so");
    // Create the directory if it does not already exist.
    std::fs::create_dir_all(&so_target_dir)
        .expect("Failed to create directory for shared object file");
    let so_file_path = so_target_dir.join("libtestlib.so");
    let cc_output = Command::new(cc)
        .args([
            "-shared",
            "-o",
            so_file_path.to_str().unwrap(),
            "tests/extern-so/test.c",
            // Only add the functions specified in libcode.version to the shared object file.
            // This is to avoid automatically adding `malloc`, etc.
            // Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/
            "-fPIC",
            "-Wl,--version-script=tests/extern-so/libcode.version",
        ])
        .output()
        .expect("failed to generate shared object file for testing external C function calls");
    if !cc_output.status.success() {
        panic!("error in generating shared object file for testing external C function calls");
    }
    so_file_path
}

fn run_tests(
    mode: Mode,
    path: &str,
    target: Option<String>,
    with_dependencies: bool,
) -> Result<()> {
    let mut config = Config {
        target,
        stderr_filters: STDERR.clone(),
        stdout_filters: STDOUT.clone(),
        root_dir: PathBuf::from(path),
        mode,
        program: miri_path(),
        quiet: false,
        ..Config::default()
    };

    let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some();

    // Add some flags we always want.
    config.args.push("--edition".into());
    config.args.push("2018".into());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        config.args.push("-Astable-features".into());
        config.args.push("-Aunused".into());
    } else {
        config.args.push("-Dwarnings".into());
        config.args.push("-Dunused".into());
    }
    if let Ok(extra_flags) = env::var("MIRIFLAGS") {
        for flag in extra_flags.split_whitespace() {
            config.args.push(flag.into());
        }
    }
    config.args.push("-Zui-testing".into());
    if let Some(target) = &config.target {
        config.args.push("--target".into());
        config.args.push(target.into());
    }

    // If we're on linux, and we're testing the extern-so functionality,
    // then build the shared object file for testing external C function calls
    // and push the relevant compiler flag.
    if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
        let so_file_path = build_so_for_c_ffi_tests();
        let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
        flag.push(so_file_path.into_os_string());
        config.args.push(flag);
    }

    let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some();

    config.output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) {
        (false, false) => OutputConflictHandling::Error,
        (true, false) => OutputConflictHandling::Bless,
        (false, true) => OutputConflictHandling::Ignore,
        (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"),
    };

    // Handle command-line arguments.
    config.path_filter.extend(std::env::args().skip(1).filter(|arg| {
        match &**arg {
            "--quiet" => {
                config.quiet = true;
                false
            }
            _ => true,
        }
    }));

    let use_std = env::var_os("MIRI_NO_STD").is_none();

    if with_dependencies && use_std {
        config.dependencies_crate_manifest_path =
            Some(Path::new("test_dependencies").join("Cargo.toml"));
        config.dependency_builder.args = vec![
            "run".into(),
            "--manifest-path".into(),
            "cargo-miri/Cargo.toml".into(),
            "--".into(),
            "miri".into(),
            "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`.
        ];
    }
    ui_test::run_tests(config)
}

macro_rules! regexes {
    ($name:ident: $($regex:expr => $replacement:expr,)*) => {lazy_static::lazy_static! {
        static ref $name: Vec<(Regex, &'static str)> = vec![
            $((Regex::new($regex).unwrap(), $replacement),)*
        ];
    }};
}

regexes! {
    STDOUT:
    // Windows file paths
    r"\\"                           => "/",
}

regexes! {
    STDERR:
    // erase line and column info
    r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC",
    // erase alloc ids
    "alloc[0-9]+"                    => "ALLOC",
    // erase Stacked Borrows tags
    "<[0-9]+>"                       => "<TAG>",
    // erase whitespace that differs between platforms
    r" +at (.*\.rs)"                 => " at $1",
    // erase generics in backtraces
    "([0-9]+: .*)::<.*>"             => "$1",
    // erase addresses in backtraces
    "([0-9]+: ) +0x[0-9a-f]+ - (.*)" => "$1$2",
    // erase long hexadecimals
    r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX",
    // erase specific alignments
    "alignment [0-9]+"               => "alignment ALIGN",
    // erase thread caller ids
    r"call [0-9]+"                  => "call ID",
    // erase platform module paths
    "sys::[a-z]+::"                  => "sys::PLATFORM::",
    // Windows file paths
    r"\\"                           => "/",
    // erase Rust stdlib path
    "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/",
    // erase platform file paths
    "sys/[a-z]+/"                    => "sys/PLATFORM/",
    // erase paths into the crate registry
    r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)"  => "CARGO_REGISTRY/.../$1",
}

enum Dependencies {
    WithDependencies,
    WithoutDependencies,
}

use Dependencies::*;

fn ui(mode: Mode, path: &str, with_dependencies: Dependencies) -> Result<()> {
    let target = get_target();

    let msg = format!(
        "## Running ui tests in {path} against miri for {}",
        target.as_deref().unwrap_or("host")
    );
    eprintln!("{}", msg.green().bold());

    let with_dependencies = match with_dependencies {
        WithDependencies => true,
        WithoutDependencies => false,
    };
    run_tests(mode, path, target, with_dependencies)
}

fn get_target() -> Option<String> {
    env::var("MIRI_TEST_TARGET").ok()
}

fn main() -> Result<()> {
    ui_test::color_eyre::install()?;

    // Add a test env var to do environment communication tests.
    env::set_var("MIRI_ENV_VAR_TEST", "0");
    // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
    env::set_var("MIRI_TEMP", env::temp_dir());

    ui(Mode::Pass, "tests/pass", WithoutDependencies)?;
    ui(Mode::Pass, "tests/pass-dep", WithDependencies)?;
    ui(Mode::Panic, "tests/panic", WithDependencies)?;
    ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?;
    if cfg!(target_os = "linux") {
        ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?;
        ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?;
    }

    Ok(())
}
<commit_msg>Auto merge of #2563 - RalfJung:nodep, r=RalfJung<commit_after>use colored::*;
use regex::Regex;
use std::path::{Path, PathBuf};
use std::{env, process::Command};
use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling};

fn miri_path() -> PathBuf {
    PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri")))
}

// Build the shared object file for testing external C function calls.
fn build_so_for_c_ffi_tests() -> PathBuf {
    let cc = option_env!("CC").unwrap_or("cc");
    // Target directory that we can write to.
    let so_target_dir = Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-extern-so");
    // Create the directory if it does not already exist.
    std::fs::create_dir_all(&so_target_dir)
        .expect("Failed to create directory for shared object file");
    let so_file_path = so_target_dir.join("libtestlib.so");
    let cc_output = Command::new(cc)
        .args([
            "-shared",
            "-o",
            so_file_path.to_str().unwrap(),
            "tests/extern-so/test.c",
            // Only add the functions specified in libcode.version to the shared object file.
            // This is to avoid automatically adding `malloc`, etc.
            // Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/
            "-fPIC",
            "-Wl,--version-script=tests/extern-so/libcode.version",
        ])
        .output()
        .expect("failed to generate shared object file for testing external C function calls");
    if !cc_output.status.success() {
        panic!("error in generating shared object file for testing external C function calls");
    }
    so_file_path
}

fn run_tests(
    mode: Mode,
    path: &str,
    target: Option<String>,
    with_dependencies: bool,
) -> Result<()> {
    let mut config = Config {
        target,
        stderr_filters: STDERR.clone(),
        stdout_filters: STDOUT.clone(),
        root_dir: PathBuf::from(path),
        mode,
        program: miri_path(),
        quiet: false,
        ..Config::default()
    };

    let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some();

    // Add some flags we always want.
    config.args.push("--edition".into());
    config.args.push("2018".into());
    if in_rustc_test_suite {
        // Less aggressive warnings to make the rustc toolstate management less painful.
        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
        config.args.push("-Astable-features".into());
        config.args.push("-Aunused".into());
    } else {
        config.args.push("-Dwarnings".into());
        config.args.push("-Dunused".into());
    }
    if let Ok(extra_flags) = env::var("MIRIFLAGS") {
        for flag in extra_flags.split_whitespace() {
            config.args.push(flag.into());
        }
    }
    config.args.push("-Zui-testing".into());
    if let Some(target) = &config.target {
        config.args.push("--target".into());
        config.args.push(target.into());
    }

    // If we're on linux, and we're testing the extern-so functionality,
    // then build the shared object file for testing external C function calls
    // and push the relevant compiler flag.
    if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") {
        let so_file_path = build_so_for_c_ffi_tests();
        let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
        flag.push(so_file_path.into_os_string());
        config.args.push(flag);
    }

    let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some();

    config.output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) {
        (false, false) => OutputConflictHandling::Error,
        (true, false) => OutputConflictHandling::Bless,
        (false, true) => OutputConflictHandling::Ignore,
        (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"),
    };

    // Handle command-line arguments.
    config.path_filter.extend(std::env::args().skip(1).filter(|arg| {
        match &**arg {
            "--quiet" => {
                config.quiet = true;
                false
            }
            _ => true,
        }
    }));

    let use_std = env::var_os("MIRI_NO_STD").is_none();

    if with_dependencies && use_std {
        config.dependencies_crate_manifest_path =
            Some(Path::new("test_dependencies").join("Cargo.toml"));
        config.dependency_builder.args = vec![
            "run".into(),
            "--manifest-path".into(),
            "cargo-miri/Cargo.toml".into(),
            "--".into(),
            "miri".into(),
            "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`.
        ];
    }
    ui_test::run_tests(config)
}

macro_rules! regexes {
    ($name:ident: $($regex:expr => $replacement:expr,)*) => {lazy_static::lazy_static! {
        static ref $name: Vec<(Regex, &'static str)> = vec![
            $((Regex::new($regex).unwrap(), $replacement),)*
        ];
    }};
}

regexes! {
    STDOUT:
    // Windows file paths
    r"\\"                           => "/",
}

regexes! {
    STDERR:
    // erase line and column info
    r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC",
    // erase alloc ids
    "alloc[0-9]+"                    => "ALLOC",
    // erase Stacked Borrows tags
    "<[0-9]+>"                       => "<TAG>",
    // erase whitespace that differs between platforms
    r" +at (.*\.rs)"                 => " at $1",
    // erase generics in backtraces
    "([0-9]+: .*)::<.*>"             => "$1",
    // erase addresses in backtraces
    "([0-9]+: ) +0x[0-9a-f]+ - (.*)" => "$1$2",
    // erase long hexadecimals
    r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX",
    // erase specific alignments
    "alignment [0-9]+"               => "alignment ALIGN",
    // erase thread caller ids
    r"call [0-9]+"                  => "call ID",
    // erase platform module paths
    "sys::[a-z]+::"                  => "sys::PLATFORM::",
    // Windows file paths
    r"\\"                           => "/",
    // erase Rust stdlib path
    "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/",
    // erase platform file paths
    "sys/[a-z]+/"                    => "sys/PLATFORM/",
    // erase paths into the crate registry
    r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)"  => "CARGO_REGISTRY/.../$1",
}

enum Dependencies {
    WithDependencies,
    WithoutDependencies,
}

use Dependencies::*;

fn ui(mode: Mode, path: &str, with_dependencies: Dependencies) -> Result<()> {
    let target = get_target();

    let msg = format!(
        "## Running ui tests in {path} against miri for {}",
        target.as_deref().unwrap_or("host")
    );
    eprintln!("{}", msg.green().bold());

    let with_dependencies = match with_dependencies {
        WithDependencies => true,
        WithoutDependencies => false,
    };
    run_tests(mode, path, target, with_dependencies)
}

fn get_target() -> Option<String> {
    env::var("MIRI_TEST_TARGET").ok()
}

fn main() -> Result<()> {
    ui_test::color_eyre::install()?;

    // Add a test env var to do environment communication tests.
    env::set_var("MIRI_ENV_VAR_TEST", "0");
    // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
    env::set_var("MIRI_TEMP", env::temp_dir());

    ui(Mode::Pass, "tests/pass", WithoutDependencies)?;
    ui(Mode::Pass, "tests/pass-dep", WithDependencies)?;
    ui(Mode::Panic, "tests/panic", WithDependencies)?;
    ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?;
    if cfg!(target_os = "linux") {
        ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?;
        ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithoutDependencies)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! This module contains all of the enums used
//! to represent messages that can be send by clients
//! ( SerialRequest::* ) and their responses by
//! by the server ( SerialReponse::* )

use serde_json;

// TODO: use when new version drops
//use serialport::{SerialPortInfo,UsbPortInfo,SerialPortType};

use std::fmt;
use std::sync::mpsc::Sender;

#[derive( Clone, Debug)]
pub struct SubscriptionRequest {
  pub sub_id: String,
  pub subscriber: Sender<SerialResponse>,
}

/// Represents the valid json requests that can be made
///
/// On the server side, every client is associated with
/// a unique subscription id which is used
/// to associate a given connection with their
/// operations
///
/// Requests that fail or can not be met will result
/// in SerialResponse::Error responses
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialRequest {
  /// Open a port for reading
  ///
  /// Opening the same port more than once is
  /// okay and has no ill effects
  ///
  ///``` json
  /// JSON:
  /// {"Open":{"port":"/dev/ttyUSB"}}
  ///```
  Open { port: String },
  /// Take control of a port for writing
  ///
  /// ``` json
  /// JSON:
  /// {"WriteLock":{"port":"/dev/ttyUSB"}}
  /// ```
  WriteLock { port: String },
  /// Release control of a port for writing
  /// If no port is given, release all write locks
  /// held by the client for all ports
  ///
  /// ``` json
  /// JSON:
  /// {"ReleaseWriteLock":{"port":"/dev/ttyUSB"}}
  ///
  /// {"ReleaseWriteLock":{}}
  /// ```
  ReleaseWriteLock { port: Option<String> },
  /// Write data, only works if the client
  /// has a WriteLock active for the given port
  ///
  /// The base64 property is only required
  /// if the data is encoded as base64
  ///
  /// ``` json
  /// JSON:
  /// {"Write":{"port":"/dev/ttyUSB",
  ///           "data": "Hello World"
  ///          }}
  ///
  /// {"Write":{"port":"/dev/ttyUSB",
  ///           "data": "SGVsbG8gV29ybGQ=",
  ///           "base64": true
  ///          }}
  /// ```
  Write {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Close the port, which stops any read updates
  /// from the port from being sent to this subscription
  ///
  /// If no port is specified, then all ports are 'closed'
  ///
  /// In most cases this behaves more as an 'unsubscribe'
  /// as the hardware port is only closed and released
  /// when the last client connected to it sends a Close message
  ///
  /// ``` json
  /// JSON:
  /// {"Close":{"port":"/dev/ttyUSB"}}
  ///
  /// {"Close":{}}
  /// ```
  Close { port: Option<String> },
  /// List available serial ports
  ///
  /// ``` json
  /// JSON:
  /// {"List":{}}
  /// ```
  List {},
}

impl fmt::Display for SerialRequest {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or(
      "Display SerialRequest: Serialization Failed!"
        .to_string(),
    );
    write!(f, "{}", json)
  }
}

/// Represents the valid json responses that can be made
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum SerialResponse {
  /// Error response
  ///
  /// ``` json
  /// JSON:
  /// {"Error":{
  ///            "description":"Error reading serial port",
  ///            "display":"Error reading serial port '/dev/ttyUSB0'"
  ///          }}
  ///
  /// ```
  Error {
    description: String,
    display: String,
  },
  /// Data that was read from port
  ///
  /// If the data could not be parsed into a utf8 string
  /// then it is base64 encoded and the base64
  /// property is set to true.
  ///
  /// ``` json
  /// JSON:
  /// {"Read":{"port":"/dev/ttyUSB",
  ///           "data": "Hello World"
  ///          }}
  ///
  /// {"Read":{"port":"/dev/ttyUSB",
  ///           "data": "SGVsbG8gV29ybGQ=",
  ///           "base64": true
  ///          }}
  /// ```
  Read {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Port was closed
  ///
  /// Sent in response to SerialRequest::Close
  /// or sent when the server detects that a serial
  /// port is misbehaving, closes it, and then
  /// notifies the clients
  ///
  ///``` json
  /// JSON:
  /// {"Closed":{"port":"/dev/ttyUSB"}}
  ///```
  Closed { port: String },
  /// Port was opened
  ///
  /// Sent in response to SerialRequest::Open
  ///
  ///``` json
  /// JSON:
  /// {"Opened":{"port":"/dev/ttyUSB"}}
  ///```
  Opened { port: String },
  /// Command successful
  Ok { msg: String },
  /// Wrote data
  ///
  /// Sent in response to SerialReques::Write
  ///
  /// Notifies the client that the request to write
  /// data was received, and the data was successfully
  /// written to the port specified
  ///
  /// ``` json
  /// JSON:
  /// {"Wrote":{"port":"/dev/ttyUSB"}}
  /// ```
  ///
  /// TODO: Return hash of data written?
  Wrote { port: String },
  /// Port successfully writelocked
  ///
  /// Sent in response to SerialReques::WriteLock
  ///
  /// Notifies the client that the WriteLock was received
  /// and completed successfully
  ///
  /// ``` json
  /// JSON:
  /// {"WriteLock":{"port":"/dev/ttyUSB"}}
  /// ```
  WriteLocked { port: String },
  /// WriteLocks on Port(s) successfully released
  ///
  /// Sent in response to SerialReques::ReleaseWriteLock
  ///
  /// Notifies the client that the ReleaseWriteLock was received
  /// and completed successfully
  ///
  /// If ReleaseWrite was sent without a port specified, then
  /// it will be empty in the response. This means that all
  /// write locks held on behalf of the client were released.
  ///
  /// ``` json
  /// JSON:
  /// {"WriteLockReleased":{"port":"/dev/ttyUSB"}}
  ///
  /// {"WriteLockReleased":{}}
  /// ```
  WriteLockReleased { port: Option<String> },
  /// List serial ports response
  ///
  /// ``` json
  /// JSON:
  /// {"List":{"ports":["/dev/ttyUSB0","/dev/ttyUSB1"]}}
  /// ```
  List { ports: Vec<String> },
}

/*
// TODO: Uncomment when new serialport module version drops
/// Needed for Serde Support as
/// SerialPortInfo is in seperate module
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(remote = "SerialPortInfo")]
pub struct SerialPortInfoDef {
    /// The short name of the serial port
    pub port_name: String,
    /// The hardware device type that exposes this port
    pub port_type: SerialPortType,

}

#[derive(Serialize, Deserialize)]
#[serde(remote = "sp::SerialPortType")]
/// The physical type of a `SerialPort`
pub enum SerialPortTypeDef {
    /// The serial port is connected via USB
    UsbPort(UsbPortInfoDef),
    /// The serial port is connected via PCI (permanent port)
    PciPort,
    /// The serial port is connected via Bluetooth
    BluetoothPort,
    /// It can't be determined how the serial port is connected
    Unknown,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "UsbPortInfo")]
pub struct UsbPortInfoDef {
    /// Vender ID
    pub vid: u16,
    /// Product ID
    pub pid: u16,
    /// Serial number (arbitrary string)
    pub serial_number: Option<String>,
    /// Manufacturer (arbitrary string)
    pub manufacturer: Option<String>,
    /// Product name (arbitrary string)
    pub product: Option<String>,
}
*/

impl fmt::Display for SerialResponse {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or(
      "Display SerialResponse: Serialization Failed!"
        .to_string(),
    );
    write!(f, "{}", json)
  }
}
<commit_msg>Make messages comparable<commit_after>//! This module contains all of the enums used
//! to represent messages that can be send by clients
//! ( SerialRequest::* ) and their responses by
//! by the server ( SerialReponse::* )

use serde_json;

// TODO: use when new version drops
//use serialport::{SerialPortInfo,UsbPortInfo,SerialPortType};

use std::fmt;
use std::sync::mpsc::Sender;

#[derive( Clone, Debug)]
pub struct SubscriptionRequest {
  pub sub_id: String,
  pub subscriber: Sender<SerialResponse>,
}

/// Represents the valid json requests that can be made
///
/// On the server side, every client is associated with
/// a unique subscription id which is used
/// to associate a given connection with their
/// operations
///
/// Requests that fail or can not be met will result
/// in SerialResponse::Error responses
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum SerialRequest {
  /// Open a port for reading
  ///
  /// Opening the same port more than once is
  /// okay and has no ill effects
  ///
  ///``` json
  /// JSON:
  /// {"Open":{"port":"/dev/ttyUSB"}}
  ///```
  Open { port: String },
  /// Take control of a port for writing
  ///
  /// ``` json
  /// JSON:
  /// {"WriteLock":{"port":"/dev/ttyUSB"}}
  /// ```
  WriteLock { port: String },
  /// Release control of a port for writing
  /// If no port is given, release all write locks
  /// held by the client for all ports
  ///
  /// ``` json
  /// JSON:
  /// {"ReleaseWriteLock":{"port":"/dev/ttyUSB"}}
  ///
  /// {"ReleaseWriteLock":{}}
  /// ```
  ReleaseWriteLock { port: Option<String> },
  /// Write data, only works if the client
  /// has a WriteLock active for the given port
  ///
  /// The base64 property is only required
  /// if the data is encoded as base64
  ///
  /// ``` json
  /// JSON:
  /// {"Write":{"port":"/dev/ttyUSB",
  ///           "data": "Hello World"
  ///          }}
  ///
  /// {"Write":{"port":"/dev/ttyUSB",
  ///           "data": "SGVsbG8gV29ybGQ=",
  ///           "base64": true
  ///          }}
  /// ```
  Write {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Close the port, which stops any read updates
  /// from the port from being sent to this subscription
  ///
  /// If no port is specified, then all ports are 'closed'
  ///
  /// In most cases this behaves more as an 'unsubscribe'
  /// as the hardware port is only closed and released
  /// when the last client connected to it sends a Close message
  ///
  /// ``` json
  /// JSON:
  /// {"Close":{"port":"/dev/ttyUSB"}}
  ///
  /// {"Close":{}}
  /// ```
  Close { port: Option<String> },
  /// List available serial ports
  ///
  /// ``` json
  /// JSON:
  /// {"List":{}}
  /// ```
  List {},
}

impl fmt::Display for SerialRequest {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or(
      "Display SerialRequest: Serialization Failed!"
        .to_string(),
    );
    write!(f, "{}", json)
  }
}

/// Represents the valid json responses that can be made
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum SerialResponse {
  /// Error response
  ///
  /// ``` json
  /// JSON:
  /// {"Error":{
  ///            "description":"Error reading serial port",
  ///            "display":"Error reading serial port '/dev/ttyUSB0'"
  ///          }}
  ///
  /// ```
  Error {
    description: String,
    display: String,
  },
  /// Data that was read from port
  ///
  /// If the data could not be parsed into a utf8 string
  /// then it is base64 encoded and the base64
  /// property is set to true.
  ///
  /// ``` json
  /// JSON:
  /// {"Read":{"port":"/dev/ttyUSB",
  ///           "data": "Hello World"
  ///          }}
  ///
  /// {"Read":{"port":"/dev/ttyUSB",
  ///           "data": "SGVsbG8gV29ybGQ=",
  ///           "base64": true
  ///          }}
  /// ```
  Read {
    port: String,
    data: String,
    base64: Option<bool>,
  },
  /// Port was closed
  ///
  /// Sent in response to SerialRequest::Close
  /// or sent when the server detects that a serial
  /// port is misbehaving, closes it, and then
  /// notifies the clients
  ///
  ///``` json
  /// JSON:
  /// {"Closed":{"port":"/dev/ttyUSB"}}
  ///```
  Closed { port: String },
  /// Port was opened
  ///
  /// Sent in response to SerialRequest::Open
  ///
  ///``` json
  /// JSON:
  /// {"Opened":{"port":"/dev/ttyUSB"}}
  ///```
  Opened { port: String },
  /// Command successful
  Ok { msg: String },
  /// Wrote data
  ///
  /// Sent in response to SerialReques::Write
  ///
  /// Notifies the client that the request to write
  /// data was received, and the data was successfully
  /// written to the port specified
  ///
  /// ``` json
  /// JSON:
  /// {"Wrote":{"port":"/dev/ttyUSB"}}
  /// ```
  ///
  /// TODO: Return hash of data written?
  Wrote { port: String },
  /// Port successfully writelocked
  ///
  /// Sent in response to SerialReques::WriteLock
  ///
  /// Notifies the client that the WriteLock was received
  /// and completed successfully
  ///
  /// ``` json
  /// JSON:
  /// {"WriteLock":{"port":"/dev/ttyUSB"}}
  /// ```
  WriteLocked { port: String },
  /// WriteLocks on Port(s) successfully released
  ///
  /// Sent in response to SerialReques::ReleaseWriteLock
  ///
  /// Notifies the client that the ReleaseWriteLock was received
  /// and completed successfully
  ///
  /// If ReleaseWrite was sent without a port specified, then
  /// it will be empty in the response. This means that all
  /// write locks held on behalf of the client were released.
  ///
  /// ``` json
  /// JSON:
  /// {"WriteLockReleased":{"port":"/dev/ttyUSB"}}
  ///
  /// {"WriteLockReleased":{}}
  /// ```
  WriteLockReleased { port: Option<String> },
  /// List serial ports response
  ///
  /// ``` json
  /// JSON:
  /// {"List":{"ports":["/dev/ttyUSB0","/dev/ttyUSB1"]}}
  /// ```
  List { ports: Vec<String> },
}

/*
// TODO: Uncomment when new serialport module version drops
/// Needed for Serde Support as
/// SerialPortInfo is in seperate module
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(remote = "SerialPortInfo")]
pub struct SerialPortInfoDef {
    /// The short name of the serial port
    pub port_name: String,
    /// The hardware device type that exposes this port
    pub port_type: SerialPortType,

}

#[derive(Serialize, Deserialize)]
#[serde(remote = "sp::SerialPortType")]
/// The physical type of a `SerialPort`
pub enum SerialPortTypeDef {
    /// The serial port is connected via USB
    UsbPort(UsbPortInfoDef),
    /// The serial port is connected via PCI (permanent port)
    PciPort,
    /// The serial port is connected via Bluetooth
    BluetoothPort,
    /// It can't be determined how the serial port is connected
    Unknown,
}

#[derive(Serialize, Deserialize)]
#[serde(remote = "UsbPortInfo")]
pub struct UsbPortInfoDef {
    /// Vender ID
    pub vid: u16,
    /// Product ID
    pub pid: u16,
    /// Serial number (arbitrary string)
    pub serial_number: Option<String>,
    /// Manufacturer (arbitrary string)
    pub manufacturer: Option<String>,
    /// Product name (arbitrary string)
    pub product: Option<String>,
}
*/

impl fmt::Display for SerialResponse {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let json = serde_json::to_string(self).unwrap_or(
      "Display SerialResponse: Serialization Failed!"
        .to_string(),
    );
    write!(f, "{}", json)
  }
}
<|endoftext|>


<commit_before>use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::future;

use std::iter::Take;
use tokio::runtime::Runtime;
use tokio_retry::{Retry, RetryIf};

#[test]
fn attempts_just_once() {
    use std::iter::empty;
    let runtime = Runtime::new().unwrap();
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(empty(), move || {
        cloned_counter.fetch_add(1, Ordering::SeqCst);
        future::ready(Err::<(), u64>(42))
    });

    let res = runtime.block_on(future);

    assert_eq!(res, Err(42));
    assert_eq!(counter.load(Ordering::SeqCst), 1);
}

#[test]
fn attempts_until_max_retries_exceeded() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100).take(2);
    let runtime = Runtime::new().unwrap();
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(s, move || {
        cloned_counter.fetch_add(1, Ordering::SeqCst);
        future::ready(Err::<(), u64>(42))
    });
    let res = runtime.block_on(future);

    assert_eq!(res, Err(42));
    assert_eq!(counter.load(Ordering::SeqCst), 3);
}

#[test]
fn attempts_until_success() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100);
    let runtime = Runtime::new().unwrap();
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(s, move || {
        let previous = cloned_counter.fetch_add(1, Ordering::SeqCst);
        if previous < 3 {
            future::ready(Err::<(), u64>(42))
        } else {
            future::ready(Ok::<(), u64>(()))
        }
    });
    let res = runtime.block_on(future);

    assert_eq!(res, Ok(()));
    assert_eq!(counter.load(Ordering::SeqCst), 4);
}

#[test]
fn compatible_with_tokio_core() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100);
    let rt = Runtime::new().unwrap();
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(s, move || {
        let previous = cloned_counter.fetch_add(1, Ordering::SeqCst);
        if previous < 3 {
            future::ready(Err::<(), u64>(42))
        } else {
            future::ready(Ok::<(), u64>(()))
        }
    });
    let res = rt.block_on(future);

    assert_eq!(res, Ok(()));
    assert_eq!(counter.load(Ordering::SeqCst), 4);
}

#[test]
fn attempts_retry_only_if_given_condition_is_true() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100).take(5);
    let runtime = Runtime::new().unwrap();
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future: RetryIf<Take<FixedInterval>, _, fn(&usize) -> _> = RetryIf::spawn(
        s,
        move || {
            let previous = cloned_counter.fetch_add(1, Ordering::SeqCst);
            future::ready(Err::<(), usize>(previous + 1))
        },
        |e: &usize| *e < 3,
    );
    let res = runtime.block_on(future);

    assert_eq!(res, Err(3));
    assert_eq!(counter.load(Ordering::SeqCst), 3);
}
<commit_msg>convert tests to #[tokio::test]<commit_after>use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::future;
use std::iter::Take;

use tokio_retry::{Retry, RetryIf};

#[tokio::test]
async fn attempts_just_once() {
    use std::iter::empty;
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(empty(), move || {
        cloned_counter.fetch_add(1, Ordering::SeqCst);
        future::ready(Err::<(), u64>(42))
    });
    let res = future.await;

    assert_eq!(res, Err(42));
    assert_eq!(counter.load(Ordering::SeqCst), 1);
}

#[tokio::test]
async fn attempts_until_max_retries_exceeded() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100).take(2);
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(s, move || {
        cloned_counter.fetch_add(1, Ordering::SeqCst);
        future::ready(Err::<(), u64>(42))
    });
    let res = future.await;

    assert_eq!(res, Err(42));
    assert_eq!(counter.load(Ordering::SeqCst), 3);
}

#[tokio::test]
async fn attempts_until_success() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100);
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(s, move || {
        let previous = cloned_counter.fetch_add(1, Ordering::SeqCst);
        if previous < 3 {
            future::ready(Err::<(), u64>(42))
        } else {
            future::ready(Ok::<(), u64>(()))
        }
    });
    let res = future.await;

    assert_eq!(res, Ok(()));
    assert_eq!(counter.load(Ordering::SeqCst), 4);
}

#[tokio::test]
async fn compatible_with_tokio_core() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100);
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future = Retry::spawn(s, move || {
        let previous = cloned_counter.fetch_add(1, Ordering::SeqCst);
        if previous < 3 {
            future::ready(Err::<(), u64>(42))
        } else {
            future::ready(Ok::<(), u64>(()))
        }
    });
    let res = future.await;

    assert_eq!(res, Ok(()));
    assert_eq!(counter.load(Ordering::SeqCst), 4);
}

#[tokio::test]
async fn attempts_retry_only_if_given_condition_is_true() {
    use tokio_retry::strategy::FixedInterval;
    let s = FixedInterval::from_millis(100).take(5);
    let counter = Arc::new(AtomicUsize::new(0));
    let cloned_counter = counter.clone();
    let future: RetryIf<Take<FixedInterval>, _, fn(&usize) -> _> = RetryIf::spawn(
        s,
        move || {
            let previous = cloned_counter.fetch_add(1, Ordering::SeqCst);
            future::ready(Err::<(), usize>(previous + 1))
        },
        |e: &usize| *e < 3,
    );
    let res = future.await;

    assert_eq!(res, Err(3));
    assert_eq!(counter.load(Ordering::SeqCst), 3);
}
<|endoftext|>


<commit_before>// (c) 2016-2017 Joost Yervante Damad <joost@productize.be>

use std::path::PathBuf;

extern crate kicad_parse_gen;

fn main() {
    let mut file_name = String::new();
    file_name.push_str(env!("CARGO_MANIFEST_DIR"));
    file_name.push_str("/tests/data/");
    file_name.push_str("breakout-cache.lib");

    let path = PathBuf::from(&file_name);
    let s = kicad_parse_gen::symbol_lib::parse_file(&path).unwrap();
    println!("{}", s);
}
<commit_msg>add symbol_lib parse_and_compare test<commit_after>// (c) 2016-2017 Joost Yervante Damad <joost@productize.be>

extern crate kicad_parse_gen as kicad;

extern crate difference;

#[test]
fn parse_and_compare() {
    let mut file_name = String::new();
    file_name.push_str(env!("CARGO_MANIFEST_DIR"));
    file_name.push_str("/tests/data/");
    file_name.push_str("breakout-cache.lib");

    let content = kicad::read_file(&file_name).unwrap();

    let s = kicad::read_symbol_lib(&file_name).unwrap();
    let s = format!("{}", s);

    // very inefficient...
    let (n, _) = difference::diff(&content, &s, "\n");
    if n > 1 {
        difference::print_diff(&content, &s, "\n");
        assert_eq!(n, 1);
    }
}
<|endoftext|>


<commit_before>#![allow(unstable)]
extern crate petgraph;

use petgraph::{
    OGraph,
    Bfs,
    BfsIter,
    Dfs,
    DfsIter,
    dijkstra,
    Incoming,
    Outgoing,
};

use petgraph::ograph::{
    min_spanning_tree,
    is_cyclic,
    NodeIndex,
};

use petgraph::visit::{
    Reversed,
    AsUndirected,
};

#[test]
fn undirected()
{
    let mut og = OGraph::new_undirected();
    let a = og.add_node(0);
    let b = og.add_node(1);
    let c = og.add_node(2);
    let d = og.add_node(3);
    let _ = og.add_edge(a, b, 0);
    let _ = og.add_edge(a, c, 1);
    og.add_edge(c, a, 2);
    og.add_edge(a, a, 3);
    og.add_edge(b, c, 4);
    og.add_edge(b, a, 5);
    og.add_edge(a, d, 6);
    assert_eq!(og.node_count(), 4);
    assert_eq!(og.edge_count(), 7);

    assert!(og.find_edge(a, b).is_some());
    assert!(og.find_edge(d, a).is_some());
    assert!(og.find_edge(a, a).is_some());

    for edge in og.raw_edges().iter() {
        assert!(og.find_edge(edge.source(), edge.target()).is_some());
        assert!(og.find_edge(edge.target(), edge.source()).is_some());
    }

    assert_eq!(og.neighbors(b).collect::<Vec<_>>(), vec![a, c, a]);

    og.remove_node(a);
    assert_eq!(og.neighbors(b).collect::<Vec<_>>(), vec![c]);
    assert_eq!(og.node_count(), 3);
    assert_eq!(og.edge_count(), 1);
    assert!(og.find_edge(a, b).is_none());
    assert!(og.find_edge(d, a).is_none());
    assert!(og.find_edge(a, a).is_none());
    assert!(og.find_edge(b, c).is_some());

}

#[test]
fn dfs() {
    let mut gr = OGraph::new();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    // Z is disconnected.
    let _ = gr.add_node("Z");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);
    gr.add_edge(i, k, 2.);

    assert_eq!(DfsIter::new(&gr, h).count(), 4);

    assert_eq!(DfsIter::new(&Reversed(&gr), h).count(), 1);

    assert_eq!(DfsIter::new(&Reversed(&gr), k).count(), 3);

    assert_eq!(DfsIter::new(&gr, i).count(), 3);

    assert_eq!(DfsIter::new(&AsUndirected(&gr), i).count(), 4);
}

#[test]
fn bfs() {
    let mut gr = OGraph::new();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    // Z is disconnected.
    let _ = gr.add_node("Z");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);
    gr.add_edge(i, k, 2.);

    assert_eq!(BfsIter::new(&gr, h).count(), 4);

    assert_eq!(BfsIter::new(&Reversed(&gr), h).count(), 1);

    assert_eq!(BfsIter::new(&Reversed(&gr), k).count(), 3);

    assert_eq!(BfsIter::new(&gr, i).count(), 3);

    assert_eq!(BfsIter::new(&AsUndirected(&gr), i).count(), 4);

    let mut bfs = Bfs::new(&gr, h);
    let nx = bfs.next(&gr);
    assert_eq!(nx, Some(h));

    let nx1 = bfs.next(&gr);
    assert!(nx1 == Some(i) || nx1 == Some(j));

    let nx2 = bfs.next(&gr);
    assert!(nx2 == Some(i) || nx2 == Some(j));
    assert!(nx1 != nx2);

    let nx = bfs.next(&gr);
    assert_eq!(nx, Some(k));
    assert_eq!(bfs.next(&gr), None);
}

#[test]
fn mst() {
    let mut gr = OGraph::<_,_>::new();
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    let d = gr.add_node("D");
    let e = gr.add_node("E");
    let f = gr.add_node("F");
    let g = gr.add_node("G");
    gr.add_edge(a, b, 7.0_f32);  // closure capture below doesn't work with default float type
    gr.add_edge(a, d, 5.);
    gr.add_edge(d, b, 9.);
    gr.add_edge(b, c, 8.);
    gr.add_edge(b, e, 7.);
    gr.add_edge(c, e, 5.);
    gr.add_edge(d, e, 15.);
    gr.add_edge(d, f, 6.);
    gr.add_edge(f, e, 8.);
    gr.add_edge(f, g, 11.);
    gr.add_edge(e, g, 9.);

    // add a disjoint part
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);

    let mst = min_spanning_tree(&gr);
    println!("MST is:\n{:?}", mst);
    assert!(mst.node_count() == gr.node_count());
    // |E| = |N| - 2  because there are two disconnected components.
    assert!(mst.edge_count() == gr.node_count() - 2);

    // check the exact edges are there
    assert!(mst.find_edge(a, b).is_some());
    assert!(mst.find_edge(a, d).is_some());
    assert!(mst.find_edge(b, e).is_some());
    assert!(mst.find_edge(e, c).is_some());
    assert!(mst.find_edge(e, g).is_some());
    assert!(mst.find_edge(d, f).is_some());

    assert!(mst.find_edge(h, i).is_some());
    assert!(mst.find_edge(i, j).is_some());

    assert!(mst.find_edge(d, b).is_none());
    assert!(mst.find_edge(b, c).is_none());

}

#[test]
fn selfloop() {
    let mut gr = OGraph::new();
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    gr.add_edge(a, b, 7.);
    gr.add_edge(c, a, 6.);
    let sed = gr.add_edge(a, a, 2.);

    assert!(gr.find_edge(a, b).is_some());
    assert!(gr.find_edge(b, a).is_none());
    assert!(gr.find_edge_undirected(b, a).is_some());
    assert!(gr.find_edge(a, a).is_some());
    println!("{:?}", gr);

    gr.remove_edge(sed);
    assert!(gr.find_edge(a, a).is_none());
    println!("{:?}", gr);
}

#[test]
fn cyclic() {
    let mut gr = OGraph::new();
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");

    assert!(!is_cyclic(&gr));
    gr.add_edge(a, b, 7.);
    gr.add_edge(c, a, 6.);
    assert!(!is_cyclic(&gr));
    {
        let e = gr.add_edge(a, a, 0.);
        assert!(is_cyclic(&gr));
        gr.remove_edge(e);
        assert!(!is_cyclic(&gr));
    }

    {
        let e = gr.add_edge(b, c, 0.);
        assert!(is_cyclic(&gr));
        gr.remove_edge(e);
        assert!(!is_cyclic(&gr));
    }

    let d = gr.add_node("D");
    let e = gr.add_node("E");
    gr.add_edge(b, d, 0.);
    gr.add_edge(d, e, 0.);
    assert!(!is_cyclic(&gr));
    gr.add_edge(c, e, 0.);
    assert!(is_cyclic(&gr));
}

#[test]
fn multi() {
    let mut gr = OGraph::new();
    let a = gr.add_node("a");
    let b = gr.add_node("b");
    gr.add_edge(a, b, ());
    gr.add_edge(a, b, ());
    assert_eq!(gr.edge_count(), 2);

}
#[test]
fn update_edge()
{
    {
        let mut gr = OGraph::new();
        let a = gr.add_node("a");
        let b = gr.add_node("b");
        let e = gr.update_edge(a, b, 1);
        let f = gr.update_edge(a, b, 2);
        let _ = gr.update_edge(b, a, 3);
        assert_eq!(gr.edge_count(), 2);
        assert_eq!(e, f);
        assert_eq!(*gr.edge_weight(f).unwrap(), 2);
    }

    {
        let mut gr = OGraph::new_undirected();
        let a = gr.add_node("a");
        let b = gr.add_node("b");
        let e = gr.update_edge(a, b, 1);
        let f = gr.update_edge(b, a, 2);
        assert_eq!(gr.edge_count(), 1);
        assert_eq!(e, f);
        assert_eq!(*gr.edge_weight(f).unwrap(), 2);
    }
}

#[test]
fn dijk() {
    let mut g = OGraph::new_undirected();
    let a = g.add_node("A");
    let b = g.add_node("B");
    let c = g.add_node("C");
    let d = g.add_node("D");
    let e = g.add_node("E");
    let f = g.add_node("F");
    g.add_edge(a, b, 7.0_f32);
    g.add_edge(c, a, 9.);
    g.add_edge(a, d, 14.);
    g.add_edge(b, c, 10.);
    g.add_edge(d, c, 2.);
    g.add_edge(d, e, 9.);
    g.add_edge(b, f, 15.);
    g.add_edge(c, f, 11.);
    g.add_edge(e, f, 6.);
    println!("{:?}", g);
    for no in BfsIter::new(&g, a) {
        println!("Visit {:?} = {:?}", no, g.node_weight(no));
    }

    let scores = dijkstra(&g, a, None, |gr, n| gr.edges(n).map(|(n, &e)| (n, e)));
    println!("Scores= {:?}", scores);
    assert_eq!(scores[c], 9.);
    assert_eq!(scores[e], 20.);
    assert_eq!(scores[f], 20.);

    let scores = dijkstra(&g, a, Some(c), |gr, n| gr.edges(n).map(|(n, &e)| (n, e)));
    assert_eq!(scores[c], 9.);
}

#[test]
fn without()
{
    let mut og = OGraph::new_undirected();
    let a = og.add_node(0);
    let b = og.add_node(1);
    let c = og.add_node(2);
    let d = og.add_node(3);
    let _ = og.add_edge(a, b, 0);
    let _ = og.add_edge(a, c, 1);
    let v: Vec<NodeIndex> = og.without_edges(Outgoing).collect();
    assert_eq!(v, vec![d]);

    let mut og = OGraph::new();
    let a = og.add_node(0);
    let b = og.add_node(1);
    let c = og.add_node(2);
    let d = og.add_node(3);
    let _ = og.add_edge(a, b, 0);
    let _ = og.add_edge(a, c, 1);
    let init: Vec<NodeIndex> = og.without_edges(Incoming).collect();
    let term: Vec<NodeIndex> = og.without_edges(Outgoing).collect();
    assert_eq!(init, vec![a, d]);
    assert_eq!(term, vec![b, c, d]);
}
<commit_msg>Add test for toposort<commit_after>#![allow(unstable)]
extern crate petgraph;

use petgraph::{
    OGraph,
    Bfs,
    BfsIter,
    Dfs,
    DfsIter,
    dijkstra,
    Incoming,
    Outgoing,
};

use petgraph::ograph::{
    min_spanning_tree,
    is_cyclic,
    NodeIndex,
};

use petgraph::visit::{
    Reversed,
    AsUndirected,
};

#[test]
fn undirected()
{
    let mut og = OGraph::new_undirected();
    let a = og.add_node(0);
    let b = og.add_node(1);
    let c = og.add_node(2);
    let d = og.add_node(3);
    let _ = og.add_edge(a, b, 0);
    let _ = og.add_edge(a, c, 1);
    og.add_edge(c, a, 2);
    og.add_edge(a, a, 3);
    og.add_edge(b, c, 4);
    og.add_edge(b, a, 5);
    og.add_edge(a, d, 6);
    assert_eq!(og.node_count(), 4);
    assert_eq!(og.edge_count(), 7);

    assert!(og.find_edge(a, b).is_some());
    assert!(og.find_edge(d, a).is_some());
    assert!(og.find_edge(a, a).is_some());

    for edge in og.raw_edges().iter() {
        assert!(og.find_edge(edge.source(), edge.target()).is_some());
        assert!(og.find_edge(edge.target(), edge.source()).is_some());
    }

    assert_eq!(og.neighbors(b).collect::<Vec<_>>(), vec![a, c, a]);

    og.remove_node(a);
    assert_eq!(og.neighbors(b).collect::<Vec<_>>(), vec![c]);
    assert_eq!(og.node_count(), 3);
    assert_eq!(og.edge_count(), 1);
    assert!(og.find_edge(a, b).is_none());
    assert!(og.find_edge(d, a).is_none());
    assert!(og.find_edge(a, a).is_none());
    assert!(og.find_edge(b, c).is_some());

}

#[test]
fn dfs() {
    let mut gr = OGraph::new();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    // Z is disconnected.
    let _ = gr.add_node("Z");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);
    gr.add_edge(i, k, 2.);

    assert_eq!(DfsIter::new(&gr, h).count(), 4);

    assert_eq!(DfsIter::new(&Reversed(&gr), h).count(), 1);

    assert_eq!(DfsIter::new(&Reversed(&gr), k).count(), 3);

    assert_eq!(DfsIter::new(&gr, i).count(), 3);

    assert_eq!(DfsIter::new(&AsUndirected(&gr), i).count(), 4);
}

#[test]
fn bfs() {
    let mut gr = OGraph::new();
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    let k = gr.add_node("K");
    // Z is disconnected.
    let _ = gr.add_node("Z");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);
    gr.add_edge(i, k, 2.);

    assert_eq!(BfsIter::new(&gr, h).count(), 4);

    assert_eq!(BfsIter::new(&Reversed(&gr), h).count(), 1);

    assert_eq!(BfsIter::new(&Reversed(&gr), k).count(), 3);

    assert_eq!(BfsIter::new(&gr, i).count(), 3);

    assert_eq!(BfsIter::new(&AsUndirected(&gr), i).count(), 4);

    let mut bfs = Bfs::new(&gr, h);
    let nx = bfs.next(&gr);
    assert_eq!(nx, Some(h));

    let nx1 = bfs.next(&gr);
    assert!(nx1 == Some(i) || nx1 == Some(j));

    let nx2 = bfs.next(&gr);
    assert!(nx2 == Some(i) || nx2 == Some(j));
    assert!(nx1 != nx2);

    let nx = bfs.next(&gr);
    assert_eq!(nx, Some(k));
    assert_eq!(bfs.next(&gr), None);
}

#[test]
fn mst() {
    let mut gr = OGraph::<_,_>::new();
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    let d = gr.add_node("D");
    let e = gr.add_node("E");
    let f = gr.add_node("F");
    let g = gr.add_node("G");
    gr.add_edge(a, b, 7.0_f32);  // closure capture below doesn't work with default float type
    gr.add_edge(a, d, 5.);
    gr.add_edge(d, b, 9.);
    gr.add_edge(b, c, 8.);
    gr.add_edge(b, e, 7.);
    gr.add_edge(c, e, 5.);
    gr.add_edge(d, e, 15.);
    gr.add_edge(d, f, 6.);
    gr.add_edge(f, e, 8.);
    gr.add_edge(f, g, 11.);
    gr.add_edge(e, g, 9.);

    // add a disjoint part
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);

    let mst = min_spanning_tree(&gr);
    println!("MST is:\n{:?}", mst);
    assert!(mst.node_count() == gr.node_count());
    // |E| = |N| - 2  because there are two disconnected components.
    assert!(mst.edge_count() == gr.node_count() - 2);

    // check the exact edges are there
    assert!(mst.find_edge(a, b).is_some());
    assert!(mst.find_edge(a, d).is_some());
    assert!(mst.find_edge(b, e).is_some());
    assert!(mst.find_edge(e, c).is_some());
    assert!(mst.find_edge(e, g).is_some());
    assert!(mst.find_edge(d, f).is_some());

    assert!(mst.find_edge(h, i).is_some());
    assert!(mst.find_edge(i, j).is_some());

    assert!(mst.find_edge(d, b).is_none());
    assert!(mst.find_edge(b, c).is_none());

}

#[test]
fn selfloop() {
    let mut gr = OGraph::new();
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    gr.add_edge(a, b, 7.);
    gr.add_edge(c, a, 6.);
    let sed = gr.add_edge(a, a, 2.);

    assert!(gr.find_edge(a, b).is_some());
    assert!(gr.find_edge(b, a).is_none());
    assert!(gr.find_edge_undirected(b, a).is_some());
    assert!(gr.find_edge(a, a).is_some());
    println!("{:?}", gr);

    gr.remove_edge(sed);
    assert!(gr.find_edge(a, a).is_none());
    println!("{:?}", gr);
}

#[test]
fn cyclic() {
    let mut gr = OGraph::new();
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");

    assert!(!is_cyclic(&gr));
    gr.add_edge(a, b, 7.);
    gr.add_edge(c, a, 6.);
    assert!(!is_cyclic(&gr));
    {
        let e = gr.add_edge(a, a, 0.);
        assert!(is_cyclic(&gr));
        gr.remove_edge(e);
        assert!(!is_cyclic(&gr));
    }

    {
        let e = gr.add_edge(b, c, 0.);
        assert!(is_cyclic(&gr));
        gr.remove_edge(e);
        assert!(!is_cyclic(&gr));
    }

    let d = gr.add_node("D");
    let e = gr.add_node("E");
    gr.add_edge(b, d, 0.);
    gr.add_edge(d, e, 0.);
    assert!(!is_cyclic(&gr));
    gr.add_edge(c, e, 0.);
    assert!(is_cyclic(&gr));
}

#[test]
fn multi() {
    let mut gr = OGraph::new();
    let a = gr.add_node("a");
    let b = gr.add_node("b");
    gr.add_edge(a, b, ());
    gr.add_edge(a, b, ());
    assert_eq!(gr.edge_count(), 2);

}
#[test]
fn update_edge()
{
    {
        let mut gr = OGraph::new();
        let a = gr.add_node("a");
        let b = gr.add_node("b");
        let e = gr.update_edge(a, b, 1);
        let f = gr.update_edge(a, b, 2);
        let _ = gr.update_edge(b, a, 3);
        assert_eq!(gr.edge_count(), 2);
        assert_eq!(e, f);
        assert_eq!(*gr.edge_weight(f).unwrap(), 2);
    }

    {
        let mut gr = OGraph::new_undirected();
        let a = gr.add_node("a");
        let b = gr.add_node("b");
        let e = gr.update_edge(a, b, 1);
        let f = gr.update_edge(b, a, 2);
        assert_eq!(gr.edge_count(), 1);
        assert_eq!(e, f);
        assert_eq!(*gr.edge_weight(f).unwrap(), 2);
    }
}

#[test]
fn dijk() {
    let mut g = OGraph::new_undirected();
    let a = g.add_node("A");
    let b = g.add_node("B");
    let c = g.add_node("C");
    let d = g.add_node("D");
    let e = g.add_node("E");
    let f = g.add_node("F");
    g.add_edge(a, b, 7.0_f32);
    g.add_edge(c, a, 9.);
    g.add_edge(a, d, 14.);
    g.add_edge(b, c, 10.);
    g.add_edge(d, c, 2.);
    g.add_edge(d, e, 9.);
    g.add_edge(b, f, 15.);
    g.add_edge(c, f, 11.);
    g.add_edge(e, f, 6.);
    println!("{:?}", g);
    for no in BfsIter::new(&g, a) {
        println!("Visit {:?} = {:?}", no, g.node_weight(no));
    }

    let scores = dijkstra(&g, a, None, |gr, n| gr.edges(n).map(|(n, &e)| (n, e)));
    println!("Scores= {:?}", scores);
    assert_eq!(scores[c], 9.);
    assert_eq!(scores[e], 20.);
    assert_eq!(scores[f], 20.);

    let scores = dijkstra(&g, a, Some(c), |gr, n| gr.edges(n).map(|(n, &e)| (n, e)));
    assert_eq!(scores[c], 9.);
}

#[test]
fn without()
{
    let mut og = OGraph::new_undirected();
    let a = og.add_node(0);
    let b = og.add_node(1);
    let c = og.add_node(2);
    let d = og.add_node(3);
    let _ = og.add_edge(a, b, 0);
    let _ = og.add_edge(a, c, 1);
    let v: Vec<NodeIndex> = og.without_edges(Outgoing).collect();
    assert_eq!(v, vec![d]);

    let mut og = OGraph::new();
    let a = og.add_node(0);
    let b = og.add_node(1);
    let c = og.add_node(2);
    let d = og.add_node(3);
    let _ = og.add_edge(a, b, 0);
    let _ = og.add_edge(a, c, 1);
    let init: Vec<NodeIndex> = og.without_edges(Incoming).collect();
    let term: Vec<NodeIndex> = og.without_edges(Outgoing).collect();
    assert_eq!(init, vec![a, d]);
    assert_eq!(term, vec![b, c, d]);
}

#[test]
fn toposort() {
    let mut gr = OGraph::<_,_>::new();
    let a = gr.add_node("A");
    let b = gr.add_node("B");
    let c = gr.add_node("C");
    let d = gr.add_node("D");
    let e = gr.add_node("E");
    let f = gr.add_node("F");
    let g = gr.add_node("G");
    gr.add_edge(a, b, 7.0);
    gr.add_edge(a, d, 5.);
    gr.add_edge(d, b, 9.);
    gr.add_edge(b, c, 8.);
    gr.add_edge(b, e, 7.);
    gr.add_edge(c, e, 5.);
    gr.add_edge(d, e, 15.);
    gr.add_edge(d, f, 6.);
    gr.add_edge(f, e, 8.);
    gr.add_edge(f, g, 11.);
    gr.add_edge(e, g, 9.);

    // add a disjoint part
    let h = gr.add_node("H");
    let i = gr.add_node("I");
    let j = gr.add_node("J");
    gr.add_edge(h, i, 1.);
    gr.add_edge(h, j, 3.);
    gr.add_edge(i, j, 1.);

    let order = petgraph::ograph::toposort(&gr);
    println!("{:?}", order);
    assert_eq!(order.len(), gr.node_count());

    // check all the edges of the graph
    for edge in gr.raw_edges().iter() {
        let a = edge.source();
        let b = edge.target();
        let ai = order.iter().position(|x| *x == a);
        let bi = order.iter().position(|x| *x == b);
        println!("Check that {:?} is before {:?}", a, b);
        assert!(ai < bi);
    }
}
<|endoftext|>


<commit_before>use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::monitor::{MonitorHandle, VideoMode};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Handle;

impl Handle {
    pub fn hidpi_factor(&self) -> f64 {
        1.0
    }

    pub fn position(&self) -> PhysicalPosition {
        PhysicalPosition { x: 0.0, y: 0.0 }
    }

    pub fn name(&self) -> Option<String> {
        None
    }

    pub fn size(&self) -> PhysicalSize {
        PhysicalSize {
            width: 0.0,
            height: 0.0,
        }
    }

    pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
        std::iter::empty()
    }
}

#[derive(Derivative)]
#[derivative(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Mode;

impl Mode {
    pub fn size(&self) -> PhysicalSize {
        unimplemented!();
    }

    pub fn bit_depth(&self) -> u16 {
        unimplemented!();
    }

    pub fn refresh_rate(&self) -> u16 {
        32
    }

    pub fn monitor(&self) -> MonitorHandle {
        MonitorHandle { inner: Handle }
    }
}
<commit_msg>Remove usage of derivative<commit_after>use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::monitor::{MonitorHandle, VideoMode};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Handle;

impl Handle {
    pub fn hidpi_factor(&self) -> f64 {
        1.0
    }

    pub fn position(&self) -> PhysicalPosition {
        PhysicalPosition { x: 0.0, y: 0.0 }
    }

    pub fn name(&self) -> Option<String> {
        None
    }

    pub fn size(&self) -> PhysicalSize {
        PhysicalSize {
            width: 0.0,
            height: 0.0,
        }
    }

    pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
        std::iter::empty()
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Mode;

impl Mode {
    pub fn size(&self) -> PhysicalSize {
        unimplemented!();
    }

    pub fn bit_depth(&self) -> u16 {
        unimplemented!();
    }

    pub fn refresh_rate(&self) -> u16 {
        32
    }

    pub fn monitor(&self) -> MonitorHandle {
        MonitorHandle { inner: Handle }
    }
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::rc::Rc;
use syntax::ast;
use syntax::codemap::MacroBang;
use syntax::codemap::{CodeMap, Span, mk_sp, BytePos, ExpnInfo, NameAndSpan};
use syntax::codemap;
use syntax::diagnostic::{Emitter, RenderSpan, Level, mk_span_handler};
use syntax::diagnostic::mk_handler;
use syntax::ext::base::ExtCtxt;
use syntax::ext::expand::ExpansionConfig;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::parse::new_parse_sess_special_handler;
use syntax::print::pprust;

use builder::Builder;
use node;
use parser::Parser;

/// Tests if the source fails to be parsed by PT parser.
pub fn fails_to_parse(src: &str) {
  with_parsed_tts(src, |_, failed, pt| {
    assert!(unsafe{*failed} == true);
    assert!(pt.is_none());
  });
}

/// Tests if the source fails to be built by PT builder.
pub fn fails_to_build(src: &str) {
  with_parsed(src, |cx, failed, pt| {
    assert!(unsafe{*failed} == false);
    Builder::build(cx, pt);
  });
}

/// Yields an ExtCtxt, parser error state and parsed PT.
///
/// TODO(farcaller): get rid of that bool, it's broken.
pub fn with_parsed(src: &str,
    block: |&mut ExtCtxt, *mut bool, Rc<node::PlatformTree>|) {
  with_parsed_tts(src, |cx, failed, pt| {
    block(cx, failed, pt.unwrap());
  });
}

pub fn with_parsed_node(name: &str, src: &str, block: |Rc<node::Node>|) {
  with_parsed(src, |_, _, pt| {
    block(pt.get_by_path(name).unwrap());
  });
}

pub fn with_parsed_tts(src: &str, block: |&mut ExtCtxt, *mut bool, Option<Rc<node::PlatformTree>>|) {
  let mut failed = false;
  let failptr = &mut failed as *mut bool;
  let ce = box CustomEmmiter::new(failptr);
  let sh = mk_span_handler(mk_handler(ce), CodeMap::new());
  let parse_sess = new_parse_sess_special_handler(sh);
  let cfg = Vec::new();
  let ecfg = ExpansionConfig {
    crate_name: ("test").parse().unwrap(),
    deriving_hash_type_parameter: false,
    enable_quotes: true,
    recursion_limit: 10,
  };
  let mut cx = ExtCtxt::new(&parse_sess, cfg, ecfg);
  cx.bt_push(ExpnInfo {
    call_site: mk_sp(BytePos(0), BytePos(0)),
    callee: NameAndSpan {
      name: "platformtree".to_string(),
      format: MacroBang,
      span: None,
    },
  });
  let tts = cx.parse_tts(src.to_string());

  let pt = Parser::new(&mut cx, tts.as_slice()).parse_platformtree();

  block(&mut cx, failptr, pt);
}

struct CustomEmmiter {
  failed: *mut bool
}

impl CustomEmmiter {
  pub fn new(fp: *mut bool) -> CustomEmmiter {
    CustomEmmiter {
      failed: fp,
    }
  }
}

impl Emitter for CustomEmmiter {
  fn emit(&mut self, _: Option<(&CodeMap, Span)>, m: &str, _: Option<&str>,
      l: Level) {
    unsafe { *self.failed = true };
    println!("{} {}", l, m);
  }
  fn custom_emit(&mut self, _: &codemap::CodeMap, _: RenderSpan, _: &str,
      _: Level) {
    panic!();
  }
}

pub fn assert_equal_source(stmt: &ast::Stmt, src: &str) {
  let gen_src = pprust::stmt_to_string(stmt);
  println!("generated: {}", gen_src);
  println!("expected:  {}", src);

  let stripped_gen_src = gen_src.replace(" ", "").replace("\n", "");
  let stripped_src = src.replace(" ", "").replace("\n", "");

  assert!(stripped_gen_src == stripped_src);
}

pub fn assert_equal_items(stmt: &ast::Item, src: &str) {
  let gen_src = pprust::item_to_string(stmt);
  println!("generated: {}", gen_src);
  println!("expected:  {}", src);

  let stripped_gen_src = gen_src.replace(" ", "").replace("\n", "");
  let stripped_src = src.replace(" ", "").replace("\n", "");

  assert!(stripped_gen_src == stripped_src);
}
<commit_msg>impl Send for CustomEmitter<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::rc::Rc;
use syntax::ast;
use syntax::codemap::MacroBang;
use syntax::codemap::{CodeMap, Span, mk_sp, BytePos, ExpnInfo, NameAndSpan};
use syntax::codemap;
use syntax::diagnostic::{Emitter, RenderSpan, Level, mk_span_handler};
use syntax::diagnostic::mk_handler;
use syntax::ext::base::ExtCtxt;
use syntax::ext::expand::ExpansionConfig;
use syntax::ext::quote::rt::ExtParseUtils;
use syntax::parse::new_parse_sess_special_handler;
use syntax::print::pprust;

use builder::Builder;
use node;
use parser::Parser;

/// Tests if the source fails to be parsed by PT parser.
pub fn fails_to_parse(src: &str) {
  with_parsed_tts(src, |_, failed, pt| {
    assert!(unsafe{*failed} == true);
    assert!(pt.is_none());
  });
}

/// Tests if the source fails to be built by PT builder.
pub fn fails_to_build(src: &str) {
  with_parsed(src, |cx, failed, pt| {
    assert!(unsafe{*failed} == false);
    Builder::build(cx, pt);
  });
}

/// Yields an ExtCtxt, parser error state and parsed PT.
///
/// TODO(farcaller): get rid of that bool, it's broken.
pub fn with_parsed(src: &str,
    block: |&mut ExtCtxt, *mut bool, Rc<node::PlatformTree>|) {
  with_parsed_tts(src, |cx, failed, pt| {
    block(cx, failed, pt.unwrap());
  });
}

pub fn with_parsed_node(name: &str, src: &str, block: |Rc<node::Node>|) {
  with_parsed(src, |_, _, pt| {
    block(pt.get_by_path(name).unwrap());
  });
}

pub fn with_parsed_tts(src: &str, block: |&mut ExtCtxt, *mut bool, Option<Rc<node::PlatformTree>>|) {
  let mut failed = false;
  let failptr = &mut failed as *mut bool;
  let ce = box CustomEmmiter::new(failptr);
  let sh = mk_span_handler(mk_handler(ce), CodeMap::new());
  let parse_sess = new_parse_sess_special_handler(sh);
  let cfg = Vec::new();
  let ecfg = ExpansionConfig {
    crate_name: ("test").parse().unwrap(),
    deriving_hash_type_parameter: false,
    enable_quotes: true,
    recursion_limit: 10,
  };
  let mut cx = ExtCtxt::new(&parse_sess, cfg, ecfg);
  cx.bt_push(ExpnInfo {
    call_site: mk_sp(BytePos(0), BytePos(0)),
    callee: NameAndSpan {
      name: "platformtree".to_string(),
      format: MacroBang,
      span: None,
    },
  });
  let tts = cx.parse_tts(src.to_string());

  let pt = Parser::new(&mut cx, tts.as_slice()).parse_platformtree();

  block(&mut cx, failptr, pt);
}

struct CustomEmmiter {
  failed: *mut bool
}

impl CustomEmmiter {
  pub fn new(fp: *mut bool) -> CustomEmmiter {
    CustomEmmiter {
      failed: fp,
    }
  }
}

unsafe impl Send for CustomEmmiter {}

impl Emitter for CustomEmmiter {
  fn emit(&mut self, _: Option<(&CodeMap, Span)>, m: &str, _: Option<&str>,
      l: Level) {
    unsafe { *self.failed = true };
    println!("{} {}", l, m);
  }
  fn custom_emit(&mut self, _: &codemap::CodeMap, _: RenderSpan, _: &str,
      _: Level) {
    panic!();
  }
}

pub fn assert_equal_source(stmt: &ast::Stmt, src: &str) {
  let gen_src = pprust::stmt_to_string(stmt);
  println!("generated: {}", gen_src);
  println!("expected:  {}", src);

  let stripped_gen_src = gen_src.replace(" ", "").replace("\n", "");
  let stripped_src = src.replace(" ", "").replace("\n", "");

  assert!(stripped_gen_src == stripped_src);
}

pub fn assert_equal_items(stmt: &ast::Item, src: &str) {
  let gen_src = pprust::item_to_string(stmt);
  println!("generated: {}", gen_src);
  println!("expected:  {}", src);

  let stripped_gen_src = gen_src.replace(" ", "").replace("\n", "");
  let stripped_src = src.replace(" ", "").replace("\n", "");

  assert!(stripped_gen_src == stripped_src);
}
<|endoftext|>


<commit_before>#![cfg(feature = "serde")]

#[macro_use]
extern crate enum_map;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate serde_test;

use enum_map::EnumMap;

use serde_test::{assert_tokens, Token};

#[derive(Debug, EnumMap, Deserialize, Serialize)]
enum Example {
    A,
    B,
}

#[test]
fn serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_tokens(
        &map,
        &[
            Token::Map { len: Some(2) },
            Token::UnitVariant {
                name: "Example",
                variant: "A",
            },
            Token::I32(5),
            Token::UnitVariant {
                name: "Example",
                variant: "B",
            },
            Token::I32(10),
            Token::MapEnd,
        ],
    );
}

const JSON: &str = r#"{"A":5,"B":10}"#;

#[test]
fn json_serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_eq!(serde_json::to_string(&map).unwrap(), String::from(JSON));
}

#[test]
fn json_deserialization() {
    let example: EnumMap<Example, i32> = serde_json::from_str(JSON).unwrap();
    assert_eq!(example, enum_map! { Example::A => 5, Example::B => 10 });
}

#[test]
fn json_invalid_deserialization() {
    let example: Result<EnumMap<Example, i32>, _> = serde_json::from_str(r"{}");
    assert!(example.is_err());
}

#[test]
fn json_invalid_key() {
    let example: Result<EnumMap<Example, i32>, _> =
        serde_json::from_str(r#"{"a": 5, "b": 10, "c": 6}"#);
    assert!(example.is_err());
}
<commit_msg>Test invalid type with serde_json<commit_after>#![cfg(feature = "serde")]

#[macro_use]
extern crate enum_map;
#[macro_use]
extern crate serde;
extern crate serde_json;
extern crate serde_test;

use enum_map::EnumMap;

use serde_test::{assert_tokens, Token};

#[derive(Debug, EnumMap, Deserialize, Serialize)]
enum Example {
    A,
    B,
}

#[test]
fn serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_tokens(
        &map,
        &[
            Token::Map { len: Some(2) },
            Token::UnitVariant {
                name: "Example",
                variant: "A",
            },
            Token::I32(5),
            Token::UnitVariant {
                name: "Example",
                variant: "B",
            },
            Token::I32(10),
            Token::MapEnd,
        ],
    );
}

const JSON: &str = r#"{"A":5,"B":10}"#;

#[test]
fn json_serialization() {
    let map = enum_map! { Example::A => 5, Example::B => 10 };
    assert_eq!(serde_json::to_string(&map).unwrap(), String::from(JSON));
}

#[test]
fn json_deserialization() {
    let example: EnumMap<Example, i32> = serde_json::from_str(JSON).unwrap();
    assert_eq!(example, enum_map! { Example::A => 5, Example::B => 10 });
}

#[test]
fn json_invalid_deserialization() {
    let example: Result<EnumMap<Example, i32>, _> = serde_json::from_str(r"{}");
    assert!(example.is_err());
}

#[test]
fn json_invalid_type() {
    let example: Result<EnumMap<Example, i32>, _> = serde::json::from_str("4");
    assert!(example.is_err());
}

#[test]
fn json_invalid_key() {
    let example: Result<EnumMap<Example, i32>, _> =
        serde_json::from_str(r#"{"a": 5, "b": 10, "c": 6}"#);
    assert!(example.is_err());
}
<|endoftext|>