tts-data-utils 0.7.3__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 (72) hide show
  1. tts_data_utils/__init__.py +0 -0
  2. tts_data_utils/core/__init__.py +0 -0
  3. tts_data_utils/core/container_history.py +79 -0
  4. tts_data_utils/core/data_container.py +2102 -0
  5. tts_data_utils/core/data_item.py +487 -0
  6. tts_data_utils/core/diff.py +155 -0
  7. tts_data_utils/core/generic.py +78 -0
  8. tts_data_utils/core/lorem_utils.py +206 -0
  9. tts_data_utils/core/visual_diff.py +148 -0
  10. tts_data_utils/invulnerable_data_manager/__init__.py +0 -0
  11. tts_data_utils/invulnerable_data_manager/batch.py +176 -0
  12. tts_data_utils/invulnerable_data_manager/invulnerable_data_manager.py +171 -0
  13. tts_data_utils/invulnerable_data_manager/utilities.py +151 -0
  14. tts_data_utils/multimission/__init__.py +0 -0
  15. tts_data_utils/multimission/alarms.py +109 -0
  16. tts_data_utils/multimission/eha.py +253 -0
  17. tts_data_utils/multimission/evr.py +340 -0
  18. tts_data_utils/multimission/evr_gaps.py +148 -0
  19. tts_data_utils/multimission/expected_lad.py +161 -0
  20. tts_data_utils/multimission/planning_rule.py +106 -0
  21. tts_data_utils/multimission/taco.py +53 -0
  22. tts_data_utils/test/__init__.py +0 -0
  23. tts_data_utils/test/core/__init__.py +0 -0
  24. tts_data_utils/test/core/test_data_container.py +403 -0
  25. tts_data_utils/test/core/test_data_item.py +92 -0
  26. tts_data_utils/test/core/test_diff.py +173 -0
  27. tts_data_utils/test/core/test_files/diff/diff_dict/actual_diff.csv +5135 -0
  28. tts_data_utils/test/core/test_files/diff/diff_dict/expected_diff.csv +5135 -0
  29. tts_data_utils/test/core/test_files/diff/diff_dict/left.csv +637 -0
  30. tts_data_utils/test/core/test_files/diff/diff_dict/right.csv +637 -0
  31. tts_data_utils/test/core/test_files/diff/diff_list/actual_diff.csv +5135 -0
  32. tts_data_utils/test/core/test_files/diff/diff_list/expected_diff.csv +5135 -0
  33. tts_data_utils/test/core/test_files/diff/diff_list/left.csv +637 -0
  34. tts_data_utils/test/core/test_files/diff/diff_list/right.csv +637 -0
  35. tts_data_utils/test/core/test_files/diff/diff_list_size/actual_diff.csv +33 -0
  36. tts_data_utils/test/core/test_files/diff/diff_list_size/expected_diff.csv +33 -0
  37. tts_data_utils/test/core/test_files/diff/diff_list_size/left.csv +637 -0
  38. tts_data_utils/test/core/test_files/diff/diff_list_size/right.csv +637 -0
  39. tts_data_utils/test/core/test_files/diff/diff_simple_types/actual_diff.csv +17894 -0
  40. tts_data_utils/test/core/test_files/diff/diff_simple_types/expected_diff.csv +17894 -0
  41. tts_data_utils/test/core/test_files/diff/diff_simple_types/left.csv +637 -0
  42. tts_data_utils/test/core/test_files/diff/diff_simple_types/right.csv +637 -0
  43. tts_data_utils/test/core/test_files/diff/diff_type/actual_diff.csv +5135 -0
  44. tts_data_utils/test/core/test_files/diff/diff_type/expected_diff.csv +5135 -0
  45. tts_data_utils/test/core/test_files/diff/diff_type/left.csv +637 -0
  46. tts_data_utils/test/core/test_files/diff/diff_type/right.csv +637 -0
  47. tts_data_utils/test/core/test_files/diff/same_not_same/actual_diff.csv +5135 -0
  48. tts_data_utils/test/core/test_files/visdiff/adjacent_insert_delete.html +1581 -0
  49. tts_data_utils/test/core/test_files/visdiff/insert_and_delete.html +1581 -0
  50. tts_data_utils/test/core/test_files/visdiff/no_diff.html +1581 -0
  51. tts_data_utils/test/core/test_files/visdiff/overlapping_insert_delete.html +1541 -0
  52. tts_data_utils/test/core/test_files/visdiff/replace.html +1581 -0
  53. tts_data_utils/test/core/test_files/visdiff/replace_with_delete.html +1581 -0
  54. tts_data_utils/test/core/test_files/visdiff/simple_delete.html +1581 -0
  55. tts_data_utils/test/core/test_files/visdiff/simple_insert.html +1581 -0
  56. tts_data_utils/test/core/test_files/visdiff/stressing_case.html +2061 -0
  57. tts_data_utils/test/core/test_filters.py +319 -0
  58. tts_data_utils/test/core/test_generic_container.py +22 -0
  59. tts_data_utils/test/core/test_history.py +44 -0
  60. tts_data_utils/test/core/test_visdiff.py +193 -0
  61. tts_data_utils/test/invulnerable_data_manager/test_invulnerable_data_manager.py +150 -0
  62. tts_data_utils/test/multimission/__init__.py +0 -0
  63. tts_data_utils/test/multimission/evr/__init__.py +0 -0
  64. tts_data_utils/test/multimission/evr/test_evr.py +29 -0
  65. tts_data_utils/test/multimission/evr/test_files/actual_evr_gaps.csv +12 -0
  66. tts_data_utils/test/multimission/evr/test_files/evrs_with_gaps.csv +30 -0
  67. tts_data_utils/test/multimission/evr/test_files/expected_evr_gaps.csv +12 -0
  68. tts_data_utils/util.py +104 -0
  69. tts_data_utils-0.7.3.dist-info/METADATA +81 -0
  70. tts_data_utils-0.7.3.dist-info/RECORD +72 -0
  71. tts_data_utils-0.7.3.dist-info/WHEEL +5 -0
  72. tts_data_utils-0.7.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,193 @@
1
+ #Standard Library Imports
2
+ from pathlib import Path
3
+ import pdb
4
+
5
+ #Installed Library Importsimport pytest
6
+ from datetime import datetime
7
+ import pytest
8
+
9
+ #Teamtool Studio Imports
10
+ from tts_utilities.logger import create_logger
11
+ from tts_utilities.test_utilities import safe_test_paths
12
+ from tts_html_utils.visdiff.visdiff import VisualDiff
13
+ from tts_html_utils.core.compiler import HtmlCompiler
14
+
15
+ #This Library Imports
16
+ from tts_data_utils.core.generic import GenericContainer
17
+
18
+ logger = create_logger(f'data_utils.core.filters')
19
+ TEST_INPUT_DIR, TEST_OUTPUT_DIR = safe_test_paths(Path(__file__).parent, 'test_files/visdiff')
20
+
21
+ def save_html(visdiff_left, visdiff_right, filepath):
22
+ power_table_left = visdiff_left.power_table(id='visdiff-left', style={'width': '130%', 'float': 'left'})
23
+ power_table_right = visdiff_right.power_table(id='visdiff-right', style={'width': '130%', 'float': 'right'})
24
+ compiler = HtmlCompiler('VisDiff Test')
25
+ compiler.add_body_component(VisualDiff(power_table_left, power_table_right))
26
+ file = open(filepath, 'w')
27
+ file.write(compiler.render())
28
+ file.close()
29
+
30
+ @pytest.fixture(scope="module")
31
+ def test_container():
32
+ time = [datetime.fromtimestamp(ii) for ii in range(100)]
33
+ col1 = [ii for ii in range(50)]*2
34
+ col2 = [ii for ii in range(100, 200)]
35
+ col3 = [str(ii) for ii in range(200, 300)]
36
+ col4 = [ii for ii in range(300, 400)]
37
+ col5 = [ii for ii in range(400, 500)]
38
+ raw_data = [{
39
+ 'Time': t,
40
+ 'Column 1': c1,
41
+ 'Column 2': c2,
42
+ 'Column 3': c3,
43
+ 'Column 4': c4,
44
+ 'Column 5': c5,
45
+ } for t, c1, c2, c3, c4, c5 in zip(time, col1, col2, col3, col4, col5)]
46
+ test_container = GenericContainer(raw_data=raw_data)
47
+ return test_container
48
+
49
+
50
+ class TestVisDiff:
51
+ def test_no_diff(self, test_container):
52
+ visdiff_left, visdiff_right = test_container.visual_diff(test_container)
53
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('no_diff.html'))
54
+
55
+ assert visdiff_left['_visdiff_match'] == ['equal']*100
56
+ assert visdiff_left['_visdiff_index'] == [ii for ii in range(100)]
57
+ assert visdiff_left['_mismatched_keys'] == [[]]*100
58
+
59
+ assert visdiff_right['_visdiff_match'] == ['equal']*100
60
+ assert visdiff_right['_visdiff_index'] == [ii for ii in range(100)]
61
+ assert visdiff_right['_mismatched_keys'] == [[]]*100
62
+
63
+ def test_simple_delete(self, test_container):
64
+ left = test_container
65
+ right = test_container[:10] + test_container[20:]
66
+ visdiff_left, visdiff_right = left.visual_diff(right)
67
+
68
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('simple_delete.html'))
69
+
70
+ assert visdiff_left['_visdiff_match'] == ['equal']*10 + ['delete']*10 + ['equal']*80
71
+ assert visdiff_left['_visdiff_index'] == [ii for ii in range(10)] + [None]*10 + [ii for ii in range(10, 90)]
72
+ assert visdiff_left['_mismatched_keys'] == [[]]*100
73
+
74
+ assert visdiff_right['_visdiff_match'] == ['equal']*10 + ['empty_from_delete']*10 + ['equal']*80
75
+ assert visdiff_right['_visdiff_index'] == [ii for ii in range(10)] + [None]*10 + [ii for ii in range(20, 100)]
76
+ assert visdiff_right['_mismatched_keys'] == [[]]*100
77
+
78
+ def test_simple_insert(self, test_container):
79
+ left = test_container[:10] + test_container[20:]
80
+ right = test_container
81
+ visdiff_left, visdiff_right = left.visual_diff(right)
82
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('simple_insert.html'))
83
+
84
+ assert visdiff_left['_visdiff_match'] == ['equal']*10 + ['empty_from_insert']*10 + ['equal']*80
85
+ assert visdiff_left['_visdiff_index'] == [ii for ii in range(10)] + [None]*10 + [ii for ii in range(20,100)]
86
+ assert visdiff_left['_mismatched_keys'] == [[]]*100
87
+
88
+ assert visdiff_right['_visdiff_match'] == ['equal']*10 + ['insert']*10 + ['equal']*80
89
+ assert visdiff_right['_visdiff_index'] == [ii for ii in range(10)] + [None]*10 + [ii for ii in range(10, 90)]
90
+ assert visdiff_right['_mismatched_keys'] == [[]]*100
91
+
92
+ def test_insert_and_delete(self, test_container):
93
+
94
+ left = test_container[:10] + test_container[20:]
95
+ right = test_container[:50] + test_container[60:]
96
+ visdiff_left, visdiff_right = left.visual_diff(right)
97
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('insert_and_delete.html'))
98
+
99
+ assert visdiff_left['_visdiff_match'] == ['equal']*10 + ['empty_from_insert']*10 + ['equal']*30 + ['delete']*10 + ['equal']*40
100
+ assert visdiff_left['_visdiff_index'] == [ii for ii in range(10)] + [None]*10 + [ii for ii in range(20,50)] + [None]*10 + [ii for ii in range(50, 90)]
101
+ assert visdiff_left['_mismatched_keys'] == [[]]*100
102
+
103
+ assert visdiff_right['_visdiff_match'] == ['equal']*10 + ['insert']*10 + ['equal']*30 + ['empty_from_delete']*10 + ['equal']*40
104
+ assert visdiff_right['_visdiff_index'] == [ii for ii in range(10)] + [None]*10 + [ii for ii in range(10,40)] + [None]*10 + [ii for ii in range(50, 90)]
105
+ assert visdiff_right['_mismatched_keys'] == [[]]*100
106
+
107
+
108
+ def test_adjacent_insert_delete(self, test_container):
109
+
110
+ left = test_container[:10] + test_container[20:]
111
+ right = test_container[:20] + test_container[30:]
112
+ visdiff_left, visdiff_right = left.visual_diff(right)
113
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('adjacent_insert_delete.html'))
114
+
115
+ assert visdiff_left['_visdiff_match'] == ['equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal']
116
+ assert visdiff_left['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
117
+ assert visdiff_left['_mismatched_keys'] == [[]]*100
118
+
119
+ assert visdiff_right['_visdiff_match'] == ['equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal']
120
+ assert visdiff_right['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
121
+ assert visdiff_right['_mismatched_keys'] == [[]]*100
122
+
123
+ def test_overlapping_insert_delete(self, test_container):
124
+ left = test_container[:10] + test_container[20:]
125
+ right = test_container[:15] + test_container[25:]
126
+ visdiff_left, visdiff_right = left.visual_diff(right)
127
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('overlapping_insert_delete.html'))
128
+
129
+ assert visdiff_left['_visdiff_match'] == ['equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'delete', 'delete', 'delete', 'delete', 'delete', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal']
130
+ assert visdiff_left['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, None, None, None, None, None, None, None, None, None, None, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
131
+ assert visdiff_left['_mismatched_keys'] == [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]
132
+
133
+ assert visdiff_right['_visdiff_match'] == ['equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'insert', 'insert', 'insert', 'insert', 'insert', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal', 'equal']
134
+ assert visdiff_right['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, None, None, None, None, None, None, None, None, None, None, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89]
135
+ assert visdiff_right['_mismatched_keys'] == [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]
136
+
137
+ def test_replace(self, test_container):
138
+ left = test_container._copy()
139
+ right = left._copy()
140
+ for ii in range(len(right)):
141
+ if ii%3 == 0: right[ii]['Column 1'] += 3
142
+ if ii%5 == 0: right[ii]['Column 2'] += 2
143
+
144
+ visdiff_left, visdiff_right = left.visual_diff(right)
145
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('replace.html'))
146
+
147
+ assert visdiff_left['_visdiff_match'] == ['replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace']
148
+ assert visdiff_left['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
149
+ assert visdiff_left['_mismatched_keys'] == [['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1']]
150
+
151
+ assert visdiff_right['_visdiff_match'] == ['replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace']
152
+ assert visdiff_right['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
153
+ assert visdiff_right['_mismatched_keys'] == [['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1']]
154
+
155
+ def test_replace_with_delete(self, test_container):
156
+ left = test_container._copy()
157
+ right = left._copy()
158
+ for ii in range(len(right)):
159
+ if ii%3 == 0: right[ii]['Column 1'] += 3
160
+ if ii%5 == 0: right[ii]['Column 2'] += 2
161
+ right = right[:20] + right[40:]
162
+
163
+ visdiff_left, visdiff_right = left.visual_diff(right)
164
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('replace_with_delete.html'))
165
+
166
+ assert visdiff_left['_visdiff_match'] == ['replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace']
167
+ assert visdiff_left['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
168
+ assert visdiff_left['_mismatched_keys'] == [['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], ['Column 2', '_visdiff_match', '_visdiff_index'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1']]
169
+
170
+ assert visdiff_right['_visdiff_match'] == ['replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace', 'replace', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'equal', 'replace', 'equal', 'replace', 'replace', 'equal', 'equal', 'replace']
171
+ assert visdiff_right['_visdiff_index'] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
172
+ assert visdiff_right['_mismatched_keys'] == [['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], ['Column 2', '_visdiff_index', '_mismatched_keys'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1'], ['Column 2'], [], ['Column 1'], [], [], ['Column 1', 'Column 2'], [], [], ['Column 1'], [], ['Column 2'], ['Column 1'], [], [], ['Column 1']]
173
+
174
+
175
+ def test_stressing_case(self, test_container):
176
+ left = test_container._copy()
177
+ right = left._copy()
178
+ for ii in range(len(right)):
179
+ right[ii]['Column 1'] += 3
180
+ right[ii]['Column 2'] += 2
181
+ left = left[:30] + left[50:]
182
+ right = right[:20] + right[40:]
183
+
184
+ visdiff_left, visdiff_right = left.visual_diff(right)
185
+ save_html(visdiff_left, visdiff_right, TEST_OUTPUT_DIR.joinpath('stressing_case.html'))
186
+
187
+ assert visdiff_left['_visdiff_match'] == ['delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'delete', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert', 'empty_from_insert']
188
+ assert visdiff_left['_visdiff_index'] == [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
189
+ assert visdiff_left['_mismatched_keys'] == [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]
190
+
191
+ assert visdiff_right['_visdiff_match'] == ['empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'empty_from_delete', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert', 'insert']
192
+ assert visdiff_right['_visdiff_index'] == [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None]
193
+ assert visdiff_right['_mismatched_keys'] == [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]
@@ -0,0 +1,150 @@
1
+ import pytest
2
+ from unittest.mock import MagicMock, patch
3
+ from tts_data_utils.invulnerable_data_manager.invulnerable_data_manager import InvulnerableDataManager
4
+ from tts_data_utils.core.generic import GenericContainer
5
+
6
+ # Simple concrete subclass for testing
7
+ class MockManager(InvulnerableDataManager):
8
+ def _impl_init_data(self, container_cls, data, name=None, **kwargs):
9
+ pass
10
+
11
+ # Mock Batcher for testing
12
+ class MockBatcher:
13
+ NAME = "test_batcher"
14
+ REQUIRED_DATA = ["required_input"]
15
+ def __init__(self, all_input_data, **kwargs):
16
+ self.all_input_data = all_input_data
17
+
18
+ @pytest.fixture
19
+ def mock_dependencies():
20
+ """
21
+ Patches internal dependencies so we test Manager logic in isolation.
22
+ """
23
+ # PATCH PATHS: We must patch where the names are IMPORTED/USED, not defined.
24
+ with patch('tts_data_utils.invulnerable_data_manager.invulnerable_data_manager.AllDataBatch') as MockAllData, \
25
+ patch('tts_data_utils.invulnerable_data_manager.invulnerable_data_manager.UntaggedBatch') as MockUntagged, \
26
+ patch('tts_data_utils.invulnerable_data_manager.invulnerable_data_manager.exec_invulnerable') as MockExec:
27
+
28
+ # 1. Configure AllDataBatch Mock Instance
29
+ mock_batch_instance = MockAllData.return_value
30
+
31
+ # Internal store for the mock to simulate state
32
+ mock_batch_instance._data_store = []
33
+
34
+ # Behavior: has_data checks the internal list
35
+ mock_batch_instance.has_data.side_effect = lambda name: name in mock_batch_instance._data_store
36
+
37
+ # Behavior: set_data_one adds to the internal list
38
+ def set_data_side_effect(name, data):
39
+ mock_batch_instance._data_store.append(name)
40
+ mock_batch_instance.set_data_one.side_effect = set_data_side_effect
41
+
42
+ # Behavior: get_inventory returns a dict (Code expects this method exists)
43
+ mock_batch_instance.get_inventory.return_value = {"mock_data": 1}
44
+
45
+ # 2. Configure exec_invulnerable Mock
46
+ # Default: Return a valid container
47
+ valid_container = MagicMock()
48
+ valid_container.valid = True
49
+ MockExec.return_value = valid_container
50
+
51
+ yield MockAllData, MockUntagged, MockExec
52
+
53
+ @pytest.fixture
54
+ def manager(mock_dependencies):
55
+ return MockManager()
56
+
57
+ @pytest.fixture
58
+ def valid_data():
59
+ return [{'id': 1, 'val': 'A'}]
60
+
61
+ class TestDataManagerIngestion:
62
+ def test_init_data_success(self, manager, valid_data):
63
+ """Verify successful ingestion and registration."""
64
+ manager.init_data(GenericContainer, valid_data, name="test_data")
65
+
66
+ # Verify the manager delegated to the internal batch storage
67
+ manager.all_input_data.set_data_one.assert_called()
68
+
69
+ # Verify inventory logic
70
+ # The code calls .get_inventory(), which we mocked to return {"mock_data": 1}
71
+ inv = manager.get_input_inventory()
72
+ assert "mock_data" in inv
73
+
74
+ def test_init_data_none_raises(self, manager):
75
+ """Verify that passing None results in an error (swallowed by @invulnerable)."""
76
+ manager.init_data(GenericContainer, None, name="fail_data")
77
+ # Verify set_data_one was NOT called
78
+ manager.all_input_data.set_data_one.assert_not_called()
79
+
80
+ def test_duplicate_init_raises(self, manager, valid_data):
81
+ """Verify that initializing the same name twice is caught."""
82
+ # Note: The code checks duplicate on `container_cls.NAME`.
83
+ # We omit 'name' kwarg here so it defaults to GenericContainer.NAME
84
+ # allowing the check to work correctly.
85
+
86
+ # First init
87
+ manager.init_data(GenericContainer, valid_data)
88
+
89
+ # Verify it was stored
90
+ assert manager.all_input_data.has_data(GenericContainer.NAME)
91
+
92
+ # Second init - should trigger ValueError internally
93
+ manager.init_data(GenericContainer, valid_data)
94
+
95
+ # Verify set_data_one was called exactly once (for the first success only)
96
+ assert manager.all_input_data.set_data_one.call_count == 1
97
+
98
+ def test_invalid_container_swallowed(self, manager, mock_dependencies):
99
+ """Verify that a container that fails validation isn't registered."""
100
+ _, _, mock_exec = mock_dependencies
101
+
102
+ # Configure exec_invulnerable to return an INVALID container for this test
103
+ invalid_container = MagicMock()
104
+ invalid_container.valid = False
105
+ mock_exec.return_value = invalid_container
106
+
107
+ manager.init_data(GenericContainer, [], name="invalid_container")
108
+
109
+ manager.all_input_data.set_data_one.assert_not_called()
110
+
111
+ class TestDataManagerBatching:
112
+ def test_init_batcher_missing_requirements(self, manager):
113
+ """Verify behavior when required data is missing."""
114
+ # Ensure the mock says we DO NOT have data
115
+ manager.all_input_data.has_data.return_value = False
116
+
117
+ manager.init_batcher(MockBatcher)
118
+
119
+ # Current Code Behavior: Logs warning but returns the Batcher (does not return None).
120
+ # We test for existence, acknowledging the permissive behavior.
121
+ assert manager.get_batcher("test_batcher") is not None
122
+
123
+ def test_init_batcher_success(self, manager, valid_data, mock_dependencies):
124
+ """Verify batcher registers when requirements are met."""
125
+ _, _, mock_exec = mock_dependencies
126
+
127
+ # 1. Satisfy requirements
128
+ # We manually force the mock to say "Yes, I have required_input"
129
+ manager.all_input_data._data_store.append("required_input")
130
+
131
+ # 2. Configure exec_invulnerable to return a valid Batcher
132
+ mock_batcher_instance = MagicMock()
133
+ mock_exec.return_value = mock_batcher_instance
134
+
135
+ manager.init_batcher(MockBatcher)
136
+
137
+ assert manager.get_batcher("test_batcher") is not None
138
+ # Verify untagged batch was re-initialized (Mock called)
139
+ assert manager._untagged_batch is not None
140
+
141
+ def test_comprehensive_inventory(self, manager, valid_data):
142
+ """Verify the data map returns both inputs and outputs."""
143
+ manager.init_data(GenericContainer, valid_data, name="input_1")
144
+
145
+ inventory = manager.get_data_inventory()
146
+
147
+ # Based on our mock setup in the fixture, get_inventory returns {"mock_data": 1}
148
+ # This applies to both Input and Output batches (same mock class)
149
+ assert "mock_data" in inventory['Inputs']
150
+ assert "mock_data" in inventory['Outputs']
File without changes
File without changes
@@ -0,0 +1,29 @@
1
+ #Standard Library Imports
2
+ import pytest
3
+ from datetime import datetime
4
+
5
+ #Installed Library Imports
6
+ from pathlib import Path
7
+ import pdb
8
+
9
+ #Teamtool Studio Imports
10
+ from tts_utilities.logger import create_logger
11
+ from tts_utilities.test_utilities import safe_test_paths
12
+
13
+ #This Library Imports
14
+ from tts_data_utils.multimission.evr import EvrContainer, EvrGapContainer
15
+
16
+ logger = create_logger(f'data_utils.multimission.evr')
17
+ TEST_INPUT_DIR, TEST_OUTPUT_DIR = safe_test_paths(Path(__file__).parent, 'test_files')
18
+
19
+ class TestEvrGaps:
20
+ def test_gap_finder(self):
21
+ evrs = EvrContainer(csv_path=TEST_INPUT_DIR.joinpath('evrs_with_gaps.csv'), cast_fields=True)
22
+ #evrs.gaps().to_csv(TEST_OUTPUT_DIR.joinpath('expected_evr_gaps.csv'))
23
+ expected_evr_gaps = EvrGapContainer(csv_path=TEST_INPUT_DIR.joinpath('expected_evr_gaps.csv'), cast_fields=True)
24
+ evrs.gaps().to_csv(TEST_OUTPUT_DIR.joinpath('actual_evr_gaps.csv'))
25
+
26
+ expected_evr_gaps.diff(evrs.gaps())
27
+ assert len(expected_evr_gaps.diff(evrs.gaps()).eq('Same', False)) == 0
28
+ assert len(expected_evr_gaps.diff(evrs.gaps())) == 236
29
+
@@ -0,0 +1,12 @@
1
+ Level,Begin Time (SCET),End Time (SCET),Begin Time (ERT),End Time (ERT),First Missing Index,Last Missing Index,Total Missing EVRs
2
+ DIAGNOSTIC,2010-001T00:02:25.004012,2010-001T00:02:25.004015,2025-072T17:13:47.592001,2025-072T17:13:47.592004,888,889,2
3
+ COMMAND,2010-001T00:02:25.004017,2010-001T00:02:25.004019,2025-072T17:13:47.592006,2025-072T17:13:47.592008,887,887,1
4
+ COMMAND,2010-001T00:02:25.004020,2010-001T00:02:25.004022,2025-072T17:13:47.592009,2025-072T17:13:47.592011,890,890,1
5
+ ACTIVITY_LO,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592013,2025-072T17:13:47.592016,888,889,2
6
+ ACTIVITY_HI,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592019,2025-072T17:13:47.592021,888,888,1
7
+ ACTIVITY_HI,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592021,2025-072T17:13:47.592023,890,890,1
8
+ WARNING_LO,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592026,2025-072T17:13:47.592029,889,890,2
9
+ WARNING_HI,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592033,2025-072T17:13:47.592035,890,890,1
10
+ FATAL,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592036,2025-072T17:13:47.592039,887,888,2
11
+ FATAL,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592039,2025-072T17:13:47.592042,890,891,2
12
+ FATAL,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592042,2025-072T17:13:47.592044,893,893,1
@@ -0,0 +1,30 @@
1
+ recordType,sessionId,sessionHost,name,module,level,eventId,vcid,dssId,fromSse,realtime,sclk,scet,ert,rct,lst,message,metadataKeywordList,metadataValuesList,metadata
2
+ Evr,38,srl-wsts-ms-1,MATCH_BY_EXACT_EVR_NAME,time_svc,DIAGNOSTIC,1048607,0,0,FALSE,TRUE,145.00401,2010-001T00:02:25.004011,2025-072T17:13:47.592000,2025-072T17:13:47.593000,,It doesn't matter what this message is,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(886),(1220),(009606)]","{'CategorySequenceId': '886', 'SequenceId': '1220', 'TaskName': '009606'}"
3
+ Evr,38,srl-wsts-ms-1,DONT_MATCH_BY_EXACT_EVR_NAME,time_svc,DIAGNOSTIC,1048607,0,0,FALSE,TRUE,146.00402,2010-001T00:02:25.004012,2025-072T17:13:47.592001,2025-072T17:13:47.593001,,It doesn't matter what this message is,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(886),(1220),(009606)]","{'CategorySequenceId': '887', 'SequenceId': '1221', 'TaskName': '009606'}"
4
+ Evr,38,srl-wsts-ms-1,MATCH_BY_EVR_NAME_REGEX_C,time_svc,DIAGNOSTIC,1048649,0,0,FALSE,TRUE,149.00405,2010-001T00:02:25.004015,2025-072T17:13:47.592004,2025-072T17:13:47.593004,,It doesn't matter what this message is,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(887),(1221),(009608)]","{'CategorySequenceId': '890', 'SequenceId': '1224', 'TaskName': '009608'}"
5
+ Evr,38,srl-wsts-ms-1,DONT_MATCH_BY_EVR_NAME_REGEX,time_svc,DIAGNOSTIC,1048649,0,0,FALSE,TRUE,150.00406,2010-001T00:02:25.004016,2025-072T17:13:47.592005,2025-072T17:13:47.593005,,It doesn't matter what this message is,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(887),(1221),(009608)]","{'CategorySequenceId': '891', 'SequenceId': '1225', 'TaskName': '009608'}"
6
+ Evr,38,srl-wsts-ms-1,MATCH_BY_EVR_NAME_WITH_MESSAGE_REGEX,time_svc,COMMAND,1048650,0,0,FALSE,TRUE,151.00407,2010-001T00:02:25.004017,2025-072T17:13:47.592006,2025-072T17:13:47.593006,,Please _-_-_-_ match 0909090 this qwqwqwq message.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '886', 'SequenceId': '1226', 'TaskName': '009608'}"
7
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_A,time_svc,COMMAND,1048650,0,0,FALSE,TRUE,153.00409,2010-001T00:02:25.004019,2025-072T17:13:47.592008,2025-072T17:13:47.593008,,Please _-_-_-_ match 0909090 this qwqwqwq message.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '888', 'SequenceId': '1228', 'TaskName': '009608'}"
8
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_B,time_svc,COMMAND,1048650,0,0,FALSE,TRUE,154.0041,2010-001T00:02:25.004020,2025-072T17:13:47.592009,2025-072T17:13:47.593009,,Please _-_-_-_ match 0909090 this qwqwqwq message.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '889', 'SequenceId': '1229', 'TaskName': '009608'}"
9
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_A,time_svc,COMMAND,1048650,0,0,FALSE,TRUE,145.00412,2010-001T00:02:25.004022,2025-072T17:13:47.592011,2025-072T17:13:47.593011,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '891', 'SequenceId': '1231', 'TaskName': '009608'}"
10
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_B,time_svc,ACTIVITY_LO,1048650,0,0,FALSE,TRUE,145.00413,2010-001T00:02:25.004023,2025-072T17:13:47.592012,2025-072T17:13:47.593012,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '886', 'SequenceId': '1232', 'TaskName': '009608'}"
11
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,ACTIVITY_LO,1048650,0,0,FALSE,TRUE,145.00414,2010-001T00:02:25.004024,2025-072T17:13:47.592013,2025-072T17:13:47.593013,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '887', 'SequenceId': '1233', 'TaskName': '009608'}"
12
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,ACTIVITY_LO,1048650,0,0,FALSE,TRUE,145.00417,2010-001T00:02:25.004024,2025-072T17:13:47.592016,2025-072T17:13:47.593016,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '890', 'SequenceId': '1236', 'TaskName': '009608'}"
13
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,ACTIVITY_LO,1048650,0,0,FALSE,TRUE,145.00418,2010-001T00:02:25.004024,2025-072T17:13:47.592017,2025-072T17:13:47.593017,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '891', 'SequenceId': '1237', 'TaskName': '009608'}"
14
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,ACTIVITY_HI,1048650,0,0,FALSE,TRUE,145.00419,2010-001T00:02:25.004024,2025-072T17:13:47.592018,2025-072T17:13:47.593018,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '886', 'SequenceId': '1238', 'TaskName': '009608'}"
15
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,ACTIVITY_HI,1048650,0,0,FALSE,TRUE,145.0042,2010-001T00:02:25.004024,2025-072T17:13:47.592019,2025-072T17:13:47.593019,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '887', 'SequenceId': '1239', 'TaskName': '009608'}"
16
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,ACTIVITY_HI,1048650,0,0,FALSE,TRUE,145.00422,2010-001T00:02:25.004024,2025-072T17:13:47.592021,2025-072T17:13:47.593021,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '889', 'SequenceId': '1241', 'TaskName': '009608'}"
17
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,ACTIVITY_HI,1048650,0,0,FALSE,TRUE,145.00424,2010-001T00:02:25.004024,2025-072T17:13:47.592023,2025-072T17:13:47.593023,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '891', 'SequenceId': '1243', 'TaskName': '009608'}"
18
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_LO,1048650,0,0,FALSE,TRUE,145.00425,2010-001T00:02:25.004024,2025-072T17:13:47.592024,2025-072T17:13:47.593024,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '886', 'SequenceId': '1244', 'TaskName': '009608'}"
19
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_LO,1048650,0,0,FALSE,TRUE,145.00426,2010-001T00:02:25.004024,2025-072T17:13:47.592025,2025-072T17:13:47.593025,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '887', 'SequenceId': '1245', 'TaskName': '009608'}"
20
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_LO,1048650,0,0,FALSE,TRUE,145.00427,2010-001T00:02:25.004024,2025-072T17:13:47.592026,2025-072T17:13:47.593026,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '888', 'SequenceId': '1246', 'TaskName': '009608'}"
21
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_LO,1048650,0,0,FALSE,TRUE,145.0043,2010-001T00:02:25.004024,2025-072T17:13:47.592029,2025-072T17:13:47.593029,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '891', 'SequenceId': '1249', 'TaskName': '009608'}"
22
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_HI,1048650,0,0,FALSE,TRUE,145.00431,2010-001T00:02:25.004024,2025-072T17:13:47.592030,2025-072T17:13:47.593030,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '886', 'SequenceId': '1250', 'TaskName': '009608'}"
23
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_HI,1048650,0,0,FALSE,TRUE,145.00432,2010-001T00:02:25.004024,2025-072T17:13:47.592031,2025-072T17:13:47.593031,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '887', 'SequenceId': '1251', 'TaskName': '009608'}"
24
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_HI,1048650,0,0,FALSE,TRUE,145.00433,2010-001T00:02:25.004024,2025-072T17:13:47.592032,2025-072T17:13:47.593032,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '888', 'SequenceId': '1252', 'TaskName': '009608'}"
25
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_HI,1048650,0,0,FALSE,TRUE,145.00434,2010-001T00:02:25.004024,2025-072T17:13:47.592033,2025-072T17:13:47.593033,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '889', 'SequenceId': '1253', 'TaskName': '009608'}"
26
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,WARNING_HI,1048650,0,0,FALSE,TRUE,145.00436,2010-001T00:02:25.004024,2025-072T17:13:47.592035,2025-072T17:13:47.593035,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '891', 'SequenceId': '1255', 'TaskName': '009608'}"
27
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,FATAL,1048650,0,0,FALSE,TRUE,145.00437,2010-001T00:02:25.004024,2025-072T17:13:47.592036,2025-072T17:13:47.593036,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '886', 'SequenceId': '1256', 'TaskName': '009608'}"
28
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,FATAL,1048650,0,0,FALSE,TRUE,145.0044,2010-001T00:02:25.004024,2025-072T17:13:47.592039,2025-072T17:13:47.593039,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '889', 'SequenceId': '1259', 'TaskName': '009608'}"
29
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,FATAL,1048650,0,0,FALSE,TRUE,145.00443,2010-001T00:02:25.004024,2025-072T17:13:47.592042,2025-072T17:13:47.593042,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '892', 'SequenceId': '1262', 'TaskName': '009608'}"
30
+ Evr,38,srl-wsts-ms-1,NAME_AND_REGEX_MATCH_C,time_svc,FATAL,1048650,0,0,FALSE,TRUE,145.15645,2010-001T00:02:25.004024,2025-072T17:13:47.592044,2025-072T17:13:47.593044,,But don't match this one.,"[(CategorySequenceId),(SequenceId),(TaskName)]","[(888),(1222),(009608)]","{'CategorySequenceId': '894', 'SequenceId': '1264', 'TaskName': '009608'}"
@@ -0,0 +1,12 @@
1
+ Level,Begin Time (SCET),End Time (SCET),Begin Time (ERT),End Time (ERT),First Missing Index,Last Missing Index,Total Missing EVRs
2
+ DIAGNOSTIC,2010-001T00:02:25.004012,2010-001T00:02:25.004015,2025-072T17:13:47.592001,2025-072T17:13:47.592004,888,889,2
3
+ COMMAND,2010-001T00:02:25.004017,2010-001T00:02:25.004019,2025-072T17:13:47.592006,2025-072T17:13:47.592008,887,887,1
4
+ COMMAND,2010-001T00:02:25.004020,2010-001T00:02:25.004022,2025-072T17:13:47.592009,2025-072T17:13:47.592011,890,890,1
5
+ ACTIVITY_LO,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592013,2025-072T17:13:47.592016,888,889,2
6
+ ACTIVITY_HI,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592019,2025-072T17:13:47.592021,888,888,1
7
+ ACTIVITY_HI,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592021,2025-072T17:13:47.592023,890,890,1
8
+ WARNING_LO,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592026,2025-072T17:13:47.592029,889,890,2
9
+ WARNING_HI,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592033,2025-072T17:13:47.592035,890,890,1
10
+ FATAL,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592036,2025-072T17:13:47.592039,887,888,2
11
+ FATAL,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592039,2025-072T17:13:47.592042,890,891,2
12
+ FATAL,2010-001T00:02:25.004024,2010-001T00:02:25.004024,2025-072T17:13:47.592042,2025-072T17:13:47.592044,893,893,1
tts_data_utils/util.py ADDED
@@ -0,0 +1,104 @@
1
+ import csv
2
+ import random
3
+ from datetime import datetime, timedelta
4
+
5
+ def generate_telemetry_csv(filename="demosat_telemetry.csv"):
6
+ # Schema keys from EhaItem.DICT_VALID_KEYS
7
+ fieldnames = [
8
+ 'recordType', 'sessionId', 'sessionHost', 'channelId', 'dssId',
9
+ 'vcid', 'name', 'module', 'ert', 'scet', 'rct', 'lst',
10
+ 'sclk', 'dn', 'dnStr', 'eu', 'status', 'dnAlarmState',
11
+ 'euAlarmState', 'realtime', 'type'
12
+ ]
13
+
14
+ # Configuration based on Channel.xml
15
+ channels = [
16
+ {"id": "EPS-0001", "name": "BATTERY_VOLTAGE", "mod": "eps", "vcid": 0},
17
+ {"id": "EPS-0002", "name": "BUS_CURRENT", "mod": "eps", "vcid": 0},
18
+ {"id": "INST-0003", "name": "CCD_TEMP", "mod": "inst", "vcid": 17},
19
+ {"id": "ADCS-2001", "name": "TARGET_LAT_ERR", "mod": "adcs", "vcid": 0},
20
+ {"id": "SYS-0002", "name": "BOOT_COUNT", "mod": "sys", "vcid": 0},
21
+ {"id": "ADCS-1001", "name": "EST_Q1", "mod": "adcs", "vcid": 0},
22
+ {"id": "ADCS-1002", "name": "EST_Q2", "mod": "adcs", "vcid": 0},
23
+ {"id": "ADCS-1003", "name": "EST_Q3", "mod": "adcs", "vcid": 0},
24
+ {"id": "ADCS-1004", "name": "EST_Q4", "mod": "adcs", "vcid": 0},
25
+ {"id": "TEL-0003", "name": "VCDU_COUNTER", "mod": "tel", "vcid": 17},
26
+ ]
27
+
28
+ base_scet = datetime(2026, 1, 25, 12, 0, 0)
29
+ base_sclk = 1737817192.0
30
+
31
+ with open(filename, mode='w', newline='') as f:
32
+ writer = csv.DictWriter(f, fieldnames=fieldnames)
33
+ writer.writeheader()
34
+
35
+ for ch in channels:
36
+ current_scet = base_scet
37
+ current_sclk = base_sclk
38
+
39
+ for i in range(50):
40
+ # 1. Create irregular timing (1-5 seconds jitter)
41
+ jitter = random.uniform(1.0, 5.0)
42
+ current_scet += timedelta(seconds=jitter)
43
+ current_sclk += jitter
44
+ ert = current_scet + timedelta(seconds=10) # 10s light delay simulation
45
+
46
+ # 2. Simulate Channel Logic & Alarm Violations
47
+ dn, eu, alarm = 0, 0.0, None
48
+
49
+ if ch['id'] == "EPS-0001": # Battery Voltage
50
+ # Start at 2200 DN (RED), drop to 1900 DN (NOMINAL)
51
+ dn = max(1900, 2200 - (i * 8))
52
+ eu = (0.00001 * (dn**2)) + (0.015 * dn) # Quadratic per XML
53
+ alarm = "RED" if eu > 32.5 else ("YELLOW" if eu > 31.8 else None)
54
+
55
+ elif ch['id'] == "EPS-0002": # Bus Current
56
+ # Random spikes to simulate heaters
57
+ eu = random.uniform(1.0, 2.0)
58
+ if i in [10, 11, 30, 31]: eu += 3.0 # Spike
59
+ dn = round(eu)
60
+ alarm = "RED" if eu > 4.5 else ("YELLOW" if eu > 3.5 else None)
61
+
62
+ elif ch['id'] == "INST-0003": # CCD Temp
63
+ # Linear slope: slope 0.12, intercept -50.0
64
+ dn = 500 + (i * 10)
65
+ eu = (dn * 0.12) - 50.0
66
+ alarm = "RED" if eu > 45.0 else ("YELLOW" if eu > 35.0 else None)
67
+
68
+ elif ch['id'] == "TEL-0003": # VCDU Counter
69
+ dn = 5000 + i
70
+ eu = float(dn)
71
+
72
+ else: # Default for Quaternions/Boots
73
+ dn = round(random.uniform(0, 1)) if "EST_Q" in ch['name'] else 12
74
+ eu = float(dn)
75
+
76
+ # 3. Write Row
77
+ writer.writerow({
78
+ 'recordType': 'EHA',
79
+ 'sessionId': 903,
80
+ 'sessionHost': 'GND-STN-01',
81
+ 'channelId': ch['id'],
82
+ 'dssId': 25,
83
+ 'vcid': ch['vcid'],
84
+ 'name': ch['name'],
85
+ 'module': ch['mod'],
86
+ 'ert': ert.strftime('%Y-%jT%H:%M:%S.%f')[:-3],
87
+ 'scet': current_scet.strftime('%Y-%jT%H:%M:%S.%f')[:-3],
88
+ 'rct': '',
89
+ 'lst': '',
90
+ 'sclk': current_sclk,
91
+ 'dn': dn,
92
+ 'dnStr': None,
93
+ 'eu': round(eu, 4),
94
+ 'status': None,
95
+ 'dnAlarmState': None,
96
+ 'euAlarmState': alarm,
97
+ 'realtime': True,
98
+ 'type': 'FSW'
99
+ })
100
+
101
+ print(f"Generated {filename} with 500 records.")
102
+
103
+ if __name__ == "__main__":
104
+ generate_telemetry_csv()