/***************************************************************************** * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * * Open MCT is licensed under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * * Open MCT includes source code licensed under additional open source * licenses. See the Open Source Licenses file (LICENSES.md) included with * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ define( [ '../../src/services/CopyTask', '../DomainObjectFactory' ], function (CopyTask, domainObjectFactory) { var ID_A = "some-string-with-vaguely-uuidish-uniqueness", ID_B = "some-other-similarly-unique-string"; function synchronousPromise(value) { return (value && value.then) ? value : { then: function (callback) { return synchronousPromise(callback(value)); } }; } describe("CopyTask", function () { var mockDomainObject, mockParentObject, mockFilter, mockQ, mockDeferred, testModel, counter, cloneIds, task; function makeMockCapabilities(childIds) { var mockCapabilities = { persistence: jasmine.createSpyObj( 'persistence', ['persist'] ), composition: jasmine.createSpyObj( 'composition', ['add', 'invoke'] ), instantiation: jasmine.createSpyObj( 'instantiation', ['instantiate', 'invoke'] ) }, mockChildren = (childIds || []).map(function (id) { return domainObjectFactory({ id: id, capabilities: makeMockCapabilities([]), model: { originalId: id } }); }); mockCapabilities.persistence.persist .andReturn(synchronousPromise(true)); mockCapabilities.composition.add.andCallFake(function (obj) { return synchronousPromise(obj); }); mockCapabilities.composition.invoke .andReturn(synchronousPromise(mockChildren)); mockCapabilities.instantiation.invoke .andCallFake(function (model) { var id = "some-id-" + counter; cloneIds[model.originalId] = id; counter += 1; return domainObjectFactory({ id: id, model: model, capabilities: makeMockCapabilities() }); }); return mockCapabilities; } beforeEach(function () { counter = 0; cloneIds = {}; testModel = { composition: [ID_A, ID_B], someObj: {}, someArr: [ID_A, ID_B], objArr: [{"id": ID_A}, {"id": ID_B}], singleElementArr: [ID_A] }; testModel.someObj[ID_A] = "some value"; testModel.someObj.someProperty = ID_B; mockDomainObject = domainObjectFactory({ capabilities: makeMockCapabilities(testModel.composition), model: testModel }); mockParentObject = domainObjectFactory({ capabilities: makeMockCapabilities() }); mockFilter = jasmine.createSpy('filter'); mockQ = jasmine.createSpyObj('$q', ['when', 'defer', 'all']); mockDeferred = jasmine.createSpyObj( 'deferred', ['notify', 'resolve', 'reject'] ); mockFilter.andReturn(true); mockQ.when.andCallFake(synchronousPromise); mockQ.defer.andReturn(mockDeferred); mockQ.all.andCallFake(function (promises) { return synchronousPromise(promises.map(function (promise) { var value; promise.then(function (v) { value = v; }); return value; })); }); mockDeferred.resolve.andCallFake(function (value) { mockDeferred.promise = synchronousPromise(value); }); }); describe("produces models which", function () { var model; beforeEach(function () { task = new CopyTask( mockDomainObject, mockParentObject, mockFilter, mockQ ); task.perform().then(function (clone) { model = clone.getModel(); }); }); it("contain rewritten identifiers in arrays", function () { expect(model.someArr) .toEqual(testModel.someArr.map(function (id) { return cloneIds[id]; })); }); it("contain rewritten identifiers in properties", function () { expect(model.someObj.someProperty) .toEqual(cloneIds[testModel.someObj.someProperty]); }); it("contain rewritten identifiers in property names", function () { expect(model.someObj[cloneIds[ID_A]]) .toEqual(testModel.someObj[ID_A]); }); it("contain rewritten identifiers in single-element arrays", function () { expect(model.singleElementArr) .toEqual(testModel.singleElementArr.map(function (id) { return cloneIds[id]; })); }); }); describe("copies object trees with multiple references to the" + " same object", function () { var mockDomainObjectB, mockComposingObject, composingObjectModel, domainObjectClone, domainObjectBClone; beforeEach(function () { mockDomainObjectB = domainObjectFactory({ capabilities: makeMockCapabilities(testModel.composition), model: testModel }); composingObjectModel = { name: 'mockComposingObject', composition: [mockDomainObject.getId(), mockDomainObjectB.getId()] }; mockComposingObject = domainObjectFactory({ capabilities: makeMockCapabilities(composingObjectModel.composition), model: composingObjectModel }); mockComposingObject.capabilities.composition.invoke.andReturn([mockDomainObject, mockDomainObjectB]); task = new CopyTask( mockComposingObject, mockParentObject, mockFilter, mockQ ); task.perform(); domainObjectClone = task.clones[2]; domainObjectBClone = task.clones[5]; }); /** * mockDomainObject and mockDomainObjectB have the same * model with references to children ID_A and ID_B. Expect * that after duplication the references should differ * because they are each now referencing different child * objects. This tests the issue reported in #428 */ it(" and correctly updates child identifiers in models ", function () { var childA_ID = task.clones[0].getId(), childB_ID = task.clones[1].getId(), childC_ID = task.clones[3].getId(), childD_ID = task.clones[4].getId(); expect(domainObjectClone.model.someArr[0]).toNotBe(domainObjectBClone.model.someArr[0]); expect(domainObjectClone.model.someArr[0]).toBe(childA_ID); expect(domainObjectBClone.model.someArr[0]).toBe(childC_ID); expect(domainObjectClone.model.someArr[1]).toNotBe(domainObjectBClone.model.someArr[1]); expect(domainObjectClone.model.someArr[1]).toBe(childB_ID); expect(domainObjectBClone.model.someArr[1]).toBe(childD_ID); expect(domainObjectClone.model.someObj.someProperty).toNotBe(domainObjectBClone.model.someObj.someProperty); expect(domainObjectClone.model.someObj.someProperty).toBe(childB_ID); expect(domainObjectBClone.model.someObj.someProperty).toBe(childD_ID); }); /** * This a bug found in testathon when testing issue #428 */ it(" and correctly updates child identifiers in object" + " arrays within models ", function () { var childA_ID = task.clones[0].getId(), childB_ID = task.clones[1].getId(); expect(domainObjectClone.model.objArr[0].id).not.toBe(ID_A); expect(domainObjectClone.model.objArr[0].id).toBe(childA_ID); expect(domainObjectClone.model.objArr[1].id).not.toBe(ID_B); expect(domainObjectClone.model.objArr[1].id).toBe(childB_ID); }); }); }); } );