]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | // Copyright 2017 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | // This is a script to deploy and execute a binary on an iOS simulator. | |
12 | // The primary use of this is to be able to run unit tests on the simulator and | |
13 | // retrieve the results. | |
14 | // | |
15 | // To do this through Cargo instead, use Dinghy | |
16 | // (https://github.com/snipsco/dinghy): cargo dinghy install, then cargo dinghy | |
17 | // test. | |
18 | ||
19 | use std::env; | |
20 | use std::fs::{self, File}; | |
21 | use std::io::Write; | |
22 | use std::path::Path; | |
23 | use std::process; | |
24 | use std::process::Command; | |
25 | ||
26 | macro_rules! t { | |
27 | ($e:expr) => (match $e { | |
28 | Ok(e) => e, | |
29 | Err(e) => panic!("{} failed with: {}", stringify!($e), e), | |
30 | }) | |
31 | } | |
32 | ||
33 | // Step one: Wrap as an app | |
34 | fn package_as_simulator_app(crate_name: &str, test_binary_path: &Path) { | |
35 | println!("Packaging simulator app"); | |
36 | drop(fs::remove_dir_all("ios_simulator_app")); | |
37 | t!(fs::create_dir("ios_simulator_app")); | |
38 | t!(fs::copy(test_binary_path, | |
39 | Path::new("ios_simulator_app").join(crate_name))); | |
40 | ||
41 | let mut f = t!(File::create("ios_simulator_app/Info.plist")); | |
42 | t!(f.write_all(format!(r#" | |
43 | <?xml version="1.0" encoding="UTF-8"?> | |
44 | <!DOCTYPE plist PUBLIC | |
45 | "-//Apple//DTD PLIST 1.0//EN" | |
46 | "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
47 | <plist version="1.0"> | |
48 | <dict> | |
49 | <key>CFBundleExecutable</key> | |
50 | <string>{}</string> | |
51 | <key>CFBundleIdentifier</key> | |
52 | <string>com.rust.unittests</string> | |
53 | </dict> | |
54 | </plist> | |
55 | "#, crate_name).as_bytes())); | |
56 | } | |
57 | ||
58 | // Step two: Start the iOS simulator | |
59 | fn start_simulator() { | |
60 | println!("Looking for iOS simulator"); | |
61 | let output = t!(Command::new("xcrun").arg("simctl").arg("list").output()); | |
62 | assert!(output.status.success()); | |
63 | let mut simulator_exists = false; | |
64 | let mut simulator_booted = false; | |
65 | let mut found_rust_sim = false; | |
66 | let stdout = t!(String::from_utf8(output.stdout)); | |
67 | for line in stdout.lines() { | |
68 | if line.contains("rust_ios") { | |
69 | if found_rust_sim { | |
70 | panic!("Duplicate rust_ios simulators found. Please \ | |
71 | double-check xcrun simctl list."); | |
72 | } | |
73 | simulator_exists = true; | |
74 | simulator_booted = line.contains("(Booted)"); | |
75 | found_rust_sim = true; | |
76 | } | |
77 | } | |
78 | ||
79 | if simulator_exists == false { | |
80 | println!("Creating iOS simulator"); | |
81 | Command::new("xcrun") | |
82 | .arg("simctl") | |
83 | .arg("create") | |
84 | .arg("rust_ios") | |
85 | .arg("com.apple.CoreSimulator.SimDeviceType.iPhone-SE") | |
86 | .arg("com.apple.CoreSimulator.SimRuntime.iOS-10-2") | |
87 | .check_status(); | |
88 | } else if simulator_booted == true { | |
89 | println!("Shutting down already-booted simulator"); | |
90 | Command::new("xcrun") | |
91 | .arg("simctl") | |
92 | .arg("shutdown") | |
93 | .arg("rust_ios") | |
94 | .check_status(); | |
95 | } | |
96 | ||
97 | println!("Starting iOS simulator"); | |
98 | // We can't uninstall the app (if present) as that will hang if the | |
99 | // simulator isn't completely booted; just erase the simulator instead. | |
100 | Command::new("xcrun").arg("simctl").arg("erase").arg("rust_ios").check_status(); | |
101 | Command::new("xcrun").arg("simctl").arg("boot").arg("rust_ios").check_status(); | |
102 | } | |
103 | ||
104 | // Step three: Install the app | |
105 | fn install_app_to_simulator() { | |
106 | println!("Installing app to simulator"); | |
107 | Command::new("xcrun") | |
108 | .arg("simctl") | |
109 | .arg("install") | |
110 | .arg("booted") | |
111 | .arg("ios_simulator_app/") | |
112 | .check_status(); | |
113 | } | |
114 | ||
115 | // Step four: Run the app | |
116 | fn run_app_on_simulator() { | |
117 | println!("Running app"); | |
118 | let output = t!(Command::new("xcrun") | |
119 | .arg("simctl") | |
120 | .arg("launch") | |
121 | .arg("--console") | |
122 | .arg("booted") | |
123 | .arg("com.rust.unittests") | |
124 | .output()); | |
125 | ||
126 | println!("stdout --\n{}\n", String::from_utf8_lossy(&output.stdout)); | |
127 | println!("stderr --\n{}\n", String::from_utf8_lossy(&output.stderr)); | |
128 | ||
129 | let stdout = String::from_utf8_lossy(&output.stdout); | |
130 | let failed = stdout.lines() | |
131 | .find(|l| l.contains("FAILED")) | |
132 | .map(|l| l.contains("FAILED")) | |
133 | .unwrap_or(false); | |
134 | ||
135 | let passed = stdout.lines() | |
136 | .find(|l| l.contains("test result: ok")) | |
137 | .map(|l| l.contains("test result: ok")) | |
138 | .unwrap_or(false); | |
139 | ||
140 | println!("Shutting down simulator"); | |
141 | Command::new("xcrun") | |
142 | .arg("simctl") | |
143 | .arg("shutdown") | |
144 | .arg("rust_ios") | |
145 | .check_status(); | |
146 | if !(passed && !failed) { | |
147 | panic!("tests didn't pass"); | |
148 | } | |
149 | } | |
150 | ||
151 | trait CheckStatus { | |
152 | fn check_status(&mut self); | |
153 | } | |
154 | ||
155 | impl CheckStatus for Command { | |
156 | fn check_status(&mut self) { | |
157 | println!("\trunning: {:?}", self); | |
158 | assert!(t!(self.status()).success()); | |
159 | } | |
160 | } | |
161 | ||
162 | fn main() { | |
163 | let args: Vec<String> = env::args().collect(); | |
164 | if args.len() != 2 { | |
165 | println!("Usage: {} <executable>", args[0]); | |
166 | process::exit(-1); | |
167 | } | |
168 | ||
169 | let test_binary_path = Path::new(&args[1]); | |
170 | let crate_name = test_binary_path.file_name().unwrap(); | |
171 | ||
172 | package_as_simulator_app(crate_name.to_str().unwrap(), test_binary_path); | |
173 | start_simulator(); | |
174 | install_app_to_simulator(); | |
175 | run_app_on_simulator(); | |
176 | } |