         }
     }
     
+    /// Assert that the operations of different tasks do not overlap (i.e. second task does not start until the firs task has finished)
     private func XCTAssertTasksDoNotOverlap(_ taskIds: [String], file: StaticString = #file, line: UInt = #line) async {
         for i in 0 ..< taskIds.count {
             for j in i + 1 ..< taskIds.count {

        }
    }
    
    private func XCTAssertAllOperationsPerformed(_ taskIds: [String], file: StaticString = #file, line: UInt = #line) async {
        let count = await timeline.numberOfOperations
        XCTAssertEqual(count, taskIds.count * Operation.Kind.allCases.count, file: file, line: line)
    }
    
    private func XCTAssertTaskOrderEqual(_ taskIds: [String], expectedOrder: [Operation.Kind], file: StaticString = #file, line: UInt = #line) async {
        for id in taskIds {
            let realOrder = await timeline.operationOrder(for: id)
            XCTAssertEqual(realOrder, expectedOrder, "Order for task \(id) is incorrect", file: file, line: line)
        }
    }
    
    private func XCTAssertTasksOverlap(_ taskIds: [String], file: StaticString = #file, line: UInt = #line) async {
        for i in 0 ..< taskIds.count {
            for j in i + 1 ..< taskIds.count {

    
    /// An operation within or outside of a task used to assert test results
    struct Operation: Hashable {
        enum Kind: String, CaseIterable, CustomStringConvertible {
            case taskStart
            case taskEnd
            case nonTask
            
            var description: String {
                return rawValue
            }
        }
        
        let id: String
