parse_enum_ut.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #include <library/cpp/resource/resource.h>
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #include <tools/enum_parser/parse_enum/parse_enum.h>
  4. #include <util/generic/array_ref.h>
  5. #include <util/generic/maybe.h>
  6. typedef TEnumParser::TEnum TEnum;
  7. typedef TEnumParser::TEnums TEnums;
  8. typedef TEnumParser::TItems TItems;
  9. namespace {
  10. using TNameValuePair = std::pair<TStringBuf, TMaybe<TStringBuf>>;
  11. void CompareNameValueItems(TConstArrayRef<TNameValuePair> ref, const TEnum& e) {
  12. const TItems& it = e.Items;
  13. for (size_t i = 0; i < Min(ref.size(), it.size()); ++i) {
  14. const auto& [refCppName, refValue] = ref[i];
  15. UNIT_ASSERT_VALUES_EQUAL_C(it[i].CppName, refCppName, e.CppName);
  16. UNIT_ASSERT_EQUAL_C(it[i].Value.Defined(), refValue.Defined(), e.CppName);
  17. if (refValue.Defined() && it[i].Value.Defined()) {
  18. UNIT_ASSERT_VALUES_EQUAL_C(*it[i].Value, *refValue, e.CppName);
  19. }
  20. }
  21. UNIT_ASSERT_VALUES_EQUAL_C(it.size(), ref.size(), e.CppName);
  22. }
  23. }
  24. Y_UNIT_TEST_SUITE(TEnumParserTest) {
  25. Y_UNIT_TEST(MainTest) {
  26. TString text = NResource::Find("/enums");
  27. TMemoryInput input(text.data(), text.size());
  28. TEnumParser parser(input);
  29. const TEnums& enums = parser.Enums;
  30. UNIT_ASSERT_VALUES_EQUAL(enums.size(), 16u);
  31. // check ESimple
  32. {
  33. const TEnum& e = enums[0];
  34. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  35. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ESimple");
  36. const TItems& it = e.Items;
  37. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  38. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
  39. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);
  40. UNIT_ASSERT(!it[0].Value.Defined());
  41. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Https");
  42. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
  43. UNIT_ASSERT(!it[1].Value.Defined());
  44. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "ItemCount");
  45. UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
  46. UNIT_ASSERT(!it[2].Value.Defined());
  47. }
  48. // ESimpleWithComma
  49. {
  50. const TEnum& e = enums[1];
  51. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  52. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ESimpleWithComma");
  53. const TItems& it = e.Items;
  54. UNIT_ASSERT_VALUES_EQUAL(it.size(), 4u);
  55. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
  56. UNIT_ASSERT(it[0].Value.Defined());
  57. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "3");
  58. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);
  59. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Http2");
  60. UNIT_ASSERT(it[1].Value.Defined());
  61. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
  62. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "Http");
  63. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "Https");
  64. UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
  65. UNIT_ASSERT(!it[2].Value.Defined());
  66. UNIT_ASSERT_VALUES_EQUAL(it[3].CppName, "ItemCount");
  67. UNIT_ASSERT_VALUES_EQUAL(it[3].Aliases.size(), 0u);
  68. UNIT_ASSERT(!it[3].Value.Defined());
  69. }
  70. // check ECustomAliases
  71. {
  72. const TEnum& e = enums[2];
  73. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  74. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ECustomAliases");
  75. const TItems& it = e.Items;
  76. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  77. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "CAHttp");
  78. UNIT_ASSERT(it[0].Value.Defined());
  79. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "3");
  80. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 1u);
  81. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[0], "http");
  82. UNIT_ASSERT(!it[1].Value.Defined());
  83. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "CAHttps");
  84. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 1u);
  85. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases[0], "https");
  86. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "CAItemCount");
  87. UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
  88. }
  89. // check EMultipleAliases
  90. {
  91. const TEnum& e = enums[3];
  92. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  93. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EMultipleAliases");
  94. const TItems& it = e.Items;
  95. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  96. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "MAHttp");
  97. UNIT_ASSERT(it[0].Value.Defined());
  98. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "9");
  99. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 3u);
  100. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[0], "http://");
  101. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[1], "secondary");
  102. // yes, quoted values are NOT decoded, it is a known (minor) bug
  103. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases[2], "old\\nvalue");
  104. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "MAHttps");
  105. UNIT_ASSERT(it[1].Value.Defined());
  106. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "1");
  107. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 1u);
  108. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases[0], "https://");
  109. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "MAItemCount");
  110. UNIT_ASSERT(!it[2].Value.Defined());
  111. UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
  112. }
  113. // check NEnumNamespace::EInNamespace
  114. {
  115. const TEnum& e = enums[4];
  116. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 1u);
  117. UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NEnumNamespace");
  118. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EInNamespace");
  119. const TItems& it = e.Items;
  120. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  121. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
  122. UNIT_ASSERT(it[0].Value.Defined());
  123. }
  124. // check NEnumNamespace::TEnumClass::EInClass
  125. {
  126. const TEnum& e = enums[5];
  127. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 2u);
  128. UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NEnumNamespace");
  129. UNIT_ASSERT_VALUES_EQUAL(e.Scope[1], "TEnumClass");
  130. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EInClass");
  131. const TItems& it = e.Items;
  132. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  133. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
  134. UNIT_ASSERT(it[0].Value.Defined());
  135. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "9");
  136. UNIT_ASSERT(it[1].Value.Defined());
  137. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "NEnumNamespace::Https");
  138. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "Https3");
  139. UNIT_ASSERT(it[2].Value.Defined());
  140. UNIT_ASSERT_VALUES_EQUAL(*it[2].Value, "1 + 2");
  141. }
  142. // check unnamed enum (no code should be generated for it)
  143. {
  144. const TEnum& e = enums[6];
  145. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  146. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "");
  147. const TItems& it = e.Items;
  148. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  149. }
  150. // TEXT_WEIGHT
  151. {
  152. const TEnum& e = enums[7];
  153. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  154. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "TEXT_WEIGHT");
  155. const TItems& it = e.Items;
  156. UNIT_ASSERT_VALUES_EQUAL(it.size(), 5u);
  157. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "WEIGHT_ZERO");
  158. UNIT_ASSERT(it[0].Value.Defined());
  159. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "-1");
  160. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);
  161. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "WEIGHT_LOW");
  162. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
  163. UNIT_ASSERT(!it[1].Value.Defined());
  164. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "WEIGHT_NORMAL");
  165. UNIT_ASSERT_VALUES_EQUAL(it[2].Aliases.size(), 0u);
  166. UNIT_ASSERT(!it[2].Value.Defined());
  167. }
  168. // EDuplicateKeys
  169. {
  170. const TEnum& e = enums[8];
  171. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  172. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EDuplicateKeys");
  173. const TItems& it = e.Items;
  174. UNIT_ASSERT_VALUES_EQUAL(it.size(), 5u);
  175. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Key0");
  176. UNIT_ASSERT(it[0].Value.Defined());
  177. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "0");
  178. UNIT_ASSERT_VALUES_EQUAL(it[0].Aliases.size(), 0u);
  179. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Key0Second");
  180. UNIT_ASSERT(it[1].Value.Defined());
  181. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "Key0");
  182. UNIT_ASSERT_VALUES_EQUAL(it[1].Aliases.size(), 0u);
  183. }
  184. // EEmpty
  185. {
  186. const TEnum& e = enums[10];
  187. const TItems& it = e.Items;
  188. UNIT_ASSERT_VALUES_EQUAL(it.size(), 0u);
  189. }
  190. // NComposite::NInner::EInCompositeNamespaceSimple
  191. {
  192. const TEnum& e = enums[11];
  193. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 1u);
  194. UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NComposite::NInner");
  195. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EInCompositeNamespaceSimple");
  196. const TItems& it = e.Items;
  197. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  198. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "one");
  199. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "2") ;
  200. }
  201. // NOuterSimple::NComposite::NMiddle::NInner::NInnerSimple::TEnumClass::EVeryDeep
  202. {
  203. const TEnum& e = enums[12];
  204. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 4u);
  205. UNIT_ASSERT_VALUES_EQUAL(e.Scope[0], "NOuterSimple");
  206. UNIT_ASSERT_VALUES_EQUAL(e.Scope[1], "NComposite::NMiddle::NInner");
  207. UNIT_ASSERT_VALUES_EQUAL(e.Scope[2], "NInnerSimple");
  208. UNIT_ASSERT_VALUES_EQUAL(e.Scope[3], "TEnumClass");
  209. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "EVeryDeep");
  210. const TItems& it = e.Items;
  211. UNIT_ASSERT_VALUES_EQUAL(it.size(), 2u);
  212. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Key0");
  213. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "Key1");
  214. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "1");
  215. }
  216. // ENonLiteralValues
  217. {
  218. const TEnum& e = enums[13];
  219. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  220. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ENonLiteralValues");
  221. const TItems& it = e.Items;
  222. UNIT_ASSERT_VALUES_EQUAL(it.size(), 5u);
  223. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "one");
  224. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "MACRO(1, 2)");
  225. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "two");
  226. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "2");
  227. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "three");
  228. UNIT_ASSERT_VALUES_EQUAL(*it[2].Value, "func(3)");
  229. UNIT_ASSERT_VALUES_EQUAL(it[3].CppName, "four");
  230. UNIT_ASSERT_VALUES_EQUAL(it[3].Value.Defined(), false);
  231. UNIT_ASSERT_VALUES_EQUAL(it[4].CppName, "five");
  232. UNIT_ASSERT_VALUES_EQUAL(it[4].Value, "MACRO(MACRO(1, 2), 2)");
  233. }
  234. // NotifyingStatus
  235. {
  236. const TEnum& e = enums[15];
  237. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  238. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "NotifyingStatus");
  239. const TItems& it = e.Items;
  240. UNIT_ASSERT_VALUES_EQUAL(it.size(), 4u);
  241. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "NEW");
  242. UNIT_ASSERT_VALUES_EQUAL(*it[0].Value, "0");
  243. UNIT_ASSERT_VALUES_EQUAL(it[1].CppName, "FAILED_WILL_RETRY");
  244. UNIT_ASSERT_VALUES_EQUAL(*it[1].Value, "1");
  245. UNIT_ASSERT_VALUES_EQUAL(it[2].CppName, "FAILED_NO_MORE_TRIALS");
  246. UNIT_ASSERT_VALUES_EQUAL(*it[2].Value, "2");
  247. UNIT_ASSERT_VALUES_EQUAL(it[3].CppName, "SENT");
  248. UNIT_ASSERT_VALUES_EQUAL(*it[3].Value, "3");
  249. }
  250. }
  251. Y_UNIT_TEST(BadCodeParseTest) {
  252. TString text = NResource::Find("/badcode");
  253. TMemoryInput input(text.data(), text.size());
  254. TEnumParser parser(input);
  255. const TEnums& enums = parser.Enums;
  256. UNIT_ASSERT_VALUES_EQUAL(enums.size(), 1u);
  257. // check <anonymous namespace>::ETest correct parsing
  258. {
  259. const TEnum& e = enums[0];
  260. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 1u);
  261. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ETest");
  262. const TItems& it = e.Items;
  263. UNIT_ASSERT_VALUES_EQUAL(it.size(), 3u);
  264. UNIT_ASSERT_VALUES_EQUAL(it[0].CppName, "Http");
  265. UNIT_ASSERT(it[0].Value.Defined());
  266. }
  267. }
  268. Y_UNIT_TEST(UnbalancedCodeParseTest) {
  269. // Thanks gotmanov@ for providing this example
  270. TString text = NResource::Find("/unbalanced");
  271. TMemoryInput input(text.data(), text.size());
  272. try {
  273. TEnumParser parser(input);
  274. UNIT_ASSERT(false);
  275. } catch(...) {
  276. UNIT_ASSERT(CurrentExceptionMessage().Contains("unbalanced scope. Did you miss a closing"));
  277. }
  278. }
  279. Y_UNIT_TEST(AliasBeforeNameTest) {
  280. TString text = NResource::Find("/alias_before_name");
  281. TMemoryInput input(text.data(), text.size());
  282. try {
  283. TEnumParser parser(input);
  284. UNIT_ASSERT(false);
  285. } catch(...) {
  286. UNIT_ASSERT(CurrentExceptionMessage().Contains("https://clubs.at.yandex-team.ru/stackoverflow/2603"));
  287. }
  288. }
  289. Y_UNIT_TEST(DigitSeparatorTest) {
  290. TString text = NResource::Find("/digit_separator");
  291. TMemoryInput input(text.data(), text.size());
  292. TEnumParser parser(input);
  293. const TEnums& enums = parser.Enums;
  294. UNIT_ASSERT_VALUES_EQUAL(enums.size(), 2u);
  295. {
  296. const TEnum& e = enums[0];
  297. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ELiterals");
  298. static constexpr TNameValuePair ref[]{
  299. {"Char", "sizeof(u8'.')"},
  300. {"Int", "123'456'789"},
  301. {"Float1", "int(456'789.123'456)"},
  302. {"Float2", "int(1'2e0'1)"},
  303. {"Float3", "int(0x1'2p4)"},
  304. };
  305. CompareNameValueItems(ref, e);
  306. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  307. }
  308. {
  309. const TEnum& e = enums[1];
  310. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  311. UNIT_ASSERT_VALUES_EQUAL(e.CppName, "ETimePrecision");
  312. static constexpr TNameValuePair ref[]{
  313. {"MicroSeconds", "1"},
  314. {"MilliSeconds", "1'000"},
  315. {"Seconds", "1'000'000"},
  316. {"Minutes", "60'000'000"},
  317. {"Hours", "3'600'000'000"},
  318. {"Days", "86'400'000'000"},
  319. {"Weeks", "604'800'000'000"},
  320. };
  321. CompareNameValueItems(ref, e);
  322. UNIT_ASSERT_VALUES_EQUAL(e.Scope.size(), 0u);
  323. }
  324. }
  325. }