test-hierarchical-addressing.js 6.99 KB
'use strict';

var PubSub = global.PubSub || require('../src/pubsub'),
    TestHelper = global.TestHelper || require('../test/helper'),
    assert = require('referee').assert,
    sinon = require('sinon');

describe( 'Hierarchical addressing', function () {
    beforeEach(function(){
        this.clock = sinon.useFakeTimers();
    });

    afterEach(function(){
        this.clock.restore();
    });

    it('publish method should not call any children in a namespace', function( done ) {
        var messages = ['library', 'library.music'],
            spy = sinon.spy(),
            data = TestHelper.getUniqueString();


        PubSub.subscribe( messages[0], spy ); //This should be called
        PubSub.subscribe( messages[1], spy );
        PubSub.publish( messages[0], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 1 );

        done();
    });

    it('publish method should call a parent namespace', function( done ) {
        // Publishing library.music should trigger parent library
        var messages = ['library', 'library.music'],
            spy = sinon.spy(),
            data = TestHelper.getUniqueString();


        PubSub.subscribe( messages[0], spy ); //This should be called
        PubSub.subscribe( messages[1], spy ); //This should be called
        PubSub.publish( messages[1], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 2 );

        done();
    });

    it('publish method should call only a parent namespace', function( done ) {
        //Publishing library.music should only trigger parents descendants
        //Even if it has a child
        var messages = ['library', 'library.music', 'library.music.jazz'],
            spy = sinon.spy(),
            data = TestHelper.getUniqueString();


        PubSub.subscribe( messages[0], spy ); //This should be called
        PubSub.subscribe( messages[1], spy ); //This should be called
        PubSub.subscribe( messages[2], spy );
        PubSub.publish( messages[1], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 2 );

        done();
    });

    it('publish method should call all parent namespaces', function( done ) {
        //Publishing library.music.jazz should trigger all parents
        var messages = ['library', 'library.music', 'library.music.jazz'],
            spy = sinon.spy(),
            data = TestHelper.getUniqueString();


        PubSub.subscribe( messages[0], spy ); //This should be called
        PubSub.subscribe( messages[1], spy ); //This should be called
        PubSub.subscribe( messages[2], spy ); //This should be called
        PubSub.publish( messages[2], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 3 );

        done();
    });

    it('publish method should call only parent descendants', function( done ) {
        //Publishing library.music.jazz should trigger only all parents descendants
        //Skipping library.playlist and library.playlist.*
        var messages = [
                'library',
                'library.music',
                'library.music.jazz',
                'library.playlist',
                'library.playlist.mine'
            ],
            spy = sinon.spy(),
            data = TestHelper.getUniqueString();

        PubSub.subscribe( messages[0], spy ); //This should be called
        PubSub.subscribe( messages[1], spy ); //This should be called
        PubSub.subscribe( messages[2], spy ); //This should be called
        PubSub.subscribe( messages[3], spy );
        PubSub.subscribe( messages[4], spy );
        PubSub.publish( messages[2], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 3 );

        done();
    });

    it('publish method should call all parent descendants deeply', function( done ) {
        //Publishing library.music.jazz.soft.swing should trigger all but
        //library.music.playlist.jazz
        var messages = [
                'library',
                'library.music',
                'library.music.jazz',
                'library.music.jazz.soft',
                'library.music.jazz.soft.swing',
                'library.music.playlist.jazz'
            ],
            spy = sinon.spy(),
            data = TestHelper.getUniqueString();


        PubSub.subscribe( messages[0], spy ); //This should be called
        PubSub.subscribe( messages[1], spy ); //This should be called
        PubSub.subscribe( messages[2], spy ); //This should be called
        PubSub.subscribe( messages[3], spy ); //This should be called
        PubSub.subscribe( messages[4], spy ); //This should be called
        PubSub.subscribe( messages[5], spy ); //This should be called
        PubSub.subscribe( messages[6], spy );
        PubSub.publish( messages[4], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 5 );

        done();
    });

    it('publish method should still call all parents, even when middle child is unsubscribed', function( done ) {
        var messages = ['library', 'library.music', 'library.music.jazz'],
            spy = sinon.spy(),
            data = TestHelper.getUniqueString(),
            token;


        PubSub.subscribe( messages[0], spy ); //This should be called
        PubSub.subscribe( messages[2], spy ); //This should be called

        token = PubSub.subscribe( messages[1], spy );

        PubSub.unsubscribe( token ); //Take out middle child

        PubSub.publish( messages[2], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 2 );

        done();
    });

    it('unsubscribe method should return tokens when succesfully removing namespaced message', function(){
        var func = function(){ return undefined; },
            messages = ['playlist.music', 'playlist.music.jazz'],
            token1 = PubSub.subscribe( messages[0], func),
            token2 = PubSub.subscribe( messages[1], func ),
            result1 = PubSub.unsubscribe( token1 ),
            result2 = PubSub.unsubscribe( token2 );

        assert.equals( result1, token1 );
        assert.equals( result2, token2 );
    });

    it('unsubscribe method should unsubscribe parent without affecting orphans', function( done ){
        var data = TestHelper.getUniqueString(),
            spy = sinon.spy(),
            messages = ['playlist', 'playlist.music', 'playlist.music.jazz'],
            token;

        token = PubSub.subscribe( messages[0], spy ); //Gets unsubscribed
        PubSub.subscribe( messages[1], spy ); //This should be called
        PubSub.subscribe( messages[2], spy ); //This should be called

        PubSub.unsubscribe( token );

        PubSub.publish( messages[2], data );

        assert.equals( spy.callCount, 0 );
        this.clock.tick(1);
        assert.equals( spy.callCount, 2 );

        done();
    });
});