Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warnings on missing .create() #113

Merged
merged 3 commits into from
Mar 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ log = "0.4.6"
percent-encoding = "2.1.0"
assert-json-diff = "1.0.3"

[dev-dependencies]
env_logger = "*"
testing_logger = "0.1"

[features]
default = ["color"]
color = ["colored"]
15 changes: 12 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,9 @@ pub struct Mock {
expected_hits_at_least: Option<usize>,
expected_hits_at_most: Option<usize>,
is_remote: bool,

/// Used to warn of mocks missing a `.create()` call. See issue #112
created: bool,
}

impl Mock {
Expand All @@ -754,6 +757,7 @@ impl Mock {
expected_hits_at_least: None,
expected_hits_at_most: None,
is_remote: false,
created: false,
}
}

Expand Down Expand Up @@ -1064,20 +1068,21 @@ impl Mock {
/// let _m = mock("GET", "/").with_body("hello world").create();
/// ```
///
pub fn create(self) -> Self {
#[must_use]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this does what you intend. This ensures someone who calls create() uses the result (Self), but doesn't require that create() itself is called. And since the intended pattern is to bind the Mock to an unused variable (let _m = mock(...);) that satisfies the must_use requirement, so normal usage won't see this.

For example:

mock("GET", "/").with_status(200); // No warning
mock("GET", "/").with_status(200).create(); // Warning: must_use
let _m = mock("GET", "/").with_status(200); // No warning
let _m = mock("GET", "/").with_status(200).create(); // No warning

Arguably all the builder methods on Mock should be #[must_use], but it still won't ensure that .create() is called.

pub fn create(mut self) -> Self {
server::try_start();

// Ensures Mockito tests are run sequentially.
LOCAL_TEST_MUTEX.with(|_| {});

let mut state = server::STATE.lock().unwrap();

self.created = true;

let mut remote_mock = self.clone();
remote_mock.is_remote = true;
state.mocks.push(remote_mock);

debug!("Mock::create() called for {}", self);

self
}

Expand All @@ -1097,6 +1102,10 @@ impl Drop for Mock {
}

debug!("Mock::drop() called for {}", self);

if !self.created {
warn!("Missing .create() call on mock {}", self);
}
}
}
}
Expand Down
40 changes: 40 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1295,3 +1295,43 @@ fn test_default_headers() {
let (_, headers, _) = request("GET /", "");
assert_eq!(vec!["connection: close", "content-length: 0"], headers);
}

#[test]
fn test_missing_create_bad() {
testing_logger::setup();

let m = mock("GET", "/");
drop(m);

// Expecting one warning
testing_logger::validate(|captured_logs| {
let warnings = captured_logs
.iter()
.filter(|c| c.level == log::Level::Warn)
.collect::<Vec<&testing_logger::CapturedLog>>();

assert_eq!(warnings.len(), 1);
assert_eq!(
warnings[0].body,
"Missing .create() call on mock \r\nGET /\r\n"
);
assert_eq!(warnings[0].level, log::Level::Warn);
});
}

#[test]
fn test_missing_create_good() {
testing_logger::setup();

let m = mock("GET", "/").create();
drop(m);

// No warnings should occur
testing_logger::validate(|captured_logs| {
let warnings = captured_logs
.iter()
.filter(|c| c.level == log::Level::Warn)
.collect::<Vec<&testing_logger::CapturedLog>>();
assert_eq!(warnings.len(), 0);
});
}