diff --git a/backend/src/data_entry/status.rs b/backend/src/data_entry/status.rs index 0cd9de9a2..e7093b153 100644 --- a/backend/src/data_entry/status.rs +++ b/backend/src/data_entry/status.rs @@ -502,45 +502,236 @@ impl Default for DataEntryStatus { #[cfg(test)] mod tests { use super::*; + use crate::data_entry::{CandidateVotes, PoliticalGroupVotes, VotersCounts, VotesCounts}; + use crate::election::{Candidate, Election, ElectionCategory, ElectionStatus, PoliticalGroup}; + use crate::polling_station::{PollingStation, PollingStationType}; + + fn polling_station_result() -> PollingStationResults { + PollingStationResults { + recounted: Some(false), + ..Default::default() + } + } + + fn polling_station() -> PollingStation { + PollingStation { + id: 1, + election_id: 1, + name: "Test polling station".to_string(), + number: 1, + number_of_voters: None, + polling_station_type: Some(PollingStationType::FixedLocation), + address: "Test street".to_string(), + postal_code: "1234 YQ".to_string(), + locality: "Test city".to_string(), + } + } + + fn election() -> Election { + Election { + id: 1, + name: "Test election".to_string(), + location: "Test location".to_string(), + number_of_voters: 100, + category: ElectionCategory::Municipal, + number_of_seats: 18, + election_date: chrono::Utc::now().date_naive(), + nomination_date: chrono::Utc::now().date_naive(), + status: ElectionStatus::DataEntryInProgress, + political_groups: Some(vec![]), + } + } + /// FirstEntryNotStarted --> FirstEntryInProgress: claim #[test] - fn can_claim_not_started() { - let status = DataEntryStatus::FirstEntryNotStarted; - let entry = PollingStationResults::default(); - let client_state = ClientState::new_from_str(Some("{}")).unwrap(); - let progress = 0; - - let new_status = status - .claim_first_entry(progress, entry.clone(), client_state.clone()) + fn first_entry_not_started_to_first_entry_in_progress() { + let initial = DataEntryStatus::FirstEntryNotStarted; + let next = initial + .claim_first_entry(0, polling_station_result(), ClientState::default()) .unwrap(); + assert!(matches!(next, DataEntryStatus::FirstEntryInProgress(_))); + } - assert_eq!( - new_status, - DataEntryStatus::FirstEntryInProgress(FirstEntryInProgress { - progress, - first_entry: entry, - client_state - }) - ); + /// FirstEntryInProgress --> FirstEntryInProgress: save + #[test] + fn first_entry_in_progress_to_first_entry_in_progress() { + let initial = DataEntryStatus::FirstEntryInProgress(FirstEntryInProgress { + progress: 0, + first_entry: polling_station_result(), + client_state: ClientState::new_from_str(Some("{}")).unwrap(), + }); + + let next = initial + .update_first_entry(0, polling_station_result(), ClientState::default()) + .unwrap(); + assert!(matches!(next, DataEntryStatus::FirstEntryInProgress(_))); } + /// FirstEntryInProgress --> SecondEntryNotStarted: finalise #[test] - fn cannot_claim_already_claimed() { - let mut initial_entry = PollingStationResults::default(); - initial_entry.votes_counts.votes_candidates_count = 100; - let initial_entry = initial_entry; + fn first_entry_in_progress_to_second_entry_not_started() { + let initial = DataEntryStatus::FirstEntryInProgress(FirstEntryInProgress { + progress: 0, + first_entry: polling_station_result(), + client_state: ClientState::new_from_str(Some("{}")).unwrap(), + }); + + let next = initial + .finalise_first_entry(&polling_station(), &election()) + .unwrap(); + assert!(matches!(next, DataEntryStatus::SecondEntryNotStarted(_))); + } - let status = DataEntryStatus::FirstEntryInProgress(FirstEntryInProgress { + /// FirstEntryInProgress --> FirstEntryNotStarted: delete + #[test] + fn first_entry_in_progress_to_first_entry_not_started() { + let initial = DataEntryStatus::FirstEntryInProgress(FirstEntryInProgress { progress: 0, - first_entry: initial_entry, + first_entry: polling_station_result(), client_state: ClientState::new_from_str(Some("{}")).unwrap(), }); - let try_new_status = - status.claim_first_entry(0, PollingStationResults::default(), ClientState::default()); - assert_eq!( - try_new_status, - Err(DataEntryTransitionError::FirstEntryAlreadyClaimed) - ); + let next = initial.delete_first_entry().unwrap(); + assert!(matches!(next, DataEntryStatus::FirstEntryNotStarted)); + } + + /// SecondEntryNotStarted --> SecondEntryInProgress: claim + #[test] + fn second_entry_not_started_to_second_entry_in_progress() { + let initial = DataEntryStatus::SecondEntryNotStarted(SecondEntryNotStarted { + finalised_first_entry: polling_station_result(), + first_entry_finished_at: chrono::Utc::now(), + }); + let next = initial + .claim_second_entry(0, polling_station_result(), ClientState::default()) + .unwrap(); + assert!(matches!(next, DataEntryStatus::SecondEntryInProgress(_))); + } + + /// SecondEntryInProgress --> SecondEntryInProgress: save + #[test] + fn second_entry_in_progress_to_second_entry_in_progress() { + let initial = DataEntryStatus::SecondEntryInProgress(SecondEntryInProgress { + finalised_first_entry: polling_station_result(), + first_entry_finished_at: chrono::Utc::now(), + progress: 0, + second_entry: polling_station_result(), + client_state: ClientState::default(), + }); + let next = initial + .update_second_entry(0, polling_station_result(), ClientState::default()) + .unwrap(); + assert!(matches!(next, DataEntryStatus::SecondEntryInProgress(_))); + } + + /// SecondEntryInProgress --> is_equal: finalise + /// is_equal --> Definitive: equal? yes + #[test] + fn second_entry_in_progress_finalise_equal() { + let initial_equal = DataEntryStatus::SecondEntryInProgress(SecondEntryInProgress { + finalised_first_entry: polling_station_result(), + first_entry_finished_at: chrono::Utc::now(), + progress: 0, + second_entry: polling_station_result(), + client_state: ClientState::default(), + }); + + let next_equal = initial_equal + .finalise_second_entry(&polling_station(), &election()) + .unwrap(); + assert!(matches!(next_equal.0, DataEntryStatus::Definitive(_))); + } + + /// SecondEntryInProgress --> is_equal: finalise + /// is_equal --> EntriesDifferent: equal? no + #[test] + fn second_entry_in_progress_finalise_not_equal() { + let initial = DataEntryStatus::SecondEntryInProgress(SecondEntryInProgress { + finalised_first_entry: polling_station_result(), + first_entry_finished_at: chrono::Utc::now(), + progress: 0, + second_entry: PollingStationResults { + voters_counts: VotersCounts { + poll_card_count: 1, + proxy_certificate_count: 0, + voter_card_count: 0, + total_admitted_voters_count: 1, + }, + votes_counts: VotesCounts { + votes_candidates_count: 1, + blank_votes_count: 0, + invalid_votes_count: 0, + total_votes_cast_count: 1, + }, + political_group_votes: vec![PoliticalGroupVotes { + number: 1, + total: 1, + candidate_votes: vec![CandidateVotes { + number: 1, + votes: 1, + }], + }], + ..polling_station_result() + }, + client_state: ClientState::default(), + }); + + let next = initial + .finalise_second_entry( + &polling_station(), + &Election { + political_groups: Some(vec![PoliticalGroup { + number: 1, + name: "Test group".to_string(), + candidates: vec![Candidate { + number: 1, + initials: "A.".to_string(), + first_name: None, + last_name_prefix: None, + last_name: "Candidate".to_string(), + locality: "Test locality".to_string(), + country_code: None, + gender: None, + }], + }]), + ..election() + }, + ) + .unwrap(); + assert!(matches!(next.0, DataEntryStatus::EntriesDifferent(_))); + } + + /// SecondEntryInProgress --> SecondEntryNotStarted: delete + #[test] + fn second_entry_in_progress_to_second_entry_not_started() { + let initial = DataEntryStatus::SecondEntryInProgress(SecondEntryInProgress { + finalised_first_entry: polling_station_result(), + first_entry_finished_at: chrono::Utc::now(), + progress: 0, + second_entry: polling_station_result(), + client_state: ClientState::default(), + }); + let next = initial.delete_second_entry().unwrap(); + assert!(matches!(next, DataEntryStatus::SecondEntryNotStarted(_))); + } + + /// EntriesDifferent --> Definitive: resolve + #[test] + fn entries_different_to_definitive() { + let initial = DataEntryStatus::EntriesDifferent(EntriesDifferent { + second_entry: polling_station_result(), + first_entry: PollingStationResults::default(), + }); + let next = initial.resolve(EntryNumber::SecondEntry).unwrap(); + assert!(matches!(next.0, DataEntryStatus::Definitive(_))); + } + + //TODO: Will be Implemented in #130: + // EntriesDifferent --> NotStarted: delete + /* + #[test] + fn entries_not_equal_to_definitive() { + todo!(); } + */ } diff --git a/documentatie/flowcharts/data-entry-state.md b/documentatie/flowcharts/data-entry-state.md index 09bb1d083..47b6b8e1f 100644 --- a/documentatie/flowcharts/data-entry-state.md +++ b/documentatie/flowcharts/data-entry-state.md @@ -14,10 +14,10 @@ SecondEntryNotStarted --> SecondEntryInProgress: claim #SecondEntryInProgress --> SecondEntryInProgress: save state is_equal <> is_equal --> Definitive: equal? yes -is_equal --> EntriesNotEqual: equal? no +is_equal --> EntriesDifferent: equal? no SecondEntryInProgress --> is_equal: finalise SecondEntryInProgress --> SecondEntryNotStarted: delete -#EntriesNotEqual --> EntriesNotEqual: save -# Will be Implemented in #130: EntriesNotEqual --> NotStarted: delete -EntriesNotEqual --> Definitive: resolve +#EntriesDifferent --> EntriesDifferent: save +# Will be Implemented in #130: EntriesDifferent --> NotStarted: delete +EntriesDifferent --> Definitive: resolve ```