@@ -12,16 +12,74 @@ cd tests/unittests
1212xcrun simctl list devices available
1313echo ' End of xcrun simctl list devices available'
1414
15- # Resolve simulator UUID to avoid ambiguous destination matching.
16- # Grab the last (newest OS) available device matching the requested name.
17- SIM_ID=$( xcrun simctl list devices available | grep " $SIMULATOR " | grep -oE ' [A-F0-9-]{36}' | tail -1)
15+ # Resolve simulator UUID from simctl JSON using an exact name match.
16+ # If the same device name exists across multiple iOS runtimes, pick the
17+ # newest runtime and fail if that runtime still contains duplicate matches.
18+ SIM_JSON=$( mktemp)
19+ cleanup_sim_json () {
20+ rm -f " $SIM_JSON "
21+ }
22+ trap cleanup_sim_json EXIT
23+ xcrun simctl list devices available --json > " $SIM_JSON "
24+ SIM_MATCH=$(
25+ python3 - " $SIMULATOR " " $SIM_JSON " << 'PY '
26+ import json
27+ import re
28+ import sys
29+ from pathlib import Path
30+
31+ simulator_name = sys.argv[1]
32+ raw = Path(sys.argv[2]).read_text()
33+ json_start = raw.find('{')
34+ if json_start < 0:
35+ print("ERROR: simctl did not emit JSON", file=sys.stderr)
36+ raise SystemExit(1)
37+
38+ devices_by_runtime = json.loads(raw[json_start:]).get("devices", {})
39+ matches = []
40+ for runtime, devices in devices_by_runtime.items():
41+ if not runtime.startswith("com.apple.CoreSimulator.SimRuntime.iOS-"):
42+ continue
43+
44+ match = re.search(r"iOS-(\d+)(?:-(\d+))?$", runtime)
45+ if match is None:
46+ continue
47+
48+ version = tuple(int(part) for part in match.groups(default="0"))
49+ runtime_label = "iOS " + ".".join(str(part) for part in version)
50+
51+ for device in devices:
52+ if device.get("name") == simulator_name and device.get("isAvailable", True):
53+ matches.append((version, runtime_label, device["udid"]))
54+
55+ if not matches:
56+ print(f"ERROR: No available simulator found for '{simulator_name}'", file=sys.stderr)
57+ raise SystemExit(1)
58+
59+ newest_version = max(version for version, _, _ in matches)
60+ newest_matches = [(runtime_label, udid) for version, runtime_label, udid in matches if version == newest_version]
61+
62+ if len(newest_matches) != 1:
63+ print(f"ERROR: Multiple available simulators found for '{simulator_name}' in newest runtime:", file=sys.stderr)
64+ for runtime_label, udid in newest_matches:
65+ print(f" - {runtime_label}: {udid}", file=sys.stderr)
66+ raise SystemExit(1)
67+
68+ runtime_label, udid = newest_matches[0]
69+ print(f"{udid}|{runtime_label}")
70+ PY
71+ )
72+ cleanup_sim_json
73+ trap - EXIT
74+ SIM_ID=${SIM_MATCH%% |* }
75+ SIM_RUNTIME=${SIM_MATCH#* |}
1876
1977if [ -z " $SIM_ID " ]; then
2078 echo " ERROR: No available simulator found for '$SIMULATOR '"
2179 exit 1
2280fi
2381
24- echo " Using simulator: $SIMULATOR (id=$SIM_ID )"
82+ echo " Using simulator: $SIMULATOR ($SIM_RUNTIME , id=$SIM_ID )"
2583
2684xcodebuild test -scheme iOSUnitTests -destination " id=$SIM_ID "
2785
0 commit comments