use std::sync::{Arc, Mutex};
use viewpoint_core::{Locator, Page};
use super::soft_locator::SoftLocatorAssertions;
use super::soft_page::SoftPageAssertions;
use super::{LocatorAssertions, PageAssertions};
use crate::error::TestError;
#[derive(Debug, Clone)]
pub struct SoftAssertionError {
pub assertion: String,
pub message: String,
pub expected: Option<String>,
pub actual: Option<String>,
}
impl SoftAssertionError {
pub fn new(assertion: impl Into<String>, message: impl Into<String>) -> Self {
Self {
assertion: assertion.into(),
message: message.into(),
expected: None,
actual: None,
}
}
#[must_use]
pub fn with_expected(mut self, expected: impl Into<String>) -> Self {
self.expected = Some(expected.into());
self
}
#[must_use]
pub fn with_actual(mut self, actual: impl Into<String>) -> Self {
self.actual = Some(actual.into());
self
}
}
impl std::fmt::Display for SoftAssertionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.assertion, self.message)?;
if let Some(ref expected) = self.expected {
write!(f, "\n Expected: {expected}")?;
}
if let Some(ref actual) = self.actual {
write!(f, "\n Actual: {actual}")?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct SoftAssertions {
errors: Arc<Mutex<Vec<SoftAssertionError>>>,
}
impl Default for SoftAssertions {
fn default() -> Self {
Self::new()
}
}
impl SoftAssertions {
pub fn new() -> Self {
Self {
errors: Arc::new(Mutex::new(Vec::new())),
}
}
pub fn expect<'a>(&self, locator: &'a Locator<'a>) -> SoftLocatorAssertions<'a> {
SoftLocatorAssertions {
assertions: LocatorAssertions::new(locator),
errors: self.errors.clone(),
}
}
pub fn expect_page<'a>(&self, page: &'a Page) -> SoftPageAssertions<'a> {
SoftPageAssertions {
assertions: PageAssertions::new(page),
errors: self.errors.clone(),
}
}
pub fn passed(&self) -> bool {
self.errors.lock().unwrap().is_empty()
}
pub fn errors(&self) -> Vec<SoftAssertionError> {
self.errors.lock().unwrap().clone()
}
pub fn failure_count(&self) -> usize {
self.errors.lock().unwrap().len()
}
pub fn clear(&self) {
self.errors.lock().unwrap().clear();
}
pub fn assert_all(&self) -> Result<(), TestError> {
let errors = self.errors.lock().unwrap();
if errors.is_empty() {
return Ok(());
}
let mut message = format!("{} soft assertion(s) failed:", errors.len());
for (i, error) in errors.iter().enumerate() {
message.push_str(&format!("\n{}. {}", i + 1, error));
}
Err(TestError::Assertion(crate::error::AssertionError::new(
message,
format!("{} assertions to pass", errors.len()),
format!("{} assertions failed", errors.len()),
)))
}
pub fn add_error(&self, error: SoftAssertionError) {
self.errors.lock().unwrap().push(error);
}
}