1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * KUnit tests for FAT filesystems. |
4 | * |
5 | * Copyright (C) 2020 Google LLC. |
6 | * Author: David Gow <davidgow@google.com> |
7 | */ |
8 | |
9 | #include <kunit/test.h> |
10 | |
11 | #include "fat.h" |
12 | |
13 | static void fat_checksum_test(struct kunit *test) |
14 | { |
15 | /* With no extension. */ |
16 | KUNIT_EXPECT_EQ(test, fat_checksum("VMLINUX " ), (u8)44); |
17 | /* With 3-letter extension. */ |
18 | KUNIT_EXPECT_EQ(test, fat_checksum("README TXT" ), (u8)115); |
19 | /* With short (1-letter) extension. */ |
20 | KUNIT_EXPECT_EQ(test, fat_checksum("ABCDEFGHA " ), (u8)98); |
21 | } |
22 | |
23 | struct fat_timestamp_testcase { |
24 | const char *name; |
25 | struct timespec64 ts; |
26 | __le16 time; |
27 | __le16 date; |
28 | u8 cs; |
29 | int time_offset; |
30 | }; |
31 | |
32 | static struct fat_timestamp_testcase time_test_cases[] = { |
33 | { |
34 | .name = "Earliest possible UTC (1980-01-01 00:00:00)" , |
35 | .ts = {.tv_sec = 315532800LL, .tv_nsec = 0L}, |
36 | .time = cpu_to_le16(0), |
37 | .date = cpu_to_le16(33), |
38 | .cs = 0, |
39 | .time_offset = 0, |
40 | }, |
41 | { |
42 | .name = "Latest possible UTC (2107-12-31 23:59:58)" , |
43 | .ts = {.tv_sec = 4354819198LL, .tv_nsec = 0L}, |
44 | .time = cpu_to_le16(49021), |
45 | .date = cpu_to_le16(65439), |
46 | .cs = 0, |
47 | .time_offset = 0, |
48 | }, |
49 | { |
50 | .name = "Earliest possible (UTC-11) (== 1979-12-31 13:00:00 UTC)" , |
51 | .ts = {.tv_sec = 315493200LL, .tv_nsec = 0L}, |
52 | .time = cpu_to_le16(0), |
53 | .date = cpu_to_le16(33), |
54 | .cs = 0, |
55 | .time_offset = 11 * 60, |
56 | }, |
57 | { |
58 | .name = "Latest possible (UTC+11) (== 2108-01-01 10:59:58 UTC)" , |
59 | .ts = {.tv_sec = 4354858798LL, .tv_nsec = 0L}, |
60 | .time = cpu_to_le16(49021), |
61 | .date = cpu_to_le16(65439), |
62 | .cs = 0, |
63 | .time_offset = -11 * 60, |
64 | }, |
65 | { |
66 | .name = "Leap Day / Year (1996-02-29 00:00:00)" , |
67 | .ts = {.tv_sec = 825552000LL, .tv_nsec = 0L}, |
68 | .time = cpu_to_le16(0), |
69 | .date = cpu_to_le16(8285), |
70 | .cs = 0, |
71 | .time_offset = 0, |
72 | }, |
73 | { |
74 | .name = "Year 2000 is leap year (2000-02-29 00:00:00)" , |
75 | .ts = {.tv_sec = 951782400LL, .tv_nsec = 0L}, |
76 | .time = cpu_to_le16(0), |
77 | .date = cpu_to_le16(10333), |
78 | .cs = 0, |
79 | .time_offset = 0, |
80 | }, |
81 | { |
82 | .name = "Year 2100 not leap year (2100-03-01 00:00:00)" , |
83 | .ts = {.tv_sec = 4107542400LL, .tv_nsec = 0L}, |
84 | .time = cpu_to_le16(0), |
85 | .date = cpu_to_le16(61537), |
86 | .cs = 0, |
87 | .time_offset = 0, |
88 | }, |
89 | { |
90 | .name = "Leap year + timezone UTC+1 (== 2004-02-29 00:30:00 UTC)" , |
91 | .ts = {.tv_sec = 1078014600LL, .tv_nsec = 0L}, |
92 | .time = cpu_to_le16(48064), |
93 | .date = cpu_to_le16(12380), |
94 | .cs = 0, |
95 | .time_offset = -60, |
96 | }, |
97 | { |
98 | .name = "Leap year + timezone UTC-1 (== 2004-02-29 23:30:00 UTC)" , |
99 | .ts = {.tv_sec = 1078097400LL, .tv_nsec = 0L}, |
100 | .time = cpu_to_le16(960), |
101 | .date = cpu_to_le16(12385), |
102 | .cs = 0, |
103 | .time_offset = 60, |
104 | }, |
105 | { |
106 | .name = "VFAT odd-second resolution (1999-12-31 23:59:59)" , |
107 | .ts = {.tv_sec = 946684799LL, .tv_nsec = 0L}, |
108 | .time = cpu_to_le16(49021), |
109 | .date = cpu_to_le16(10143), |
110 | .cs = 100, |
111 | .time_offset = 0, |
112 | }, |
113 | { |
114 | .name = "VFAT 10ms resolution (1980-01-01 00:00:00:0010)" , |
115 | .ts = {.tv_sec = 315532800LL, .tv_nsec = 10000000L}, |
116 | .time = cpu_to_le16(0), |
117 | .date = cpu_to_le16(33), |
118 | .cs = 1, |
119 | .time_offset = 0, |
120 | }, |
121 | }; |
122 | |
123 | static void time_testcase_desc(struct fat_timestamp_testcase *t, |
124 | char *desc) |
125 | { |
126 | strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); |
127 | } |
128 | |
129 | KUNIT_ARRAY_PARAM(fat_time, time_test_cases, time_testcase_desc); |
130 | |
131 | static void fat_time_fat2unix_test(struct kunit *test) |
132 | { |
133 | static struct msdos_sb_info fake_sb; |
134 | struct timespec64 ts; |
135 | struct fat_timestamp_testcase *testcase = |
136 | (struct fat_timestamp_testcase *)test->param_value; |
137 | |
138 | fake_sb.options.tz_set = 1; |
139 | fake_sb.options.time_offset = testcase->time_offset; |
140 | |
141 | fat_time_fat2unix(sbi: &fake_sb, ts: &ts, |
142 | time: testcase->time, |
143 | date: testcase->date, |
144 | time_cs: testcase->cs); |
145 | KUNIT_EXPECT_EQ_MSG(test, |
146 | testcase->ts.tv_sec, |
147 | ts.tv_sec, |
148 | "Timestamp mismatch (seconds)\n" ); |
149 | KUNIT_EXPECT_EQ_MSG(test, |
150 | testcase->ts.tv_nsec, |
151 | ts.tv_nsec, |
152 | "Timestamp mismatch (nanoseconds)\n" ); |
153 | } |
154 | |
155 | static void fat_time_unix2fat_test(struct kunit *test) |
156 | { |
157 | static struct msdos_sb_info fake_sb; |
158 | __le16 date, time; |
159 | u8 cs; |
160 | struct fat_timestamp_testcase *testcase = |
161 | (struct fat_timestamp_testcase *)test->param_value; |
162 | |
163 | fake_sb.options.tz_set = 1; |
164 | fake_sb.options.time_offset = testcase->time_offset; |
165 | |
166 | fat_time_unix2fat(sbi: &fake_sb, ts: &testcase->ts, |
167 | time: &time, date: &date, time_cs: &cs); |
168 | KUNIT_EXPECT_EQ_MSG(test, |
169 | le16_to_cpu(testcase->time), |
170 | le16_to_cpu(time), |
171 | "Time mismatch\n" ); |
172 | KUNIT_EXPECT_EQ_MSG(test, |
173 | le16_to_cpu(testcase->date), |
174 | le16_to_cpu(date), |
175 | "Date mismatch\n" ); |
176 | KUNIT_EXPECT_EQ_MSG(test, |
177 | testcase->cs, |
178 | cs, |
179 | "Centisecond mismatch\n" ); |
180 | } |
181 | |
182 | static struct kunit_case fat_test_cases[] = { |
183 | KUNIT_CASE(fat_checksum_test), |
184 | KUNIT_CASE_PARAM(fat_time_fat2unix_test, fat_time_gen_params), |
185 | KUNIT_CASE_PARAM(fat_time_unix2fat_test, fat_time_gen_params), |
186 | {}, |
187 | }; |
188 | |
189 | static struct kunit_suite fat_test_suite = { |
190 | .name = "fat_test" , |
191 | .test_cases = fat_test_cases, |
192 | }; |
193 | |
194 | kunit_test_suites(&fat_test_suite); |
195 | |
196 | MODULE_LICENSE("GPL v2" ); |
197 | |