efdfcf27b8e53ad54b1650e0c87766d14b614f33
[gps-watch.git] / test / logger_test.rs
1 /*
2  * Copyright (c) 2020 Tilman Sauerbeck (tilman at code-monkey de)
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 use common::buffer::{Buffer, BufferUserData};
25 use common::gps;
26 use common::storage::{Storage, Error};
27 use common::logger::{MEMORY_SIZE, Logger, Error as LoggerError};
28
29 struct FakeStorage {
30     expected: Box<[u8]>,
31     actual: Box<[u8]>,
32 }
33
34 impl FakeStorage {
35     fn new() -> FakeStorage {
36         FakeStorage {
37             expected: vec![0xff; MEMORY_SIZE].into_boxed_slice(),
38             actual: vec![0xff; MEMORY_SIZE].into_boxed_slice(),
39         }
40     }
41 }
42
43 impl Storage for FakeStorage {
44     fn size(&self) -> usize {
45         MEMORY_SIZE
46     }
47
48     fn read(&self, address: usize, buffer: &mut [u8]) {
49         for i in 0..buffer.len() {
50             buffer[i] = self.actual[address + i];
51         }
52     }
53
54     fn write(&mut self, address: usize, buffer: &[u8; 4096]) -> Result<(), Error> {
55         if (address & 4095) != 0 {
56             return Err(Error::UnalignedAddress);
57         }
58
59         for i in 0..buffer.len() {
60             self.actual[address + i] = buffer[i];
61         }
62
63         Ok(())
64     }
65
66     fn clear(&mut self) {
67         self.actual = vec![0xff; MEMORY_SIZE].into_boxed_slice();
68     }
69 }
70
71 // Runs a couple of recordings on fully erased flash memory.
72 #[test]
73 fn first_recording() {
74     let mut fake_storage = FakeStorage::new();
75
76     let mut logger = Logger::new(&mut fake_storage);
77     logger.init();
78
79     let tap = gps::TimeAndPos {
80         system_time: 0,
81         unix_time: 1478026311,
82         latitude: 0x73234e,
83         longitude: 0x73234f,
84     };
85
86     let recording_id = logger.start_recording(&tap);
87     assert_eq!(1, recording_id);
88
89     let sectors_written = logger.stop_recording(&tap);
90     assert_eq!(1, sectors_written);
91
92     let expected = [
93         // Header:
94         0x01, 0x00, 0x01, 0x00,
95         0x47, 0xe4, 0x18, 0x58,
96
97         // First point:
98         0x03,
99         0x00,
100         0x9c, 0x8d, 0x99, 0x07,
101         0x9e, 0x8d, 0x99, 0x07,
102
103         // Sentinel:
104         0xff, 0xff, 0xff, 0xff, 0x0f,
105
106         // Footer:
107         0x00, 0x00
108     ];
109
110     let start = 0;
111     let end = start + expected.len();
112     fake_storage.expected[start..end].copy_from_slice(&expected);
113
114     assert_eq!(fake_storage.expected, fake_storage.actual);
115 }
116
117 #[test]
118 fn second_recording() {
119     let mut fake_storage = FakeStorage::new();
120
121     // Mark first sector as in use.
122     let recording0 = [
123         // Header:
124         0x01, 0x00, 0x01, 0x00,
125     ];
126
127     fake_storage.expected[0..recording0.len()].copy_from_slice(&recording0);
128     fake_storage.actual[0..recording0.len()].copy_from_slice(&recording0);
129
130     let mut logger = Logger::new(&mut fake_storage);
131     logger.init();
132
133     let tap = gps::TimeAndPos {
134         system_time: 0,
135         unix_time: 1478026312,
136         latitude: 0x73234e,
137         longitude: 0x73234f,
138     };
139
140     let recording_id = logger.start_recording(&tap);
141     assert_eq!(2, recording_id);
142
143     let sectors_written = logger.stop_recording(&tap);
144     assert_eq!(1, sectors_written);
145
146     let expected = [
147         // Header:
148         0x01, 0x00, 0x02, 0x00,
149         0x48, 0xe4, 0x18, 0x58,
150
151         // First point:
152         0x03,
153         0x00,
154         0x9c, 0x8d, 0x99, 0x07,
155         0x9e, 0x8d, 0x99, 0x07,
156
157         // Sentinel:
158         0xff, 0xff, 0xff, 0xff, 0x0f,
159
160         // Footer:
161         0x00, 0x00
162     ];
163
164     let start = 4096;
165     let end = start + expected.len();
166     fake_storage.expected[start..end].copy_from_slice(&expected);
167
168     assert_eq!(fake_storage.expected, fake_storage.actual);
169 }
170
171 #[test]
172 fn multi_sector_recording() {
173     let mut fake_storage = FakeStorage::new();
174
175     let mut logger = Logger::new(&mut fake_storage);
176     logger.init();
177
178     let tap = gps::TimeAndPos {
179         system_time: 0,
180         unix_time: 1578425250,
181         latitude: 0x73234e,
182         longitude: 0x73234f,
183     };
184
185     let recording_id = logger.start_recording(&tap);
186     assert_eq!(1, recording_id);
187
188     let mut prev_tap = tap;
189
190     for _ in 0..2048 {
191         let tap = gps::TimeAndPos {
192             system_time: 0,
193             unix_time: prev_tap.unix_time + 1,
194             latitude: prev_tap.latitude + 1,
195             longitude: prev_tap.longitude + 1,
196         };
197
198         logger.log(&prev_tap, &tap);
199
200         prev_tap = tap;
201     }
202
203     let sectors_written = logger.stop_recording(&tap);
204     assert_eq!(2, sectors_written);
205
206     let header0 = [
207         0x01, 0x00, 0x01, 0x00,
208     ];
209
210     let header1 = [
211         0x03, 0x00, 0x01, 0x00,
212     ];
213
214     assert_eq!(header0, fake_storage.actual[0..(0 + header0.len())]);
215     assert_eq!(header1, fake_storage.actual[4096..(4096 + header1.len())]);
216 }
217
218 extern "C" fn flush_write_buffer(user_data: *mut BufferUserData,
219                                  buf: *const u8,
220                                  _bufsiz: usize,
221                                  count: usize) -> isize {
222     let _final_buffer = user_data as *mut [u8; 8192];
223     let final_buffer = unsafe { &mut * _final_buffer };
224
225     unsafe {
226         core::ptr::copy_nonoverlapping(buf, final_buffer.as_mut_ptr(), count);
227     }
228
229     count as isize
230 }
231
232 // Verifies that Logger::get_recording() detects unknown recording IDs.
233 #[test]
234 fn get_recording_invalid() {
235     let mut final_buffer = [0u8; 8192];
236
237     let mut yenc_buffer_space = [0u8; 8192];
238     let mut yenc_buffer = Buffer::alloc();
239
240     let user_data = (&mut final_buffer as *mut [u8; 8192]) as *mut BufferUserData;
241
242     yenc_buffer.init(yenc_buffer_space.as_mut_ptr(),
243                      yenc_buffer_space.len(),
244                      flush_write_buffer,
245                      user_data);
246     let mut fake_storage = FakeStorage::new();
247
248     let mut logger = Logger::new(&mut fake_storage);
249     logger.init();
250
251     // Zero is never a valid recording id.
252     let result = logger.get_recording(0, &mut yenc_buffer);
253     assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
254
255     let result = logger.get_recording(1, &mut yenc_buffer);
256     assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
257 }
258
259 // Verifies that Logger::get_recording() can retrieve finished recordings.
260 #[test]
261 fn get_recording_valid() {
262     let mut final_buffer = [0u8; 8192];
263
264     let mut yenc_buffer_space = [0u8; 8192];
265     let mut yenc_buffer = Buffer::alloc();
266
267     let user_data = (&mut final_buffer as *mut [u8; 8192]) as *mut BufferUserData;
268
269     yenc_buffer.init(yenc_buffer_space.as_mut_ptr(),
270                      yenc_buffer_space.len(),
271                      flush_write_buffer,
272                      user_data);
273
274     let mut fake_storage = FakeStorage::new();
275
276     let mut logger = Logger::new(&mut fake_storage);
277     logger.init();
278
279     let result = logger.get_recording(1, &mut yenc_buffer);
280     assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
281
282     let tap0 = gps::TimeAndPos {
283         system_time: 0,
284         unix_time: 1478026311,
285         latitude: 0x73234e,
286         longitude: 0x73234f,
287     };
288
289     logger.start_recording(&tap0);
290
291     let tap1 = gps::TimeAndPos {
292         system_time: 0,
293         unix_time: 1478026311 + 1,
294         latitude: 0x73234e + 5,
295         longitude: 0x73234f + 5,
296     };
297
298     logger.log(&tap0, &tap1);
299
300     let tap2 = gps::TimeAndPos {
301         system_time: 0,
302         unix_time: 1478026311 + 2,
303         latitude: 0x73234e + 10,
304         longitude: 0x73234f + 10,
305     };
306
307     logger.log(&tap1, &tap2);
308
309     logger.stop_recording(&tap2);
310
311     assert!(logger.get_recording(1, &mut yenc_buffer).is_ok());
312 }