Add a single KUnit test case for the drm_mode_addfb2 function.

Signed-off-by: Carlos Eduardo Gallo Filho <gcar...@disroot.org>
---
 drivers/gpu/drm/tests/drm_framebuffer_test.c | 100 ++++++++++++++++++-
 1 file changed, 98 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/tests/drm_framebuffer_test.c 
b/drivers/gpu/drm/tests/drm_framebuffer_test.c
index 8eca92fdc645..b8ddd7e34db5 100644
--- a/drivers/gpu/drm/tests/drm_framebuffer_test.c
+++ b/drivers/gpu/drm/tests/drm_framebuffer_test.c
@@ -10,6 +10,7 @@
 #include <drm/drm_device.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_mode.h>
+#include <drm/drm_file.h>
 #include <drm/drm_framebuffer.h>
 #include <drm/drm_fourcc.h>
 #include <drm/drm_print.h>
@@ -343,8 +344,18 @@ static const struct drm_framebuffer_test 
drm_framebuffer_create_cases[] = {
 },
 };
 
+/*
+ * This struct is intended to provide a way to mocked functions communicate
+ * with the outer test when it can't be achieved by using its return value. In
+ * this way, the functions that receive the mocked drm_device, for example, can
+ * grab a reference to @private and actually return something to be used on 
some
+ * expectation. Also having the @test member allows doing expectations from
+ * inside mocked functions.
+ */
 struct drm_mock {
        struct drm_device dev;
+       struct drm_file file_priv;
+       struct kunit *test;
        void *private;
 };
 
@@ -366,13 +377,18 @@ static int drm_framebuffer_test_init(struct kunit *test)
 {
        struct drm_mock *mock;
        struct drm_device *dev;
+       struct drm_file *file_priv;
+       struct drm_driver *driver;
 
        mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
        KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
        dev = &mock->dev;
+       file_priv = &mock->file_priv;
 
-       dev->driver = kunit_kzalloc(test, sizeof(*dev->driver), GFP_KERNEL);
-       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev->driver);
+       driver = kunit_kzalloc(test, sizeof(*dev->driver), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, driver);
+       driver->driver_features = DRIVER_MODESET;
+       dev->driver = driver;
 
        idr_init_base(&dev->mode_config.object_idr, 1);
        mutex_init(&dev->mode_config.fb_lock);
@@ -384,6 +400,9 @@ static int drm_framebuffer_test_init(struct kunit *test)
        dev->mode_config.max_height = MAX_HEIGHT;
        dev->mode_config.funcs = &mock_config_funcs;
 
+       mutex_init(&file_priv->fbs_lock);
+       INIT_LIST_HEAD(&file_priv->fbs);
+
        test->priv = mock;
        return 0;
 }
@@ -392,8 +411,10 @@ static void drm_framebuffer_test_exit(struct kunit *test)
 {
        struct drm_mock *mock = test->priv;
        struct drm_device *dev = &mock->dev;
+       struct drm_file *file_priv = &mock->file_priv;
 
        mutex_destroy(&dev->mode_config.fb_lock);
+       mutex_destroy(&file_priv->fbs_lock);
 }
 
 static void drm_test_framebuffer_create(struct kunit *test)
@@ -656,7 +677,82 @@ static void drm_test_framebuffer_free(struct kunit *test)
        KUNIT_EXPECT_PTR_EQ(test, obj, NULL);
 }
 
+static struct drm_framebuffer *
+fb_create_addfb2_mock(struct drm_device *dev, struct drm_file *file_priv,
+                     const struct drm_mode_fb_cmd2 *cmd)
+{
+       struct drm_mock *mock = container_of(dev, typeof(*mock), dev);
+       struct drm_framebuffer *fb;
+       struct kunit *test = mock->test;
+
+       fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb);
+
+       fb->base.id = 1;
+
+       mock->private = fb;
+       return fb;
+}
+
+static struct drm_mode_config_funcs config_funcs_addfb2_mock = {
+       .fb_create = fb_create_addfb2_mock,
+};
+
+static void drm_test_framebuffer_addfb2(struct kunit *test)
+{
+       struct drm_mock *mock = test->priv;
+       struct drm_device *dev = &mock->dev;
+       struct drm_file *file_priv = &mock->file_priv;
+       struct drm_framebuffer *fb = NULL;
+       int ret;
+
+       /* A valid cmd */
+       struct drm_mode_fb_cmd2 cmd = {
+               .width = 600, .height = 600,
+               .pixel_format = DRM_FORMAT_ABGR8888,
+               .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
+       };
+
+       mock->test = test;
+       dev->mode_config.funcs = &config_funcs_addfb2_mock;
+
+       /* Must fail due to missing DRIVER_MODESET support */
+       ret = drm_mode_addfb2(dev, &cmd, file_priv);
+       KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP);
+       KUNIT_ASSERT_PTR_EQ(test, mock->private, NULL);
+
+       /* Set DRIVER_MODESET support */
+       dev->driver_features = dev->driver->driver_features;
+
+       /*
+        * Set an invalid cmd to trigger a fail on the
+        * drm_internal_framebuffer_create function
+        */
+       cmd.width = 0;
+       ret = drm_mode_addfb2(dev, &cmd, file_priv);
+       KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+       KUNIT_ASSERT_PTR_EQ(test, mock->private, NULL);
+       cmd.width = 600; /* restore to a valid value */
+
+       ret = drm_mode_addfb2(dev, &cmd, file_priv);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+
+       /* The fb_create_addfb2_mock set fb id to 1 */
+       KUNIT_EXPECT_EQ(test, cmd.fb_id, 1);
+
+       fb = mock->private;
+
+       /* The fb must be properly added to the file_priv->fbs list */
+       KUNIT_EXPECT_PTR_EQ(test, file_priv->fbs.prev, &fb->filp_head);
+       KUNIT_EXPECT_PTR_EQ(test, file_priv->fbs.next, &fb->filp_head);
+
+       /* There must be just one fb on the list */
+       KUNIT_EXPECT_PTR_EQ(test, fb->filp_head.prev, &file_priv->fbs);
+       KUNIT_EXPECT_PTR_EQ(test, fb->filp_head.next, &file_priv->fbs);
+}
+
 static struct kunit_case drm_framebuffer_tests[] = {
+       KUNIT_CASE(drm_test_framebuffer_addfb2),
        KUNIT_CASE(drm_test_framebuffer_cleanup),
        KUNIT_CASE(drm_test_framebuffer_free),
        KUNIT_CASE(drm_test_framebuffer_init),
-- 
2.41.0

Reply via email to