Skip to content

Commit

Permalink
Support returning default values for methods returning references
Browse files Browse the repository at this point in the history
When the nightly feature is enabled, methods whose return values aren't
explicitly set will return a default value, if the type implements
Default.  This feature has now been extended to methods returning
references to types that implement Default.
  • Loading branch information
asomers committed Aug 17, 2019
1 parent ed7892b commit f298efe
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 62 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased] - ReleaseDate
### Added
### Changed
### Fixed

- Methods returning non-`'static` references (mutable or otherwise) will now
return a default value if no return value is set, if the output type
implements `Default` and the `nightly` feature is enabled. This more closely
matches existing behavior for methods returning non-reference types.
([#32](https://github.com/asomers/mockall/pull/32))

### Removed

## [0.3.0] - 10 August 2019
### Added

Expand Down
15 changes: 14 additions & 1 deletion mockall/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@
//!
//! With **nightly** enabled, you can omit the return value like this:
#![cfg_attr(feature = "nightly", doc = "```")]
#![cfg_attr(not(feature = "nightly"), doc = "```ignore")]
#![cfg_attr(not(feature = "nightly"), doc = "```should_panic")]
//! # use mockall::*;
//! #[automock]
//! trait Foo {
Expand Down Expand Up @@ -1169,6 +1169,7 @@ downcast!(dyn AnyExpectations);

#[doc(hidden)]
pub trait ReturnDefault<O> {
fn maybe_return_default() -> Option<O>;
fn return_default() -> O;
}

Expand All @@ -1179,18 +1180,30 @@ pub struct DefaultReturner<O: 'static>(PhantomData<O>);
::cfg_if::cfg_if! {
if #[cfg(feature = "nightly")] {
impl<O> ReturnDefault<O> for DefaultReturner<O> {
default fn maybe_return_default() -> Option<O> {
None
}

default fn return_default() -> O {
panic!("Can only return default values for types that impl std::Default");
}
}

impl<O: Default> ReturnDefault<O> for DefaultReturner<O> {
fn maybe_return_default() -> Option<O> {
Some(O::default())
}

fn return_default() -> O {
O::default()
}
}
} else {
impl<O> ReturnDefault<O> for DefaultReturner<O> {
fn maybe_return_default() -> Option<O> {
None
}

fn return_default() -> O {
panic!("Returning default values requires the \"nightly\" feature");
}
Expand Down
10 changes: 10 additions & 0 deletions mockall/tests/mock_return_mutable_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ mock! {
}
}

#[test]
#[cfg_attr(not(feature = "nightly"),
should_panic(expected = "Returning default values requires"))]
fn return_default() {
let mut mock = MockFoo::new();
mock.expect_foo();
let r = mock.foo(0);
assert_eq!(u32::default(), *r);
}

#[test]
fn return_var() {
let mut mock = MockFoo::new();
Expand Down
10 changes: 10 additions & 0 deletions mockall/tests/mock_return_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ fn return_const() {
assert_eq!(5, *mock.foo());
}

#[test]
#[cfg_attr(not(feature = "nightly"),
should_panic(expected = "Returning default values requires"))]
fn return_default() {
let mut mock = MockFoo::new();
mock.expect_foo();
let r = mock.foo();
assert_eq!(u32::default(), *r);
}

mod sequence {
use super::*;

Expand Down
3 changes: 2 additions & 1 deletion mockall/tests/mock_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,9 @@ fn return_const() {
assert_eq!(42, mock.foo(5));
}

#[cfg_attr(not(feature = "nightly"),
should_panic(expected = "Returning default values requires"))]
#[test]
#[cfg_attr(not(feature = "nightly"), ignore)]
fn return_default() {
let mut mock = MockFoo::new();
mock.expect_foo();
Expand Down
12 changes: 12 additions & 0 deletions mockall/tests/mock_struct_with_static_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ fn checkpoint() {
panic!("Shouldn't get here!");
}

// Until we get some kind of context for free functions, the return_default
// feature won't work if there are any other tests that mock the same function.
// https://github.com/asomers/mockall/issues/30
#[cfg_attr(not(feature = "nightly"),
should_panic(expected = "Returning default values requires"))]
#[test]
fn return_default() {
MockFoo::expect_baz();
let r = MockFoo::baz(5);
assert_eq!(u8::default(), r);
}

#[test]
fn returning() {
MockFoo::expect_bar()
Expand Down
Loading

0 comments on commit f298efe

Please sign in to comment.