// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // Portions ©2008-2011 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ==========================================================================

/*globals module test ok equals same people */

var object ;

module(“object.registerDependentKeys()”, {

setup: function() {
  object = SC.Object.create({

      // normal properties
      firstName:  'John',
      lastName:   'Doe',
      observedValue: '',

      // computed property
      fullName: function() {
        return this.getEach('firstName','lastName').compact().join(' ');
      }.property(),

      // init to setup registerDependentKey...
      init: function() {
        sc_super();
        this.registerDependentKey('fullName', 'firstName', 'lastName');
      },

      //observer that should fire whenever the 'fullName' property changes
      fullNameDidChange:  function() {
        this.set('observedValue', this.get('fullName')) ;
      }.observes('fullName')
  });
}

});

test(“should indicate the registered property changes if the dependent key value changes”, function() {

// now, change the firstName...
object.set('firstName', 'Jane');

// since fullName is 'dependent' on firstName, then the observer for  
// 'fullName' should fire here because you changed a dependent key.
equals(object.get('observedValue'), 'Jane Doe');

// now change the lastName
object.set('lastName', 'Johnson');

// again, fullName is 'dependent' on lastName, so observer for  
// fullName should fire.
equals(object.get('observedValue'), 'Jane Johnson');

});

test(“should indicate the registered property changes if the dependent key value changes and change is within begin property loop ”, function() {

// Wrap the changes with begin property changes call
object.beginPropertyChanges();

// now, change the firstName & lastname...
object.set('firstName', 'Jane');
object.set('lastName', 'Johnson');

// The observer for fullName should not have fired yet at this  
// point because we are inside a propertyChange loop.
equals(object.get('observedValue'), '');

//End the property changes loop.
object.endPropertyChanges();

// now change the lastName
object.set('lastName', 'Johnson');

// again, fullName is 'dependent' on lastName, so observer for  
// fullName should fire.
equals(object.get('observedValue'), 'Jane Johnson');

});

module(“object.registerDependentKeys() - @each”);

test(“should invalidate computed property once per changed key”, function() {

var setCalls = 0;
var getCalls = 0;

window.people = SC.Object.create({
  content: [SC.Object.create({name:'Juan'}),
            SC.Object.create({name:'Camilo'}),
            SC.Object.create({name:'Pinzon'})],

  fullName: function(key, value) {
    if (value !== undefined) {
      setCalls++;
      this.content.setEach('name', value);
    } else {
      getCalls++;
    }

    return this.content.getEach('name').join(' ');
  }.property('content.@each.name')
});

var peopleWatcher = SC.Object.create({
  nameBinding: 'window.people.fullName'
});

SC.run(function() { people.set('fullName', 'foo bar baz'); });
equals(setCalls, 1, "calls set once");
equals(getCalls, 3, "calls get three times");

});

test(“should invalidate key when properties higher up in the chain change”, function() {

var notified = 0;

var obj = SC.Object.create({
  contact: null,

  fullName: function(key, value) {
    return [this.getPath('contact.firstName'), this.getPath('contact.lastName')].join(' ');
  }.property('contact.firstName', 'contact.lastName').cacheable(),

  fullNameDidChange: function() {
    notified++;
  }.observes('fullName')
});

var johnDoe = SC.Object.create({ firstName: 'John', lastName: 'Doe' });
var janeDoe = SC.Object.create({ firstName: 'Jane', lastName: 'Doe' });

equals(notified, 0, 'should start empty');
SC.run(function() {  obj.set('contact', johnDoe);  });
equals(notified, 1, 'should notify once after set content=johnDoe');
equals(obj.get('fullName'), 'John Doe', 'should get proper name');

notified = 0;
SC.run(function() { johnDoe.set('firstName', 'JOHNNY'); });
equals(notified, 1, 'should notify again after set firstName=JOHNNY');
equals(obj.get('fullName'), 'JOHNNY Doe', 'should get proper name');

notified = 0;
SC.run(function() { obj.set('contact', janeDoe); });
equals(notified, 1, 'should notify again after set content=janeDoe');
equals(obj.get('fullName'), 'Jane Doe', 'should get proper name');

notified = 0;
SC.run(function() { johnDoe.set('firstName', 'JON'); });
equals(notified, 0, 'should NOT notify again after set johnDoe.firstName=JON (johnDoe is not current contact)');
equals(obj.get('fullName'), 'Jane Doe', 'should get proper name while janeDoe is current');

notified = 0;
SC.run(function() { janeDoe.set('firstName', 'Janna'); });
equals(notified, 1, 'should notify again after set janeDoe.firstName=Janna');
equals(obj.get('fullName'), 'Janna Doe', 'should get proper name after firstname=Janna');

});