# Unit Testing Aztec.nr Contracts
Contents:
* Rahul's High level thoughts on how a good unit test framework could look.
* Notes for noir team on bugs/feature requests
---
# Rahul's High level thoughts on how a good unit test framework could look.
*ignore this section. It is just my ramblings and notes*
I wrote unit tests within the contract scope. [Ref this file](https://github.com/AztecProtocol/aztec-packages/blob/b5a5a0b5e2f99992e5083d1d8044169961b0210e/yarn-project/noir-contracts/contracts/unit_test/src/main.nr)
**`beforeAll()`/`beforeEach()`/`afterEach`/`afterAll`**
* analyse all oracle calls being made by functions called in this block (e.g. constructor). **HOW?????**
* Is this really needed? To abstract away mocking the oracle calls? Or are we okay forcing devs to know about it. i think its fine for v1.
* Before all fns, call them
**normal test functions**:
* Wrappers around values coming from `priv_circ_pub_inputs` - example wrappers could be `getReturnValues()`, `getNewNullifiers()`, `getNewReadRequests()`...
* Add good cheatcodes to set `Private/PublicContextInputs` e.g. set msg.sender()
* Other forge based cheatcodes - setting public or private storage,...
* Good wrappers around oracle mocker:
* Create a dedicated struct for each aztec.nr oracle call
* only provide params that are needed
* easier mocking of return values - `storageWrite` requires hash values to provided that isn't used.
* easier mocking of return values - for oracles like `getNotes` which require 14+ values to be mocked:
```
let mut returnVal = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH];
returnVal[0] = 1; // return header - num_notes
returnVal[1] = this_address; // return header - contract_address
returnVal[2] = 1; // return header - nonce
returnVal[3] = 0; // return header - is_transient
returnVal[4] = note1.value1
returnVal[5] = note1.value2
....
OracleMock::mock("getNotes").withParams(...).returns(returnVal)
```
* Abstract away need to provide storage slots
* Working with nonce, sideEffectCounter feels like a footgun
## TODOs
* Write unit test for the uniswap portal fn and see how to improve
* Use Manas' debugger
* Integration tests: https://noir-lang.org/docs/dev/how_to/how-to-oracles/#step-2---write-an-rpc-server
---
# Notes for noir team on bugs/feature requests
This is really powerful and great! A lot of Aztec.nr is currently untested and as is, we can use it for testing! However, there are some inconsistencies/bugs/faeture requests that I have based on my hacking:
## Noir: Feature Requests
### Better failure errors:
```
let pub_circ_pub_inputs.return_values[0] = 11;
assert_eq(pub_circ_pub_inputs.return_values[0], 10);
```
this says `Failed to solve brillig function, reason: explicit trap hit in brillig`.
Proposed Improvement: `expected 10. got 11`
### Check how many times a mock was called.
Needed for checking that only x many storage slots were written or external function was only called x times. Current work around is mock.times(x) which can test if oracle was called more than x times, but not less than x times.
* setups like `beforeEach/beforeAll`
### Oracle mocker to mock some params but not others. Useful for various oracles like
a.
```
#[oracle(notifyCreatedNote)]
fn notify_created_note_oracle<N>(_storage_slot: Field, _serialized_note: [Field; N], _inner_note_hash: Field) -> Field {}
```
We can expect devs to know `_storage_slot` and `_serialized_note` but not `_inner_note_hash`
b. Or consider this oracle with so many parameters:
```
#[oracle(getNotes)]
fn get_notes_oracle<N, S>(
_storage_slot: Field,
_num_selects: u8,
_select_by: [u8; N],
_select_values: [Field; N],
_sort_by: [u8; N],
_sort_order: [u2; N],
_limit: u32,
_offset: u32,
_return_size: u32,
_placeholder_fields: [Field; S]
) -> [Field; S] {}
```
### ability to write tests outside of contract scope.
[Unsure how this changes with the contract keyword being removed]
e.g. in a new file. May require new type, `TestContract`. Depends on how we handle deprecation of the contract keyword...
## Noir: Bugs
1.
```
#[aztec(private)]
fn add_rand(b: Field) -> Field {
rand() + b
}
#[test]
unconstrained fn test_add_rand() {
OracleMock::mock("getRandomField").returns(3).times(1);
let priv_circ_pub_inputs = add_rand(PrivateContextInputs::empty(), 2);
assert(2.lt(priv_circ_pub_inputs.return_values[0]), "Is not less than!!");
}
```
Crashes. but if I change `times(2)` then works
2. Inconsistency if I am mocking 3+ oracles at once. E.g. [this doesn't work](https://github.com/AztecProtocol/aztec-packages/blob/4b973309cceb4da49f9364ceff4afa2532b01b6e/yarn-project/noir-contracts/contracts/unit_test/src/main.nr#L209-L212)
If I comment out the last Oracle Mocker (`enqueuePublicFunctionCall`, then the test works (just mocks `callPrivateFunction` but if I uncomment, then it says `callPrivateFunction` not mocked but it is with the expected params!)
---