Files
wehub-resource-sync 1d1286fadb
Build / Build and test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:18:38 +08:00

125 lines
6.0 KiB
Swift

import XCTest
@testable import MacTools
@testable import LaunchpadPlugin
final class LaunchpadAppScannerTests: XCTestCase {
// MARK: - strippedAppSuffix (only trailing ".app", never mid-string)
func testStrippedAppSuffixRemovesOnlyTrailingDotApp() {
XCTAssertEqual(LaunchpadAppScanner.strippedAppSuffix("Safari.app"), "Safari")
XCTAssertEqual(LaunchpadAppScanner.strippedAppSuffix("Safari"), "Safari")
XCTAssertEqual(LaunchpadAppScanner.strippedAppSuffix("App Store"), "App Store")
// ".app" in the middle must NOT be removed (the bug Codex flagged).
XCTAssertEqual(LaunchpadAppScanner.strippedAppSuffix("My.app Helper"), "My.app Helper")
// Only ONE trailing suffix removed.
XCTAssertEqual(LaunchpadAppScanner.strippedAppSuffix("Weird.app.app"), "Weird.app")
XCTAssertEqual(LaunchpadAppScanner.strippedAppSuffix(""), "")
}
// MARK: - nested-helper guard (path-level)
func testIsNestedInsideAnotherApp() {
XCTAssertFalse(LaunchpadAppScanner.isNestedInsideAnotherApp(URL(fileURLWithPath: "/Applications/Foo.app")))
XCTAssertFalse(LaunchpadAppScanner.isNestedInsideAnotherApp(URL(fileURLWithPath: "/Applications/Utilities/Terminal.app")))
XCTAssertTrue(LaunchpadAppScanner.isNestedInsideAnotherApp(
URL(fileURLWithPath: "/Applications/Foo.app/Contents/Helpers/Bar.app")
))
}
// MARK: - isValidAppBundle (directory + Contents/Info.plist)
func testIsValidAppBundleRequiresDirectoryAndInfoPlist() throws {
let tmp = try makeTempDir()
let validApp = try makeAppBundle(in: tmp, named: "Real.app")
let emptyDirApp = tmp.appendingPathComponent("Empty.app")
try FileManager.default.createDirectory(at: emptyDirApp, withIntermediateDirectories: true)
let fileApp = tmp.appendingPathComponent("File.app")
try Data().write(to: fileApp)
XCTAssertTrue(LaunchpadAppScanner.isValidAppBundle(at: validApp.path))
XCTAssertFalse(LaunchpadAppScanner.isValidAppBundle(at: emptyDirApp.path)) // no Info.plist
XCTAssertFalse(LaunchpadAppScanner.isValidAppBundle(at: fileApp.path)) // not a directory
XCTAssertFalse(LaunchpadAppScanner.isValidAppBundle(at: tmp.appendingPathComponent("Missing.app").path))
}
// MARK: - scan over a fixture tree
func testScanFindsAppsRecursivelyAndSorts() throws {
let tmp = try makeTempDir()
_ = try makeAppBundle(in: tmp, named: "Zebra.app")
// Recursion: an app inside a subfolder (like /Applications/Utilities).
let utilities = tmp.appendingPathComponent("Utilities", isDirectory: true)
try FileManager.default.createDirectory(at: utilities, withIntermediateDirectories: true)
_ = try makeAppBundle(in: utilities, named: "Alpha.app")
let items = LaunchpadAppScanner.scan(roots: [tmp.path])
XCTAssertEqual(items.map(\.name), ["Alpha", "Zebra"]) // sorted
XCTAssertEqual(Set(items.map(\.id)).count, 2)
}
func testScanExcludesCorruptBundleWithoutInfoPlist() throws {
let tmp = try makeTempDir()
_ = try makeAppBundle(in: tmp, named: "Good.app")
// A directory named like an app but with no Info.plist (corrupt/placeholder).
try FileManager.default.createDirectory(
at: tmp.appendingPathComponent("Broken.app"), withIntermediateDirectories: true
)
// A FILE named like an app.
try Data().write(to: tmp.appendingPathComponent("NotReal.app"))
let items = LaunchpadAppScanner.scan(roots: [tmp.path])
XCTAssertEqual(items.map(\.name), ["Good"])
}
func testScanExcludesNestedHelperApp() throws {
let tmp = try makeTempDir()
let host = try makeAppBundle(in: tmp, named: "Host.app")
// A real helper app embedded inside the host bundle. `.skipsPackageDescendants`
// should prevent it from ever being yielded; the nested guard is the backstop.
let helpersDir = host.appendingPathComponent("Contents/Helpers", isDirectory: true)
try FileManager.default.createDirectory(at: helpersDir, withIntermediateDirectories: true)
_ = try makeAppBundle(in: helpersDir, named: "Helper.app")
let items = LaunchpadAppScanner.scan(roots: [tmp.path])
XCTAssertEqual(items.map(\.name), ["Host"]) // Helper.app excluded
}
func testScanSkipsNonexistentRoots() {
let items = LaunchpadAppScanner.scan(roots: ["/no/such/path/\(UUID().uuidString)"])
XCTAssertTrue(items.isEmpty)
}
func testScanDedupesSymlinkedDuplicate() throws {
let tmp = try makeTempDir()
let real = try makeAppBundle(in: tmp, named: "Real.app")
let link = tmp.appendingPathComponent("Link.app")
try FileManager.default.createSymbolicLink(at: link, withDestinationURL: real)
let items = LaunchpadAppScanner.scan(roots: [tmp.path])
// Real.app and Link.app resolve to the same path → a single deduped entry.
XCTAssertEqual(items.count, 1)
XCTAssertEqual(items.first?.id, real.resolvingSymlinksInPath().path)
}
// MARK: - Helpers
private func makeTempDir() throws -> URL {
let dir = FileManager.default.temporaryDirectory
.appendingPathComponent("LaunchpadAppScannerTests-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
addTeardownBlock { try? FileManager.default.removeItem(at: dir) }
return dir
}
/// Creates a minimal valid `.app` bundle (a directory with `Contents/Info.plist`).
@discardableResult
private func makeAppBundle(in parent: URL, named name: String) throws -> URL {
let app = parent.appendingPathComponent(name, isDirectory: true)
let contents = app.appendingPathComponent("Contents", isDirectory: true)
try FileManager.default.createDirectory(at: contents, withIntermediateDirectories: true)
try Data("<plist></plist>".utf8).write(to: contents.appendingPathComponent("Info.plist"))
return app
}
}