// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2011 Apple Inc. and contributors. // License: Licensed under MIT license (see license.js) // ========================================================================== /*globals module ok equals same test MyApp */

// NOTE: The test below are based on the Data Hashes state chart. This models // the “write” event in the NestedStore portion of the diagram.

var parent, store, child, storeKey, json; module(“SC.NestedStore#writeDataHash”, {

setup: function() {
  parent = SC.Store.create();

  json = {
    string: "string",
    number: 23,
    bool:   YES
  };

  storeKey = SC.Store.generateStoreKey();

  parent.writeDataHash(storeKey, json, SC.Record.READY_CLEAN);
  parent.editables = null; // manually patch to setup test state

  store = parent.chain(); // create nested store
  child = store.chain();  // test multiple levels deep
}

});

// .….….….….….….….….….….….….….….. // BASIC STATE TRANSITIONS //

// The transition from each base state performs the same operation, so just // run the same test on each state. function testWriteDataHash() {

var oldrev = store.revisions[storeKey];

// perform test
var json2 = { foo: "bar" };
equals(store.writeDataHash(storeKey, json2, SC.Record.READY_NEW), store, 'should return receiver');

// verify
equals(store.storeKeyEditState(storeKey), SC.Store.EDITABLE, 'new edit state should be editable');

equals(store.readDataHash(storeKey), json2, 'should have new json data hash');
equals(store.readStatus(storeKey), SC.Record.READY_NEW, 'should have new status');

equals(store.revisions[storeKey], oldrev, 'should not change revision');
if (!SC.none(oldrev)) {
  ok(store.revisions.hasOwnProperty(storeKey), 'should clone reference to revision');
}

}

test(“edit state=INHERITED”, function() {

// test preconditions
equals(store.storeKeyEditState(storeKey), SC.Store.INHERITED, 'precond - edit state should be inherited');

testWriteDataHash();

});

test(“edit state=LOCKED”, function() {

// test preconditions
store.readDataHash(storeKey);
equals(store.storeKeyEditState(storeKey), SC.Store.LOCKED, 'precond - edit state should be locked');

testWriteDataHash();

});

test(“edit state=EDITABLE”, function() {

// test preconditions
store.readEditableDataHash(storeKey);
equals(store.storeKeyEditState(storeKey), SC.Store.EDITABLE, 'precond - edit state should be editable');

testWriteDataHash();

});

// .….….….….….….….….….….….….….….. // WRITING NEW VS EXISTING //

test(“writing a new hash”, function() {

storeKey = SC.Store.generateStoreKey(); // new store key!
equals(parent.readDataHash(storeKey), null, 'precond - parent should not have a data hash for store key yet');
equals(store.storeKeyEditState(storeKey), SC.Store.INHERITED, 'precond - edit status should be inherited');

// perform write
equals(store.writeDataHash(storeKey, json, SC.Record.READY_NEW), store, 'should return receiver');

// verify change
equals(store.storeKeyEditState(storeKey), SC.Store.EDITABLE, 'new status should be editable');
equals(store.readDataHash(storeKey), json, 'should match new json');
equals(store.readStatus(storeKey), SC.Record.READY_NEW, 'should have new record status');

});

// .….….….….….….….….….….….….….….. // PROPOGATING TO NESTED STORES //

test(“change should propogate to child if child edit state = INHERITED”, function() {

// verify preconditions
equals(child.storeKeyEditState(storeKey), SC.Store.INHERITED, 'precond - child edit state should be INHERITED');

// perform change
var json2 = { version: 2 };
store.writeDataHash(storeKey, json2, SC.Record.READY_NEW);

// verify
same(child.readDataHash(storeKey), json2, 'child should pick up change');
equals(parent.readDataHash(storeKey), json, 'parent should still have old json');

equals(child.readStatus(storeKey), SC.Record.READY_NEW, 'child should pick up new status');
equals(parent.readStatus(storeKey), SC.Record.READY_CLEAN, 'parent should still have old status');

});

function testLockedOrEditableChild() {

// perform change
var json2 = { version: 2 };
store.writeDataHash(storeKey, json2, SC.Record.READY_NEW);

// verify
same(child.readDataHash(storeKey), json, 'child should NOT pick up change');
equals(parent.readDataHash(storeKey), json, 'parent should still have old json');

equals(child.readStatus(storeKey), SC.Record.READY_CLEAN, 'child should pick up new status');
equals(parent.readStatus(storeKey), SC.Record.READY_CLEAN, 'parent should still have old status');

}

test(“change should not propogate to child if child edit state = LOCKED”, function() {

// verify preconditions
child.readDataHash(storeKey);
equals(child.storeKeyEditState(storeKey), SC.Store.LOCKED, 'precond - child edit state should be LOCKED');

testLockedOrEditableChild();

});

test(“change should not propogate to child if child edit state = EDITABLE”, function() {

// verify preconditions
child.readEditableDataHash(storeKey);
equals(child.storeKeyEditState(storeKey), SC.Store.EDITABLE, 'precond - child edit state should be EDITABLE');

testLockedOrEditableChild();

});

test(“writeDataHash on parent records should be propagated to nested children and eventually to the parent store”, function() {

var model = SC.Record.extend( {
              v: SC.Record.attr( String ),
              c: SC.Record.toMany( SC.Record.extend( {
                                     v: SC.Record.attr( String ),
                                   } ),
                                   {
                                     nested: YES
                                   } )
            } );
var json1 = { guid: "p1", v: "p1-1", c: [ { guid: "c1", v: "c1-1" }, { id: "c2", v: "c2-1" } ] };
var json12 = { guid: "p1", v: "p1-2", c: [ { guid: "c1", v: "c1-2" }, { id: "c2", v: "c2-1" } ] };

SC.RunLoop.begin();

// load the data into the main store
var storeKey1 = parent.loadRecord( model, json1 );
var rec1 = parent.find( model, "p1" );

equals( rec1.get( "v" ), "p1-1", "the data loaded into the record should be correct" );
equals( rec1.get( "c" ).objectAt( 0 ).get( "v" ), "c1-1", "the data loaded into the 1st child record should be correct" );
equals( rec1.get( "c" ).objectAt( 1 ).get( "v" ), "c2-1", "the data loaded into the 2nd child record should be correct" );

// start an "editing" session into the nested store store
var rec12 = store.find( rec1 );

equals( rec12.get( "c" ).objectAt( 0 ).get( "v" ), "c1-1", "the data loaded into the 1st child record should be correct" );
equals( rec12.get( "c" ).objectAt( 1 ).get( "v" ), "c2-1", "the data loaded into the 2nd child record should be correct" );

// replace the content and notify the changes
store.writeDataHash( storeKey1, json12, SC.Record.READY_CLEAN );
store.dataHashDidChange( storeKey1 );

SC.RunLoop.end();

SC.RunLoop.begin();
// check if the values from the hash are properly propagated to the record + children
equals( rec12.get( "v" ), "p1-2", "after writeDataHash the data loaded into the record should be updated" );
equals( rec12.get( "c" ).objectAt( 0 ).get( "v" ), "c1-2", "after writeDataHash the data loaded into the 1st child record should be updated" );
equals( rec12.get( "c" ).objectAt( 1 ).get( "v" ), "c2-1", "after writeDataHash the data loaded into the 2nd child record should not be updated" );

// push the changes to the parent store
store.commitChanges(YES);
SC.RunLoop.end();

SC.RunLoop.begin();
// check if the values updated into the nested store are properly propagated to the record + children
equals( rec1.get( "v" ), "p1-2", "after commitChanges the data loaded into the record should be updated" );
equals( rec1.get( "c" ).objectAt( 0 ).get( "v" ), "c1-2", "after commitChanges the data loaded into the 1st child record should be updated" );
equals( rec1.get( "c" ).objectAt( 1 ).get( "v" ), "c2-1", "the data loaded into the 2nd child record should be correct" );
SC.RunLoop.end();

});