From 00858ee95e74484fd24069f97ba2ace68353b6cc Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:01:58 +0200 Subject: [PATCH 01/12] Change the type of path --- Sources/Shared/Configuration.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Shared/Configuration.swift b/Sources/Shared/Configuration.swift index f184cad70..19146ce92 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 From c565aeaa83f505d218f0bbb6763ce0a59383189b Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 09:50:08 +0200 Subject: [PATCH 02/12] Super draft acceptance test --- Package.swift | 24 +- .../Commands/CheckUpdateCommand.swift | 9 +- .../Commands/ClearCacheCommand.swift | 8 +- .../Commands/FrontendCommand.swift | 4 +- .../{Frontend => }/Commands/ScanCommand.swift | 9 +- Sources/Commands/VersionCommand.swift | 16 + .../Frontend/Commands/VersionCommand.swift | 13 - Sources/Frontend/Project.swift | 2 +- Sources/Frontend/Scan.swift | 6 +- .../{Commands => }/ScanBehavior.swift | 8 +- Sources/Frontend/UpdateChecker.swift | 8 +- Sources/Frontend/Version.swift | 2 +- .../{Frontend => PeripheryMain}/main.swift | 1 + Sources/Shared/Logger.swift | 10 +- Tests/FrontendTests/ScanTests.swift | 40 ++ .../project.pbxproj | 349 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Assets.xcassets/Contents.json | 6 + .../DefaultiOSProject/ContentView.swift | 24 ++ .../DefaultiOSProjectApp.swift | 17 + .../Preview Assets.xcassets/Contents.json | 6 + 24 files changed, 561 insertions(+), 40 deletions(-) rename Sources/{Frontend => }/Commands/CheckUpdateCommand.swift (83%) rename Sources/{Frontend => }/Commands/ClearCacheCommand.swift (58%) rename Sources/{Frontend => }/Commands/FrontendCommand.swift (54%) rename Sources/{Frontend => }/Commands/ScanCommand.swift (98%) create mode 100644 Sources/Commands/VersionCommand.swift delete mode 100644 Sources/Frontend/Commands/VersionCommand.swift rename Sources/Frontend/{Commands => }/ScanBehavior.swift (90%) rename Sources/{Frontend => PeripheryMain}/main.swift (97%) create mode 100644 Tests/FrontendTests/ScanTests.swift create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift create mode 100644 fixtures/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json diff --git a/Package.swift b/Package.swift index 1f5c5742d..7c81ba8c1 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,12 @@ var targets: [PackageDescription.Target] = [ .target(name: "PeripheryKit") ] ), + .testTarget( + name: "FrontendTests", + dependencies: [ + .target(name: "Commands") + ] + ), .testTarget( name: "SPMTests", dependencies: [ @@ -141,7 +161,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 6c222645e..47325de1a 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 1309171a7..a80aac3f3 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 872d120eb..ae0ef676b 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 2f2ee1d68..9e61445fd 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 000000000..22e7aa881 --- /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 4cbf76923..000000000 --- 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 12f00df83..1ecccced4 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 diff --git a/Sources/Frontend/Scan.swift b/Sources/Frontend/Scan.swift index c5452b00a..ea6c616a0 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 e77dda4fe..c300c5454 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 dbd7db27d..ca1aaed5a 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 c7e7d4dc4..98a0eefee 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 91289fe80..5cce40833 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/Logger.swift b/Sources/Shared/Logger.swift index 240086e36..845f28048 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/Tests/FrontendTests/ScanTests.swift b/Tests/FrontendTests/ScanTests.swift new file mode 100644 index 000000000..f4ca3f749 --- /dev/null +++ b/Tests/FrontendTests/ScanTests.swift @@ -0,0 +1,40 @@ +import XCTest +import PathKit +import SystemPackage +import ArgumentParser +import Commands +import Shared + +final class ScanTests: XCTestCase { + fileprivate let packageRootPath = URL(fileURLWithPath: #file).pathComponents + .prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst() + + func testScanWorkspaceWithPath() async throws { + var file = FilePath(String(packageRootPath)) + + file.append(FilePath.Component("fixtures")) + file.append(FilePath.Component("DefaultiOSProject")) + file.append(FilePath.Component("DefaultiOSProject.xcodeproj")) + + let command = try ScanCommand.parse( + [ + "--project", "\(file.url.path())", + "--schemes", "DefaultiOSProject" + ] + ) + try command.run() + + XCTAssertTrue(LoggerStorage.collectedLogs.contains( + [ + "* Inspecting project...", + "* Building DefaultiOSProject...", + "* Indexing...", + "* Analyzing...", + "", + "* No unused code detected." + ] + ) + ) + } +} + diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj b/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj new file mode 100644 index 000000000..2a80eb92b --- /dev/null +++ b/fixtures/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/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json b/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json b/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..13613e3ee --- /dev/null +++ b/fixtures/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/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json b/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift b/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift new file mode 100644 index 000000000..99a0b15ef --- /dev/null +++ b/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift @@ -0,0 +1,24 @@ +// +// ContentView.swift +// DefaultiOSProject +// +// Created by Roman Gorbenko on 15.08.2024. +// + +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/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift b/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift new file mode 100644 index 000000000..70a26feda --- /dev/null +++ b/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift @@ -0,0 +1,17 @@ +// +// DefaultiOSProjectApp.swift +// DefaultiOSProject +// +// Created by Roman Gorbenko on 15.08.2024. +// + +import SwiftUI + +@main +struct DefaultiOSProjectApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json b/fixtures/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/fixtures/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} From 8c1ef691199545c464702d1b26c5865adc92652d Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 09:55:48 +0200 Subject: [PATCH 03/12] Removed Xcode static headers --- Sources/Commands/VersionCommand.swift | 2 +- Tests/FrontendTests/ScanTests.swift | 60 +++++++++---------- .../DefaultiOSProject/ContentView.swift | 7 --- .../DefaultiOSProjectApp.swift | 7 --- 4 files changed, 31 insertions(+), 45 deletions(-) diff --git a/Sources/Commands/VersionCommand.swift b/Sources/Commands/VersionCommand.swift index 22e7aa881..4de1cdaeb 100644 --- a/Sources/Commands/VersionCommand.swift +++ b/Sources/Commands/VersionCommand.swift @@ -8,7 +8,7 @@ public struct VersionCommand: FrontendCommand { abstract: "Display the version of Periphery" ) - public init() { } + public init() { } public func run() throws { print(PeripheryVersion) diff --git a/Tests/FrontendTests/ScanTests.swift b/Tests/FrontendTests/ScanTests.swift index f4ca3f749..0bd56a153 100644 --- a/Tests/FrontendTests/ScanTests.swift +++ b/Tests/FrontendTests/ScanTests.swift @@ -6,35 +6,35 @@ import Commands import Shared final class ScanTests: XCTestCase { - fileprivate let packageRootPath = URL(fileURLWithPath: #file).pathComponents - .prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst() - - func testScanWorkspaceWithPath() async throws { - var file = FilePath(String(packageRootPath)) - - file.append(FilePath.Component("fixtures")) - file.append(FilePath.Component("DefaultiOSProject")) - file.append(FilePath.Component("DefaultiOSProject.xcodeproj")) + fileprivate let packageRootPath = URL(fileURLWithPath: #file).pathComponents + .prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst() - let command = try ScanCommand.parse( - [ - "--project", "\(file.url.path())", - "--schemes", "DefaultiOSProject" - ] - ) - try command.run() - - XCTAssertTrue(LoggerStorage.collectedLogs.contains( - [ - "* Inspecting project...", - "* Building DefaultiOSProject...", - "* Indexing...", - "* Analyzing...", - "", - "* No unused code detected." - ] - ) - ) - } + func testScanWorkspaceWithPath() async throws { + var file = FilePath(String(packageRootPath)) + + file.append(FilePath.Component("fixtures")) + file.append(FilePath.Component("DefaultiOSProject")) + file.append(FilePath.Component("DefaultiOSProject.xcodeproj")) + + let command = try ScanCommand.parse( + [ + "--project", "\(file.url.path())", + "--schemes", "DefaultiOSProject" + ] + ) + try command.run() + + XCTAssertTrue(LoggerStorage.collectedLogs.contains( + [ + "* Inspecting project...", + "* Building DefaultiOSProject...", + "* Indexing...", + "* Analyzing...", + "", + "* No unused code detected." + ] + ) + ) + } } - + diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift b/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift index 99a0b15ef..b000a7e46 100644 --- a/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift +++ b/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift @@ -1,10 +1,3 @@ -// -// ContentView.swift -// DefaultiOSProject -// -// Created by Roman Gorbenko on 15.08.2024. -// - import SwiftUI struct ContentView: View { diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift b/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift index 70a26feda..39276d078 100644 --- a/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift +++ b/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift @@ -1,10 +1,3 @@ -// -// DefaultiOSProjectApp.swift -// DefaultiOSProject -// -// Created by Roman Gorbenko on 15.08.2024. -// - import SwiftUI @main From d062e003dc16578e97043120b1452ad4c4078d51 Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:16:17 +0200 Subject: [PATCH 04/12] Remove unused import --- Tests/FrontendTests/ScanTests.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/FrontendTests/ScanTests.swift b/Tests/FrontendTests/ScanTests.swift index 0bd56a153..67b021093 100644 --- a/Tests/FrontendTests/ScanTests.swift +++ b/Tests/FrontendTests/ScanTests.swift @@ -1,5 +1,4 @@ import XCTest -import PathKit import SystemPackage import ArgumentParser import Commands From f26d2ed47f532eaad491a022593dcfe5147fc378 Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:32:32 +0200 Subject: [PATCH 05/12] Changed Foundation on FilePath --- Tests/FrontendTests/ScanTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/FrontendTests/ScanTests.swift b/Tests/FrontendTests/ScanTests.swift index 67b021093..331ea4332 100644 --- a/Tests/FrontendTests/ScanTests.swift +++ b/Tests/FrontendTests/ScanTests.swift @@ -14,10 +14,10 @@ final class ScanTests: XCTestCase { file.append(FilePath.Component("fixtures")) file.append(FilePath.Component("DefaultiOSProject")) file.append(FilePath.Component("DefaultiOSProject.xcodeproj")) - + let command = try ScanCommand.parse( [ - "--project", "\(file.url.path())", + "--project", "\(file.string)", "--schemes", "DefaultiOSProject" ] ) From d6ae7489d94ed06da8e0786a7d84607c38011dc9 Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:42:14 +0200 Subject: [PATCH 06/12] Replace fatalError with Error --- Sources/Frontend/Project.swift | 2 +- Sources/Shared/PeripheryError.swift | 3 +++ Tests/FrontendTests/ScanTests.swift | 8 +++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Sources/Frontend/Project.swift b/Sources/Frontend/Project.swift index 1ecccced4..c39fa1967 100644 --- a/Sources/Frontend/Project.swift +++ b/Sources/Frontend/Project.swift @@ -34,7 +34,7 @@ public 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/Shared/PeripheryError.swift b/Sources/Shared/PeripheryError.swift index 4f2dcc592..3f616924e 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(message: String) 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(message: let message): + return "Xcode projects are not supported on this platform" } } diff --git a/Tests/FrontendTests/ScanTests.swift b/Tests/FrontendTests/ScanTests.swift index 331ea4332..245679750 100644 --- a/Tests/FrontendTests/ScanTests.swift +++ b/Tests/FrontendTests/ScanTests.swift @@ -21,7 +21,13 @@ final class ScanTests: XCTestCase { "--schemes", "DefaultiOSProject" ] ) - try command.run() + do { + try command.run() + } catch PeripheryError.xcodeProjectsAreUnsupported { + #if os(Linux) + return + #endif + } XCTAssertTrue(LoggerStorage.collectedLogs.contains( [ From 51e5d2269282736275e50df97e1f84368df542b6 Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:03:01 +0200 Subject: [PATCH 07/12] Removed string --- Sources/Shared/PeripheryError.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Shared/PeripheryError.swift b/Sources/Shared/PeripheryError.swift index 3f616924e..6e08d572a 100644 --- a/Sources/Shared/PeripheryError.swift +++ b/Sources/Shared/PeripheryError.swift @@ -5,7 +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(message: String) + case xcodeProjectsAreUnsupported case underlyingError(Error) case invalidScheme(name: String, project: String) case sourceGraphIntegrityError(message: String) @@ -56,7 +56,7 @@ 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(message: let message): + case .xcodeProjectsAreUnsupported: return "Xcode projects are not supported on this platform" } } From caaefa8560e45db82f8cb1a9bac7dd861ef1d4af Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:24:25 +0200 Subject: [PATCH 08/12] added reset configuration --- Tests/PeripheryTests/CrossModuleRetentionTest.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/PeripheryTests/CrossModuleRetentionTest.swift b/Tests/PeripheryTests/CrossModuleRetentionTest.swift index 06772cba2..64c04c796 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() } From 8e33fa6c373cdfc0cb7e7dc847fd55622e4d35ad Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:31:40 +0200 Subject: [PATCH 09/12] Reset configuration --- Tests/SPMTests/SPMProjectTest.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/SPMTests/SPMProjectTest.swift b/Tests/SPMTests/SPMProjectTest.swift index 8fc099af1..40899be9f 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() } From 07c5bbd23556ef65641a64212760c51c54c4e61a Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Sun, 18 Aug 2024 14:47:39 +0200 Subject: [PATCH 10/12] Moved fixture --- Tests/FrontendTests/AcceptanceTestCase.swift | 51 +++++++++++++++++++ .../project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../DefaultiOSProject/ContentView.swift | 0 .../DefaultiOSProjectApp.swift | 0 .../Preview Assets.xcassets/Contents.json | 0 Tests/FrontendTests/ScanTests.swift | 32 ++---------- .../Extensions/FilePathGlobTest.swift | 1 - 12 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 Tests/FrontendTests/AcceptanceTestCase.swift rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject/ContentView.swift (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift (100%) rename {fixtures => Tests/FrontendTests}/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json (100%) diff --git a/Tests/FrontendTests/AcceptanceTestCase.swift b/Tests/FrontendTests/AcceptanceTestCase.swift new file mode 100644 index 000000000..5c8cbbf63 --- /dev/null +++ b/Tests/FrontendTests/AcceptanceTestCase.swift @@ -0,0 +1,51 @@ +import XCTest +import Commands +import ArgumentParser +import Shared +import System + + +public enum Fixture: String { + case defaultiOSProject = "Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj" +} + +public class AcceptanceTestCase: XCTestCase { + let packageRootPath = URL(fileURLWithPath: #file).pathComponents + .prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst() + + public override class func setUp() { + Configuration.shared.reset() + super.setUp() + } + + public override class func tearDown() { + Configuration.shared.reset() + super.tearDown() + } + + public func run(command: FrontendCommand.Type, arguments: String...) throws { + var command = try command + .parse(arguments) + try command.run() + } + + public func setupFixture(fixture: Fixture) -> FilePath { + var file = FilePath(String(packageRootPath)) + file.append(fixture.rawValue) + return file + } + + public func XCTOutputDefaultOutputWithoutUnusedCode(scheme: String) { + XCTAssertTrue(LoggerStorage.collectedLogs.contains( + [ + "* Inspecting project...", + "* Building \(scheme)...", + "* Indexing...", + "* Analyzing...", + "", + "* No unused code detected." + ] + )) + } + +} diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.pbxproj diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Assets.xcassets/Contents.json diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/ContentView.swift similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject/ContentView.swift rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/ContentView.swift diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/DefaultiOSProjectApp.swift diff --git a/fixtures/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json b/Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json similarity index 100% rename from fixtures/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json rename to Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject/Preview Content/Preview Assets.xcassets/Contents.json diff --git a/Tests/FrontendTests/ScanTests.swift b/Tests/FrontendTests/ScanTests.swift index 245679750..79925173a 100644 --- a/Tests/FrontendTests/ScanTests.swift +++ b/Tests/FrontendTests/ScanTests.swift @@ -4,42 +4,20 @@ import ArgumentParser import Commands import Shared -final class ScanTests: XCTestCase { - fileprivate let packageRootPath = URL(fileURLWithPath: #file).pathComponents - .prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst() - +final class ScanTests: AcceptanceTestCase { func testScanWorkspaceWithPath() async throws { - var file = FilePath(String(packageRootPath)) - - file.append(FilePath.Component("fixtures")) - file.append(FilePath.Component("DefaultiOSProject")) - file.append(FilePath.Component("DefaultiOSProject.xcodeproj")) + let project = setupFixture(fixture: .defaultiOSProject) - let command = try ScanCommand.parse( - [ - "--project", "\(file.string)", - "--schemes", "DefaultiOSProject" - ] - ) do { - try command.run() + try run(command: ScanCommand.self, arguments: "--project", "\(project)", + "--schemes", "DefaultiOSProject") } catch PeripheryError.xcodeProjectsAreUnsupported { #if os(Linux) return #endif } - XCTAssertTrue(LoggerStorage.collectedLogs.contains( - [ - "* Inspecting project...", - "* Building DefaultiOSProject...", - "* Indexing...", - "* Analyzing...", - "", - "* No unused code detected." - ] - ) - ) + XCTOutputDefaultOutputWithoutUnusedCode(scheme: "DefaultiOSProject") } } diff --git a/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift b/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift index a3d5d3462..0bf7a15a7 100644 --- a/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift +++ b/Tests/PeripheryTests/Extensions/FilePathGlobTest.swift @@ -1,4 +1,3 @@ -import Shared import SystemPackage import XCTest From 5bef2b0d2de0f55376c4eeea5658b2c9cb8d91bc Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Sun, 18 Aug 2024 14:55:42 +0200 Subject: [PATCH 11/12] Removed public --- Tests/FrontendTests/AcceptanceTestCase.swift | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Tests/FrontendTests/AcceptanceTestCase.swift b/Tests/FrontendTests/AcceptanceTestCase.swift index 5c8cbbf63..e780a51a6 100644 --- a/Tests/FrontendTests/AcceptanceTestCase.swift +++ b/Tests/FrontendTests/AcceptanceTestCase.swift @@ -1,41 +1,40 @@ import XCTest import Commands +import SystemPackage import ArgumentParser import Shared -import System - -public enum Fixture: String { +enum Fixture: String { case defaultiOSProject = "Tests/FrontendTests/DefaultiOSProject/DefaultiOSProject.xcodeproj" } -public class AcceptanceTestCase: XCTestCase { +class AcceptanceTestCase: XCTestCase { let packageRootPath = URL(fileURLWithPath: #file).pathComponents .prefix(while: { $0 != "Tests" }).joined(separator: "/").dropFirst() - public override class func setUp() { + override class func setUp() { Configuration.shared.reset() super.setUp() } - public override class func tearDown() { + override class func tearDown() { Configuration.shared.reset() super.tearDown() } - public func run(command: FrontendCommand.Type, arguments: String...) throws { + func run(command: FrontendCommand.Type, arguments: String...) throws { var command = try command .parse(arguments) try command.run() } - public func setupFixture(fixture: Fixture) -> FilePath { + func setupFixture(fixture: Fixture) -> FilePath { var file = FilePath(String(packageRootPath)) file.append(fixture.rawValue) return file } - public func XCTOutputDefaultOutputWithoutUnusedCode(scheme: String) { + func XCTOutputDefaultOutputWithoutUnusedCode(scheme: String) { XCTAssertTrue(LoggerStorage.collectedLogs.contains( [ "* Inspecting project...", From bedb72c288f12d1c0ecac8b3b86de2a61a1a3833 Mon Sep 17 00:00:00 2001 From: Gorbenko Roman <45801227+rofle100lvl@users.noreply.github.com> Date: Sun, 18 Aug 2024 14:59:21 +0200 Subject: [PATCH 12/12] Exclude Project --- Package.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 7c81ba8c1..528d02cc7 100644 --- a/Package.swift +++ b/Package.swift @@ -114,7 +114,8 @@ var targets: [PackageDescription.Target] = [ name: "FrontendTests", dependencies: [ .target(name: "Commands") - ] + ], + exclude: ["DefaultiOSProject"] ), .testTarget( name: "SPMTests",