creator_simctl/
ui.rs

1//! Supporting types for the `simctl ui` subcommand.
2
3use std::process::Stdio;
4
5use super::{Device, Result, Validate};
6
7/// Determines the appearance mode of the UI.
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub enum Appearance {
10    /// Indicates a light appearance (i.e. the pre-iOS 13.0 default).
11    Light,
12
13    /// Indicates a dark appearance that was introduced in iOS 13.0.
14    Dark,
15
16    /// This is returned when trying to access the appearance of an unsupported
17    /// device (e.g. watchOS or tvOS).
18    Custom(String),
19}
20
21/// Wrapper around the `simctl ui` subcommand.
22#[derive(Clone, Debug)]
23pub struct UI {
24    device: Device,
25}
26
27impl Device {
28    /// Returns a wrapper around the `simctl ui` subcommand.
29    pub fn ui(&self) -> UI {
30        UI {
31            device: self.clone(),
32        }
33    }
34}
35
36impl UI {
37    /// Returns the current appearance of the UI of this device. Returns
38    /// [`Appearance::Custom`] if the device doesn't support
39    /// changing its appearance.
40    pub fn appearance(&self) -> Result<Appearance> {
41        let output = self
42            .device
43            .simctl()
44            .command("ui")
45            .arg(&self.device.udid)
46            .arg("appearance")
47            .stdout(Stdio::piped())
48            .output()?;
49
50        let output = output.validate_with_output()?;
51
52        let appearance = String::from_utf8(output.stdout)?.trim().to_owned();
53        Ok(match appearance.as_str() {
54            "light" => Appearance::Light,
55            "dark" => Appearance::Dark,
56            _ => Appearance::Custom(appearance),
57        })
58    }
59
60    /// Sets the current appearance of the UI of this device.
61    pub fn set_appearance(&self, appearance: Appearance) -> Result<()> {
62        let appearance = match &appearance {
63            Appearance::Light => "light",
64            Appearance::Dark => "dark",
65            Appearance::Custom(appearance) => appearance,
66        };
67
68        self.device
69            .simctl()
70            .command("ui")
71            .arg(&self.device.udid)
72            .arg("appearance")
73            .arg(appearance)
74            .output()?
75            .validate()
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use serial_test::serial;
82
83    use super::*;
84    use crate::mock;
85
86    #[test]
87    #[serial]
88    fn test_appearance() -> Result<()> {
89        mock::device()?.boot()?;
90
91        mock::device()?.ui().set_appearance(Appearance::Dark)?;
92        assert_eq!(mock::device()?.ui().appearance()?, Appearance::Dark);
93
94        mock::device()?.ui().set_appearance(Appearance::Light)?;
95        assert_eq!(mock::device()?.ui().appearance()?, Appearance::Light);
96
97        mock::device()?.shutdown()?;
98
99        Ok(())
100    }
101}