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