X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=test%2Flogger_test.rs;h=18b0fbb9921854a4ce876a9f5da0abe4631de32e;hb=beddb8cf26138f9aaa5fa8bacf8aa355fa0b069c;hp=efdfcf27b8e53ad54b1650e0c87766d14b614f33;hpb=f68ab85d65e9053868ce022e997b3834d6812f59;p=gps-watch.git diff --git a/test/logger_test.rs b/test/logger_test.rs index efdfcf2..18b0fbb 100644 --- a/test/logger_test.rs +++ b/test/logger_test.rs @@ -21,11 +21,16 @@ * 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]>, @@ -63,11 +68,56 @@ 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(); } } +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() { @@ -79,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); @@ -133,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); @@ -178,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); @@ -191,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); @@ -219,11 +279,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 +293,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 +323,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(), @@ -282,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); @@ -291,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); @@ -300,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); @@ -310,3 +382,232 @@ 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()); +} + +// 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); +}