creator_simctl/
privacy.rs

1//! Supporting types for the `simctl privacy` subcommand.
2
3use super::{Device, Result, Validate};
4
5/// Refers to a specific service that an app needs to have permission for to
6/// access.
7#[derive(Copy, Clone, Debug, Eq, PartialEq)]
8pub enum PrivacyService {
9    /// Wildcard that includes all services.
10    All,
11
12    /// Grants access to a user's calendar.
13    Calendar,
14
15    /// Grants limited access to a user's contacts.
16    ContactsLimited,
17
18    /// Grants access to a user's contacts.
19    Contacts,
20
21    /// Grants access to a user's location when an app is active.
22    Location,
23
24    /// Grants access to a user's location even if the app is in background.
25    LocationAlways,
26
27    /// Grants access to adding photos to the user's photo library.
28    PhotosAdd,
29
30    /// Grants access to reading photos from the user's photo library.
31    Photos,
32
33    /// Grants access to the user's media library (i.e. music and videos).
34    MediaLibrary,
35
36    /// Grants access to the user's microphone (which will most likely be the
37    /// microphone of the Mac that the simulator runs on).
38    Microphone,
39
40    /// Grants access to the user's motion sensors.
41    Motion,
42
43    /// Grants access to the user's reminders.
44    Reminders,
45
46    /// Grants access to Siri.
47    Siri,
48}
49
50impl ToString for PrivacyService {
51    fn to_string(&self) -> String {
52        match self {
53            PrivacyService::All => "all",
54            PrivacyService::Calendar => "calendar",
55            PrivacyService::ContactsLimited => "contacts-limited",
56            PrivacyService::Contacts => "contacts",
57            PrivacyService::Location => "location",
58            PrivacyService::LocationAlways => "location-always",
59            PrivacyService::PhotosAdd => "photos-add",
60            PrivacyService::Photos => "photos",
61            PrivacyService::MediaLibrary => "media-library",
62            PrivacyService::Microphone => "microphone",
63            PrivacyService::Motion => "motion",
64            PrivacyService::Reminders => "reminders",
65            PrivacyService::Siri => "siri",
66        }
67        .to_owned()
68    }
69}
70
71/// Wrapper around the `simctl privacy` subcommand.
72pub struct Privacy {
73    device: Device,
74}
75
76impl Device {
77    /// Returns a wrapper around the `simctl privacy` subcommand.
78    pub fn privacy(&self) -> Privacy {
79        Privacy {
80            device: self.clone(),
81        }
82    }
83}
84
85impl Privacy {
86    /// Grants access to the given service to an application with the given
87    /// bundle ID.
88    pub fn grant(&self, service: PrivacyService, bundle_id: &str) -> Result<()> {
89        self.device
90            .simctl()
91            .command("privacy")
92            .arg(&self.device.udid)
93            .arg("grant")
94            .arg(service.to_string())
95            .arg(bundle_id)
96            .output()?
97            .validate()
98    }
99
100    /// Revokes access to the given service from an application with the given
101    /// bundle ID.
102    pub fn revoke(&self, service: PrivacyService, bundle_id: &str) -> Result<()> {
103        self.device
104            .simctl()
105            .command("privacy")
106            .arg(&self.device.udid)
107            .arg("revoke")
108            .arg(service.to_string())
109            .arg(bundle_id)
110            .output()?
111            .validate()
112    }
113
114    /// Resets access to the given service from an application with the given
115    /// bundle ID. This will cause the OS to ask again when this app requests
116    /// permission to use the given service.
117    pub fn reset(&self, service: PrivacyService, bundle_id: &str) -> Result<()> {
118        self.device
119            .simctl()
120            .command("privacy")
121            .arg(&self.device.udid)
122            .arg("reset")
123            .arg(service.to_string())
124            .arg(bundle_id)
125            .output()?
126            .validate()
127    }
128
129    /// Resets access to the given service from all applications running on the
130    /// device.
131    pub fn reset_all(&self, service: PrivacyService) -> Result<()> {
132        self.device
133            .simctl()
134            .command("privacy")
135            .arg(&self.device.udid)
136            .arg("reset")
137            .arg(service.to_string())
138            .output()?
139            .validate()
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use serial_test::serial;
146
147    use super::*;
148    use crate::mock;
149
150    #[test]
151    #[serial]
152    fn test_privacy_grant() -> Result<()> {
153        mock::device()?.boot()?;
154        mock::device()?
155            .privacy()
156            .grant(PrivacyService::Location, "com.apple.Maps")?;
157        mock::device()?.shutdown()?;
158
159        Ok(())
160    }
161
162    #[test]
163    #[serial]
164    fn test_privacy_revoke() -> Result<()> {
165        mock::device()?.boot()?;
166        mock::device()?
167            .privacy()
168            .revoke(PrivacyService::Location, "com.apple.Maps")?;
169        mock::device()?.shutdown()?;
170
171        Ok(())
172    }
173
174    #[test]
175    #[serial]
176    fn test_privacy_reset() -> Result<()> {
177        mock::device()?.boot()?;
178        mock::device()?
179            .privacy()
180            .grant(PrivacyService::Location, "com.apple.Maps")?;
181        mock::device()?
182            .privacy()
183            .reset(PrivacyService::Location, "com.apple.Maps")?;
184        mock::device()?.shutdown()?;
185
186        Ok(())
187    }
188
189    #[test]
190    #[serial]
191    fn test_privacy_reset_all() -> Result<()> {
192        mock::device()?.boot()?;
193        mock::device()?
194            .privacy()
195            .grant(PrivacyService::Location, "com.apple.Maps")?;
196        mock::device()?
197            .privacy()
198            .reset_all(PrivacyService::Location)?;
199        mock::device()?.shutdown()?;
200
201        Ok(())
202    }
203}