// Build dependencies: the JDK the project needs, version parsing, and doctor --install planning. import { describe, expect, test } from 'bun:test'; import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { installPlan, type DoctorResult } from '../cli/doctor'; import { installCommands, majorOf, parseVersion, requiredJdk } from '../cli/lib/tools'; function project(files: Record): string { const dir = mkdtempSync(join(tmpdir(), 'sb-deps-')); for (const [p, text] of Object.entries(files)) { mkdirSync(join(dir, p, '..'), { recursive: true }); writeFileSync(join(dir, p), text); } return dir; } describe('build dependencies', () => { test('JDK version from java -version and majors', () => { expect(parseVersion('openjdk version "17.0.9" 2023-10-17')).toBe('17.0.9'); expect(parseVersion('java version "1.8.0_392"')).toBe('1.8.0_392'); expect(majorOf('17.0.9')).toBe(17); expect(majorOf('1.8.0_392')).toBe(8); }); test('the JDK a project needs: AGP minimum, jvmToolchain wins when higher', () => { expect(requiredJdk(project({ 'android/build.gradle': "classpath 'com.android.tools.build:gradle:8.7.2'" }))).toBe('17'); expect(requiredJdk(project({ 'android/build.gradle': "classpath 'com.android.tools.build:gradle:7.4.2'" }))).toBe('11'); expect(requiredJdk(project({ 'android/gradle/libs.versions.toml': 'agp = "8.5.0"', 'android/app/build.gradle.kts': 'kotlin { jvmToolchain(21) }' }))).toBe('21'); expect(requiredJdk(project({ 'package.json': '{}' }))).toBeNull(); }); test('install commands per OS; doctor --install runs only package-manager commands, never sudo', () => { expect(installCommands('java', 'win32')[0]).toBe('winget install --id EclipseAdoptium.Temurin.17.JDK'); expect(installCommands('sdkmanager', 'darwin')[0]).toBe('brew install --cask android-commandlinetools'); const r = { tools: [{ id: 'java', name: 'JDK (Java)', found: false, version: null, path: null, source: null, usedFor: '', install: [], url: null, status: 'missing' }] } as unknown as DoctorResult; expect(installPlan(r, 'java', 'win32')).toMatchObject({ command: 'winget install --id EclipseAdoptium.Temurin.17.JDK', runnable: true }); expect(installPlan(r, 'java', 'linux').runnable).toBe(false); expect(() => installPlan(r, 'nope', 'win32')).toThrow('no tool "nope"'); }); });