summaryrefslogtreecommitdiff
path: root/exercises
diff options
context:
space:
mode:
authormarisa <mokou@fastmail.com>2021-06-24 14:12:34 +0200
committerGitHub <noreply@github.com>2021-06-24 14:12:34 +0200
commitec63cadadb51b43738b29b1acedf815464bc86aa (patch)
tree73330b20e7ffe163bd00ae35916f41fbf5cb486f /exercises
parent84d8305730b6759635f63490d28e07ae5469de41 (diff)
parentb7ddd09fab97fc96f032bc8c0b9e1a64e5ffbcdd (diff)
Merge pull request #772 from tlyu/errors-rework
feature: improve error_handling exercises
Diffstat (limited to 'exercises')
-rw-r--r--exercises/error_handling/errors4.rs (renamed from exercises/error_handling/result1.rs)4
-rw-r--r--exercises/error_handling/errors5.rs53
-rw-r--r--exercises/error_handling/errors6.rs95
-rw-r--r--exercises/error_handling/errorsn.rs117
4 files changed, 150 insertions, 119 deletions
diff --git a/exercises/error_handling/result1.rs b/exercises/error_handling/errors4.rs
index b978001..0685c37 100644
--- a/exercises/error_handling/result1.rs
+++ b/exercises/error_handling/errors4.rs
@@ -1,5 +1,5 @@
-// result1.rs
-// Make this test pass! Execute `rustlings hint result1` for hints :)
+// errors4.rs
+// Make this test pass! Execute `rustlings hint errors4` for hints :)
// I AM NOT DONE
diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs
new file mode 100644
index 0000000..365a869
--- /dev/null
+++ b/exercises/error_handling/errors5.rs
@@ -0,0 +1,53 @@
+// errors5.rs
+
+// This program uses a completed version of the code from errors4.
+// It won't compile right now! Why?
+// Execute `rustlings hint errors5` for hints!
+
+// I AM NOT DONE
+
+use std::error;
+use std::fmt;
+use std::num::ParseIntError;
+
+// TODO: update the return type of `main()` to make this compile.
+fn main() -> Result<(), ParseIntError> {
+ let pretend_user_input = "42";
+ let x: i64 = pretend_user_input.parse()?;
+ println!("output={:?}", PositiveNonzeroInteger::new(x)?);
+ Ok(())
+}
+
+// Don't change anything below this line.
+
+#[derive(PartialEq, Debug)]
+struct PositiveNonzeroInteger(u64);
+
+#[derive(PartialEq, Debug)]
+enum CreationError {
+ Negative,
+ Zero,
+}
+
+impl PositiveNonzeroInteger {
+ fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
+ match value {
+ x if x < 0 => Err(CreationError::Negative),
+ x if x == 0 => Err(CreationError::Zero),
+ x => Ok(PositiveNonzeroInteger(x as u64))
+ }
+ }
+}
+
+// This is required so that `CreationError` can implement `error::Error`.
+impl fmt::Display for CreationError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let description = match *self {
+ CreationError::Negative => "number is negative",
+ CreationError::Zero => "number is zero",
+ };
+ f.write_str(description)
+ }
+}
+
+impl error::Error for CreationError {}
diff --git a/exercises/error_handling/errors6.rs b/exercises/error_handling/errors6.rs
new file mode 100644
index 0000000..0f6b27a
--- /dev/null
+++ b/exercises/error_handling/errors6.rs
@@ -0,0 +1,95 @@
+// errors6.rs
+
+// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
+// for library code, where callers might want to make decisions based on the
+// error content, instead of printing it out or propagating it further. Here,
+// we define a custom error type to make it possible for callers to decide
+// what to do next when our function returns an error.
+
+// Make these tests pass! Execute `rustlings hint errors6` for hints :)
+
+// I AM NOT DONE
+
+use std::num::ParseIntError;
+
+// This is a custom error type that we will be using in `parse_pos_nonzero()`.
+#[derive(PartialEq, Debug)]
+enum ParsePosNonzeroError {
+ Creation(CreationError),
+ ParseInt(ParseIntError)
+}
+
+impl ParsePosNonzeroError {
+ fn from_creation(err: CreationError) -> ParsePosNonzeroError {
+ ParsePosNonzeroError::Creation(err)
+ }
+ // TODO: add another error conversion function here.
+}
+
+fn parse_pos_nonzero(s: &str)
+ -> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
+{
+ // TODO: change this to return an appropriate error instead of panicking
+ // when `parse()` returns an error.
+ let x: i64 = s.parse().unwrap();
+ PositiveNonzeroInteger::new(x)
+ .map_err(ParsePosNonzeroError::from_creation)
+}
+
+// Don't change anything below this line.
+
+#[derive(PartialEq, Debug)]
+struct PositiveNonzeroInteger(u64);
+
+#[derive(PartialEq, Debug)]
+enum CreationError {
+ Negative,
+ Zero,
+}
+
+impl PositiveNonzeroInteger {
+ fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
+ match value {
+ x if x < 0 => Err(CreationError::Negative),
+ x if x == 0 => Err(CreationError::Zero),
+ x => Ok(PositiveNonzeroInteger(x as u64))
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_parse_error() {
+ // We can't construct a ParseIntError, so we have to pattern match.
+ assert!(matches!(
+ parse_pos_nonzero("not a number"),
+ Err(ParsePosNonzeroError::ParseInt(_))
+ ));
+ }
+
+ #[test]
+ fn test_negative() {
+ assert_eq!(
+ parse_pos_nonzero("-555"),
+ Err(ParsePosNonzeroError::Creation(CreationError::Negative))
+ );
+ }
+
+ #[test]
+ fn test_zero() {
+ assert_eq!(
+ parse_pos_nonzero("0"),
+ Err(ParsePosNonzeroError::Creation(CreationError::Zero))
+ );
+ }
+
+ #[test]
+ fn test_positive() {
+ let x = PositiveNonzeroInteger::new(42);
+ assert!(x.is_ok());
+ assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap()));
+ }
+}
diff --git a/exercises/error_handling/errorsn.rs b/exercises/error_handling/errorsn.rs
deleted file mode 100644
index 5fe212b..0000000
--- a/exercises/error_handling/errorsn.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-// errorsn.rs
-// This is a bigger error exercise than the previous ones!
-// You can do it! :)
-//
-// Edit the `read_and_validate` function ONLY. Don't create any Errors
-// that do not already exist.
-//
-// So many things could go wrong!
-//
-// - Reading from stdin could produce an io::Error
-// - Parsing the input could produce a num::ParseIntError
-// - Validating the input could produce a CreationError (defined below)
-//
-// How can we lump these errors into one general error? That is, what
-// type goes where the question marks are, and how do we return
-// that type from the body of read_and_validate?
-//
-// Execute `rustlings hint errorsn` for hints :)
-
-// I AM NOT DONE
-
-use std::error;
-use std::fmt;
-use std::io;
-
-// PositiveNonzeroInteger is a struct defined below the tests.
-fn read_and_validate(b: &mut dyn io::BufRead) -> Result<PositiveNonzeroInteger, ???> {
- let mut line = String::new();
- b.read_line(&mut line);
- let num: i64 = line.trim().parse();
- let answer = PositiveNonzeroInteger::new(num);
- answer
-}
-
-//
-// Nothing below this needs to be modified
-//
-
-// This is a test helper function that turns a &str into a BufReader.
-fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<dyn error::Error>> {
- let mut b = io::BufReader::new(s.as_bytes());
- read_and_validate(&mut b)
-}
-
-#[test]
-fn test_success() {
- let x = test_with_str("42\n");
- assert_eq!(PositiveNonzeroInteger(42), x.unwrap());
-}
-
-#[test]
-fn test_not_num() {
- let x = test_with_str("eleven billion\n");
- assert!(x.is_err());
-}
-
-#[test]
-fn test_non_positive() {
- let x = test_with_str("-40\n");
- assert!(x.is_err());
-}
-
-#[test]
-fn test_ioerror() {
- struct Broken;
- impl io::Read for Broken {
- fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
- Err(io::Error::new(io::ErrorKind::BrokenPipe, "uh-oh!"))
- }
- }
- let mut b = io::BufReader::new(Broken);
- assert!(read_and_validate(&mut b).is_err());
- assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string());
-}
-
-#[derive(PartialEq, Debug)]
-struct PositiveNonzeroInteger(u64);
-
-impl PositiveNonzeroInteger {
- fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
- if value == 0 {
- Err(CreationError::Zero)
- } else if value < 0 {
- Err(CreationError::Negative)
- } else {
- Ok(PositiveNonzeroInteger(value as u64))
- }
- }
-}
-
-#[test]
-fn test_positive_nonzero_integer_creation() {
- assert!(PositiveNonzeroInteger::new(10).is_ok());
- assert_eq!(
- Err(CreationError::Negative),
- PositiveNonzeroInteger::new(-10)
- );
- assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
-}
-
-#[derive(PartialEq, Debug)]
-enum CreationError {
- Negative,
- Zero,
-}
-
-impl fmt::Display for CreationError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let description = match *self {
- CreationError::Negative => "Number is negative",
- CreationError::Zero => "Number is zero",
- };
- f.write_str(description)
- }
-}
-
-impl error::Error for CreationError {}