Run the unit tests on the iOS simulator for x86_64-apple-ios
diff --git a/.travis.yml b/.travis.yml
index fa07ffc..13ca73e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -17,7 +17,7 @@
       sh ci/run.sh $TARGET;
     fi
   - rustc ci/style.rs && ./style src
-osx_image: xcode7.3
+osx_image: xcode8.2
 env:
   global:
     secure: "e2/3QjgRN9atOuSHp22TrYG7QVKcYUWY48Hi9b60w+r1+BhPkTseIJLte7WefRhdXtqpjjUJTooKDhnurFOeHaCT+nmBgiv+FPU893sBl4bhesY4m0vgUJVbNZcs6lTImYekWVb+aqjGdgV/XAgCw7c3kPmrZV0MzGDWL64Xaps="
diff --git a/ci/ios/deploy_and_run_x86_64_binary_on_ios_simulator.py b/ci/ios/deploy_and_run_x86_64_binary_on_ios_simulator.py
new file mode 100755
index 0000000..07be5b3
--- /dev/null
+++ b/ci/ios/deploy_and_run_x86_64_binary_on_ios_simulator.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+#
+# This is a script to deploy and execute a binary on an x86-64 iOS simulator.
+# The primary use of this is to be able to run unit tests on the simulator and retrieve the results.
+#
+# To do this through Cargo instead, use Dinghy (https://github.com/snipsco/dinghy): 
+# cargo dinghy install, then cargo dinghy test.
+
+import os.path
+import subprocess
+import sys
+import time
+
+# Step one: Wrap as an app
+def package_as_simulator_app(crate_name, test_binary_path):
+	print 'Packaging simulator app'
+	subprocess.call(['rm', '-rf', 'ios_simulator_app'])
+	subprocess.check_call(['mkdir', 'ios_simulator_app'])
+	subprocess.check_call(['cp', test_binary_path, 'ios_simulator_app/' + crate_name])
+	f = open('ios_simulator_app/Info.plist', 'w')
+	f.write('<?xml version="1.0" encoding="UTF-8"?>\n'
+			'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
+			'<plist version="1.0">\n'
+			'	<dict>\n'
+			'		<key>CFBundleExecutable</key>\n'
+			'		<string>' + crate_name + '</string>\n'
+			'		<key>CFBundleIdentifier</key>\n'
+			'		<string>com.rust.unittests</string>\n'
+			'		<key>UIRequiredDeviceCapabilities</key>\n'
+			'		<array>\n'
+			'			<string>x86_64</string>\n'
+			'		</array>\n'
+			'	</dict>\n'
+			'</plist>\n')
+
+# Step two: Start the iOS simulator
+def start_simulator():
+	print 'Looking for iOS simulator'
+	xcrun_list = subprocess.Popen(['xcrun', 'simctl', 'list'], stdout=subprocess.PIPE, bufsize=1, universal_newlines=True)
+	simulator_exists = False
+	simulator_booted = False
+	found_rust_sim = False
+	for line in xcrun_list.stdout:
+		if "rust_ios" in line:
+			if found_rust_sim == True:
+				raise Exception("Duplicate rust_ios simulators found. Please double-check xcrun simctl list.")
+			simulator_exists = True
+			simulator_booted = "(Booted)" in line
+			found_rust_sim = True
+	
+	if simulator_exists == False:
+		print 'Creating iOS simulator'
+		subprocess.check_output(['xcrun',  'simctl', 'create', 'rust_ios', 'com.apple.CoreSimulator.SimDeviceType.iPhone-SE', 'com.apple.CoreSimulator.SimRuntime.iOS-10-2'])
+	elif simulator_booted == True:
+		print 'Shutting down already-booted simulator'
+		subprocess.call(['xcrun', 'simctl', 'shutdown', 'rust_ios'])
+	
+	print 'Starting iOS simulator'
+	# We can't uninstall the app (if present) as that will hang if the simulator isn't completely booted; just erase the simulator instead.
+	subprocess.check_call(['xcrun', 'simctl', 'erase', 'rust_ios'])
+	subprocess.check_call(['xcrun', 'simctl', 'boot', 'rust_ios'])
+
+# Step three: Install the app
+def install_app_to_simulator():
+	print 'Installing app to simulator'	
+	subprocess.check_call(['xcrun', 'simctl', 'install', 'booted', 'ios_simulator_app/'])
+
+# Step four: Run the app
+def run_app_on_simulator():
+	print 'Running app'
+	try:
+		test_run = subprocess.Popen(['xcrun', 'simctl', 'launch', '--console', 'booted', 'com.rust.unittests'], stdout=subprocess.PIPE, bufsize=1, universal_newlines=True)
+		test_run_failed = False
+		for line in test_run.stdout:
+			sys.stdout.write(line)
+			if test_run_failed == False:
+				test_run_failed = 'test result: FAILED.' in line
+		
+		sys.stdout.flush()
+		if test_run_failed == True:
+			raise Exception('Some tests failed')
+	finally:
+		print 'Shutting down simulator'
+		subprocess.call(['xcrun', 'simctl', 'shutdown', 'rust_ios'])
+
+# Run all steps in sequence
+# TODO 1: Use a /tmp place for the app instead of current dir?
+def main():
+	if len(sys.argv) != 2:
+		print 'usage: ' + os.path.basename(sys.argv[0]) + ' executable'
+		sys.exit(-1)
+	
+	crate_name = os.path.basename(sys.argv[1])
+	test_binary_path = sys.argv[1]
+
+	package_as_simulator_app(crate_name, test_binary_path)
+	start_simulator()
+	install_app_to_simulator()
+	run_app_on_simulator()
+
+# Entry point
+if __name__ == '__main__':
+    main()
\ No newline at end of file
diff --git a/ci/run.sh b/ci/run.sh
index 179fe7a..44432ff 100755
--- a/ci/run.sh
+++ b/ci/run.sh
@@ -113,6 +113,10 @@
     grep "^PASSED .* tests" /tmp/out
     ;;
 
+  x86_64-apple-ios)
+    python ./ci/ios/deploy_and_run_x86_64_binary_on_ios_simulator.py $CARGO_TARGET_DIR/$TARGET/debug/libc-test
+    ;;
+
   arm-unknown-linux-gnueabihf)
     qemu-arm -L /usr/arm-linux-gnueabihf $CARGO_TARGET_DIR/$TARGET/debug/libc-test
     ;;