summaryrefslogtreecommitdiff
path: root/common/mock/README.md
blob: df984c3314a34838d063e40064bf9e889b7abad6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# Common Mocks
This directory holds mock implementations for use in fuzzers and tests.

Each mock is given some friendly build name, like ROLLBACK or FP_SENSOR.
This name is defined in [common/mock/build.mk](build.mk) and referenced
from unit tests and fuzzers' `.mocklist` file.

## Creating a new mock

* Add the mock source to [common/mock](/common/mock) and the
  optional header file to [include/mock](/include/mock).
  Header files are only necessary if you want to expose additional
  [mock control](#mock-controls) functions/variables.
  See the [Design Patterns](#design-patterns) section
  for more detail on design patterns.
* Add an new entry in [common/mock/build.mk](build.mk)
  that is conditioned on your mock's name.

If a unit test or fuzzer requests this mock, the build system will
set the variable `HAS_MOCK_<BUILD_NAME>` to `y` at build time.
This variable is used to conditionally include the the mock source
in [common/mock/build.mk](build.mk).

Example line from [common/mock/build.mk](build.mk):

```make
# Mocks
mock-$(HAS_MOCK_ROLLBACK) += mock/rollback_mock.o
```

## Using a mock
Unit tests and fuzzers can request a particular mock by adding an entry to
their `.mocklist` file. The mocklist file is similar to a `.tasklist`
file, where it is named according to the test/fuzz's name followed by
`.mocklist`, like `fpsensor.mocklist`.
The mocklist file is optional, so you may need to create one.

Example `.mocklist`:

```c
/* Copyright 2019 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

 #define CONFIG_TEST_MOCK_LIST \
	MOCK(ROLLBACK)         \
	MOCK(FP_SENSOR)
```

If you need additional [mock control](#mock-controls) functionality,
you may need to include the mock's header file, which is prepended
with `mock/` in the include line.

For example, to control the return values of the rollback mock:

```c
#include "mock/rollback_mock.h"

void yourfunction() {
	mock_ctrl_rollback.get_secret_fail = true;
}
```

## Mock Controls
Mocks can change their behavior by exposing "mock controls".

We do this, most commonly, by exposing an additional global struct
per mock that acts as the settings for the mock implementation.
The mock user can then modify fields of the struct to change the mock's behavior.
For example, the `fp_sensor_init_return` field may control what value
the mocked `fp_sensor_init` function returns.

The declaration for these controls are specified in the mock's header file,
which resides in [include/mock](/include/mock).

## Design Patterns
* When creating mock controls, consider placing all your mock parameters in
  one externally facing struct, like in
  [fp_sensor_mock.h](/include/mock/fp_sensor_mock.h).
  The primary reason for this is to allow the mock to be easily used
  by a fuzzer (write random bytes into the struct with memcpy).
* When following the above pattern, please provide a macro for resetting
  default values for this struct, like in
  [fp_sensor_mock.h](/include/mock/fp_sensor_mock.h).
  This allows unit tests to quickly reset the mock state/parameters
  before each unrelated unit test.