mirror of
https://github.com/nasa/openmct.git
synced 2024-12-19 21:27:52 +00:00
Merge remote-tracking branch 'github-open/open97' into open-master
This commit is contained in:
commit
70bc17c79f
@ -86,37 +86,18 @@ define(
|
|||||||
// composition, so that it will subsequently appear
|
// composition, so that it will subsequently appear
|
||||||
// as a child contained by that parent.
|
// as a child contained by that parent.
|
||||||
function addToComposition(id, parent, parentPersistence) {
|
function addToComposition(id, parent, parentPersistence) {
|
||||||
var mutatationResult = parent.useCapability("mutation", function (model) {
|
var compositionCapability = parent.getCapability('composition'),
|
||||||
if (Array.isArray(model.composition)) {
|
addResult = compositionCapability &&
|
||||||
// Don't add if the id is already there
|
compositionCapability.add(id);
|
||||||
if (model.composition.indexOf(id) === -1) {
|
|
||||||
model.composition.push(id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This is abnormal; composition should be an array
|
|
||||||
self.$log.warn(NO_COMPOSITION_WARNING + parent.getId());
|
|
||||||
return false; // Cancel mutation
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return self.$q.when(mutatationResult).then(function (result) {
|
return self.$q.when(addResult).then(function (result) {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
self.$log.error("Could not mutate " + parent.getId());
|
self.$log.error("Could not modify " + parent.getId());
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parentPersistence.persist().then(function () {
|
return parentPersistence.persist().then(function () {
|
||||||
// Locate and return new Object in context of parent.
|
return result;
|
||||||
return parent
|
|
||||||
.useCapability('composition')
|
|
||||||
.then(function (children) {
|
|
||||||
var i;
|
|
||||||
for (i = 0; i < children.length; i += 1) {
|
|
||||||
if (children[i].getId() === id) {
|
|
||||||
return children[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ define(
|
|||||||
);
|
);
|
||||||
mockCompositionCapability = jasmine.createSpyObj(
|
mockCompositionCapability = jasmine.createSpyObj(
|
||||||
"composition",
|
"composition",
|
||||||
["invoke"]
|
["invoke", "add"]
|
||||||
);
|
);
|
||||||
mockContextCapability = jasmine.createSpyObj(
|
mockContextCapability = jasmine.createSpyObj(
|
||||||
"context",
|
"context",
|
||||||
@ -120,6 +120,7 @@ define(
|
|||||||
mockCompositionCapability.invoke.andReturn(
|
mockCompositionCapability.invoke.andReturn(
|
||||||
mockPromise([mockNewObject])
|
mockPromise([mockNewObject])
|
||||||
);
|
);
|
||||||
|
mockCompositionCapability.add.andReturn(mockPromise(true));
|
||||||
|
|
||||||
creationService = new CreationService(
|
creationService = new CreationService(
|
||||||
mockPersistenceService,
|
mockPersistenceService,
|
||||||
@ -143,33 +144,34 @@ define(
|
|||||||
parentModel = { composition: ["notAnyUUID"] };
|
parentModel = { composition: ["notAnyUUID"] };
|
||||||
creationService.createObject(model, mockParentObject);
|
creationService.createObject(model, mockParentObject);
|
||||||
|
|
||||||
// Invoke the mutation callback
|
// Verify that a new ID was added
|
||||||
expect(mockMutationCapability.invoke).toHaveBeenCalled();
|
expect(mockCompositionCapability.add)
|
||||||
mockMutationCapability.invoke.mostRecentCall.args[0](parentModel);
|
.toHaveBeenCalledWith(jasmine.any(String));
|
||||||
|
|
||||||
// Should have a longer composition now, with the new UUID
|
|
||||||
expect(parentModel.composition.length).toEqual(2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("warns if parent has no composition", function () {
|
it("provides the newly-created object", function () {
|
||||||
var model = { someKey: "some value" },
|
var mockDomainObject = jasmine.createSpyObj(
|
||||||
parentModel = { };
|
'newDomainObject',
|
||||||
creationService.createObject(model, mockParentObject);
|
['getId', 'getModel', 'getCapability']
|
||||||
|
),
|
||||||
|
mockCallback = jasmine.createSpy('callback');
|
||||||
|
|
||||||
// Verify precondition; no prior warnings
|
// Act as if the object had been created
|
||||||
expect(mockLog.warn).not.toHaveBeenCalled();
|
mockCompositionCapability.add.andCallFake(function (id) {
|
||||||
|
mockDomainObject.getId.andReturn(id);
|
||||||
|
mockCompositionCapability.invoke
|
||||||
|
.andReturn(mockPromise([mockDomainObject]));
|
||||||
|
return mockPromise(mockDomainObject);
|
||||||
|
});
|
||||||
|
|
||||||
// Invoke the mutation callback
|
// Should find it in the composition
|
||||||
expect(mockMutationCapability.invoke).toHaveBeenCalled();
|
creationService.createObject({}, mockParentObject)
|
||||||
mockMutationCapability.invoke.mostRecentCall.args[0](parentModel);
|
.then(mockCallback);
|
||||||
|
|
||||||
|
expect(mockCallback).toHaveBeenCalledWith(mockDomainObject);
|
||||||
|
|
||||||
// Should have a longer composition now, with the new UUID
|
|
||||||
expect(mockLog.warn).toHaveBeenCalled();
|
|
||||||
// Composition should still be undefined
|
|
||||||
expect(parentModel.composition).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("warns if parent has no persistence capability", function () {
|
it("warns if parent has no persistence capability", function () {
|
||||||
// Callbacks
|
// Callbacks
|
||||||
var success = jasmine.createSpy("success"),
|
var success = jasmine.createSpy("success"),
|
||||||
@ -185,7 +187,6 @@ define(
|
|||||||
expect(mockLog.warn).toHaveBeenCalled();
|
expect(mockLog.warn).toHaveBeenCalled();
|
||||||
expect(success).not.toHaveBeenCalled();
|
expect(success).not.toHaveBeenCalled();
|
||||||
expect(failure).toHaveBeenCalled();
|
expect(failure).toHaveBeenCalled();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("logs an error when mutaton fails", function () {
|
it("logs an error when mutaton fails", function () {
|
||||||
@ -194,7 +195,7 @@ define(
|
|||||||
var model = { someKey: "some value" },
|
var model = { someKey: "some value" },
|
||||||
parentModel = { composition: ["notAnyUUID"] };
|
parentModel = { composition: ["notAnyUUID"] };
|
||||||
|
|
||||||
mockMutationCapability.invoke.andReturn(mockPromise(false));
|
mockCompositionCapability.add.andReturn(mockPromise(false));
|
||||||
|
|
||||||
creationService.createObject(model, mockParentObject);
|
creationService.createObject(model, mockParentObject);
|
||||||
|
|
||||||
|
@ -36,20 +36,11 @@ define(
|
|||||||
function LinkAction(context) {
|
function LinkAction(context) {
|
||||||
this.domainObject = (context || {}).domainObject;
|
this.domainObject = (context || {}).domainObject;
|
||||||
this.selectedObject = (context || {}).selectedObject;
|
this.selectedObject = (context || {}).selectedObject;
|
||||||
this.selectedId = this.selectedObject && this.selectedObject.getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkAction.prototype.perform = function () {
|
LinkAction.prototype.perform = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Add this domain object's identifier
|
|
||||||
function addId(model) {
|
|
||||||
if (Array.isArray(model.composition) &&
|
|
||||||
model.composition.indexOf(self.selectedId) < 0) {
|
|
||||||
model.composition.push(self.selectedId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Persist changes to the domain object
|
// Persist changes to the domain object
|
||||||
function doPersist() {
|
function doPersist() {
|
||||||
var persistence =
|
var persistence =
|
||||||
@ -59,11 +50,13 @@ define(
|
|||||||
|
|
||||||
// Link these objects
|
// Link these objects
|
||||||
function doLink() {
|
function doLink() {
|
||||||
return self.domainObject.useCapability("mutation", addId)
|
var composition = self.domainObject &&
|
||||||
.then(doPersist);
|
self.domainObject.getCapability('composition');
|
||||||
|
return composition && composition.add(self.selectedObject)
|
||||||
|
.then(doPersist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.selectedId && doLink();
|
return this.selectedObject && doLink();
|
||||||
};
|
};
|
||||||
|
|
||||||
return LinkAction;
|
return LinkAction;
|
||||||
|
@ -54,6 +54,9 @@ define(
|
|||||||
var row = Object.create(property.getDefinition());
|
var row = Object.create(property.getDefinition());
|
||||||
row.key = index;
|
row.key = index;
|
||||||
return row;
|
return row;
|
||||||
|
}).filter(function (row) {
|
||||||
|
// Only show properties which are editable
|
||||||
|
return row.control;
|
||||||
})
|
})
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
@ -31,7 +31,7 @@ define(
|
|||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockParent,
|
mockParent,
|
||||||
mockContext,
|
mockContext,
|
||||||
mockMutation,
|
mockComposition,
|
||||||
mockPersistence,
|
mockPersistence,
|
||||||
mockType,
|
mockType,
|
||||||
actionContext,
|
actionContext,
|
||||||
@ -67,7 +67,7 @@ define(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
mockContext = jasmine.createSpyObj("context", [ "getParent" ]);
|
mockContext = jasmine.createSpyObj("context", [ "getParent" ]);
|
||||||
mockMutation = jasmine.createSpyObj("mutation", [ "invoke" ]);
|
mockComposition = jasmine.createSpyObj("composition", [ "invoke", "add" ]);
|
||||||
mockPersistence = jasmine.createSpyObj("persistence", [ "persist" ]);
|
mockPersistence = jasmine.createSpyObj("persistence", [ "persist" ]);
|
||||||
mockType = jasmine.createSpyObj("type", [ "hasFeature" ]);
|
mockType = jasmine.createSpyObj("type", [ "hasFeature" ]);
|
||||||
|
|
||||||
@ -75,11 +75,11 @@ define(
|
|||||||
mockDomainObject.getCapability.andReturn(mockContext);
|
mockDomainObject.getCapability.andReturn(mockContext);
|
||||||
mockContext.getParent.andReturn(mockParent);
|
mockContext.getParent.andReturn(mockParent);
|
||||||
mockType.hasFeature.andReturn(true);
|
mockType.hasFeature.andReturn(true);
|
||||||
mockMutation.invoke.andReturn(mockPromise(true));
|
mockComposition.invoke.andReturn(mockPromise(true));
|
||||||
|
mockComposition.add.andReturn(mockPromise(true));
|
||||||
|
|
||||||
capabilities = {
|
capabilities = {
|
||||||
mutation: mockMutation,
|
composition: mockComposition,
|
||||||
persistence: mockPersistence,
|
persistence: mockPersistence,
|
||||||
type: mockType
|
type: mockType
|
||||||
};
|
};
|
||||||
@ -96,33 +96,17 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("mutates the parent when performed", function () {
|
it("adds to the parent's composition when performed", function () {
|
||||||
action.perform();
|
action.perform();
|
||||||
expect(mockMutation.invoke)
|
expect(mockComposition.add)
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
.toHaveBeenCalledWith(mockDomainObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("changes composition from its mutation function", function () {
|
it("persists changes afterward", function () {
|
||||||
var mutator, result;
|
|
||||||
action.perform();
|
action.perform();
|
||||||
mutator = mockMutation.invoke.mostRecentCall.args[0];
|
|
||||||
result = mutator(model);
|
|
||||||
|
|
||||||
// Should not have cancelled the mutation
|
|
||||||
expect(result).not.toBe(false);
|
|
||||||
|
|
||||||
// Simulate mutate's behavior (remove can either return a
|
|
||||||
// new model or modify this one in-place)
|
|
||||||
result = result || model;
|
|
||||||
|
|
||||||
// Should have removed "test" - that was our
|
|
||||||
// mock domain object's id.
|
|
||||||
expect(result.composition).toEqual(["a", "b", "c", "test"]);
|
|
||||||
|
|
||||||
// Finally, should have persisted
|
|
||||||
expect(mockPersistence.persist).toHaveBeenCalled();
|
expect(mockPersistence.persist).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -39,7 +39,7 @@ define(
|
|||||||
return {
|
return {
|
||||||
getValue: function (model) { return model[k]; },
|
getValue: function (model) { return model[k]; },
|
||||||
setValue: function (model, v) { model[k] = v; },
|
setValue: function (model, v) { model[k] = v; },
|
||||||
getDefinition: function () { return {}; }
|
getDefinition: function () { return { control: 'textfield '}; }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -63,7 +63,12 @@
|
|||||||
"provides": "modelService",
|
"provides": "modelService",
|
||||||
"type": "provider",
|
"type": "provider",
|
||||||
"implementation": "models/PersistedModelProvider.js",
|
"implementation": "models/PersistedModelProvider.js",
|
||||||
"depends": [ "persistenceService", "$q", "PERSISTENCE_SPACE" ]
|
"depends": [
|
||||||
|
"persistenceService",
|
||||||
|
"$q",
|
||||||
|
"PERSISTENCE_SPACE",
|
||||||
|
"ADDITIONAL_PERSISTENCE_SPACES"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"provides": "modelService",
|
"provides": "modelService",
|
||||||
@ -218,6 +223,17 @@
|
|||||||
"composition": []
|
"composition": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"constants": [
|
||||||
|
{
|
||||||
|
"key": "PERSISTENCE_SPACE",
|
||||||
|
"value": "mct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "ADDITIONAL_PERSISTENCE_SPACES",
|
||||||
|
"value": [],
|
||||||
|
"description": "An array of additional persistence spaces to load models from."
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,66 @@ define(
|
|||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a domain object to the composition of the field.
|
||||||
|
* This mutates but does not persist the modified object.
|
||||||
|
*
|
||||||
|
* If no index is given, this is added to the end of the composition.
|
||||||
|
*
|
||||||
|
* @param {DomainObject|string} domainObject the domain object to add,
|
||||||
|
* or simply its identifier
|
||||||
|
* @param {number} [index] the index at which to add the object
|
||||||
|
* @returns {Promise.<DomainObject>} a promise for the added object
|
||||||
|
* in its new context
|
||||||
|
*/
|
||||||
|
CompositionCapability.prototype.add = function (domainObject, index) {
|
||||||
|
var self = this,
|
||||||
|
id = typeof domainObject === 'string' ?
|
||||||
|
domainObject : domainObject.getId(),
|
||||||
|
model = self.domainObject.getModel(),
|
||||||
|
composition = model.composition,
|
||||||
|
oldIndex = composition.indexOf(id);
|
||||||
|
|
||||||
|
// Find the object with the above id, used to contextualize
|
||||||
|
function findObject(objects) {
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < objects.length; i += 1) {
|
||||||
|
if (objects[i].getId() === id) {
|
||||||
|
return objects[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function contextualize(mutationResult) {
|
||||||
|
return mutationResult && self.invoke().then(findObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addIdToModel(model) {
|
||||||
|
// Pick a specific index if needed.
|
||||||
|
index = isNaN(index) ? composition.length : index;
|
||||||
|
// Also, don't put past the end of the array
|
||||||
|
index = Math.min(composition.length, index);
|
||||||
|
|
||||||
|
// Remove the existing instance of the id
|
||||||
|
if (oldIndex !== -1) {
|
||||||
|
model.composition.splice(oldIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...and add it back at the appropriate index.
|
||||||
|
model.composition.splice(index, 0, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no index has been specified already and the id is already
|
||||||
|
// present, nothing to do. If the id is already at that index,
|
||||||
|
// also nothing to do, so cancel mutation.
|
||||||
|
if ((isNaN(index) && oldIndex !== -1) || (index === oldIndex)) {
|
||||||
|
return contextualize(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.domainObject.useCapability('mutation', addIdToModel)
|
||||||
|
.then(contextualize);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request the composition of this object.
|
* Request the composition of this object.
|
||||||
* @returns {Promise.<DomainObject[]>} a list of all domain
|
* @returns {Promise.<DomainObject[]>} a list of all domain
|
||||||
|
@ -39,23 +39,37 @@ define(
|
|||||||
* @param {PersistenceService} persistenceService the service in which
|
* @param {PersistenceService} persistenceService the service in which
|
||||||
* domain object models are persisted.
|
* domain object models are persisted.
|
||||||
* @param $q Angular's $q service, for working with promises
|
* @param $q Angular's $q service, for working with promises
|
||||||
* @param {string} SPACE the name of the persistence space from which
|
* @param {string} space the name of the persistence space(s)
|
||||||
* models should be retrieved.
|
* from which models should be retrieved.
|
||||||
|
* @param {string} spaces additional persistence spaces to use
|
||||||
*/
|
*/
|
||||||
function PersistedModelProvider(persistenceService, $q, space) {
|
function PersistedModelProvider(persistenceService, $q, space, spaces) {
|
||||||
this.persistenceService = persistenceService;
|
this.persistenceService = persistenceService;
|
||||||
this.$q = $q;
|
this.$q = $q;
|
||||||
this.space = space;
|
this.spaces = [space].concat(spaces || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take the most recently modified model, for cases where
|
||||||
|
// multiple persistence spaces return models.
|
||||||
|
function takeMostRecent(modelA, modelB) {
|
||||||
|
return (!modelB || modelB.modified === undefined) ? modelA :
|
||||||
|
(!modelA || modelA.modified === undefined) ? modelB :
|
||||||
|
modelB.modified > modelA.modified ? modelB :
|
||||||
|
modelA;
|
||||||
}
|
}
|
||||||
|
|
||||||
PersistedModelProvider.prototype.getModels = function (ids) {
|
PersistedModelProvider.prototype.getModels = function (ids) {
|
||||||
var persistenceService = this.persistenceService,
|
var persistenceService = this.persistenceService,
|
||||||
$q = this.$q,
|
$q = this.$q,
|
||||||
space = this.space;
|
spaces = this.spaces;
|
||||||
|
|
||||||
// Load a single object model from persistence
|
// Load a single object model from any persistence spaces
|
||||||
function loadModel(id) {
|
function loadModel(id) {
|
||||||
return persistenceService.readObject(space, id);
|
return $q.all(spaces.map(function (space) {
|
||||||
|
return persistenceService.readObject(space, id);
|
||||||
|
})).then(function (models) {
|
||||||
|
return models.reduce(takeMostRecent);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Package the result as id->model
|
// Package the result as id->model
|
||||||
|
@ -51,7 +51,7 @@ define(
|
|||||||
// so support that, but don't introduce complication of
|
// so support that, but don't introduce complication of
|
||||||
// native promises.
|
// native promises.
|
||||||
function mockPromise(value) {
|
function mockPromise(value) {
|
||||||
return {
|
return (value || {}).then ? value : {
|
||||||
then: function (callback) {
|
then: function (callback) {
|
||||||
return mockPromise(callback(value));
|
return mockPromise(callback(value));
|
||||||
}
|
}
|
||||||
@ -123,6 +123,98 @@ define(
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("allows domain objects to be added", function () {
|
||||||
|
var result,
|
||||||
|
testModel = { composition: [] },
|
||||||
|
mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS);
|
||||||
|
|
||||||
|
mockDomainObject.getModel.andReturn(testModel);
|
||||||
|
mockObjectService.getObjects.andReturn(mockPromise({a: mockChild}));
|
||||||
|
mockChild.getCapability.andReturn(undefined);
|
||||||
|
mockChild.getId.andReturn('a');
|
||||||
|
|
||||||
|
mockDomainObject.useCapability.andCallFake(function (key, mutator) {
|
||||||
|
if (key === 'mutation') {
|
||||||
|
mutator(testModel);
|
||||||
|
return mockPromise(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
composition.add(mockChild).then(function (domainObject) {
|
||||||
|
result = domainObject;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(testModel.composition).toEqual(['a']);
|
||||||
|
|
||||||
|
// Should have returned the added object in its new context
|
||||||
|
expect(result.getId()).toEqual('a');
|
||||||
|
expect(result.getCapability('context')).toBeDefined();
|
||||||
|
expect(result.getCapability('context').getParent())
|
||||||
|
.toEqual(mockDomainObject);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not re-add IDs which are already present", function () {
|
||||||
|
var result,
|
||||||
|
testModel = { composition: [ 'a' ] },
|
||||||
|
mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS);
|
||||||
|
|
||||||
|
mockDomainObject.getModel.andReturn(testModel);
|
||||||
|
mockObjectService.getObjects.andReturn(mockPromise({a: mockChild}));
|
||||||
|
mockChild.getCapability.andReturn(undefined);
|
||||||
|
mockChild.getId.andReturn('a');
|
||||||
|
|
||||||
|
mockDomainObject.useCapability.andCallFake(function (key, mutator) {
|
||||||
|
if (key === 'mutation') {
|
||||||
|
mutator(testModel);
|
||||||
|
return mockPromise(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
composition.add(mockChild).then(function (domainObject) {
|
||||||
|
result = domainObject;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Still just 'a'
|
||||||
|
expect(testModel.composition).toEqual(['a']);
|
||||||
|
|
||||||
|
// Should have returned the added object in its new context
|
||||||
|
expect(result.getId()).toEqual('a');
|
||||||
|
expect(result.getCapability('context')).toBeDefined();
|
||||||
|
expect(result.getCapability('context').getParent())
|
||||||
|
.toEqual(mockDomainObject);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can add objects at a specified index", function () {
|
||||||
|
var result,
|
||||||
|
testModel = { composition: [ 'a', 'b', 'c' ] },
|
||||||
|
mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS);
|
||||||
|
|
||||||
|
mockDomainObject.getModel.andReturn(testModel);
|
||||||
|
mockObjectService.getObjects.andReturn(mockPromise({a: mockChild}));
|
||||||
|
mockChild.getCapability.andReturn(undefined);
|
||||||
|
mockChild.getId.andReturn('a');
|
||||||
|
|
||||||
|
mockDomainObject.useCapability.andCallFake(function (key, mutator) {
|
||||||
|
if (key === 'mutation') {
|
||||||
|
mutator(testModel);
|
||||||
|
return mockPromise(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
composition.add(mockChild, 1).then(function (domainObject) {
|
||||||
|
result = domainObject;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Still just 'a'
|
||||||
|
expect(testModel.composition).toEqual(['b', 'a', 'c']);
|
||||||
|
|
||||||
|
// Should have returned the added object in its new context
|
||||||
|
expect(result.getId()).toEqual('a');
|
||||||
|
expect(result.getCapability('context')).toBeDefined();
|
||||||
|
expect(result.getCapability('context').getParent())
|
||||||
|
.toEqual(mockDomainObject);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -32,7 +32,9 @@ define(
|
|||||||
describe("The persisted model provider", function () {
|
describe("The persisted model provider", function () {
|
||||||
var mockQ,
|
var mockQ,
|
||||||
mockPersistenceService,
|
mockPersistenceService,
|
||||||
SPACE = "some space",
|
SPACE = "space0",
|
||||||
|
spaces = [ "space1" ],
|
||||||
|
modTimes,
|
||||||
provider;
|
provider;
|
||||||
|
|
||||||
function mockPromise(value) {
|
function mockPromise(value) {
|
||||||
@ -51,12 +53,14 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
modTimes = {};
|
||||||
mockQ = { when: mockPromise, all: mockAll };
|
mockQ = { when: mockPromise, all: mockAll };
|
||||||
mockPersistenceService = {
|
mockPersistenceService = {
|
||||||
readObject: function (space, id) {
|
readObject: function (space, id) {
|
||||||
return mockPromise({
|
return mockPromise({
|
||||||
space: space,
|
space: space,
|
||||||
id: id
|
id: id,
|
||||||
|
modified: (modTimes[space] || {})[id]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -64,7 +68,8 @@ define(
|
|||||||
provider = new PersistedModelProvider(
|
provider = new PersistedModelProvider(
|
||||||
mockPersistenceService,
|
mockPersistenceService,
|
||||||
mockQ,
|
mockQ,
|
||||||
SPACE
|
SPACE,
|
||||||
|
spaces
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,6 +87,24 @@ define(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("reads object models from multiple spaces", function () {
|
||||||
|
var models;
|
||||||
|
|
||||||
|
modTimes.space1 = {
|
||||||
|
'x': 12321
|
||||||
|
};
|
||||||
|
|
||||||
|
provider.getModels(["a", "x", "zz"]).then(function (m) {
|
||||||
|
models = m;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(models).toEqual({
|
||||||
|
a: { space: SPACE, id: "a" },
|
||||||
|
x: { space: 'space1', id: "x", modified: 12321 },
|
||||||
|
zz: { space: SPACE, id: "zz" }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -32,7 +32,8 @@ define(
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Change the composition of the specified objects.
|
* Change the composition of the specified objects. Note that this
|
||||||
|
* should only be invoked after successfully validating.
|
||||||
*
|
*
|
||||||
* @param {DomainObject} domainObject the domain object to
|
* @param {DomainObject} domainObject the domain object to
|
||||||
* move, copy, or link.
|
* move, copy, or link.
|
||||||
@ -43,7 +44,8 @@ define(
|
|||||||
* @method platform/entanglement.AbstractComposeService#perform
|
* @method platform/entanglement.AbstractComposeService#perform
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Check if one object can be composed into another.
|
* Check if this composition change is valid for these objects.
|
||||||
|
*
|
||||||
* @param {DomainObject} domainObject the domain object to
|
* @param {DomainObject} domainObject the domain object to
|
||||||
* move, copy, or link.
|
* move, copy, or link.
|
||||||
* @param {DomainObject} parent the domain object whose composition
|
* @param {DomainObject} parent the domain object whose composition
|
||||||
|
@ -64,6 +64,12 @@ define(
|
|||||||
return self.perform(domainObject, parent);
|
return self.perform(domainObject, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.validate(domainObject, parent)) {
|
||||||
|
throw new Error(
|
||||||
|
"Tried to copy objects without validating first."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (domainObject.hasCapability('composition')) {
|
if (domainObject.hasCapability('composition')) {
|
||||||
model.composition = [];
|
model.composition = [];
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,9 @@ define(
|
|||||||
if (parentCandidate.getId() === object.getId()) {
|
if (parentCandidate.getId() === object.getId()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!parentCandidate.hasCapability('composition')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -56,26 +59,18 @@ define(
|
|||||||
};
|
};
|
||||||
|
|
||||||
LinkService.prototype.perform = function (object, parentObject) {
|
LinkService.prototype.perform = function (object, parentObject) {
|
||||||
function findChild(children) {
|
if (!this.validate(object, parentObject)) {
|
||||||
var i;
|
throw new Error(
|
||||||
for (i = 0; i < children.length; i += 1) {
|
"Tried to link objects without validating first."
|
||||||
if (children[i].getId() === object.getId()) {
|
);
|
||||||
return children[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parentObject.useCapability('mutation', function (model) {
|
return parentObject.getCapability('composition').add(object)
|
||||||
if (model.composition.indexOf(object.getId()) === -1) {
|
.then(function (objectInNewContext) {
|
||||||
model.composition.push(object.getId());
|
return parentObject.getCapability('persistence')
|
||||||
}
|
.persist()
|
||||||
}).then(function () {
|
.then(function () { return objectInNewContext; });
|
||||||
return parentObject.getCapability('persistence').persist();
|
});
|
||||||
}).then(function getObjectWithNewContext() {
|
|
||||||
return parentObject
|
|
||||||
.useCapability('composition')
|
|
||||||
.then(findChild);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return LinkService;
|
return LinkService;
|
||||||
|
@ -82,6 +82,12 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.validate(object, parentObject)) {
|
||||||
|
throw new Error(
|
||||||
|
"Tried to move objects without validating first."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return this.linkService
|
return this.linkService
|
||||||
.perform(object, parentObject)
|
.perform(object, parentObject)
|
||||||
.then(relocate)
|
.then(relocate)
|
||||||
|
@ -41,19 +41,23 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("CopyService", function () {
|
describe("CopyService", function () {
|
||||||
|
var policyService;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
policyService = jasmine.createSpyObj(
|
||||||
|
'policyService',
|
||||||
|
['allow']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe("validate", function () {
|
describe("validate", function () {
|
||||||
|
|
||||||
var policyService,
|
var copyService,
|
||||||
copyService,
|
|
||||||
object,
|
object,
|
||||||
parentCandidate,
|
parentCandidate,
|
||||||
validate;
|
validate;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
policyService = jasmine.createSpyObj(
|
|
||||||
'policyService',
|
|
||||||
['allow']
|
|
||||||
);
|
|
||||||
copyService = new CopyService(
|
copyService = new CopyService(
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
@ -126,6 +130,16 @@ define(
|
|||||||
copyResult,
|
copyResult,
|
||||||
copyFinished;
|
copyFinished;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
creationService = jasmine.createSpyObj(
|
||||||
|
'creationService',
|
||||||
|
['createObject']
|
||||||
|
);
|
||||||
|
createObjectPromise = synchronousPromise(undefined);
|
||||||
|
creationService.createObject.andReturn(createObjectPromise);
|
||||||
|
policyService.allow.andReturn(true);
|
||||||
|
});
|
||||||
|
|
||||||
describe("on domain object without composition", function () {
|
describe("on domain object without composition", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
object = domainObjectFactory({
|
object = domainObjectFactory({
|
||||||
@ -142,13 +156,7 @@ define(
|
|||||||
composition: []
|
composition: []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
creationService = jasmine.createSpyObj(
|
copyService = new CopyService(null, creationService, policyService);
|
||||||
'creationService',
|
|
||||||
['createObject']
|
|
||||||
);
|
|
||||||
createObjectPromise = synchronousPromise(undefined);
|
|
||||||
creationService.createObject.andReturn(createObjectPromise);
|
|
||||||
copyService = new CopyService(null, creationService);
|
|
||||||
copyResult = copyService.perform(object, newParent);
|
copyResult = copyService.perform(object, newParent);
|
||||||
copyFinished = jasmine.createSpy('copyFinished');
|
copyFinished = jasmine.createSpy('copyFinished');
|
||||||
copyResult.then(copyFinished);
|
copyResult.then(copyFinished);
|
||||||
@ -180,7 +188,8 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("on domainObject with composition", function () {
|
describe("on domainObject with composition", function () {
|
||||||
var childObject,
|
var newObject,
|
||||||
|
childObject,
|
||||||
compositionCapability,
|
compositionCapability,
|
||||||
compositionPromise;
|
compositionPromise;
|
||||||
|
|
||||||
@ -216,6 +225,17 @@ define(
|
|||||||
composition: compositionCapability
|
composition: compositionCapability
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
newObject = domainObjectFactory({
|
||||||
|
name: 'object',
|
||||||
|
id: 'abc2',
|
||||||
|
model: {
|
||||||
|
name: 'some object',
|
||||||
|
composition: []
|
||||||
|
},
|
||||||
|
capabilities: {
|
||||||
|
composition: compositionCapability
|
||||||
|
}
|
||||||
|
});
|
||||||
newParent = domainObjectFactory({
|
newParent = domainObjectFactory({
|
||||||
name: 'newParent',
|
name: 'newParent',
|
||||||
id: '456',
|
id: '456',
|
||||||
@ -223,13 +243,10 @@ define(
|
|||||||
composition: []
|
composition: []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
creationService = jasmine.createSpyObj(
|
|
||||||
'creationService',
|
createObjectPromise = synchronousPromise(newObject);
|
||||||
['createObject']
|
|
||||||
);
|
|
||||||
createObjectPromise = synchronousPromise(undefined);
|
|
||||||
creationService.createObject.andReturn(createObjectPromise);
|
creationService.createObject.andReturn(createObjectPromise);
|
||||||
copyService = new CopyService(mockQ, creationService);
|
copyService = new CopyService(mockQ, creationService, policyService);
|
||||||
copyResult = copyService.perform(object, newParent);
|
copyResult = copyService.perform(object, newParent);
|
||||||
copyFinished = jasmine.createSpy('copyFinished');
|
copyFinished = jasmine.createSpy('copyFinished');
|
||||||
copyResult.then(copyFinished);
|
copyResult.then(copyFinished);
|
||||||
@ -266,6 +283,38 @@ define(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("on invalid inputs", function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
object = domainObjectFactory({
|
||||||
|
name: 'object',
|
||||||
|
capabilities: {
|
||||||
|
type: { type: 'object' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
newParent = domainObjectFactory({
|
||||||
|
name: 'parentCandidate',
|
||||||
|
capabilities: {
|
||||||
|
type: { type: 'parentCandidate' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws an error", function () {
|
||||||
|
var copyService =
|
||||||
|
new CopyService(mockQ, creationService, policyService);
|
||||||
|
|
||||||
|
function perform() {
|
||||||
|
copyService.perform(object, newParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
spyOn(copyService, "validate");
|
||||||
|
copyService.validate.andReturn(true);
|
||||||
|
expect(perform).not.toThrow();
|
||||||
|
copyService.validate.andReturn(false);
|
||||||
|
expect(perform).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*global define,describe,beforeEach,it,jasmine,expect */
|
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
|
||||||
|
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
@ -41,6 +41,7 @@ define(
|
|||||||
'policyService',
|
'policyService',
|
||||||
['allow']
|
['allow']
|
||||||
);
|
);
|
||||||
|
mockPolicyService.allow.andReturn(true);
|
||||||
linkService = new LinkService(mockPolicyService);
|
linkService = new LinkService(mockPolicyService);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -55,7 +56,13 @@ define(
|
|||||||
name: 'object'
|
name: 'object'
|
||||||
});
|
});
|
||||||
parentCandidate = domainObjectFactory({
|
parentCandidate = domainObjectFactory({
|
||||||
name: 'parentCandidate'
|
name: 'parentCandidate',
|
||||||
|
capabilities: {
|
||||||
|
composition: jasmine.createSpyObj(
|
||||||
|
'composition',
|
||||||
|
['invoke', 'add']
|
||||||
|
)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
validate = function () {
|
validate = function () {
|
||||||
return linkService.validate(object, parentCandidate);
|
return linkService.validate(object, parentCandidate);
|
||||||
@ -81,6 +88,18 @@ define(
|
|||||||
expect(validate()).toBe(false);
|
expect(validate()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not allow parents without composition", function () {
|
||||||
|
parentCandidate = domainObjectFactory({
|
||||||
|
name: 'parentCandidate'
|
||||||
|
});
|
||||||
|
object.id = 'abc';
|
||||||
|
parentCandidate.id = 'xyz';
|
||||||
|
parentCandidate.hasCapability.andCallFake(function (c) {
|
||||||
|
return c !== 'composition';
|
||||||
|
});
|
||||||
|
expect(validate()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
describe("defers to policyService", function () {
|
describe("defers to policyService", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
object.id = 'abc';
|
object.id = 'abc';
|
||||||
@ -121,16 +140,16 @@ define(
|
|||||||
linkedObject,
|
linkedObject,
|
||||||
parentModel,
|
parentModel,
|
||||||
parentObject,
|
parentObject,
|
||||||
mutationPromise,
|
|
||||||
compositionPromise,
|
compositionPromise,
|
||||||
persistencePromise,
|
persistencePromise,
|
||||||
|
addPromise,
|
||||||
compositionCapability,
|
compositionCapability,
|
||||||
persistenceCapability;
|
persistenceCapability;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mutationPromise = new ControlledPromise();
|
|
||||||
compositionPromise = new ControlledPromise();
|
compositionPromise = new ControlledPromise();
|
||||||
persistencePromise = new ControlledPromise();
|
persistencePromise = new ControlledPromise();
|
||||||
|
addPromise = new ControlledPromise();
|
||||||
persistenceCapability = jasmine.createSpyObj(
|
persistenceCapability = jasmine.createSpyObj(
|
||||||
'persistenceCapability',
|
'persistenceCapability',
|
||||||
['persist']
|
['persist']
|
||||||
@ -138,9 +157,10 @@ define(
|
|||||||
persistenceCapability.persist.andReturn(persistencePromise);
|
persistenceCapability.persist.andReturn(persistencePromise);
|
||||||
compositionCapability = jasmine.createSpyObj(
|
compositionCapability = jasmine.createSpyObj(
|
||||||
'compositionCapability',
|
'compositionCapability',
|
||||||
['invoke']
|
['invoke', 'add']
|
||||||
);
|
);
|
||||||
compositionCapability.invoke.andReturn(compositionPromise);
|
compositionCapability.invoke.andReturn(compositionPromise);
|
||||||
|
compositionCapability.add.andReturn(addPromise);
|
||||||
parentModel = {
|
parentModel = {
|
||||||
composition: []
|
composition: []
|
||||||
};
|
};
|
||||||
@ -151,7 +171,7 @@ define(
|
|||||||
mutation: {
|
mutation: {
|
||||||
invoke: function (mutator) {
|
invoke: function (mutator) {
|
||||||
mutator(parentModel);
|
mutator(parentModel);
|
||||||
return mutationPromise;
|
return new ControlledPromise();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
persistence: persistenceCapability,
|
persistence: persistenceCapability,
|
||||||
@ -172,20 +192,17 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("modifies parent model composition", function () {
|
it("adds to the parent's composition", function () {
|
||||||
expect(parentModel.composition.length).toBe(0);
|
expect(compositionCapability.add).not.toHaveBeenCalled();
|
||||||
linkService.perform(object, parentObject);
|
linkService.perform(object, parentObject);
|
||||||
expect(parentObject.useCapability).toHaveBeenCalledWith(
|
expect(compositionCapability.add)
|
||||||
'mutation',
|
.toHaveBeenCalledWith(object);
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
expect(parentModel.composition).toContain('xyz');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("persists parent", function () {
|
it("persists parent", function () {
|
||||||
linkService.perform(object, parentObject);
|
linkService.perform(object, parentObject);
|
||||||
expect(mutationPromise.then).toHaveBeenCalled();
|
expect(addPromise.then).toHaveBeenCalled();
|
||||||
mutationPromise.resolve();
|
addPromise.resolve(linkedObject);
|
||||||
expect(parentObject.getCapability)
|
expect(parentObject.getCapability)
|
||||||
.toHaveBeenCalledWith('persistence');
|
.toHaveBeenCalledWith('persistence');
|
||||||
expect(persistenceCapability.persist).toHaveBeenCalled();
|
expect(persistenceCapability.persist).toHaveBeenCalled();
|
||||||
@ -197,11 +214,23 @@ define(
|
|||||||
whenComplete = jasmine.createSpy('whenComplete');
|
whenComplete = jasmine.createSpy('whenComplete');
|
||||||
returnPromise.then(whenComplete);
|
returnPromise.then(whenComplete);
|
||||||
|
|
||||||
mutationPromise.resolve();
|
addPromise.resolve(linkedObject);
|
||||||
persistencePromise.resolve();
|
persistencePromise.resolve();
|
||||||
compositionPromise.resolve([linkedObject]);
|
compositionPromise.resolve([linkedObject]);
|
||||||
expect(whenComplete).toHaveBeenCalledWith(linkedObject);
|
expect(whenComplete).toHaveBeenCalledWith(linkedObject);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throws an error when performed on invalid inputs", function () {
|
||||||
|
function perform() {
|
||||||
|
linkService.perform(object, parentObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
spyOn(linkService, 'validate');
|
||||||
|
linkService.validate.andReturn(true);
|
||||||
|
expect(perform).not.toThrow();
|
||||||
|
linkService.validate.andReturn(false);
|
||||||
|
expect(perform).toThrow();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/*global define,describe,beforeEach,it,jasmine,expect */
|
/*global define,describe,beforeEach,it,jasmine,expect,spyOn */
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'../../src/services/MoveService',
|
'../../src/services/MoveService',
|
||||||
@ -40,58 +40,57 @@ define(
|
|||||||
|
|
||||||
var moveService,
|
var moveService,
|
||||||
policyService,
|
policyService,
|
||||||
|
object,
|
||||||
|
objectContextCapability,
|
||||||
|
currentParent,
|
||||||
|
parentCandidate,
|
||||||
linkService;
|
linkService;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
objectContextCapability = jasmine.createSpyObj(
|
||||||
|
'objectContextCapability',
|
||||||
|
[
|
||||||
|
'getParent'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
object = domainObjectFactory({
|
||||||
|
name: 'object',
|
||||||
|
id: 'a',
|
||||||
|
capabilities: {
|
||||||
|
context: objectContextCapability,
|
||||||
|
type: { type: 'object' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
currentParent = domainObjectFactory({
|
||||||
|
name: 'currentParent',
|
||||||
|
id: 'b'
|
||||||
|
});
|
||||||
|
|
||||||
|
objectContextCapability.getParent.andReturn(currentParent);
|
||||||
|
|
||||||
|
parentCandidate = domainObjectFactory({
|
||||||
|
name: 'parentCandidate',
|
||||||
|
model: { composition: [] },
|
||||||
|
id: 'c',
|
||||||
|
capabilities: {
|
||||||
|
type: { type: 'parentCandidate' }
|
||||||
|
}
|
||||||
|
});
|
||||||
policyService = jasmine.createSpyObj(
|
policyService = jasmine.createSpyObj(
|
||||||
'policyService',
|
'policyService',
|
||||||
['allow']
|
['allow']
|
||||||
);
|
);
|
||||||
linkService = new MockLinkService();
|
linkService = new MockLinkService();
|
||||||
|
policyService.allow.andReturn(true);
|
||||||
moveService = new MoveService(policyService, linkService);
|
moveService = new MoveService(policyService, linkService);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("validate", function () {
|
describe("validate", function () {
|
||||||
var object,
|
var validate;
|
||||||
objectContextCapability,
|
|
||||||
currentParent,
|
|
||||||
parentCandidate,
|
|
||||||
validate;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
|
||||||
objectContextCapability = jasmine.createSpyObj(
|
|
||||||
'objectContextCapability',
|
|
||||||
[
|
|
||||||
'getParent'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
object = domainObjectFactory({
|
|
||||||
name: 'object',
|
|
||||||
id: 'a',
|
|
||||||
capabilities: {
|
|
||||||
context: objectContextCapability,
|
|
||||||
type: { type: 'object' }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
currentParent = domainObjectFactory({
|
|
||||||
name: 'currentParent',
|
|
||||||
id: 'b'
|
|
||||||
});
|
|
||||||
|
|
||||||
objectContextCapability.getParent.andReturn(currentParent);
|
|
||||||
|
|
||||||
parentCandidate = domainObjectFactory({
|
|
||||||
name: 'parentCandidate',
|
|
||||||
model: { composition: [] },
|
|
||||||
id: 'c',
|
|
||||||
capabilities: {
|
|
||||||
type: { type: 'parentCandidate' }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
validate = function () {
|
validate = function () {
|
||||||
return moveService.validate(object, parentCandidate);
|
return moveService.validate(object, parentCandidate);
|
||||||
};
|
};
|
||||||
@ -145,14 +144,15 @@ define(
|
|||||||
|
|
||||||
describe("perform", function () {
|
describe("perform", function () {
|
||||||
|
|
||||||
var object,
|
var actionCapability,
|
||||||
newParent,
|
|
||||||
actionCapability,
|
|
||||||
locationCapability,
|
locationCapability,
|
||||||
locationPromise,
|
locationPromise,
|
||||||
|
newParent,
|
||||||
moveResult;
|
moveResult;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
newParent = parentCandidate;
|
||||||
|
|
||||||
actionCapability = jasmine.createSpyObj(
|
actionCapability = jasmine.createSpyObj(
|
||||||
'actionCapability',
|
'actionCapability',
|
||||||
['perform']
|
['perform']
|
||||||
@ -175,7 +175,9 @@ define(
|
|||||||
name: 'object',
|
name: 'object',
|
||||||
capabilities: {
|
capabilities: {
|
||||||
action: actionCapability,
|
action: actionCapability,
|
||||||
location: locationCapability
|
location: locationCapability,
|
||||||
|
context: objectContextCapability,
|
||||||
|
type: { type: 'object' }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -194,6 +196,18 @@ define(
|
|||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("throws an error when performed on invalid inputs", function () {
|
||||||
|
function perform() {
|
||||||
|
moveService.perform(object, newParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
spyOn(moveService, "validate");
|
||||||
|
moveService.validate.andReturn(true);
|
||||||
|
expect(perform).not.toThrow();
|
||||||
|
moveService.validate.andReturn(false);
|
||||||
|
expect(perform).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
describe("when moving an original", function () {
|
describe("when moving an original", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
locationCapability.getContextualLocation
|
locationCapability.getContextualLocation
|
||||||
|
Loading…
Reference in New Issue
Block a user