test_numeral.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. # -*- coding: utf-8 -*-
  2. """
  3. Unit-tests for pytils.numeral
  4. """
  5. import decimal
  6. import unittest
  7. import pytils
  8. class ChoosePluralTestCase(unittest.TestCase):
  9. """
  10. Test case for pytils.numeral.choose_plural
  11. """
  12. def setUp(self):
  13. """
  14. Setting up environment for tests
  15. """
  16. self.variants = ("гвоздь", "гвоздя", "гвоздей")
  17. def checkChoosePlural(self, amount, estimated):
  18. """
  19. Checks choose_plural
  20. """
  21. self.assertEqual(
  22. pytils.numeral.choose_plural(amount, self.variants),
  23. estimated
  24. )
  25. def testChoosePlural(self):
  26. """
  27. Unit-test for choose_plural
  28. """
  29. self.checkChoosePlural(1, "гвоздь")
  30. self.checkChoosePlural(2, "гвоздя")
  31. self.checkChoosePlural(3, "гвоздя")
  32. self.checkChoosePlural(5, "гвоздей")
  33. self.checkChoosePlural(11, "гвоздей")
  34. self.checkChoosePlural(109, "гвоздей")
  35. def testChoosePluralNegativeBug9(self):
  36. """
  37. Test handling of negative numbers
  38. """
  39. self.checkChoosePlural(-5, "гвоздей")
  40. self.checkChoosePlural(-2, "гвоздя")
  41. def testChoosePluralExceptions(self):
  42. """
  43. Unit-test for testing choos_plural's exceptions
  44. """
  45. self.assertRaises(
  46. ValueError,
  47. pytils.numeral.choose_plural,
  48. 25,
  49. "any,bene"
  50. )
  51. def testChoosePluralVariantsInStr(self):
  52. """
  53. Tests new-style variants
  54. """
  55. self.assertEqual(
  56. pytils.numeral.choose_plural(1, "гвоздь,гвоздя, гвоздей"),
  57. "гвоздь"
  58. )
  59. self.assertEqual(
  60. pytils.numeral.choose_plural(5, "гвоздь, гвоздя, гвоздей\, шпунтов"),
  61. "гвоздей, шпунтов"
  62. )
  63. class GetPluralTestCase(unittest.TestCase):
  64. """
  65. Test case for get_plural
  66. """
  67. def testGetPlural(self):
  68. """
  69. Test regular get_plural
  70. """
  71. self.assertEqual(
  72. pytils.numeral.get_plural(1, "комментарий, комментария, комментариев"),
  73. "1 комментарий"
  74. )
  75. self.assertEqual(
  76. pytils.numeral.get_plural(0, "комментарий, комментария, комментариев"),
  77. "0 комментариев"
  78. )
  79. def testGetPluralAbsence(self):
  80. """
  81. Test get_plural with absence
  82. """
  83. self.assertEqual(
  84. pytils.numeral.get_plural(
  85. 1,
  86. "комментарий, комментария, комментариев",
  87. "без комментариев"
  88. ),
  89. "1 комментарий"
  90. )
  91. self.assertEqual(
  92. pytils.numeral.get_plural(
  93. 0,
  94. "комментарий, комментария, комментариев",
  95. "без комментариев"
  96. ),
  97. "без комментариев"
  98. )
  99. def testGetPluralLegacy(self):
  100. """
  101. Test _get_plural_legacy
  102. """
  103. self.assertEqual(
  104. pytils.numeral._get_plural_legacy(1, "комментарий, комментария, комментариев"),
  105. "1 комментарий"
  106. )
  107. self.assertEqual(
  108. pytils.numeral._get_plural_legacy(0, "комментарий, комментария, комментариев"),
  109. "0 комментариев"
  110. )
  111. self.assertEqual(
  112. pytils.numeral._get_plural_legacy(1, "комментарий, комментария, комментариев, без комментариев"),
  113. "1 комментарий"
  114. )
  115. self.assertEqual(
  116. pytils.numeral._get_plural_legacy(0, "комментарий, комментария, комментариев, без комментариев"),
  117. "без комментариев"
  118. )
  119. class GetFloatRemainderTestCase(unittest.TestCase):
  120. """
  121. Test case for pytils.numeral._get_float_remainder
  122. """
  123. def testFloatRemainder(self):
  124. """
  125. Unit-test for _get_float_remainder
  126. """
  127. self.assertEqual(
  128. pytils.numeral._get_float_remainder(1.3),
  129. '3'
  130. )
  131. self.assertEqual(
  132. pytils.numeral._get_float_remainder(2.35, 1),
  133. '4'
  134. )
  135. self.assertEqual(
  136. pytils.numeral._get_float_remainder(123.1234567891),
  137. '123456789'
  138. )
  139. self.assertEqual(
  140. pytils.numeral._get_float_remainder(2.353, 2),
  141. '35'
  142. )
  143. self.assertEqual(
  144. pytils.numeral._get_float_remainder(0.01),
  145. '01'
  146. )
  147. self.assertEqual(
  148. pytils.numeral._get_float_remainder(5),
  149. '0'
  150. )
  151. def testFloatRemainderDecimal(self):
  152. """
  153. Unit-test for _get_float_remainder with decimal type
  154. """
  155. D = decimal.Decimal
  156. self.assertEqual(
  157. pytils.numeral._get_float_remainder(D("1.3")),
  158. '3'
  159. )
  160. self.assertEqual(
  161. pytils.numeral._get_float_remainder(D("2.35"), 1),
  162. '4'
  163. )
  164. self.assertEqual(
  165. pytils.numeral._get_float_remainder(D("123.1234567891")),
  166. '123456789'
  167. )
  168. self.assertEqual(
  169. pytils.numeral._get_float_remainder(D("2.353"), 2),
  170. '35'
  171. )
  172. self.assertEqual(
  173. pytils.numeral._get_float_remainder(D("0.01")),
  174. '01'
  175. )
  176. self.assertEqual(
  177. pytils.numeral._get_float_remainder(D("5")),
  178. '0'
  179. )
  180. def testFloatRemainderExceptions(self):
  181. """
  182. Unit-test for testing _get_float_remainder's exceptions
  183. """
  184. self.assertRaises(
  185. ValueError,
  186. pytils.numeral._get_float_remainder,
  187. 2.998,
  188. 2
  189. )
  190. self.assertRaises(
  191. ValueError,
  192. pytils.numeral._get_float_remainder,
  193. -1.23
  194. )
  195. class RublesTestCase(unittest.TestCase):
  196. """
  197. Test case for pytils.numeral.rubles
  198. """
  199. def testRubles(self):
  200. """
  201. Unit-test for rubles
  202. """
  203. self.assertEqual(
  204. pytils.numeral.rubles(10.01),
  205. "десять рублей одна копейка"
  206. )
  207. self.assertEqual(
  208. pytils.numeral.rubles(10.10),
  209. "десять рублей десять копеек"
  210. )
  211. self.assertEqual(
  212. pytils.numeral.rubles(2.353),
  213. "два рубля тридцать пять копеек"
  214. )
  215. self.assertEqual(
  216. pytils.numeral.rubles(2.998),
  217. "три рубля"
  218. )
  219. self.assertEqual(
  220. pytils.numeral.rubles(3),
  221. "три рубля"
  222. )
  223. self.assertEqual(
  224. pytils.numeral.rubles(3, True),
  225. "три рубля ноль копеек"
  226. )
  227. def testRublesDecimal(self):
  228. """
  229. Test for rubles with decimal instead of float/integer
  230. """
  231. D = decimal.Decimal
  232. self.assertEqual(
  233. pytils.numeral.rubles(D("10.01")),
  234. "десять рублей одна копейка"
  235. )
  236. self.assertEqual(
  237. pytils.numeral.rubles(D("10.10")),
  238. "десять рублей десять копеек"
  239. )
  240. self.assertEqual(
  241. pytils.numeral.rubles(D("2.35")),
  242. "два рубля тридцать пять копеек"
  243. )
  244. self.assertEqual(
  245. pytils.numeral.rubles(D(3)),
  246. "три рубля"
  247. )
  248. self.assertEqual(
  249. pytils.numeral.rubles(D(3), True),
  250. "три рубля ноль копеек"
  251. )
  252. def testRublesExceptions(self):
  253. """
  254. Unit-test for testing rubles' exceptions
  255. """
  256. self.assertRaises(ValueError, pytils.numeral.rubles, -15)
  257. class InWordsTestCase(unittest.TestCase):
  258. """
  259. Test case for pytils.numeral.in_words
  260. """
  261. def testInt(self):
  262. """
  263. Unit-test for in_words_int
  264. """
  265. self.assertEqual(pytils.numeral.in_words_int(0), "ноль")
  266. self.assertEqual(pytils.numeral.in_words_int(10), "десять")
  267. self.assertEqual(pytils.numeral.in_words_int(5), "пять")
  268. self.assertEqual(pytils.numeral.in_words_int(102), "сто два")
  269. self.assertEqual(pytils.numeral.in_words_int(3521), "три тысячи пятьсот двадцать один")
  270. self.assertEqual(pytils.numeral.in_words_int(3500), "три тысячи пятьсот")
  271. self.assertEqual(pytils.numeral.in_words_int(5231000), "пять миллионов двести тридцать одна тысяча")
  272. def testIntExceptions(self):
  273. """
  274. Unit-test for testing in_words_int's exceptions
  275. """
  276. self.assertRaises(ValueError, pytils.numeral.in_words_int, -3)
  277. def testFloat(self):
  278. """
  279. Unit-test for in_words_float
  280. """
  281. self.assertEqual(pytils.numeral.in_words_float(10.0), "десять целых ноль десятых")
  282. self.assertEqual(pytils.numeral.in_words_float(2.25), "две целых двадцать пять сотых")
  283. self.assertEqual(pytils.numeral.in_words_float(0.01), "ноль целых одна сотая")
  284. self.assertEqual(pytils.numeral.in_words_float(0.10), "ноль целых одна десятая")
  285. def testDecimal(self):
  286. """
  287. Unit-test for in_words_float with decimal type
  288. """
  289. D = decimal.Decimal
  290. self.assertEqual(
  291. pytils.numeral.in_words_float(D("10.0")),
  292. "десять целых ноль десятых"
  293. )
  294. self.assertEqual(
  295. pytils.numeral.in_words_float(D("2.25")),
  296. "две целых двадцать пять сотых"
  297. )
  298. self.assertEqual(
  299. pytils.numeral.in_words_float(D("0.01")),
  300. "ноль целых одна сотая"
  301. )
  302. # поскольку это Decimal, то здесь нет незначащих нулей
  303. # т.е. нули определяют точность, поэтому десять сотых,
  304. # а не одна десятая
  305. self.assertEqual(
  306. pytils.numeral.in_words_float(D("0.10")),
  307. "ноль целых десять сотых"
  308. )
  309. def testFloatExceptions(self):
  310. """
  311. Unit-test for testing in_words_float's exceptions
  312. """
  313. self.assertRaises(ValueError, pytils.numeral.in_words_float, -2.3)
  314. def testWithGenderOldStyle(self):
  315. """
  316. Unit-test for in_words_float with gender (old-style, i.e. ints)
  317. """
  318. self.assertEqual(pytils.numeral.in_words(21, 1), "двадцать один")
  319. self.assertEqual(pytils.numeral.in_words(21, 2), "двадцать одна")
  320. self.assertEqual(pytils.numeral.in_words(21, 3), "двадцать одно")
  321. # на дробные пол не должен влиять - всегда в женском роде
  322. self.assertEqual(pytils.numeral.in_words(21.0, 1), "двадцать одна целая ноль десятых")
  323. self.assertEqual(pytils.numeral.in_words(21.0, 2), "двадцать одна целая ноль десятых")
  324. self.assertEqual(pytils.numeral.in_words(21.0, 3), "двадцать одна целая ноль десятых")
  325. def testWithGender(self):
  326. """
  327. Unit-test for in_words_float with gender (old-style, i.e. ints)
  328. """
  329. self.assertEqual(
  330. pytils.numeral.in_words(21, pytils.numeral.MALE),
  331. "двадцать один"
  332. )
  333. self.assertEqual(
  334. pytils.numeral.in_words(21, pytils.numeral.FEMALE),
  335. "двадцать одна"
  336. )
  337. self.assertEqual(
  338. pytils.numeral.in_words(21, pytils.numeral.NEUTER),
  339. "двадцать одно"
  340. )
  341. # на дробные пол не должен влиять - всегда в женском роде
  342. self.assertEqual(
  343. pytils.numeral.in_words(21.0, pytils.numeral.MALE),
  344. "двадцать одна целая ноль десятых"
  345. )
  346. self.assertEqual(
  347. pytils.numeral.in_words(21.0, pytils.numeral.FEMALE),
  348. "двадцать одна целая ноль десятых"
  349. )
  350. self.assertEqual(
  351. pytils.numeral.in_words(21.0, pytils.numeral.NEUTER),
  352. "двадцать одна целая ноль десятых"
  353. )
  354. def testCommon(self):
  355. """
  356. Unit-test for general in_words
  357. """
  358. D = decimal.Decimal
  359. self.assertEqual(
  360. pytils.numeral.in_words(10),
  361. "десять"
  362. )
  363. self.assertEqual(
  364. pytils.numeral.in_words(5),
  365. "пять"
  366. )
  367. self.assertEqual(
  368. pytils.numeral.in_words(102),
  369. "сто два"
  370. )
  371. self.assertEqual(
  372. pytils.numeral.in_words(3521),
  373. "три тысячи пятьсот двадцать один"
  374. )
  375. self.assertEqual(
  376. pytils.numeral.in_words(3500),
  377. "три тысячи пятьсот"
  378. )
  379. self.assertEqual(
  380. pytils.numeral.in_words(5231000),
  381. "пять миллионов двести тридцать одна тысяча"
  382. )
  383. self.assertEqual(
  384. pytils.numeral.in_words(10.0),
  385. "десять целых ноль десятых"
  386. )
  387. self.assertEqual(
  388. pytils.numeral.in_words(2.25),
  389. "две целых двадцать пять сотых"
  390. )
  391. self.assertEqual(
  392. pytils.numeral.in_words(0.01),
  393. "ноль целых одна сотая"
  394. )
  395. self.assertEqual(
  396. pytils.numeral.in_words(0.10),
  397. "ноль целых одна десятая"
  398. )
  399. self.assertEqual(
  400. pytils.numeral.in_words(D("2.25")),
  401. "две целых двадцать пять сотых"
  402. )
  403. self.assertEqual(
  404. pytils.numeral.in_words(D("0.01")),
  405. "ноль целых одна сотая"
  406. )
  407. self.assertEqual(
  408. pytils.numeral.in_words(D("0.10")),
  409. "ноль целых десять сотых"
  410. )
  411. self.assertEqual(
  412. pytils.numeral.in_words(D("10")),
  413. "десять"
  414. )
  415. def testCommonExceptions(self):
  416. """
  417. Unit-test for testing in_words' exceptions
  418. """
  419. self.assertRaises(ValueError, pytils.numeral.in_words, -2)
  420. self.assertRaises(ValueError, pytils.numeral.in_words, -2.5)
  421. class SumStringTestCase(unittest.TestCase):
  422. """
  423. Test case for pytils.numeral.sum_string
  424. """
  425. def setUp(self):
  426. """
  427. Setting up environment for tests
  428. """
  429. self.variants_male = ("гвоздь", "гвоздя", "гвоздей")
  430. self.variants_female = ("шляпка", "шляпки", "шляпок")
  431. def ckMaleOldStyle(self, amount, estimated):
  432. """
  433. Checks sum_string with male gender with old-style genders (i.e. ints)
  434. """
  435. self.assertEqual(
  436. pytils.numeral.sum_string(amount, 1, self.variants_male),
  437. estimated
  438. )
  439. def ckMale(self, amount, estimated):
  440. """
  441. Checks sum_string with male gender
  442. """
  443. self.assertEqual(
  444. pytils.numeral.sum_string(amount, pytils.numeral.MALE, self.variants_male),
  445. estimated
  446. )
  447. def ckFemaleOldStyle(self, amount, estimated):
  448. """
  449. Checks sum_string with female gender wuth old-style genders (i.e. ints)
  450. """
  451. self.assertEqual(
  452. pytils.numeral.sum_string(amount, 2, self.variants_female),
  453. estimated
  454. )
  455. def ckFemale(self, amount, estimated):
  456. """
  457. Checks sum_string with female gender
  458. """
  459. self.assertEqual(
  460. pytils.numeral.sum_string(amount, pytils.numeral.FEMALE, self.variants_female),
  461. estimated
  462. )
  463. def testSumStringOldStyleGender(self):
  464. """
  465. Unit-test for sum_string with old-style genders
  466. """
  467. self.ckMaleOldStyle(10, "десять гвоздей")
  468. self.ckMaleOldStyle(2, "два гвоздя")
  469. self.ckMaleOldStyle(31, "тридцать один гвоздь")
  470. self.ckFemaleOldStyle(10, "десять шляпок")
  471. self.ckFemaleOldStyle(2, "две шляпки")
  472. self.ckFemaleOldStyle(31, "тридцать одна шляпка")
  473. self.assertEqual(
  474. "одиннадцать негритят",
  475. pytils.numeral.sum_string(11, 1, "негритенок,негритенка,негритят")
  476. )
  477. def testSumString(self):
  478. """
  479. Unit-test for sum_string
  480. """
  481. self.ckMale(10, "десять гвоздей")
  482. self.ckMale(2, "два гвоздя")
  483. self.ckMale(31, "тридцать один гвоздь")
  484. self.ckFemale(10, "десять шляпок")
  485. self.ckFemale(2, "две шляпки")
  486. self.ckFemale(31, "тридцать одна шляпка")
  487. self.assertEqual(
  488. "одиннадцать негритят",
  489. pytils.numeral.sum_string(11, pytils.numeral.MALE, "негритенок,негритенка,негритят")
  490. )
  491. def testSumStringExceptions(self):
  492. """
  493. Unit-test for testing sum_string's exceptions
  494. """
  495. self.assertRaises(
  496. ValueError,
  497. pytils.numeral.sum_string,
  498. -1,
  499. pytils.numeral.MALE,
  500. "any,bene,raba"
  501. )
  502. if __name__ == '__main__':
  503. unittest.main()