// ========================================================================== // 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 */

// test core array-mapping methods for RecordArray var store, storeKey, json, rec, storeKey2, json2, rec2, storeKeys, recs; module(“SC.RecordArray core methods”, {

setup: function() {
  // setup dummy store
  store = SC.Store.create();

  storeKey = SC.Record.storeKeyFor('foo');
  json = { guid: "foo", foo: "bar" };
  store.writeDataHash(storeKey, json, SC.Record.READY_CLEAN);

  storeKey2 = SC.Record.storeKeyFor('baz');
  json2 = { guid: "baz", baz: "bash" };
  store.writeDataHash(storeKey2, json2, SC.Record.READY_CLEAN);

  // get records
  rec = store.materializeRecord(storeKey);
  equals(rec.get('foo'), 'bar', 'precond - record should have json');
  rec2 = store.materializeRecord(storeKey2);
  equals(rec2.get('baz'), 'bash', 'precond - record 2 should have json');

  // get record array.
  storeKeys = [storeKey, storeKey2];
  recs = SC.RecordArray.create({ store: store, storeKeys: storeKeys });
}

});

test(“initial status”, function() {

equals(recs.get('status'), SC.Record.EMPTY, 'status should be SC.Record.EMPTY');

});

// .….….….….….….….….….….….….….….. // LENGTH //

test(“should pass through length”, function() {

equals(recs.get('length'), storeKeys.length, 'rec should pass through length');

});

test(“changing storeKeys length should change length of rec array also”, function() {

var oldlen = recs.get('length');

storeKeys.pushObject(SC.Store.generateStoreKey()); // change length

ok(storeKeys.length > oldlen, 'precond - storeKeys.length should have changed');
equals(recs.get('length'), storeKeys.length, 'rec should pass through length');

});

// .….….….….….….….….….….….….….….. // objectAt //

test(“should materialize record for object”, function() {

equals(storeKeys[0], storeKey, 'precond - storeKeys[0] should be storeKey');
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');

});

test(“reading past end of array length should return undefined”, function() {

equals(recs.objectAt(2000), undefined, 'recs.objectAt(2000) should be undefined');

});

test(“modifying the underlying storeKey should change the returned materialized record”, function() {

// read record once to make it materialized
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');

// create a new record.
SC.RunLoop.begin();
var rec3 = store.createRecord(SC.Record, { foo: "rec3" });
SC.RunLoop.end();

var storeKey3 = rec3.get('storeKey');

// add to beginning of storeKey array
storeKeys.unshiftObject(storeKey3);
equals(recs.get('length'), 3, 'should now have length of 3');
equals(recs.objectAt(0), rec3, 'objectAt(0) should return new record');
equals(recs.objectAt(1), rec, 'objectAt(1) should return old record 1');
equals(recs.objectAt(2), rec2, 'objectAt(2) should return old record 2');

});

test(“reading a record not loaded in store should trigger retrieveRecord”, function() {

var callCount = 0;

// patch up store to record a call and to make it look like data is not
// loaded.
store.removeDataHash(storeKey, SC.Record.EMPTY);
store.retrieveRecord = function() { callCount++; };

equals(store.peekStatus(storeKeys.objectAt(0)), SC.Record.EMPTY, 'precond - storeKey must not be loaded');

var rec = recs.objectAt(0);
equals(callCount, 1, 'store.retrieveRecord() should have been called');

});

// .….….….….….….….….….….….….….….. // replace() //

test(“adding a record to the record array should pass through storeKeys”, function() {

// read record once to make it materialized
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');

// create a new record.
SC.RunLoop.begin();
var rec3 = store.createRecord(SC.Record, { foo: "rec3" });
SC.RunLoop.end();

var storeKey3 = rec3.get('storeKey');

// add record to beginning of record array
recs.unshiftObject(rec3);

// verify record array
equals(recs.get('length'), 3, 'should now have length of 3');
equals(recs.objectAt(0), rec3, 'recs.objectAt(0) should return new record');
equals(recs.objectAt(1), rec, 'recs.objectAt(1) should return old record 1');
equals(recs.objectAt(2), rec2, 'recs.objectAt(2) should return old record 2');

// verify storeKeys
equals(storeKeys.objectAt(0), storeKey3, 'storeKeys[0] should return new storeKey');
equals(storeKeys.objectAt(1), storeKey, 'storeKeys[1] should return old storeKey 1');
equals(storeKeys.objectAt(2), storeKey2, 'storeKeys[2] should return old storeKey 2');

});

// .….….….….….….….….….….….….….….. // Property Observing //

test(“changing the underlying storeKeys should notify observers of records”, function() {

// setup observer
var obj = SC.Object.create({
  cnt: 0,
  observer: function() { this.cnt++; }
});
recs.addObserver('[]', obj, obj.observer);

// now modify storeKeys
storeKeys.pushObject(SC.Store.generateStoreKey());
equals(obj.cnt, 1, 'observer should have fired after changing storeKeys');

});

test(“swapping storeKey array should change recordArray and observers”, function() {

// setup alternate storeKeys
SC.RunLoop.begin();
var rec2 = store.createRecord(SC.Record, { foo: "rec2" });
SC.RunLoop.end();

var storeKey2 = rec2.get('storeKey');
var storeKeys2 = [storeKey2];

// setup observer
var obj = SC.Object.create({
  cnt: 0,
  observer: function() { this.cnt++; }
});
recs.addObserver('[]', obj, obj.observer);

// read record once to make it materialized
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should materialize record');

// now swap storeKeys
obj.cnt = 0 ;
recs.set('storeKeys', storeKeys2);

// verify observer fired and record changed
equals(obj.cnt, 1, 'observer should have fired after swap');
equals(recs.objectAt(0), rec2, 'recs.objectAt(0) should return new rec');

// modify storeKey2, make sure observer fires and content changes
obj.cnt = 0;
storeKeys2.unshiftObject(storeKey);
equals(obj.cnt, 1, 'observer should have fired after edit');
equals(recs.get('length'), 2, 'should reflect new length');
equals(recs.objectAt(0), rec, 'recs.objectAt(0) should return pushed rec');

});

test(“find works with query”, function(){

var filtered = recs.find(SC.Query.create({ conditions: "foo = 'bar'" }));

equals(filtered.get('length'), 1);
equals(filtered.objectAt(0), rec);

});

test(“find works as enumerable”, function(){

var filtered = recs.find(function(r){ return r.get('foo') === 'bar'; });
equals(filtered, rec);

});