|
6 | 6 | //!
|
7 | 7 | //! Reference: <https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html>
|
8 | 8 |
|
| 9 | +use crate::task::Task; |
| 10 | +use core::ops::Deref; |
9 | 11 | use macros::kunit_tests;
|
10 | 12 |
|
11 | 13 | /// Asserts that a boolean expression is `true` at runtime.
|
@@ -183,11 +185,86 @@ macro_rules! kunit_unsafe_test_suite {
|
183 | 185 | };
|
184 | 186 | }
|
185 | 187 |
|
| 188 | +/// In some cases, you need to call test-only code from outside the test case, for example, to |
| 189 | +/// create a function mock. This function can be invoked to know whether we are currently running a |
| 190 | +/// KUnit test or not. |
| 191 | +/// |
| 192 | +/// # Examples |
| 193 | +/// |
| 194 | +/// This example shows how a function can be mocked to return a well-known value while testing: |
| 195 | +/// |
| 196 | +/// ``` |
| 197 | +/// # use kernel::kunit::in_kunit_test; |
| 198 | +/// # |
| 199 | +/// fn fn_mock_example(n: i32) -> i32 { |
| 200 | +/// if in_kunit_test() { |
| 201 | +/// 100 |
| 202 | +/// } else { |
| 203 | +/// n + 1 |
| 204 | +/// } |
| 205 | +/// } |
| 206 | +/// |
| 207 | +/// let mock_res = fn_mock_example(5); |
| 208 | +/// assert_eq!(mock_res, 100); |
| 209 | +/// ``` |
| 210 | +/// |
| 211 | +/// Sometimes, you don't control the code that needs to be mocked. This example shows how the |
| 212 | +/// `bindings` module can be mocked: |
| 213 | +/// |
| 214 | +/// ``` |
| 215 | +/// // Import our mock naming it as the real module. |
| 216 | +/// #[cfg(CONFIG_KUNIT)] |
| 217 | +/// use bindings_mock_example as bindings; |
| 218 | +/// |
| 219 | +/// // This module mocks `bindings`. |
| 220 | +/// mod bindings_mock_example { |
| 221 | +/// use kernel::kunit::in_kunit_test; |
| 222 | +/// use kernel::bindings::u64_; |
| 223 | +/// |
| 224 | +/// // Make the other binding functions available. |
| 225 | +/// pub(crate) use kernel::bindings::*; |
| 226 | +/// |
| 227 | +/// // Mock `ktime_get_boot_fast_ns` to return a well-known value when running a KUnit test. |
| 228 | +/// pub(crate) unsafe fn ktime_get_boot_fast_ns() -> u64_ { |
| 229 | +/// if in_kunit_test() { |
| 230 | +/// 1234 |
| 231 | +/// } else { |
| 232 | +/// unsafe { kernel::bindings::ktime_get_boot_fast_ns() } |
| 233 | +/// } |
| 234 | +/// } |
| 235 | +/// } |
| 236 | +/// |
| 237 | +/// // This is the function we want to test. Since `bindings` has been mocked, we can use its |
| 238 | +/// // functions seamlessly. |
| 239 | +/// fn get_boot_ns() -> u64 { |
| 240 | +/// unsafe { bindings::ktime_get_boot_fast_ns() } |
| 241 | +/// } |
| 242 | +/// |
| 243 | +/// let time = get_boot_ns(); |
| 244 | +/// assert_eq!(time, 1234); |
| 245 | +/// ``` |
| 246 | +pub fn in_kunit_test() -> bool { |
| 247 | + if cfg!(CONFIG_KUNIT) { |
| 248 | + let test = unsafe { (*Task::current().deref().0.get()).kunit_test }; |
| 249 | + !test.is_null() |
| 250 | + } else { |
| 251 | + false |
| 252 | + } |
| 253 | +} |
| 254 | + |
186 | 255 | #[kunit_tests(rust_kernel_kunit)]
|
187 | 256 | mod tests {
|
| 257 | + use super::*; |
| 258 | + |
188 | 259 | #[test]
|
189 | 260 | fn rust_test_kunit_kunit_tests() {
|
190 | 261 | let running = true;
|
191 | 262 | assert_eq!(running, true);
|
192 | 263 | }
|
| 264 | + |
| 265 | + #[test] |
| 266 | + fn rust_test_kunit_in_kunit_test() { |
| 267 | + let in_kunit = in_kunit_test(); |
| 268 | + assert_eq!(in_kunit, true); |
| 269 | + } |
193 | 270 | }
|
0 commit comments