2022-05-25 22:12:02

by Daniel Latypov

[permalink] [raw]
Subject: [RFC PATCH 0/4] kunit: more assertion reworking

This is a follow up to these three series:
https://lore.kernel.org/all/[email protected]/
https://lore.kernel.org/all/[email protected]/
https://lore.kernel.org/all/[email protected]/

The two goals of those series were
a) reduce the size of struct kunit_assert and friends.
(struct kunit_assert went from 48 => 8 bytes on UML.)
b) simplify the internal code, mostly by deleting macros

This series goes further
a) sizeof(struct kunit_assert) = 0 now
b) e.g. we delete another class of macros (KUNIT_INIT_*_ASSERT_STRUCT)

Note: this does change the function signature of
kunit_do_failed_assertion, so we'd need to update the rust wrapper in https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/kunit.rs
But otherwise, I don't think this series changes anything on the
rust-side.

Daniel Latypov (4):
rfc: kunit: remove format func from struct kunit_assert, get it to 0
bytes
rfc: kunit: rename base KUNIT_ASSERTION macro to _KUNIT_FAILED
rfc: kunit: eliminate KUNIT_INIT_*_ASSERT_STRUCT macros
kunit: delcare kunit_assert structs as const

include/kunit/assert.h | 74 ++-----------------------
include/kunit/test.h | 123 ++++++++++++++++++++++-------------------
lib/kunit/test.c | 7 ++-
3 files changed, 76 insertions(+), 128 deletions(-)


base-commit: e7eaffce47b7db72b077630dbe836f0c4132496d
--
2.36.1.124.g0e6072fb45-goog



2022-05-26 03:50:29

by Daniel Latypov

[permalink] [raw]
Subject: [RFC PATCH 3/4] rfc: kunit: eliminate KUNIT_INIT_*_ASSERT_STRUCT macros

These macros exist because passing an initializer list to other macros
is hard.

The goal of these macros is to generate a line like
struct $ASSERT_TYPE __assertion = $APPROPRIATE_INITIALIZER;
e.g.
struct kunit_unary_assertion __assertion = {
.condition = "foo()",
.expected_true = true
};

But the challenge is you can't pass `{.condition=..., .expect_true=...}`
as a macro argument, since the comma means you're actually passing two
arguments, `{.condition=...` and `.expect_true=....}`.
So we'd made custom macros for each different initializer-list shape.

But we can work around this with the following generic macro
#define KUNIT_INIT_ASSERT(initializers...) { initializers }

Signed-off-by: Daniel Latypov <[email protected]>
---
include/kunit/assert.h | 48 ------------------------------------------
include/kunit/test.h | 27 +++++++++++++-----------
2 files changed, 15 insertions(+), 60 deletions(-)

diff --git a/include/kunit/assert.h b/include/kunit/assert.h
index aab5b1147df9..c041cd9fb0d4 100644
--- a/include/kunit/assert.h
+++ b/include/kunit/assert.h
@@ -90,19 +90,6 @@ void kunit_unary_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream);

-/**
- * KUNIT_INIT_UNARY_ASSERT_STRUCT() - Initializes &struct kunit_unary_assert.
- * @cond: A string representation of the expression asserted true or false.
- * @expect_true: True if of type KUNIT_{EXPECT|ASSERT}_TRUE, false otherwise.
- *
- * Initializes a &struct kunit_unary_assert. Intended to be used in
- * KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
- */
-#define KUNIT_INIT_UNARY_ASSERT_STRUCT(cond, expect_true) { \
- .condition = cond, \
- .expected_true = expect_true \
-}
-
/**
* struct kunit_ptr_not_err_assert - An expectation/assertion that a pointer is
* not NULL and not a -errno.
@@ -123,20 +110,6 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream);

-/**
- * KUNIT_INIT_PTR_NOT_ERR_ASSERT_STRUCT() - Initializes a
- * &struct kunit_ptr_not_err_assert.
- * @txt: A string representation of the expression passed to the expectation.
- * @val: The actual evaluated pointer value of the expression.
- *
- * Initializes a &struct kunit_ptr_not_err_assert. Intended to be used in
- * KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
- */
-#define KUNIT_INIT_PTR_NOT_ERR_STRUCT(txt, val) { \
- .text = txt, \
- .value = val \
-}
-
/**
* struct kunit_binary_assert_text - holds strings for &struct
* kunit_binary_assert and friends to try and make the structs smaller.
@@ -173,27 +146,6 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
const struct va_format *message,
struct string_stream *stream);

-/**
- * KUNIT_INIT_BINARY_ASSERT_STRUCT() - Initializes a binary assert like
- * kunit_binary_assert, kunit_binary_ptr_assert, etc.
- *
- * @text_: Pointer to a kunit_binary_assert_text.
- * @left_val: The actual evaluated value of the expression in the left slot.
- * @right_val: The actual evaluated value of the expression in the right slot.
- *
- * Initializes a binary assert like kunit_binary_assert,
- * kunit_binary_ptr_assert, etc. This relies on these structs having the same
- * fields but with different types for left_val/right_val.
- * This is ultimately used by binary assertion macros like KUNIT_EXPECT_EQ, etc.
- */
-#define KUNIT_INIT_BINARY_ASSERT_STRUCT(text_, \
- left_val, \
- right_val) { \
- .text = text_, \
- .left_value = left_val, \
- .right_value = right_val \
-}
-
/**
* struct kunit_binary_ptr_assert - An expectation/assertion that compares two
* pointer values (for example, KUNIT_EXPECT_PTR_EQ(test, foo, bar)).
diff --git a/include/kunit/test.h b/include/kunit/test.h
index 4a7cb7e72660..e4b54f5d2731 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -551,21 +551,24 @@ void kunit_do_failed_assertion(struct kunit *test,
fmt, \
##__VA_ARGS__)

+/* Helper to safely pass around an initializer list to other macros. */
+#define KUNIT_INIT_ASSERT(initializers...) { initializers }
+
#define KUNIT_UNARY_ASSERTION(test, \
assert_type, \
- condition, \
- expected_true, \
+ condition_, \
+ expected_true_, \
fmt, \
...) \
do { \
- if (likely(!!(condition) == !!expected_true)) break; \
+ if (likely(!!(condition_) == !!expected_true_)) break; \
\
_KUNIT_FAILED(test, \
assert_type, \
kunit_unary_assert, \
kunit_unary_assert_format, \
- KUNIT_INIT_UNARY_ASSERT_STRUCT(#condition, \
- expected_true), \
+ KUNIT_INIT_ASSERT(.condition=#condition_, \
+ .expected_true=expected_true_), \
fmt, \
##__VA_ARGS__); \
} while(0)
@@ -624,9 +627,9 @@ do { \
assert_type, \
assert_class, \
format_func, \
- KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
- __left, \
- __right), \
+ KUNIT_INIT_ASSERT(.text = &__text, \
+ .left_value = __left, \
+ .right_value = __right), \
fmt, \
##__VA_ARGS__); \
} while (0)
@@ -684,9 +687,9 @@ do { \
assert_type, \
kunit_binary_str_assert, \
kunit_binary_str_assert_format, \
- KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
- __left, \
- __right), \
+ KUNIT_INIT_ASSERT(.text = &__text, \
+ .left_value = __left, \
+ .right_value = __right), \
fmt, \
##__VA_ARGS__); \
} while (0)
@@ -705,7 +708,7 @@ do { \
assert_type, \
kunit_ptr_not_err_assert, \
kunit_ptr_not_err_assert_format, \
- KUNIT_INIT_PTR_NOT_ERR_STRUCT(#ptr, __ptr), \
+ KUNIT_INIT_ASSERT(.text = #ptr, .value = __ptr), \
fmt, \
##__VA_ARGS__); \
} while (0)
--
2.36.1.124.g0e6072fb45-goog


2022-05-26 06:09:50

by Daniel Latypov

[permalink] [raw]
Subject: Re: [RFC PATCH 0/4] kunit: more assertion reworking

On Wed, May 25, 2022 at 8:56 AM Miguel Ojeda
<[email protected]> wrote:
>
> Hi Daniel,
>
> On Wed, May 25, 2022 at 5:44 PM Daniel Latypov <[email protected]> wrote:
> >
> > Note: this does change the function signature of
> > kunit_do_failed_assertion, so we'd need to update the rust wrapper in https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/kunit.rs
> > But otherwise, I don't think this series changes anything on the
> > rust-side.
>
> Thanks for the heads up! I can take care of that.

FYI This probably won't need to happen soon.
I'd mentioned the idea of patch #1, which changes
kunit_do_failed_assertion(), and Brendan didn't seem keen on it
before.

But the diff should be simple, e.g. just something like this:
@@ -38,9 +38,7 @@
});
static CONDITION: &'static $crate::str::CStr =
$crate::c_str!(stringify!($cond));
static ASSERTION: UnaryAssert =
UnaryAssert($crate::bindings::kunit_unary_assert {
- assert: $crate::bindings::kunit_assert {
- format: Some($crate::bindings::kunit_unary_assert_format),
- },
+ assert: $crate::bindings::kunit_assert {},
condition: CONDITION.as_char_ptr(),
expected_true: true,
});
@@ -67,6 +65,7 @@
core::ptr::addr_of!(LOCATION.0),
$crate::bindings::kunit_assert_type_KUNIT_ASSERTION,
core::ptr::addr_of!(ASSERTION.0.assert),
+ Some($crate::bindings::kunit_unary_assert_format),
core::ptr::null(),
);
}

The only tricky bit will be coordinating the changes :)

Daniel

2022-05-26 08:27:00

by Daniel Latypov

[permalink] [raw]
Subject: [RFC PATCH 2/4] rfc: kunit: rename base KUNIT_ASSERTION macro to _KUNIT_FAILED

Context:
Currently this macro's name, KUNIT_ASSERTION conflicts with the name of
an enum whose values are {KUNIT_EXPECTATION, KUNIT_ASSERTION}.

It's hard to think of a better name for the enum, so rename this macro.
It's also a bit strange that the macro might do nothing depending on the
boolean argument `pass`. Why not have callers check themselves?

This patch:
Moves the pass/fail checking into the callers of KUNIT_ASSERTION, so now
we only call it when the check has failed.
Then we rename the macro the _KUNIT_FAILED() to reflect the new
semantics.

Signed-off-by: Daniel Latypov <[email protected]>
---
include/kunit/test.h | 119 ++++++++++++++++++++++---------------------
1 file changed, 61 insertions(+), 58 deletions(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index 6730734a2216..4a7cb7e72660 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -512,30 +512,27 @@ void kunit_do_failed_assertion(struct kunit *test,
assert_format_t assert_format,
const char *fmt, ...);

-#define KUNIT_ASSERTION(test, assert_type, pass, assert_class, assert_format, INITIALIZER, fmt, ...) do { \
- if (unlikely(!(pass))) { \
- static const struct kunit_loc __loc = KUNIT_CURRENT_LOC; \
- struct assert_class __assertion = INITIALIZER; \
- kunit_do_failed_assertion(test, \
- &__loc, \
- assert_type, \
- &__assertion.assert, \
- assert_format, \
- fmt, \
- ##__VA_ARGS__); \
- } \
+#define _KUNIT_FAILED(test, assert_type, assert_class, assert_format, INITIALIZER, fmt, ...) do { \
+ static const struct kunit_loc __loc = KUNIT_CURRENT_LOC; \
+ struct assert_class __assertion = INITIALIZER; \
+ kunit_do_failed_assertion(test, \
+ &__loc, \
+ assert_type, \
+ &__assertion.assert, \
+ assert_format, \
+ fmt, \
+ ##__VA_ARGS__); \
} while (0)


#define KUNIT_FAIL_ASSERTION(test, assert_type, fmt, ...) \
- KUNIT_ASSERTION(test, \
- assert_type, \
- false, \
- kunit_fail_assert, \
- kunit_fail_assert_format, \
- {}, \
- fmt, \
- ##__VA_ARGS__)
+ _KUNIT_FAILED(test, \
+ assert_type, \
+ kunit_fail_assert, \
+ kunit_fail_assert_format, \
+ {}, \
+ fmt, \
+ ##__VA_ARGS__)

/**
* KUNIT_FAIL() - Always causes a test to fail when evaluated.
@@ -560,15 +557,18 @@ void kunit_do_failed_assertion(struct kunit *test,
expected_true, \
fmt, \
...) \
- KUNIT_ASSERTION(test, \
- assert_type, \
- !!(condition) == !!expected_true, \
- kunit_unary_assert, \
- kunit_unary_assert_format, \
- KUNIT_INIT_UNARY_ASSERT_STRUCT(#condition, \
- expected_true), \
- fmt, \
- ##__VA_ARGS__)
+do { \
+ if (likely(!!(condition) == !!expected_true)) break; \
+ \
+ _KUNIT_FAILED(test, \
+ assert_type, \
+ kunit_unary_assert, \
+ kunit_unary_assert_format, \
+ KUNIT_INIT_UNARY_ASSERT_STRUCT(#condition, \
+ expected_true), \
+ fmt, \
+ ##__VA_ARGS__); \
+} while(0)

#define KUNIT_TRUE_MSG_ASSERTION(test, assert_type, condition, fmt, ...) \
KUNIT_UNARY_ASSERTION(test, \
@@ -618,16 +618,17 @@ do { \
.right_text = #right, \
}; \
\
- KUNIT_ASSERTION(test, \
- assert_type, \
- __left op __right, \
- assert_class, \
- format_func, \
- KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
- __left, \
- __right), \
- fmt, \
- ##__VA_ARGS__); \
+ if (likely(__left op __right)) break; \
+ \
+ _KUNIT_FAILED(test, \
+ assert_type, \
+ assert_class, \
+ format_func, \
+ KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
+ __left, \
+ __right), \
+ fmt, \
+ ##__VA_ARGS__); \
} while (0)

#define KUNIT_BINARY_INT_ASSERTION(test, \
@@ -676,16 +677,18 @@ do { \
.right_text = #right, \
}; \
\
- KUNIT_ASSERTION(test, \
- assert_type, \
- strcmp(__left, __right) op 0, \
- kunit_binary_str_assert, \
- kunit_binary_str_assert_format, \
- KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
- __left, \
- __right), \
- fmt, \
- ##__VA_ARGS__); \
+ if (likely(strcmp(__left, __right) op 0)) break; \
+ \
+ \
+ _KUNIT_FAILED(test, \
+ assert_type, \
+ kunit_binary_str_assert, \
+ kunit_binary_str_assert_format, \
+ KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
+ __left, \
+ __right), \
+ fmt, \
+ ##__VA_ARGS__); \
} while (0)

#define KUNIT_PTR_NOT_ERR_OR_NULL_MSG_ASSERTION(test, \
@@ -696,15 +699,15 @@ do { \
do { \
const typeof(ptr) __ptr = (ptr); \
\
- KUNIT_ASSERTION(test, \
- assert_type, \
- !IS_ERR_OR_NULL(__ptr), \
- kunit_ptr_not_err_assert, \
- kunit_ptr_not_err_assert_format, \
- KUNIT_INIT_PTR_NOT_ERR_STRUCT(#ptr, \
- __ptr), \
- fmt, \
- ##__VA_ARGS__); \
+ if (likely(!IS_ERR_OR_NULL(__ptr))) break; \
+ \
+ _KUNIT_FAILED(test, \
+ assert_type, \
+ kunit_ptr_not_err_assert, \
+ kunit_ptr_not_err_assert_format, \
+ KUNIT_INIT_PTR_NOT_ERR_STRUCT(#ptr, __ptr), \
+ fmt, \
+ ##__VA_ARGS__); \
} while (0)

/**
--
2.36.1.124.g0e6072fb45-goog


2022-05-26 10:13:45

by Miguel Ojeda

[permalink] [raw]
Subject: Re: [RFC PATCH 0/4] kunit: more assertion reworking

Hi Daniel,

On Wed, May 25, 2022 at 5:44 PM Daniel Latypov <[email protected]> wrote:
>
> Note: this does change the function signature of
> kunit_do_failed_assertion, so we'd need to update the rust wrapper in https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/kunit.rs
> But otherwise, I don't think this series changes anything on the
> rust-side.

Thanks for the heads up! I can take care of that.

Cheers,
Miguel

2022-05-26 11:47:08

by Daniel Latypov

[permalink] [raw]
Subject: [RFC PATCH 4/4] kunit: delcare kunit_assert structs as const

Everywhere we use the assert structs now takes them via const*, as of
https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git/commit/?h=kunit&id=7466886b400b1904ce30fa311904849e314a2cf4

So now let's properly declare the structs as const as well.
---
include/kunit/test.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index e4b54f5d2731..fa5955c8b412 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -514,7 +514,7 @@ void kunit_do_failed_assertion(struct kunit *test,

#define _KUNIT_FAILED(test, assert_type, assert_class, assert_format, INITIALIZER, fmt, ...) do { \
static const struct kunit_loc __loc = KUNIT_CURRENT_LOC; \
- struct assert_class __assertion = INITIALIZER; \
+ const struct assert_class __assertion = INITIALIZER; \
kunit_do_failed_assertion(test, \
&__loc, \
assert_type, \
--
2.36.1.124.g0e6072fb45-goog