summaryrefslogtreecommitdiffstats
path: root/third_party/rust/anyhow/tests
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/anyhow/tests')
-rw-r--r--third_party/rust/anyhow/tests/common/mod.rs14
-rw-r--r--third_party/rust/anyhow/tests/compiletest.rs6
-rw-r--r--third_party/rust/anyhow/tests/drop/mod.rs52
-rw-r--r--third_party/rust/anyhow/tests/test_autotrait.rs13
-rw-r--r--third_party/rust/anyhow/tests/test_backtrace.rs13
-rw-r--r--third_party/rust/anyhow/tests/test_boxed.rs40
-rw-r--r--third_party/rust/anyhow/tests/test_chain.rs45
-rw-r--r--third_party/rust/anyhow/tests/test_context.rs159
-rw-r--r--third_party/rust/anyhow/tests/test_convert.rs24
-rw-r--r--third_party/rust/anyhow/tests/test_downcast.rs106
-rw-r--r--third_party/rust/anyhow/tests/test_fmt.rs94
-rw-r--r--third_party/rust/anyhow/tests/test_macros.rs33
-rw-r--r--third_party/rust/anyhow/tests/test_repr.rs29
-rw-r--r--third_party/rust/anyhow/tests/test_source.rs62
-rw-r--r--third_party/rust/anyhow/tests/ui/no-impl.rs8
-rw-r--r--third_party/rust/anyhow/tests/ui/no-impl.stderr21
16 files changed, 719 insertions, 0 deletions
diff --git a/third_party/rust/anyhow/tests/common/mod.rs b/third_party/rust/anyhow/tests/common/mod.rs
new file mode 100644
index 0000000000..fc165a5be9
--- /dev/null
+++ b/third_party/rust/anyhow/tests/common/mod.rs
@@ -0,0 +1,14 @@
+use anyhow::{bail, Result};
+use std::io;
+
+pub fn bail_literal() -> Result<()> {
+ bail!("oh no!");
+}
+
+pub fn bail_fmt() -> Result<()> {
+ bail!("{} {}!", "oh", "no");
+}
+
+pub fn bail_error() -> Result<()> {
+ bail!(io::Error::new(io::ErrorKind::Other, "oh no!"));
+}
diff --git a/third_party/rust/anyhow/tests/compiletest.rs b/third_party/rust/anyhow/tests/compiletest.rs
new file mode 100644
index 0000000000..f9aea23b51
--- /dev/null
+++ b/third_party/rust/anyhow/tests/compiletest.rs
@@ -0,0 +1,6 @@
+#[rustversion::attr(not(nightly), ignore)]
+#[test]
+fn ui() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/*.rs");
+}
diff --git a/third_party/rust/anyhow/tests/drop/mod.rs b/third_party/rust/anyhow/tests/drop/mod.rs
new file mode 100644
index 0000000000..c9d7144479
--- /dev/null
+++ b/third_party/rust/anyhow/tests/drop/mod.rs
@@ -0,0 +1,52 @@
+use std::error::Error as StdError;
+use std::fmt::{self, Display};
+use std::sync::atomic::AtomicBool;
+use std::sync::atomic::Ordering::SeqCst;
+use std::sync::Arc;
+
+#[derive(Debug)]
+pub struct Flag {
+ atomic: Arc<AtomicBool>,
+}
+
+impl Flag {
+ pub fn new() -> Self {
+ Flag {
+ atomic: Arc::new(AtomicBool::new(false)),
+ }
+ }
+
+ pub fn get(&self) -> bool {
+ self.atomic.load(SeqCst)
+ }
+}
+
+#[derive(Debug)]
+pub struct DetectDrop {
+ has_dropped: Flag,
+}
+
+impl DetectDrop {
+ pub fn new(has_dropped: &Flag) -> Self {
+ DetectDrop {
+ has_dropped: Flag {
+ atomic: Arc::clone(&has_dropped.atomic),
+ },
+ }
+ }
+}
+
+impl StdError for DetectDrop {}
+
+impl Display for DetectDrop {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "oh no!")
+ }
+}
+
+impl Drop for DetectDrop {
+ fn drop(&mut self) {
+ let already_dropped = self.has_dropped.atomic.swap(true, SeqCst);
+ assert!(!already_dropped);
+ }
+}
diff --git a/third_party/rust/anyhow/tests/test_autotrait.rs b/third_party/rust/anyhow/tests/test_autotrait.rs
new file mode 100644
index 0000000000..0c9326dad6
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_autotrait.rs
@@ -0,0 +1,13 @@
+use anyhow::Error;
+
+#[test]
+fn test_send() {
+ fn assert_send<T: Send>() {}
+ assert_send::<Error>();
+}
+
+#[test]
+fn test_sync() {
+ fn assert_sync<T: Sync>() {}
+ assert_sync::<Error>();
+}
diff --git a/third_party/rust/anyhow/tests/test_backtrace.rs b/third_party/rust/anyhow/tests/test_backtrace.rs
new file mode 100644
index 0000000000..ce385f5011
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_backtrace.rs
@@ -0,0 +1,13 @@
+#[rustversion::not(nightly)]
+#[ignore]
+#[test]
+fn test_backtrace() {}
+
+#[rustversion::nightly]
+#[test]
+fn test_backtrace() {
+ use anyhow::anyhow;
+
+ let error = anyhow!("oh no!");
+ let _ = error.backtrace();
+}
diff --git a/third_party/rust/anyhow/tests/test_boxed.rs b/third_party/rust/anyhow/tests/test_boxed.rs
new file mode 100644
index 0000000000..38a568fb73
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_boxed.rs
@@ -0,0 +1,40 @@
+use anyhow::anyhow;
+use std::error::Error as StdError;
+use std::io;
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+#[error("outer")]
+struct MyError {
+ source: io::Error,
+}
+
+#[test]
+fn test_boxed_str() {
+ let error = Box::<dyn StdError + Send + Sync>::from("oh no!");
+ let error = anyhow!(error);
+ assert_eq!("oh no!", error.to_string());
+ assert_eq!(
+ "oh no!",
+ error
+ .downcast_ref::<Box<dyn StdError + Send + Sync>>()
+ .unwrap()
+ .to_string()
+ );
+}
+
+#[test]
+fn test_boxed_thiserror() {
+ let error = MyError {
+ source: io::Error::new(io::ErrorKind::Other, "oh no!"),
+ };
+ let error = anyhow!(error);
+ assert_eq!("oh no!", error.source().unwrap().to_string());
+}
+
+#[test]
+fn test_boxed_anyhow() {
+ let error = anyhow!("oh no!").context("it failed");
+ let error = anyhow!(error);
+ assert_eq!("oh no!", error.source().unwrap().to_string());
+}
diff --git a/third_party/rust/anyhow/tests/test_chain.rs b/third_party/rust/anyhow/tests/test_chain.rs
new file mode 100644
index 0000000000..b1c5a3daaa
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_chain.rs
@@ -0,0 +1,45 @@
+use anyhow::{anyhow, Error};
+
+fn error() -> Error {
+ anyhow!(0).context(1).context(2).context(3)
+}
+
+#[test]
+fn test_iter() {
+ let e = error();
+ let mut chain = e.chain();
+ assert_eq!("3", chain.next().unwrap().to_string());
+ assert_eq!("2", chain.next().unwrap().to_string());
+ assert_eq!("1", chain.next().unwrap().to_string());
+ assert_eq!("0", chain.next().unwrap().to_string());
+ assert!(chain.next().is_none());
+ assert!(chain.next_back().is_none());
+}
+
+#[test]
+fn test_rev() {
+ let e = error();
+ let mut chain = e.chain().rev();
+ assert_eq!("0", chain.next().unwrap().to_string());
+ assert_eq!("1", chain.next().unwrap().to_string());
+ assert_eq!("2", chain.next().unwrap().to_string());
+ assert_eq!("3", chain.next().unwrap().to_string());
+ assert!(chain.next().is_none());
+ assert!(chain.next_back().is_none());
+}
+
+#[test]
+fn test_len() {
+ let e = error();
+ let mut chain = e.chain();
+ assert_eq!(4, chain.len());
+ assert_eq!("3", chain.next().unwrap().to_string());
+ assert_eq!(3, chain.len());
+ assert_eq!("0", chain.next_back().unwrap().to_string());
+ assert_eq!(2, chain.len());
+ assert_eq!("2", chain.next().unwrap().to_string());
+ assert_eq!(1, chain.len());
+ assert_eq!("1", chain.next_back().unwrap().to_string());
+ assert_eq!(0, chain.len());
+ assert!(chain.next().is_none());
+}
diff --git a/third_party/rust/anyhow/tests/test_context.rs b/third_party/rust/anyhow/tests/test_context.rs
new file mode 100644
index 0000000000..44c1c7036e
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_context.rs
@@ -0,0 +1,159 @@
+mod drop;
+
+use crate::drop::{DetectDrop, Flag};
+use anyhow::{Context, Error, Result};
+use std::fmt::{self, Display};
+use thiserror::Error;
+
+// https://github.com/dtolnay/anyhow/issues/18
+#[test]
+fn test_inference() -> Result<()> {
+ let x = "1";
+ let y: u32 = x.parse().context("...")?;
+ assert_eq!(y, 1);
+ Ok(())
+}
+
+macro_rules! context_type {
+ ($name:ident) => {
+ #[derive(Debug)]
+ struct $name {
+ message: &'static str,
+ drop: DetectDrop,
+ }
+
+ impl Display for $name {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(self.message)
+ }
+ }
+ };
+}
+
+context_type!(HighLevel);
+context_type!(MidLevel);
+
+#[derive(Error, Debug)]
+#[error("{message}")]
+struct LowLevel {
+ message: &'static str,
+ drop: DetectDrop,
+}
+
+struct Dropped {
+ low: Flag,
+ mid: Flag,
+ high: Flag,
+}
+
+impl Dropped {
+ fn none(&self) -> bool {
+ !self.low.get() && !self.mid.get() && !self.high.get()
+ }
+
+ fn all(&self) -> bool {
+ self.low.get() && self.mid.get() && self.high.get()
+ }
+}
+
+fn make_chain() -> (Error, Dropped) {
+ let dropped = Dropped {
+ low: Flag::new(),
+ mid: Flag::new(),
+ high: Flag::new(),
+ };
+
+ let low = LowLevel {
+ message: "no such file or directory",
+ drop: DetectDrop::new(&dropped.low),
+ };
+
+ // impl Context for Result<T, E>
+ let mid = Err::<(), LowLevel>(low)
+ .context(MidLevel {
+ message: "failed to load config",
+ drop: DetectDrop::new(&dropped.mid),
+ })
+ .unwrap_err();
+
+ // impl Context for Result<T, Error>
+ let high = Err::<(), Error>(mid)
+ .context(HighLevel {
+ message: "failed to start server",
+ drop: DetectDrop::new(&dropped.high),
+ })
+ .unwrap_err();
+
+ (high, dropped)
+}
+
+#[test]
+fn test_downcast_ref() {
+ let (err, dropped) = make_chain();
+
+ assert!(!err.is::<String>());
+ assert!(err.downcast_ref::<String>().is_none());
+
+ assert!(err.is::<HighLevel>());
+ let high = err.downcast_ref::<HighLevel>().unwrap();
+ assert_eq!(high.to_string(), "failed to start server");
+
+ assert!(err.is::<MidLevel>());
+ let mid = err.downcast_ref::<MidLevel>().unwrap();
+ assert_eq!(mid.to_string(), "failed to load config");
+
+ assert!(err.is::<LowLevel>());
+ let low = err.downcast_ref::<LowLevel>().unwrap();
+ assert_eq!(low.to_string(), "no such file or directory");
+
+ assert!(dropped.none());
+ drop(err);
+ assert!(dropped.all());
+}
+
+#[test]
+fn test_downcast_high() {
+ let (err, dropped) = make_chain();
+
+ let err = err.downcast::<HighLevel>().unwrap();
+ assert!(!dropped.high.get());
+ assert!(dropped.low.get() && dropped.mid.get());
+
+ drop(err);
+ assert!(dropped.all());
+}
+
+#[test]
+fn test_downcast_mid() {
+ let (err, dropped) = make_chain();
+
+ let err = err.downcast::<MidLevel>().unwrap();
+ assert!(!dropped.mid.get());
+ assert!(dropped.low.get() && dropped.high.get());
+
+ drop(err);
+ assert!(dropped.all());
+}
+
+#[test]
+fn test_downcast_low() {
+ let (err, dropped) = make_chain();
+
+ let err = err.downcast::<LowLevel>().unwrap();
+ assert!(!dropped.low.get());
+ assert!(dropped.mid.get() && dropped.high.get());
+
+ drop(err);
+ assert!(dropped.all());
+}
+
+#[test]
+fn test_unsuccessful_downcast() {
+ let (err, dropped) = make_chain();
+
+ let err = err.downcast::<String>().unwrap_err();
+ assert!(dropped.none());
+
+ drop(err);
+ assert!(dropped.all());
+}
diff --git a/third_party/rust/anyhow/tests/test_convert.rs b/third_party/rust/anyhow/tests/test_convert.rs
new file mode 100644
index 0000000000..72da020be6
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_convert.rs
@@ -0,0 +1,24 @@
+mod drop;
+
+use self::drop::{DetectDrop, Flag};
+use anyhow::{Error, Result};
+use std::error::Error as StdError;
+
+#[test]
+fn test_convert() {
+ let has_dropped = Flag::new();
+ let error = Error::new(DetectDrop::new(&has_dropped));
+ let box_dyn = Box::<dyn StdError + Send + Sync>::from(error);
+ assert_eq!("oh no!", box_dyn.to_string());
+ drop(box_dyn);
+ assert!(has_dropped.get());
+}
+
+#[test]
+fn test_question_mark() -> Result<(), Box<dyn StdError>> {
+ fn f() -> Result<()> {
+ Ok(())
+ }
+ f()?;
+ Ok(())
+}
diff --git a/third_party/rust/anyhow/tests/test_downcast.rs b/third_party/rust/anyhow/tests/test_downcast.rs
new file mode 100644
index 0000000000..c2c3e129ff
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_downcast.rs
@@ -0,0 +1,106 @@
+mod common;
+mod drop;
+
+use self::common::*;
+use self::drop::{DetectDrop, Flag};
+use anyhow::Error;
+use std::error::Error as StdError;
+use std::fmt::{self, Display};
+use std::io;
+
+#[test]
+fn test_downcast() {
+ assert_eq!(
+ "oh no!",
+ bail_literal().unwrap_err().downcast::<&str>().unwrap(),
+ );
+ assert_eq!(
+ "oh no!",
+ bail_fmt().unwrap_err().downcast::<String>().unwrap(),
+ );
+ assert_eq!(
+ "oh no!",
+ bail_error()
+ .unwrap_err()
+ .downcast::<io::Error>()
+ .unwrap()
+ .to_string(),
+ );
+}
+
+#[test]
+fn test_downcast_ref() {
+ assert_eq!(
+ "oh no!",
+ *bail_literal().unwrap_err().downcast_ref::<&str>().unwrap(),
+ );
+ assert_eq!(
+ "oh no!",
+ bail_fmt().unwrap_err().downcast_ref::<String>().unwrap(),
+ );
+ assert_eq!(
+ "oh no!",
+ bail_error()
+ .unwrap_err()
+ .downcast_ref::<io::Error>()
+ .unwrap()
+ .to_string(),
+ );
+}
+
+#[test]
+fn test_downcast_mut() {
+ assert_eq!(
+ "oh no!",
+ *bail_literal().unwrap_err().downcast_mut::<&str>().unwrap(),
+ );
+ assert_eq!(
+ "oh no!",
+ bail_fmt().unwrap_err().downcast_mut::<String>().unwrap(),
+ );
+ assert_eq!(
+ "oh no!",
+ bail_error()
+ .unwrap_err()
+ .downcast_mut::<io::Error>()
+ .unwrap()
+ .to_string(),
+ );
+}
+
+#[test]
+fn test_drop() {
+ let has_dropped = Flag::new();
+ let error = Error::new(DetectDrop::new(&has_dropped));
+ drop(error.downcast::<DetectDrop>().unwrap());
+ assert!(has_dropped.get());
+}
+
+#[test]
+fn test_large_alignment() {
+ #[repr(align(64))]
+ #[derive(Debug)]
+ struct LargeAlignedError(&'static str);
+
+ impl Display for LargeAlignedError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(self.0)
+ }
+ }
+
+ impl StdError for LargeAlignedError {}
+
+ let error = Error::new(LargeAlignedError("oh no!"));
+ assert_eq!(
+ "oh no!",
+ error.downcast_ref::<LargeAlignedError>().unwrap().0
+ );
+}
+
+#[test]
+fn test_unsuccessful_downcast() {
+ let mut error = bail_error().unwrap_err();
+ assert!(error.downcast_ref::<&str>().is_none());
+ assert!(error.downcast_mut::<&str>().is_none());
+ assert!(error.downcast::<&str>().is_err());
+}
diff --git a/third_party/rust/anyhow/tests/test_fmt.rs b/third_party/rust/anyhow/tests/test_fmt.rs
new file mode 100644
index 0000000000..cc4929197d
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_fmt.rs
@@ -0,0 +1,94 @@
+use anyhow::{bail, Context, Result};
+use std::io;
+
+fn f() -> Result<()> {
+ bail!(io::Error::new(io::ErrorKind::PermissionDenied, "oh no!"));
+}
+
+fn g() -> Result<()> {
+ f().context("f failed")
+}
+
+fn h() -> Result<()> {
+ g().context("g failed")
+}
+
+const EXPECTED_ALTDISPLAY_F: &str = "oh no!";
+
+const EXPECTED_ALTDISPLAY_G: &str = "f failed: oh no!";
+
+const EXPECTED_ALTDISPLAY_H: &str = "g failed: f failed: oh no!";
+
+const EXPECTED_DEBUG_F: &str = "oh no!";
+
+const EXPECTED_DEBUG_G: &str = "\
+f failed
+
+Caused by:
+ oh no!\
+";
+
+const EXPECTED_DEBUG_H: &str = "\
+g failed
+
+Caused by:
+ 0: f failed
+ 1: oh no!\
+";
+
+const EXPECTED_ALTDEBUG_F: &str = "\
+Custom {
+ kind: PermissionDenied,
+ error: \"oh no!\",
+}\
+";
+
+const EXPECTED_ALTDEBUG_G: &str = "\
+Error {
+ context: \"f failed\",
+ source: Custom {
+ kind: PermissionDenied,
+ error: \"oh no!\",
+ },
+}\
+";
+
+const EXPECTED_ALTDEBUG_H: &str = "\
+Error {
+ context: \"g failed\",
+ source: Error {
+ context: \"f failed\",
+ source: Custom {
+ kind: PermissionDenied,
+ error: \"oh no!\",
+ },
+ },
+}\
+";
+
+#[test]
+fn test_display() {
+ assert_eq!("g failed", h().unwrap_err().to_string());
+}
+
+#[test]
+fn test_altdisplay() {
+ assert_eq!(EXPECTED_ALTDISPLAY_F, format!("{:#}", f().unwrap_err()));
+ assert_eq!(EXPECTED_ALTDISPLAY_G, format!("{:#}", g().unwrap_err()));
+ assert_eq!(EXPECTED_ALTDISPLAY_H, format!("{:#}", h().unwrap_err()));
+}
+
+#[test]
+#[cfg_attr(not(backtrace), ignore)]
+fn test_debug() {
+ assert_eq!(EXPECTED_DEBUG_F, format!("{:?}", f().unwrap_err()));
+ assert_eq!(EXPECTED_DEBUG_G, format!("{:?}", g().unwrap_err()));
+ assert_eq!(EXPECTED_DEBUG_H, format!("{:?}", h().unwrap_err()));
+}
+
+#[test]
+fn test_altdebug() {
+ assert_eq!(EXPECTED_ALTDEBUG_F, format!("{:#?}", f().unwrap_err()));
+ assert_eq!(EXPECTED_ALTDEBUG_G, format!("{:#?}", g().unwrap_err()));
+ assert_eq!(EXPECTED_ALTDEBUG_H, format!("{:#?}", h().unwrap_err()));
+}
diff --git a/third_party/rust/anyhow/tests/test_macros.rs b/third_party/rust/anyhow/tests/test_macros.rs
new file mode 100644
index 0000000000..c6888b6b63
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_macros.rs
@@ -0,0 +1,33 @@
+mod common;
+
+use self::common::*;
+use anyhow::ensure;
+
+#[test]
+fn test_messages() {
+ assert_eq!("oh no!", bail_literal().unwrap_err().to_string());
+ assert_eq!("oh no!", bail_fmt().unwrap_err().to_string());
+ assert_eq!("oh no!", bail_error().unwrap_err().to_string());
+}
+
+#[test]
+fn test_ensure() {
+ let f = || {
+ ensure!(1 + 1 == 2, "This is correct");
+ Ok(())
+ };
+ assert!(f().is_ok());
+
+ let v = 1;
+ let f = || {
+ ensure!(v + v == 2, "This is correct, v: {}", v);
+ Ok(())
+ };
+ assert!(f().is_ok());
+
+ let f = || {
+ ensure!(v + v == 1, "This is not correct, v: {}", v);
+ Ok(())
+ };
+ assert!(f().is_err());
+}
diff --git a/third_party/rust/anyhow/tests/test_repr.rs b/third_party/rust/anyhow/tests/test_repr.rs
new file mode 100644
index 0000000000..72f5002ae1
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_repr.rs
@@ -0,0 +1,29 @@
+mod drop;
+
+use self::drop::{DetectDrop, Flag};
+use anyhow::Error;
+use std::marker::Unpin;
+use std::mem;
+
+#[test]
+fn test_error_size() {
+ assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
+}
+
+#[test]
+fn test_null_pointer_optimization() {
+ assert_eq!(mem::size_of::<Result<(), Error>>(), mem::size_of::<usize>());
+}
+
+#[test]
+fn test_autotraits() {
+ fn assert<E: Unpin + Send + Sync + 'static>() {}
+ assert::<Error>();
+}
+
+#[test]
+fn test_drop() {
+ let has_dropped = Flag::new();
+ drop(Error::new(DetectDrop::new(&has_dropped)));
+ assert!(has_dropped.get());
+}
diff --git a/third_party/rust/anyhow/tests/test_source.rs b/third_party/rust/anyhow/tests/test_source.rs
new file mode 100644
index 0000000000..018267d315
--- /dev/null
+++ b/third_party/rust/anyhow/tests/test_source.rs
@@ -0,0 +1,62 @@
+use anyhow::anyhow;
+use std::error::Error as StdError;
+use std::fmt::{self, Display};
+use std::io;
+
+#[derive(Debug)]
+enum TestError {
+ Io(io::Error),
+}
+
+impl Display for TestError {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ TestError::Io(e) => Display::fmt(e, formatter),
+ }
+ }
+}
+
+impl StdError for TestError {
+ fn source(&self) -> Option<&(dyn StdError + 'static)> {
+ match self {
+ TestError::Io(io) => Some(io),
+ }
+ }
+}
+
+#[test]
+fn test_literal_source() {
+ let error = anyhow!("oh no!");
+ assert!(error.source().is_none());
+}
+
+#[test]
+fn test_variable_source() {
+ let msg = "oh no!";
+ let error = anyhow!(msg);
+ assert!(error.source().is_none());
+
+ let msg = msg.to_owned();
+ let error = anyhow!(msg);
+ assert!(error.source().is_none());
+}
+
+#[test]
+fn test_fmt_source() {
+ let error = anyhow!("{} {}!", "oh", "no");
+ assert!(error.source().is_none());
+}
+
+#[test]
+fn test_io_source() {
+ let io = io::Error::new(io::ErrorKind::Other, "oh no!");
+ let error = anyhow!(TestError::Io(io));
+ assert_eq!("oh no!", error.source().unwrap().to_string());
+}
+
+#[test]
+fn test_anyhow_from_anyhow() {
+ let error = anyhow!("oh no!").context("context");
+ let error = anyhow!(error);
+ assert_eq!("oh no!", error.source().unwrap().to_string());
+}
diff --git a/third_party/rust/anyhow/tests/ui/no-impl.rs b/third_party/rust/anyhow/tests/ui/no-impl.rs
new file mode 100644
index 0000000000..d2e89afc1b
--- /dev/null
+++ b/third_party/rust/anyhow/tests/ui/no-impl.rs
@@ -0,0 +1,8 @@
+use anyhow::anyhow;
+
+#[derive(Debug)]
+struct Error;
+
+fn main() {
+ let _ = anyhow!(Error);
+}
diff --git a/third_party/rust/anyhow/tests/ui/no-impl.stderr b/third_party/rust/anyhow/tests/ui/no-impl.stderr
new file mode 100644
index 0000000000..be957370d3
--- /dev/null
+++ b/third_party/rust/anyhow/tests/ui/no-impl.stderr
@@ -0,0 +1,21 @@
+error[E0599]: no method named `anyhow_kind` found for reference `&Error` in the current scope
+ --> $DIR/no-impl.rs:7:13
+ |
+4 | struct Error;
+ | -------------
+ | |
+ | doesn't satisfy `Error: anyhow::kind::TraitKind`
+ | doesn't satisfy `Error: std::convert::Into<anyhow::Error>`
+ | doesn't satisfy `Error: std::fmt::Display`
+...
+7 | let _ = anyhow!(Error);
+ | ^^^^^^^^^^^^^^ method not found in `&Error`
+ |
+ = note: the method `anyhow_kind` exists but the following trait bounds were not satisfied:
+ `Error: std::convert::Into<anyhow::Error>`
+ which is required by `Error: anyhow::kind::TraitKind`
+ `Error: std::fmt::Display`
+ which is required by `&Error: anyhow::kind::AdhocKind`
+ `&Error: std::convert::Into<anyhow::Error>`
+ which is required by `&Error: anyhow::kind::TraitKind`
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)