Skip to main content

io_conformance_util/
flags.rs

1// Copyright 2021 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
5use fidl_fuchsia_io as fio;
6
7/// Helper struct that encapsulates generation of valid/invalid sets of flags based on
8/// which rights are supported by a particular node type.
9pub struct Rights {
10    rights: fio::Rights,
11}
12
13impl Rights {
14    /// Creates a new Rights struct based on the rights in specified in `fio::Rights`.
15    pub fn new(rights: fio::Rights) -> Rights {
16        Rights { rights }
17    }
18
19    /// Returns all supported rights.
20    pub fn all_rights(&self) -> fio::Rights {
21        self.rights
22    }
23
24    /// Returns all supported rights as `fio::Flags` right flags.
25    pub fn all_flags(&self) -> fio::Flags {
26        // We can do this conversion because Flags has a 1:1 to Rights.
27        fio::Flags::from_bits_truncate(self.rights.bits())
28    }
29
30    /// Returns a vector of all valid rights combinations.
31    pub fn rights_combinations(&self) -> Vec<fio::Rights> {
32        vfs::test_utils::build_flag_combinations(fio::Rights::empty(), self.rights)
33    }
34
35    /// Returns a vector of all valid flag combinations as `fio::Flags` flags.
36    pub fn combinations(&self) -> Vec<fio::Flags> {
37        vfs::test_utils::build_flag_combinations(fio::Flags::empty(), self.all_flags())
38    }
39
40    // Returns all rights combinations that contains all the rights specified in `with_rights`.
41    fn rights_combinations_containing(&self, with_rights: fio::Rights) -> Vec<fio::Rights> {
42        let mut right_combinations = self.rights_combinations();
43        right_combinations.retain(|&flags| flags.contains(with_rights));
44        right_combinations
45    }
46
47    /// Returns all rights combinations that include *all* the specified rights in `with_rights` as
48    /// `fio::Flags` flags. Will be empty if none of the requested rights are supported.
49    pub fn combinations_containing(&self, with_rights: fio::Rights) -> Vec<fio::Flags> {
50        self.rights_combinations_containing(with_rights)
51            .into_iter()
52            .map(|combination| fio::Flags::from_bits_truncate(combination.bits()))
53            .collect()
54    }
55
56    /// Returns all rights combinations without the rights specified in `without_rights`,
57    fn combinations_without_as_rights(&self, without_rights: fio::Rights) -> Vec<fio::Rights> {
58        let mut right_combinations = self.rights_combinations();
59        right_combinations.retain(|&flags| !flags.intersects(without_rights));
60        right_combinations
61    }
62
63    /// Returns all rights combinations that does not include the specified rights in
64    /// `without_rights` as `fio::Flags` flags. Will be empty if none are supported.
65    pub fn combinations_without(&self, without_rights: fio::Rights) -> Vec<fio::Flags> {
66        self.combinations_without_as_rights(without_rights)
67            .into_iter()
68            .map(|combination| fio::Flags::from_bits_truncate(combination.bits()))
69            .collect()
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_rights_combinations_flags() {
79        const TEST_RIGHTS: fio::Rights = fio::Rights::empty()
80            .union(fio::Rights::READ_BYTES)
81            .union(fio::Rights::WRITE_BYTES)
82            .union(fio::Rights::EXECUTE);
83
84        // We should get 0, R, W, X, RW, RX, WX, RWX (8 in total).
85        const EXPECTED_COMBINATIONS: [fio::Flags; 8] = [
86            fio::Flags::empty(),
87            fio::Flags::PERM_READ_BYTES,
88            fio::Flags::PERM_WRITE_BYTES,
89            fio::Flags::PERM_EXECUTE,
90            fio::Flags::empty()
91                .union(fio::Flags::PERM_READ_BYTES)
92                .union(fio::Flags::PERM_WRITE_BYTES),
93            fio::Flags::empty().union(fio::Flags::PERM_READ_BYTES).union(fio::Flags::PERM_EXECUTE),
94            fio::Flags::empty().union(fio::Flags::PERM_WRITE_BYTES).union(fio::Flags::PERM_EXECUTE),
95            fio::Flags::empty()
96                .union(fio::Flags::PERM_READ_BYTES)
97                .union(fio::Flags::PERM_WRITE_BYTES)
98                .union(fio::Flags::PERM_EXECUTE),
99        ];
100
101        // Check that we get the expected Flags.
102        let rights = Rights::new(TEST_RIGHTS);
103        assert_eq!(
104            rights.all_flags(),
105            fio::Flags::PERM_READ_BYTES | fio::Flags::PERM_WRITE_BYTES | fio::Flags::PERM_EXECUTE
106        );
107
108        // Test that all possible combinations are generated correctly.
109        let all_combinations = rights.combinations();
110        assert_eq!(all_combinations.len(), EXPECTED_COMBINATIONS.len());
111        for expected_rights in EXPECTED_COMBINATIONS {
112            assert!(all_combinations.contains(&expected_rights));
113        }
114
115        // Test that combinations including READABLE are generated correctly.
116        // We should get R, RW, RX, and RWX (4 in total).
117        const EXPECTED_READABLE_COMBOS: [fio::Flags; 4] = [
118            fio::Flags::PERM_READ_BYTES,
119            fio::Flags::empty()
120                .union(fio::Flags::PERM_READ_BYTES)
121                .union(fio::Flags::PERM_WRITE_BYTES),
122            fio::Flags::empty().union(fio::Flags::PERM_READ_BYTES).union(fio::Flags::PERM_EXECUTE),
123            fio::Flags::empty()
124                .union(fio::Flags::PERM_READ_BYTES)
125                .union(fio::Flags::PERM_WRITE_BYTES)
126                .union(fio::Flags::PERM_EXECUTE),
127        ];
128        let readable_combos = rights.combinations_containing(fio::Rights::READ_BYTES);
129        assert_eq!(readable_combos.len(), EXPECTED_READABLE_COMBOS.len());
130        for expected_rights in EXPECTED_READABLE_COMBOS {
131            assert!(readable_combos.contains(&expected_rights));
132        }
133
134        // Test that combinations excluding READABLE are generated correctly.
135        // We should get 0, W, X, and WX (4 in total).
136        const EXPECTED_NONREADABLE_COMBOS: [fio::Flags; 4] = [
137            fio::Flags::empty(),
138            fio::Flags::PERM_WRITE_BYTES,
139            fio::Flags::PERM_EXECUTE,
140            fio::Flags::empty().union(fio::Flags::PERM_WRITE_BYTES).union(fio::Flags::PERM_EXECUTE),
141        ];
142        let nonreadable_combos = rights.combinations_without(fio::Rights::READ_BYTES);
143        assert_eq!(nonreadable_combos.len(), EXPECTED_NONREADABLE_COMBOS.len());
144        for expected_rights in EXPECTED_NONREADABLE_COMBOS {
145            assert!(nonreadable_combos.contains(&expected_rights));
146        }
147    }
148}