I am writing tests for a generator function that walks a tree. The next function accepts a boolean to determine if it should continue to explore that branch of the tree.
I would like to be able to test it as follows:
let tree_walker = make_tree_walking_generator(some_arguments)
let result = tree_walker.next()
test(result.value, "0", "Test it returns root element")
// I assume this is not possible yet / ever?
let tree_walker_clone = clone_generator_and_state(tree_walker) // <--
result = tree_walker.next(true) // true === first element was consumed (i.e. it was all that was needed)
test(result.value, undefined, "Test it returns undefined if last element was consumed")
test(result.done, true) // should be finished
// Restore the original state captured in the clone
tree_walker = tree_walker_clone
result = tree_walker.next(false) // false === first element was not consumed
test(result.value, "0->1", "Test it returns the next element if the last element was not consumed")
test(result.done, false) // should not be finished
This is important because otherwise you have to call the generator again with all the same arguments, e.g.:
// get the same starting generator again
tree_walker = make_tree_walking_generator(some_arguments)
// Bring it back up to the same penultimate position (n-1)
result = tree_walker.next()
// Continue testing from this point. The problem is the previous
// call is made twice and for a deep tree this might be many 10s of
// calls with complex arguments.
result = tree_walker.next(false) // false === first element was not consumed
test(result.value, "0->1", "Test it returns the next element if the last element was not consumed")
test(result.done, false) // should not be finished
An alternatively to some cloning function would be the ability to rewind a generator. A second alternative is to write a wrapper that records all of the arguments and (assuming the generator is pure) can replay the last n-1 arguments to get a generator in the previous state.