describe Wisper::GlobalListeners do
  let(:global_listener)  { double('listener') }
  let(:local_listener)   { double('listener') }
  let(:publisher)        { publisher_class.new }

  describe '.subscribe' do
    it 'adds given listener to every publisher' do
      Wisper::GlobalListeners.subscribe(global_listener)
      expect(global_listener).to receive(:it_happened)
      publisher.send(:broadcast, :it_happened)
    end

    it 'works with options' do
      Wisper::GlobalListeners.subscribe(global_listener, :on => :it_happened,
                                                   :with => :woot)
      expect(global_listener).to receive(:woot).once
      expect(global_listener).not_to receive(:it_happened_again)
      publisher.send(:broadcast, :it_happened)
      publisher.send(:broadcast, :it_happened_again)
    end

    it 'works along side local listeners' do
      # global listener
      Wisper::GlobalListeners.subscribe(global_listener)

      # local listener
      publisher.subscribe(local_listener)

      expect(global_listener).to receive(:it_happened)
      expect(local_listener).to receive(:it_happened)

      publisher.send(:broadcast, :it_happened)
    end

    it 'can be scoped to classes' do
      publisher_1 = publisher_class.new
      publisher_2 = publisher_class.new
      publisher_3 = publisher_class.new

      Wisper::GlobalListeners.subscribe(global_listener, :scope => [publisher_1.class,
                                                              publisher_2.class])

      expect(global_listener).to receive(:it_happened_1).once
      expect(global_listener).to receive(:it_happened_2).once
      expect(global_listener).not_to receive(:it_happened_3)

      publisher_1.send(:broadcast, :it_happened_1)
      publisher_2.send(:broadcast, :it_happened_2)
      publisher_3.send(:broadcast, :it_happened_3)
    end

    it 'is threadsafe' do
      num_threads = 100
      (1..num_threads).to_a.map do
        Thread.new do
          Wisper::GlobalListeners.subscribe(Object.new)
          sleep(rand) # a little chaos
        end
      end.each(&:join)

      expect(Wisper::GlobalListeners.listeners.size).to eq num_threads
    end
  end

  describe '.listeners' do
    it 'returns collection of global listeners' do
      Wisper::GlobalListeners.subscribe(global_listener)
      expect(Wisper::GlobalListeners.listeners).to eq [global_listener]
    end

    it 'returns an immutable collection' do
      expect(Wisper::GlobalListeners.listeners).to be_frozen
      expect { Wisper::GlobalListeners.listeners << global_listener }.to raise_error(RuntimeError)
    end
  end

  it '.clear clears all global listeners' do
    Wisper::GlobalListeners.subscribe(global_listener)
    Wisper::GlobalListeners.clear
    expect(Wisper::GlobalListeners.listeners).to be_empty
  end
end