Re: [PATCH] kunit: Cover 'assert.c' with tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Apr 27, 2024 at 6:04 PM Ivan Orlov <ivan.orlov0322@xxxxxxxxx> wrote:
>
> There are multiple assertion formatting functions in the `assert.c`
> file, which are not covered with tests yet. Implement the KUnit test
> for these functions.
>
> The test consists of 11 test cases for the following functions:
>
> 1) 'is_literal'
> 2) 'is_str_literal'
> 3) 'kunit_assert_prologue', test case for multiple assert types
> 4) 'kunit_assert_print_msg'
> 5) 'kunit_unary_assert_format'
> 6) 'kunit_ptr_not_err_assert_format'
> 7) 'kunit_binary_assert_format'
> 8) 'kunit_binary_ptr_assert_format'
> 9) 'kunit_binary_str_assert_format'
> 10) 'kunit_assert_hexdump'
> 11) 'kunit_mem_assert_format'
>
> The test aims at maximizing the branch coverage for the assertion
> formatting functions. As you can see, it covers some of the static
> helper functions as well, so we have to import the test source in the
> `assert.c` file in order to be able to call and validate them.
>
> Signed-off-by: Ivan Orlov <ivan.orlov0322@xxxxxxxxx>

Hello,

I'll give this a full review tomorrow. But with a quick glance and
test, this is looking good to me.

Tested-by: Rae Moar <rmoar@xxxxxxxxxx>

Thanks!
-Rae

> ---
>  lib/kunit/assert.c      |   4 +
>  lib/kunit/assert_test.c | 416 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 420 insertions(+)
>  create mode 100644 lib/kunit/assert_test.c
>
> diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
> index dd1d633d0fe2..ab68c6daf546 100644
> --- a/lib/kunit/assert.c
> +++ b/lib/kunit/assert.c
> @@ -270,3 +270,7 @@ void kunit_mem_assert_format(const struct kunit_assert *assert,
>         }
>  }
>  EXPORT_SYMBOL_GPL(kunit_mem_assert_format);
> +
> +#if IS_ENABLED(CONFIG_KUNIT_TEST)
> +#include "assert_test.c"
> +#endif
> diff --git a/lib/kunit/assert_test.c b/lib/kunit/assert_test.c
> new file mode 100644
> index 000000000000..d54841740761
> --- /dev/null
> +++ b/lib/kunit/assert_test.c
> @@ -0,0 +1,416 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * KUnit test for the assertion formatting functions.
> + * Author: Ivan Orlov <ivan.orlov0322@xxxxxxxxx>
> + */
> +#include <kunit/test.h>
> +
> +#define TEST_PTR_EXPECTED_BUF_SIZE 128
> +
> +static void kunit_test_is_literal(struct kunit *test)
> +{
> +       KUNIT_EXPECT_TRUE(test, is_literal("5", 5));
> +       KUNIT_EXPECT_TRUE(test, is_literal("0", 0));
> +       KUNIT_EXPECT_TRUE(test, is_literal("1234567890", 1234567890));
> +       KUNIT_EXPECT_TRUE(test, is_literal("-1234567890", -1234567890));
> +       KUNIT_EXPECT_FALSE(test, is_literal("05", 5));
> +       KUNIT_EXPECT_FALSE(test, is_literal("", 0));
> +       KUNIT_EXPECT_FALSE(test, is_literal("-0", 0));
> +       KUNIT_EXPECT_FALSE(test, is_literal("12#45", 1245));
> +}
> +
> +static void kunit_test_is_str_literal(struct kunit *test)
> +{
> +       KUNIT_EXPECT_TRUE(test, is_str_literal("\"Hello, World!\"", "Hello, World!"));
> +       KUNIT_EXPECT_TRUE(test, is_str_literal("\"\"", ""));
> +       KUNIT_EXPECT_TRUE(test, is_str_literal("\"\"\"", "\""));
> +       KUNIT_EXPECT_FALSE(test, is_str_literal("", ""));
> +       KUNIT_EXPECT_FALSE(test, is_str_literal("\"", "\""));
> +       KUNIT_EXPECT_FALSE(test, is_str_literal("\"Abacaba", "Abacaba"));
> +       KUNIT_EXPECT_FALSE(test, is_str_literal("Abacaba\"", "Abacaba"));
> +       KUNIT_EXPECT_FALSE(test, is_str_literal("\"Abacaba\"", "\"Abacaba\""));
> +}
> +
> +KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
> +
> +/* this function is used to get a "char *" string from the string stream and defer its cleanup  */
> +static char *get_str_from_stream(struct kunit *test, struct string_stream *stream)
> +{
> +       char *str = string_stream_get_string(stream);
> +
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str);
> +       kunit_add_action(test, kfree_wrapper, (void *)str);
> +
> +       return str;
> +}
> +
> +static void kunit_test_assert_prologue(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +       const struct kunit_loc location = {
> +               .file = "testfile.c",
> +               .line = 1337,
> +       };
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +       /* Test an expectation fail prologue */
> +       kunit_assert_prologue(&location, KUNIT_EXPECTATION, stream);
> +       KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream),
> +                          "EXPECTATION FAILED at testfile.c:1337\n");
> +
> +       /* Test an assertion fail prologue */
> +       string_stream_clear(stream);
> +       kunit_assert_prologue(&location, KUNIT_ASSERTION, stream);
> +       KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream),
> +                          "ASSERTION FAILED at testfile.c:1337\n");
> +}
> +
> +/*
> + * This function accepts an arbitrary count of parameters and generates a va_format struct,
> + * which can be used to validate kunit_assert_print_msg function
> + */
> +static void verify_assert_print_msg(struct kunit *test,
> +                                   struct string_stream *stream,
> +                                   char *expected, const char *format, ...)
> +{
> +       va_list list;
> +       const struct va_format vformat = {
> +               .fmt = format,
> +               .va = &list,
> +       };
> +
> +       va_start(list, format);
> +       string_stream_clear(stream);
> +       kunit_assert_print_msg(&vformat, stream);
> +       KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream), expected);
> +}
> +
> +static void kunit_test_assert_print_msg(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +       verify_assert_print_msg(test, stream, "\nTest", "Test");
> +       verify_assert_print_msg(test, stream, "\nAbacaba -123 234", "%s %d %u",
> +                               "Abacaba", -123, 234U);
> +       verify_assert_print_msg(test, stream, "", NULL);
> +}
> +
> +/*
> + * Further code contains the tests for different assert format functions.
> + * This helper function accepts the assert format function, executes it and
> + * validates the result string from the stream.
> + */
> +static void validate_assert(assert_format_t format_func, struct kunit *test,
> +                           const struct kunit_assert *assert,
> +                           const char *expected, struct string_stream *stream)
> +{
> +       struct va_format message = { NULL, NULL };
> +
> +       string_stream_clear(stream);
> +       format_func(assert, &message, stream);
> +       KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream), expected);
> +}
> +
> +static void kunit_test_unary_assert_format(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +       struct kunit_assert assert = {};
> +       struct kunit_unary_assert un_assert = {
> +               .assert = assert,
> +               .condition = "expr",
> +               .expected_true = true,
> +       };
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +       validate_assert(kunit_unary_assert_format, test, &un_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected expr to be true, but is false\n",
> +                       stream);
> +
> +       un_assert.expected_true = false;
> +       validate_assert(kunit_unary_assert_format, test, &un_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected expr to be false, but is true\n",
> +                       stream);
> +}
> +
> +static void kunit_test_ptr_not_err_assert_format(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +       struct kunit_assert assert = {};
> +       struct kunit_ptr_not_err_assert not_err_assert = {
> +               .assert = assert,
> +               .text = "expr",
> +               .value = NULL,
> +       };
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +       /* Value is NULL. The corresponding message should be printed out */
> +       validate_assert(kunit_ptr_not_err_assert_format, test,
> +                       &not_err_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected expr is not null, but is\n",
> +                       stream);
> +
> +       /* Value is not NULL, but looks like an error pointer. Error should be printed out */
> +       not_err_assert.value = (void *)-12;
> +       validate_assert(kunit_ptr_not_err_assert_format, test,
> +                       &not_err_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected expr is not error, but is: -12\n",
> +                       stream);
> +}
> +
> +static void kunit_test_binary_assert_format(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +       struct kunit_assert assert = {};
> +       struct kunit_binary_assert_text text = {
> +               .left_text = "1 + 2",
> +               .operation = "==",
> +               .right_text = "2",
> +       };
> +       const struct kunit_binary_assert binary_assert = {
> +               .assert = assert,
> +               .text = &text,
> +               .left_value = 3,
> +               .right_value = 2,
> +       };
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +       /*
> +        * the right argument is "literal" (see test for `is_literal` above),
> +        * so the right argument won't be printed out separately.
> +        */
> +       validate_assert(kunit_binary_assert_format, test, &binary_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected 1 + 2 == 2, but\n" KUNIT_SUBSUBTEST_INDENT
> +                       "1 + 2 == 3 (0x3)\n",
> +                       stream);
> +
> +       /* Now both arguments are not "literal". They both will be printed out separately  */
> +       text.right_text = "4 - 2";
> +       validate_assert(kunit_binary_assert_format, test, &binary_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected 1 + 2 == 4 - 2, but\n" KUNIT_SUBSUBTEST_INDENT
> +                       "1 + 2 == 3 (0x3)\n" KUNIT_SUBSUBTEST_INDENT
> +                       "4 - 2 == 2 (0x2)",
> +                       stream);
> +
> +       /* Now the left argument is "literal", so it won't be printed out */
> +       text.left_text = "3";
> +       validate_assert(kunit_binary_assert_format, test, &binary_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected 3 == 4 - 2, but\n" KUNIT_SUBSUBTEST_INDENT
> +                       "4 - 2 == 2 (0x2)",
> +                       stream);
> +
> +       /* The left and the right arguments are not "literal", so they won't be printed out */
> +       text.right_text = "2";
> +       validate_assert(kunit_binary_assert_format, test, &binary_assert.assert,
> +                       KUNIT_SUBTEST_INDENT "Expected 3 == 2, but\n", stream);
> +}
> +
> +static void kunit_test_binary_ptr_assert_format(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +       struct kunit_assert assert = {};
> +       char *expected;
> +       static const void *var_a = (void *)0xDEADBEEF;
> +       static const void *var_b = (void *)0xBADDCAFE;
> +       struct kunit_binary_assert_text text = {
> +               .left_text = "var_a",
> +               .operation = "==",
> +               .right_text = "var_b",
> +       };
> +       struct kunit_binary_ptr_assert binary_ptr_assert = {
> +               .assert = assert,
> +               .text = &text,
> +               .left_value = var_a,
> +               .right_value = var_b,
> +       };
> +
> +       expected = kunit_kzalloc(test, TEST_PTR_EXPECTED_BUF_SIZE, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected);
> +       /*
> +        * Print the expected string to the buffer first.
> +        * This is necessary as we may have different count of leading zeros in the pointer
> +        * on different architectures.
> +        */
> +       snprintf(expected, TEST_PTR_EXPECTED_BUF_SIZE,
> +                KUNIT_SUBTEST_INDENT
> +                "Expected var_a == var_b, but\n" KUNIT_SUBSUBTEST_INDENT
> +                "var_a == %px\n" KUNIT_SUBSUBTEST_INDENT "var_b == %px",
> +                var_a, var_b);
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +       validate_assert(kunit_binary_ptr_assert_format, test,
> +                       &binary_ptr_assert.assert, expected, stream);
> +}
> +
> +static void kunit_test_binary_str_assert_format(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +       struct kunit_assert assert = {};
> +       static const char *var_a = "abacaba";
> +       static const char *var_b = "kernel";
> +       struct kunit_binary_assert_text text = {
> +               .left_text = "var_a",
> +               .operation = "==",
> +               .right_text = "var_b",
> +       };
> +       struct kunit_binary_str_assert binary_str_assert = {
> +               .assert = assert,
> +               .text = &text,
> +               .left_value = var_a,
> +               .right_value = var_b,
> +       };
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +       /* Both arguments are not "string literals", so they should be printed separately */
> +       validate_assert(kunit_binary_str_assert_format, test,
> +                       &binary_str_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected var_a == var_b, but\n" KUNIT_SUBSUBTEST_INDENT
> +                       "var_a == \"abacaba\"\n" KUNIT_SUBSUBTEST_INDENT
> +                       "var_b == \"kernel\"",
> +                       stream);
> +
> +       /* Left argument is a "string literal", so it shouldn't be printed separately */
> +       text.left_text = "\"abacaba\"";
> +       validate_assert(kunit_binary_str_assert_format, test, &binary_str_assert.assert,
> +                       KUNIT_SUBTEST_INDENT "Expected \"abacaba\" == var_b, but\n"
> +                       KUNIT_SUBSUBTEST_INDENT "var_b == \"kernel\"", stream);
> +
> +       /* Both arguments are "string literals", so they shouldn't be printed separately */
> +       text.right_text = "\"kernel\"";
> +       validate_assert(kunit_binary_str_assert_format, test, &binary_str_assert.assert,
> +                       KUNIT_SUBTEST_INDENT "Expected \"abacaba\" == \"kernel\", but\n", stream);
> +}
> +
> +static const u8 hex_testbuf1[] = { 0x26, 0x74, 0x6b, 0x9c, 0x55,
> +                                  0x45, 0x9d, 0x47, 0xd6, 0x47,
> +                                  0x1,  0x89, 0x8c, 0x81, 0x94,
> +                                  0x12, 0xfe, 0x01 };
> +static const u8 hex_testbuf2[] = { 0x26, 0x74, 0x6b, 0x9c, 0x55,
> +                                  0x45, 0x9d, 0x47, 0x21, 0x47,
> +                                  0xcd, 0x89, 0x24, 0x50, 0x94,
> +                                  0x12, 0xba, 0x01 };
> +static void kunit_test_assert_hexdump(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +       /*
> +        * Check that we are getting numbers like <xx> on the right places.
> +        * Also check that we get a newline after 16 bytes
> +        */
> +       kunit_assert_hexdump(stream, hex_testbuf1, hex_testbuf2, sizeof(hex_testbuf1));
> +       KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream), KUNIT_SUBSUBTEST_INDENT
> +                          " 26  74  6b  9c  55  45  9d  47 <d6> 47 <01> 89 <8c><81> 94  12 \n"
> +                          KUNIT_SUBSUBTEST_INDENT "<fe> 01 ");
> +
> +       /*
> +        * We shouldn't get any <xx> numbers when comparing the buffer with itself.
> +        * We still should get a newline after 16 printed bytes
> +        */
> +       string_stream_clear(stream);
> +       kunit_assert_hexdump(stream, hex_testbuf1, hex_testbuf1, sizeof(hex_testbuf1));
> +       KUNIT_EXPECT_STREQ(test, get_str_from_stream(test, stream),
> +                          KUNIT_SUBSUBTEST_INDENT
> +                          " 26  74  6b  9c  55  45  9d  47  d6  47  01  89  8c  81  94  12 \n"
> +                          KUNIT_SUBSUBTEST_INDENT " fe  01 ");
> +}
> +
> +static void kunit_test_mem_assert_format(struct kunit *test)
> +{
> +       struct string_stream *stream;
> +       struct string_stream *expected_stream;
> +       struct kunit_assert assert = {};
> +       static const struct kunit_binary_assert_text text = {
> +               .left_text = "hex_testbuf1",
> +               .operation = "==",
> +               .right_text = "hex_testbuf2",
> +       };
> +       struct kunit_mem_assert mem_assert = {
> +               .assert = assert,
> +               .text = &text,
> +               .left_value = NULL,
> +               .right_value = hex_testbuf2,
> +               .size = sizeof(hex_testbuf1),
> +       };
> +
> +       expected_stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_stream);
> +       stream = kunit_alloc_string_stream(test, GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
> +
> +       /* The left value is NULL */
> +       validate_assert(kunit_mem_assert_format, test, &mem_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected hex_testbuf1 is not null, but is\n",
> +                       stream);
> +
> +       /* The right value is NULL, the left value is not NULL */
> +       mem_assert.left_value = hex_testbuf1;
> +       mem_assert.right_value = NULL;
> +       validate_assert(kunit_mem_assert_format, test, &mem_assert.assert,
> +                       KUNIT_SUBTEST_INDENT
> +                       "Expected hex_testbuf2 is not null, but is\n",
> +                       stream);
> +
> +       /* Both arguments are not null */
> +       mem_assert.left_value = hex_testbuf1;
> +       mem_assert.right_value = hex_testbuf2;
> +
> +       /*
> +        * Building the expected buffer.
> +        */
> +       string_stream_add(expected_stream,
> +                         KUNIT_SUBTEST_INDENT "Expected hex_testbuf1 == hex_testbuf2, but\n");
> +       string_stream_add(expected_stream, KUNIT_SUBSUBTEST_INDENT "hex_testbuf1 ==\n");
> +       kunit_assert_hexdump(expected_stream, hex_testbuf1, hex_testbuf2, mem_assert.size);
> +       string_stream_add(expected_stream,
> +                         "\n" KUNIT_SUBSUBTEST_INDENT "hex_testbuf2 ==\n");
> +       kunit_assert_hexdump(expected_stream, hex_testbuf2, hex_testbuf1, mem_assert.size);
> +
> +       validate_assert(kunit_mem_assert_format, test, &mem_assert.assert,
> +                       get_str_from_stream(test, expected_stream), stream);
> +}
> +
> +struct kunit_case assert_test_cases[] = {
> +       KUNIT_CASE(kunit_test_is_literal),
> +       KUNIT_CASE(kunit_test_is_str_literal),
> +       KUNIT_CASE(kunit_test_assert_prologue),
> +       KUNIT_CASE(kunit_test_assert_print_msg),
> +       KUNIT_CASE(kunit_test_unary_assert_format),
> +       KUNIT_CASE(kunit_test_ptr_not_err_assert_format),
> +       KUNIT_CASE(kunit_test_binary_assert_format),
> +       KUNIT_CASE(kunit_test_binary_ptr_assert_format),
> +       KUNIT_CASE(kunit_test_binary_str_assert_format),
> +       KUNIT_CASE(kunit_test_assert_hexdump),
> +       KUNIT_CASE(kunit_test_mem_assert_format),
> +       {}
> +};
> +
> +struct kunit_suite assert_test_suite = {
> +       .name = "kunit-assert",
> +       .test_cases = assert_test_cases,
> +};
> +
> +kunit_test_suites(&assert_test_suite);
> --
> 2.34.1
>





[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux