Skip to content

Commit e2fc846

Browse files
committed
feat: implement "does not..." assertions for strings
1 parent 38c17a8 commit e2fc846

12 files changed

Lines changed: 1593 additions & 303 deletions

File tree

src/assertions.rs

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,6 +2234,13 @@ pub trait AssertErrorHasSource<'a, R> {
22342234
/// assert_that!(subject).starts_with('d');
22352235
/// assert_that!(subject).ends_with("t eum");
22362236
/// assert_that!(subject).ends_with('m');
2237+
///
2238+
/// assert_that!(subject).does_not_contain("pat");
2239+
/// assert_that!(subject).does_not_contain('k');
2240+
/// assert_that!(subject).does_not_start_with("omi");
2241+
/// assert_that!(subject).does_not_start_with('o');
2242+
/// assert_that!(subject).does_not_end_with("meum");
2243+
/// assert_that!(subject).does_not_end_with('u');
22372244
/// ```
22382245
pub trait AssertStringPattern<E> {
22392246
/// Verifies that a string contains a substring or character.
@@ -2251,6 +2258,21 @@ pub trait AssertStringPattern<E> {
22512258
#[track_caller]
22522259
fn contains(self, pattern: E) -> Self;
22532260

2261+
/// Verifies that a string does not contain a substring or character.
2262+
///
2263+
/// # Examples
2264+
///
2265+
/// ```
2266+
/// use asserting::prelude::*;
2267+
///
2268+
/// let subject = "consequat nihil sanctus commodo";
2269+
///
2270+
/// assert_that!(subject).does_not_contain("nixil");
2271+
/// assert_that!(subject).does_not_contain('v');
2272+
/// ```
2273+
#[track_caller]
2274+
fn does_not_contain(self, pattern: E) -> Self;
2275+
22542276
/// Verifies that a string starts with a substring or character.
22552277
///
22562278
/// # Examples
@@ -2266,6 +2288,21 @@ pub trait AssertStringPattern<E> {
22662288
#[track_caller]
22672289
fn starts_with(self, pattern: E) -> Self;
22682290

2291+
/// Verifies that a string does not start with a substring or character.
2292+
///
2293+
/// # Examples
2294+
///
2295+
/// ```
2296+
/// use asserting::prelude::*;
2297+
///
2298+
/// let subject = "ex nulla nostrud proident";
2299+
///
2300+
/// assert_that!(subject).does_not_start_with("nulla");
2301+
/// assert_that!(subject).does_not_start_with('v');
2302+
/// ```
2303+
#[track_caller]
2304+
fn does_not_start_with(self, pattern: E) -> Self;
2305+
22692306
/// Verifies that a string ends with a substring or character.
22702307
///
22712308
/// # Examples
@@ -2280,6 +2317,19 @@ pub trait AssertStringPattern<E> {
22802317
/// ```
22812318
#[track_caller]
22822319
fn ends_with(self, pattern: E) -> Self;
2320+
2321+
/// Verifies that a string does not end with a substring or character.
2322+
///
2323+
/// ```
2324+
/// use asserting::prelude::*;
2325+
///
2326+
/// let subject = "sunt lorem at duo";
2327+
///
2328+
/// assert_that!(subject).does_not_end_with("duos");
2329+
/// assert_that!(subject).does_not_end_with('v');
2330+
/// ```
2331+
#[track_caller]
2332+
fn does_not_end_with(self, pattern: E) -> Self;
22832333
}
22842334

22852335
/// Assert that a string contains any char from a collection of chars.
@@ -2294,9 +2344,14 @@ pub trait AssertStringPattern<E> {
22942344
/// assert_that!(subject).contains_any_of(['a', 'b', 'm', 'z']);
22952345
/// assert_that!(subject).contains_any_of(&['a', 'b', 'm', 'z']);
22962346
/// assert_that!(subject).contains_any_of(&['a', 'b', 'm', 'z'][..]);
2347+
///
2348+
/// assert_that!(subject).does_not_contain_any_of(['x', 'y', 'z']);
2349+
/// assert_that!(subject).does_not_contain_any_of(&['x', 'y', 'z']);
2350+
/// assert_that!(subject).does_not_contain_any_of(&['x', 'y', 'z'][..]);
22972351
/// ```
22982352
pub trait AssertStringContainsAnyOf<E> {
2299-
/// Verifies that a string contains any char from a collection of chars.
2353+
/// Verifies that a string contains any char from a collection of
2354+
/// characters.
23002355
///
23012356
/// # Examples
23022357
///
@@ -2310,7 +2365,24 @@ pub trait AssertStringContainsAnyOf<E> {
23102365
/// assert_that!(subject).contains_any_of(&['a', 'b', 'm', 'z'][..]);
23112366
/// ```
23122367
#[track_caller]
2313-
fn contains_any_of(self, pattern: E) -> Self;
2368+
fn contains_any_of(self, expected: E) -> Self;
2369+
2370+
/// Verifies that a string does not contain any char from a collection of
2371+
/// characters.
2372+
///
2373+
/// # Examples
2374+
///
2375+
/// ```
2376+
/// use asserting::prelude::*;
2377+
///
2378+
/// let subject = "sunt lorem at duo";
2379+
///
2380+
/// assert_that!(subject).does_not_contain_any_of(['v', 'w', 'x']);
2381+
/// assert_that!(subject).does_not_contain_any_of(&['v', 'w', 'x']);
2382+
/// assert_that!(subject).does_not_contain_any_of(&['v', 'w', 'x'][..]);
2383+
/// ```
2384+
#[track_caller]
2385+
fn does_not_contain_any_of(self, expected: E) -> Self;
23142386
}
23152387

23162388
/// Assert that a string matches a regex pattern.
@@ -2325,12 +2397,13 @@ pub trait AssertStringContainsAnyOf<E> {
23252397
/// use asserting::prelude::*;
23262398
///
23272399
/// assert_that("tation odio placerat in").matches(r"\b\w{8}\b");
2400+
/// assert_that("tation odio placerat in").does_not_match(r"^[A-Z0-9 ]+$");
23282401
/// # }
23292402
/// ```
23302403
#[cfg(feature = "regex")]
23312404
#[cfg_attr(docsrs, doc(cfg(feature = "regex")))]
23322405
pub trait AssertStringMatches {
2333-
/// Verifies that a string matches the given regex pattern.
2406+
/// Verifies that a string matches a regex pattern.
23342407
///
23352408
/// # Example
23362409
///
@@ -2344,8 +2417,35 @@ pub trait AssertStringMatches {
23442417
/// assert_that("tation odio placerat in").matches(r"\b\w{8}\b");
23452418
/// # }
23462419
/// ```
2420+
///
2421+
/// # Panics
2422+
///
2423+
/// This method panics if the given regex pattern is invalid or exceeds the
2424+
/// size limit.
23472425
#[track_caller]
23482426
fn matches(self, regex_pattern: &str) -> Self;
2427+
2428+
/// Verifies that a string does not match a regex pattern.
2429+
///
2430+
/// # Example
2431+
///
2432+
/// ```
2433+
/// # #[cfg(not(feature = "regex"))]
2434+
/// # fn main() {}
2435+
/// # #[cfg(feature = "regex")]
2436+
/// # fn main() {
2437+
/// use asserting::prelude::*;
2438+
///
2439+
/// assert_that("tation odio placerat in").does_not_match(r"^[A-Z0-9 ]+$");
2440+
/// # }
2441+
/// ```
2442+
///
2443+
/// # Panics
2444+
///
2445+
/// This method panics if the given regex pattern is invalid or exceeds the
2446+
/// size limit.
2447+
#[track_caller]
2448+
fn does_not_match(self, regex_pattern: &str) -> Self;
23492449
}
23502450

23512451
/// Assert that an iterator or collection contains the expected value.

src/char/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::assertions::AssertChar;
2-
use crate::colored::{mark_missing_substr, mark_unexpected_char};
2+
use crate::colored::{mark_missing_string, mark_unexpected_char};
33
use crate::expectations::{
44
IsAlphabetic, IsAlphanumeric, IsAscii, IsControlChar, IsDigit, IsLowerCase, IsUpperCase,
55
IsWhitespace,
@@ -100,7 +100,7 @@ impl Expectation<char> for IsLowerCase {
100100
("", actual.to_lowercase().to_string())
101101
};
102102
let marked_actual = mark_unexpected_char(*actual, format);
103-
let marked_expected = mark_missing_substr(&expected, format);
103+
let marked_expected = mark_missing_string(&expected, format);
104104
format!("expected {expression} to be {not}lowercase\n but was: {marked_actual}\n expected: {marked_expected}")
105105
}
106106
}
@@ -141,7 +141,7 @@ impl Expectation<char> for IsUpperCase {
141141
("", actual.to_uppercase().to_string())
142142
};
143143
let marked_actual = mark_unexpected_char(*actual, format);
144-
let marked_expected = mark_missing_substr(&expected, format);
144+
let marked_expected = mark_missing_string(&expected, format);
145145
format!("expected {expression} to be {not}uppercase\n but was: {marked_actual}\n expected: {marked_expected}")
146146
}
147147
}

0 commit comments

Comments
 (0)