| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * KUnit test for the generic kernel FIFO implementation. |
| * |
| * Copyright (C) 2024 Diego Vieira <diego.daniel.professional@gmail.com> |
| */ |
| #include <kunit/test.h> |
| |
| #include <linux/kfifo.h> |
| |
| #define KFIFO_SIZE 32 |
| #define N_ELEMENTS 5 |
| |
| static void kfifo_test_reset_should_clear_the_fifo(struct kunit *test) |
| { |
| DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| kfifo_put(&my_fifo, 1); |
| kfifo_put(&my_fifo, 2); |
| kfifo_put(&my_fifo, 3); |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); |
| |
| kfifo_reset(&my_fifo); |
| |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); |
| KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo)); |
| } |
| |
| static void kfifo_test_define_should_define_an_empty_fifo(struct kunit *test) |
| { |
| DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo)); |
| KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo)); |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); |
| } |
| |
| static void kfifo_test_len_should_ret_n_of_stored_elements(struct kunit *test) |
| { |
| u8 buffer1[N_ELEMENTS]; |
| |
| for (int i = 0; i < N_ELEMENTS; i++) |
| buffer1[i] = i + 1; |
| |
| DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); |
| |
| kfifo_in(&my_fifo, buffer1, N_ELEMENTS); |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS); |
| |
| kfifo_in(&my_fifo, buffer1, N_ELEMENTS); |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS * 2); |
| |
| kfifo_reset(&my_fifo); |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); |
| } |
| |
| static void kfifo_test_put_should_insert_and_get_should_pop(struct kunit *test) |
| { |
| u8 out_data = 0; |
| int processed_elements; |
| u8 elements[] = { 3, 5, 11 }; |
| |
| DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| // If the fifo is empty, get returns 0 |
| processed_elements = kfifo_get(&my_fifo, &out_data); |
| KUNIT_EXPECT_EQ(test, processed_elements, 0); |
| KUNIT_EXPECT_EQ(test, out_data, 0); |
| |
| for (int i = 0; i < 3; i++) |
| kfifo_put(&my_fifo, elements[i]); |
| |
| for (int i = 0; i < 3; i++) { |
| processed_elements = kfifo_get(&my_fifo, &out_data); |
| KUNIT_EXPECT_EQ(test, processed_elements, 1); |
| KUNIT_EXPECT_EQ(test, out_data, elements[i]); |
| } |
| } |
| |
| static void kfifo_test_in_should_insert_multiple_elements(struct kunit *test) |
| { |
| u8 in_buffer[] = { 11, 25, 65 }; |
| u8 out_data; |
| int processed_elements; |
| |
| DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| kfifo_in(&my_fifo, in_buffer, 3); |
| |
| for (int i = 0; i < 3; i++) { |
| processed_elements = kfifo_get(&my_fifo, &out_data); |
| KUNIT_EXPECT_EQ(test, processed_elements, 1); |
| KUNIT_EXPECT_EQ(test, out_data, in_buffer[i]); |
| } |
| } |
| |
| static void kfifo_test_out_should_pop_multiple_elements(struct kunit *test) |
| { |
| u8 in_buffer[] = { 11, 25, 65 }; |
| u8 out_buffer[3]; |
| int copied_elements; |
| |
| DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| for (int i = 0; i < 3; i++) |
| kfifo_put(&my_fifo, in_buffer[i]); |
| |
| copied_elements = kfifo_out(&my_fifo, out_buffer, 3); |
| KUNIT_EXPECT_EQ(test, copied_elements, 3); |
| |
| for (int i = 0; i < 3; i++) |
| KUNIT_EXPECT_EQ(test, out_buffer[i], in_buffer[i]); |
| KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo)); |
| } |
| |
| static void kfifo_test_dec_init_should_define_an_empty_fifo(struct kunit *test) |
| { |
| DECLARE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| INIT_KFIFO(my_fifo); |
| |
| // my_fifo is a struct with an inplace buffer |
| KUNIT_EXPECT_FALSE(test, __is_kfifo_ptr(&my_fifo)); |
| |
| KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo)); |
| } |
| |
| static void kfifo_test_define_should_equal_declare_init(struct kunit *test) |
| { |
| // declare a variable my_fifo of type struct kfifo of u8 |
| DECLARE_KFIFO(my_fifo1, u8, KFIFO_SIZE); |
| // initialize the my_fifo variable |
| INIT_KFIFO(my_fifo1); |
| |
| // DEFINE_KFIFO declares the variable with the initial value |
| // essentially the same as calling DECLARE_KFIFO and INIT_KFIFO |
| DEFINE_KFIFO(my_fifo2, u8, KFIFO_SIZE); |
| |
| // my_fifo1 and my_fifo2 have the same size |
| KUNIT_EXPECT_EQ(test, sizeof(my_fifo1), sizeof(my_fifo2)); |
| KUNIT_EXPECT_EQ(test, kfifo_initialized(&my_fifo1), |
| kfifo_initialized(&my_fifo2)); |
| KUNIT_EXPECT_EQ(test, kfifo_is_empty(&my_fifo1), |
| kfifo_is_empty(&my_fifo2)); |
| } |
| |
| static void kfifo_test_alloc_should_initiliaze_a_ptr_fifo(struct kunit *test) |
| { |
| int ret; |
| DECLARE_KFIFO_PTR(my_fifo, u8); |
| |
| INIT_KFIFO(my_fifo); |
| |
| // kfifo_initialized returns false signaling the buffer pointer is NULL |
| KUNIT_EXPECT_FALSE(test, kfifo_initialized(&my_fifo)); |
| |
| // kfifo_alloc allocates the buffer |
| ret = kfifo_alloc(&my_fifo, KFIFO_SIZE, GFP_KERNEL); |
| KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Memory allocation should succeed"); |
| KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo)); |
| |
| // kfifo_free frees the buffer |
| kfifo_free(&my_fifo); |
| } |
| |
| static void kfifo_test_peek_should_not_remove_elements(struct kunit *test) |
| { |
| u8 out_data; |
| int processed_elements; |
| |
| DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); |
| |
| // If the fifo is empty, peek returns 0 |
| processed_elements = kfifo_peek(&my_fifo, &out_data); |
| KUNIT_EXPECT_EQ(test, processed_elements, 0); |
| |
| kfifo_put(&my_fifo, 3); |
| kfifo_put(&my_fifo, 5); |
| kfifo_put(&my_fifo, 11); |
| |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); |
| |
| processed_elements = kfifo_peek(&my_fifo, &out_data); |
| KUNIT_EXPECT_EQ(test, processed_elements, 1); |
| KUNIT_EXPECT_EQ(test, out_data, 3); |
| |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); |
| |
| // Using peek doesn't remove the element |
| // so the read element and the fifo length |
| // remains the same |
| processed_elements = kfifo_peek(&my_fifo, &out_data); |
| KUNIT_EXPECT_EQ(test, processed_elements, 1); |
| KUNIT_EXPECT_EQ(test, out_data, 3); |
| |
| KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); |
| } |
| |
| static struct kunit_case kfifo_test_cases[] = { |
| KUNIT_CASE(kfifo_test_reset_should_clear_the_fifo), |
| KUNIT_CASE(kfifo_test_define_should_define_an_empty_fifo), |
| KUNIT_CASE(kfifo_test_len_should_ret_n_of_stored_elements), |
| KUNIT_CASE(kfifo_test_put_should_insert_and_get_should_pop), |
| KUNIT_CASE(kfifo_test_in_should_insert_multiple_elements), |
| KUNIT_CASE(kfifo_test_out_should_pop_multiple_elements), |
| KUNIT_CASE(kfifo_test_dec_init_should_define_an_empty_fifo), |
| KUNIT_CASE(kfifo_test_define_should_equal_declare_init), |
| KUNIT_CASE(kfifo_test_alloc_should_initiliaze_a_ptr_fifo), |
| KUNIT_CASE(kfifo_test_peek_should_not_remove_elements), |
| {}, |
| }; |
| |
| static struct kunit_suite kfifo_test_module = { |
| .name = "kfifo", |
| .test_cases = kfifo_test_cases, |
| }; |
| |
| kunit_test_suites(&kfifo_test_module); |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_AUTHOR("Diego Vieira <diego.daniel.professional@gmail.com>"); |
| MODULE_DESCRIPTION("KUnit test for the kernel FIFO"); |