diff --git a/Package.swift b/Package.swift index 1f5c5742d6..528d02cc75 100644 --- a/Package.swift +++ b/Package.swift @@ -33,10 +33,24 @@ frontendDependencies.append(.target(name: "XcodeSupport")) #endif var targets: [PackageDescription.Target] = [ - .executableTarget( + .executableTarget( + name: "PeripheryMain", + dependencies: [ + .target(name: "Commands"), + .target(name: "Shared"), + ] + ), + .target( name: "Frontend", dependencies: frontendDependencies ), + .target(name: "Commands", + dependencies: [ + .product(name: "SystemPackage", package: "swift-system"), + .product(name: "ArgumentParser", package: "swift-argument-parser"), + .target(name: "Shared"), + .target(name: "Frontend") + ]), .target( name: "PeripheryKit", dependencies: [ @@ -96,6 +110,13 @@ var targets: [PackageDescription.Target] = [ .target(name: "PeripheryKit") ] ), + .testTarget( + name: "FrontendTests", + dependencies: [ + .target(name: "Commands") + ], + exclude: ["DefaultiOSProject"] + ), .testTarget( name: "SPMTests", dependencies: [ @@ -141,7 +162,7 @@ let package = Package( name: "Periphery", platforms: [.macOS(.v13)], products: [ - .executable(name: "periphery", targets: ["Frontend"]), + .executable(name: "periphery", targets: ["PeripheryMain"]), .library(name: "PeripheryKit", targets: ["PeripheryKit"]) ], dependencies: dependencies, diff --git a/Sources/Frontend/Commands/CheckUpdateCommand.swift b/Sources/Commands/CheckUpdateCommand.swift similarity index 83% rename from Sources/Frontend/Commands/CheckUpdateCommand.swift rename to Sources/Commands/CheckUpdateCommand.swift index 6c222645e3..47325de1a0 100644 --- a/Sources/Frontend/Commands/CheckUpdateCommand.swift +++ b/Sources/Commands/CheckUpdateCommand.swift @@ -1,14 +1,17 @@ import ArgumentParser +import Frontend import Foundation import Shared -struct CheckUpdateCommand: FrontendCommand { - static let configuration = CommandConfiguration( +public struct CheckUpdateCommand: FrontendCommand { + public static let configuration = CommandConfiguration( commandName: "check-update", abstract: "Check for available update" ) + + public init() { } - func run() throws { + public func run() throws { let logger = Logger() let checker = UpdateChecker() DispatchQueue.global().async { checker.run() } diff --git a/Sources/Frontend/Commands/ClearCacheCommand.swift b/Sources/Commands/ClearCacheCommand.swift similarity index 58% rename from Sources/Frontend/Commands/ClearCacheCommand.swift rename to Sources/Commands/ClearCacheCommand.swift index 1309171a78..a80aac3f38 100644 --- a/Sources/Frontend/Commands/ClearCacheCommand.swift +++ b/Sources/Commands/ClearCacheCommand.swift @@ -2,13 +2,15 @@ import ArgumentParser import Foundation import Shared -struct ClearCacheCommand: FrontendCommand { - static let configuration = CommandConfiguration( +public struct ClearCacheCommand: FrontendCommand { + public static let configuration = CommandConfiguration( commandName: "clear-cache", abstract: "Clear Periphery's build cache" ) + + public init() { } - func run() throws { + public func run() throws { try Shell.shared.exec(["rm", "-rf", Constants.cachePath().string]) } } diff --git a/Sources/Frontend/Commands/FrontendCommand.swift b/Sources/Commands/FrontendCommand.swift similarity index 54% rename from Sources/Frontend/Commands/FrontendCommand.swift rename to Sources/Commands/FrontendCommand.swift index 872d120eb3..ae0ef676b8 100644 --- a/Sources/Frontend/Commands/FrontendCommand.swift +++ b/Sources/Commands/FrontendCommand.swift @@ -1,7 +1,7 @@ import ArgumentParser import Shared -protocol FrontendCommand: ParsableCommand {} -extension FrontendCommand { +public protocol FrontendCommand: ParsableCommand {} +public extension FrontendCommand { static var _errorLabel: String { colorize("error", .boldRed) } } diff --git a/Sources/Frontend/Commands/ScanCommand.swift b/Sources/Commands/ScanCommand.swift similarity index 98% rename from Sources/Frontend/Commands/ScanCommand.swift rename to Sources/Commands/ScanCommand.swift index 2f2ee1d687..9e61445fd8 100644 --- a/Sources/Frontend/Commands/ScanCommand.swift +++ b/Sources/Commands/ScanCommand.swift @@ -2,9 +2,10 @@ import ArgumentParser import Foundation import Shared import SystemPackage +import Frontend -struct ScanCommand: FrontendCommand { - static let configuration = CommandConfiguration( +public struct ScanCommand: FrontendCommand { + public static let configuration = CommandConfiguration( commandName: "scan", abstract: "Scan for unused code" ) @@ -127,8 +128,10 @@ struct ScanCommand: FrontendCommand { var genericProjectConfig: FilePath? private static let defaultConfiguration = Configuration() + + public init() { } - func run() throws { + public func run() throws { let scanBehavior = ScanBehavior() if !setup { diff --git a/Sources/Commands/VersionCommand.swift b/Sources/Commands/VersionCommand.swift new file mode 100644 index 0000000000..4de1cdaebb --- /dev/null +++ b/Sources/Commands/VersionCommand.swift @@ -0,0 +1,16 @@ +import ArgumentParser +import Foundation +import Frontend + +public struct VersionCommand: FrontendCommand { + public static let configuration = CommandConfiguration( + commandName: "version", + abstract: "Display the version of Periphery" + ) + + public init() { } + + public func run() throws { + print(PeripheryVersion) + } +} diff --git a/Sources/Frontend/Commands/VersionCommand.swift b/Sources/Frontend/Commands/VersionCommand.swift deleted file mode 100644 index 4cbf769234..0000000000 --- a/Sources/Frontend/Commands/VersionCommand.swift +++ /dev/null @@ -1,13 +0,0 @@ -import ArgumentParser -import Foundation - -struct VersionCommand: FrontendCommand { - static let configuration = CommandConfiguration( - commandName: "version", - abstract: "Display the version of Periphery" - ) - - func run() throws { - print(PeripheryVersion) - } -} diff --git a/Sources/Frontend/Project.swift b/Sources/Frontend/Project.swift index 12f00df831..c39fa19677 100644 --- a/Sources/Frontend/Project.swift +++ b/Sources/Frontend/Project.swift @@ -7,7 +7,7 @@ import SystemPackage import XcodeSupport #endif -final class Project { +public final class Project { static func identify() throws -> Self { let configuration = Configuration.shared @@ -34,7 +34,7 @@ final class Project { #if canImport(XcodeSupport) return try XcodeProjectDriver.build(projectPath: projectPath) #else - fatalError("Xcode projects are not supported on this platform.") + throw PeripheryError.xcodeProjectsAreUnsupported #endif case .spm: return try SPMProjectDriver.build() diff --git a/Sources/Frontend/Scan.swift b/Sources/Frontend/Scan.swift index c5452b00a9..ea6c616a05 100644 --- a/Sources/Frontend/Scan.swift +++ b/Sources/Frontend/Scan.swift @@ -4,17 +4,17 @@ import PeripheryKit import Shared import SourceGraph -final class Scan { +public final class Scan { private let configuration: Configuration private let logger: Logger private let graph = SourceGraph.shared - required init(configuration: Configuration = .shared, logger: Logger = .init()) { + public required init(configuration: Configuration = .shared, logger: Logger = .init()) { self.configuration = configuration self.logger = logger } - func perform(project: Project) throws -> [ScanResult] { + public func perform(project: Project) throws -> [ScanResult] { if !configuration.indexStorePath.isEmpty { logger.warn("When using the '--index-store-path' option please ensure that Xcode is not running. False-positives can occur if Xcode writes to the index store while Periphery is running.") diff --git a/Sources/Frontend/Commands/ScanBehavior.swift b/Sources/Frontend/ScanBehavior.swift similarity index 90% rename from Sources/Frontend/Commands/ScanBehavior.swift rename to Sources/Frontend/ScanBehavior.swift index e77dda4fe5..c300c54546 100644 --- a/Sources/Frontend/Commands/ScanBehavior.swift +++ b/Sources/Frontend/ScanBehavior.swift @@ -3,16 +3,16 @@ import PeripheryKit import Shared import SystemPackage -final class ScanBehavior { +public final class ScanBehavior { private let configuration: Configuration private let logger: Logger - required init(configuration: Configuration = .shared, logger: Logger = .init()) { + public required init(configuration: Configuration = .shared, logger: Logger = .init()) { self.configuration = configuration self.logger = logger } - func setup(_ configPath: FilePath?) -> Result<(), PeripheryError> { + public func setup(_ configPath: FilePath?) -> Result<(), PeripheryError> { do { try configuration.load(from: configPath) } catch let error as PeripheryError { @@ -24,7 +24,7 @@ final class ScanBehavior { return .success(()) } - func main(_ block: (Project) throws -> [ScanResult]) -> Result<(), PeripheryError> { + public func main(_ block: (Project) throws -> [ScanResult]) -> Result<(), PeripheryError> { logger.contextualized(with: "version").debug(PeripheryVersion) let project: Project diff --git a/Sources/Frontend/UpdateChecker.swift b/Sources/Frontend/UpdateChecker.swift index dbd7db27da..ca1aaed5a4 100644 --- a/Sources/Frontend/UpdateChecker.swift +++ b/Sources/Frontend/UpdateChecker.swift @@ -5,7 +5,7 @@ import Shared import FoundationNetworking #endif -final class UpdateChecker { +public final class UpdateChecker { private let logger: Logger private let debugLogger: ContextualLogger private let configuration: Configuration @@ -15,7 +15,7 @@ final class UpdateChecker { private let semaphore: DispatchSemaphore private var error: Error? - required init(logger: Logger = .init(), configuration: Configuration = .shared) { + public required init(logger: Logger = .init(), configuration: Configuration = .shared) { self.logger = logger self.debugLogger = logger.contextualized(with: "update-check") self.configuration = configuration @@ -29,7 +29,7 @@ final class UpdateChecker { urlSession.invalidateAndCancel() } - func run() { + public func run() { // We only perform the update check with xcode format because it may interfere with // parsing json and csv. guard !configuration.disableUpdateCheck, @@ -92,7 +92,7 @@ final class UpdateChecker { logger.info("To disable update checks pass the \(boldOption) option to the \(boldScan) command.") } - func wait() -> Result { + public func wait() -> Result { let waitResult = semaphore.wait(timeout: .now() + 60) if let error { diff --git a/Sources/Frontend/Version.swift b/Sources/Frontend/Version.swift index c7e7d4dc40..98a0eefeea 100644 --- a/Sources/Frontend/Version.swift +++ b/Sources/Frontend/Version.swift @@ -1 +1 @@ -let PeripheryVersion = "2.21.0" +public let PeripheryVersion = "2.21.0" diff --git a/Sources/Frontend/main.swift b/Sources/PeripheryMain/main.swift similarity index 97% rename from Sources/Frontend/main.swift rename to Sources/PeripheryMain/main.swift index 91289fe80d..5cce40833d 100644 --- a/Sources/Frontend/main.swift +++ b/Sources/PeripheryMain/main.swift @@ -1,6 +1,7 @@ import ArgumentParser import Foundation import Shared +import Commands Logger.configureBuffering() diff --git a/Sources/Shared/Configuration.swift b/Sources/Shared/Configuration.swift index f184cad707..19146ce929 100644 --- a/Sources/Shared/Configuration.swift +++ b/Sources/Shared/Configuration.swift @@ -294,8 +294,8 @@ protocol AbstractSetting { } private let filePathSetter: (Any) -> FilePath? = { value in - if let value = value as? String { - return FilePath(value) + if let value = value as? FilePath { + return value } return nil diff --git a/Sources/Shared/Logger.swift b/Sources/Shared/Logger.swift index 240086e36f..845f28048c 100644 --- a/Sources/Shared/Logger.swift +++ b/Sources/Shared/Logger.swift @@ -4,6 +4,11 @@ import Foundation import os #endif +public class LoggerStorage { + public static var collectedLogs: [String] = [] + +} + public enum ANSIColor: String { case bold = "\u{001B}[0;1m" case red = "\u{001B}[0;31m" @@ -72,7 +77,10 @@ public final class BaseLogger { @inlinable func log(_ line: String, output: UnsafeMutablePointer) { - _ = outputQueue.sync { fputs(line + "\n", output) } + outputQueue.sync { + fputs(line + "\n", output) + LoggerStorage.collectedLogs.append(line) + } } } diff --git a/Sources/Shared/PeripheryError.swift b/Sources/Shared/PeripheryError.swift index 4f2dcc5921..6e08d572a9 100644 --- a/Sources/Shared/PeripheryError.swift +++ b/Sources/Shared/PeripheryError.swift @@ -5,6 +5,7 @@ public enum PeripheryError: Error, LocalizedError, CustomStringConvertible { case shellCommandFailed(cmd: String, args: [String], status: Int32, output: String) case shellOutputEncodingFailed(cmd: String, args: [String], encoding: String.Encoding) case usageError(String) + case xcodeProjectsAreUnsupported case underlyingError(Error) case invalidScheme(name: String, project: String) case sourceGraphIntegrityError(message: String) @@ -55,6 +56,8 @@ public enum PeripheryError: Error, LocalizedError, CustomStringConvertible { return "JSON deserialization failed: \(describe(error))\nJSON:\n\(json)" case let .indexStoreNotFound(derivedDataPath): return "Failed to find index datastore at path: \(derivedDataPath)" + case .xcodeProjectsAreUnsupported: + return "Xcode projects are not supported on this platform" } } diff --git a/Tests/FrontendTests/AcceptanceTestCase.swift b/Tests/FrontendTests/AcceptanceTestCase.swift new file mode 100644 index 0000000000..e780a51a6c --- /dev/null +++ b/Tests/FrontendTests/AcceptanceTestCase.swift @@ -0,0 +1,50 @@ +import XCTest +import Commands +import SystemPackage +import ArgumentParser +import Shared + +enum Fixture: String { + case defaultiOSProject = "Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj" +} + +class AcceptanceTestCase: XCTestCase { + let packageRootPath = URL(fileURLWithPath: #file).pathComponents + .prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst() + + override class func setUp() { + Configuration.shared.reset() + super.setUp() + } + + override class func tearDown() { + Configuration.shared.reset() + super.tearDown() + } + + func run(command: FrontendCommand.Type, arguments: String...) throws { + var command = try command + .parse(arguments) + try command.run() + } + + func setupFixture(fixture: Fixture) -> FilePath { + var file = FilePath(String(packageRootPath)) + file.append(fixture.rawValue) + return file + } + + func XCTOutputDefaultOutputWithoutUnusedCode(scheme: String) { + XCTAssertTrue(LoggerStorage.collectedLogs.contains( + [ + "* Inspecting project...", + "* Building \(scheme)...", + "* Indexing...", + "* Analyzing...", + "", + "* No unused code detected." + ] + )) + } + +} diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..2a80eb92b3 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj @@ -0,0 +1,349 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + E4C110BA2C6E9AE300005784 /* DefaultiOSProjectApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C110B92C6E9AE300005784 /* DefaultiOSProjectApp.swift */; }; + E4C110BC2C6E9AE300005784 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C110BB2C6E9AE300005784 /* ContentView.swift */; }; + E4C110BE2C6E9AE500005784 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E4C110BD2C6E9AE500005784 /* Assets.xcassets */; }; + E4C110C12C6E9AE500005784 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E4C110C02C6E9AE500005784 /* Preview Assets.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + E4C110B62C6E9AE300005784 /* DefaultiOSProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DefaultiOSProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E4C110B92C6E9AE300005784 /* DefaultiOSProjectApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultiOSProjectApp.swift; sourceTree = ""; }; + E4C110BB2C6E9AE300005784 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + E4C110BD2C6E9AE500005784 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + E4C110C02C6E9AE500005784 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E4C110B32C6E9AE300005784 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E4C110AD2C6E9AE300005784 = { + isa = PBXGroup; + children = ( + E4C110B82C6E9AE300005784 /* DefaultiOSProject */, + E4C110B72C6E9AE300005784 /* Products */, + ); + sourceTree = ""; + }; + E4C110B72C6E9AE300005784 /* Products */ = { + isa = PBXGroup; + children = ( + E4C110B62C6E9AE300005784 /* DefaultiOSProject.app */, + ); + name = Products; + sourceTree = ""; + }; + E4C110B82C6E9AE300005784 /* DefaultiOSProject */ = { + isa = PBXGroup; + children = ( + E4C110B92C6E9AE300005784 /* DefaultiOSProjectApp.swift */, + E4C110BB2C6E9AE300005784 /* ContentView.swift */, + E4C110BD2C6E9AE500005784 /* Assets.xcassets */, + E4C110BF2C6E9AE500005784 /* Preview Content */, + ); + path = DefaultiOSProject; + sourceTree = ""; + }; + E4C110BF2C6E9AE500005784 /* Preview Content */ = { + isa = PBXGroup; + children = ( + E4C110C02C6E9AE500005784 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E4C110B52C6E9AE300005784 /* DefaultiOSProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = E4C110C42C6E9AE500005784 /* Build configuration list for PBXNativeTarget "DefaultiOSProject" */; + buildPhases = ( + E4C110B22C6E9AE300005784 /* Sources */, + E4C110B32C6E9AE300005784 /* Frameworks */, + E4C110B42C6E9AE300005784 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DefaultiOSProject; + productName = DefaultiOSProject; + productReference = E4C110B62C6E9AE300005784 /* DefaultiOSProject.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E4C110AE2C6E9AE300005784 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1540; + LastUpgradeCheck = 1540; + TargetAttributes = { + E4C110B52C6E9AE300005784 = { + CreatedOnToolsVersion = 15.4; + }; + }; + }; + buildConfigurationList = E4C110B12C6E9AE300005784 /* Build configuration list for PBXProject "DefaultiOSProject" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E4C110AD2C6E9AE300005784; + productRefGroup = E4C110B72C6E9AE300005784 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E4C110B52C6E9AE300005784 /* DefaultiOSProject */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E4C110B42C6E9AE300005784 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E4C110C12C6E9AE500005784 /* Preview Assets.xcassets in Resources */, + E4C110BE2C6E9AE500005784 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E4C110B22C6E9AE300005784 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E4C110BC2C6E9AE300005784 /* ContentView.swift in Sources */, + E4C110BA2C6E9AE300005784 /* DefaultiOSProjectApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + E4C110C22C6E9AE500005784 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + E4C110C32C6E9AE500005784 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + E4C110C52C6E9AE500005784 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"DefaultiOSProject/Preview Content\""; + DEVELOPMENT_TEAM = 26Y9H2V4NN; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dsa.DefaultiOSProject; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + E4C110C62C6E9AE500005784 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"DefaultiOSProject/Preview Content\""; + DEVELOPMENT_TEAM = 26Y9H2V4NN; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dsa.DefaultiOSProject; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E4C110B12C6E9AE300005784 /* Build configuration list for PBXProject "DefaultiOSProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E4C110C22C6E9AE500005784 /* Debug */, + E4C110C32C6E9AE500005784 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E4C110C42C6E9AE500005784 /* Build configuration list for PBXNativeTarget "DefaultiOSProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E4C110C52C6E9AE500005784 /* Debug */, + E4C110C62C6E9AE500005784 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = E4C110AE2C6E9AE300005784 /* Project object */; +} diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000000..eb87897008 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..13613e3ee1 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/ContentView.swift b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/ContentView.swift new file mode 100644 index 0000000000..b000a7e461 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/ContentView.swift @@ -0,0 +1,17 @@ +import SwiftUI + +struct ContentView: View { + var body: some View { + VStack { + Image(systemName: "globe") + .imageScale(.large) + .foregroundStyle(.tint) + Text("Hello, world!") + } + .padding() + } +} + +#Preview { + ContentView() +} diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift new file mode 100644 index 0000000000..39276d0781 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct DefaultiOSProjectApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Tests/FrontendTests/ScanTests.swift b/Tests/FrontendTests/ScanTests.swift new file mode 100644 index 0000000000..79925173a4 --- /dev/null +++ b/Tests/FrontendTests/ScanTests.swift @@ -0,0 +1,23 @@ +import XCTest +import SystemPackage +import ArgumentParser +import Commands +import Shared + +final class ScanTests: AcceptanceTestCase { + func testScanWorkspaceWithPath() async throws { + let project = setupFixture(fixture: .defaultiOSProject) + + do { + try run(command: ScanCommand.self, arguments: "--project", "\(project)", + "--schemes", "DefaultiOSProject") + } catch PeripheryError.xcodeProjectsAreUnsupported { + #if os(Linux) + return + #endif + } + + XCTOutputDefaultOutputWithoutUnusedCode(scheme: "DefaultiOSProject") + } +} + diff --git a/Tests/PeripheryTests/CrossModuleRetentionTest.swift b/Tests/PeripheryTests/CrossModuleRetentionTest.swift index 06772cba29..64c04c7967 100644 --- a/Tests/PeripheryTests/CrossModuleRetentionTest.swift +++ b/Tests/PeripheryTests/CrossModuleRetentionTest.swift @@ -5,7 +5,8 @@ import SystemPackage final class CrossModuleRetentionTest: SPMSourceGraphTestCase { override static func setUp() { super.setUp() - + + configuration.reset() build(projectPath: FixturesProjectPath) index() } diff --git a/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift b/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift index a3d5d34620..0bf7a15a7f 100644 --- a/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift +++ b/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift @@ -1,4 +1,3 @@ -import Shared import SystemPackage import XCTest diff --git a/Tests/SPMTests/SPMProjectTest.swift b/Tests/SPMTests/SPMProjectTest.swift index 8fc099af1a..40899be9f2 100644 --- a/Tests/SPMTests/SPMProjectTest.swift +++ b/Tests/SPMTests/SPMProjectTest.swift @@ -6,6 +6,7 @@ class SPMProjectTest: SPMSourceGraphTestCase { override static func setUp() { super.setUp() + configuration.reset() build(projectPath: SPMProjectPath) index() }