File: TaskExecutionTestSupport.swift

package info (click to toggle)
swiftlang 6.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,856,264 kB
  • sloc: cpp: 9,995,718; ansic: 2,234,019; asm: 1,092,167; python: 313,940; objc: 82,726; f90: 80,126; lisp: 38,373; pascal: 25,580; sh: 20,378; ml: 5,058; perl: 4,751; makefile: 4,725; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (107 lines) | stat: -rw-r--r-- 7,191 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

package import SWBCore
package import SWBTaskConstruction
package import SWBTaskExecution
package import SWBUtil
package import struct SWBProtocol.BuildDescriptionID
package import struct SWBProtocol.BuildOperationTaskEnded
package import struct SWBProtocol.TargetDependencyRelationship
import Synchronization

/// An empty delegate implementation.
package final class MockTestBuildDescriptionConstructionDelegate: BuildDescriptionConstructionDelegate, Sendable {
    package let diagnosticContext: DiagnosticContextData

    package func diagnosticsEngine(for target: ConfiguredTarget?) -> DiagnosticProducingDelegateProtocolPrivate<DiagnosticsEngine> {
        .init(diagnosticsEngines.withLock { $0.getOrInsert(target, { DiagnosticsEngine() }) })
    }

    package var diagnostics: [ConfiguredTarget? : [Diagnostic]] {
        diagnosticsEngines.withLock { $0.mapValues { $0.diagnostics } }
    }

    package var hadErrors: Bool {
        diagnosticsEngines.withLock { $0.contains(where: { _, engine in engine.hasErrors }) }
    }

    package let cancelled = false

    private let forPerf: Bool
    private let _manifest = SWBMutex<TestManifest?>(nil)
    package var manifest: TestManifest? {
        _manifest.withLock { $0 }
    }

    package func updateProgress(statusMessage: String, showInLog: Bool) {}

    package func beginActivity(ruleInfo: String, executionDescription: String, signature: ByteString, target: ConfiguredTarget?, parentActivity: ActivityID?) -> ActivityID { .init(rawValue: -1) }
    package func endActivity(id: ActivityID, signature: ByteString, status: BuildOperationTaskEnded.Status) { }
    package func emit(data: [UInt8], for activity: ActivityID, signature: ByteString) { }
    package func emit(diagnostic: Diagnostic, for activity: ActivityID, signature: ByteString) {
        diagnosticsEngine(for: nil).emit(diagnostic) // FIXME: Technically this should be a "global task" diagnostic
    }

    package func emit(_ diagnostic: Diagnostic) {
        diagnosticsEngine(for: nil).emit(diagnostic)
    }

    package func buildDescriptionCreated(_ buildDescriptionID: BuildDescriptionID) {}

    private let diagnosticsEngines = LockedValue<[ConfiguredTarget?: DiagnosticsEngine]>(.init())

    /// - parameter forPerf: Pass `true` if this delegate is for a performance test.  This will skip recording the manifest to the delegate, as that could take significant time.
    package init(forPerf: Bool = false) {
        self.forPerf = forPerf
        self.diagnosticContext = DiagnosticContextData(target: nil)
    }

    package func recordManifest(targetDefinitions: [String: ByteString], toolDefinitions: [String: ByteString], nodeDefinitions: [String: ByteString], commandDefinitions: [String: ByteString]) throws {
        guard !forPerf else {
            return
        }
        try _manifest.withLock { manifest in
            manifest = try TestManifest(targetDefinitions: targetDefinitions, toolDefinitions: toolDefinitions, nodeDefinitions: nodeDefinitions, commandDefinitions: commandDefinitions)
        }
    }
}

/// A representation of the manifest data for testing purposes.
package struct TestManifest: Sendable {
    package let targetDefinitions: [String: PropertyListItem]
    package let toolDefinitions: [String: PropertyListItem]
    package let nodeDefinitions: [String: PropertyListItem]
    package let commandDefinitions: [String: PropertyListItem]

    package init(targetDefinitions: [String: ByteString], toolDefinitions: [String: ByteString], nodeDefinitions: [String: ByteString], commandDefinitions: [String: ByteString]) throws {
        self.targetDefinitions = try targetDefinitions.mapValues({ try PropertyList.fromJSONData($0) })
        self.toolDefinitions = try toolDefinitions.mapValues({ try PropertyList.fromJSONData($0) })
        self.nodeDefinitions = try nodeDefinitions.mapValues({ try PropertyList.fromJSONData($0) })
        self.commandDefinitions = try commandDefinitions.mapValues({ try PropertyList.fromJSONData($0) })
    }

}

extension BuildDescription {
    /// Convenience testing method which omits the `capturedBuildInfo:` parameter.
    static package func construct(workspace: Workspace, tasks: [any PlannedTask], path: Path, signature: BuildDescriptionSignature, buildCommand: BuildCommand, diagnostics: [ConfiguredTarget?: [Diagnostic]] = [:], indexingInfo: [(forTarget: ConfiguredTarget?, path: Path, indexingInfo: any SourceFileIndexingInfo)] = [], fs: any FSProxy = localFS, bypassActualTasks: Bool = false, moduleSessionFilePath: Path? = nil, invalidationPaths: [Path] = [], recursiveSearchPathResults: [RecursiveSearchPathResolver.CachedResult] = [], copiedPathMap: [String: String] = [:], rootPathsPerTarget: [ConfiguredTarget:[Path]] = [:], moduleCachePathsPerTarget: [ConfiguredTarget: [Path]] = [:], casValidationInfos: [BuildDescription.CASValidationInfo] = [], staleFileRemovalIdentifierPerTarget: [ConfiguredTarget: String] = [:], settingsPerTarget: [ConfiguredTarget: Settings] = [:], delegate: any BuildDescriptionConstructionDelegate, targetDependencies: [TargetDependencyRelationship] = [], definingTargetsByModuleName: [String: OrderedSet<ConfiguredTarget>] = [:]) async throws -> BuildDescription? {
        return try await construct(workspace: workspace, tasks: tasks, path: path, signature: signature, buildCommand: buildCommand, diagnostics: diagnostics, indexingInfo: indexingInfo, fs: fs, bypassActualTasks: bypassActualTasks, moduleSessionFilePath: moduleSessionFilePath, invalidationPaths: invalidationPaths, recursiveSearchPathResults: recursiveSearchPathResults, copiedPathMap: copiedPathMap, rootPathsPerTarget: rootPathsPerTarget, moduleCachePathsPerTarget: moduleCachePathsPerTarget, casValidationInfos: casValidationInfos, staleFileRemovalIdentifierPerTarget: staleFileRemovalIdentifierPerTarget, settingsPerTarget: settingsPerTarget, delegate: delegate, targetDependencies: targetDependencies, definingTargetsByModuleName: definingTargetsByModuleName, capturedBuildInfo: nil, userPreferences: .defaultForTesting)
    }
}

extension BuildDescriptionManager {
    package func getNewOrCachedBuildDescription(_ request: BuildPlanRequest, bypassActualTasks: Bool = false, clientDelegate: any TaskPlanningClientDelegate, constructionDelegate: any BuildDescriptionConstructionDelegate) async throws -> BuildDescriptionRetrievalInfo? {
        let descRequest = BuildDescriptionRequest.newOrCached(request, bypassActualTasks: bypassActualTasks, useSynchronousBuildDescriptionSerialization: true)
        return try await getNewOrCachedBuildDescription(descRequest, clientDelegate: clientDelegate, constructionDelegate: constructionDelegate)
    }
}