schwern/test-more — Issue #187: Add/remove/check_for types of watchers in the coordinator
Author: schwern
Created: 2011-11-08 23:04:16+00:00
State: open
Labels: DO IT, Easy, Events, Test-Builder2

There is a problem where someone might want to add the same event watcher or formatter. It's a pain in the butt to make sure that somebody else hasn't already done it.

For example, Test::NoWarnings would be implemented as a module that inserts a watcher. It should do this only once. It could do this by doing it only at compile time, but that's not a great solution. It would be nice if it could ask the TestState "hey, do you already have a Test::NoWarnings::Watcher?"

Another example, a builder might want to enforce linear test numbers or only one plan. This would be best done as watchers and you don't want each builder adding their own. So they'd want to check if it's already there.

Similarly, a builder might want to remove a watcher to disable an effect.

Implement a series of methods in Test::Builder2::EventCoordinator...

* Check if the EC already has a given watcher class (and return the watchers if it does).
* Add a watcher only if there isnt' already one of that class (and return the watchers if it does).
* Add *or replace* the existing watcher of that class (return the replaced watchers).
* Remove all watchers of a given class (return the removed watchers).

The interface should generally take arguments like:

class => class name to look for
watcher => the watcher to add/replace with (if class is not given, use the watcher's class)
object_id => the specific watcher ID to look for (if #162 is done)
which => the watcher slot to look in. Defaults to all_watchers. For example "formatters" or "early_watchers".

For example...

my $tap_formatter = Test::Builder2::Formatter::TAP->new;

# Returns all watchers for which $watcher->isa( ref $tap_formatter ) is true.
my @formatters = $ec->check_for_watcher( watcher => $tap_formatter );

# Return all watcher for which $watcher->isa( "Test::Builder2::Formatter::TAP" is true )
# Note: not necessarily the same as the above, because $tap_formatter is probably a TAP::v13.
my @formatters = $ec->check_for_watcher( class => "Test::Builder2::Formatter::TAP" );

When replacing, only replace the *first* matching watcher. Delete the rest.