aa-ledger 1.0.4__py3-none-any.whl → 2.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/METADATA +5 -6
  2. aa_ledger-2.0.0.dist-info/RECORD +267 -0
  3. ledger/__init__.py +2 -2
  4. ledger/admin.py +23 -18
  5. ledger/api/__init__.py +23 -7
  6. ledger/api/{ledger/admin.py → admin.py} +25 -31
  7. ledger/api/alliance.py +755 -0
  8. ledger/api/character.py +786 -0
  9. ledger/api/corporation.py +1141 -0
  10. ledger/api/{helpers.py → helpers/core.py} +33 -33
  11. ledger/api/helpers/icons.py +372 -0
  12. ledger/api/helpers/planetary_helper.py +354 -0
  13. ledger/api/planetary.py +354 -0
  14. ledger/api/schema.py +240 -15
  15. ledger/app_settings.py +11 -27
  16. ledger/auth_hooks.py +2 -2
  17. ledger/constants.py +50 -177
  18. ledger/decorators.py +2 -46
  19. ledger/forms.py +133 -39
  20. ledger/helpers/billboard.py +194 -144
  21. ledger/helpers/cache.py +105 -0
  22. ledger/helpers/discord.py +2 -4
  23. ledger/helpers/eveonline.py +160 -0
  24. ledger/helpers/ledger_data.py +23 -0
  25. ledger/helpers/ref_type.py +53 -78
  26. ledger/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  27. ledger/locale/cs_CZ/LC_MESSAGES/django.po +349 -193
  28. ledger/locale/de/LC_MESSAGES/django.mo +0 -0
  29. ledger/locale/de/LC_MESSAGES/django.po +528 -379
  30. ledger/locale/django.pot +721 -546
  31. ledger/locale/es/LC_MESSAGES/django.mo +0 -0
  32. ledger/locale/es/LC_MESSAGES/django.po +349 -194
  33. ledger/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  34. ledger/locale/fr_FR/LC_MESSAGES/django.po +349 -193
  35. ledger/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  36. ledger/locale/it_IT/LC_MESSAGES/django.po +349 -193
  37. ledger/locale/ja/LC_MESSAGES/django.mo +0 -0
  38. ledger/locale/ja/LC_MESSAGES/django.po +348 -193
  39. ledger/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  40. ledger/locale/ko_KR/LC_MESSAGES/django.po +349 -193
  41. ledger/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  42. ledger/locale/nl_NL/LC_MESSAGES/django.po +349 -193
  43. ledger/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  44. ledger/locale/pl_PL/LC_MESSAGES/django.po +350 -193
  45. ledger/locale/ru/LC_MESSAGES/django.mo +0 -0
  46. ledger/locale/ru/LC_MESSAGES/django.po +348 -193
  47. ledger/locale/sk/LC_MESSAGES/django.mo +0 -0
  48. ledger/locale/sk/LC_MESSAGES/django.po +348 -193
  49. ledger/locale/uk/LC_MESSAGES/django.mo +0 -0
  50. ledger/locale/uk/LC_MESSAGES/django.po +348 -193
  51. ledger/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  52. ledger/locale/zh_Hans/LC_MESSAGES/django.po +348 -193
  53. ledger/managers/character_audit_manager.py +28 -20
  54. ledger/managers/character_journal_manager.py +185 -357
  55. ledger/managers/character_mining_manager.py +52 -26
  56. ledger/managers/character_planetary_manager.py +178 -136
  57. ledger/managers/corporation_audit_manager.py +36 -27
  58. ledger/managers/corporation_journal_manager.py +92 -56
  59. ledger/managers/general_manager.py +8 -7
  60. ledger/migrations/0018_remove_characterplanet_ledger_char_planet__58a5b6_idx_and_more.py +44 -0
  61. ledger/migrations/0019_rename_characteraudit_characterowner_and_more.py +48 -0
  62. ledger/models/__init__.py +5 -11
  63. ledger/models/characteraudit.py +101 -109
  64. ledger/models/corporationaudit.py +94 -49
  65. ledger/models/general.py +105 -211
  66. ledger/models/helpers/update_manager.py +302 -0
  67. ledger/models/planetary.py +60 -205
  68. ledger/providers.py +101 -0
  69. ledger/static/ledger/css/{ledger.css → aa-ledger.css} +54 -28
  70. ledger/static/ledger/js/aa-ledger.js +124 -0
  71. ledger/static/ledger/js/charts.js +25 -1
  72. ledger/static/ledger/js/view-alliance-ledger.js +383 -0
  73. ledger/static/ledger/js/view-character-ledger.js +388 -0
  74. ledger/static/ledger/js/view-corporation-ledger.js +402 -0
  75. ledger/static/ledger/js/view-planetary.js +492 -0
  76. ledger/static/ledger/libs/amCharts/5.14.4/js/flow.js +2 -0
  77. ledger/static/ledger/libs/amCharts/5.14.4/js/index.js +2 -0
  78. ledger/static/ledger/libs/amCharts/5.14.4/js/percent.js +2 -0
  79. ledger/static/ledger/libs/amCharts/5.14.4/js/themes/Animated.js +2 -0
  80. ledger/static/ledger/libs/amCharts/5.14.4/js/themes/Dark.js +2 -0
  81. ledger/static/ledger/libs/amCharts/5.14.4/js/xy.js +2 -0
  82. ledger/static/ledger/libs/datatables/2.3.5/css/dataTables.bootstrap5.css +610 -0
  83. ledger/static/ledger/libs/datatables/2.3.5/js/dataTables.bootstrap5.js +122 -0
  84. ledger/static/ledger/libs/datatables/2.3.5/js/dataTables.js +14127 -0
  85. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/css/columnControl.bootstrap5.css +516 -0
  86. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/css/columnControl.dataTables.css +529 -0
  87. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/js/columnControl.bootstrap5.js +73 -0
  88. ledger/static/ledger/libs/datatables/Extensions/ColumnControl/1.1.1/js/dataTables.columnControl.js +3090 -0
  89. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/css/fixedHeader.bootstrap5.css +20 -0
  90. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/js/dataTables.fixedHeader.js +1203 -0
  91. ledger/static/ledger/libs/datatables/Extensions/FixedHeader/4.0.4/js/fixedHeader.bootstrap5.js +59 -0
  92. ledger/tasks.py +157 -141
  93. ledger/templates/ledger/base.html +59 -21
  94. ledger/templates/ledger/bundles/aa-ledger-css.html +3 -0
  95. ledger/templates/ledger/bundles/aa-ledger-js.html +3 -0
  96. ledger/templates/ledger/bundles/view-alliance-ledger-js.html +14 -0
  97. ledger/templates/ledger/bundles/view-character-ledger-js.html +15 -0
  98. ledger/templates/ledger/bundles/view-character-planetary-css.html +3 -0
  99. ledger/templates/ledger/bundles/view-character-planetary-js.html +4 -0
  100. ledger/templates/ledger/bundles/view-corporation-ledger-js.html +15 -0
  101. ledger/templates/ledger/partials/modal/confirm.html +0 -1
  102. ledger/templates/ledger/partials/modal/request-accept-delete-alliance.html +38 -0
  103. ledger/templates/ledger/partials/modal/request-accept-delete-character.html +38 -0
  104. ledger/templates/ledger/partials/modal/request-accept-delete-corporation.html +38 -0
  105. ledger/templates/ledger/partials/modal/request-accept-switch-notification.html +38 -0
  106. ledger/templates/ledger/partials/modal/request-view-alliance-details.html +26 -0
  107. ledger/templates/ledger/partials/modal/request-view-character-details.html +26 -0
  108. ledger/templates/ledger/partials/modal/request-view-corporation-details.html +26 -0
  109. ledger/templates/ledger/partials/modal/request-view-extractor.html +32 -0
  110. ledger/templates/ledger/partials/modal/request-view-factory.html +31 -0
  111. ledger/templates/ledger/partials/{menu → navigation}/administration.html +8 -0
  112. ledger/templates/ledger/partials/{menu → navigation}/navigation.html +2 -2
  113. ledger/templates/ledger/partials/{administration → view-alliance-administration}/alliance_corporations.html +3 -3
  114. ledger/templates/ledger/partials/view-alliance-administration/dashboard.html +81 -0
  115. ledger/templates/ledger/partials/view-alliance-ledger/alliance-billboard.html +25 -0
  116. ledger/templates/ledger/partials/view-alliance-ledger/alliance-ledger-details.html +21 -0
  117. ledger/templates/ledger/partials/view-alliance-ledger/alliance-table.html +24 -0
  118. ledger/templates/ledger/partials/view-alliance-ledger/information/daily.html +18 -0
  119. ledger/templates/ledger/partials/view-alliance-ledger/information/hourly.html +18 -0
  120. ledger/templates/ledger/partials/view-alliance-ledger/information/summary.html +19 -0
  121. ledger/templates/ledger/partials/{administration → view-character-administration}/character.html +1 -9
  122. ledger/templates/ledger/partials/{administration → view-character-administration}/dashboard.html +0 -34
  123. ledger/templates/ledger/partials/view-character-ledger/character-billboard.html +25 -0
  124. ledger/templates/ledger/partials/view-character-ledger/character-ledger-details.html +21 -0
  125. ledger/templates/ledger/partials/view-character-ledger/character-table.html +25 -0
  126. ledger/templates/ledger/partials/view-character-ledger/information/daily.html +18 -0
  127. ledger/templates/ledger/partials/view-character-ledger/information/hourly.html +18 -0
  128. ledger/templates/ledger/partials/view-character-ledger/information/summary.html +19 -0
  129. ledger/templates/ledger/partials/view-character-planetary/extractor-table.html +24 -0
  130. ledger/templates/ledger/partials/view-character-planetary/factory-table.html +24 -0
  131. ledger/templates/ledger/partials/view-character-planetary/planetary-table.html +22 -0
  132. ledger/templates/ledger/partials/view-character-planetary/storage-table.html +23 -0
  133. ledger/templates/ledger/partials/{administration → view-corporation-administration}/corporation.html +5 -13
  134. ledger/templates/ledger/partials/{administration → view-corporation-administration}/corporation_characters.html +1 -1
  135. ledger/templates/ledger/partials/view-corporation-administration/dashboard.html +81 -0
  136. ledger/templates/ledger/partials/view-corporation-ledger/corporation-billboard.html +25 -0
  137. ledger/templates/ledger/partials/view-corporation-ledger/corporation-ledger-details.html +21 -0
  138. ledger/templates/ledger/partials/view-corporation-ledger/corporation-table.html +26 -0
  139. ledger/templates/ledger/partials/view-corporation-ledger/information/daily.html +18 -0
  140. ledger/templates/ledger/partials/view-corporation-ledger/information/hourly.html +18 -0
  141. ledger/templates/ledger/partials/view-corporation-ledger/information/summary.html +19 -0
  142. ledger/templates/ledger/view-administration.html +62 -0
  143. ledger/templates/ledger/view-alliance-administration.html +49 -0
  144. ledger/templates/ledger/view-alliance-ledger.html +72 -0
  145. ledger/templates/ledger/view-alliance-overview.html +131 -0
  146. ledger/templates/ledger/view-character-administration.html +42 -0
  147. ledger/templates/ledger/view-character-ledger.html +73 -0
  148. ledger/templates/ledger/view-character-overview.html +135 -0
  149. ledger/templates/ledger/view-character-planetary-overview.html +135 -0
  150. ledger/templates/ledger/view-character-planetary.html +73 -0
  151. ledger/templates/ledger/view-corporation-administration.html +42 -0
  152. ledger/templates/ledger/view-corporation-ledger.html +73 -0
  153. ledger/templates/ledger/view-corporation-overview.html +131 -0
  154. ledger/templatetags/ledger.py +3 -5
  155. ledger/tests/__init__.py +187 -0
  156. ledger/tests/test_admin.py +164 -68
  157. ledger/tests/test_auth_hook.py +31 -13
  158. ledger/tests/test_decarators.py +14 -79
  159. ledger/tests/test_discord_installed.py +0 -1
  160. ledger/tests/test_helpers/test_ledger_data.py +19 -0
  161. ledger/tests/test_managers/test_character_audit_manager.py +111 -69
  162. ledger/tests/test_managers/test_character_journal_manager.py +48 -208
  163. ledger/tests/test_managers/test_character_mining_manager.py +37 -16
  164. ledger/tests/test_managers/test_corporation_division_manager.py +66 -28
  165. ledger/tests/test_managers/test_corporation_journal_manager.py +39 -42
  166. ledger/tests/test_managers/test_general_manager.py +78 -18
  167. ledger/tests/test_managers/test_planetary_manager.py +73 -32
  168. ledger/tests/test_models/test_characteraudit.py +58 -74
  169. ledger/tests/test_models/test_characterminingledger.py +20 -26
  170. ledger/tests/test_models/test_characterwalletjournal.py +10 -33
  171. ledger/tests/test_models/test_corporationaudit.py +41 -35
  172. ledger/tests/test_models/test_corporationwalletjournal.py +35 -32
  173. ledger/tests/test_models/test_general.py +44 -11
  174. ledger/tests/test_models/test_planetary.py +14 -80
  175. ledger/tests/test_templatetags.py +2 -7
  176. ledger/tests/test_views/corporation/test_add_corp.py +16 -35
  177. ledger/tests/test_views/corporation/test_delete_corporation.py +66 -42
  178. ledger/tests/test_views/test_access.py +512 -545
  179. ledger/tests/test_views/test_add_ally.py +57 -46
  180. ledger/tests/test_views/test_add_char.py +21 -33
  181. ledger/tests/test_views/test_delete_character.py +24 -21
  182. ledger/tests/testdata/README_ESI_STUB.md +430 -0
  183. ledger/tests/testdata/esi_stub_openapi.py +511 -0
  184. ledger/tests/testdata/integrations/__init__.py +0 -0
  185. ledger/tests/testdata/{load_eveuniverse.py → integrations/eveuniverse.py} +0 -1
  186. ledger/tests/testdata/integrations/planetary.py +13 -0
  187. ledger/tests/testdata/json/factory.json +281 -0
  188. ledger/tests/testdata/json/inactive.json +281 -0
  189. ledger/tests/testdata/json/pins.json +175 -272
  190. ledger/tests/testdata/json/route.json +95 -528
  191. ledger/tests/testdata/test_esi_stub.py +468 -0
  192. ledger/tests/testdata/utils.py +601 -0
  193. ledger/thirdparty/charlink_hook.py +60 -30
  194. ledger/urls.py +0 -135
  195. ledger/views/alliance/add_ally.py +2 -4
  196. ledger/views/alliance/alliance_ledger.py +64 -147
  197. ledger/views/character/add_char.py +8 -10
  198. ledger/views/character/character_ledger.py +60 -126
  199. ledger/views/character/planetary.py +5 -98
  200. ledger/views/corporation/add_corp.py +10 -12
  201. ledger/views/corporation/corporation_ledger.py +65 -327
  202. ledger/views/index.py +92 -30
  203. aa_ledger-1.0.4.dist-info/RECORD +0 -236
  204. ledger/api/api_helper/planetary_helper.py +0 -107
  205. ledger/api/ledger/__init__.py +0 -7
  206. ledger/api/ledger/planetary.py +0 -231
  207. ledger/helpers/alliance.py +0 -317
  208. ledger/helpers/character.py +0 -251
  209. ledger/helpers/core.py +0 -665
  210. ledger/helpers/corporation.py +0 -427
  211. ledger/helpers/data_exporter.py +0 -452
  212. ledger/static/ledger/js/planetary-confirm.js +0 -66
  213. ledger/static/ledger/js/planetary.js +0 -143
  214. ledger/templates/ledger/admin.html +0 -43
  215. ledger/templates/ledger/allyledger/admin/alliance_administration.html +0 -46
  216. ledger/templates/ledger/allyledger/admin/alliance_overview.html +0 -108
  217. ledger/templates/ledger/allyledger/alliance_ledger.html +0 -86
  218. ledger/templates/ledger/bundles/character-ledger-bundles.html +0 -66
  219. ledger/templates/ledger/bundles/corporation-ledger-bundles.html +0 -75
  220. ledger/templates/ledger/bundles/ledger-bundles.html +0 -23
  221. ledger/templates/ledger/bundles/ledger-css.html +0 -3
  222. ledger/templates/ledger/bundles/planetary-bundles.html +0 -50
  223. ledger/templates/ledger/bundles/table-css.html +0 -3
  224. ledger/templates/ledger/charledger/admin/character_administration.html +0 -39
  225. ledger/templates/ledger/charledger/admin/character_overview.html +0 -106
  226. ledger/templates/ledger/charledger/character_ledger.html +0 -94
  227. ledger/templates/ledger/charledger/planetary/admin/planetary_overview.html +0 -123
  228. ledger/templates/ledger/charledger/planetary/planetary_ledger.html +0 -54
  229. ledger/templates/ledger/corpledger/admin/corporation_administration.html +0 -39
  230. ledger/templates/ledger/corpledger/admin/corporation_overview.html +0 -108
  231. ledger/templates/ledger/corpledger/corporation_ledger.html +0 -129
  232. ledger/templates/ledger/data-export.html +0 -78
  233. ledger/templates/ledger/error.html +0 -31
  234. ledger/templates/ledger/partials/form/error-message.html +0 -1
  235. ledger/templates/ledger/partials/information/daily.html +0 -56
  236. ledger/templates/ledger/partials/information/day.html +0 -48
  237. ledger/templates/ledger/partials/information/error.html +0 -8
  238. ledger/templates/ledger/partials/information/hourly.html +0 -53
  239. ledger/templates/ledger/partials/information/summary.html +0 -88
  240. ledger/templates/ledger/partials/information/view_character_content.html +0 -35
  241. ledger/templates/ledger/partials/modal/switchalarm_confirm.html +0 -39
  242. ledger/templates/ledger/partials/modal/view_extractor.html +0 -48
  243. ledger/templates/ledger/partials/modal/view_factory.html +0 -123
  244. ledger/templates/ledger/partials/table/char-ledger.html +0 -85
  245. ledger/templates/ledger/partials/table/corp-ledger.html +0 -66
  246. ledger/templates/ledger/partials/table/planetary.html +0 -18
  247. ledger/templates/ledger/partials/thirdparty/billboard.html +0 -22
  248. ledger/templates/ledger/partials/view/card.html +0 -160
  249. ledger/templates/ledger/permission.html +0 -2
  250. ledger/tests/test_helpers/test_billboard.py +0 -11
  251. ledger/tests/test_helpers/test_data_exporter.py +0 -207
  252. ledger/tests/test_tasks.py +0 -282
  253. ledger/tests/test_view_helpers/test_core.py +0 -47
  254. ledger/tests/test_views/corporation/test_corporation.py +0 -267
  255. ledger/tests/test_views/test_planetary.py +0 -137
  256. ledger/tests/testdata/esi_stub.py +0 -109
  257. ledger/tests/testdata/esi_stub_migration.py +0 -80
  258. ledger/tests/testdata/generate_characteraudit.py +0 -106
  259. ledger/tests/testdata/generate_corporationaudit.py +0 -74
  260. ledger/tests/testdata/generate_events.py +0 -31
  261. ledger/tests/testdata/generate_miningledger.py +0 -13
  262. ledger/tests/testdata/generate_planets.py +0 -48
  263. ledger/tests/testdata/generate_walletjournal.py +0 -42
  264. ledger/tests/testdata/json/czarno-pins.json +0 -240
  265. ledger/tests/testdata/json/czarno-routes.json +0 -165
  266. ledger/tests/testdata/json/pins2.json +0 -538
  267. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/WHEEL +0 -0
  268. {aa_ledger-1.0.4.dist-info → aa_ledger-2.0.0.dist-info}/licenses/LICENSE +0 -0
  269. /ledger/{tests/test_view_helpers → api/helpers}/__init__.py +0 -0
  270. /ledger/templates/ledger/bundles/{ally-administration-bundles.html → view-alliance-administration-js.html} +0 -0
  271. /ledger/templates/ledger/bundles/{char-administration-bundles.html → view-character-administration-js.html} +0 -0
  272. /ledger/templates/ledger/bundles/{corp-administration-bundles.html → view-corporation-administration-js.html} +0 -0
  273. /ledger/templates/ledger/partials/{administration → view-alliance-administration}/alliance.html +0 -0
  274. /ledger/tests/testdata/{esi.json → esi_test_data.json} +0 -0
  275. /ledger/tests/testdata/{allianceauth.json → integrations/allianceauth.json} +0 -0
  276. /ledger/tests/testdata/{load_allianceauth.py → integrations/allianceauth.py} +0 -0
  277. /ledger/tests/testdata/{eveentity.json → integrations/eveentity.json} +0 -0
  278. /ledger/tests/testdata/{load_eveentity.py → integrations/eveentity.py} +0 -0
  279. /ledger/tests/testdata/{eveuniverse.json → integrations/eveuniverse.json} +0 -0
  280. /ledger/tests/testdata/{planetary.json → integrations/planetary.json} +0 -0
@@ -0,0 +1,468 @@
1
+ """
2
+ Example tests demonstrating usage of the ESI OpenAPI stub system.
3
+ """
4
+
5
+ # Standard Library
6
+ from unittest.mock import patch
7
+
8
+ # Third Party
9
+ # AA TaxSystem
10
+ # AA Taxsystem
11
+ from taxsystem.tests import NoSocketsTestCase
12
+ from taxsystem.tests.testdata.esi_stub_openapi import (
13
+ EsiEndpoint,
14
+ create_esi_client_stub,
15
+ )
16
+
17
+ # Alliance Auth
18
+ from esi.exceptions import HTTPClientError, HTTPNotModified, HTTPServerError
19
+
20
+ # Example test data configuration
21
+ EXAMPLE_TEST_DATA = {
22
+ "Skills": {
23
+ "GetCharactersCharacterIdSkills": {
24
+ "skills": [
25
+ {"skill_id": 12345, "trained_skill_level": 5, "active_skill_level": 5},
26
+ {"skill_id": 67890, "trained_skill_level": 3, "active_skill_level": 3},
27
+ ],
28
+ "total_sp": 50000000,
29
+ "unallocated_sp": 100000,
30
+ },
31
+ "GetCharactersCharacterIdSkillqueue": [
32
+ {
33
+ "skill_id": 11111,
34
+ "finished_level": 4,
35
+ "queue_position": 0,
36
+ "finish_date": "2025-12-31T23:59:59Z",
37
+ "start_date": "2025-12-01T00:00:00Z",
38
+ "training_start_sp": 100000,
39
+ "level_start_sp": 50000,
40
+ "level_end_sp": 150000,
41
+ },
42
+ {
43
+ "skill_id": 22222,
44
+ "finished_level": 5,
45
+ "queue_position": 1,
46
+ "finish_date": "2026-01-15T12:00:00Z",
47
+ "start_date": "2025-12-31T23:59:59Z",
48
+ "training_start_sp": 200000,
49
+ "level_start_sp": 150000,
50
+ "level_end_sp": 300000,
51
+ },
52
+ ],
53
+ },
54
+ "Character": {
55
+ "GetCharactersCharacterId": {
56
+ "character_id": 12345678,
57
+ "name": "Test Character",
58
+ "corporation_id": 98765432,
59
+ "birthday": "2015-03-24T11:37:00Z",
60
+ },
61
+ },
62
+ }
63
+
64
+ # Example endpoints for basic tests
65
+ EXAMPLE_ENDPOINTS = [
66
+ EsiEndpoint("Character", "GetCharactersCharacterId", "character_id"),
67
+ EsiEndpoint("Skills", "GetCharactersCharacterIdSkills", "character_id"),
68
+ EsiEndpoint("Skills", "GetCharactersCharacterIdSkillqueue", "character_id"),
69
+ ]
70
+
71
+
72
+ class TestEsiStubUsage(NoSocketsTestCase):
73
+ """Example tests showing how to use the ESI stub system."""
74
+
75
+ def test_should_return_single_result(self):
76
+ """
77
+ Test should return single result using result() method.
78
+ """
79
+ # Create a stub with example data and endpoints
80
+ stub = create_esi_client_stub(EXAMPLE_TEST_DATA, endpoints=EXAMPLE_ENDPOINTS)
81
+ # Simulate an ESI call that returns a single result
82
+ operation = stub.Character.GetCharactersCharacterId(character_id=12345678)
83
+ result = operation.result()
84
+ # Verify the data - now using attributes instead of dict keys
85
+ self.assertEqual(result.character_id, 12345678)
86
+ self.assertEqual(result.name, "Test Character")
87
+ self.assertEqual(result.corporation_id, 98765432)
88
+
89
+ def test_should_return_list(self):
90
+ """
91
+ Test should return list of results using results() method.
92
+ """
93
+ # Create a stub with example data and endpoints
94
+ stub = create_esi_client_stub(EXAMPLE_TEST_DATA, endpoints=EXAMPLE_ENDPOINTS)
95
+ # Simulate an ESI call that returns a list of results
96
+ operation = stub.Skills.GetCharactersCharacterIdSkillqueue(
97
+ character_id=12345678
98
+ )
99
+ results = operation.results()
100
+ # Verify the data - now using attributes
101
+ self.assertIsInstance(results, list)
102
+ self.assertEqual(len(results), 2)
103
+ self.assertEqual(results[0].skill_id, 11111)
104
+ self.assertEqual(results[1].skill_id, 22222)
105
+
106
+ def test_should_create_stub_with_custom_data(self):
107
+ """
108
+ Test should create stub with custom test data and return custom values.
109
+ """
110
+ # Define custom test data
111
+ custom_data = {
112
+ "Skills": {
113
+ "GetCharactersCharacterIdSkills": {
114
+ "skills": [
115
+ {
116
+ "skill_id": 99999,
117
+ "trained_skill_level": 5,
118
+ "active_skill_level": 5,
119
+ }
120
+ ],
121
+ "total_sp": 1000000,
122
+ "unallocated_sp": 0,
123
+ }
124
+ }
125
+ }
126
+ # Define endpoints
127
+ endpoints = [
128
+ EsiEndpoint("Skills", "GetCharactersCharacterIdSkills", "character_id"),
129
+ ]
130
+ # Create stub with custom data and endpoints
131
+ stub = create_esi_client_stub(custom_data, endpoints=endpoints)
132
+ # Use the stub
133
+ operation = stub.Skills.GetCharactersCharacterIdSkills(character_id=12345)
134
+ result = operation.result()
135
+ # Verify custom data is returned - using attributes
136
+ self.assertEqual(result.total_sp, 1000000)
137
+ self.assertEqual(len(result.skills), 1)
138
+ self.assertEqual(result.skills[0].skill_id, 99999)
139
+
140
+ @patch("taxsystem.providers.esi")
141
+ def test_should_mock_esi(self, mock_esi):
142
+ """
143
+ Test should mock esi provider to return the stub client.
144
+ """
145
+ # Create a stub with endpoints
146
+ stub = create_esi_client_stub(EXAMPLE_TEST_DATA, endpoints=EXAMPLE_ENDPOINTS)
147
+ # Make mock.client return our stub
148
+ type(mock_esi).client = property(lambda self: stub)
149
+ # Now when code calls esi.client, it will get our stub - Verify it works
150
+ self.assertEqual(mock_esi.client, stub)
151
+
152
+ def test_should_handle_nested_data_structures(self):
153
+ """
154
+ Test should handle stub with nested data structures correctly.
155
+ """
156
+ # Create stub with example data and endpoints
157
+ stub = create_esi_client_stub(EXAMPLE_TEST_DATA, endpoints=EXAMPLE_ENDPOINTS)
158
+ # Simulate an ESI call that returns nested data
159
+ operation = stub.Skills.GetCharactersCharacterIdSkills(character_id=12345)
160
+ result = operation.result()
161
+ # Verify nested structure - using attributes
162
+ self.assertTrue(hasattr(result, "skills"))
163
+ self.assertIsInstance(result.skills, list)
164
+ self.assertEqual(result.skills[0].skill_id, 12345)
165
+
166
+ def test_should_support_dynamic_callable_data(self):
167
+ """
168
+ Test should support callable/dynamic test data based on input parameters.
169
+ """
170
+
171
+ def dynamic_skill_data(**kwargs):
172
+ """Return dynamic data based on skill_points parameter."""
173
+ skill_points = kwargs.get("skill_points", 0)
174
+ return {
175
+ "total_sp": skill_points, # SP based on input parameter
176
+ "skills": [],
177
+ "unallocated_sp": skill_points // 10, # 10% unallocated
178
+ }
179
+
180
+ # Create stub with callable data - using a custom parameter
181
+ custom_data = {
182
+ "Skills": {
183
+ "GetCharactersCharacterIdSkills": dynamic_skill_data,
184
+ }
185
+ }
186
+ endpoints = [
187
+ EsiEndpoint("Skills", "GetCharactersCharacterIdSkills", "skill_points"),
188
+ ]
189
+ stub = create_esi_client_stub(custom_data, endpoints=endpoints)
190
+ # Call with different skill_points values
191
+ op1 = stub.Skills.GetCharactersCharacterIdSkills(skill_points=1000000)
192
+ result1 = op1.result()
193
+ op2 = stub.Skills.GetCharactersCharacterIdSkills(skill_points=2000000)
194
+ result2 = op2.result()
195
+ # Verify dynamic data works - using attributes
196
+ self.assertEqual(result1.total_sp, 1000000)
197
+ self.assertEqual(result1.unallocated_sp, 100000)
198
+ self.assertEqual(result2.total_sp, 2000000)
199
+ self.assertEqual(result2.unallocated_sp, 200000)
200
+
201
+ def test_should_raise_attribute_error_for_unregistered_method(self):
202
+ """
203
+ Test should raise AttributeError when calling unregistered method.
204
+ """
205
+ endpoints = [
206
+ EsiEndpoint("Skills", "GetCharactersCharacterIdSkills", "character_id"),
207
+ ]
208
+ stub = create_esi_client_stub({"Skills": {}}, endpoints=endpoints)
209
+ # Call a method that isn't registered should raise AttributeError
210
+ with self.assertRaises(AttributeError) as context:
211
+ stub.Skills.SomeUnconfiguredMethod(character_id=12345)
212
+ self.assertIn("not registered", str(context.exception))
213
+
214
+ def test_should_wrap_single_item_in_list(self):
215
+ """
216
+ Test should wrap single items in a list when using results() method.
217
+ """
218
+ custom_data = {
219
+ "Test": {
220
+ "SingleItemMethod": {"id": 1, "name": "single"},
221
+ }
222
+ }
223
+ endpoints = [
224
+ EsiEndpoint("Test", "SingleItemMethod", "id"),
225
+ ]
226
+ stub = create_esi_client_stub(custom_data, endpoints=endpoints)
227
+
228
+ operation = stub.Test.SingleItemMethod()
229
+ results = operation.results()
230
+
231
+ # Single item should be wrapped in list - using attributes
232
+ self.assertIsInstance(results, list)
233
+ self.assertEqual(len(results), 1)
234
+ self.assertEqual(results[0].id, 1)
235
+
236
+ def test_should_return_tuple_with_response_on_result(self):
237
+ """
238
+ Test should return tuple with data and response when return_response=True for result() method.
239
+ """
240
+
241
+ stub = create_esi_client_stub(EXAMPLE_TEST_DATA, endpoints=EXAMPLE_ENDPOINTS)
242
+
243
+ operation = stub.Character.GetCharactersCharacterId(character_id=12345678)
244
+ data, response = operation.result(return_response=True)
245
+
246
+ self.assertEqual(data.character_id, 12345678)
247
+ self.assertEqual(response.status_code, 200)
248
+ self.assertIsInstance(response.headers, dict)
249
+
250
+ def test_should_return_tuple_with_response_on_results(self):
251
+ """
252
+ Test should return tuple with list data and response for results() method.
253
+ """
254
+
255
+ stub = create_esi_client_stub(EXAMPLE_TEST_DATA, endpoints=EXAMPLE_ENDPOINTS)
256
+
257
+ operation = stub.Skills.GetCharactersCharacterIdSkillqueue(
258
+ character_id=12345678
259
+ )
260
+ data, response = operation.results(return_response=True)
261
+
262
+ self.assertIsInstance(data, list)
263
+ self.assertEqual(len(data), 2)
264
+ self.assertEqual(response.status_code, 200)
265
+
266
+ def test_should_raise_http_not_modified_exception(self):
267
+ """
268
+ Test should raise HTTPNotModified exception via side_effect parameter.
269
+ """
270
+ # Define endpoints with side effects
271
+ _endpoints = [
272
+ EsiEndpoint(
273
+ "Character",
274
+ "GetCharactersCharacterId",
275
+ "character_id",
276
+ side_effect=HTTPNotModified(304, {}),
277
+ ),
278
+ ]
279
+ test_data = {
280
+ "Character": {
281
+ "GetCharactersCharacterId": {"character_id": 12345, "name": "Test"}
282
+ }
283
+ }
284
+ stub = create_esi_client_stub(test_data, endpoints=_endpoints)
285
+ operation = stub.Character.GetCharactersCharacterId(character_id=12345)
286
+ with self.assertRaises(HTTPNotModified):
287
+ operation.result()
288
+
289
+ def test_should_raise_http_client_error_exception(self):
290
+ """
291
+ Test should raise HTTPClientError exception via side_effect parameter.
292
+ """
293
+ _endpoints = [
294
+ EsiEndpoint(
295
+ "Skills",
296
+ "GetCharactersCharacterIdSkills",
297
+ "character_id",
298
+ side_effect=HTTPClientError(404, {}, b"Not Found"),
299
+ ),
300
+ ]
301
+ test_data = {
302
+ "Skills": {"GetCharactersCharacterIdSkills": {"total_sp": 0, "skills": []}}
303
+ }
304
+ stub = create_esi_client_stub(test_data, endpoints=_endpoints)
305
+ operation = stub.Skills.GetCharactersCharacterIdSkills(character_id=12345)
306
+ with self.assertRaises(HTTPClientError):
307
+ operation.result()
308
+
309
+ def test_should_raise_http_server_error_exception(self):
310
+ """
311
+ Test should raise HTTPServerError exception via side_effect parameter.
312
+ """
313
+ _endpoints = [
314
+ EsiEndpoint(
315
+ "Skills",
316
+ "GetCharactersCharacterIdSkillqueue",
317
+ "character_id",
318
+ side_effect=HTTPServerError(500, {}, b"Server Error"),
319
+ ),
320
+ ]
321
+ test_data = {"Skills": {"GetCharactersCharacterIdSkillqueue": []}}
322
+ stub = create_esi_client_stub(test_data, endpoints=_endpoints)
323
+ operation = stub.Skills.GetCharactersCharacterIdSkillqueue(character_id=12345)
324
+ with self.assertRaises(HTTPServerError):
325
+ operation.results()
326
+
327
+ def test_side_effect_os_error(self):
328
+ """
329
+ Test that OSError exception can be simulated via endpoints.
330
+ """
331
+ _endpoints = [
332
+ EsiEndpoint(
333
+ "Character",
334
+ "GetCharactersCharacterId",
335
+ "character_id",
336
+ side_effect=OSError("Connection timeout"),
337
+ ),
338
+ ]
339
+
340
+ test_data = {"Character": {"GetCharactersCharacterId": {"character_id": 12345}}}
341
+
342
+ stub = create_esi_client_stub(test_data, endpoints=_endpoints)
343
+ operation = stub.Character.GetCharactersCharacterId(character_id=12345)
344
+
345
+ # Should raise OSError
346
+ with self.assertRaises(OSError):
347
+ operation.result()
348
+
349
+ def test_endpoints_restrict_available_methods(self):
350
+ """
351
+ Test that only registered endpoints are available when endpoints are provided.
352
+ """
353
+ _endpoints = [
354
+ EsiEndpoint(
355
+ "Character",
356
+ "GetCharactersCharacterId",
357
+ "character_id",
358
+ ),
359
+ ]
360
+
361
+ test_data = {
362
+ "Character": {
363
+ "GetCharactersCharacterId": {"character_id": 12345, "name": "Test"},
364
+ "GetCharactersCharacterIdRoles": {"roles": []}, # Not registered
365
+ }
366
+ }
367
+
368
+ stub = create_esi_client_stub(test_data, endpoints=_endpoints)
369
+
370
+ # Registered endpoint should work
371
+ operation = stub.Character.GetCharactersCharacterId(character_id=12345)
372
+ result = operation.result()
373
+ self.assertEqual(result.character_id, 12345)
374
+
375
+ # Non-registered endpoint should raise AttributeError
376
+ with self.assertRaises(AttributeError) as context:
377
+ stub.Character.GetCharactersCharacterIdRoles(character_id=12345)
378
+
379
+ self.assertIn("not registered", str(context.exception))
380
+
381
+ def test_endpoints_restrict_available_categories(self):
382
+ """
383
+ Test that only categories with registered endpoints are available.
384
+ """
385
+ _endpoints = [
386
+ EsiEndpoint(
387
+ "Character",
388
+ "GetCharactersCharacterId",
389
+ "character_id",
390
+ ),
391
+ ]
392
+
393
+ test_data = {
394
+ "Character": {
395
+ "GetCharactersCharacterId": {"character_id": 12345, "name": "Test"}
396
+ },
397
+ "Skills": {
398
+ "GetCharactersCharacterIdSkills": {
399
+ "total_sp": 0
400
+ } # Category not registered
401
+ },
402
+ }
403
+
404
+ stub = create_esi_client_stub(test_data, endpoints=_endpoints)
405
+
406
+ # Registered category should work
407
+ operation = stub.Character.GetCharactersCharacterId(character_id=12345)
408
+ result = operation.result()
409
+ self.assertEqual(result.name, "Test")
410
+
411
+ # Non-registered category should raise AttributeError
412
+ with self.assertRaises(AttributeError) as context:
413
+ stub.Skills.GetCharactersCharacterIdSkills(character_id=12345)
414
+
415
+ self.assertIn("not registered", str(context.exception))
416
+
417
+ def test_endpoints_are_required(self):
418
+ """
419
+ Test that endpoints parameter is required.
420
+ """
421
+ test_data = {
422
+ "Character": {
423
+ "GetCharactersCharacterId": {"character_id": 12345, "name": "Test"}
424
+ }
425
+ }
426
+
427
+ # Should raise ValueError when no endpoints provided
428
+ with self.assertRaises(ValueError) as context:
429
+ create_esi_client_stub(test_data)
430
+
431
+ self.assertIn("endpoints parameter is required", str(context.exception))
432
+
433
+ def test_multiple_endpoints_mixed(self):
434
+ """
435
+ Test multiple endpoints with and without side effects.
436
+ """
437
+ _endpoints = [
438
+ EsiEndpoint(
439
+ "Character",
440
+ "GetCharactersCharacterId",
441
+ "character_id",
442
+ side_effect=HTTPNotModified(304, {}),
443
+ ),
444
+ EsiEndpoint(
445
+ "Skills",
446
+ "GetCharactersCharacterIdSkills",
447
+ "character_id",
448
+ ),
449
+ ]
450
+
451
+ test_data = {
452
+ "Character": {"GetCharactersCharacterId": {"character_id": 12345}},
453
+ "Skills": {
454
+ "GetCharactersCharacterIdSkills": {"total_sp": 5000000, "skills": []}
455
+ },
456
+ }
457
+
458
+ stub = create_esi_client_stub(test_data, endpoints=_endpoints)
459
+
460
+ # Character endpoint should raise exception
461
+ char_op = stub.Character.GetCharactersCharacterId(character_id=12345)
462
+ with self.assertRaises(HTTPNotModified):
463
+ char_op.result()
464
+
465
+ # Skills endpoint should return normal data
466
+ skills_op = stub.Skills.GetCharactersCharacterIdSkills(character_id=12345)
467
+ skills_result = skills_op.result()
468
+ self.assertEqual(skills_result.total_sp, 5000000)