|
1 | 1 | import os |
| 2 | +import sys |
2 | 3 | import copy |
3 | 4 | import unittest |
4 | 5 | import numpy as np |
@@ -99,68 +100,94 @@ def test_load_complex_file(self): |
99 | 100 | trk = TrkFile.load(DATA['complex_trk_fname'], lazy_load=lazy_load) |
100 | 101 | assert_tractogram_equal(trk.tractogram, DATA['complex_tractogram']) |
101 | 102 |
|
| 103 | + def trk_with_bytes(self, trk_key='simple_trk_fname', endian='<'): |
| 104 | + """ Return example trk file bytes and struct view onto bytes """ |
| 105 | + with open(DATA[trk_key], 'rb') as fobj: |
| 106 | + trk_bytes = fobj.read() |
| 107 | + dt = trk_module.header_2_dtype.newbyteorder(endian) |
| 108 | + trk_struct = np.ndarray((1,), dt, buffer=trk_bytes) |
| 109 | + trk_struct.flags.writeable = True |
| 110 | + return trk_struct, trk_bytes |
| 111 | + |
102 | 112 | def test_load_file_with_wrong_information(self): |
103 | 113 | trk_file = open(DATA['simple_trk_fname'], 'rb').read() |
104 | 114 |
|
105 | 115 | # Simulate a TRK file where `count` was not provided. |
106 | | - count = np.array(0, dtype="int32").tostring() |
107 | | - new_trk_file = trk_file[:1000-12] + count + trk_file[1000-8:] |
108 | | - trk = TrkFile.load(BytesIO(new_trk_file), lazy_load=False) |
| 116 | + trk_struct, trk_bytes = self.trk_with_bytes() |
| 117 | + trk_struct[Field.NB_STREAMLINES] = 0 |
| 118 | + trk = TrkFile.load(BytesIO(trk_bytes), lazy_load=False) |
109 | 119 | assert_tractogram_equal(trk.tractogram, DATA['simple_tractogram']) |
110 | 120 |
|
111 | 121 | # Simulate a TRK where `vox_to_ras` is not recorded (i.e. all zeros). |
112 | | - vox_to_ras = np.zeros((4, 4), dtype=np.float32).tostring() |
113 | | - new_trk_file = trk_file[:440] + vox_to_ras + trk_file[440+64:] |
| 122 | + trk_struct, trk_bytes = self.trk_with_bytes() |
| 123 | + trk_struct[Field.VOXEL_TO_RASMM] = np.zeros((4, 4)) |
114 | 124 | with clear_and_catch_warnings(record=True, modules=[trk_module]) as w: |
115 | | - trk = TrkFile.load(BytesIO(new_trk_file)) |
| 125 | + trk = TrkFile.load(BytesIO(trk_bytes)) |
116 | 126 | assert_equal(len(w), 1) |
117 | 127 | assert_true(issubclass(w[0].category, HeaderWarning)) |
118 | 128 | assert_true("identity" in str(w[0].message)) |
119 | 129 | assert_array_equal(trk.affine, np.eye(4)) |
120 | 130 |
|
121 | 131 | # Simulate a TRK where `vox_to_ras` is invalid. |
122 | | - vox_to_ras = np.zeros((4, 4), dtype=np.float32) |
123 | | - vox_to_ras[3, 3] = 1 |
124 | | - vox_to_ras = vox_to_ras.tostring() |
125 | | - new_trk_file = trk_file[:440] + vox_to_ras + trk_file[440+64:] |
| 132 | + trk_struct, trk_bytes = self.trk_with_bytes() |
| 133 | + trk_struct[Field.VOXEL_TO_RASMM] = np.diag([0, 0, 0, 1]) |
126 | 134 | with clear_and_catch_warnings(record=True, modules=[trk_module]) as w: |
127 | | - assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) |
| 135 | + assert_raises(HeaderError, TrkFile.load, BytesIO(trk_bytes)) |
128 | 136 |
|
129 | 137 | # Simulate a TRK file where `voxel_order` was not provided. |
130 | | - voxel_order = np.zeros(1, dtype="|S3").tostring() |
131 | | - new_trk_file = trk_file[:948] + voxel_order + trk_file[948+3:] |
| 138 | + trk_struct, trk_bytes = self.trk_with_bytes() |
| 139 | + trk_struct[Field.VOXEL_ORDER] = b'' |
132 | 140 | with clear_and_catch_warnings(record=True, modules=[trk_module]) as w: |
133 | | - TrkFile.load(BytesIO(new_trk_file)) |
| 141 | + TrkFile.load(BytesIO(trk_bytes)) |
134 | 142 | assert_equal(len(w), 1) |
135 | 143 | assert_true(issubclass(w[0].category, HeaderWarning)) |
136 | 144 | assert_true("LPS" in str(w[0].message)) |
137 | 145 |
|
138 | 146 | # Simulate a TRK file with an unsupported version. |
139 | | - version = np.int32(123).tostring() |
140 | | - new_trk_file = trk_file[:992] + version + trk_file[992+4:] |
141 | | - assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) |
| 147 | + trk_struct, trk_bytes = self.trk_with_bytes() |
| 148 | + trk_struct['version'] = 123 |
| 149 | + assert_raises(HeaderError, TrkFile.load, BytesIO(trk_bytes)) |
142 | 150 |
|
143 | 151 | # Simulate a TRK file with a wrong hdr_size. |
144 | | - hdr_size = np.int32(1234).tostring() |
145 | | - new_trk_file = trk_file[:996] + hdr_size + trk_file[996+4:] |
146 | | - assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) |
| 152 | + trk_struct, trk_bytes = self.trk_with_bytes() |
| 153 | + trk_struct['hdr_size'] = 1234 |
| 154 | + assert_raises(HeaderError, TrkFile.load, BytesIO(trk_bytes)) |
147 | 155 |
|
148 | 156 | # Simulate a TRK file with a wrong scalar_name. |
149 | | - trk_file = open(DATA['complex_trk_fname'], 'rb').read() |
150 | | - noise = np.int32(42).tostring() |
151 | | - new_trk_file = trk_file[:47] + noise + trk_file[47+4:] |
152 | | - assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) |
| 157 | + trk_struct, trk_bytes = self.trk_with_bytes('complex_trk_fname') |
| 158 | + trk_struct['scalar_name'][0, 0] = b'colors\x003\x004' |
| 159 | + assert_raises(HeaderError, TrkFile.load, BytesIO(trk_bytes)) |
153 | 160 |
|
154 | 161 | # Simulate a TRK file with a wrong property_name. |
155 | | - noise = np.int32(42).tostring() |
156 | | - new_trk_file = trk_file[:254] + noise + trk_file[254+4:] |
157 | | - assert_raises(HeaderError, TrkFile.load, BytesIO(new_trk_file)) |
| 162 | + trk_struct, trk_bytes = self.trk_with_bytes('complex_trk_fname') |
| 163 | + trk_struct['property_name'][0, 0] = b'colors\x003\x004' |
| 164 | + assert_raises(HeaderError, TrkFile.load, BytesIO(trk_bytes)) |
| 165 | + |
| 166 | + def test_load_trk_version_1(self): |
| 167 | + # Simulate and test a TRK (version 1). |
| 168 | + # First check that setting the RAS affine works in version 2. |
| 169 | + trk_struct, trk_bytes = self.trk_with_bytes() |
| 170 | + trk_struct[Field.VOXEL_TO_RASMM] = np.diag([2, 3, 4, 1]) |
| 171 | + trk = TrkFile.load(BytesIO(trk_bytes)) |
| 172 | + assert_array_equal(trk.affine, np.diag([2, 3, 4, 1])) |
| 173 | + # Next check that affine assumed identity if version 1. |
| 174 | + trk_struct['version'] = 1 |
| 175 | + with clear_and_catch_warnings(record=True, modules=[trk_module]) as w: |
| 176 | + trk = TrkFile.load(BytesIO(trk_bytes)) |
| 177 | + assert_equal(len(w), 1) |
| 178 | + assert_true(issubclass(w[0].category, HeaderWarning)) |
| 179 | + assert_true("identity" in str(w[0].message)) |
| 180 | + assert_array_equal(trk.affine, np.eye(4)) |
| 181 | + assert_array_equal(trk.header['version'], 1) |
158 | 182 |
|
159 | 183 | def test_load_complex_file_in_big_endian(self): |
160 | | - trk_file = open(DATA['complex_trk_big_endian_fname'], 'rb').read() |
| 184 | + trk_struct, trk_bytes = self.trk_with_bytes( |
| 185 | + 'complex_trk_big_endian_fname', endian='>') |
161 | 186 | # We use hdr_size as an indicator of little vs big endian. |
162 | | - hdr_size_big_endian = np.array(1000, dtype=">i4").tostring() |
163 | | - assert_equal(trk_file[996:996+4], hdr_size_big_endian) |
| 187 | + good_orders = '>' if sys.byteorder == 'little' else '>=' |
| 188 | + hdr_size = trk_struct['hdr_size'] |
| 189 | + assert_true(hdr_size.dtype.byteorder in good_orders) |
| 190 | + assert_equal(hdr_size, 1000) |
164 | 191 |
|
165 | 192 | for lazy_load in [False, True]: |
166 | 193 | trk = TrkFile.load(DATA['complex_trk_big_endian_fname'], |
|
0 commit comments