% for Kind in Kinds: %Minimal = 'Minimal' + Kind ${Test}.test("flatMap/${Kind}/Lazy") { for test in flatMapTests { let s = ${Minimal}>( elements: test.sequence.map(OpaqueValue.init)) let closureLifetimeTracker = LifetimeTracked(0) var timesClosureWasCalled = 0 var result = s.lazy.flatMap { (element: OpaqueValue) -> ${Minimal}> in _blackHole(closureLifetimeTracker) timesClosureWasCalled += 1 let elements = test.transform(element.value) return ${Minimal}>( elements: elements.map { OpaqueValue($0) }) } expectEqual(0, timesClosureWasCalled, "Unexpected eagerness") % if Kind == 'Sequence': let expected = test.expected.map(OpaqueValue.init) check${Kind}(expected, result, stackTrace: SourceLocStack().with(test.loc), resiliencyChecks: .none ) { $0.value == $1.value } expectEqual( test.sequence.count, timesClosureWasCalled, "iterating forward the result of the lazy flatMap() should call " + "the closure only once for element") % else: _ = Array(result) /* FIXME: this check is failing. This is a fundamental problem with lazy flatMap(). Investigate other Collection schemes: indices are compositions of offsets expectEqual( test.sequence.count, timesClosureWasCalled, "iterating forward the result of the lazy flatMap() should call " + "the closure only once for element") */ // FIXME: we are not calling check${Kind} because of the same issue again. // let expected = test.expected.map(OpaqueValue.init) expectEqualSequence( expected, result, stackTrace: SourceLocStack().with(test.loc) ) { $0.value == $1.value } % end % if Kind == 'Sequence': expectTrue(Array(s).isEmpty, "sequence should be consumed") expectEqual( test.sequence.count, timesClosureWasCalled, "iterating a lazy flatMap() should call the predicate" + "once per element") % end } for test in flatMapToOptionalTests { let s = ${Minimal}>(elements: test.sequence.map(OpaqueValue.init)) let closureLifetimeTracker = LifetimeTracked(0) var timesClosureWasCalled = 0 var result = s.lazy.flatMap { (element: OpaqueValue) -> OpaqueValue? in _blackHole(closureLifetimeTracker) timesClosureWasCalled += 1 return test.transform(element.value).map(OpaqueValue.init) } expectEqual(0, timesClosureWasCalled, "unexpected eagerness") let expected = test.expected.map(OpaqueValue.init) expectEqualSequence( expected, result, stackTrace: SourceLocStack().with(test.loc) ) { $0.value == $1.value } expectEqual( test.sequence.count, timesClosureWasCalled, "iterating lazy flatMap() should call closure once per element") } } % end