/*
This file is part of Ext JS 3.4

Copyright (c) 2011-2013 Sencha Inc

Contact:  http://www.sencha.com/contact

GNU General Public License Usage
This file may be used under the terms of the GNU General Public License version 3.0 as
published by the Free Software Foundation and appearing in the file LICENSE included in the
packaging of this file.

Please review the following information to ensure the GNU General Public License version 3.0
requirements will be met: http://www.gnu.org/copyleft/gpl.html.

If you are unsure which license is appropriate for your use, please contact the sales department
at http://www.sencha.com/contact.

Build date: 2013-04-03 15:07:25
*/
/**
 * Tests Ext.data.Store functionality
 * @author Ed Spencer
 */
(function() {
    var suite  = Ext.test.session.getSuite('Ext.data.Store'),
        assert = Y.Assert;

    //a shared setup function used by several of the suites
    var defaultSetup = function() {
        this.store = new Ext.data.Store({
            proxy : new Ext.data.MemoryProxy({}),
            reader: new Ext.data.ArrayReader({}, [
                {name: 'name',      type: 'string'},
                {name: 'email',     type: 'string'},
                {name: 'greatness', type: 'int'},
                {name: 'group',     type: 'string'},
                {name: 'old',       type: 'boolean'}
            ]),
            storeId: 'myStore',
            remoteSort: false
        });

        this.store.loadData([
            ['Ed Spencer',   'ed@extjs.com',    100, 'code',  false],
            ['Abe Elias',    'abe@extjs.com',   70,  'admin', false],
            ['Aaron Conran', 'aaron@extjs.com', 5,   'admin', true],
            ['Tommy Maintz', 'tommy@extjs.com', -15, 'code',  true]
        ]);
    };

    suite.add(new Y.Test.Case({
        name: 'local single sorting',

        setUp: defaultSetup,

        testSetDefaultSort: function() {
            this.store.setDefaultSort('name', 'DESC');

            var store    = this.store,
                sortInfo = store.sortInfo;

            assert.areEqual('name', sortInfo.field);
            assert.areEqual('DESC', sortInfo.direction);
            assert.areEqual('DESC', store.sortToggle['name']);
        },

        testSetDefaultSortDefaultToASC: function() {
            this.store.setDefaultSort('email');

            var store    = this.store,
                sortInfo = store.sortInfo;

            assert.areEqual('email', sortInfo.field);
            assert.areEqual('ASC', sortInfo['direction']);
            assert.areEqual('ASC', store.sortToggle['email']);
        },

        testSortByField: function() {
            var store = this.store;

            store.sort('name', 'ASC');
            assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(2).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(3).get('name'));
        },

        testToggling: function() {
            var store = this.store;

            store.sort('name', 'ASC');

            //second call to sort toggles the direction
            store.sort('name');

            assert.areEqual('Aaron Conran', store.getAt(3).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(2).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(1).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(0).get('name'));
        },

        testSetsHasMultiSort: function() {
            this.store.sort('name', 'ASC');

            assert.isFalse(this.store.hasMultiSort);
        },

        testEventFired: function() {
            var executed = false,
                store    = this.store;

            store.on('datachanged', function() {
                executed = true;
            }, this);

            store.sort('name');
            assert.isTrue(executed);
        },

        testSavesSortInfo: function() {
            var store = this.store;

            store.sort('name', 'DESC');

            assert.areEqual('name', store.sortInfo.field);
            assert.areEqual('DESC', store.sortInfo.direction);
        },

        //if we tell store to sort on a non-existent field it should return false and do nothing
        testInvalidFieldIgnored: function() {
            var store = this.store;

            //first we'll sort by name to give some reference sorting
            store.sort('name', 'ASC');

            assert.isFalse(store.sort('someUnknownField'));

            //make sure the original sorting was preserved
            assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(2).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(3).get('name'));
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'local multiple sorting',

        setUp: function() {
            defaultSetup.call(this);

            this.sorters = [
                {
                    field    : 'group',
                    direction: 'ASC'
                },
                {
                    field    : 'old',
                    direction: 'DESC'
                }
            ];
        },

        testSetsHasMultiSort: function() {
            this.store.sort(this.sorters);

            assert.isTrue(this.store.hasMultiSort);
        },

        testMultipleSorters: function() {
            var store   = this.store,
                sorters = this.sorters;

            store.sort(sorters);

            assert.areEqual('Aaron Conran', store.getAt(0).get('name'));
            assert.areEqual('Abe Elias',    store.getAt(1).get('name'));
            assert.areEqual('Tommy Maintz', store.getAt(2).get('name'));
            assert.areEqual('Ed Spencer',   store.getAt(3).get('name'));
        }

        // testMultipleSorterToggling: function() {
        //     var store   = this.store,
        //         sorters = this.sorters;
        //
        //     //first we'll sort to give some reference sorting
        //     store.sort(sorters, "ASC");
        //
        //     //second call to sort toggles direction
        //     store.sort(sorters);
        //
        //     assert.areEqual('Aaron Conran', store.getAt(3).get('name'));
        //     assert.areEqual('Abe Elias',    store.getAt(2).get('name'));
        //     assert.areEqual('Tommy Maintz', store.getAt(1).get('name'));
        //     assert.areEqual('Ed Spencer',   store.getAt(0).get('name'));
        // }
    }));

    suite.add(new Y.Test.Case({
        name: 'single filtering',

        setUp: defaultSetup,

        testFilterByField: function() {
            var store = this.store;

            store.filter('group', 'code');
            assert.areEqual(2, store.getCount());
        },

        testFilterByFieldAnyMatch: function() {
            var store = this.store;

            store.filter('email', 'extjs', true);
            assert.areEqual(4, store.getCount());
        },

        testFilterByFieldCaseSensitive: function() {
            var store = this.store;

            store.filter('group', 'Code', false, true);
            assert.areEqual(0, store.getCount());
        },

        testFilterByFieldExactMatch: function() {
            var store = this.store;

            store.filter('email', 'aaron', false, false, true);
            assert.areEqual(0, store.getCount());
        },

        testClearFilter: function() {
            var store    = this.store,
                executed = false;

            store.on('datachanged', function() {
                executed = true;
            }, this);

            store.filter('group', 'code');
            assert.areEqual(2, store.getCount());

            store.clearFilter();
            assert.areEqual(4, store.getCount());

            assert.isTrue(executed);
        },

        testSuppressClearFilterEvent: function() {
            var store    = this.store,
                executed = false;

            store.filter('group', 'email');
            store.clearFilter(true);

            store.on('datachanged', function() {
                executed = true;
            }, this);
            assert.isFalse(executed);
        },

        testIsFiltered: function() {
            var store = this.store;

            assert.isFalse(store.isFiltered());
            store.filter('group', 'code');
            assert.isTrue(store.isFiltered());
        },

        testFilterByFunction: function() {
            var store = this.store,
                execScope,
                executed;

            store.on('datachanged', function() {
                executed = true;
            }, this);

            var filterFn = function(item) {
                execScope = this;

                return item.get('greatness') > 50;
            };

            store.filterBy(filterFn, this);
            assert.areEqual(this, execScope);
            assert.areEqual(2, store.getCount());
            assert.isTrue(executed);
        }
    }));

    suite.add(new Y.Test.Case({
        name : 'filtering more than once',
        setUp: defaultSetup,

        testFirstFilterIsCleared: function() {
            var store = this.store;

            store.filter('group', 'code');
            assert.areEqual(2, store.getCount());

            store.filter('old', false);

            //if filter had not been reset first, count would be 1
            assert.areEqual(2, store.getCount());
        }
    }));

    suite.add(new Y.Test.Case({
        name : 'multiple filters',
        setUp: function() {
            defaultSetup.call(this);

            this.filters = [
                {
                    property: 'group',
                    value   : 'code'
                },
                {
                    property: 'old',
                    value   : true
                }
            ];
        },

        testMultipleBasicFilters: function() {
            this.store.filter(this.filters);

            //applying the filter set above shoule yield one result
            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Tommy Maintz', this.store.data.first().get('name'));
        },

        testMultiFiltersFiresDataChanged: function() {
            var executed = false;

            this.store.on('datachanged', function() {
                executed = true;
            }, this);

            this.store.filter(this.filters);

            assert.isTrue(executed);
        },

        //tests that the anyMatch and caseSensitive defaults are correctly applied
        testMultiFilterDefaults: function() {
            //PENDING
        },

        //tests a single custom filter
        testCustomFilter: function() {
            var execScope;

            //tests that the passed filter function is called
            //tests that the filter is called in the right scope
            this.store.filter({
                fn: function(record) {
                    execScope = this;
                    return record.get('group') == 'admin' && record.get('old') === true;
                },
                scope: this
            });

            assert.areEqual(this, execScope);
            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Aaron Conran', this.store.data.first().get('name'));
        },

        //tests multiple filters where we pass in custom matcher functions
        testMultiCustomFilters: function() {
            this.store.filter([
                {
                    fn: function(record) {
                        return record.get('group') == 'admin';
                    }
                },
                {
                    fn: function(record) {
                        return record.get('old') === false;
                    }
                }
            ]);

            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Abe Elias', this.store.data.first().get('name'));
        },

        testBasicAndCustomFilters: function() {
            //should return a single result - Ed Spencer
            this.store.filter([
                {
                    fn: function(record) {
                        return record.get('old') === false;
                    }
                },
                {
                    property: 'group',
                    value   : 'code'
                }
            ]);

            assert.areEqual(1, this.store.getCount());
            assert.areEqual('Ed Spencer', this.store.data.first().get('name'));
        },

        testClearMultipleFilters: function() {
            this.store.filter(this.filters);
            assert.areEqual(1, this.store.getCount());

            //make sure that clearing multiple filters is still correct
            this.store.clearFilter();
            assert.areEqual(4, this.store.getCount());
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'inserting and removing',

        testInsert: function() {
            //PENDING
        },

        testInsertFiresAddEvent: function() {
            //PENDING
        },

        testRemove: function() {
            //PENDING
        },

        testRemoveAll: function() {
            //PENDING
        },

        testRemoveAt: function() {
            //PENDING
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'destroying',

        setUp: defaultSetup,

        //we hijack Ext.StoreMgr.unregister temporarily and then set it back in this test case
        testUnregistersFromStore: function() {
            var executed   = false,
                arg        = undefined,
                unregister = Ext.StoreMgr.unregister;

            Ext.StoreMgr.unregister = function(store) {
                executed = true;
                arg = store;
            };

            this.store.destroy();

            assert.isTrue(executed);
            assert.areEqual(this.store, arg);

            Ext.StoreMgr.unregister = unregister;
        },

        testClearsData: function() {
            var executed = false;
            this.store.clearData = function() {
                executed = true;
            };

            this.store.destroy();
            assert.isTrue(executed);
        },

        testDestroysProxy: function() {
            var executed = false,
                arg      = undefined,
                proxy    = this.store.proxy,
                destroy  = Ext.destroy;

            Ext.destroy = function(store) {
                executed = true;
                arg = store;
            };

            this.store.destroy();

            assert.isTrue(executed);
            assert.areEqual(proxy, arg);

            Ext.destroy = destroy;
        },

        testUnsetsReferences: function() {
            this.store.destroy();

            assert.isNull(this.store.reader);
            assert.isNull(this.store.writer);
            assert.isNull(this.store.data);
        },

        testIsDestroyed: function() {
            assert.isFalse(this.store.isDestroyed);

            this.store.destroy();

            assert.isTrue(this.store.isDestroyed);
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'counting and iterators',

        setUp: defaultSetup,

        testGetCount: function() {
            assert.areEqual(4, this.store.getCount());
        },

        testGetTotalCount: function() {
            //PENDING - need a fake remote data set test with paging
        },

        testEach: function() {
            var count = 0,
                callScope;

            this.store.each(function() {
                callScope = this;
                count ++;
            }, this);

            assert.areEqual(4, count);
            assert.areEqual(this, callScope);
        },

        testSum: function() {
            var sum = this.store.sum('greatness');

            assert.areEqual(160, sum);
        },

        testSumWithStartAndEnd: function() {
            var sum = this.store.sum('greatness', 1, 3);

            assert.areEqual(60, sum);
        },

        //a normal collect test - check that we're pulling the right values out of the store
        testCollect: function() {
            var values = this.store.collect('name');

            assert.areEqual(4, values.length);
            assert.areNotEqual(-1, values.indexOf("Ed Spencer"));
            assert.areNotEqual(-1, values.indexOf("Abe Elias"));
            assert.areNotEqual(-1, values.indexOf("Aaron Conran"));
            assert.areNotEqual(-1, values.indexOf("Tommy Maintz"));
        },

        //checks that all collected values are unique
        testCollectIsUnique: function() {
            var values = this.store.collect('group');

            assert.areEqual(2, values.length);
            assert.areNotEqual(-1, values.indexOf("code"));
            assert.areNotEqual(-1, values.indexOf("admin"));
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'committing',

        testCommitChanges: function() {
            //PENDING
        },

        testRejectChanges: function() {
            //PENDING
        },

        testAfterCommit: function() {
            //PENDING
        },

        testAfterReject: function() {
            //PENDING
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'modified',

        testGetModifiedRecords: function() {
            //PENDING
        }
    }));

    suite.add(new Y.Test.Case({
        name: 'loading'
    }));
})();
