common: Make Logger calculate and publish pace.
[gps-watch.git] / test / logger_test.rs
index bbf8dd56b2254448275e030b613b5d49b932a86d..18b0fbb9921854a4ce876a9f5da0abe4631de32e 100644 (file)
 use std::io::{Read, Write};
 use std::os::unix::io::FromRawFd;
 use common::buffer::{Buffer, BufferUserData};
+use common::fixed15_49;
 use common::gps;
 use common::storage::{Storage, Error};
 use common::logger::{MEMORY_SIZE, Logger, Error as LoggerError};
 
+type Fixed = fixed15_49::Fixed15_49;
+
 struct FakeStorage {
     expected: Box<[u8]>,
     actual: Box<[u8]>,
@@ -65,6 +68,19 @@ impl Storage for FakeStorage {
         Ok(())
     }
 
+    fn erase(&mut self, address: usize) -> Result<(), Error> {
+        if (address & 4095) != 0 {
+            return Err(Error::UnalignedAddress);
+        }
+
+        for i in 0..4096 {
+            self.actual[address + i] = 0xff;
+        }
+
+        Ok(())
+
+    }
+
     fn clear(&mut self) {
         self.actual = vec![0xff; MEMORY_SIZE].into_boxed_slice();
     }
@@ -113,8 +129,10 @@ fn first_recording() {
     let tap = gps::TimeAndPos {
         system_time: 0,
         unix_time: 1478026311,
-        latitude: 0x73234e,
-        longitude: 0x73234f,
+        latitude_deg: 0x73234e,
+        longitude_deg: 0x73234f,
+        latitude_rad: Fixed::from_f32(12.57613).to_radians(),
+        longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
     };
 
     let recording_id = logger.start_recording(&tap);
@@ -167,8 +185,10 @@ fn second_recording() {
     let tap = gps::TimeAndPos {
         system_time: 0,
         unix_time: 1478026312,
-        latitude: 0x73234e,
-        longitude: 0x73234f,
+        latitude_deg: 0x73234e,
+        longitude_deg: 0x73234f,
+        latitude_rad: Fixed::from_f32(12.57613).to_radians(),
+        longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
     };
 
     let recording_id = logger.start_recording(&tap);
@@ -212,8 +232,10 @@ fn multi_sector_recording() {
     let tap = gps::TimeAndPos {
         system_time: 0,
         unix_time: 1578425250,
-        latitude: 0x73234e,
-        longitude: 0x73234f,
+        latitude_deg: 0x73234e,
+        longitude_deg: 0x73234f,
+        latitude_rad: Fixed::from_f32(12.57613).to_radians(),
+        longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
     };
 
     let recording_id = logger.start_recording(&tap);
@@ -225,8 +247,12 @@ fn multi_sector_recording() {
         let tap = gps::TimeAndPos {
             system_time: 0,
             unix_time: prev_tap.unix_time + 1,
-            latitude: prev_tap.latitude + 1,
-            longitude: prev_tap.longitude + 1,
+            latitude_deg: prev_tap.latitude_deg + 1,
+            longitude_deg: prev_tap.longitude_deg + 1,
+            latitude_rad: Fixed::from_f32(
+                (prev_tap.latitude_deg + 1) as f32 / 600000.0).to_radians(),
+            longitude_rad: Fixed::from_f32(
+                (prev_tap.longitude_deg + 1) as f32 / 600000.0).to_radians(),
         };
 
         logger.log(&prev_tap, &tap);
@@ -322,8 +348,10 @@ fn get_recording_valid() {
     let tap0 = gps::TimeAndPos {
         system_time: 0,
         unix_time: 1478026311,
-        latitude: 0x73234e,
-        longitude: 0x73234f,
+        latitude_deg: 0x73234e,
+        longitude_deg: 0x73234f,
+        latitude_rad: Fixed::from_f32(12.57613).to_radians(),
+        longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
     };
 
     logger.start_recording(&tap0);
@@ -331,8 +359,10 @@ fn get_recording_valid() {
     let tap1 = gps::TimeAndPos {
         system_time: 0,
         unix_time: 1478026311 + 1,
-        latitude: 0x73234e + 5,
-        longitude: 0x73234f + 5,
+        latitude_deg: 0x73234e + 5,
+        longitude_deg: 0x73234f + 5,
+        latitude_rad: Fixed::from_f32(12.576138333333333).to_radians(),
+        longitude_rad: Fixed::from_f32(12.57614).to_radians(),
     };
 
     logger.log(&tap0, &tap1);
@@ -340,8 +370,10 @@ fn get_recording_valid() {
     let tap2 = gps::TimeAndPos {
         system_time: 0,
         unix_time: 1478026311 + 2,
-        latitude: 0x73234e + 10,
-        longitude: 0x73234f + 10,
+        latitude_deg: 0x73234e + 10,
+        longitude_deg: 0x73234f + 10,
+        latitude_rad: Fixed::from_f32(12.576146666666666).to_radians(),
+        longitude_rad: Fixed::from_f32(12.576148333333334).to_radians(),
     };
 
     logger.log(&tap1, &tap2);
@@ -425,8 +457,157 @@ fn list_recordings1() {
     let num_bytes_read = file.read(&mut listing_raw).unwrap();
 
     let expected_bytes = b"\
-2020-01-07 19:27:30              1\n";
+2020-01-07 19:27:30       4K       1\n";
+
+    assert_eq!(String::from_utf8(expected_bytes.to_vec()).unwrap(),
+               String::from_utf8(listing_raw[0..num_bytes_read].to_vec()).unwrap());
+}
+
+// Verifies that Logger::list_recordings() handles sectors holding
+// additional recording data.
+#[test]
+fn list_recording1_multi_sector() {
+    let pipe = Pipe::new();
+
+    let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
+
+    let mut ls_buffer_space = [0u8; 4096];
+    let mut ls_buffer = Buffer::alloc();
+
+    let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
+
+    ls_buffer.init(ls_buffer_space.as_mut_ptr(),
+                   ls_buffer_space.len(),
+                   flush_write_buffer,
+                   user_data);
+
+    let mut fake_storage = FakeStorage::new();
+
+    // The first sector starts recording 1.
+    let header0 = [
+        // Header:
+        0x01, 0x00, 0x01, 0x00,
+        0x75, 0x18, 0x17, 0x5e,
+    ];
+
+    // The second sector has additional data for recording 1.
+    let header1 = [
+        0x03, 0x00, 0x01, 0x00,
+    ];
+
+    fake_storage.actual[0..header0.len()].copy_from_slice(&header0);
+    fake_storage.actual[4096..4096 + header1.len()].copy_from_slice(&header1);
+
+    let mut logger = Logger::new(&mut fake_storage);
+    logger.init();
+
+    logger.list_recordings(&mut ls_buffer);
+
+    let mut file = unsafe { std::fs::File::from_raw_fd(pipe.read_fd()) };
+
+    let mut listing_raw = [0u8; 4096];
+    let num_bytes_read = file.read(&mut listing_raw).unwrap();
+
+    let expected_bytes = b"\
+2020-01-09 12:11:33       8K       1\n";
 
     assert_eq!(String::from_utf8(expected_bytes.to_vec()).unwrap(),
                String::from_utf8(listing_raw[0..num_bytes_read].to_vec()).unwrap());
 }
+
+// Verifies that Logger::remove_recording() reports an error if there is no
+// recording with the given ID.
+#[test]
+fn remove_recording0() {
+    let mut fake_storage = FakeStorage::new();
+
+    let mut logger = Logger::new(&mut fake_storage);
+    logger.init();
+
+    let result = logger.remove_recording(42);
+    assert_eq!(LoggerError::NoSuchRecording, result.unwrap_err());
+}
+
+// Verifies that Logger::remove_recording() clears consecutive sectors
+// belonging to the recording identified by the given ID.
+#[test]
+fn remove_recording1() {
+    let mut fake_storage = FakeStorage::new();
+
+    // Mark first sector as in use.
+    let header0 = [
+        0x01, 0x00, 0x01, 0x00,
+        0xa2, 0xdb, 0x14, 0x5e,
+    ];
+
+    // Mark second sector as in use by the same recording.
+    let header1 = [
+        0x03, 0x00, 0x01, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+    ];
+
+    // Mark third sector as in use by another recording.
+    let header2 = [
+        0x01, 0x00, 0x02, 0x00,
+        0xa2, 0xdb, 0x14, 0x5f,
+    ];
+
+    fake_storage.actual[0..header0.len()].copy_from_slice(&header0);
+    fake_storage.actual[4096..4096 + header1.len()].copy_from_slice(&header1);
+    fake_storage.actual[8192..8192 + header2.len()].copy_from_slice(&header2);
+
+    let mut logger = Logger::new(&mut fake_storage);
+    logger.init();
+
+    assert!(logger.remove_recording(1).is_ok());
+
+    let cleared = [
+        0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff,
+    ];
+
+    fake_storage.expected[0..cleared.len()].copy_from_slice(&cleared);
+    fake_storage.expected[4096..4096 + header1.len()].copy_from_slice(&cleared);
+    fake_storage.expected[8192..8192 + header2.len()].copy_from_slice(&header2);
+
+    assert_eq!(fake_storage.expected, fake_storage.actual);
+}
+
+#[test]
+fn pace0() {
+    let mut fake_storage = FakeStorage::new();
+
+    let mut logger = Logger::new(&mut fake_storage);
+    logger.init();
+
+    let lat_lon = [
+        (49.372117, 8.820219),
+        (49.372229, 8.821636),
+    ];
+
+    let template = gps::TimeAndPos {
+        system_time: 0,
+        unix_time: 0,
+        latitude_deg: 0,
+        longitude_deg: 0,
+        latitude_rad: Fixed::from_f32(0.0),
+        longitude_rad: Fixed::from_f32(0.0),
+    };
+
+    let mut taps = [template; 11];
+
+    for i in 0..taps.len() {
+        taps[i].system_time = (i as u32) * 100;
+        taps[i].unix_time = i as u32;
+        taps[i].latitude_rad = Fixed::from_f32(lat_lon[i % lat_lon.len()].0).to_radians();
+        taps[i].longitude_rad = Fixed::from_f32(lat_lon[i % lat_lon.len()].1).to_radians();
+    }
+
+    logger.start_recording(&taps[0]);
+
+    for i in 0..(taps.len() - 1) {
+        logger.log(&taps[i], &taps[i + 1]);
+    }
+
+    assert_eq!(logger.pace_s, 10);
+}