diff options
| author | Gabriel Krisman Bertazi <krisman@collabora.co.uk> | 2019-04-25 13:56:01 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2019-04-25 13:56:01 -0400 |
| commit | f0d6cc00325b3887f9a9df7755acf85f52b23ff2 (patch) | |
| tree | a73e6ca7c911df9b2d0babb02ffe6b44bc108659 | |
| parent | 9d53690f0d4e5686e80f034ea584b7a822b356d3 (diff) | |
unicode: introduce test module for normalized utf8 implementation
This implements a in-kernel sanity test module for the utf8
normalization core. At probe time, it will run basic sequences through
the utf8n core, to identify problems will equivalent sequences and
normalization/casefold code. This is supposed to be useful for
regression testing when adding support for a new version of utf8 to
linux.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
| -rw-r--r-- | fs/unicode/Kconfig | 5 | ||||
| -rw-r--r-- | fs/unicode/Makefile | 1 | ||||
| -rw-r--r-- | fs/unicode/utf8-selftest.c | 320 |
3 files changed, 326 insertions, 0 deletions
diff --git a/fs/unicode/Kconfig b/fs/unicode/Kconfig index f41520f57dff..b560a879edf7 100644 --- a/fs/unicode/Kconfig +++ b/fs/unicode/Kconfig | |||
| @@ -6,3 +6,8 @@ config UNICODE | |||
| 6 | help | 6 | help |
| 7 | Say Y here to enable UTF-8 NFD normalization and NFD+CF casefolding | 7 | Say Y here to enable UTF-8 NFD normalization and NFD+CF casefolding |
| 8 | support. | 8 | support. |
| 9 | |||
| 10 | config UNICODE_NORMALIZATION_SELFTEST | ||
| 11 | tristate "Test UTF-8 normalization support" | ||
| 12 | depends on UNICODE | ||
| 13 | default n | ||
diff --git a/fs/unicode/Makefile b/fs/unicode/Makefile index bfb0360687df..671d31f83006 100644 --- a/fs/unicode/Makefile +++ b/fs/unicode/Makefile | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | ||
| 3 | obj-$(CONFIG_UNICODE) += unicode.o | 3 | obj-$(CONFIG_UNICODE) += unicode.o |
| 4 | obj-$(CONFIG_UNICODE_NORMALIZATION_SELFTEST) += utf8-selftest.o | ||
| 4 | 5 | ||
| 5 | unicode-y := utf8-norm.o utf8-core.o | 6 | unicode-y := utf8-norm.o utf8-core.o |
| 6 | 7 | ||
diff --git a/fs/unicode/utf8-selftest.c b/fs/unicode/utf8-selftest.c new file mode 100644 index 000000000000..492d934d5c1c --- /dev/null +++ b/fs/unicode/utf8-selftest.c | |||
| @@ -0,0 +1,320 @@ | |||
| 1 | /* | ||
| 2 | * Kernel module for testing utf-8 support. | ||
| 3 | * | ||
| 4 | * Copyright 2017 Collabora Ltd. | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/printk.h> | ||
| 20 | #include <linux/unicode.h> | ||
| 21 | #include <linux/dcache.h> | ||
| 22 | |||
| 23 | #include "utf8n.h" | ||
| 24 | |||
| 25 | unsigned int failed_tests; | ||
| 26 | unsigned int total_tests; | ||
| 27 | |||
| 28 | /* Tests will be based on this version. */ | ||
| 29 | #define latest_maj 11 | ||
| 30 | #define latest_min 0 | ||
| 31 | #define latest_rev 0 | ||
| 32 | |||
| 33 | #define _test(cond, func, line, fmt, ...) do { \ | ||
| 34 | total_tests++; \ | ||
| 35 | if (!cond) { \ | ||
| 36 | failed_tests++; \ | ||
| 37 | pr_err("test %s:%d Failed: %s%s", \ | ||
| 38 | func, line, #cond, (fmt?":":".")); \ | ||
| 39 | if (fmt) \ | ||
| 40 | pr_err(fmt, ##__VA_ARGS__); \ | ||
| 41 | } \ | ||
| 42 | } while (0) | ||
| 43 | #define test_f(cond, fmt, ...) _test(cond, __func__, __LINE__, fmt, ##__VA_ARGS__) | ||
| 44 | #define test(cond) _test(cond, __func__, __LINE__, "") | ||
| 45 | |||
| 46 | const static struct { | ||
| 47 | /* UTF-8 strings in this vector _must_ be NULL-terminated. */ | ||
| 48 | unsigned char str[10]; | ||
| 49 | unsigned char dec[10]; | ||
| 50 | } nfdi_test_data[] = { | ||
| 51 | /* Trivial sequence */ | ||
| 52 | { | ||
| 53 | /* "ABba" decomposes to itself */ | ||
| 54 | .str = "aBba", | ||
| 55 | .dec = "aBba", | ||
| 56 | }, | ||
| 57 | /* Simple equivalent sequences */ | ||
| 58 | { | ||
| 59 | /* 'VULGAR FRACTION ONE QUARTER' cannot decompose to | ||
| 60 | 'NUMBER 1' + 'FRACTION SLASH' + 'NUMBER 4' on | ||
| 61 | canonical decomposition */ | ||
| 62 | .str = {0xc2, 0xbc, 0x00}, | ||
| 63 | .dec = {0xc2, 0xbc, 0x00}, | ||
| 64 | }, | ||
| 65 | { | ||
| 66 | /* 'LATIN SMALL LETTER A WITH DIAERESIS' decomposes to | ||
| 67 | 'LETTER A' + 'COMBINING DIAERESIS' */ | ||
| 68 | .str = {0xc3, 0xa4, 0x00}, | ||
| 69 | .dec = {0x61, 0xcc, 0x88, 0x00}, | ||
| 70 | }, | ||
| 71 | { | ||
| 72 | /* 'LATIN SMALL LETTER LJ' can't decompose to | ||
| 73 | 'LETTER L' + 'LETTER J' on canonical decomposition */ | ||
| 74 | .str = {0xC7, 0x89, 0x00}, | ||
| 75 | .dec = {0xC7, 0x89, 0x00}, | ||
| 76 | }, | ||
| 77 | { | ||
| 78 | /* GREEK ANO TELEIA decomposes to MIDDLE DOT */ | ||
| 79 | .str = {0xCE, 0x87, 0x00}, | ||
| 80 | .dec = {0xC2, 0xB7, 0x00} | ||
| 81 | }, | ||
| 82 | /* Canonical ordering */ | ||
| 83 | { | ||
| 84 | /* A + 'COMBINING ACUTE ACCENT' + 'COMBINING OGONEK' decomposes | ||
| 85 | to A + 'COMBINING OGONEK' + 'COMBINING ACUTE ACCENT' */ | ||
| 86 | .str = {0x41, 0xcc, 0x81, 0xcc, 0xa8, 0x0}, | ||
| 87 | .dec = {0x41, 0xcc, 0xa8, 0xcc, 0x81, 0x0}, | ||
| 88 | }, | ||
| 89 | { | ||
| 90 | /* 'LATIN SMALL LETTER A WITH DIAERESIS' + 'COMBINING OGONEK' | ||
| 91 | decomposes to | ||
| 92 | 'LETTER A' + 'COMBINING OGONEK' + 'COMBINING DIAERESIS' */ | ||
| 93 | .str = {0xc3, 0xa4, 0xCC, 0xA8, 0x00}, | ||
| 94 | |||
| 95 | .dec = {0x61, 0xCC, 0xA8, 0xcc, 0x88, 0x00}, | ||
| 96 | }, | ||
| 97 | |||
| 98 | }; | ||
| 99 | |||
| 100 | const static struct { | ||
| 101 | /* UTF-8 strings in this vector _must_ be NULL-terminated. */ | ||
| 102 | unsigned char str[30]; | ||
| 103 | unsigned char ncf[30]; | ||
| 104 | } nfdicf_test_data[] = { | ||
| 105 | /* Trivial sequences */ | ||
| 106 | { | ||
| 107 | /* "ABba" folds to lowercase */ | ||
| 108 | .str = {0x41, 0x42, 0x62, 0x61, 0x00}, | ||
| 109 | .ncf = {0x61, 0x62, 0x62, 0x61, 0x00}, | ||
| 110 | }, | ||
| 111 | { | ||
| 112 | /* All ASCII folds to lower-case */ | ||
| 113 | .str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0.1", | ||
| 114 | .ncf = "abcdefghijklmnopqrstuvwxyz0.1", | ||
| 115 | }, | ||
| 116 | { | ||
| 117 | /* LATIN SMALL LETTER SHARP S folds to | ||
| 118 | LATIN SMALL LETTER S + LATIN SMALL LETTER S */ | ||
| 119 | .str = {0xc3, 0x9f, 0x00}, | ||
| 120 | .ncf = {0x73, 0x73, 0x00}, | ||
| 121 | }, | ||
| 122 | { | ||
| 123 | /* LATIN CAPITAL LETTER A WITH RING ABOVE folds to | ||
| 124 | LATIN SMALL LETTER A + COMBINING RING ABOVE */ | ||
| 125 | .str = {0xC3, 0x85, 0x00}, | ||
| 126 | .ncf = {0x61, 0xcc, 0x8a, 0x00}, | ||
| 127 | }, | ||
| 128 | /* Introduced by UTF-8.0.0. */ | ||
| 129 | /* Cherokee letters are interesting test-cases because they fold | ||
| 130 | to upper-case. Before 8.0.0, Cherokee lowercase were | ||
| 131 | undefined, thus, the folding from LC is not stable between | ||
| 132 | 7.0.0 -> 8.0.0, but it is from UC. */ | ||
| 133 | { | ||
| 134 | /* CHEROKEE SMALL LETTER A folds to CHEROKEE LETTER A */ | ||
| 135 | .str = {0xea, 0xad, 0xb0, 0x00}, | ||
| 136 | .ncf = {0xe1, 0x8e, 0xa0, 0x00}, | ||
| 137 | }, | ||
| 138 | { | ||
| 139 | /* CHEROKEE SMALL LETTER YE folds to CHEROKEE LETTER YE */ | ||
| 140 | .str = {0xe1, 0x8f, 0xb8, 0x00}, | ||
| 141 | .ncf = {0xe1, 0x8f, 0xb0, 0x00}, | ||
| 142 | }, | ||
| 143 | { | ||
| 144 | /* OLD HUNGARIAN CAPITAL LETTER AMB folds to | ||
| 145 | OLD HUNGARIAN SMALL LETTER AMB */ | ||
| 146 | .str = {0xf0, 0x90, 0xb2, 0x83, 0x00}, | ||
| 147 | .ncf = {0xf0, 0x90, 0xb3, 0x83, 0x00}, | ||
| 148 | }, | ||
| 149 | /* Introduced by UTF-9.0.0. */ | ||
| 150 | { | ||
| 151 | /* OSAGE CAPITAL LETTER CHA folds to | ||
| 152 | OSAGE SMALL LETTER CHA */ | ||
| 153 | .str = {0xf0, 0x90, 0x92, 0xb5, 0x00}, | ||
| 154 | .ncf = {0xf0, 0x90, 0x93, 0x9d, 0x00}, | ||
| 155 | }, | ||
| 156 | { | ||
| 157 | /* LATIN CAPITAL LETTER SMALL CAPITAL I folds to | ||
| 158 | LATIN LETTER SMALL CAPITAL I */ | ||
| 159 | .str = {0xea, 0x9e, 0xae, 0x00}, | ||
| 160 | .ncf = {0xc9, 0xaa, 0x00}, | ||
| 161 | }, | ||
| 162 | /* Introduced by UTF-11.0.0. */ | ||
| 163 | { | ||
| 164 | /* GEORGIAN SMALL LETTER AN folds to GEORGIAN MTAVRULI | ||
| 165 | CAPITAL LETTER AN */ | ||
| 166 | .str = {0xe1, 0xb2, 0x90, 0x00}, | ||
| 167 | .ncf = {0xe1, 0x83, 0x90, 0x00}, | ||
| 168 | } | ||
| 169 | }; | ||
| 170 | |||
| 171 | static void check_utf8_nfdi(void) | ||
| 172 | { | ||
| 173 | int i; | ||
| 174 | struct utf8cursor u8c; | ||
| 175 | const struct utf8data *data; | ||
| 176 | |||
| 177 | data = utf8nfdi(UNICODE_AGE(latest_maj, latest_min, latest_rev)); | ||
| 178 | if (!data) { | ||
| 179 | pr_err("%s: Unable to load utf8-%d.%d.%d. Skipping.\n", | ||
| 180 | __func__, latest_maj, latest_min, latest_rev); | ||
| 181 | return; | ||
| 182 | } | ||
| 183 | |||
