| // SPDX-License-Identifier: GPL-2.0-or-later | |
| /* | |
| * KUnit test for the assertion formatting functions. | |
| * Author: Ivan Orlov <ivan.orlov0322@gmail.com> | |
| */ | |
| #include <kunit/test.h> | |
| #include "string-stream.h" | |
| #define TEST_PTR_EXPECTED_BUF_SIZE 32 | |
| #define HEXDUMP_TEST_BUF_LEN 5 | |
| #define ASSERT_TEST_EXPECT_CONTAIN(test, str, substr) KUNIT_EXPECT_TRUE(test, strstr(str, substr)) | |
| #define ASSERT_TEST_EXPECT_NCONTAIN(test, str, substr) KUNIT_EXPECT_FALSE(test, strstr(str, substr)) | |
| 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; | |
| char *str; | |
| 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); | |
| str = get_str_from_stream(test, stream); | |
| ASSERT_TEST_EXPECT_CONTAIN(test, str, "EXPECTATION"); | |
| ASSERT_TEST_EXPECT_CONTAIN(test, str, "testfile.c"); | |
| ASSERT_TEST_EXPECT_CONTAIN(test, str, "1337"); | |
| /* Test an assertion fail prologue */ | |
| string_stream_clear(stream); | |
| kunit_assert_prologue(&location, KUNIT_ASSERTION, stream); | |
| str = get_str_from_stream(test, stream); | |
| ASSERT_TEST_EXPECT_CONTAIN(test, str, "ASSERTION"); | |
| ASSERT_TEST_EXPECT_CONTAIN(test, str, "testfile.c"); | |
| ASSERT_TEST_EXPECT_CONTAIN(test, str, "1337"); | |
| } | |
| /* | |
| * 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 by checking that all of the | |
| * substrings exist in the output. | |
| */ | |
| static void validate_assert(assert_format_t format_func, struct kunit *test, | |
| const struct kunit_assert *assert, | |
| struct string_stream *stream, int num_checks, ...) | |
| { | |
| size_t i; | |
| va_list checks; | |
| char *cur_substr_exp; | |
| struct va_format message = { NULL, NULL }; | |
| va_start(checks, num_checks); | |
| string_stream_clear(stream); | |
| format_func(assert, &message, stream); | |
| for (i = 0; i < num_checks; i++) { | |
| cur_substr_exp = va_arg(checks, char *); | |
| ASSERT_TEST_EXPECT_CONTAIN(test, get_str_from_stream(test, stream), cur_substr_exp); | |
| } | |
| } | |
| 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, | |
| stream, 2, "true", "is false"); | |
| un_assert.expected_true = false; | |
| validate_assert(kunit_unary_assert_format, test, &un_assert.assert, | |
| stream, 2, "false", "is true"); | |
| } | |
| 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, | |
| ¬_err_assert.assert, | |
| stream, 1, "null"); | |
| /* 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, | |
| ¬_err_assert.assert, stream, 2, | |
| "error", "-12"); | |
| } | |
| 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); | |
| /* | |
| * Printed values should depend on the input we provide: the left text, right text, left | |
| * value and the right value. | |
| */ | |
| validate_assert(kunit_binary_assert_format, test, &binary_assert.assert, | |
| stream, 4, "1 + 2", "2", "3", "=="); | |
| text.right_text = "4 - 2"; | |
| validate_assert(kunit_binary_assert_format, test, &binary_assert.assert, | |
| stream, 3, "==", "1 + 2", "4 - 2"); | |
| text.left_text = "3"; | |
| validate_assert(kunit_binary_assert_format, test, &binary_assert.assert, | |
| stream, 4, "3", "4 - 2", "2", "=="); | |
| text.right_text = "2"; | |
| validate_assert(kunit_binary_assert_format, test, &binary_assert.assert, | |
| stream, 3, "3", "2", "=="); | |
| } | |
| static void kunit_test_binary_ptr_assert_format(struct kunit *test) | |
| { | |
| struct string_stream *stream; | |
| struct kunit_assert assert = {}; | |
| char *addr_var_a, *addr_var_b; | |
| 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, | |
| }; | |
| addr_var_a = kunit_kzalloc(test, TEST_PTR_EXPECTED_BUF_SIZE, GFP_KERNEL); | |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, addr_var_a); | |
| addr_var_b = kunit_kzalloc(test, TEST_PTR_EXPECTED_BUF_SIZE, GFP_KERNEL); | |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, addr_var_b); | |
| /* | |
| * Print the addresses to the buffers first. | |
| * This is necessary as we may have different count of leading zeros in the pointer | |
| * on different architectures. | |
| */ | |
| snprintf(addr_var_a, TEST_PTR_EXPECTED_BUF_SIZE, "%px", var_a); | |
| snprintf(addr_var_b, TEST_PTR_EXPECTED_BUF_SIZE, "%px", 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, | |
| stream, 3, addr_var_a, addr_var_b, "=="); | |
| } | |
| 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); | |
| validate_assert(kunit_binary_str_assert_format, test, | |
| &binary_str_assert.assert, | |
| stream, 5, "var_a", "var_b", "\"abacaba\"", | |
| "\"kernel\"", "=="); | |
| text.left_text = "\"abacaba\""; | |
| validate_assert(kunit_binary_str_assert_format, test, &binary_str_assert.assert, | |
| stream, 4, "\"abacaba\"", "var_b", "\"kernel\"", "=="); | |
| text.right_text = "\"kernel\""; | |
| validate_assert(kunit_binary_str_assert_format, test, &binary_str_assert.assert, | |
| stream, 3, "\"abacaba\"", "\"kernel\"", "=="); | |
| } | |
| static const u8 hex_testbuf1[] = { 0x26, 0x74, 0x6b, 0x9c, 0x55, | |
| 0x45, 0x9d, 0x47, 0xd6, 0x47, | |
| 0x2, 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; | |
| char *str; | |
| size_t i; | |
| char buf[HEXDUMP_TEST_BUF_LEN]; | |
| stream = kunit_alloc_string_stream(test, GFP_KERNEL); | |
| KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); | |
| /* Check that we are getting output like <xx> for non-matching numbers. */ | |
| kunit_assert_hexdump(stream, hex_testbuf1, hex_testbuf2, sizeof(hex_testbuf1)); | |
| str = get_str_from_stream(test, stream); | |
| for (i = 0; i < sizeof(hex_testbuf1); i++) { | |
| snprintf(buf, HEXDUMP_TEST_BUF_LEN, "<%02x>", hex_testbuf1[i]); | |
| if (hex_testbuf1[i] != hex_testbuf2[i]) | |
| ASSERT_TEST_EXPECT_CONTAIN(test, str, buf); | |
| } | |
| /* We shouldn't get any <xx> numbers when comparing the buffer with itself. */ | |
| string_stream_clear(stream); | |
| kunit_assert_hexdump(stream, hex_testbuf1, hex_testbuf1, sizeof(hex_testbuf1)); | |
| str = get_str_from_stream(test, stream); | |
| ASSERT_TEST_EXPECT_NCONTAIN(test, str, "<"); | |
| ASSERT_TEST_EXPECT_NCONTAIN(test, str, ">"); | |
| } | |
| 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, | |
| stream, 2, "hex_testbuf1", "is not null"); | |
| /* 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, | |
| stream, 2, "hex_testbuf2", "is not null"); | |
| /* Both arguments are not null */ | |
| mem_assert.left_value = hex_testbuf1; | |
| mem_assert.right_value = hex_testbuf2; | |
| validate_assert(kunit_mem_assert_format, test, &mem_assert.assert, | |
| stream, 3, "hex_testbuf1", "hex_testbuf2", "=="); | |
| } | |
| static 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), | |
| {} | |
| }; | |
| static struct kunit_suite assert_test_suite = { | |
| .name = "kunit-assert", | |
| .test_cases = assert_test_cases, | |
| }; | |
| kunit_test_suites(&assert_test_suite); |