#![allow(trivial_numeric_casts)]
#[macro_use]
extern crate grust;
extern crate glib_2_0_sys as glib;
use grust::enumeration::IntrospectedEnum;
use grust::enumeration::UnknownValue as UnknownEnumValue;
use grust::error;
use grust::error::{Error, Domain, DomainError};
use grust::boxed;
use grust::quark::Quark;
use grust::types::gint;
use grust::value::Value;
use std::error::Error as ErrorTrait;
use std::ffi::CString;
use std::str;
const NON_UTF8: &'static [u8] = b"U can't parse this.\x9c Hammer time!";
const NON_UTF8_LOSSY: &'static str = "U can't parse this.\u{FFFD} Hammer time!";
const NON_UTF8_ESCAPED: &'static str = r#"U can\'t parse this.\x9c Hammer time!"#;
const A_FOO: gint = 1;
const A_BAR: gint = 2;
const B_BAZ: gint = 1;
const UNKNOWN_CODE: gint = 1337;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum AError {
Foo = A_FOO as isize,
Bar = A_BAR as isize,
}
impl IntrospectedEnum for AError {
fn from_int(v: gint) -> Result<Self, UnknownEnumValue> {
match v {
A_FOO => Ok(AError::Foo),
A_BAR => Ok(AError::Bar),
_ => Err(UnknownEnumValue(v))
}
}
fn to_int(&self) -> gint {
*self as gint
}
fn name(&self) -> &'static str {
match *self {
AError::Foo => "foo",
AError::Bar => "bar"
}
}
}
impl Domain for AError {
fn domain() -> Quark {
g_static_quark!(b"a-error\0")
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum BError {
Baz = B_BAZ as isize
}
impl IntrospectedEnum for BError {
fn from_int(v: gint) -> Result<Self, UnknownEnumValue> {
match v {
B_BAZ => Ok(BError::Baz),
_ => Err(UnknownEnumValue(v))
}
}
fn to_int(&self) -> gint {
*self as gint
}
fn name(&self) -> &'static str {
match *self {
BError::Baz => "baz"
}
}
}
impl Domain for BError {
fn domain() -> Quark {
g_static_quark!(b"b-error\0")
}
}
fn new_error<T>(code: gint, message: &[u8]) -> Error where T: Domain {
let domain = error::domain::<T>();
let msg_buf = CString::new(message).unwrap();
unsafe {
let raw = glib::g_error_new_literal(
domain.to_raw(), code, msg_buf.as_ptr());
Error::from_raw(raw)
}
}
fn new_domain_error<T>(code: gint, message: &[u8]) -> DomainError<T>
where T: Domain
{
new_error::<T>(code, message).into_domain().unwrap()
}
#[test]
fn test_domain() {
let domain = error::domain::<AError>();
assert_eq!(domain, <AError as Domain>::domain());
assert_eq!(domain.to_bytes(), b"a-error");
let domain = error::domain::<BError>();
assert_eq!(domain, <BError as Domain>::domain());
assert_eq!(domain.to_bytes(), b"b-error");
}
#[test]
fn test_error_domain() {
let err = new_error::<AError>(A_FOO, b"test error");
assert_eq!(err.domain(), error::domain::<AError>());
}
#[test]
fn test_error_matches() {
let err = new_error::<AError>(A_FOO, b"test error");
assert!(err.matches(AError::Foo));
assert!(!err.matches(AError::Bar));
assert!(!err.matches(BError::Baz));
}
#[test]
fn test_error_key() {
let err_foo1 = new_error::<AError>(A_FOO, b"test error");
let err_foo2 = new_error::<AError>(A_FOO, b"same error, different message");
assert_eq!(err_foo1.key(), err_foo2.key());
let err_bar = new_error::<AError>(A_BAR, b"test error");
assert!(err_foo1.key() != err_bar.key());
let err_baz = new_error::<BError>(B_BAZ, b"test error");
assert!(err_foo1.key() != err_baz.key());
}
#[test]
fn test_error_in_domain() {
let err = new_error::<AError>(A_FOO, b"test error");
assert!(err.in_domain::<AError>());
assert!(!err.in_domain::<BError>());
}
#[test]
fn test_error_into_domain() {
let err = new_error::<AError>(A_FOO, b"test error");
let res = err.into_domain::<AError>();
let a_err = res.unwrap();
assert_eq!(a_err.code(), error::Code::Known(AError::Foo));
}
#[test]
fn test_domain_error_code() {
let err = new_domain_error::<AError>(A_FOO, b"test error");
let code = err.code();
match code {
error::Code::Known(c) => assert_eq!(c, AError::Foo),
error::Code::Unknown(_) => unreachable!()
}
let known = code.known();
assert_eq!(known, Some(AError::Foo));
let err = new_domain_error::<AError>(UNKNOWN_CODE, b"unknown error");
let code = err.code();
match code {
error::Code::Known(_) => unreachable!(),
error::Code::Unknown(int_code) => assert_eq!(int_code, UNKNOWN_CODE)
}
let known = code.known();
assert!(known.is_none());
}
#[test]
fn test_error_description() {
let message = "test error";
let err = new_error::<AError>(A_FOO, message.as_bytes());
assert_eq!(err.description(), message);
let err = new_error::<AError>(A_FOO, NON_UTF8);
assert_eq!(err.description(), "a-error");
}
#[test]
fn test_domain_error_description() {
let message = "test error";
let err = new_domain_error::<AError>(A_FOO, message.as_bytes());
assert_eq!(err.description(), message);
let err = new_domain_error::<AError>(A_FOO, NON_UTF8);
assert_eq!(err.description(), "foo");
}
#[test]
fn test_error_display() {
let message = "test error";
let err = new_error::<AError>(A_FOO, message.as_bytes());
let s = format!("{}", err);
assert_eq!(&s[..], message);
let err = new_error::<AError>(A_FOO, NON_UTF8);
let s = format!("{}", err);
assert_eq!(&s[..], NON_UTF8_LOSSY)
}
#[test]
fn test_domain_error_display() {
let message = "test error";
let err = new_domain_error::<AError>(A_FOO, message.as_bytes());
let s = format!("{}", err);
assert_eq!(&s[..], message);
let err = new_domain_error::<AError>(A_FOO, NON_UTF8);
let s = format!("{}", err);
assert_eq!(&s[..], NON_UTF8_LOSSY)
}
macro_rules! assert_contains_or_dump {
($inp:expr, $needle:expr) => {
assert!($inp.contains($needle),
"unexpected `Debug` formatting: `{}`", $inp)
}
}
macro_rules! assert_contains {
($inp:expr, $str:expr) => (
assert_contains_or_dump!($inp, $str)
);
($inp:expr, $fmt:expr, $($arg:expr),*) => (
assert_contains_or_dump!($inp, &format!($fmt, $($arg),*)[..])
)
}
#[test]
fn test_error_debug() {
let message = "test error";
let err = new_error::<AError>(A_FOO, message.as_bytes());
let s = format!("{:?}", err);
let (domain, code) = err.key();
let domain_str = str::from_utf8(domain.to_bytes()).unwrap();
assert_contains!(s, "GError");
assert_contains!(s, "{}", domain_str);
assert_contains!(s, "{}", code);
assert_contains!(s, r#""{}""#, message);
let err = new_error::<BError>(B_BAZ, NON_UTF8);
let s = format!("{:?}", err);
let (domain, code) = err.key();
let domain_str = str::from_utf8(domain.to_bytes()).unwrap();
assert_contains!(s, "GError");
assert_contains!(s, "{}", domain_str);
assert_contains!(s, "{}", code);
assert_contains!(s, r#""{}""#, NON_UTF8_ESCAPED);
}
#[test]
fn test_domain_error_debug() {
let message = "test error";
let err = new_domain_error::<AError>(A_FOO, message.as_bytes());
let s = format!("{:?}", err);
let domain = error::domain::<AError>();
let domain_str = str::from_utf8(domain.to_bytes()).unwrap();
let code = err.code().known().unwrap();
assert_contains!(s, "GError");
assert_contains!(s, "{}", domain_str);
assert_contains!(s, "{}", code.name());
assert_contains!(s, r#""{}""#, message);
let err = new_domain_error::<BError>(B_BAZ, NON_UTF8);
let s = format!("{:?}", err);
let domain = error::domain::<BError>();
let domain_str = str::from_utf8(domain.to_bytes()).unwrap();
let code = err.code().known().unwrap();
assert_contains!(s, "GError");
assert_contains!(s, "{}", domain_str);
assert_contains!(s, "{}", code.name());
assert_contains!(s, r#""{}""#, NON_UTF8_ESCAPED);
let err = new_domain_error::<AError>(UNKNOWN_CODE, b"unknown error");
let s = format!("{:?}", err);
let domain = error::domain::<AError>();
let domain_str = str::from_utf8(domain.to_bytes()).unwrap();
assert_contains!(s, "GError");
assert_contains!(s, "{}", domain_str);
assert_contains!(s, "{}", UNKNOWN_CODE);
}
#[test]
fn test_error_from_domain_error() {
let message = "test error";
let domain_err = new_domain_error::<AError>(A_FOO, message.as_bytes());
let err = Error::from(domain_err);
let (domain, code) = err.key();
assert_eq!(domain, error::domain::<AError>());
assert_eq!(code, A_FOO);
assert_eq!(err.description(), message);
}
#[test]
fn test_error_clone() {
let message = "test error";
let err = new_error::<AError>(A_FOO, message.as_bytes());
let err2 = err.clone();
assert_eq!(err2.description(), message);
}
#[test]
fn test_domain_error_clone() {
let message = "test error";
let err = new_domain_error::<AError>(A_FOO, message.as_bytes());
let err2 = err.clone();
assert_eq!(err2.description(), message);
}
#[test]
fn test_error_match_macro() {
let err = new_error::<AError>(A_FOO, b"test error");
g_error_match! {
(err) {
other any_err => {
any_err.into_domain::<AError>().unwrap();
}
}
}
let err = new_error::<AError>(A_FOO, b"test error");
g_error_match! {
(err) {
(a_err: DomainError<AError>) => {
assert_eq!(a_err.code(), error::Code::Known(AError::Foo));
},
(_b_err: DomainError<BError>) => unreachable!(),
other _err => unreachable!()
}
}
}
#[test]
fn test_boxed_error() {
let mut value = Value::new(boxed::type_of::<Error>());
value.take_boxed(new_error::<AError>(A_FOO, b"test error"));
let value = value.clone();
let err = value.dup_boxed().unwrap();
g_error_match! {
(err) {
(a_err: DomainError<AError>) => {
assert_eq!(a_err.code(), error::Code::Known(AError::Foo));
},
other _err => unreachable!()
}
}
}