-
Notifications
You must be signed in to change notification settings - Fork 219
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: get last mock oracles params (#4789)
Resolves #4652 # Description This adds a new foreign call `get_mock_last_params` that can be used to configure mocked oracles. It returns the last parameters the mock was called with, or panics if it wasn't. Note that this doesn't play very nicely with the `times` feature, since e.g. if a mock is setup with `times(1)` it is then impossible to ever retrieve the last params, as the mock will be automatically cleared. There's a bunch of ways this could be handled, including keeping track of cleared mocks and llowing these queries over them. I didn't stress too much about this since we're only now starting to use the mocks, and I think it might be better to experiment more with them and get more feedback before worrying about having a nicer API. I also moved the mock oracle tests outside of `execution_success` into `noir_test_success`, and added a few simpler cases that I think also help illustrate how the mocks are supposed to be used (which I personally found quite useful). I considered adding tests for the scenarios in which the mocked oracle engine panics (e.g. if no mock matches the foreign call, or if requesting last params for a mock that was never called), but run into quite a lot of trouble getting this working and ultimately gave up. I did at least improve a misleading error message. --------- Co-authored-by: Tom French <tom@tomfren.ch>
- Loading branch information
1 parent
ce1e662
commit 1d96937
Showing
7 changed files
with
172 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,6 @@ | |
name = "mock_oracle" | ||
type = "bin" | ||
authors = [""] | ||
compiler_version = ">=0.23.0" | ||
|
||
[dependencies] | ||
[dependencies] |
Empty file.
130 changes: 130 additions & 0 deletions
130
test_programs/noir_test_success/mock_oracle/src/main.nr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
use dep::std::test::OracleMock; | ||
|
||
struct Point { | ||
x: Field, | ||
y: Field, | ||
} | ||
|
||
impl Eq for Point { | ||
fn eq(self, other: Point) -> bool { | ||
(self.x == other.x) & (self.y == other.y) | ||
} | ||
} | ||
|
||
#[oracle(void_field)] | ||
unconstrained fn void_field_oracle() -> Field {} | ||
|
||
unconstrained fn void_field() -> Field { | ||
void_field_oracle() | ||
} | ||
|
||
#[oracle(field_field)] | ||
unconstrained fn field_field_oracle(_x: Field) -> Field {} | ||
|
||
unconstrained fn field_field(x: Field) -> Field { | ||
field_field_oracle(x) | ||
} | ||
|
||
#[oracle(struct_field)] | ||
unconstrained fn struct_field_oracle(_point: Point, _array: [Field; 4]) -> Field {} | ||
|
||
unconstrained fn struct_field(point: Point, array: [Field; 4]) -> Field { | ||
struct_field_oracle(point, array) | ||
} | ||
|
||
#[test(should_fail)] | ||
fn test_mock_no_returns() { | ||
OracleMock::mock("void_field"); | ||
void_field(); // Some return value must be set | ||
} | ||
|
||
#[test] | ||
fn test_mock() { | ||
OracleMock::mock("void_field").returns(10); | ||
assert_eq(void_field(), 10); | ||
} | ||
|
||
#[test] | ||
fn test_multiple_mock() { | ||
let first_mock = OracleMock::mock("void_field").returns(10); | ||
OracleMock::mock("void_field").returns(42); | ||
|
||
// The mocks are searched for in creation order, so the first one prevents the second from being called. | ||
assert_eq(void_field(), 10); | ||
|
||
first_mock.clear(); | ||
assert_eq(void_field(), 42); | ||
} | ||
|
||
#[test] | ||
fn test_multiple_mock_times() { | ||
OracleMock::mock("void_field").returns(10).times(2); | ||
OracleMock::mock("void_field").returns(42); | ||
|
||
assert_eq(void_field(), 10); | ||
assert_eq(void_field(), 10); | ||
assert_eq(void_field(), 42); | ||
} | ||
|
||
#[test] | ||
fn test_mock_with_params() { | ||
OracleMock::mock("field_field").with_params((5,)).returns(10); | ||
assert_eq(field_field(5), 10); | ||
} | ||
|
||
#[test] | ||
fn test_multiple_mock_with_params() { | ||
OracleMock::mock("field_field").with_params((5,)).returns(10); | ||
OracleMock::mock("field_field").with_params((7,)).returns(14); | ||
|
||
assert_eq(field_field(5), 10); | ||
assert_eq(field_field(7), 14); | ||
} | ||
|
||
#[test] | ||
fn test_mock_last_params() { | ||
let mock = OracleMock::mock("field_field").returns(10); | ||
assert_eq(field_field(5), 10); | ||
|
||
assert_eq(mock.get_last_params(), 5); | ||
} | ||
|
||
#[test] | ||
fn test_mock_last_params_many_calls() { | ||
let mock = OracleMock::mock("field_field").returns(10); | ||
assert_eq(field_field(5), 10); | ||
assert_eq(field_field(7), 10); | ||
|
||
assert_eq(mock.get_last_params(), 7); | ||
} | ||
|
||
#[test] | ||
fn test_mock_struct_field() { | ||
// Combination of simpler test cases | ||
|
||
let array = [1, 2, 3, 4]; | ||
let another_array = [4, 3, 2, 1]; | ||
let point = Point { x: 14, y: 27 }; | ||
|
||
OracleMock::mock("struct_field").returns(42).times(2); | ||
let timeless_mock = OracleMock::mock("struct_field").returns(0); | ||
|
||
assert_eq(42, struct_field(point, array)); | ||
assert_eq(42, struct_field(point, array)); | ||
// The times(2) mock is now cleared | ||
|
||
assert_eq(0, struct_field(point, array)); | ||
|
||
let last_params: (Point, [Field; 4]) = timeless_mock.get_last_params(); | ||
assert_eq(last_params.0, point); | ||
assert_eq(last_params.1, array); | ||
|
||
// We clear the mock with no times() to allow other mocks to be callable | ||
timeless_mock.clear(); | ||
|
||
OracleMock::mock("struct_field").with_params((point, array)).returns(10); | ||
OracleMock::mock("struct_field").with_params((point, another_array)).returns(20); | ||
assert_eq(10, struct_field(point, array)); | ||
assert_eq(20, struct_field(point, another_array)); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters