common: Store GPS coordinates in radians, too.
[gps-watch.git] / test / logger_test.rs
index efdfcf27b8e53ad54b1650e0c87766d14b614f33..7b0cdbd1391455d5361d9cc0672f2c4d6a84ad32 100644 (file)
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+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]>,
@@ -68,6 +73,38 @@ impl Storage for FakeStorage {
     }
 }
 
+struct Pipe {
+    pipe_fd: [i32; 2],
+}
+
+impl Pipe {
+    fn new() -> Pipe {
+        let mut pipe_fd = [-1i32; 2];
+
+        unsafe {
+            extern {
+                fn pipe2(pipefd: *mut i32, flags: i32) -> i32;
+            }
+
+            const O_NONBLOCK : i32 = 0x800;
+
+            pipe2(pipe_fd.as_mut_ptr(), O_NONBLOCK);
+        }
+
+        Pipe {
+            pipe_fd: pipe_fd,
+        }
+    }
+
+    fn read_fd(&self) -> i32 {
+        self.pipe_fd[0]
+    }
+
+    fn write_fd(&self) -> i32 {
+        self.pipe_fd[1]
+    }
+}
+
 // Runs a couple of recordings on fully erased flash memory.
 #[test]
 fn first_recording() {
@@ -81,6 +118,8 @@ fn first_recording() {
         unix_time: 1478026311,
         latitude: 0x73234e,
         longitude: 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);
@@ -135,6 +174,8 @@ fn second_recording() {
         unix_time: 1478026312,
         latitude: 0x73234e,
         longitude: 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);
@@ -180,6 +221,8 @@ fn multi_sector_recording() {
         unix_time: 1578425250,
         latitude: 0x73234e,
         longitude: 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);
@@ -193,6 +236,10 @@ fn multi_sector_recording() {
             unix_time: prev_tap.unix_time + 1,
             latitude: prev_tap.latitude + 1,
             longitude: prev_tap.longitude + 1,
+            latitude_rad: Fixed::from_f32(
+                (prev_tap.latitude + 1) as f32 / 600000.0).to_radians(),
+            longitude_rad: Fixed::from_f32(
+                (prev_tap.longitude + 1) as f32 / 600000.0).to_radians(),
         };
 
         logger.log(&prev_tap, &tap);
@@ -219,11 +266,12 @@ extern "C" fn flush_write_buffer(user_data: *mut BufferUserData,
                                  buf: *const u8,
                                  _bufsiz: usize,
                                  count: usize) -> isize {
-    let _final_buffer = user_data as *mut [u8; 8192];
-    let final_buffer = unsafe { &mut * _final_buffer };
+    let _file = user_data as *mut std::fs::File;
 
     unsafe {
-        core::ptr::copy_nonoverlapping(buf, final_buffer.as_mut_ptr(), count);
+        let file = &mut * _file;
+
+        file.write_all(std::slice::from_raw_parts(buf, count)).unwrap();
     }
 
     count as isize
@@ -232,17 +280,20 @@ extern "C" fn flush_write_buffer(user_data: *mut BufferUserData,
 // Verifies that Logger::get_recording() detects unknown recording IDs.
 #[test]
 fn get_recording_invalid() {
-    let mut final_buffer = [0u8; 8192];
+    let pipe = Pipe::new();
+
+    let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
 
     let mut yenc_buffer_space = [0u8; 8192];
     let mut yenc_buffer = Buffer::alloc();
 
-    let user_data = (&mut final_buffer as *mut [u8; 8192]) as *mut BufferUserData;
+    let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
 
     yenc_buffer.init(yenc_buffer_space.as_mut_ptr(),
                      yenc_buffer_space.len(),
                      flush_write_buffer,
                      user_data);
+
     let mut fake_storage = FakeStorage::new();
 
     let mut logger = Logger::new(&mut fake_storage);
@@ -259,12 +310,14 @@ fn get_recording_invalid() {
 // Verifies that Logger::get_recording() can retrieve finished recordings.
 #[test]
 fn get_recording_valid() {
-    let mut final_buffer = [0u8; 8192];
+    let pipe = Pipe::new();
+
+    let mut file = unsafe { std::fs::File::from_raw_fd(pipe.write_fd()) };
 
     let mut yenc_buffer_space = [0u8; 8192];
     let mut yenc_buffer = Buffer::alloc();
 
-    let user_data = (&mut final_buffer as *mut [u8; 8192]) as *mut BufferUserData;
+    let user_data = (&mut file as *mut std::fs::File) as *mut BufferUserData;
 
     yenc_buffer.init(yenc_buffer_space.as_mut_ptr(),
                      yenc_buffer_space.len(),
@@ -284,6 +337,8 @@ fn get_recording_valid() {
         unix_time: 1478026311,
         latitude: 0x73234e,
         longitude: 0x73234f,
+        latitude_rad: Fixed::from_f32(12.57613).to_radians(),
+        longitude_rad: Fixed::from_f32(12.576131666666667).to_radians(),
     };
 
     logger.start_recording(&tap0);
@@ -293,6 +348,8 @@ fn get_recording_valid() {
         unix_time: 1478026311 + 1,
         latitude: 0x73234e + 5,
         longitude: 0x73234f + 5,
+        latitude_rad: Fixed::from_f32(12.576138333333333).to_radians(),
+        longitude_rad: Fixed::from_f32(12.57614).to_radians(),
     };
 
     logger.log(&tap0, &tap1);
@@ -302,6 +359,8 @@ fn get_recording_valid() {
         unix_time: 1478026311 + 2,
         latitude: 0x73234e + 10,
         longitude: 0x73234f + 10,
+        latitude_rad: Fixed::from_f32(12.576146666666666).to_radians(),
+        longitude_rad: Fixed::from_f32(12.576148333333334).to_radians(),
     };
 
     logger.log(&tap1, &tap2);
@@ -310,3 +369,135 @@ fn get_recording_valid() {
 
     assert!(logger.get_recording(1, &mut yenc_buffer).is_ok());
 }
+
+// Verifies that Logger::list_recordings() shows an empty listing
+// if there are no recordings.
+#[test]
+fn list_recordings0() {
+    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();
+
+    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; 256];
+
+    // There are no recordings, so there's no data in the pipe either.
+    assert!(file.read(&mut listing_raw).is_err());
+}
+
+// Verifies that Logger::list_recordings() shows a listing
+// of a single recording in the very first sector.
+#[test]
+fn list_recordings1() {
+    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();
+
+    // Mark first sector as in use.
+    let recording0 = [
+        // Header:
+        0x01, 0x00, 0x01, 0x00,
+        0xa2, 0xdb, 0x14, 0x5e,
+    ];
+
+    fake_storage.expected[0..recording0.len()].copy_from_slice(&recording0);
+    fake_storage.actual[0..recording0.len()].copy_from_slice(&recording0);
+
+    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; 256];
+    let num_bytes_read = file.read(&mut listing_raw).unwrap();
+
+    let expected_bytes = b"\
+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());
+}