vfs/test_utils/
assertions.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Assertion helpers common to both file and directory tests.
6
7#[doc(hidden)]
8pub mod reexport {
9    pub use crate::directory::test_utils::DirentsSameInodeBuilder;
10    pub use fidl_fuchsia_io as fio;
11    pub use futures::stream::StreamExt;
12    pub use zx_status::Status;
13
14    #[cfg(not(target_os = "fuchsia"))]
15    pub use fuchsia_async::emulated_handle::MessageBuf;
16    #[cfg(target_os = "fuchsia")]
17    pub use zx::MessageBuf;
18}
19
20// All of the macros in this file should be async functions.  There are two reasons they are not:
21//   1. It is shorter to write (`assert_read!(...)` instead of `assert_read(...).await`).
22//   2. Until we get proper backtraces we only see the line number of the line with the assertion.
23//      So macros produce better error messages.
24//
25// As soon as the second item is fixed, we should start migrating to functions.  We may consider
26// still using "thin" macro wrappers to remove the repetition of `await`. Also, https://fxbug.dev/42109299 is tracking
27// compile time degradation due to repetition macros are introducing.
28
29// See comment at the top of the file for why this is a macro.
30#[macro_export]
31macro_rules! assert_read {
32    ($proxy:expr, $expected:expr) => {{
33        use $crate::test_utils::assertions::reexport::Status;
34
35        let content = $proxy
36            .read($expected.len() as u64)
37            .await
38            .expect("read failed")
39            .map_err(Status::from_raw)
40            .expect("read error");
41
42        assert_eq!(content.as_slice(), $expected.as_bytes());
43    }};
44}
45
46// See comment at the top of the file for why this is a macro.
47#[macro_export]
48macro_rules! assert_read_err {
49    ($proxy:expr, $expected_status:expr) => {{
50        use $crate::test_utils::assertions::reexport::Status;
51
52        let result = $proxy.read(100).await.expect("read failed").map_err(Status::from_raw);
53
54        assert_eq!(result, Err($expected_status));
55    }};
56}
57
58// See comment at the top of the file for why this is a macro.
59#[macro_export]
60macro_rules! assert_read_fidl_err_closed {
61    ($proxy:expr) => {{
62        match $proxy.read(100).await {
63            Err(error) if error.is_closed() => (),
64            Err(error) => panic!("read() returned unexpected error: {:?}", error),
65            Ok(result) => {
66                panic!("Read succeeded: {:?}", result)
67            }
68        }
69    }};
70}
71
72// See comment at the top of the file for why this is a macro.
73#[macro_export]
74macro_rules! assert_read_at {
75    ($proxy:expr, $offset:expr, $expected:expr) => {{
76        use $crate::test_utils::assertions::reexport::Status;
77
78        let content = $proxy
79            .read_at($expected.len() as u64, $offset)
80            .await
81            .expect("read failed")
82            .map_err(Status::from_raw)
83            .expect("read error");
84
85        assert_eq!(content.as_slice(), $expected.as_bytes());
86    }};
87}
88
89// See comment at the top of the file for why this is a macro.
90#[macro_export]
91macro_rules! assert_read_at_err {
92    ($proxy:expr, $offset:expr, $expected_status:expr) => {{
93        use $crate::test_utils::assertions::reexport::Status;
94
95        let result =
96            $proxy.read_at(100, $offset).await.expect("read failed").map_err(Status::from_raw);
97
98        assert_eq!(result, Err($expected_status));
99    }};
100}
101
102// See comment at the top of the file for why this is a macro.
103#[macro_export]
104macro_rules! assert_write {
105    ($proxy:expr, $content:expr) => {{
106        use $crate::test_utils::assertions::reexport::Status;
107
108        let len_written = $proxy
109            .write($content.as_bytes())
110            .await
111            .expect("write failed")
112            .map_err(Status::from_raw)
113            .expect("write error");
114
115        assert_eq!(len_written, $content.len() as u64);
116    }};
117}
118
119// See comment at the top of the file for why this is a macro.
120#[macro_export]
121macro_rules! assert_write_err {
122    ($proxy:expr, $content:expr, $expected_status:expr) => {{
123        use $crate::test_utils::assertions::reexport::Status;
124
125        let result = $proxy
126            .write($content.as_bytes())
127            .await
128            .expect("write failed")
129            .map_err(Status::from_raw);
130
131        assert_eq!(result, Err($expected_status));
132    }};
133}
134
135// See comment at the top of the file for why this is a macro.
136#[macro_export]
137macro_rules! assert_write_fidl_err_closed {
138    ($proxy:expr, $content:expr) => {
139        match $proxy.write($content.as_bytes()).await {
140            Err(error) if error.is_closed() => (),
141            Err(error) => panic!("write() returned unexpected error: {:?}", error),
142            Ok(result) => {
143                panic!("Write succeeded: {:?}", result)
144            }
145        }
146    };
147}
148
149// See comment at the top of the file for why this is a macro.
150#[macro_export]
151macro_rules! assert_write_at {
152    ($proxy:expr, $offset:expr, $content:expr) => {{
153        use $crate::test_utils::assertions::reexport::Status;
154
155        let len_written = $proxy
156            .write_at($content.as_bytes(), $offset)
157            .await
158            .expect("write failed")
159            .map_err(Status::from_raw)
160            .expect("write error");
161
162        assert_eq!(len_written, $content.len() as u64);
163    }};
164}
165
166// See comment at the top of the file for why this is a macro.
167#[macro_export]
168macro_rules! assert_write_at_err {
169    ($proxy:expr, $offset:expr, $content:expr, $expected_status:expr) => {{
170        use $crate::test_utils::assertions::reexport::Status;
171
172        let result = $proxy
173            .write_at($content.as_bytes(), $offset)
174            .await
175            .expect("write failed")
176            .map_err(Status::from_raw);
177
178        assert_eq!(result, Err($expected_status));
179    }};
180}
181
182// See comment at the top of the file for why this is a macro.
183#[macro_export]
184macro_rules! assert_seek {
185    ($proxy:expr, $pos:expr, $start:ident, $expected:expr) => {{
186        use $crate::test_utils::assertions::reexport::{fio, Status};
187
188        let actual = $proxy
189            .seek(fio::SeekOrigin::$start, $pos)
190            .await
191            .expect("seek failed")
192            .map_err(Status::from_raw);
193
194        assert_eq!(actual, $expected);
195    }};
196    ($proxy:expr, $pos:expr, Start) => {
197        assert_seek!($proxy, $pos, Start, Ok($pos as u64))
198    };
199}
200
201// See comment at the top of the file for why this is a macro.
202#[macro_export]
203macro_rules! assert_truncate {
204    ($proxy:expr, $length:expr) => {{
205        use $crate::test_utils::assertions::reexport::Status;
206
207        let () = $proxy
208            .resize($length)
209            .await
210            .expect("resize failed")
211            .map_err(Status::from_raw)
212            .expect("resize error");
213    }};
214}
215
216// See comment at the top of the file for why this is a macro.
217#[macro_export]
218macro_rules! assert_truncate_err {
219    ($proxy:expr, $length:expr, $expected_status:expr) => {{
220        use $crate::test_utils::assertions::reexport::Status;
221
222        let result = $proxy.resize($length).await.expect("resize failed").map_err(Status::from_raw);
223
224        assert_eq!(result, Err($expected_status));
225    }};
226}
227
228// See comment at the top of the file for why this is a macro.
229#[macro_export]
230macro_rules! assert_get_attr {
231    ($proxy:expr, $expected:expr) => {{
232        use $crate::test_utils::assertions::reexport::Status;
233
234        let (status, attrs) = $proxy.get_attr().await.expect("get_attr failed");
235
236        assert_eq!(Status::from_raw(status), Status::OK);
237        assert_eq!(attrs, $expected);
238    }};
239}
240
241// See comment at the top of the file for why this is a macro.
242#[macro_export]
243macro_rules! assert_query {
244    ($proxy:expr, $expected:expr) => {
245        let protocol = $proxy.query().await.expect("describe failed");
246        assert_eq!(protocol, $expected.as_bytes());
247    };
248}
249
250// See comment at the top of the file for why this is a macro.
251#[macro_export]
252macro_rules! assert_close {
253    ($proxy:expr) => {{
254        use $crate::test_utils::assertions::reexport::Status;
255
256        let () = $proxy
257            .close()
258            .await
259            .expect("close failed")
260            .map_err(Status::from_raw)
261            .expect("close error");
262    }};
263}
264
265// PartialEq is not defined for FileEvent for the moment.
266// Because of that I can not write a macro that would just accept a FileEvent instance to
267// compare against:
268//
269//     assert_event!(proxy, FileEvent::OnOpen_ {
270//         s: Status::SHOULD_WAIT.into_raw(),
271//         info: Some(Box::new(NodeInfoDeprecated::{File,Directory} { ... })),
272//     });
273//
274// Instead, I need to split the assertion into a pattern and then additional assertions on what
275// the pattern have matched.
276#[macro_export]
277macro_rules! assert_event {
278    ($proxy:expr, $expected_pattern:pat, $expected_assertion:block) => {{
279        use $crate::test_utils::assertions::reexport::StreamExt;
280
281        let event_stream = $proxy.take_event_stream();
282        match event_stream.into_future().await {
283            (Some(Ok($expected_pattern)), _) => $expected_assertion,
284            (unexpected, _) => {
285                panic!("Unexpected event: {:?}", unexpected);
286            }
287        }
288    }};
289}
290
291// See comment at the top of the file for why this is a macro.
292#[macro_export]
293macro_rules! open_get_proxy_assert {
294    ($proxy:expr, $flags:expr, $path:expr, $new_proxy_type:ty, $expected_pattern:pat,
295     $expected_assertion:block) => {{
296        use $crate::test_utils::node::open_get_proxy;
297        let new_proxy = open_get_proxy::<$new_proxy_type>($proxy, $flags, $path);
298        assert_event!(new_proxy, $expected_pattern, $expected_assertion);
299        new_proxy
300    }};
301}
302
303// See comment at the top of the file for why this is a macro.
304#[macro_export]
305macro_rules! open_get_vmo_file_proxy_assert_ok {
306    ($proxy:expr, $flags:expr, $path:expr) => {{
307        use $crate::test_utils::assertions::reexport::{fio, Status};
308
309        open_get_proxy_assert!(
310            $proxy,
311            $flags,
312            $path,
313            fio::FileMarker,
314            fio::FileEvent::OnOpen_ { s, info },
315            {
316                assert_eq!(Status::from_raw(s), Status::OK);
317                let info = *info.expect("Empty fio::NodeInfoDeprecated");
318                assert!(
319                    matches!(info, fio::NodeInfoDeprecated::File(fio::FileObject { .. })),
320                    "Expected fio::File but got {:?}",
321                    info
322                );
323            }
324        )
325    }};
326}
327
328// See comment at the top of the file for why this is a macro.
329#[macro_export]
330macro_rules! open_as_file_assert_err {
331    ($proxy:expr, $flags:expr, $path:expr, $expected_status:expr) => {{
332        use $crate::test_utils::assertions::reexport::{fio, Status};
333
334        open_get_proxy_assert!(
335            $proxy,
336            $flags,
337            $path,
338            fio::FileMarker,
339            fio::FileEvent::OnOpen_ { s, info },
340            {
341                assert_eq!(Status::from_raw(s), $expected_status);
342                assert_eq!(info, None);
343            }
344        );
345    }};
346}
347
348// See comment at the top of the file for why this is a macro.
349#[macro_export]
350macro_rules! open_get_directory_proxy_assert_ok {
351    ($proxy:expr, $flags:expr, $path:expr) => {{
352        use $crate::test_utils::assertions::reexport::{fio, Status};
353
354        open_get_proxy_assert!(
355            $proxy,
356            $flags,
357            $path,
358            fio::DirectoryMarker,
359            fio::DirectoryEvent::OnOpen_ { s, info },
360            {
361                assert_eq!(Status::from_raw(s), Status::OK);
362                assert_eq!(
363                    info,
364                    Some(Box::new(fio::NodeInfoDeprecated::Directory(fio::DirectoryObject))),
365                );
366            }
367        )
368    }};
369}
370
371// See comment at the top of the file for why this is a macro.
372#[macro_export]
373macro_rules! open_as_directory_assert_err {
374    ($proxy:expr, $flags:expr, $path:expr, $expected_status:expr) => {{
375        use $crate::test_utils::assertions::reexport::{fio, Status};
376
377        open_get_proxy_assert!(
378            $proxy,
379            $flags,
380            $path,
381            fio::DirectoryMarker,
382            fio::DirectoryEvent::OnOpen_ { s, info },
383            {
384                assert_eq!(Status::from_raw(s), $expected_status);
385                assert_eq!(info, None);
386            }
387        );
388    }};
389}
390
391#[macro_export]
392macro_rules! clone_get_proxy_assert {
393    ($proxy:expr, $flags:expr, $new_proxy_type:ty, $expected_pattern:pat,
394     $expected_assertion:block) => {{
395        use $crate::test_utils::node::clone_get_proxy;
396        let new_proxy = clone_get_proxy::<$new_proxy_type, _>($proxy, $flags);
397        assert_event!(new_proxy, $expected_pattern, $expected_assertion);
398        new_proxy
399    }};
400}
401
402// See comment at the top of the file for why this is a macro.
403#[macro_export]
404macro_rules! clone_get_vmo_file_proxy_assert_ok {
405    ($proxy:expr, $flags:expr) => {{
406        use $crate::test_utils::assertions::reexport::{fio, Status};
407
408        clone_get_proxy_assert!(
409            $proxy,
410            $flags,
411            fio::FileMarker,
412            fio::FileEvent::OnOpen_ { s, info },
413            {
414                assert_eq!(Status::from_raw(s), Status::OK);
415                let info = *info.expect("Empty fio::NodeInfoDeprecated");
416                assert!(
417                    matches!(info, fio::NodeInfoDeprecated::File(fio::FileObject { .. }),),
418                    "Expected fio::File but got {:?}",
419                    info
420                );
421            }
422        )
423    }};
424}
425
426// See comment at the top of the file for why this is a macro.
427#[macro_export]
428macro_rules! clone_get_vmo_file_proxy_assert_err {
429    ($proxy:expr, $flags:expr) => {{
430        use $crate::test_utils::assertions::reexport::{fio, Status};
431
432        clone_get_proxy_assert!(
433            $proxy,
434            $flags,
435            fio::FileMarker,
436            fio::FileEvent::OnOpen_ { s, info },
437            {
438                assert_eq!(Status::from_raw(s), Status::OK);
439                let info = *info.expect("Empty fio::NodeInfoDeprecated");
440                assert!(
441                    matches!(info, fio::NodeInfoDeprecated::Service(fio::Service)),
442                    "Expected fio::Service but got {:?}",
443                    info
444                );
445            }
446        )
447    }};
448}
449
450// See comment at the top of the file for why this is a macro.
451#[macro_export]
452macro_rules! clone_as_file_assert_err {
453    ($proxy:expr, $flags:expr, $expected_status:expr) => {{
454        use $crate::test_utils::assertions::reexport::{fio, Status};
455
456        clone_get_proxy_assert!(
457            $proxy,
458            $flags,
459            fio::FileMarker,
460            fio::FileEvent::OnOpen_ { s, info },
461            {
462                assert_eq!(Status::from_raw(s), $expected_status);
463                assert_eq!(info, None);
464            }
465        )
466    }};
467}
468
469// See comment at the top of the file for why this is a macro.
470#[macro_export]
471macro_rules! clone_get_service_proxy_assert_ok {
472    ($proxy:expr, $flags:expr) => {{
473        use $crate::test_utils::assertions::reexport::{fio, Status};
474
475        clone_get_proxy_assert!(
476            $proxy,
477            $flags,
478            fio::NodeMarker,
479            fio::NodeEvent::OnOpen_ { s, info },
480            {
481                assert_eq!(Status::from_raw(s), Status::OK);
482                assert_eq!(info, Some(Box::new(fio::NodeInfoDeprecated::Service(fio::Service))),);
483            }
484        )
485    }};
486}
487
488// See comment at the top of the file for why this is a macro.
489#[macro_export]
490macro_rules! clone_get_directory_proxy_assert_ok {
491    ($proxy:expr, $flags:expr) => {{
492        use $crate::test_utils::assertions::reexport::{fio, Status};
493
494        clone_get_proxy_assert!(
495            $proxy,
496            $flags,
497            fio::DirectoryMarker,
498            fio::DirectoryEvent::OnOpen_ { s, info },
499            {
500                assert_eq!(Status::from_raw(s), Status::OK);
501                assert_eq!(
502                    info,
503                    Some(Box::new(fio::NodeInfoDeprecated::Directory(fio::DirectoryObject))),
504                );
505            }
506        )
507    }};
508}
509
510// See comment at the top of the file for why this is a macro.
511#[macro_export]
512macro_rules! clone_as_directory_assert_err {
513    ($proxy:expr, $flags:expr, $expected_status:expr) => {{
514        use $crate::test_utils::assertions::reexport::{fio, Status};
515
516        clone_get_proxy_assert!(
517            $proxy,
518            $flags,
519            fio::DirectoryMarker,
520            fio::DirectoryEvent::OnOpen_ { s, info },
521            {
522                assert_eq!(Status::from_raw(s), $expected_status);
523                assert_eq!(info, None);
524            }
525        )
526    }};
527}
528
529// See comment at the top of the file for why this is a macro.
530#[macro_export]
531macro_rules! assert_read_dirents {
532    ($proxy:expr, $max_bytes:expr, $expected:expr) => {{
533        use $crate::test_utils::assertions::reexport::Status;
534
535        let expected = $expected as Vec<u8>;
536
537        let (status, entries) = $proxy.read_dirents($max_bytes).await.expect("read_dirents failed");
538
539        assert_eq!(Status::from_raw(status), Status::OK);
540        assert!(
541            entries == expected,
542            "Read entries do not match the expectation.\n\
543             Expected entries: {:?}\n\
544             Actual entries:   {:?}\n\
545             Expected as UTF-8 lossy: {:?}\n\
546             Received as UTF-8 lossy: {:?}",
547            expected,
548            entries,
549            String::from_utf8_lossy(&expected),
550            String::from_utf8_lossy(&entries),
551        );
552    }};
553}
554
555#[macro_export]
556macro_rules! assert_read_dirents_one_listing {
557    ($proxy:expr, $max_bytes:expr, $( { $type:tt, $name:expr $(,)* } ),* $(,)*) => {{
558        use $crate::test_utils::assertions::reexport::{DirentsSameInodeBuilder, fio};
559
560        let mut expected = DirentsSameInodeBuilder::new(fio::INO_UNKNOWN);
561        expected
562            $(.add(assert_read_dirents_one_listing!(@expand_dirent_type $type), $name))*
563            ;
564
565        assert_read_dirents!($proxy, $max_bytes, expected.into_vec());
566    }};
567
568    (@expand_dirent_type UNKNOWN) => { fio::DirentType::Unknown };
569    (@expand_dirent_type DIRECTORY) => { fio::DirentType::Directory };
570    (@expand_dirent_type BLOCK_DEVICE) => { fio::DirentType::BlockDevice };
571    (@expand_dirent_type FILE) => { fio::DirentType::File };
572    (@expand_dirent_type SERVICE) => { fio::DirentType::Service };
573}
574
575#[macro_export]
576macro_rules! assert_read_dirents_path_one_listing {
577    ($proxy:expr, $path:expr, $max_bytes:expr, $( { $type:tt, $name:expr $(,)* } ),* $(,)*) => {{
578        use $crate::test_utils::assertions::reexport::fio;
579
580        let flags = fio::OpenFlags::DESCRIBE;
581        let path = open_get_directory_proxy_assert_ok!($proxy, flags, $path);
582
583        assert_read_dirents_one_listing!(path, $max_bytes, $( { $type, $name }, )*);
584        assert_close!(path);
585    }};
586}
587
588// See comment at the top of the file for why this is a macro.
589#[macro_export]
590macro_rules! assert_read_dirents_err {
591    ($proxy:expr, $max_bytes:expr, $expected_status:expr) => {{
592        use $crate::test_utils::assertions::reexport::Status;
593
594        let (status, entries) = $proxy.read_dirents($max_bytes).await.expect("read_dirents failed");
595
596        assert_eq!(Status::from_raw(status), $expected_status);
597        assert!(
598            entries.len() == 0,
599            "`read_dirents` returned non-empty list of entries along with an error.\n\
600             Got {} entries.\n\
601             Content: {:?}\n\
602             Content as UTF-8 lossy: {:?}",
603            entries.len(),
604            entries,
605            String::from_utf8_lossy(&entries),
606        );
607    }};
608}
609
610#[macro_export]
611macro_rules! assert_channel_closed {
612    ($channel:expr) => {{
613        use $crate::test_utils::assertions::reexport::{MessageBuf, Status};
614
615        // Allows $channel to be a temporary.
616        let channel = &$channel;
617
618        let mut msg = MessageBuf::new();
619        match channel.recv_msg(&mut msg).await {
620            Ok(()) => panic!(
621                "'{}' received a message, instead of been closed: {:?}",
622                stringify!($channel),
623                msg.bytes(),
624            ),
625            Err(Status::PEER_CLOSED) => (),
626            Err(status) => panic!("'{}' closed with status: {}", stringify!($channel), status),
627        }
628    }};
629}
630
631#[macro_export]
632macro_rules! assert_get_vmo {
633    ($proxy:expr, $flags:expr) => {{
634        use $crate::test_utils::assertions::reexport::Status;
635        $proxy
636            .get_backing_memory($flags)
637            .await
638            .expect("`get_backing_memory()` failed")
639            .map_err(Status::from_raw)
640            .expect("`get_backing_memory` error")
641    }};
642}
643
644#[macro_export]
645macro_rules! assert_get_vmo_err {
646    ($proxy:expr, $flags:expr, $expected_status:expr) => {{
647        use $crate::test_utils::assertions::reexport::Status;
648
649        let result = $proxy
650            .get_backing_memory($flags)
651            .await
652            .expect("`get_backing_memory()` failed")
653            .map_err(Status::from_raw);
654
655        assert_eq!(result, Err($expected_status));
656    }};
657}
658
659// See comment at the top of the file for why this is a macro.
660#[macro_export]
661macro_rules! assert_unlink {
662    ($proxy:expr, $path:expr) => {{
663        $proxy
664            .unlink($path, &fio::UnlinkOptions::default())
665            .await
666            .expect("fidl failed")
667            .expect("unlink failed");
668    }};
669}
670
671// See comment at the top of the file for why this is a macro.
672#[macro_export]
673macro_rules! assert_unlink_err {
674    ($proxy:expr, $path:expr, $expected_status:expr) => {{
675        use $crate::test_utils::assertions::reexport::{fio, Status};
676
677        assert_eq!(
678            Status::from_raw(
679                $proxy
680                    .unlink($path, &fio::UnlinkOptions::default())
681                    .await
682                    .expect("fidl failed")
683                    .expect_err("unlink succeeded")
684            ),
685            $expected_status
686        );
687    }};
688}
689
690// See comment at the top of the file for why this is a macro.
691#[macro_export]
692macro_rules! assert_get_token {
693    ($proxy:expr) => {{
694        use $crate::test_utils::assertions::reexport::Status;
695
696        let (status, o_token) = $proxy.get_token().await.expect("get_token failed");
697
698        assert_eq!(Status::from_raw(status), Status::OK);
699        match o_token {
700            None => panic!("`get_token` returned Status::OK, but no token"),
701            Some(token) => token,
702        }
703    }};
704}
705
706// See comment at the top of the file for why this is a macro.
707#[macro_export]
708macro_rules! assert_get_token_err {
709    ($proxy:expr, $expected_status:expr) => {{
710        use $crate::test_utils::assertions::reexport::Status;
711
712        let (status, token) = $proxy.get_token().await.expect("get_token failed");
713
714        assert_eq!(Status::from_raw(status), $expected_status);
715        assert!(
716            token.is_none(),
717            "`get_token` returned a token along with an error code.\n\
718             token: {:?}",
719            token
720        );
721    }};
722}
723
724// See comment at the top of the file for why this is a macro.
725#[macro_export]
726macro_rules! assert_rename {
727    ($proxy:expr, $src:expr, $dst_parent_token:expr, $dst:expr) => {{
728        let status = $proxy.rename($src, $dst_parent_token, $dst).await.expect("rename failed");
729
730        assert!(status.is_ok());
731    }};
732}
733
734// See comment at the top of the file for why this is a macro.
735#[macro_export]
736macro_rules! assert_rename_err {
737    ($proxy:expr, $src:expr, $dst_parent_token:expr, $dst:expr, $expected_status:expr) => {{
738        use $crate::test_utils::assertions::reexport::Status;
739
740        let status = $proxy.rename($src, $dst_parent_token, $dst).await.expect("rename failed");
741
742        assert!(status.is_err());
743        assert_eq!(status.err().unwrap(), $expected_status.into_raw());
744    }};
745}
746
747// See comment at the top of the file for why this is a macro.
748#[macro_export]
749macro_rules! assert_link_err {
750    ($proxy:expr, $src:expr, $dst_parent_token:expr, $dst:expr, $expected_status:expr) => {{
751        use $crate::test_utils::assertions::reexport::Status;
752
753        let status = $proxy.link($src, $dst_parent_token, $dst).await.expect("link failed");
754
755        assert_eq!(Status::from_raw(status), $expected_status);
756    }};
757}
758
759// See comment at the top of the file for why this is a macro.
760#[macro_export]
761macro_rules! assert_get_attributes {
762    ($proxy:expr, $requested_attributes:expr, $expected:expr) => {{
763        use $crate::test_utils::assertions::reexport::Status;
764
765        let (mutable_attributes, immutable_attributes) = $proxy
766            .get_attributes($requested_attributes)
767            .await
768            .expect("get_attributes failed")
769            .map_err(Status::from_raw)
770            .expect("get_attributes error");
771
772        assert_eq!(mutable_attributes, $expected.mutable_attributes);
773        assert_eq!(immutable_attributes, $expected.immutable_attributes);
774    }};
775}