From 02bbeb8190e8da3358abc7d9444e9532891d6c60 Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 6 Jun 2026 23:45:13 +0530 Subject: [PATCH] feat(doctor): split iOS checks into simulator and physical-device paths --- cmd/sanderling/doctor.go | 29 +++++++++++++++++++++-------- cmd/sanderling/doctor_test.go | 22 +++++++++++++++++++++- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/cmd/sanderling/doctor.go b/cmd/sanderling/doctor.go index dafe612..e5433bf 100644 --- a/cmd/sanderling/doctor.go +++ b/cmd/sanderling/doctor.go @@ -33,6 +33,8 @@ func doctorChecksFor(platform string) []doctorCheck { return androidChecks() case "ios": return iosChecks() + case "ios-device": + return append(iosChecks(), iosDeviceChecks()...) case "all": return allChecks() default: @@ -55,19 +57,30 @@ func androidChecks() []doctorCheck { } } +// iosChecks covers the simulator path, which the native companion drives with +// no JVM. A simulator host with no Java still passes. Physical-device runs +// additionally need java and the sidecar JAR, covered by iosDeviceChecks and +// surfaced through the "all" union. func iosChecks() []doctorCheck { return []doctorCheck{ - {Name: "xcrun on PATH", Run: checkExecutableOnPath("xcrun")}, - {Name: "simctl on PATH", Run: checkExecutableOnPath("simctl")}, - {Name: "java 17+ on PATH", Run: checkJavaVersion}, - {Name: "sidecar JAR is real (not placeholder)", Run: checkSidecarJAR}, + {Name: "xcrun on PATH (ios simulator)", Run: checkExecutableOnPath("xcrun")}, + {Name: "simctl on PATH (ios simulator)", Run: checkExecutableOnPath("simctl")}, + } +} + +// iosDeviceChecks covers the extra prerequisites a physical iOS device needs: +// the JVM and a real sidecar JAR for the sidecar driver path. +func iosDeviceChecks() []doctorCheck { + return []doctorCheck{ + {Name: "java 17+ on PATH (ios physical device)", Run: checkJavaVersion}, + {Name: "sidecar JAR is real (ios physical device)", Run: checkSidecarJAR}, } } func allChecks() []doctorCheck { seen := map[string]bool{} var combined []doctorCheck - for _, group := range [][]doctorCheck{webChecks(), androidChecks(), iosChecks()} { + for _, group := range [][]doctorCheck{webChecks(), androidChecks(), iosChecks(), iosDeviceChecks()} { for _, c := range group { if seen[c.Name] { continue @@ -116,15 +129,15 @@ func parseDoctorArgs(args []string, stderr io.Writer) (doctorOptions, error) { flagSet := flag.NewFlagSet("doctor", flag.ContinueOnError) flagSet.SetOutput(stderr) var options doctorOptions - flagSet.StringVar(&options.platform, "platform", "all", "target platform: web, android, ios, all") + flagSet.StringVar(&options.platform, "platform", "all", "target platform: web, android, ios, ios-device, all") if err := flagSet.Parse(args); err != nil { return doctorOptions{}, err } switch options.platform { - case "web", "android", "ios", "all": + case "web", "android", "ios", "ios-device", "all": return options, nil default: - return doctorOptions{}, fmt.Errorf("unsupported platform: %q (web, android, ios, all)", options.platform) + return doctorOptions{}, fmt.Errorf("unsupported platform: %q (web, android, ios, ios-device, all)", options.platform) } } diff --git a/cmd/sanderling/doctor_test.go b/cmd/sanderling/doctor_test.go index d33a34c..d6c464d 100644 --- a/cmd/sanderling/doctor_test.go +++ b/cmd/sanderling/doctor_test.go @@ -127,13 +127,33 @@ func TestDoctorChecksFor_All_IsUnion(t *testing.T) { for _, c := range all { names[c.Name]++ } - for _, name := range []string{"adb on PATH", "xcrun on PATH", "headless chromium can launch"} { + for _, name := range []string{"adb on PATH", "xcrun on PATH (ios simulator)", "headless chromium can launch"} { if names[name] != 1 { t.Errorf("expected %q in 'all' exactly once, got %d", name, names[name]) } } } +func TestDoctorChecksFor_iOSSimulator_OmitsJava(t *testing.T) { + for _, c := range doctorChecksFor("ios") { + if strings.Contains(c.Name, "java") || strings.Contains(c.Name, "sidecar") { + t.Errorf("ios simulator checks must omit %q; simulator runs need no JVM", c.Name) + } + } +} + +func TestDoctorChecksFor_iOSDevice_IncludesJava(t *testing.T) { + found := false + for _, c := range doctorChecksFor("ios-device") { + if strings.Contains(c.Name, "java") { + found = true + } + } + if !found { + t.Error("ios-device checks must include java for the sidecar path") + } +} + func TestDoctorChecksFor_UnknownPlatform(t *testing.T) { if got := doctorChecksFor("fuchsia"); got != nil { t.Errorf("expected nil for unknown platform, got %+v", got)