test_character.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. # jogai - Python Game Library
  2. #
  3. # This library is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU Library General Public
  5. # License as published by the Free Software Foundation; either
  6. # version 2 of the License, or (at your option) any later version.
  7. #
  8. # This library is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. # Library General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU Library General Public
  14. # License along with this library; if not, write to the Free
  15. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. #
  17. # Ramón Palleiro Rodríguez
  18. # Zero! Factorial Studio
  19. # info@zero.gal
  20. from os.path import join
  21. import pygame
  22. import pytest
  23. from jogai import paths, settings
  24. from jogai import videogame as vg
  25. from jogai.character import (
  26. Character,
  27. _check_and_format_args_for_group,
  28. _load_characters_and_groups,
  29. )
  30. from jogai.texts import SpeechBubble
  31. from jogai.translations import gettext as _
  32. def test_check_and_format_args_for_a_random_group_with_a_dict():
  33. assert (
  34. _check_and_format_args_for_group('random', {'foo': 'bar'})
  35. == '**arguments'
  36. )
  37. def test_check_and_format_args_for_a_rectangle_group_with_a_list():
  38. assert (
  39. _check_and_format_args_for_group('rectangle', [2, 3]) == '*arguments'
  40. )
  41. def test_check_and_format_args_for_a_square_group_with_a_integer():
  42. assert _check_and_format_args_for_group('square', 3) == 'arguments'
  43. def test_check_and_format_args_for_a_stairs_group_with_a_dict():
  44. assert (
  45. _check_and_format_args_for_group('stairs', {'foo': 'bar'})
  46. == '**arguments'
  47. )
  48. def test_check_and_format_args_for_group_with_wrong_args():
  49. group_type = 'rectangle'
  50. args_type = list.__name__
  51. with pytest.raises(TypeError) as e:
  52. _check_and_format_args_for_group(group_type, 5)
  53. assert (
  54. str(e.value)
  55. == f'the arguments for the {group_type} group must be {args_type}'
  56. )
  57. def test_check_and_format_args_for_unknown_group():
  58. group_type = 'foo'
  59. with pytest.raises(TypeError) as e:
  60. format = _check_and_format_args_for_group(group_type, 3)
  61. assert str(e.value) == f'the group type {group_type} is unknown'
  62. def test_load_characters_with_no_characters_key_in_data():
  63. characters = _load_characters_and_groups({})
  64. assert characters == ([], [])
  65. def test_load_characters_with_a_correct_filename():
  66. characters = _load_characters_and_groups(
  67. {'foo': {'filename': 'protagonist.png'}}
  68. )
  69. assert characters[0][0].name == 'foo'
  70. assert characters[0][0].image_filename == 'protagonist.png'
  71. # def test_load_data_with_none_argument(videogame_test):
  72. # ... # protagonist._load_data(None)
  73. class TestCharacter:
  74. def test_load_data_with_wrong_type(self, videogame_test, character_test):
  75. with pytest.raises(TypeError) as e:
  76. character_test._load_data('foo')
  77. assert str(e.value) == 'the data input must be a dict'
  78. def test_height_is_a_non_negative_integer(
  79. self, videogame_test, character_test
  80. ):
  81. assert character_test.height > -1
  82. def test_width_is_a_non_negative_integer(
  83. self, videogame_test, character_test
  84. ):
  85. assert character_test.width > -1
  86. def test_x_coordinate_is_an_integer(self, videogame_test, character_test):
  87. assert isinstance(character_test.x, int)
  88. def test_y_coordinate_is_an_integer(self, videogame_test, character_test):
  89. assert isinstance(character_test.y, int)
  90. def test_wrong_character_name(self):
  91. with pytest.raises(TypeError) as e:
  92. Character('protagonist.png', name=1)
  93. assert str(e.value) == 'the character name must be a string'
  94. def test_repr_character(self, videogame_test, character_test):
  95. assert repr(character_test) == f'Character: {character_test.name}'
  96. def test_angle_property(self, videogame_test, character_test):
  97. angle = 90
  98. character_test.angle = angle
  99. assert character_test.angle == angle
  100. def test_bouncy_property(self, videogame_test, character_test):
  101. bouncy = True
  102. character_test.bouncy = bouncy
  103. assert character_test.bouncy == bouncy
  104. def test_center_property(self, videogame_test, character_test):
  105. assert character_test.center == (
  106. character_test.x + character_test.width // 2,
  107. character_test.y + character_test.height // 2,
  108. )
  109. def test_collidable_property(self, videogame_test, character_test):
  110. collidable = True
  111. character_test.collidable = collidable
  112. assert character_test.collidable == collidable
  113. def test_gravitative_property(self, videogame_test, character_test):
  114. gravitative = True
  115. character_test.gravitative = gravitative
  116. assert character_test.gravitative == gravitative
  117. def test_height_property(self, videogame_test, character_test):
  118. height = 100
  119. character_test.height = height
  120. assert character_test.height == height
  121. def test_image_filename_property(self, character_filename_test):
  122. ch = Character(character_filename_test)
  123. assert ch.image_filename == character_filename_test
  124. def test_image_path_property(self, character_filename_test):
  125. ch = Character(character_filename_test)
  126. assert ch.image_path == join(
  127. paths.CHARACTERS_DIR, character_filename_test
  128. )
  129. def test_jump_force_property(self, videogame_test, character_test):
  130. assert (
  131. character_test.jump_force == settings.CHARACTER_DEFAULT_JUMP_FORCE
  132. )
  133. def test_jumping_property(self, videogame_test, character_test):
  134. assert character_test.jumping == False
  135. def test_lives_property(self, videogame_test, character_test):
  136. lives = 3
  137. character_test.lives = lives
  138. assert character_test.lives == lives
  139. def test_lives_no_property(self, videogame_test, secondary_character_test):
  140. assert secondary_character_test.lives is None
  141. def test_name_property(self, character_filename_test, character_name_test):
  142. ch = Character(character_filename_test, character_name_test)
  143. assert ch.name == character_name_test
  144. def test_position_property(self, videogame_test, character_test):
  145. x, y = 200, 300
  146. character_test.x = x
  147. character_test.y = y
  148. assert character_test.position == (x, y)
  149. def test_scale_property(self, videogame_test, character_test):
  150. scale = 0.5
  151. character_test.scale = scale
  152. assert character_test.scale == scale
  153. def test_score_property(self, videogame_test, character_test):
  154. score = 3
  155. character_test.score = score
  156. assert character_test.score == score
  157. def test_score_no_property(self, videogame_test, secondary_character_test):
  158. assert secondary_character_test.score is None
  159. def test_speaking_property(self, videogame_test, character_test):
  160. character_test.speak('foo')
  161. assert character_test.speaking == True
  162. def test_speech_bubble_property(self, videogame_test, character_test):
  163. assert isinstance(character_test.speech_bubble, SpeechBubble)
  164. def test_speed_property(self, videogame_test, character_test):
  165. speed = 20
  166. character_test.speed = speed
  167. assert character_test.speed == speed
  168. def test_touchable_property(self, videogame_test, character_test):
  169. touchable = True
  170. character_test.touchable = touchable
  171. assert character_test.touchable == touchable
  172. def test_visible_property(self, videogame_test, character_test):
  173. visible = False
  174. character_test.visible = visible
  175. assert character_test.visible == visible
  176. def test_width_property(self, videogame_test, character_test):
  177. width = 100
  178. character_test.width = width
  179. assert character_test.width == width
  180. def test_calculate_relative_position_top(
  181. self, videogame_test, character_test, secondary_character_test
  182. ):
  183. character_test.move_to(0, 0)
  184. secondary_character_test.move_to(0, character_test.height + 1)
  185. assert (
  186. character_test.calculate_relative_position(
  187. secondary_character_test
  188. )
  189. == character_test.TOP
  190. )
  191. def test_calculate_relative_position_bottom(
  192. self, videogame_test, character_test, secondary_character_test
  193. ):
  194. character_test.move_to(0, secondary_character_test.height + 1)
  195. secondary_character_test.move_to(0, 0)
  196. assert (
  197. character_test.calculate_relative_position(
  198. secondary_character_test
  199. )
  200. == character_test.BOTTOM
  201. )
  202. def test_calculate_relative_position_left(
  203. self, videogame_test, character_test, secondary_character_test
  204. ):
  205. character_test.move_to(0, 0)
  206. secondary_character_test.move_to(character_test.width + 1, 0)
  207. assert (
  208. character_test.calculate_relative_position(
  209. secondary_character_test
  210. )
  211. == character_test.LEFT
  212. )
  213. def test_calculate_relative_position_right(
  214. self, videogame_test, character_test, secondary_character_test
  215. ):
  216. character_test.move_to(secondary_character_test.width + 1, 0)
  217. secondary_character_test.move_to(0, 0)
  218. assert (
  219. character_test.calculate_relative_position(
  220. secondary_character_test
  221. )
  222. == character_test.RIGHT
  223. )
  224. def test_move_with_wrong_coordinates(self, videogame_test, character_test):
  225. with pytest.raises(TypeError) as e:
  226. character_test.move('foo', 'bar')
  227. assert str(e.value) == 'amount to move must be an integer'
  228. def test_move_with_wrong_key_type(self, videogame_test, character_test):
  229. with pytest.raises(TypeError) as e:
  230. character_test.move(5, 3, key=-1)
  231. assert str(e.value) == 'key pressed must be a string'
  232. def test_rotate_with_wrong_type(self, videogame_test, character_test):
  233. with pytest.raises(TypeError) as e:
  234. character_test.rotate('foo')
  235. assert str(e.value) == 'the rotation increment must be an integer'
  236. def test_decrease_with_integer_argument(
  237. self, videogame_test, character_test
  238. ):
  239. character_test.decrease(2)
  240. def test_decrease_with_wrong_type(self, videogame_test, character_test):
  241. with pytest.raises(TypeError) as e:
  242. character_test.decrease('foo')
  243. assert str(e.value) == 'the decrement must be a float number'
  244. def test_increase_with_integer_argument(
  245. self, videogame_test, character_test
  246. ):
  247. character_test.increase(2)
  248. def test_increase_with_wrong_type(self, videogame_test, character_test):
  249. with pytest.raises(TypeError) as e:
  250. character_test.increase('foo')
  251. assert str(e.value) == 'the increment must be a float number'
  252. def test_scale_with_wrong_factor_type(
  253. self, videogame_test, character_test
  254. ):
  255. with pytest.raises(TypeError) as e:
  256. character_test.scale_to('foo')
  257. assert (
  258. str(e.value)
  259. == 'the scale factor must be a positive number (float or int)'
  260. )
  261. def test_scale_with_a_negative_factor(
  262. self, videogame_test, character_test
  263. ):
  264. with pytest.raises(ValueError) as e:
  265. character_test.scale_to(-1)
  266. assert (
  267. str(e.value)
  268. == 'the scale factor must be a non-negative number (float or int)'
  269. )
  270. def test_flip_with_wrong_type(self, videogame_test, character_test):
  271. with pytest.raises(TypeError) as e:
  272. character_test.flip('foo', 'bar')
  273. assert (
  274. str(e.value)
  275. == 'both the horizontal and vertical axis must be booleans'
  276. )
  277. def test_set_angle_with_wrong_type(self, videogame_test, character_test):
  278. with pytest.raises(TypeError) as e:
  279. character_test.set_angle('foo')
  280. assert str(e.value) == 'the rotation angle must be an integer'
  281. @pytest.mark.parametrize('height', [True, False, 'foo', [1, 2, 3]])
  282. def test_set_height_with_wrong_type(
  283. self, videogame_test, character_test, height
  284. ):
  285. with pytest.raises(TypeError) as e:
  286. character_test.set_height(height)
  287. assert str(e.value) == 'height must be a non-negative integer'
  288. def test_set_height_with_a_negative_amount(
  289. self, videogame_test, character_test
  290. ):
  291. with pytest.raises(ValueError) as e:
  292. character_test.set_height(-1)
  293. assert str(e.value) == 'height must be a non-negative integer'
  294. def test_set_keys_with_wrong_type(self, videogame_test, character_test):
  295. with pytest.raises(TypeError) as e:
  296. character_test.set_keys('foo')
  297. assert (
  298. str(e.value)
  299. == 'the predefined keys must be a dict. No keys are loaded'
  300. )
  301. def test_set_position_with_wrong_types(
  302. self, videogame_test, character_test
  303. ):
  304. with pytest.raises(TypeError) as e:
  305. character_test.set_position('foo', 'bar')
  306. assert str(e.value) == 'the position must be a tuple or list (x, y)'
  307. def test_set_position_with_wrong_number_of_parameters(
  308. self, videogame_test, character_test
  309. ):
  310. with pytest.raises(ValueError) as e:
  311. character_test.set_position((2, 3, 4))
  312. assert str(e.value) == 'the position has two coordinates (x, y)'
  313. @pytest.mark.parametrize('width', [True, False, 'foo', [1, 2, 3]])
  314. def test_set_width_with_wrong_type(
  315. self, videogame_test, character_test, width
  316. ):
  317. with pytest.raises(TypeError) as e:
  318. character_test.set_width(width)
  319. assert str(e.value) == 'width must be a non-negative integer'
  320. def test_set_width_with_a_negative_amount(
  321. self, videogame_test, character_test
  322. ):
  323. with pytest.raises(ValueError) as e:
  324. character_test.set_width(-1)
  325. assert str(e.value) == 'width must be a non-negative integer'
  326. def test_touch_with_wrong_characters_type(
  327. self, videogame_test, character_test
  328. ):
  329. with pytest.raises(TypeError) as e:
  330. character_test.touch('foo')
  331. assert (
  332. str(e.value)
  333. == 'the instances to be touched must be a character, a group or a list of characters'
  334. )
  335. def test_touch_with_list_not_all_characters(
  336. self, videogame_test, character_test, secondary_character_test
  337. ):
  338. with pytest.raises(TypeError) as e:
  339. character_test.touch([secondary_character_test, 'foo'])
  340. assert (
  341. str(e.value)
  342. == 'the instances to be touched must be a character, a group or a list of characters'
  343. )
  344. def test_touch_with_wrong_key_type(
  345. self, videogame_test, character_test, secondary_character_test
  346. ):
  347. with pytest.raises(TypeError) as e:
  348. character_test.touch(secondary_character_test, key=-1)
  349. assert str(e.value) == 'key pressed must be a string'
  350. def test_touch_without_sprites_colliding(
  351. self, videogame_test, character_test, secondary_character_test
  352. ):
  353. character_test.move_to(0, 0)
  354. secondary_character_test.move_to(5000, 500)
  355. vg.update()
  356. assert character_test.touch(secondary_character_test) == []
  357. # TODO: assert ??
  358. def test_jump_with_force_as_integer(self, videogame_test, character_test):
  359. character_test.jump(5)
  360. def test_jump_with_wrong_force_type(self, videogame_test, character_test):
  361. with pytest.raises(TypeError) as e:
  362. character_test.jump('foo')
  363. assert (
  364. str(e.value)
  365. == 'the jump force must be a non-negative float number'
  366. )
  367. def test_jump_with_negative_force(self, videogame_test, character_test):
  368. with pytest.raises(ValueError) as e:
  369. character_test.jump(-5)
  370. assert str(e.value) == 'the jump force must be a non-negative float'
  371. def test_jump_with_wrong_key_type(self, videogame_test, character_test):
  372. with pytest.raises(TypeError) as e:
  373. character_test.jump(5, key=-1)
  374. assert str(e.value) == 'key pressed must be a string'
  375. def test_jump_counter_when_updating_jump(
  376. self, videogame_test, character_test
  377. ):
  378. character_test.jump()
  379. previous_jump_counter = character_test._jump_counter
  380. character_test._update_jump()
  381. assert character_test._jump_counter == previous_jump_counter - 1
  382. def test_update_rect_position_with_wrong_traking_type(
  383. self, videogame_test, character_test
  384. ):
  385. with pytest.raises(TypeError) as e:
  386. character_test._update_rect_position(tracking='foo')
  387. assert str(e.value) == 'the tracking argument must be a boolean'
  388. """
  389. def test_update_rect_position_when_character_moved(
  390. self, videogame_test, character_test
  391. ):
  392. character_test.move_to(1000, 0)
  393. character_test._update_rect_position(tracking=True)
  394. character_test.move_to(3000, 0)
  395. character_test._update_rect_position(tracking=True)
  396. """