aa-intel-tool 2.10.0__py3-none-any.whl → 2.11.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 (101) hide show
  1. aa_intel_tool/__init__.py +3 -2
  2. aa_intel_tool/apps.py +5 -4
  3. aa_intel_tool/auth_hooks.py +2 -2
  4. aa_intel_tool/constants.py +9 -3
  5. aa_intel_tool/exceptions.py +1 -1
  6. aa_intel_tool/locale/cs_CZ/LC_MESSAGES/django.po +13 -17
  7. aa_intel_tool/locale/de/LC_MESSAGES/django.mo +0 -0
  8. aa_intel_tool/locale/de/LC_MESSAGES/django.po +21 -21
  9. aa_intel_tool/locale/django.pot +14 -18
  10. aa_intel_tool/locale/es/LC_MESSAGES/django.po +17 -17
  11. aa_intel_tool/locale/fr_FR/LC_MESSAGES/django.po +19 -17
  12. aa_intel_tool/locale/it_IT/LC_MESSAGES/django.po +13 -17
  13. aa_intel_tool/locale/ja/LC_MESSAGES/django.mo +0 -0
  14. aa_intel_tool/locale/ja/LC_MESSAGES/django.po +48 -48
  15. aa_intel_tool/locale/ko_KR/LC_MESSAGES/django.po +19 -17
  16. aa_intel_tool/locale/nl_NL/LC_MESSAGES/django.po +13 -17
  17. aa_intel_tool/locale/pl_PL/LC_MESSAGES/django.po +13 -17
  18. aa_intel_tool/locale/ru/LC_MESSAGES/django.po +19 -17
  19. aa_intel_tool/locale/sk/LC_MESSAGES/django.po +13 -17
  20. aa_intel_tool/locale/uk/LC_MESSAGES/django.mo +0 -0
  21. aa_intel_tool/locale/uk/LC_MESSAGES/django.po +23 -23
  22. aa_intel_tool/locale/zh_Hans/LC_MESSAGES/django.po +13 -17
  23. aa_intel_tool/parser/module/chatlist.py +3 -3
  24. aa_intel_tool/parser/module/dscan.py +4 -5
  25. aa_intel_tool/static/aa_intel_tool/css/aa-intel-tool.css +13 -16
  26. aa_intel_tool/static/aa_intel_tool/css/aa-intel-tool.min.css +1 -1
  27. aa_intel_tool/static/aa_intel_tool/css/aa-intel-tool.min.css.map +1 -1
  28. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-chatscan.js +171 -282
  29. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-chatscan.min.js +1 -1
  30. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-chatscan.min.js.map +1 -1
  31. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-dscan.js +251 -572
  32. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-dscan.min.js +1 -1
  33. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-dscan.min.js.map +1 -1
  34. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-fleetcomposition.js +163 -237
  35. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-fleetcomposition.min.js +1 -1
  36. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-fleetcomposition.min.js.map +1 -1
  37. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-scan-result-common.js +18 -0
  38. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-scan-result-common.min.js +1 -1
  39. aa_intel_tool/static/aa_intel_tool/javascript/aa-intel-tool-scan-result-common.min.js.map +1 -1
  40. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/dataTables.bootstrap5.css +610 -0
  41. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/dataTables.bootstrap5.js +123 -0
  42. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/dataTables.bootstrap5.min.css +8 -0
  43. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/dataTables.bootstrap5.min.css.map +1 -0
  44. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/dataTables.bootstrap5.min.js +6 -0
  45. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/dataTables.bootstrap5.min.js.map +1 -0
  46. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/datatables.min.js +10 -0
  47. aa_intel_tool/static/aa_intel_tool/libs/DataTables/2.3.4/datatables.min.js.map +1 -0
  48. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/css/columnControl.bootstrap5.css +516 -0
  49. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/css/columnControl.bootstrap5.min.css +2 -0
  50. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/css/columnControl.bootstrap5.min.css.map +1 -0
  51. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/js/columnControl.bootstrap5.js +73 -0
  52. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/js/columnControl.bootstrap5.min.js +6 -0
  53. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/js/columnControl.bootstrap5.min.js.map +1 -0
  54. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/js/dataTables.columnControl.js +3091 -0
  55. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/js/dataTables.columnControl.min.js +10 -0
  56. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/ColumnControl/1.1.1/js/dataTables.columnControl.min.js.map +1 -0
  57. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/css/fixedHeader.bootstrap5.css +20 -0
  58. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/css/fixedHeader.bootstrap5.min.css +2 -0
  59. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/css/fixedHeader.bootstrap5.min.css.map +1 -0
  60. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/js/dataTables.fixedHeader.js +1203 -0
  61. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/js/dataTables.fixedHeader.min.js +6 -0
  62. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/js/dataTables.fixedHeader.min.js.map +1 -0
  63. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/js/fixedHeader.bootstrap5.js +59 -0
  64. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/js/fixedHeader.bootstrap5.min.js +6 -0
  65. aa_intel_tool/static/aa_intel_tool/libs/DataTables/Extensions/FixedHeader/4.0.4/js/fixedHeader.bootstrap5.min.js.map +1 -0
  66. aa_intel_tool/templates/aa_intel_tool/base.html +30 -0
  67. aa_intel_tool/templates/aa_intel_tool/bundles/datatables-2-css.html +11 -0
  68. aa_intel_tool/templates/aa_intel_tool/bundles/datatables-2-js.html +14 -0
  69. aa_intel_tool/templates/aa_intel_tool/partials/scan/chatlist/alliances.html +1 -1
  70. aa_intel_tool/templates/aa_intel_tool/partials/scan/chatlist/corporations.html +1 -1
  71. aa_intel_tool/templates/aa_intel_tool/partials/scan/chatlist/pilots.html +1 -1
  72. aa_intel_tool/templates/aa_intel_tool/partials/scan/dscan/interesting-on-grid/items.html +1 -1
  73. aa_intel_tool/templates/aa_intel_tool/partials/scan/dscan/ships-breakdown/ship-classes.html +1 -1
  74. aa_intel_tool/templates/aa_intel_tool/partials/scan/dscan/ships-breakdown/ship-types.html +1 -1
  75. aa_intel_tool/templates/aa_intel_tool/partials/scan/fleetcomp/fleet-details/pilots.html +1 -1
  76. aa_intel_tool/templates/aa_intel_tool/views/scan/chatlist.html +2 -2
  77. aa_intel_tool/templates/aa_intel_tool/views/scan/dscan.html +2 -2
  78. aa_intel_tool/templates/aa_intel_tool/views/scan/fleetcomp.html +2 -2
  79. aa_intel_tool/tests/__init__.py +38 -0
  80. aa_intel_tool/tests/test_access.py +2 -2
  81. aa_intel_tool/tests/test_admin.py +4 -3
  82. aa_intel_tool/tests/test_app_settings.py +3 -2
  83. aa_intel_tool/tests/test_auth_hooks.py +2 -2
  84. aa_intel_tool/tests/test_helper_data_structures.py +2 -4
  85. aa_intel_tool/tests/test_helper_eve_character.py +5 -7
  86. aa_intel_tool/tests/test_models.py +3 -3
  87. aa_intel_tool/tests/test_parser_general.py +48 -34
  88. aa_intel_tool/tests/test_parser_helper_db.py +2 -4
  89. aa_intel_tool/tests/test_parser_module_chatlist.py +2 -2
  90. aa_intel_tool/tests/test_parser_module_dscan.py +828 -0
  91. aa_intel_tool/tests/test_parser_module_feetcomp.py +230 -0
  92. aa_intel_tool/tests/test_tasks.py +56 -0
  93. aa_intel_tool/tests/test_views_ajax.py +72 -0
  94. aa_intel_tool/tests/test_views_general.py +240 -0
  95. aa_intel_tool/urls.py +1 -1
  96. aa_intel_tool/views/general.py +13 -5
  97. {aa_intel_tool-2.10.0.dist-info → aa_intel_tool-2.11.0.dist-info}/METADATA +9 -7
  98. aa_intel_tool-2.11.0.dist-info/RECORD +169 -0
  99. aa_intel_tool-2.10.0.dist-info/RECORD +0 -136
  100. {aa_intel_tool-2.10.0.dist-info → aa_intel_tool-2.11.0.dist-info}/WHEEL +0 -0
  101. {aa_intel_tool-2.10.0.dist-info → aa_intel_tool-2.11.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,828 @@
1
+ """
2
+ Unit tests for the D-Scan parser module.
3
+ """
4
+
5
+ # Standard Library
6
+ from unittest.mock import MagicMock, patch
7
+
8
+ # AA Intel Tool
9
+ from aa_intel_tool.exceptions import ParserError
10
+ from aa_intel_tool.models import Scan, ScanData
11
+ from aa_intel_tool.parser.module.dscan import (
12
+ _get_ansiblex_jumpgate_destination,
13
+ _get_deployables_on_grid,
14
+ _get_scan_details,
15
+ _get_ships,
16
+ _get_starbases_on_grid,
17
+ _get_type_info_dict,
18
+ _get_upwell_structures_on_grid,
19
+ _is_on_grid,
20
+ parse,
21
+ )
22
+ from aa_intel_tool.tests import BaseTestCase
23
+
24
+
25
+ class TestParseDScan(BaseTestCase):
26
+ """
27
+ Testing the D-Scan parser
28
+ """
29
+
30
+ def test_raises_error_when_module_is_disabled(self):
31
+ with patch(
32
+ "aa_intel_tool.app_settings.AppSettings.INTELTOOL_ENABLE_MODULE_DSCAN",
33
+ False,
34
+ ):
35
+ with self.assertRaises(ParserError) as context:
36
+ parse(scan_data=[])
37
+
38
+ self.assertEqual(
39
+ str(context.exception),
40
+ "A parser error occurred » The D-Scan module is currently disabled.",
41
+ )
42
+
43
+ def test_returns_empty_scan_when_no_data_provided(self):
44
+ """
45
+ Testing that an empty scan returns empty parsed data
46
+
47
+ :return:
48
+ :rtype:
49
+ """
50
+
51
+ with (
52
+ patch(
53
+ "aa_intel_tool.app_settings.AppSettings.INTELTOOL_ENABLE_MODULE_DSCAN",
54
+ True,
55
+ ),
56
+ patch(
57
+ "aa_intel_tool.parser.module.dscan._get_scan_details",
58
+ return_value=(None, {}, {"all": []}),
59
+ ),
60
+ patch(
61
+ "aa_intel_tool.parser.module.dscan.EveType.objects.bulk_get_or_create_esi",
62
+ return_value=MagicMock(values_list=MagicMock(return_value=[])),
63
+ ),
64
+ patch(
65
+ "aa_intel_tool.parser.module.dscan._get_ships",
66
+ return_value={"all": [], "ongrid": [], "offgrid": [], "types": []},
67
+ ),
68
+ patch(
69
+ "aa_intel_tool.parser.module.dscan._get_upwell_structures_on_grid",
70
+ return_value={"all": [], "ongrid": [], "offgrid": [], "types": []},
71
+ ),
72
+ patch(
73
+ "aa_intel_tool.parser.module.dscan._get_deployables_on_grid",
74
+ return_value={"all": [], "ongrid": [], "offgrid": [], "types": []},
75
+ ),
76
+ patch(
77
+ "aa_intel_tool.parser.module.dscan._get_starbases_on_grid",
78
+ return_value={"all": [], "ongrid": [], "offgrid": [], "types": []},
79
+ ),
80
+ patch(
81
+ "aa_intel_tool.parser.module.dscan.safe_scan_to_db"
82
+ ) as mock_safe_scan_to_db,
83
+ ):
84
+ result = parse(scan_data=[])
85
+
86
+ expected_parsed = {
87
+ "structures_on_grid": {
88
+ "section": ScanData.Section.STRUCTURES_ON_GRID,
89
+ "data": {"all": [], "ongrid": [], "offgrid": [], "types": []},
90
+ },
91
+ "deployables": {
92
+ "section": ScanData.Section.DEPLOYABLES_ON_GRID,
93
+ "data": {"all": [], "ongrid": [], "offgrid": [], "types": []},
94
+ },
95
+ "starbases": {
96
+ "section": ScanData.Section.STARBASES_ON_GRID,
97
+ "data": {"all": [], "ongrid": [], "offgrid": [], "types": []},
98
+ },
99
+ }
100
+
101
+ mock_safe_scan_to_db.assert_called_once_with(
102
+ scan_type=Scan.Type.DSCAN, parsed_data=expected_parsed
103
+ )
104
+ self.assertEqual(result, mock_safe_scan_to_db.return_value)
105
+
106
+ def test_parses_scan_data_correctly(self):
107
+ """
108
+ Testing that scan data is parsed correctly
109
+
110
+ :return:
111
+ :rtype:
112
+ """
113
+
114
+ with (
115
+ patch(
116
+ "aa_intel_tool.app_settings.AppSettings.INTELTOOL_ENABLE_MODULE_DSCAN",
117
+ True,
118
+ ),
119
+ patch(
120
+ "aa_intel_tool.parser.module.dscan._get_scan_details",
121
+ return_value=("Destination", {"all": {1: 2}}, {"all": [1]}),
122
+ ),
123
+ patch(
124
+ "aa_intel_tool.parser.module.dscan.EveType.objects.bulk_get_or_create_esi"
125
+ ) as mock_bulk_get,
126
+ patch(
127
+ "aa_intel_tool.parser.module.dscan._get_ships",
128
+ return_value={
129
+ "all": ["ship1"],
130
+ "ongrid": [],
131
+ "offgrid": [],
132
+ "types": [],
133
+ },
134
+ ),
135
+ patch(
136
+ "aa_intel_tool.parser.module.dscan._get_upwell_structures_on_grid",
137
+ return_value=[],
138
+ ),
139
+ patch(
140
+ "aa_intel_tool.parser.module.dscan._get_deployables_on_grid",
141
+ return_value=[],
142
+ ),
143
+ patch(
144
+ "aa_intel_tool.parser.module.dscan._get_starbases_on_grid",
145
+ return_value=[],
146
+ ),
147
+ patch(
148
+ "aa_intel_tool.parser.module.dscan.safe_scan_to_db"
149
+ ) as mock_safe_scan_to_db,
150
+ ):
151
+ mock_bulk_get.return_value.values_list.return_value = [
152
+ (1, "Ship", 2, "Group", 1000)
153
+ ]
154
+
155
+ result = parse(scan_data=["some data"])
156
+
157
+ mock_safe_scan_to_db.assert_called_once_with(
158
+ scan_type=Scan.Type.DSCAN,
159
+ parsed_data={
160
+ "all": {"section": ScanData.Section.SHIPLIST, "data": ["ship1"]},
161
+ },
162
+ )
163
+ self.assertEqual(result, mock_safe_scan_to_db.return_value)
164
+
165
+
166
+ class TestHelperGetScanDetails(BaseTestCase):
167
+ """
168
+ Testing the _get_scan_details helper function
169
+ """
170
+
171
+ def test_returns_correct_details_for_valid_scan_data(self):
172
+ """
173
+ Testing that correct details are returned for valid scan data
174
+
175
+ :return:
176
+ :rtype:
177
+ """
178
+
179
+ scan_data = [
180
+ "123\tShip Name\tShip Class\t10 km",
181
+ "456\tStructure Name\tStructure Type\t100 km",
182
+ ]
183
+
184
+ with patch(
185
+ "aa_intel_tool.parser.module.dscan._is_on_grid",
186
+ side_effect=[True, False],
187
+ ):
188
+ ansiblex_destination, counter, eve_ids = _get_scan_details(
189
+ scan_data=scan_data
190
+ )
191
+
192
+ self.assertIsNone(ansiblex_destination)
193
+ self.assertEqual(counter["all"], {123: 1, 456: 1})
194
+ self.assertEqual(counter["ongrid"], {123: 1})
195
+ self.assertEqual(counter["offgrid"], {456: 1})
196
+ self.assertEqual(eve_ids["all"], [123, 456])
197
+ self.assertEqual(eve_ids["ongrid"], [123])
198
+ self.assertEqual(eve_ids["offgrid"], [456])
199
+
200
+ def test_handles_empty_scan_data(self):
201
+ """
202
+ Testing that empty scan data is handled correctly
203
+
204
+ :return:
205
+ :rtype:
206
+ """
207
+
208
+ scan_data = []
209
+
210
+ ansiblex_destination, counter, eve_ids = _get_scan_details(scan_data=scan_data)
211
+
212
+ self.assertIsNone(ansiblex_destination)
213
+ self.assertEqual(counter.get("all", {}), {})
214
+ self.assertEqual(counter.get("ongrid", {}), {})
215
+ self.assertEqual(counter.get("offgrid", {}), {})
216
+ self.assertEqual(eve_ids.get("all", []), [])
217
+ self.assertEqual(eve_ids.get("ongrid", []), [])
218
+ self.assertEqual(eve_ids.get("offgrid", []), [])
219
+
220
+ def test_raises_error_for_invalid_scan_data_format(self):
221
+ """
222
+ Testing that an error is raised for invalid scan data format
223
+
224
+ :return:
225
+ :rtype:
226
+ """
227
+
228
+ scan_data = ["Invalid Data"]
229
+
230
+ with self.assertRaises(AttributeError):
231
+ _get_scan_details(scan_data=scan_data)
232
+
233
+ def test_detects_ansiblex_jump_gate_destination(self):
234
+ scan_data = [
235
+ "35841\tC-N4OD » Jita - Der Geile Springen\tAnsiblex Jump Bridge\t2,748 km"
236
+ ]
237
+
238
+ ansiblex_destination, counter, eve_ids = _get_scan_details(scan_data=scan_data)
239
+
240
+ self.assertEqual(ansiblex_destination, "Jita")
241
+ self.assertEqual(counter["all"], {35841: 1})
242
+ self.assertEqual(counter["ongrid"], {35841: 1})
243
+ self.assertEqual(eve_ids["all"], [35841])
244
+ self.assertEqual(eve_ids["ongrid"], [35841])
245
+
246
+
247
+ class TestHelperGetAnsiblexJumpgateDestination(BaseTestCase):
248
+ """
249
+ Testing the _get_ansiblex_jumpgate_destination helper function
250
+ """
251
+
252
+ def test_returns_correct_destination_for_valid_ansiblex_name(self):
253
+ """
254
+ Testing that correct destination is returned for valid Ansiblex jumpgate name
255
+
256
+ :return:
257
+ :rtype:
258
+ """
259
+
260
+ ansiblex_name = "C-N4OD » Jita - Der Geile Springen"
261
+
262
+ result = _get_ansiblex_jumpgate_destination(ansiblex_name)
263
+
264
+ self.assertEqual(result, "Jita")
265
+
266
+ def test_handles_invalid_ansiblex_name_format(self):
267
+ """
268
+ Testing that invalid Ansiblex name format is handled
269
+
270
+ :return:
271
+ :rtype:
272
+ """
273
+
274
+ ansiblex_name = "Invalid Name Format"
275
+
276
+ with self.assertRaises(IndexError):
277
+ _get_ansiblex_jumpgate_destination(ansiblex_name)
278
+
279
+
280
+ class TestHelperGetStarbasesOnGrid(BaseTestCase):
281
+ """
282
+ Testing the _get_starbases_on_grid helper function
283
+ """
284
+
285
+ def test_returns_starbases_on_grid_with_valid_data(self):
286
+ """
287
+ Testing that starbases on grid are returned with valid data
288
+
289
+ :return:
290
+ :rtype:
291
+ """
292
+
293
+ eve_types = [
294
+ (1, "Starbase Alpha", 100, "Starbase Group", 0),
295
+ (2, "Starbase Beta", 101, "Starbase Group", 0),
296
+ ]
297
+ counter = {"ongrid": {1: 2, 2: 1}}
298
+
299
+ eve_types_qs = MagicMock()
300
+ eve_types_qs.filter.return_value = eve_types
301
+
302
+ with patch(
303
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
304
+ ) as mock_type_info:
305
+ mock_type_info.side_effect = lambda eve_type: {
306
+ "id": eve_type[0],
307
+ "name": eve_type[1],
308
+ "type_id": eve_type[2],
309
+ "type_name": eve_type[3],
310
+ "image": f"url/{eve_type[0]}",
311
+ }
312
+
313
+ result = _get_starbases_on_grid(eve_types=eve_types_qs, counter=counter)
314
+
315
+ self.assertEqual(len(result), 2)
316
+ self.assertEqual(result[0]["name"], "Starbase Alpha")
317
+ self.assertEqual(result[0]["count"], 2)
318
+ self.assertEqual(result[1]["name"], "Starbase Beta")
319
+ self.assertEqual(result[1]["count"], 1)
320
+
321
+ def test_returns_empty_list_when_no_starbases_on_grid(self):
322
+ """
323
+ Testing that an empty list is returned when no starbases are on grid
324
+
325
+ :return:
326
+ :rtype:
327
+ """
328
+
329
+ eve_types = [
330
+ (1, "Starbase Alpha", 100, "Starbase Group", 0),
331
+ (2, "Starbase Beta", 101, "Starbase Group", 0),
332
+ ]
333
+ counter = {"ongrid": {}}
334
+
335
+ eve_types_qs = MagicMock()
336
+ eve_types_qs.filter.return_value = eve_types
337
+
338
+ result = _get_starbases_on_grid(eve_types=eve_types_qs, counter=counter)
339
+
340
+ self.assertEqual(result, [])
341
+
342
+ def test_ignores_starbases_not_on_grid(self):
343
+ """
344
+ Testing that starbases not on grid are ignored
345
+
346
+ :return:
347
+ :rtype:
348
+ """
349
+
350
+ eve_types = [
351
+ (1, "Starbase Alpha", 100, "Starbase Group", 0),
352
+ (2, "Starbase Beta", 101, "Starbase Group", 0),
353
+ ]
354
+ counter = {"ongrid": {1: 2}}
355
+
356
+ eve_types_qs = MagicMock()
357
+ eve_types_qs.filter.return_value = eve_types
358
+
359
+ with patch(
360
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
361
+ ) as mock_type_info:
362
+ mock_type_info.side_effect = lambda eve_type: {
363
+ "id": eve_type[0],
364
+ "name": eve_type[1],
365
+ "type_id": eve_type[2],
366
+ "type_name": eve_type[3],
367
+ "image": f"url/{eve_type[0]}",
368
+ }
369
+
370
+ result = _get_starbases_on_grid(eve_types=eve_types_qs, counter=counter)
371
+
372
+ self.assertEqual(len(result), 1)
373
+ self.assertEqual(result[0]["name"], "Starbase Alpha")
374
+ self.assertEqual(result[0]["count"], 2)
375
+
376
+
377
+ class TestHelperGetDeployablesOnGrid(BaseTestCase):
378
+ """
379
+ Testing the _get_deployables_on_grid helper function
380
+ """
381
+
382
+ def test_returns_deployables_on_grid_with_valid_data(self):
383
+ """
384
+ Testing that deployables on grid are returned with valid data
385
+
386
+ :return:
387
+ :rtype:
388
+ """
389
+
390
+ eve_types = [
391
+ (1, "Deployable Alpha", 200, "Deployable Group", 0),
392
+ (2, "Deployable Beta", 201, "Deployable Group", 0),
393
+ ]
394
+ counter = {"ongrid": {1: 3, 2: 1}}
395
+
396
+ eve_types_qs = MagicMock()
397
+ eve_types_qs.filter.return_value = eve_types
398
+
399
+ with patch(
400
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
401
+ ) as mock_type_info:
402
+ mock_type_info.side_effect = lambda eve_type: {
403
+ "id": eve_type[0],
404
+ "name": eve_type[1],
405
+ "type_id": eve_type[2],
406
+ "type_name": eve_type[3],
407
+ "image": f"url/{eve_type[0]}",
408
+ }
409
+
410
+ result = _get_deployables_on_grid(eve_types=eve_types_qs, counter=counter)
411
+
412
+ self.assertEqual(len(result), 2)
413
+ self.assertEqual(result[0]["name"], "Deployable Alpha")
414
+ self.assertEqual(result[0]["count"], 3)
415
+ self.assertEqual(result[1]["name"], "Deployable Beta")
416
+ self.assertEqual(result[1]["count"], 1)
417
+
418
+ def test_returns_empty_list_when_no_deployables_on_grid(self):
419
+ """
420
+ Testing that an empty list is returned when no deployables are on grid
421
+
422
+ :return:
423
+ :rtype:
424
+ """
425
+
426
+ eve_types = [
427
+ (1, "Deployable Alpha", 200, "Deployable Group", 0),
428
+ (2, "Deployable Beta", 201, "Deployable Group", 0),
429
+ ]
430
+ counter = {"ongrid": {}}
431
+
432
+ eve_types_qs = MagicMock()
433
+ eve_types_qs.filter.return_value = eve_types
434
+
435
+ result = _get_deployables_on_grid(eve_types=eve_types_qs, counter=counter)
436
+
437
+ self.assertEqual(result, [])
438
+
439
+ def test_ignores_deployables_not_on_grid(self):
440
+ """
441
+ Testing that deployables not on grid are ignored
442
+
443
+ :return:
444
+ :rtype:
445
+ """
446
+
447
+ eve_types = [
448
+ (1, "Deployable Alpha", 200, "Deployable Group", 0),
449
+ (2, "Deployable Beta", 201, "Deployable Group", 0),
450
+ ]
451
+ counter = {"ongrid": {1: 2}}
452
+
453
+ eve_types_qs = MagicMock()
454
+ eve_types_qs.filter.return_value = eve_types
455
+
456
+ with patch(
457
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
458
+ ) as mock_type_info:
459
+ mock_type_info.side_effect = lambda eve_type: {
460
+ "id": eve_type[0],
461
+ "name": eve_type[1],
462
+ "type_id": eve_type[2],
463
+ "type_name": eve_type[3],
464
+ "image": f"url/{eve_type[0]}",
465
+ }
466
+
467
+ result = _get_deployables_on_grid(eve_types=eve_types_qs, counter=counter)
468
+
469
+ self.assertEqual(len(result), 1)
470
+ self.assertEqual(result[0]["name"], "Deployable Alpha")
471
+ self.assertEqual(result[0]["count"], 2)
472
+
473
+
474
+ class TestHelperGetUpwellStructuresOnGrid(BaseTestCase):
475
+ """
476
+ Testing the _get_upwell_structures_on_grid helper function
477
+ """
478
+
479
+ def test_returns_upwell_structures_on_grid_with_valid_data(self):
480
+ """
481
+ Testing that upwell structures on grid are returned with valid data
482
+
483
+ :return:
484
+ :rtype:
485
+ """
486
+
487
+ eve_types = [
488
+ (1, "Structure Alpha", 300, "Structure Group", 0),
489
+ (2, "Structure Beta", 301, "Structure Group", 0),
490
+ ]
491
+ counter = {"ongrid": {1: 2, 2: 1}}
492
+ ansiblex_destination = "System XYZ"
493
+
494
+ eve_types_qs = MagicMock()
495
+ eve_types_qs.filter.return_value = eve_types
496
+
497
+ with patch(
498
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
499
+ ) as mock_type_info:
500
+ mock_type_info.side_effect = lambda eve_type: {
501
+ "id": eve_type[0],
502
+ "name": eve_type[1],
503
+ "type_id": eve_type[2],
504
+ "type_name": eve_type[3],
505
+ "image": f"url/{eve_type[0]}",
506
+ }
507
+
508
+ result = _get_upwell_structures_on_grid(
509
+ eve_types=eve_types_qs,
510
+ counter=counter,
511
+ ansiblex_destination=ansiblex_destination,
512
+ )
513
+
514
+ self.assertEqual(len(result), 2)
515
+ self.assertEqual(result[0]["name"], "Structure Alpha")
516
+ self.assertEqual(result[1]["name"], "Structure Beta")
517
+
518
+ def test_returns_empty_list_when_no_upwell_structures_on_grid(self):
519
+ """
520
+ Testing that an empty list is returned when no upwell structures are on grid
521
+
522
+ :return:
523
+ :rtype:
524
+ """
525
+
526
+ eve_types = [
527
+ (1, "Structure Alpha", 300, "Structure Group", 0),
528
+ (2, "Structure Beta", 301, "Structure Group", 0),
529
+ ]
530
+ counter = {"ongrid": {}}
531
+
532
+ eve_types_qs = MagicMock()
533
+ eve_types_qs.filter.return_value = eve_types
534
+
535
+ result = _get_upwell_structures_on_grid(eve_types=eve_types_qs, counter=counter)
536
+
537
+ self.assertEqual(result, [])
538
+
539
+ def test_handles_ansiblex_jump_gate_with_destination(self):
540
+ """
541
+ Testing that Ansiblex jump gate with destination is handled
542
+
543
+ :return:
544
+ :rtype:
545
+ """
546
+
547
+ eve_types = [
548
+ (35841, "Ansiblex Jump Gate", 400, "Structure Group", 0),
549
+ ]
550
+ counter = {"ongrid": {35841: 1}}
551
+ ansiblex_destination = "System ABC"
552
+
553
+ eve_types_qs = MagicMock()
554
+ eve_types_qs.filter.return_value = eve_types
555
+
556
+ with patch(
557
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
558
+ ) as mock_type_info:
559
+ mock_type_info.side_effect = lambda eve_type: {
560
+ "id": eve_type[0],
561
+ "name": eve_type[1],
562
+ "type_id": eve_type[2],
563
+ "type_name": eve_type[3],
564
+ "image": f"url/{eve_type[0]}",
565
+ }
566
+
567
+ result = _get_upwell_structures_on_grid(
568
+ eve_types=eve_types_qs,
569
+ counter=counter,
570
+ ansiblex_destination=ansiblex_destination,
571
+ )
572
+
573
+ self.assertEqual(len(result), 1)
574
+ self.assertEqual(result[0]["name"], "Ansiblex Jump Gate » System ABC")
575
+
576
+
577
+ class TestHelperGetShips(BaseTestCase):
578
+ """
579
+ Testing the _get_ships helper function
580
+ """
581
+
582
+ def test_returns_all_ships_with_valid_data(self):
583
+ """
584
+ Testing that all ships are returned with valid data
585
+
586
+ :return:
587
+ :rtype:
588
+ """
589
+
590
+ eve_types = [
591
+ (1, "Ship Alpha", 100, "Frigate", 500),
592
+ (2, "Ship Beta", 101, "Destroyer", 1000),
593
+ ]
594
+ counter = {"all": {1: 3, 2: 2}, "ongrid": {1: 2}, "offgrid": {2: 1}}
595
+
596
+ eve_types_qs = MagicMock()
597
+ eve_types_qs.filter.return_value = eve_types
598
+
599
+ with patch(
600
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
601
+ ) as mock_type_info:
602
+ mock_type_info.side_effect = lambda eve_type: {
603
+ "id": eve_type[0],
604
+ "name": eve_type[1],
605
+ "type_id": eve_type[2],
606
+ "type_name": eve_type[3],
607
+ "image": f"url/{eve_type[0]}",
608
+ }
609
+
610
+ result = _get_ships(eve_types=eve_types_qs, counter=counter)
611
+
612
+ self.assertEqual(len(result["all"]), 2)
613
+ self.assertEqual(result["all"][0]["name"], "Ship Alpha")
614
+ self.assertEqual(result["all"][0]["count"], 3)
615
+ self.assertEqual(result["all"][0]["mass"], 1500)
616
+ self.assertEqual(result["all"][1]["name"], "Ship Beta")
617
+ self.assertEqual(result["all"][1]["count"], 2)
618
+ self.assertEqual(result["all"][1]["mass"], 2000)
619
+
620
+ def test_returns_empty_lists_when_no_ships(self):
621
+ """
622
+ Testing that empty lists are returned when no ships are present
623
+
624
+ :return:
625
+ :rtype:
626
+ """
627
+
628
+ eve_types = []
629
+ counter = {"all": {}, "ongrid": {}, "offgrid": {}}
630
+
631
+ eve_types_qs = MagicMock()
632
+ eve_types_qs.filter.return_value = eve_types
633
+
634
+ result = _get_ships(eve_types=eve_types_qs, counter=counter)
635
+
636
+ self.assertEqual(result["all"], [])
637
+ self.assertEqual(result["ongrid"], [])
638
+ self.assertEqual(result["offgrid"], [])
639
+ self.assertEqual(result["types"], [])
640
+
641
+ def test_separates_ships_into_correct_categories(self):
642
+ """
643
+ Testing that ships are separated into correct categories
644
+
645
+ :return:
646
+ :rtype:
647
+ """
648
+
649
+ eve_types = [
650
+ (1, "Ship Alpha", 100, "Frigate", 500),
651
+ (2, "Ship Beta", 101, "Destroyer", 1000),
652
+ ]
653
+ counter = {
654
+ "all": {1: 3, 2: 2},
655
+ "ongrid": {1: 2},
656
+ "offgrid": {2: 1},
657
+ }
658
+
659
+ eve_types_qs = MagicMock()
660
+ eve_types_qs.filter.return_value = eve_types
661
+
662
+ with patch(
663
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
664
+ ) as mock_type_info:
665
+ mock_type_info.side_effect = lambda eve_type: {
666
+ "id": eve_type[0],
667
+ "name": eve_type[1],
668
+ "type_id": eve_type[2],
669
+ "type_name": eve_type[3],
670
+ "image": f"url/{eve_type[0]}",
671
+ }
672
+
673
+ result = _get_ships(eve_types=eve_types_qs, counter=counter)
674
+
675
+ self.assertEqual(len(result["ongrid"]), 1)
676
+ self.assertEqual(result["ongrid"][0]["name"], "Ship Alpha")
677
+ self.assertEqual(result["ongrid"][0]["count"], 2)
678
+ self.assertEqual(len(result["offgrid"]), 1)
679
+ self.assertEqual(result["offgrid"][0]["name"], "Ship Beta")
680
+ self.assertEqual(result["offgrid"][0]["count"], 1)
681
+
682
+ def test_aggregates_ship_types_correctly(self):
683
+ """
684
+ Testing that ship types are aggregated correctly
685
+
686
+ :return:
687
+ :rtype:
688
+ """
689
+
690
+ eve_types = [
691
+ (1, "Ship Alpha", 100, "Frigate", 500),
692
+ (2, "Ship Beta", 101, "Frigate", 1000),
693
+ ]
694
+ counter = {"all": {1: 3, 2: 2}, "ongrid": {}, "offgrid": {}}
695
+
696
+ eve_types_qs = MagicMock()
697
+ eve_types_qs.filter.return_value = eve_types
698
+
699
+ with patch(
700
+ "aa_intel_tool.parser.module.dscan._get_type_info_dict"
701
+ ) as mock_type_info:
702
+ mock_type_info.side_effect = lambda eve_type: {
703
+ "id": eve_type[0],
704
+ "name": eve_type[1],
705
+ "type_id": eve_type[2],
706
+ "type_name": eve_type[3],
707
+ "image": f"url/{eve_type[0]}",
708
+ }
709
+
710
+ result = _get_ships(eve_types=eve_types_qs, counter=counter)
711
+
712
+ self.assertEqual(len(result["types"]), 1)
713
+ self.assertEqual(result["types"][0]["name"], "Frigate")
714
+ self.assertEqual(result["types"][0]["count"], 5)
715
+
716
+
717
+ class TestHelperGetTypeInfoDict(BaseTestCase):
718
+ """
719
+ Testing the _get_type_info_dict helper function
720
+ """
721
+
722
+ def test_returns_correct_dict_for_valid_eve_type(self):
723
+ """
724
+ Testing that correct dict is returned for valid eve type
725
+
726
+ :return:
727
+ :rtype:
728
+ """
729
+ eve_type = (123, "Test Ship", 456, "Test Group")
730
+
731
+ result = _get_type_info_dict(eve_type)
732
+
733
+ self.assertEqual(result["id"], 123)
734
+ self.assertEqual(result["name"], "Test Ship")
735
+ self.assertEqual(result["type_id"], 456)
736
+ self.assertEqual(result["type_name"], "Test Group")
737
+ self.assertIn(str(123), result["image"])
738
+
739
+ def test_handles_empty_eve_type_tuple(self):
740
+ """
741
+ Testing that empty eve type tuple is handled
742
+
743
+ :return:
744
+ :rtype:
745
+ """
746
+
747
+ eve_type = ()
748
+
749
+ with self.assertRaises(IndexError):
750
+ _get_type_info_dict(eve_type)
751
+
752
+ def test_handles_partial_eve_type_tuple(self):
753
+ """
754
+ Testing that partial eve type tuple is handled
755
+
756
+ :return:
757
+ :rtype:
758
+ """
759
+
760
+ eve_type = (123, "Test Ship")
761
+
762
+ with self.assertRaises(IndexError):
763
+ _get_type_info_dict(eve_type)
764
+
765
+ def test_handles_non_integer_id_in_eve_type(self):
766
+ """
767
+ Testing that non-integer ID in eve type is handled
768
+
769
+ :return:
770
+ :rtype:
771
+ """
772
+
773
+ eve_type = ("abc", "Test Ship", 456, "Test Group")
774
+
775
+ with self.assertRaises(ValueError):
776
+ _get_type_info_dict(eve_type)
777
+
778
+
779
+ class TestHelperIsOnGrid(BaseTestCase):
780
+ """
781
+ Testing the _is_on_grid helper function
782
+ """
783
+
784
+ def test_returns_true_for_distance_within_grid_size(self):
785
+ """
786
+ Testing that true is returned for distance within grid size
787
+
788
+ :return:
789
+ :rtype:
790
+ """
791
+
792
+ with patch(
793
+ "aa_intel_tool.app_settings.AppSettings.INTELTOOL_DSCAN_GRID_SIZE", 150
794
+ ):
795
+ self.assertTrue(_is_on_grid("100 km"))
796
+
797
+ def test_returns_false_for_distance_exceeding_grid_size(self):
798
+ """
799
+ Testing that false is returned for distance exceeding grid size
800
+
801
+ :return:
802
+ :rtype:
803
+ """
804
+
805
+ with patch(
806
+ "aa_intel_tool.app_settings.AppSettings.INTELTOOL_DSCAN_GRID_SIZE", 150
807
+ ):
808
+ self.assertFalse(_is_on_grid("200 km"))
809
+
810
+ def test_returns_false_for_invalid_distance_format(self):
811
+ """
812
+ Testing that false is returned for invalid distance format
813
+
814
+ :return:
815
+ :rtype:
816
+ """
817
+
818
+ self.assertFalse(_is_on_grid("invalid distance"))
819
+
820
+ def test_returns_false_for_empty_distance_string(self):
821
+ """
822
+ Testing that false is returned for empty distance string
823
+
824
+ :return:
825
+ :rtype:
826
+ """
827
+
828
+ self.assertFalse(_is_on_grid(""))