More unit/integration tests

This commit is contained in:
RunasSudo 2021-09-13 03:43:17 +10:00
parent b05e0e06f2
commit e1e347c255
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
9 changed files with 429 additions and 62 deletions

View File

@ -16,6 +16,7 @@ eval llvm-cov show target/coverage/debug/opentally -instr-profile=target/coverag
-ignore-filename-regex="$HOME/." \ -ignore-filename-regex="$HOME/." \
-ignore-filename-regex=rustc \ -ignore-filename-regex=rustc \
-ignore-filename-regex=numbers/rational_num.rs \ -ignore-filename-regex=numbers/rational_num.rs \
-ignore-filename-regex=stv/gregory/prettytable_html.rs \
-ignore-filename-regex=stv/wasm.rs \ -ignore-filename-regex=stv/wasm.rs \
-ignore-filename-regex=tests \ -ignore-filename-regex=tests \
-format=html --show-instantiations=false --output-dir=target/coverage/html -format=html --show-instantiations=false --output-dir=target/coverage/html

View File

@ -18,7 +18,7 @@
use super::{Assign, Number}; use super::{Assign, Number};
use ibig::{IBig, ops::Abs}; use ibig::{IBig, ops::Abs};
use num_traits::{Num, One, Zero}; use num_traits::{Num, One, Signed, Zero};
use std::cmp::{Ord, PartialEq, PartialOrd}; use std::cmp::{Ord, PartialEq, PartialOrd};
use std::ops; use std::ops;
@ -57,6 +57,9 @@ impl Number for Fixed {
fn describe() -> String { format!("--numbers fixed --decimals {}", get_dps()) } fn describe() -> String { format!("--numbers fixed --decimals {}", get_dps()) }
fn pow_assign(&mut self, exponent: i32) { fn pow_assign(&mut self, exponent: i32) {
if exponent < 0 {
todo!();
}
self.0 = self.0.pow(exponent as usize) * get_factor() / get_factor().pow(exponent as usize); self.0 = self.0.pow(exponent as usize) * get_factor() / get_factor().pow(exponent as usize);
} }
@ -83,13 +86,11 @@ impl Number for Fixed {
fn round_mut(&mut self, dps: usize) { fn round_mut(&mut self, dps: usize) {
// Only do something if truncating // Only do something if truncating
if dps < get_dps() { if dps < get_dps() {
// TODO: Streamline let mut factor = IBig::from(10).pow(get_dps() - dps);
let mut factor = Self::from(10); factor /= IBig::from(2);
factor.pow_assign(-(dps as i32));
factor /= Self::from(2);
*self = self.clone() - factor; self.0 += factor;
self.ceil_mut(dps); self.floor_mut(dps);
} }
} }
@ -105,7 +106,12 @@ impl Number for Fixed {
Ok(value) => value, Ok(value) => value,
Err(_) => panic!("Syntax Error"), Err(_) => panic!("Syntax Error"),
} * get_factor() / IBig::from(10).pow(decimal.len()); } * get_factor() / IBig::from(10).pow(decimal.len());
return Self(whole + decimal);
if whole.is_negative() {
return Self(whole - decimal);
} else {
return Self(whole + decimal);
}
} }
// Parse integer // Parse integer
@ -117,6 +123,26 @@ impl Number for Fixed {
} }
} }
#[test]
fn rounding() {
Fixed::set_dps(2);
let mut x = Fixed::parse("555.50"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
let mut x = Fixed::parse("555.52"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
let mut x = Fixed::parse("555.55"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
let mut x = Fixed::parse("555.57"); x.floor_mut(1); assert_eq!(x, Fixed::parse("555.5"));
let mut x = Fixed::parse("555.50"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.5"));
let mut x = Fixed::parse("555.52"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.6"));
let mut x = Fixed::parse("555.55"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.6"));
let mut x = Fixed::parse("555.57"); x.ceil_mut(1); assert_eq!(x, Fixed::parse("555.6"));
let mut x = Fixed::parse("555.50"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.5"));
let mut x = Fixed::parse("555.52"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.5"));
let mut x = Fixed::parse("555.55"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.6"));
let mut x = Fixed::parse("555.57"); x.round_mut(1); assert_eq!(x, Fixed::parse("555.6"));
}
impl Num for Fixed { impl Num for Fixed {
type FromStrRadixErr = ibig::error::ParseError; type FromStrRadixErr = ibig::error::ParseError;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> { fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
@ -199,9 +225,7 @@ impl ops::Add for Fixed {
impl ops::Sub for Fixed { impl ops::Sub for Fixed {
type Output = Self; type Output = Self;
fn sub(self, _rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output { Self(self.0 - rhs.0) }
todo!()
}
} }
impl ops::Mul for Fixed { impl ops::Mul for Fixed {
@ -221,6 +245,18 @@ impl ops::Rem for Fixed {
} }
} }
#[test]
fn arith_owned_owned() {
Fixed::set_dps(2);
let a = Fixed::parse("123.45");
let b = Fixed::parse("678.90");
assert_eq!(a.clone() + b.clone(), Fixed::parse("802.35"));
assert_eq!(a.clone() - b.clone(), Fixed::parse("-555.45"));
assert_eq!(a.clone() * b.clone(), Fixed::parse("83810.20")); // = 83810.205 rounds to 83810.20
assert_eq!(a.clone() / b.clone(), Fixed::parse("0.18"));
}
impl ops::Add<&Self> for Fixed { impl ops::Add<&Self> for Fixed {
type Output = Self; type Output = Self;
fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) } fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) }
@ -248,6 +284,18 @@ impl ops::Rem<&Self> for Fixed {
} }
} }
#[test]
fn arith_owned_ref() {
Fixed::set_dps(2);
let a = Fixed::parse("123.45");
let b = Fixed::parse("678.90");
assert_eq!(a.clone() + &b, Fixed::parse("802.35"));
assert_eq!(a.clone() - &b, Fixed::parse("-555.45"));
assert_eq!(a.clone() * &b, Fixed::parse("83810.20"));
assert_eq!(a.clone() / &b, Fixed::parse("0.18"));
}
impl ops::AddAssign for Fixed { impl ops::AddAssign for Fixed {
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; } fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }
} }
@ -276,6 +324,18 @@ impl ops::RemAssign for Fixed {
} }
} }
#[test]
fn arithassign_owned() {
Fixed::set_dps(2);
let a = Fixed::parse("123.45");
let b = Fixed::parse("678.90");
let mut x = a.clone(); x += b.clone(); assert_eq!(x, Fixed::parse("802.35"));
let mut x = a.clone(); x -= b.clone(); assert_eq!(x, Fixed::parse("-555.45"));
let mut x = a.clone(); x *= b.clone(); assert_eq!(x, Fixed::parse("83810.20"));
let mut x = a.clone(); x /= b.clone(); assert_eq!(x, Fixed::parse("0.18"));
}
impl ops::AddAssign<&Self> for Fixed { impl ops::AddAssign<&Self> for Fixed {
fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0; } fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0; }
} }
@ -304,6 +364,18 @@ impl ops::RemAssign<&Self> for Fixed {
} }
} }
#[test]
fn arithassign_ref() {
Fixed::set_dps(2);
let a = Fixed::parse("123.45");
let b = Fixed::parse("678.90");
let mut x = a.clone(); x += &b; assert_eq!(x, Fixed::parse("802.35"));
let mut x = a.clone(); x -= &b; assert_eq!(x, Fixed::parse("-555.45"));
let mut x = a.clone(); x *= &b; assert_eq!(x, Fixed::parse("83810.20"));
let mut x = a.clone(); x /= &b; assert_eq!(x, Fixed::parse("0.18"));
}
impl ops::Neg for &Fixed { impl ops::Neg for &Fixed {
type Output = Fixed; type Output = Fixed;
fn neg(self) -> Self::Output { Fixed(-&self.0) } fn neg(self) -> Self::Output { Fixed(-&self.0) }
@ -336,6 +408,18 @@ impl ops::Rem<Self> for &Fixed {
} }
} }
#[test]
fn arith_ref_ref() {
Fixed::set_dps(2);
let a = Fixed::parse("123.45");
let b = Fixed::parse("678.90");
assert_eq!(&a + &b, Fixed::parse("802.35"));
assert_eq!(&a - &b, Fixed::parse("-555.45"));
assert_eq!(&a * &b, Fixed::parse("83810.20"));
assert_eq!(&a / &b, Fixed::parse("0.18"));
}
/* /*
impl ops::Add<&&Rational> for &Rational { impl ops::Add<&&Rational> for &Rational {

View File

@ -18,7 +18,7 @@
use super::{Assign, Number}; use super::{Assign, Number};
use ibig::{IBig, ops::Abs}; use ibig::{IBig, ops::Abs};
use num_traits::{Num, One, Zero}; use num_traits::{Num, One, Signed, Zero};
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::ops; use std::ops;
@ -64,6 +64,9 @@ impl Number for GuardedFixed {
fn describe() -> String { format!("--numbers gfixed --decimals {}", get_dps()) } fn describe() -> String { format!("--numbers gfixed --decimals {}", get_dps()) }
fn pow_assign(&mut self, exponent: i32) { fn pow_assign(&mut self, exponent: i32) {
if exponent < 0 {
todo!();
}
self.0 = self.0.pow(exponent as usize) * get_factor() / get_factor().pow(exponent as usize); self.0 = self.0.pow(exponent as usize) * get_factor() / get_factor().pow(exponent as usize);
} }
@ -90,13 +93,11 @@ impl Number for GuardedFixed {
fn round_mut(&mut self, dps: usize) { fn round_mut(&mut self, dps: usize) {
// Only do something if truncating // Only do something if truncating
if dps < get_dps() * 2 { if dps < get_dps() * 2 {
// TODO: Streamline let mut factor = IBig::from(10).pow(get_dps() * 2 - dps);
let mut factor = Self::from(10); factor /= IBig::from(2);
factor.pow_assign(-(dps as i32));
factor /= Self::from(2);
*self = self.clone() - factor; self.0 += factor;
self.ceil_mut(dps); self.floor_mut(dps);
} }
} }
@ -112,7 +113,12 @@ impl Number for GuardedFixed {
Ok(value) => value, Ok(value) => value,
Err(_) => panic!("Syntax Error"), Err(_) => panic!("Syntax Error"),
} * get_factor() / IBig::from(10).pow(decimal.len()); } * get_factor() / IBig::from(10).pow(decimal.len());
return Self(whole + decimal);
if whole.is_negative() {
return Self(whole - decimal);
} else {
return Self(whole + decimal);
}
} }
// Parse integer // Parse integer
@ -124,6 +130,26 @@ impl Number for GuardedFixed {
} }
} }
#[test]
fn rounding() {
GuardedFixed::set_dps(2);
let mut x = GuardedFixed::parse("555.50"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
let mut x = GuardedFixed::parse("555.52"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
let mut x = GuardedFixed::parse("555.55"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
let mut x = GuardedFixed::parse("555.57"); x.floor_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
let mut x = GuardedFixed::parse("555.50"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
let mut x = GuardedFixed::parse("555.52"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
let mut x = GuardedFixed::parse("555.55"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
let mut x = GuardedFixed::parse("555.57"); x.ceil_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
let mut x = GuardedFixed::parse("555.50"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
let mut x = GuardedFixed::parse("555.52"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.5"));
let mut x = GuardedFixed::parse("555.55"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
let mut x = GuardedFixed::parse("555.57"); x.round_mut(1); assert_eq!(x, GuardedFixed::parse("555.6"));
}
impl Num for GuardedFixed { impl Num for GuardedFixed {
type FromStrRadixErr = ibig::error::ParseError; type FromStrRadixErr = ibig::error::ParseError;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> { fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
@ -231,9 +257,7 @@ impl ops::Add for GuardedFixed {
impl ops::Sub for GuardedFixed { impl ops::Sub for GuardedFixed {
type Output = Self; type Output = Self;
fn sub(self, _rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output { Self(self.0 - rhs.0) }
todo!()
}
} }
impl ops::Mul for GuardedFixed { impl ops::Mul for GuardedFixed {
@ -253,6 +277,18 @@ impl ops::Rem for GuardedFixed {
} }
} }
#[test]
fn arith_owned_owned() {
GuardedFixed::set_dps(2);
let a = GuardedFixed::parse("123.45");
let b = GuardedFixed::parse("678.90");
assert_eq!(a.clone() + b.clone(), GuardedFixed::parse("802.35"));
assert_eq!(a.clone() - b.clone(), GuardedFixed::parse("-555.45"));
assert_eq!(a.clone() * b.clone(), GuardedFixed::parse("83810.205")); // Must compare to 3 d.p.s as doesn't meet FACTOR_CMP
assert_eq!(a.clone() / b.clone(), GuardedFixed::parse("0.18")); // Meets FACTOR_CMP so compare only 2 d.p.s
}
impl ops::Add<&Self> for GuardedFixed { impl ops::Add<&Self> for GuardedFixed {
type Output = Self; type Output = Self;
fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) } fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) }
@ -280,6 +316,18 @@ impl ops::Rem<&Self> for GuardedFixed {
} }
} }
#[test]
fn arith_owned_ref() {
GuardedFixed::set_dps(2);
let a = GuardedFixed::parse("123.45");
let b = GuardedFixed::parse("678.90");
assert_eq!(a.clone() + &b, GuardedFixed::parse("802.35"));
assert_eq!(a.clone() - &b, GuardedFixed::parse("-555.45"));
assert_eq!(a.clone() * &b, GuardedFixed::parse("83810.205"));
assert_eq!(a.clone() / &b, GuardedFixed::parse("0.18"));
}
impl ops::AddAssign for GuardedFixed { impl ops::AddAssign for GuardedFixed {
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; } fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }
} }
@ -308,6 +356,18 @@ impl ops::RemAssign for GuardedFixed {
} }
} }
#[test]
fn arithassign_owned() {
GuardedFixed::set_dps(2);
let a = GuardedFixed::parse("123.45");
let b = GuardedFixed::parse("678.90");
let mut x = a.clone(); x += b.clone(); assert_eq!(x, GuardedFixed::parse("802.35"));
let mut x = a.clone(); x -= b.clone(); assert_eq!(x, GuardedFixed::parse("-555.45"));
let mut x = a.clone(); x *= b.clone(); assert_eq!(x, GuardedFixed::parse("83810.205"));
let mut x = a.clone(); x /= b.clone(); assert_eq!(x, GuardedFixed::parse("0.18"));
}
impl ops::AddAssign<&Self> for GuardedFixed { impl ops::AddAssign<&Self> for GuardedFixed {
fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0; } fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0; }
} }
@ -336,6 +396,18 @@ impl ops::RemAssign<&Self> for GuardedFixed {
} }
} }
#[test]
fn arithassign_ref() {
GuardedFixed::set_dps(2);
let a = GuardedFixed::parse("123.45");
let b = GuardedFixed::parse("678.90");
let mut x = a.clone(); x += &b; assert_eq!(x, GuardedFixed::parse("802.35"));
let mut x = a.clone(); x -= &b; assert_eq!(x, GuardedFixed::parse("-555.45"));
let mut x = a.clone(); x *= &b; assert_eq!(x, GuardedFixed::parse("83810.205"));
let mut x = a.clone(); x /= &b; assert_eq!(x, GuardedFixed::parse("0.18"));
}
impl ops::Neg for &GuardedFixed { impl ops::Neg for &GuardedFixed {
type Output = GuardedFixed; type Output = GuardedFixed;
fn neg(self) -> Self::Output { GuardedFixed(-&self.0) } fn neg(self) -> Self::Output { GuardedFixed(-&self.0) }
@ -368,6 +440,18 @@ impl ops::Rem<Self> for &GuardedFixed {
} }
} }
#[test]
fn arith_ref_ref() {
GuardedFixed::set_dps(2);
let a = GuardedFixed::parse("123.45");
let b = GuardedFixed::parse("678.90");
assert_eq!(&a + &b, GuardedFixed::parse("802.35"));
assert_eq!(&a - &b, GuardedFixed::parse("-555.45"));
assert_eq!(&a * &b, GuardedFixed::parse("83810.205"));
assert_eq!(&a / &b, GuardedFixed::parse("0.18"));
}
/* /*
impl ops::Add<&&Rational> for &Rational { impl ops::Add<&&Rational> for &Rational {

View File

@ -54,6 +54,24 @@ impl Number for NativeFloat64 {
} }
} }
#[test]
fn rounding() {
let mut x = NativeFloat64::parse("55.550"); x.floor_mut(2); assert_eq!(x, NativeFloat64::parse("55.55"));
let mut x = NativeFloat64::parse("55.552"); x.floor_mut(2); assert_eq!(x, NativeFloat64::parse("55.55"));
let mut x = NativeFloat64::parse("55.555"); x.floor_mut(2); assert_eq!(x, NativeFloat64::parse("55.55"));
let mut x = NativeFloat64::parse("55.557"); x.floor_mut(2); assert_eq!(x, NativeFloat64::parse("55.55"));
let mut x = NativeFloat64::parse("55.550"); x.ceil_mut(2); assert_eq!(x, NativeFloat64::parse("55.55"));
let mut x = NativeFloat64::parse("55.552"); x.ceil_mut(2); assert_eq!(x, NativeFloat64::parse("55.56"));
let mut x = NativeFloat64::parse("55.555"); x.ceil_mut(2); assert_eq!(x, NativeFloat64::parse("55.56"));
let mut x = NativeFloat64::parse("55.557"); x.ceil_mut(2); assert_eq!(x, NativeFloat64::parse("55.56"));
let mut x = NativeFloat64::parse("55.550"); x.round_mut(2); assert_eq!(x, NativeFloat64::parse("55.55"));
let mut x = NativeFloat64::parse("55.552"); x.round_mut(2); assert_eq!(x, NativeFloat64::parse("55.55"));
let mut x = NativeFloat64::parse("55.555"); x.round_mut(2); assert_eq!(x, NativeFloat64::parse("55.56"));
let mut x = NativeFloat64::parse("55.557"); x.round_mut(2); assert_eq!(x, NativeFloat64::parse("55.56"));
}
impl Num for NativeFloat64 { impl Num for NativeFloat64 {
type FromStrRadixErr = ParseFloatError; type FromStrRadixErr = ParseFloatError;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> { fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
@ -76,6 +94,10 @@ impl From<usize> for NativeFloat64 {
fn from(n: usize) -> Self { Self(n as ImplType) } fn from(n: usize) -> Self { Self(n as ImplType) }
} }
impl From<f64> for NativeFloat64 {
fn from(n: f64) -> Self { Self(n as ImplType) }
}
impl One for NativeFloat64 { impl One for NativeFloat64 {
fn one() -> Self { Self(1.0) } fn one() -> Self { Self(1.0) }
} }
@ -102,9 +124,7 @@ impl ops::Add for NativeFloat64 {
impl ops::Sub for NativeFloat64 { impl ops::Sub for NativeFloat64 {
type Output = NativeFloat64; type Output = NativeFloat64;
fn sub(self, _rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output { Self(self.0 - rhs.0) }
todo!()
}
} }
impl ops::Mul for NativeFloat64 { impl ops::Mul for NativeFloat64 {
@ -124,6 +144,17 @@ impl ops::Rem for NativeFloat64 {
} }
} }
#[test]
fn arith_owned_owned() {
let a = NativeFloat64::parse("123.45");
let b = NativeFloat64::parse("678.90");
assert_eq!(a.clone() + b.clone(), NativeFloat64::from(123.45_f64 + 678.90_f64));
assert_eq!(a.clone() - b.clone(), NativeFloat64::from(123.45_f64 - 678.90_f64));
assert_eq!(a.clone() * b.clone(), NativeFloat64::from(123.45_f64 * 678.90_f64));
assert_eq!(a.clone() / b.clone(), NativeFloat64::from(123.45_f64 / 678.90_f64));
}
impl ops::Add<&NativeFloat64> for NativeFloat64 { impl ops::Add<&NativeFloat64> for NativeFloat64 {
type Output = NativeFloat64; type Output = NativeFloat64;
fn add(self, rhs: &NativeFloat64) -> Self::Output { Self(self.0 + &rhs.0) } fn add(self, rhs: &NativeFloat64) -> Self::Output { Self(self.0 + &rhs.0) }
@ -151,6 +182,17 @@ impl ops::Rem<&NativeFloat64> for NativeFloat64 {
} }
} }
#[test]
fn arith_owned_ref() {
let a = NativeFloat64::parse("123.45");
let b = NativeFloat64::parse("678.90");
assert_eq!(a.clone() + &b, NativeFloat64::from(123.45_f64 + 678.90_f64));
assert_eq!(a.clone() - &b, NativeFloat64::from(123.45_f64 - 678.90_f64));
assert_eq!(a.clone() * &b, NativeFloat64::from(123.45_f64 * 678.90_f64));
assert_eq!(a.clone() / &b, NativeFloat64::from(123.45_f64 / 678.90_f64));
}
impl ops::AddAssign for NativeFloat64 { impl ops::AddAssign for NativeFloat64 {
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; } fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }
} }
@ -173,6 +215,17 @@ impl ops::RemAssign for NativeFloat64 {
} }
} }
#[test]
fn arithassign_owned() {
let a = NativeFloat64::parse("123.45");
let b = NativeFloat64::parse("678.90");
let mut x = a.clone(); x += b.clone(); assert_eq!(x, NativeFloat64::from(123.45_f64 + 678.90_f64));
let mut x = a.clone(); x -= b.clone(); assert_eq!(x, NativeFloat64::from(123.45_f64 - 678.90_f64));
let mut x = a.clone(); x *= b.clone(); assert_eq!(x, NativeFloat64::from(123.45_f64 * 678.90_f64));
let mut x = a.clone(); x /= b.clone(); assert_eq!(x, NativeFloat64::from(123.45_f64 / 678.90_f64));
}
impl ops::AddAssign<&NativeFloat64> for NativeFloat64 { impl ops::AddAssign<&NativeFloat64> for NativeFloat64 {
fn add_assign(&mut self, rhs: &NativeFloat64) { self.0 += &rhs.0; } fn add_assign(&mut self, rhs: &NativeFloat64) { self.0 += &rhs.0; }
} }
@ -195,6 +248,17 @@ impl ops::RemAssign<&NativeFloat64> for NativeFloat64 {
} }
} }
#[test]
fn arithassign_ref() {
let a = NativeFloat64::parse("123.45");
let b = NativeFloat64::parse("678.90");
let mut x = a.clone(); x += &b; assert_eq!(x, NativeFloat64::from(123.45_f64 + 678.90_f64));
let mut x = a.clone(); x -= &b; assert_eq!(x, NativeFloat64::from(123.45_f64 - 678.90_f64));
let mut x = a.clone(); x *= &b; assert_eq!(x, NativeFloat64::from(123.45_f64 * 678.90_f64));
let mut x = a.clone(); x /= &b; assert_eq!(x, NativeFloat64::from(123.45_f64 / 678.90_f64));
}
impl ops::Neg for &NativeFloat64 { impl ops::Neg for &NativeFloat64 {
type Output = NativeFloat64; type Output = NativeFloat64;
fn neg(self) -> Self::Output { NativeFloat64(-&self.0) } fn neg(self) -> Self::Output { NativeFloat64(-&self.0) }
@ -227,6 +291,17 @@ impl ops::Rem<Self> for &NativeFloat64 {
} }
} }
#[test]
fn arith_ref_ref() {
let a = NativeFloat64::parse("123.45");
let b = NativeFloat64::parse("678.90");
assert_eq!(&a + &b, NativeFloat64::from(123.45_f64 + 678.90_f64));
assert_eq!(&a - &b, NativeFloat64::from(123.45_f64 - 678.90_f64));
assert_eq!(&a * &b, NativeFloat64::from(123.45_f64 * 678.90_f64));
assert_eq!(&a / &b, NativeFloat64::from(123.45_f64 / 678.90_f64));
}
/* /*
impl ops::Add<&&NativeFloat> for &NativeFloat { impl ops::Add<&&NativeFloat> for &NativeFloat {

View File

@ -70,8 +70,8 @@ impl Number for Rational {
factor.pow_assign(-(dps as i32)); factor.pow_assign(-(dps as i32));
factor /= Self::from(2); factor /= Self::from(2);
*self = self.clone() - factor; *self = self.clone() + factor;
self.ceil_mut(dps); self.floor_mut(dps);
} }
} }
@ -87,7 +87,12 @@ impl Number for Rational {
Ok(value) => rug::Rational::from(value), Ok(value) => rug::Rational::from(value),
Err(_) => panic!("Syntax Error"), Err(_) => panic!("Syntax Error"),
} / rug::Rational::from(10).pow(decimal.len() as u32); } / rug::Rational::from(10).pow(decimal.len() as u32);
return Self(whole + decimal);
if whole < rug::Rational::new() {
return Self(whole - decimal);
} else {
return Self(whole + decimal);
}
} }
// Parse integer // Parse integer
@ -99,6 +104,24 @@ impl Number for Rational {
} }
} }
#[test]
fn rounding() {
let mut x = Rational::parse("55.550"); x.floor_mut(2); assert_eq!(x, Rational::parse("55.55"));
let mut x = Rational::parse("55.552"); x.floor_mut(2); assert_eq!(x, Rational::parse("55.55"));
let mut x = Rational::parse("55.555"); x.floor_mut(2); assert_eq!(x, Rational::parse("55.55"));
let mut x = Rational::parse("55.557"); x.floor_mut(2); assert_eq!(x, Rational::parse("55.55"));
let mut x = Rational::parse("55.550"); x.ceil_mut(2); assert_eq!(x, Rational::parse("55.55"));
let mut x = Rational::parse("55.552"); x.ceil_mut(2); assert_eq!(x, Rational::parse("55.56"));
let mut x = Rational::parse("55.555"); x.ceil_mut(2); assert_eq!(x, Rational::parse("55.56"));
let mut x = Rational::parse("55.557"); x.ceil_mut(2); assert_eq!(x, Rational::parse("55.56"));
let mut x = Rational::parse("55.550"); x.round_mut(2); assert_eq!(x, Rational::parse("55.55"));
let mut x = Rational::parse("55.552"); x.round_mut(2); assert_eq!(x, Rational::parse("55.55"));
let mut x = Rational::parse("55.555"); x.round_mut(2); assert_eq!(x, Rational::parse("55.56"));
let mut x = Rational::parse("55.557"); x.round_mut(2); assert_eq!(x, Rational::parse("55.56"));
}
impl Num for Rational { impl Num for Rational {
type FromStrRadixErr = ParseRationalError; type FromStrRadixErr = ParseRationalError;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> { fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
@ -178,9 +201,7 @@ impl ops::Add for Rational {
impl ops::Sub for Rational { impl ops::Sub for Rational {
type Output = Self; type Output = Self;
fn sub(self, _rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output { Self(self.0 - rhs.0) }
todo!()
}
} }
impl ops::Mul for Rational { impl ops::Mul for Rational {
@ -200,6 +221,17 @@ impl ops::Rem for Rational {
} }
} }
#[test]
fn arith_owned_owned() {
let a = Rational::parse("123.45");
let b = Rational::parse("678.90");
assert_eq!(a.clone() + b.clone(), Rational::parse("802.35"));
assert_eq!(a.clone() - b.clone(), Rational::parse("-555.45"));
assert_eq!(a.clone() * b.clone(), Rational::parse("83810.205"));
assert_eq!((a.clone() / b.clone()) * b, a);
}
impl ops::Add<&Self> for Rational { impl ops::Add<&Self> for Rational {
type Output = Self; type Output = Self;
fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) } fn add(self, rhs: &Self) -> Self::Output { Self(self.0 + &rhs.0) }
@ -227,6 +259,17 @@ impl ops::Rem<&Self> for Rational {
} }
} }
#[test]
fn arith_owned_ref() {
let a = Rational::parse("123.45");
let b = Rational::parse("678.90");
assert_eq!(a.clone() + &b, Rational::parse("802.35"));
assert_eq!(a.clone() - &b, Rational::parse("-555.45"));
assert_eq!(a.clone() * &b, Rational::parse("83810.205"));
assert_eq!((a.clone() / &b) * b, a);
}
impl ops::AddAssign for Rational { impl ops::AddAssign for Rational {
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; } fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }
} }
@ -249,6 +292,17 @@ impl ops::RemAssign for Rational {
} }
} }
#[test]
fn arithassign_owned() {
let a = Rational::parse("123.45");
let b = Rational::parse("678.90");
let mut x = a.clone(); x += b.clone(); assert_eq!(x, Rational::parse("802.35"));
let mut x = a.clone(); x -= b.clone(); assert_eq!(x, Rational::parse("-555.45"));
let mut x = a.clone(); x *= b.clone(); assert_eq!(x, Rational::parse("83810.205"));
let mut x = a.clone(); x /= b.clone(); x *= b; assert_eq!(x, a);
}
impl ops::AddAssign<&Self> for Rational { impl ops::AddAssign<&Self> for Rational {
fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0; } fn add_assign(&mut self, rhs: &Self) { self.0 += &rhs.0; }
} }
@ -271,6 +325,17 @@ impl ops::RemAssign<&Self> for Rational {
} }
} }
#[test]
fn arithassign_ref() {
let a = Rational::parse("123.45");
let b = Rational::parse("678.90");
let mut x = a.clone(); x += &b; assert_eq!(x, Rational::parse("802.35"));
let mut x = a.clone(); x -= &b; assert_eq!(x, Rational::parse("-555.45"));
let mut x = a.clone(); x *= &b; assert_eq!(x, Rational::parse("83810.205"));
let mut x = a.clone(); x /= &b; x *= b; assert_eq!(x, a);
}
impl ops::Neg for &Rational { impl ops::Neg for &Rational {
type Output = Rational; type Output = Rational;
fn neg(self) -> Self::Output { Rational(rug::Rational::from(-&self.0)) } fn neg(self) -> Self::Output { Rational(rug::Rational::from(-&self.0)) }
@ -303,6 +368,17 @@ impl ops::Rem<Self> for &Rational {
} }
} }
#[test]
fn arith_ref_ref() {
let a = Rational::parse("123.45");
let b = Rational::parse("678.90");
assert_eq!(&a + &b, Rational::parse("802.35"));
assert_eq!(&a - &b, Rational::parse("-555.45"));
assert_eq!(&a * &b, Rational::parse("83810.205"));
assert_eq!((&a / &b) * b, a);
}
/* /*
impl ops::Add<&&Rational> for &Rational { impl ops::Add<&&Rational> for &Rational {

View File

@ -0,0 +1,24 @@
"Election for","ERS Model - 1997 Edition"
"Date"," / / "
"Number to be elected",6
"Valid votes",753
"Invalid votes",0
"Quota",107.58
"OpenTally","VERSION"
"Election rules","--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"
,,"Stage",2,"Stage",3,"Stage",4,"Stage",5,"Stage",6,"Stage",7,"Stage",8
,"First","Surplus of",,"Exclusion of",,"Exclusion of",,"Exclusion of",,"Exclusion of",,"Surplus of",,"Exclusion of",
"Candidates","Preferences","Smith",,"Monk",,"Monk",,"Glazier+Wright",,"Glazier+Wright",,"Carpenter",,"Abbot",
"Smith",134,-26.42,107.58,,107.58,,107.58,,107.58,,107.58,,107.58,,107.58,"Elected"
"Duke",105,+1.68,106.68,+2.00,108.68,,108.68,,108.68,,108.68,,108.68,,108.68,"Elected"
"Prince",91,+0.63,91.63,+4.00,95.63,,95.63,+5.00,100.63,+1.68,102.31,+2.00,104.31,,104.31,"Elected"
"Freeman",90,+2.94,92.94,+1.00,93.94,,93.94,+4.00,97.94,+1.68,99.62,+1.00,100.62,+1.00,101.62,"Elected"
"Carpenter",81,+7.14,88.14,,88.14,+0.21,88.35,+34.00,122.35,,122.35,-14.77,107.58,,107.58,"Elected"
"Baron",64,+0.21,64.21,,64.21,,64.21,+3.00,67.21,+1.05,68.26,+2.00,70.26,+12.00,82.26,
"Abbot",59,+0.84,59.84,+5.00,64.84,,64.84,+1.00,65.84,+1.26,67.10,+1.00,68.10,-66.00,2.10,
"Vicar",55,+0.21,55.21,+10.00,65.21,,65.21,+3.00,68.21,+2.10,70.31,+2.00,72.31,+41.00,113.31,"Elected"
"Wright",27,+5.25,32.25,,32.25,,32.25,-27.00,5.25,-5.25,"-",,"-",,"-",
"Glazier",24,+6.51,30.51,,30.51,,30.51,-24.00,6.51,-6.51,"-",,"-",,"-",
"Monk",23,+0.42,23.42,-23.00,0.42,-0.42,"-",,"-",,"-",,"-",,"-",
"Non-transferable",,+0.59,0.59,+1.00,1.59,+0.21,1.80,+1.00,2.80,+3.99,6.79,+6.77,13.56,+12.00,25.56,
"Totals",753,,753.00,,753.00,,753.00,,753.00,,753.00,,753.00,,753.00
Can't render this file because it has a wrong number of fields in line 9.

View File

@ -25,6 +25,13 @@ fn cli_ers97old() {
.assert().success(); .assert().success();
} }
#[test]
fn cli_ers97_transfers_detail() {
Command::cargo_bin("opentally").expect("Cargo Error")
.args(&["stv", "tests/data/ers97.blt", "--numbers", "fixed", "--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", "--bulk-exclude", "--defer-surpluses", "--transfers-detail"])
.assert().success();
}
#[test] #[test]
fn cli_meekm_wigm_ties_prompt() { fn cli_meekm_wigm_ties_prompt() {
Command::cargo_bin("opentally").expect("Cargo Error") Command::cargo_bin("opentally").expect("Cargo Error")

View File

@ -15,43 +15,41 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
use opentally::election::Election; use assert_cmd::Command;
use opentally::numbers::Rational;
use opentally::parser;
use opentally::writer;
use std::fs; use std::fs;
#[test] #[test]
fn ers97_wd_conversions() { fn convert_ers97_blt_bin() {
let blt_input = fs::read_to_string("tests/data/ers97_wd.blt").expect("IO Error"); let blt_input = fs::read_to_string("tests/data/ers97_wd.blt").expect("IO Error");
let election: Election<Rational> = parser::blt::parse_path("tests/data/ers97_wd.blt").expect("Parse Error"); Command::cargo_bin("opentally").expect("Cargo Error")
.args(&["convert", "tests/data/ers97_wd.blt", "/tmp/opentally.bin"])
.assert().success();
// Check BLT Command::cargo_bin("opentally").expect("Cargo Error")
let mut buf: Vec<u8> = Vec::new(); .args(&["convert", "/tmp/opentally.bin", "/tmp/opentally.blt"])
writer::blt::write(election.clone(), &mut buf); .assert().success();
assert_eq!(blt_input, std::str::from_utf8(&buf).expect("UTF-8 Error"));
// Check BIN let blt_roundtrip = fs::read_to_string("/tmp/opentally.blt").expect("IO Error");
buf.clear(); assert_eq!(blt_input, blt_roundtrip);
writer::bin::write(election.clone(), &mut buf); }
let election2: Election<Rational> = parser::bin::parse_bytes(&buf);
#[test]
buf.clear(); fn convert_ers97_blt_csp() {
writer::blt::write(election2, &mut buf); // Withdrawn candidates not supported
assert_eq!(blt_input, std::str::from_utf8(&buf).expect("UTF-8 Error")); let blt_input = fs::read_to_string("tests/data/ers97_wd.blt").expect("IO Error")
.replace(r#""ERS Model - 1997 Edition""#, r#""""#)
// Check CSP .replace("-1 -2\n", "");
buf.clear();
writer::csp::write(election.clone(), &mut buf); Command::cargo_bin("opentally").expect("Cargo Error")
let mut election2: Election<Rational> = parser::csp::parse_reader(&buf[..]); .args(&["convert", "tests/data/ers97_wd.blt", "/tmp/opentally.csp"])
.assert().success();
election2.seats = election.seats;
election2.name = election.name; Command::cargo_bin("opentally").expect("Cargo Error")
election2.withdrawn_candidates = election.withdrawn_candidates.clone(); .args(&["convert", "/tmp/opentally.csp", "/tmp/opentally.blt", "--seats", "6"])
.assert().success();
buf.clear();
writer::blt::write(election2, &mut buf); let blt_roundtrip = fs::read_to_string("/tmp/opentally.blt").expect("IO Error");
assert_eq!(blt_input, std::str::from_utf8(&buf).expect("UTF-8 Error")); assert_eq!(blt_input, blt_roundtrip);
} }

View File

@ -20,6 +20,10 @@ use crate::utils;
use opentally::numbers::Rational; use opentally::numbers::Rational;
use opentally::stv; use opentally::stv;
use assert_cmd::Command;
use std::fs;
#[test] #[test]
fn ers97old_rational() { fn ers97old_rational() {
let stv_opts = stv::STVOptionsBuilder::default() let stv_opts = stv::STVOptionsBuilder::default()
@ -62,6 +66,20 @@ fn ers97_rational() {
utils::read_validate_election::<Rational>("tests/data/ers97.csv", "tests/data/ers97.blt", stv_opts, None, &["nt", "vre"]); utils::read_validate_election::<Rational>("tests/data/ers97.csv", "tests/data/ers97.blt", stv_opts, None, &["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] #[test]
fn ers76_rational() { fn ers76_rational() {
let stv_opts = stv::STVOptionsBuilder::default() let stv_opts = stv::STVOptionsBuilder::default()