Skip to content

Commit

Permalink
Added more tests and fixed handling of some edge cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
awinterstein committed Jan 14, 2025
1 parent b97e441 commit f599f79
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 9 deletions.
186 changes: 186 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions net_income_germany/src/income_tax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,12 @@ mod tests {
assert_eq!(result, data.o);
}
}

#[test]
fn test_with_maximum_input_value() {
let config = crate::config::Config::default();

let result = calculate(&config.income_tax, std::u32::MAX, false);
assert!(result > 2000000000); // check that there won't be some overflow that leads to a small result value
}
}
81 changes: 72 additions & 9 deletions net_income_germany/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! income:
//! - health insurance (Gesetzliche Krankenversicherung)
//! - nursing care insurance (Pflegeversicherung)
//! - unemplyoment insurance (Arbeitslosenversicherung)
//! - unemployment insurance (Arbeitslosenversicherung)
//! - income tax (Einkommenssteuer)
//! - solidarity surcharge (Solidaritätszuschlag)
//!
Expand Down Expand Up @@ -103,6 +103,12 @@ impl TaxResult {
///
/// Returns the remaining net income and the calculated social security taxes and income taxes.
pub fn calculate(config: &config::Config, tax_data: &TaxData) -> Result<TaxResult, &'static str> {
if tax_data.expenses < tax_data.gross_income
&& tax_data.gross_income - tax_data.expenses > std::i32::MAX as u32
{
return Err("Input values are too large to fit for the signed output.");
}

// calculate the social security taxes
let social_security = social_security::calculate(
&config.health_insurance,
Expand All @@ -112,20 +118,77 @@ pub fn calculate(config: &config::Config, tax_data: &TaxData) -> Result<TaxResul
)?;

// reduce income by social security taxes and calculate income taxes on this
let taxable_income =
tax_data.gross_income as i32 - social_security as i32 - tax_data.expenses as i32;
let taxes = income_tax::calculate(
&config.income_tax,
taxable_income.max(0) as u32,
tax_data.married,
);
let deductions = social_security + tax_data.expenses;
let taxable_income = match deductions < tax_data.gross_income {
true => tax_data.gross_income - deductions,
false => 0,
};
let taxes = income_tax::calculate(&config.income_tax, taxable_income, tax_data.married);

// store the results in the result struct
let tax_result = TaxResult {
net_income: taxable_income - taxes as i32,
net_income: (tax_data.gross_income as i64
- tax_data.expenses as i64
- social_security as i64
- taxes as i64) as i32,
social_security_taxes: social_security as u32,
income_taxes: taxes,
};

return Ok(tax_result);
}

#[cfg(test)]
mod tests {
use crate::calculate;

#[test]
fn test_negative_net_income_employed() {
let config = crate::config::Config::default();

let tax_data = crate::TaxData {
gross_income: 0,
expenses: 1500,
fixed_retirement: None,
self_employed: false,
married: false,
};

let result = calculate(&config, &tax_data).unwrap();

// no social security to be paid for employed person
assert_eq!(result.social_security_taxes, 0);

// net income is then just the negative expenses (no taxes)
assert_eq!(
result.net_income,
tax_data.gross_income as i32 - tax_data.expenses as i32
);
}

#[test]
fn test_negative_net_income_self_employed() {
let config = crate::config::create(2025).unwrap();

let tax_data = crate::TaxData {
gross_income: 0,
expenses: 1500,
fixed_retirement: None,
self_employed: true,
married: false,
};

let result = calculate(&config, &tax_data).unwrap();

// minimum social security need to be paid for self-employed person
assert_eq!(result.social_security_taxes, 3093);

// net income is then just the negative expenses (no taxes)
assert_eq!(
result.net_income,
tax_data.gross_income as i32
- tax_data.expenses as i32
- result.social_security_taxes as i32
);
}
}
22 changes: 22 additions & 0 deletions net_income_germany/src/social_security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,26 @@ mod tests {
assert_eq!(result, data.o);
}
}

#[test]
fn test_with_maximum_input_value() {
let config = crate::config::Config::default();

let tax_data = TaxData {
gross_income: u32::MAX,
expenses: 0,
fixed_retirement: None,
self_employed: false,
married: false,
};

let result = calculate(
&config.health_insurance,
&config.retirement_insurance,
&config.unemployment_insurance,
&tax_data,
)
.unwrap();
assert_eq!(result, 17466);
}
}
Loading

0 comments on commit f599f79

Please sign in to comment.