Serenity Operating System
at master 253 lines 8.3 kB view raw
1/* 2 * Copyright (c) 2021, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibTest/TestCase.h> 8 9#include <AK/Array.h> 10#include <stdio.h> 11#include <string.h> 12 13typedef long double longdouble; 14typedef long long longlong; 15typedef unsigned long long unsignedlonglong; 16typedef unsigned long unsignedlong; 17typedef char charstar[32]; 18 19template<typename T> 20constexpr static Array<unsigned char, 32> to_value_t(T x) 21{ 22 // The endianness doesn't really matter, since we're going to convert both sides with this anyway. 23 union Value { 24 u8 v[32]; 25 T t; 26 }; 27 28 auto value = Value { .t = x }; 29 30 return { 31 value.v[0], 32 value.v[1], 33 value.v[2], 34 value.v[3], 35 value.v[4], 36 value.v[5], 37 value.v[6], 38 value.v[7], 39 value.v[8], 40 value.v[9], 41 value.v[10], 42 value.v[11], 43 value.v[12], 44 value.v[13], 45 value.v[14], 46 value.v[15], 47 value.v[16], 48 value.v[17], 49 value.v[18], 50 value.v[19], 51 value.v[20], 52 value.v[21], 53 value.v[22], 54 value.v[23], 55 value.v[24], 56 value.v[25], 57 value.v[26], 58 value.v[27], 59 value.v[28], 60 value.v[29], 61 value.v[30], 62 value.v[31], 63 }; 64} 65 66template<size_t N> 67constexpr static Array<unsigned char, 32> str_to_value_t(char const (&x)[N]) 68{ 69 Array<unsigned char, 32> value { 0 }; 70 for (size_t i = 0; i < N; ++i) 71 value[i] = x[i]; 72 return value; 73} 74 75struct Argument { 76 size_t size; 77 void* data; 78}; 79 80static Array<u8, 32> arg_to_value_t(Argument const& arg) 81{ 82 if (arg.size == 1) 83 return to_value_t(*(u8*)arg.data); 84 85 if (arg.size == 2) 86 return to_value_t(*(u16*)arg.data); 87 88 if (arg.size == 4) 89 return to_value_t(*(u32*)arg.data); 90 91 if (arg.size == 8) 92 return to_value_t(*(u64*)arg.data); 93 94 if (arg.size == 16) { 95 auto& data = *(charstar*)arg.data; 96 Array<unsigned char, 32> value { 0 }; 97 for (size_t i = 0; i < 16; ++i) 98 value[i] = data[i]; 99 return value; 100 } 101 102 if (arg.size == 32) { 103 auto& data = *(charstar*)arg.data; 104 auto length = strlen(data); 105 Array<unsigned char, 32> value { 0 }; 106 for (size_t i = 0; i < length; ++i) 107 value[i] = data[i]; 108 return value; 109 } 110 111 VERIFY_NOT_REACHED(); 112} 113 114#define DECL_WITH_TYPE(ty) \ 115 ty _##ty##arg0; \ 116 ty _##ty##arg1; \ 117 ty _##ty##arg2; \ 118 Argument ty##arg0 { sizeof(ty), &_##ty##arg0 }; \ 119 Argument ty##arg1 { sizeof(ty), &_##ty##arg1 }; \ 120 Argument ty##arg2 { sizeof(ty), &_##ty##arg2 }; 121 122DECL_WITH_TYPE(int); 123DECL_WITH_TYPE(unsigned); 124DECL_WITH_TYPE(long); 125DECL_WITH_TYPE(longlong); 126DECL_WITH_TYPE(float); 127DECL_WITH_TYPE(double); 128DECL_WITH_TYPE(longdouble); 129DECL_WITH_TYPE(unsignedlong); 130DECL_WITH_TYPE(unsignedlonglong); 131 132#undef DECL_WITH_TYPE 133 134charstar _charstararg0; 135charstar _charstararg1; 136charstar _charstararg2; 137Argument charstararg0 { sizeof(charstar), &_charstararg0[0] }; 138Argument charstararg1 { sizeof(charstar), &_charstararg1[0] }; 139Argument charstararg2 { sizeof(charstar), &_charstararg2[0] }; 140 141struct TestSuite { 142 char const* format; 143 char const* input; 144 int expected_return_value; 145 size_t argument_count; 146 Argument arguments[8]; 147 Array<unsigned char, 32> expected_values[8]; // 32 bytes for each argument's value. 148}; 149 150const TestSuite test_suites[] { 151 { "%d", "", 0, 0, {}, {} }, 152 { "%x", "0x519", 1, 1, { unsignedarg0 }, { to_value_t(0x519) } }, 153 { "%x", "0x51g", 1, 1, { unsignedarg0 }, { to_value_t(0x51u) } }, 154 { "%06x", "0xabcdef", 1, 1, { unsignedarg0 }, { to_value_t(0xabcdefu) } }, 155 { "%X", "0xCAFEBABE", 1, 1, { unsignedarg0 }, { to_value_t(0xcafebabe) } }, 156 { "%04X", "0x5E4E", 1, 1, { unsignedarg0 }, { to_value_t(0x5e4e) } }, 157 { "%X", "0x51Eg", 1, 1, { unsignedarg0 }, { to_value_t(0x51e) } }, 158 { "\"%%%d#", "\"%42#", 1, 1, { intarg0 }, { to_value_t(42) } }, 159 { " %d", "42", 1, 1, { intarg0 }, { to_value_t(42) } }, 160 { "%d", " 42", 1, 1, { intarg0 }, { to_value_t(42) } }, 161 { "%ld", "42", 1, 1, { longarg0 }, { to_value_t(42l) } }, 162 { "%lld", "42", 1, 1, { longlongarg0 }, { to_value_t(42ll) } }, 163 { "%f", "42", 1, 1, { floatarg0 }, { to_value_t(42.0f) } }, 164 { "%lf", "42", 1, 1, { doublearg0 }, { to_value_t(42.0) } }, 165 { "%s", "42", 1, 1, { charstararg0 }, { str_to_value_t("42") } }, 166 { "%d%s", "42yoinks", 2, 2, { intarg0, charstararg0 }, { to_value_t(42), str_to_value_t("yoinks") } }, 167 { "%[^\n]", "aaaa\n", 1, 1, { charstararg0 }, { str_to_value_t("aaaa") } }, 168 { "%u.%u.%u", "3.19", 2, 3, { unsignedarg0, unsignedarg1, unsignedarg2 }, { to_value_t(3u), to_value_t(19u) } }, 169 // Failing test case from previous impl: 170 { "SSH-%d.%d-%[^\n]\n", "SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.1\n", 3, 3, { intarg0, intarg1, charstararg0 }, { to_value_t(2), to_value_t(0), str_to_value_t("OpenSSH_8.2p1 Ubuntu-4ubuntu0.1") } }, 171 // GCC failure tests 172 { "%d.%d.%d", "10.2.0", 3, 3, { intarg0, intarg1, intarg2 }, { to_value_t(10), to_value_t(2), to_value_t(0) } }, 173 { "%lu", "3054 ", 1, 1, { unsignedlongarg0 }, { to_value_t(3054ul) } }, 174 // "actual" long long and unsigned long long, from #6096 175 // Note: '9223372036854775806' is the max value for 'long long'. 176 { "%lld", "9223372036854775805", 1, 1, { longlongarg0 }, { to_value_t(9223372036854775805LL) } }, 177 { "%llu", "9223372036854775810", 1, 1, { unsignedlonglongarg0 }, { to_value_t(9223372036854775810ULL) } }, 178 { "%n", "", 0, 1, { intarg0 }, { to_value_t(0) } }, 179 { "%d %n", "1 a", 1, 2, { intarg0, intarg1 }, { to_value_t(1), to_value_t(2) } }, 180 { "%*d", " 42", 0, 0, {}, {} }, 181 { "%d%*1[:/]%d", "24/7", 2, 2, { intarg0, intarg1 }, { to_value_t(24), to_value_t(7) } }, 182 { " %[^a]", " b", 1, 1, { charstararg0 }, { str_to_value_t("b") } }, 183}; 184 185bool g_any_failed = false; 186 187static bool check_value_conformance(TestSuite const& test) 188{ 189 bool fail = false; 190 for (size_t i = 0; i < test.argument_count; ++i) { 191 auto& arg = test.arguments[i]; 192 auto arg_value = arg_to_value_t(arg); 193 auto& value = test.expected_values[i]; 194 if (arg_value != value) { 195 auto arg_ptr = (u32 const*)arg_value.data(); 196 auto value_ptr = (u32 const*)value.data(); 197 printf(" value %zu FAIL,\n", i); 198 printf(" expected %08x%08x%08x%08x%08x%08x%08x%08x\n", 199 value_ptr[0], value_ptr[1], value_ptr[2], value_ptr[3], 200 value_ptr[4], value_ptr[5], value_ptr[6], value_ptr[7]); 201 printf(" but got %08x%08x%08x%08x%08x%08x%08x%08x\n", 202 arg_ptr[0], arg_ptr[1], arg_ptr[2], arg_ptr[3], 203 arg_ptr[4], arg_ptr[5], arg_ptr[6], arg_ptr[7]); 204 fail = true; 205 } else { 206 printf(" value %zu PASS\n", i); 207 } 208 } 209 210 return !fail; 211} 212 213static void do_one_test(TestSuite const& test) 214{ 215 printf("Testing '%s' against '%s'...\n", test.input, test.format); 216 217#pragma GCC diagnostic push 218#pragma GCC diagnostic ignored "-Wformat-nonliteral" 219 auto rc = sscanf(test.input, test.format, 220 test.arguments[0].data, test.arguments[1].data, test.arguments[2].data, test.arguments[3].data, 221 test.arguments[4].data, test.arguments[5].data, test.arguments[6].data, test.arguments[7].data); 222#pragma GCC diagnostic pop 223 224 bool overall = true; 225 printf(" return value...\n"); 226 if (rc != test.expected_return_value) { 227 printf(" return value FAIL, expected %d but got %d\n", test.expected_return_value, rc); 228 overall = false; 229 } else { 230 printf(" return value PASS\n"); 231 } 232 233 printf(" read values...\n"); 234 if (check_value_conformance(test)) { 235 printf(" read values PASS\n"); 236 } else { 237 printf(" read values FAIL\n"); 238 overall = false; 239 } 240 241 if (overall) 242 printf(" overall PASS\n"); 243 else 244 printf(" overall FAIL\n"); 245 246 VERIFY(overall); 247} 248 249TEST_CASE(scanf) 250{ 251 for (auto& test : test_suites) 252 do_one_test(test); 253}