1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
// Copyright (C) 2023 Andreas Hartmann <hartan@7x.de>
// GNU General Public License v3.0+ (https://www.gnu.org/licenses/gpl-3.0.txt)
// SPDX-License-Identifier: GPL-3.0-or-later
//! Mockups for unit testing.
//!
//! At the moment only contains a [`Mock` env](Mock) implementation, used to simulate command
//! executions in unit tests with [`output_of()`](crate::environment::Environment::output_of).
use std::cell::RefCell;
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::Mutex;
use crate::environment::prelude::*;
use crate::environment::ExecutionError;
/// Mock environment.
///
/// Only available when running tests, implements the [`IsEnvironment`][crate::env::IsEnvironment]
/// trait to allow testing [`Provider`](crate::provider::Provider) implementations. Holds an
/// internal queue of "replies" to return, using the [`Mock::push_raw()`] and [`Mock::pop_raw()`]
/// functions. Replies are returned from [`pop_raw()`](Mock::pop_raw) in the exact order they were
/// pushed in.
#[derive(Debug, Serialize, Deserialize)]
pub struct Mock {
#[serde(skip)]
queue: Mutex<RefCell<VecDeque<Result<String, ExecutionError>>>>,
}
// I don't care about these, but they're needed due to the trait requirements on `IsEnvironment`.
impl PartialEq for Mock {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl Eq for Mock {}
impl PartialOrd for Mock {
fn partial_cmp(&self, _other: &Self) -> Option<std::cmp::Ordering> {
Some(std::cmp::Ordering::Equal)
}
}
impl Ord for Mock {
fn cmp(&self, _other: &Self) -> std::cmp::Ordering {
std::cmp::Ordering::Equal
}
}
impl Mock {
pub fn new() -> Self {
Mock {
queue: Mutex::new(RefCell::new(VecDeque::new())),
}
}
/// Push a raw result into the result queue.
pub fn push_raw(&self, entry: Result<String, ExecutionError>) {
self.queue.lock().unwrap().borrow_mut().push_back(entry);
}
/// Pop a raw result from the result queue.
pub fn pop_raw(&self) -> Result<String, ExecutionError> {
self.queue
.lock()
.unwrap()
.borrow_mut()
.pop_front()
.expect("requested more entries from mock env than were previously created")
}
/// Convert into an `Arc<Environment>`.
pub fn to_env(self) -> Arc<Environment> {
Arc::new(Environment::Mock(self))
}
}
impl fmt::Display for Mock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MOCK (test-only)")
}
}
impl environment::IsEnvironment for Mock {
type Err = std::convert::Infallible;
fn exists(&self) -> bool {
true
}
fn execute(&self, _command: CommandLine) -> Result<Command, Self::Err> {
// We just assume 'rustc' to be available on any system capable of running `cargo
// test`.
let mut cmd = Command::new("rustc");
cmd.arg("--version");
Ok(cmd)
}
}