From: Tilman Sauerbeck Date: Tue, 11 Feb 2020 18:56:37 +0000 (+0100) Subject: common: Implement Logger::remove_recording(). X-Git-Url: http://git.code-monkey.de/?p=gps-watch.git;a=commitdiff_plain;h=20891d38ee4363b3cbc9fc5fd69dae5c6ae59a82 common: Implement Logger::remove_recording(). --- diff --git a/src/common/logger.rs b/src/common/logger.rs index 8a1c05c..9b498ce 100644 --- a/src/common/logger.rs +++ b/src/common/logger.rs @@ -38,6 +38,7 @@ const NUM_SECTORS: usize = MEMORY_SIZE / SECTOR_SIZE; #[derive(Clone, Copy, PartialEq, Debug)] pub enum Error { NoSuchRecording, + StorageError, } enum SectorFlag { @@ -666,4 +667,40 @@ impl<'a> Logger<'a> { Err(Error::NoSuchRecording) } } + + /// + /// Remove recording @p recording_id. + pub fn remove_recording(&mut self, recording_id: u16) -> Result<(), Error> { + if let Some(found_index) = (0..NUM_SECTORS).find(|&index| { + let sector_header = &self.sector_header[index as usize]; + + sector_header.recording_id == recording_id && + sector_header.starts_recording() + }) { + let mut next_sector = found_index as usize; + + for _ in 0..NUM_SECTORS { + let address = next_sector * SECTOR_SIZE; + + if let Err(_) = self.storage.erase(address) { + return Err(Error::StorageError); + } + + // Mark this sector as eligible for the next recording + // and ensure it won't be picked up by list_recordings(). + self.read_sector_header(next_sector); + + next_sector += 1; + next_sector &= NUM_SECTORS - 1; + + if !self.sector_header[next_sector].belongs_to(recording_id) { + break; + } + } + + Ok(()) + } else { + Err(Error::NoSuchRecording) + } + } } diff --git a/test/logger_test.rs b/test/logger_test.rs index a254f50..784c049 100644 --- a/test/logger_test.rs +++ b/test/logger_test.rs @@ -514,3 +514,61 @@ fn list_recording1_multi_sector() { 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); +}