/* OpenTally: Open-source election vote counting * Copyright © 2021 Lee Yingtong Li (RunasSudo) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use crate::utils; use opentally::numbers::{Fixed, GuardedFixed, NativeFloat64, Rational}; use opentally::stv; use assert_cmd::Command; use std::fs; #[test] fn ers97old_rational() { let stv_opts = stv::STVOptionsBuilder::default() .round_surplus_fractions(Some(2)) .round_values(Some(2)) .round_votes(Some(2)) .round_quota(Some(2)) .quota(stv::QuotaType::DroopExact) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .quota_mode(stv::QuotaMode::ERS97) .surplus(stv::SurplusMethod::EG) .transferable_only(true) .exclusion(stv::ExclusionMethod::ByValue) .early_bulk_elect(false) .bulk_exclude(true) .defer_surpluses(true) .build().unwrap(); assert_eq!(stv_opts.describe::(), "--round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --quota droop_exact --quota-criterion geq --quota-mode ers97 --surplus eg --transferable-only --exclusion by_value --no-early-bulk-elect --bulk-exclude --defer-surpluses"); utils::read_validate_election::("tests/data/ers97old.csv", "tests/data/ers97old.blt", stv_opts, None, &["nt", "vre"]); } #[test] fn ers97_rational() { let stv_opts = stv::STVOptionsBuilder::default() .round_surplus_fractions(Some(2)) .round_values(Some(2)) .round_votes(Some(2)) .round_quota(Some(2)) .quota(stv::QuotaType::DroopExact) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .quota_mode(stv::QuotaMode::ERS97) .surplus(stv::SurplusMethod::EG) .transferable_only(true) .exclusion(stv::ExclusionMethod::ByValue) .early_bulk_elect(false) .bulk_exclude(true) .defer_surpluses(true) .build().unwrap(); assert_eq!(stv_opts.describe::(), "--round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --quota droop_exact --quota-criterion geq --quota-mode ers97 --surplus eg --transferable-only --exclusion by_value --no-early-bulk-elect --bulk-exclude --defer-surpluses"); utils::read_validate_election::("tests/data/ers97.csv", "tests/data/ers97.blt", stv_opts, None, &["nt", "vre"]); } #[test] fn ers97_fixed9() { let stv_opts = stv::STVOptionsBuilder::default() .round_surplus_fractions(Some(2)) .round_values(Some(2)) .round_votes(Some(2)) .round_quota(Some(2)) .quota(stv::QuotaType::DroopExact) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .quota_mode(stv::QuotaMode::ERS97) .surplus(stv::SurplusMethod::EG) .transferable_only(true) .exclusion(stv::ExclusionMethod::ByValue) .early_bulk_elect(false) .bulk_exclude(true) .defer_surpluses(true) .build().unwrap(); Fixed::set_dps(9); assert_eq!(stv_opts.describe::(), "--numbers fixed --decimals 9 --round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --quota droop_exact --quota-criterion geq --quota-mode ers97 --surplus eg --transferable-only --exclusion by_value --no-early-bulk-elect --bulk-exclude --defer-surpluses"); utils::read_validate_election::("tests/data/ers97.csv", "tests/data/ers97.blt", stv_opts, None, &["nt", "vre"]); } #[test] fn ers97_gfixed5() { let stv_opts = stv::STVOptionsBuilder::default() .round_surplus_fractions(Some(2)) .round_values(Some(2)) .round_votes(Some(2)) .round_quota(Some(2)) .quota(stv::QuotaType::DroopExact) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .quota_mode(stv::QuotaMode::ERS97) .surplus(stv::SurplusMethod::EG) .transferable_only(true) .exclusion(stv::ExclusionMethod::ByValue) .early_bulk_elect(false) .bulk_exclude(true) .defer_surpluses(true) .build().unwrap(); GuardedFixed::set_dps(5); assert_eq!(stv_opts.describe::(), "--numbers gfixed --decimals 5 --round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --quota droop_exact --quota-criterion geq --quota-mode ers97 --surplus eg --transferable-only --exclusion by_value --no-early-bulk-elect --bulk-exclude --defer-surpluses"); utils::read_validate_election::("tests/data/ers97.csv", "tests/data/ers97.blt", stv_opts, None, &["nt", "vre"]); } #[test] fn ers97_float64() { let stv_opts = stv::STVOptionsBuilder::default() .round_surplus_fractions(Some(2)) .round_values(Some(2)) .round_votes(Some(2)) .round_quota(Some(2)) .quota(stv::QuotaType::DroopExact) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .quota_mode(stv::QuotaMode::ERS97) .surplus(stv::SurplusMethod::EG) .transferable_only(true) .exclusion(stv::ExclusionMethod::ByValue) .early_bulk_elect(false) .bulk_exclude(true) .defer_surpluses(true) .build().unwrap(); assert_eq!(stv_opts.describe::(), "--numbers float64 --round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 2 --quota droop_exact --quota-criterion geq --quota-mode ers97 --surplus eg --transferable-only --exclusion by_value --no-early-bulk-elect --bulk-exclude --defer-surpluses"); utils::read_validate_election::("tests/data/ers97.csv", "tests/data/ers97.blt", stv_opts, Some(2), &["nt", "vre"]); } #[test] fn ers97_rational_csv() { let cmd = Command::cargo_bin("opentally").expect("Cargo Error") .args(&["stv", "tests/data/ers97.blt", "--round-surplus-fractions", "2", "--round-values", "2", "--round-votes", "2", "--round-quota", "2", "--quota", "droop_exact", "--quota-criterion", "geq", "--quota-mode", "ers97", "--surplus", "eg", "--transferable-only", "--exclusion", "by_value", "--bulk-exclude", "--defer-surpluses", "--output", "csv"]) .assert().success(); let output = std::str::from_utf8(&cmd.get_output().stdout).expect("Unicode Error") .replace(&format!(r#""{}""#, opentally::VERSION), r#""VERSION""#); let expected = fs::read_to_string("tests/data/ers97_csv_output.csv").expect("IO Error"); assert_eq!(output, expected); } #[test] fn ers76_rational() { let stv_opts = stv::STVOptionsBuilder::default() .round_surplus_fractions(Some(2)) .round_values(Some(2)) .round_votes(Some(2)) .round_quota(Some(0)) .quota(stv::QuotaType::DroopExact) .quota_criterion(stv::QuotaCriterion::GreaterOrEqual) .quota_mode(stv::QuotaMode::ERS76) .surplus(stv::SurplusMethod::EG) .transferable_only(true) .exclusion(stv::ExclusionMethod::ByValue) .early_bulk_elect(false) .bulk_exclude(true) .defer_surpluses(true) .build().unwrap(); assert_eq!(stv_opts.describe::(), "--round-surplus-fractions 2 --round-values 2 --round-votes 2 --round-quota 0 --quota droop_exact --quota-criterion geq --quota-mode ers76 --surplus eg --transferable-only --exclusion by_value --no-early-bulk-elect --bulk-exclude --defer-surpluses"); utils::read_validate_election::("tests/data/ers76.csv", "tests/data/ers76.blt", stv_opts, None, &["nt", "vre"]); }