Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-only
2 : /*
3 : * KUnit tests for the TTY null driver
4 : *
5 : * Tests for the ttynull driver covering basic lifecycle and sink behavior.
6 : * The ttynull driver acts as a data sink, discarding all written data
7 : * while providing minimal overhead for applications that need a TTY
8 : * but don't care about the output.
9 : *
10 : * Copyright (c) 2025 Abhinav Saxena <[email protected]>
11 : *
12 : */
13 :
14 : #include <kunit/test.h>
15 : #include <linux/tty.h>
16 : #include <linux/tty_driver.h>
17 : #include <linux/tty_flip.h>
18 : #include <linux/string.h>
19 :
20 : #include "tests/tty_test_helpers.h"
21 :
22 : /**
23 : * test_ttynull_write_sink - Verify ttynull acts as data sink
24 : * @test: KUnit test context
25 : *
26 : * ttynull should accept all write data and discard it silently.
27 : * This tests the core functionality of the null TTY driver.
28 : */
29 1 : static void test_ttynull_write_sink(struct kunit *test)
30 : {
31 1 : struct tty_driver *drv = ttynull_driver;
32 1 : struct tty_test_fixture *fx;
33 1 : const char *msg = "test data; discard me";
34 1 : unsigned int room;
35 1 : ssize_t write_result;
36 :
37 1 : fx = tty_test_create_fixture(test, drv, 0);
38 1 : KUNIT_ASSERT_NOT_NULL(test, fx);
39 :
40 1 : KUNIT_ASSERT_EQ(test, tty_test_open(fx), 0);
41 1 : KUNIT_ASSERT_TRUE(test, fx->opened);
42 :
43 : /* Verify TTY is properly initialized */
44 1 : KUNIT_EXPECT_NOT_NULL(test, fx->tty);
45 1 : KUNIT_EXPECT_NOT_NULL(test, fx->tty->ldisc);
46 1 : KUNIT_EXPECT_TRUE(test, !list_empty(&fx->tty->tty_files));
47 :
48 : /* Check initial write room - should be available */
49 1 : room = tty_test_get_write_room(fx);
50 1 : KUNIT_EXPECT_GT(test, room, 0U);
51 :
52 : /* Write data - should be completely accepted */
53 1 : KUNIT_ASSERT_EQ(test, tty_test_write_all(fx, msg, strlen(msg)), 0);
54 :
55 : /* ttynull discards writes; buffer should remain empty */
56 1 : KUNIT_EXPECT_EQ(test, tty_test_get_chars_in_buffer(fx), 0U);
57 :
58 : /* Write room should remain available for a sink */
59 1 : room = tty_test_get_write_room(fx);
60 1 : KUNIT_EXPECT_GT(test, room, 0U);
61 :
62 : /* ttynull should accept all data */
63 1 : write_result = tty_test_write(fx, msg, strlen(msg));
64 1 : KUNIT_EXPECT_EQ(test, write_result, strlen(msg));
65 :
66 : /* Multiple writes should all succeed */
67 1 : write_result = tty_test_write(fx, msg, strlen(msg));
68 1 : KUNIT_EXPECT_EQ(test, write_result, strlen(msg));
69 :
70 : /*
71 : * TODO: Simulate hangup condition making subsequent writes fail
72 : * For now, just release.
73 : */
74 1 : KUNIT_ASSERT_EQ(test, tty_test_release(fx), 0);
75 1 : }
76 :
77 : /**
78 : * test_ttynull_read_behavior - Verify read behavior on null device
79 : * @test: KUnit test context
80 : *
81 : * While ttynull technically supports read (via N_TTY), reading should
82 : * behave predictably (likely EOF or blocking).
83 : */
84 1 : static void test_ttynull_read_behavior(struct kunit *test)
85 : {
86 1 : struct tty_driver *drv = ttynull_driver;
87 1 : struct tty_test_fixture *fx;
88 1 : struct tty_ldisc *ld;
89 : /* char read_buffer[128]; */
90 : /* ssize_t bytes_read; */
91 :
92 1 : fx = tty_test_create_fixture(test, drv, 0);
93 1 : KUNIT_ASSERT_NOT_NULL(test, fx);
94 :
95 1 : KUNIT_ASSERT_EQ(test, tty_test_open(fx), 0);
96 1 : KUNIT_ASSERT_TRUE(test, fx->opened);
97 :
98 1 : ld = tty_ldisc_ref(fx->tty);
99 1 : KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ld);
100 1 : KUNIT_ASSERT_TRUE(test, ld->ops && ld->ops->read);
101 1 : tty_ldisc_deref(ld);
102 :
103 : /*
104 : * Reading from ttynull should behave consistently.
105 : * Depending on implementation, this might:
106 : * - Return 0 (EOF)
107 : * - Block (if no data available)
108 : * - Return -EAGAIN (if non-blocking)
109 : */
110 1 : KUNIT_ASSERT_NOT_NULL(test, fx->tty->disc_data);
111 : /* bytes_read = tty_test_read(fx, read_buffer, sizeof(read_buffer)); */
112 :
113 : /*
114 : * Document the expected behavior
115 : * - adjust based on actual ttynull implementation
116 : */
117 : /* KUNIT_EXPECT_GE(test, bytes_read, 0); /\* Should not return error *\/ */
118 :
119 1 : KUNIT_ASSERT_EQ(test, tty_test_release(fx), 0);
120 1 : }
121 :
122 : /**
123 : * test_ttynull_driver_properties - Verify driver characteristics
124 : * @test: KUnit test context
125 : *
126 : * Test the driver's static properties and configuration. Also, ensure that
127 : * it implements the required file_operation ops.
128 : */
129 1 : static void test_ttynull_driver_properties(struct kunit *test)
130 : {
131 1 : struct tty_driver *drv = ttynull_driver;
132 :
133 1 : KUNIT_ASSERT_NOT_NULL(test, drv);
134 :
135 : /* Verify driver identification */
136 1 : KUNIT_EXPECT_STREQ(test, drv->driver_name, "ttynull");
137 1 : KUNIT_EXPECT_STREQ(test, drv->name, "ttynull");
138 :
139 : /* Ensure that driver implements the required ops. */
140 1 : KUNIT_ASSERT_NOT_NULL(test, drv);
141 1 : tty_test_assert_valid_ops(test, drv);
142 :
143 : /* Verify driver type */
144 1 : KUNIT_EXPECT_EQ(test, drv->type, TTY_DRIVER_TYPE_CONSOLE);
145 :
146 : /* Verify driver flags */
147 1 : KUNIT_EXPECT_TRUE(test, drv->flags & TTY_DRIVER_REAL_RAW);
148 1 : KUNIT_EXPECT_TRUE(test, drv->flags & TTY_DRIVER_RESET_TERMIOS);
149 1 : }
150 :
151 : static struct kunit_case ttynull_test_cases[] = {
152 : KUNIT_CASE(test_ttynull_write_sink),
153 : KUNIT_CASE(test_ttynull_read_behavior),
154 : KUNIT_CASE(test_ttynull_driver_properties),
155 : {}
156 : };
157 :
158 : static struct kunit_suite ttynull_test_suite = {
159 : .name = "ttynull",
160 : .test_cases = ttynull_test_cases,
161 : };
162 :
163 : kunit_test_suite(ttynull_test_suite);
|