TestScanf.cpp 8.1 KB

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