blob: afbbe3a92c4cd4fb1979d4a732945d402d631bca [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use failure::{Error, Fail};
use fidl_fuchsia_auth_account::Status;
/// An extension trait to simplify conversion of results based on general errors to
/// AccountManagerErrors.
pub trait ResultExt<T, E> {
/// Wraps the error in a non-fatal `AccountManagerError` with the supplied `Status`.
fn account_manager_status(self, status: Status) -> Result<T, AccountManagerError>;
}
impl<T, E> ResultExt<T, E> for Result<T, E>
where
E: Into<Error> + Send + Sync + Sized,
{
fn account_manager_status(self, status: Status) -> Result<T, AccountManagerError> {
self.map_err(|err| AccountManagerError::new(status).with_cause(err))
}
}
/// An Error type for problems encountered in the account manager and account handler. Each error
/// contains the fuchsia.auth.account.Status that should be reported back to the client and an
/// indication of whether it is fatal.
#[derive(Debug, Fail)]
#[fail(display = "AccountManager error, returning {:?}. ({:?})", status, cause)]
pub struct AccountManagerError {
/// The most appropriate `fuchsia.auth.account.Status` to describe this problem.
pub status: Status,
/// Whether this error should be considered fatal, i.e. whether it should
/// terminate processing of all requests on the current channel.
pub fatal: bool,
/// The root cause of this error, if available.
pub cause: Option<Error>,
}
impl AccountManagerError {
/// Constructs a new non-fatal error based on the supplied `Status`.
pub fn new(status: Status) -> Self {
AccountManagerError {
status,
fatal: false,
cause: None,
}
}
/// Sets a cause on the current error.
pub fn with_cause<T: Into<Error>>(mut self, cause: T) -> Self {
self.cause = Some(cause.into());
self
}
}
impl From<Status> for AccountManagerError {
fn from(status: Status) -> Self {
AccountManagerError::new(status)
}
}
#[cfg(test)]
mod tests {
use super::*;
use failure::format_err;
const TEST_STATUS: Status = Status::UnknownError;
fn create_test_error() -> Error {
format_err!("Test error")
}
#[test]
fn test_new() {
let cause = format_err!("Example cause");
let error = AccountManagerError::new(TEST_STATUS).with_cause(cause);
assert_eq!(error.status, TEST_STATUS);
assert!(!error.fatal);
assert!(error.cause.is_some());
}
#[test]
fn test_from_status() {
let error: AccountManagerError = TEST_STATUS.into();
assert_eq!(error.status, TEST_STATUS);
assert!(!error.fatal);
assert!(error.cause.is_none());
}
#[test]
fn test_account_manager_status() {
let test_result: Result<(), Error> = Err(create_test_error());
let wrapped_result = test_result.account_manager_status(TEST_STATUS);
assert_eq!(wrapped_result.as_ref().unwrap_err().status, TEST_STATUS);
assert_eq!(
format!("{:?}", wrapped_result.unwrap_err().cause.unwrap()),
format!("{:?}", create_test_error()));
}
}