Compare commits

...

10 Commits

Author SHA1 Message Date
Juhani Krekelä f354fbe555 Suggest disambiguations for ambiguous units 2023-05-31 23:19:57 +03:00
Juhani Krekelä e2e1349913 Add support for US teaspoons 2023-05-31 22:42:00 +03:00
Juhani Krekelä c16befe55c Add support for US tablespoons 2023-05-31 22:41:29 +03:00
Juhani Krekelä 1639748c68 Add support for US fluid ounces 2023-05-31 22:19:55 +03:00
Juhani Krekelä 1c3315d19d Add support for US cups 2023-05-31 22:10:49 +03:00
Juhani Krekelä 5555d0712e Add support for US liquid pints 2023-05-31 17:57:48 +03:00
Juhani Krekelä 6acd0d56a6 Add an additional way to spell imperial pint 2023-05-31 17:57:25 +03:00
Juhani Krekelä 6acd8b0e82 Add support for US liquid quarts 2023-05-31 17:57:09 +03:00
Juhani Krekelä 8a3002a8ad Add support for US gallons 2023-05-31 17:56:43 +03:00
Juhani Krekelä 9380d9059a Resort fluid volume units from smallest to largest for consistency 2023-05-31 17:55:40 +03:00
4 changed files with 396 additions and 46 deletions

View File

@ -23,6 +23,9 @@ fn get_conversion(unit: NonMetric) -> Conversion {
let imperial_gallon_from = 100_000.0;
let imperial_gallon_to = 454609.0;
let us_gallon_from = inch_from * inch_from * inch_from;
let us_gallon_to = 231.0 * inch_to * inch_to * inch_to * 1000.0;
match unit {
// Length
NonMetric::Inch => Conversion {
@ -100,14 +103,9 @@ fn get_conversion(unit: NonMetric) -> Conversion {
to: MetricQuantity { amount: 12.0 * inch_to * 12.0 * inch_to * 12.0 * inch_to, unit: Metric::CubicMetre },
},
// Fluid volume
NonMetric::ImperialGallon => Conversion {
NonMetric::ImperialFluidOunce => Conversion {
offset: 0.0,
from: imperial_gallon_from,
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::ImperialQuart => Conversion {
offset: 0.0,
from: 4.0 * imperial_gallon_from,
from: 20.0 * 2.0 * 4.0 * imperial_gallon_from,
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::ImperialPint => Conversion {
@ -115,11 +113,51 @@ fn get_conversion(unit: NonMetric) -> Conversion {
from: 2.0 * 4.0 * imperial_gallon_from,
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::ImperialFluidOunce => Conversion {
NonMetric::ImperialQuart => Conversion {
offset: 0.0,
from: 20.0 * 2.0 * 4.0 * imperial_gallon_from,
from: 4.0 * imperial_gallon_from,
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::ImperialGallon => Conversion {
offset: 0.0,
from: imperial_gallon_from,
to: MetricQuantity { amount: imperial_gallon_to, unit: Metric::Litre },
},
NonMetric::USTeaspoon => Conversion {
offset: 0.0,
from: 6.0 * 16.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
NonMetric::USTablespoon => Conversion {
offset: 0.0,
from: 2.0 * 16.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
NonMetric::USFluidOunce => Conversion {
offset: 0.0,
from: 16.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
NonMetric::USCup => Conversion {
offset: 0.0,
from: 2.0 * 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
NonMetric::USLiquidPint => Conversion {
offset: 0.0,
from: 2.0 * 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
NonMetric::USLiquidQuart => Conversion {
offset: 0.0,
from: 4.0 * us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
NonMetric::USGallon => Conversion {
offset: 0.0,
from: us_gallon_from,
to: MetricQuantity { amount: us_gallon_to, unit: Metric::Litre },
},
}
}
@ -191,10 +229,17 @@ mod test {
#[test]
fn fluid_volume() {
let tests = [
Test(NonMetric::ImperialGallon, 4.54609),
Test(NonMetric::ImperialQuart, 1.1365225),
Test(NonMetric::ImperialPint, 0.56826125),
Test(NonMetric::ImperialFluidOunce, 0.0284130625),
Test(NonMetric::ImperialPint, 0.56826125),
Test(NonMetric::ImperialQuart, 1.1365225),
Test(NonMetric::ImperialGallon, 4.54609),
Test(NonMetric::USTeaspoon, 0.00492892159375),
Test(NonMetric::USTablespoon, 0.01478676478125),
Test(NonMetric::USFluidOunce, 0.0295735295625),
Test(NonMetric::USCup, 0.2365882365),
Test(NonMetric::USLiquidPint, 0.473176473),
Test(NonMetric::USLiquidQuart, 0.946352946),
Test(NonMetric::USGallon, 3.785411784),
];
run_tests(&tests, Metric::Litre);
}

View File

@ -23,6 +23,9 @@ pub fn run(input: &str) -> Result<String, String> {
Err(ParseError::ExpectedUnit) => {
return Err("Expected a unit".to_string());
}
Err(ParseError::AmbiguousUnit(unit, prefix1, prefix2)) => {
return Err(format!("Ambiguous unit '{unit}', use either '{prefix1} {unit}' or '{prefix2} {unit}'"));
}
};
if non_metric.len() == 0 {
@ -85,10 +88,17 @@ fn unit_to_name(unit: NonMetric) -> &'static str {
NonMetric::CubicInch => "cubic inches",
NonMetric::CubicFoot => "cubic feet",
// Fluid volume
NonMetric::ImperialGallon => "imperial gallons",
NonMetric::ImperialQuart => "imperial quarts",
NonMetric::ImperialPint => "imperial pints",
NonMetric::ImperialFluidOunce => "imperial fluid ounces",
NonMetric::ImperialPint => "imperial pints",
NonMetric::ImperialQuart => "imperial quarts",
NonMetric::ImperialGallon => "imperial gallons",
NonMetric::USTeaspoon => "US teaspoons",
NonMetric::USTablespoon => "US tablespoons",
NonMetric::USFluidOunce => "US fluid ounces",
NonMetric::USCup => "US cups",
NonMetric::USLiquidPint => "US liquid pints",
NonMetric::USLiquidQuart => "US liquid quarts",
NonMetric::USGallon => "US gallons",
}
}
@ -103,6 +113,7 @@ mod test {
assert_eq!(run("1 tf"), Err("Unknown unit: tf".to_string()));
assert_eq!(run("1"), Err("Expected a unit".to_string()));
assert_eq!(run(""), Err("Expected quantity or quantities to convert".to_string()));
assert_eq!(run("1 fl oz"), Err("Ambiguous unit 'fl oz', use either 'imp fl oz' or 'US fl oz'".to_string()));
assert_eq!(run("6 ft 1 lbs"), Err("Incompatible units: feet, pounds".to_string()));
assert_eq!(run("0 °F 0 °F"), Err("Cannot sum together temperatures".to_string()));
}
@ -131,9 +142,16 @@ mod test {
assert_eq!(run("1 in³"), Ok("16.39 cm³".to_string()));
assert_eq!(run("1 ft³"), Ok("28 317 cm³".to_string()));
// Fluid volume
assert_eq!(run("1 imp gal"), Ok("4.546 l".to_string()));
assert_eq!(run("1 imp qt"), Ok("1.137 l".to_string()));
assert_eq!(run("1 imp pt"), Ok("5.683 dl".to_string()));
assert_eq!(run("1 imp fl oz"), Ok("2.841 cl".to_string()));
assert_eq!(run("1 imp pt"), Ok("5.683 dl".to_string()));
assert_eq!(run("1 imp qt"), Ok("1.137 l".to_string()));
assert_eq!(run("1 imp gal"), Ok("4.546 l".to_string()));
assert_eq!(run("1 tsp"), Ok("4.929 ml".to_string()));
assert_eq!(run("1 Tbsp"), Ok("1.479 cl".to_string()));
assert_eq!(run("1 US fl oz"), Ok("2.957 cl".to_string()));
assert_eq!(run("1 US cup"), Ok("2.366 dl".to_string()));
assert_eq!(run("1 US pt"), Ok("4.732 dl".to_string()));
assert_eq!(run("1 US qt"), Ok("9.464 dl".to_string()));
assert_eq!(run("1 US gal"), Ok("3.785 l".to_string()));
}
}

View File

@ -11,6 +11,7 @@ pub enum ParseError {
UnexpectedUnit(String),
UnknownUnit(String),
ExpectedUnit,
AmbiguousUnit(String, &'static str, &'static str),
}
pub fn parse(input: &str) -> Result<Vec<NonMetricQuantity>, ParseError> {
@ -186,24 +187,121 @@ fn parse_unit(input: String) -> Result<NonMetric, ParseError> {
"ft^3" => Ok(NonMetric::CubicFoot),
// Fluid volume
"imperial gallon" => Ok(NonMetric::ImperialGallon),
"imperial gallons" => Ok(NonMetric::ImperialGallon),
"imp gal" => Ok(NonMetric::ImperialGallon),
"imperial quart" => Ok(NonMetric::ImperialQuart),
"imperial quarts" => Ok(NonMetric::ImperialQuart),
"imp qt" => Ok(NonMetric::ImperialQuart),
"imperial pint" => Ok(NonMetric::ImperialPint),
"imperial pints" => Ok(NonMetric::ImperialPint),
"imp pt" => Ok(NonMetric::ImperialPint),
"imperial fluid ounce" => Ok(NonMetric::ImperialFluidOunce),
"imperial fluid ounces" => Ok(NonMetric::ImperialFluidOunce),
"imp fl oz" => Ok(NonMetric::ImperialFluidOunce),
"imp fl. oz." => Ok(NonMetric::ImperialFluidOunce),
"imp oz. fl." => Ok(NonMetric::ImperialFluidOunce),
"imperial pint" => Ok(NonMetric::ImperialPint),
"imperial pints" => Ok(NonMetric::ImperialPint),
"imp pt" => Ok(NonMetric::ImperialPint),
"imp p" => Ok(NonMetric::ImperialPint),
"imperial quart" => Ok(NonMetric::ImperialQuart),
"imperial quarts" => Ok(NonMetric::ImperialQuart),
"imp qt" => Ok(NonMetric::ImperialQuart),
"imperial gallon" => Ok(NonMetric::ImperialGallon),
"imperial gallons" => Ok(NonMetric::ImperialGallon),
"imp gal" => Ok(NonMetric::ImperialGallon),
"US teaspoon" => Ok(NonMetric::USTeaspoon),
"US teaspoons" => Ok(NonMetric::USTeaspoon),
"US tsp." => Ok(NonMetric::USTeaspoon),
"US tsp" => Ok(NonMetric::USTeaspoon),
"us teaspoon" => Ok(NonMetric::USTeaspoon),
"us teaspoons" => Ok(NonMetric::USTeaspoon),
"us tsp." => Ok(NonMetric::USTeaspoon),
"us tsp" => Ok(NonMetric::USTeaspoon),
"teaspoon" => Ok(NonMetric::USTeaspoon),
"teaspoons" => Ok(NonMetric::USTeaspoon),
"tsp." => Ok(NonMetric::USTeaspoon),
"tsp" => Ok(NonMetric::USTeaspoon),
"US tablespoon" => Ok(NonMetric::USTablespoon),
"US tablespoons" => Ok(NonMetric::USTablespoon),
"US Tbsp." => Ok(NonMetric::USTablespoon),
"US Tbsp" => Ok(NonMetric::USTablespoon),
"us tablespoon" => Ok(NonMetric::USTablespoon),
"us tablespoons" => Ok(NonMetric::USTablespoon),
"us tbsp." => Ok(NonMetric::USTablespoon),
"us tbsp" => Ok(NonMetric::USTablespoon),
"tablespoon" => Ok(NonMetric::USTablespoon),
"tablespoons" => Ok(NonMetric::USTablespoon),
"Tbsp." => Ok(NonMetric::USTablespoon),
"Tbsp" => Ok(NonMetric::USTablespoon),
"tbsp." => Ok(NonMetric::USTablespoon),
"tbsp" => Ok(NonMetric::USTablespoon),
"US fluid ounce" => Ok(NonMetric::USFluidOunce),
"US fluid ounces" => Ok(NonMetric::USFluidOunce),
"US fl oz" => Ok(NonMetric::USFluidOunce),
"US fl. oz." => Ok(NonMetric::USFluidOunce),
"US oz. fl." => Ok(NonMetric::USFluidOunce),
"us fluid ounce" => Ok(NonMetric::USFluidOunce),
"us fluid ounces" => Ok(NonMetric::USFluidOunce),
"us fl oz" => Ok(NonMetric::USFluidOunce),
"us fl. oz." => Ok(NonMetric::USFluidOunce),
"us oz. fl." => Ok(NonMetric::USFluidOunce),
"US cup" => Ok(NonMetric::USCup),
"US cups" => Ok(NonMetric::USCup),
"us cup" => Ok(NonMetric::USCup),
"us cups" => Ok(NonMetric::USCup),
"US liquid pint" => Ok(NonMetric::USLiquidPint),
"US liquid pints" => Ok(NonMetric::USLiquidPint),
"US pint" => Ok(NonMetric::USLiquidPint),
"US pints" => Ok(NonMetric::USLiquidPint),
"US pt" => Ok(NonMetric::USLiquidPint),
"US p" => Ok(NonMetric::USLiquidPint),
"us liquid pint" => Ok(NonMetric::USLiquidPint),
"us liquid pints" => Ok(NonMetric::USLiquidPint),
"us pint" => Ok(NonMetric::USLiquidPint),
"us pints" => Ok(NonMetric::USLiquidPint),
"us pt" => Ok(NonMetric::USLiquidPint),
"us p" => Ok(NonMetric::USLiquidPint),
"US liquid quart" => Ok(NonMetric::USLiquidQuart),
"US liquid quarts" => Ok(NonMetric::USLiquidQuart),
"US quart" => Ok(NonMetric::USLiquidQuart),
"US quarts" => Ok(NonMetric::USLiquidQuart),
"US qt" => Ok(NonMetric::USLiquidQuart),
"us liquid quart" => Ok(NonMetric::USLiquidQuart),
"us liquid quarts" => Ok(NonMetric::USLiquidQuart),
"us quart" => Ok(NonMetric::USLiquidQuart),
"us quarts" => Ok(NonMetric::USLiquidQuart),
"us qt" => Ok(NonMetric::USLiquidQuart),
"US gallon" => Ok(NonMetric::USGallon),
"US gallons" => Ok(NonMetric::USGallon),
"US gal" => Ok(NonMetric::USGallon),
"us gallon" => Ok(NonMetric::USGallon),
"us gallons" => Ok(NonMetric::USGallon),
"us gal" => Ok(NonMetric::USGallon),
// Ambiguous units
"fluid ounce" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"fluid ounces" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"fl oz" => Err(ParseError::AmbiguousUnit(input, "imp", "US")),
"fl. oz." => Err(ParseError::AmbiguousUnit(input, "imp", "US")),
"oz. fl." => Err(ParseError::AmbiguousUnit(input, "imp", "US")),
"pint" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"pints" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"pt" => Err(ParseError::AmbiguousUnit(input, "imp", "US")),
"p" => Err(ParseError::AmbiguousUnit(input, "imp", "US")),
"quart" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"quarts" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"qt" => Err(ParseError::AmbiguousUnit(input, "imp", "US")),
"gallon" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"gallons" => Err(ParseError::AmbiguousUnit(input, "imperial", "US")),
"gal" => Err(ParseError::AmbiguousUnit(input, "imp", "US")),
// Unknown unit
_ => Err(ParseError::UnknownUnit(input)),
}
}
@ -298,6 +396,7 @@ mod test {
assert_eq!(parse("ft"), Err(ParseError::UnexpectedUnit("ft".to_string())));
assert_eq!(parse("5 tf"), Err(ParseError::UnknownUnit("tf".to_string())));
assert_eq!(parse("12"), Err(ParseError::ExpectedUnit));
assert_eq!(parse("1 gallon"), Err(ParseError::AmbiguousUnit("gallon".to_string(), "imperial", "US")));
}
#[test]
@ -439,25 +538,206 @@ mod test {
assert_eq!(parse_unit("ft^3".to_string()), Ok(NonMetric::CubicFoot));
// Fluid volume
assert_eq!(parse_unit("imperial gallon".to_string()), Ok(NonMetric::ImperialGallon));
assert_eq!(parse_unit("imperial gallons".to_string()), Ok(NonMetric::ImperialGallon));
assert_eq!(parse_unit("imp gal".to_string()), Ok(NonMetric::ImperialGallon));
assert_eq!(parse_unit("imperial quart".to_string()), Ok(NonMetric::ImperialQuart));
assert_eq!(parse_unit("imperial quarts".to_string()), Ok(NonMetric::ImperialQuart));
assert_eq!(parse_unit("imp qt".to_string()), Ok(NonMetric::ImperialQuart));
assert_eq!(parse_unit("imperial pint".to_string()), Ok(NonMetric::ImperialPint));
assert_eq!(parse_unit("imperial pints".to_string()), Ok(NonMetric::ImperialPint));
assert_eq!(parse_unit("imp pt".to_string()), Ok(NonMetric::ImperialPint));
assert_eq!(parse_unit("imperial fluid ounce".to_string()), Ok(NonMetric::ImperialFluidOunce));
assert_eq!(parse_unit("imperial fluid ounces".to_string()), Ok(NonMetric::ImperialFluidOunce));
assert_eq!(parse_unit("imp fl oz".to_string()), Ok(NonMetric::ImperialFluidOunce));
assert_eq!(parse_unit("imp fl. oz.".to_string()), Ok(NonMetric::ImperialFluidOunce));
assert_eq!(parse_unit("imp oz. fl.".to_string()), Ok(NonMetric::ImperialFluidOunce));
// Unknown unit
assert_eq!(parse_unit("imperial pint".to_string()), Ok(NonMetric::ImperialPint));
assert_eq!(parse_unit("imperial pints".to_string()), Ok(NonMetric::ImperialPint));
assert_eq!(parse_unit("imp pt".to_string()), Ok(NonMetric::ImperialPint));
assert_eq!(parse_unit("imp p".to_string()), Ok(NonMetric::ImperialPint));
assert_eq!(parse_unit("imperial quart".to_string()), Ok(NonMetric::ImperialQuart));
assert_eq!(parse_unit("imperial quarts".to_string()), Ok(NonMetric::ImperialQuart));
assert_eq!(parse_unit("imp qt".to_string()), Ok(NonMetric::ImperialQuart));
assert_eq!(parse_unit("imperial gallon".to_string()), Ok(NonMetric::ImperialGallon));
assert_eq!(parse_unit("imperial gallons".to_string()), Ok(NonMetric::ImperialGallon));
assert_eq!(parse_unit("imp gal".to_string()), Ok(NonMetric::ImperialGallon));
assert_eq!(parse_unit("US teaspoon".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("US teaspoons".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("US tsp.".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("US tsp".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("us teaspoon".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("us teaspoons".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("us tsp.".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("us tsp".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("teaspoon".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("teaspoons".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("tsp.".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("tsp".to_string()), Ok(NonMetric::USTeaspoon));
assert_eq!(parse_unit("US tablespoon".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("US tablespoons".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("US Tbsp.".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("US Tbsp".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("us tablespoon".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("us tablespoons".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("us tbsp.".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("us tbsp".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("tablespoon".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("tablespoons".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("Tbsp.".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("Tbsp".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("tbsp.".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("tbsp".to_string()), Ok(NonMetric::USTablespoon));
assert_eq!(parse_unit("US fluid ounce".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("US fluid ounces".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("US fl oz".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("US fl. oz.".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("US oz. fl.".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("us fluid ounce".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("us fluid ounces".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("us fl oz".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("us fl. oz.".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("us oz. fl.".to_string()), Ok(NonMetric::USFluidOunce));
assert_eq!(parse_unit("US cup".to_string()), Ok(NonMetric::USCup));
assert_eq!(parse_unit("US cups".to_string()), Ok(NonMetric::USCup));
assert_eq!(parse_unit("us cup".to_string()), Ok(NonMetric::USCup));
assert_eq!(parse_unit("us cups".to_string()), Ok(NonMetric::USCup));
assert_eq!(parse_unit("US liquid pint".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("US liquid pints".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("US pint".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("US pints".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("US pt".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("US p".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("us liquid pint".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("us liquid pints".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("us pint".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("us pints".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("us pt".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("us p".to_string()), Ok(NonMetric::USLiquidPint));
assert_eq!(parse_unit("US liquid quart".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("US liquid quarts".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("US quart".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("US quarts".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("US qt".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("us liquid quart".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("us liquid quarts".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("us quart".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("us quarts".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("us qt".to_string()), Ok(NonMetric::USLiquidQuart));
assert_eq!(parse_unit("US gallon".to_string()), Ok(NonMetric::USGallon));
assert_eq!(parse_unit("US gallons".to_string()), Ok(NonMetric::USGallon));
assert_eq!(parse_unit("US gal".to_string()), Ok(NonMetric::USGallon));
assert_eq!(parse_unit("us gallon".to_string()), Ok(NonMetric::USGallon));
assert_eq!(parse_unit("us gallons".to_string()), Ok(NonMetric::USGallon));
assert_eq!(parse_unit("us gal".to_string()), Ok(NonMetric::USGallon));
}
#[test]
fn ambiguous_units() {
assert_eq!(
parse_unit("fluid ounce".to_string()),
Err(ParseError::AmbiguousUnit("fluid ounce".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("fluid ounces".to_string()),
Err(ParseError::AmbiguousUnit("fluid ounces".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("fl oz".to_string()),
Err(ParseError::AmbiguousUnit("fl oz".to_string(), "imp", "US"))
);
assert_eq!(
parse_unit("fl. oz.".to_string()),
Err(ParseError::AmbiguousUnit("fl. oz.".to_string(), "imp", "US"))
);
assert_eq!(
parse_unit("oz. fl.".to_string()),
Err(ParseError::AmbiguousUnit("oz. fl.".to_string(), "imp", "US"))
);
assert_eq!(
parse_unit("pint".to_string()),
Err(ParseError::AmbiguousUnit("pint".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("pints".to_string()),
Err(ParseError::AmbiguousUnit("pints".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("pt".to_string()),
Err(ParseError::AmbiguousUnit("pt".to_string(), "imp", "US"))
);
assert_eq!(
parse_unit("p".to_string()),
Err(ParseError::AmbiguousUnit("p".to_string(), "imp", "US"))
);
assert_eq!(
parse_unit("quart".to_string()),
Err(ParseError::AmbiguousUnit("quart".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("quarts".to_string()),
Err(ParseError::AmbiguousUnit("quarts".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("qt".to_string()),
Err(ParseError::AmbiguousUnit("qt".to_string(), "imp", "US"))
);
assert_eq!(
parse_unit("gallon".to_string()),
Err(ParseError::AmbiguousUnit("gallon".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("gallons".to_string()),
Err(ParseError::AmbiguousUnit("gallons".to_string(), "imperial", "US"))
);
assert_eq!(
parse_unit("gal".to_string()),
Err(ParseError::AmbiguousUnit("gal".to_string(), "imp", "US"))
);
}
#[test]
fn ambiguous_unit_suggestions() {
let ambiguous_units = [
"fluid ounce",
"fluid ounces",
"fl oz",
"fl. oz.",
"oz. fl.",
"pint",
"pints",
"pt",
"p",
"quart",
"quarts",
"qt",
"gallon",
"gallons",
"gal",
];
for unit in ambiguous_units {
let parsed = parse_unit(unit.to_string());
if let Err(ParseError::AmbiguousUnit(unit, prefix1, prefix2)) = parsed {
let suggestion1 = format!("{prefix1} {unit}");
let suggestion2 = format!("{prefix2} {unit}");
assert!(parse_unit(suggestion1).is_ok());
assert!(parse_unit(suggestion2).is_ok());
} else {
unreachable!();
}
}
}
#[test]
fn unknown_unit() {
assert_eq!(parse_unit("hutenosa".to_string()), Err(ParseError::UnknownUnit("hutenosa".to_string())));
}

View File

@ -30,10 +30,17 @@ pub enum NonMetric {
CubicInch,
CubicFoot,
// Fluid volume
ImperialGallon,
ImperialQuart,
ImperialPint,
ImperialFluidOunce,
ImperialPint,
ImperialQuart,
ImperialGallon,
USTeaspoon,
USTablespoon,
USFluidOunce,
USCup,
USLiquidPint,
USLiquidQuart,
USGallon,
}
#[derive(Clone, Copy, Debug, PartialEq)]