diff --git a/docs/src/guide/index.md b/docs/src/guide/index.md index 369ad05144..5bf5c34b37 100644 --- a/docs/src/guide/index.md +++ b/docs/src/guide/index.md @@ -2261,7 +2261,7 @@ The platform understands the following policy categories (specifiable as the * `action`: Determines whether or not a given action is allowable. The candidate argument here is an Action; the context is its action context object. -* `composition`: Determines whether or not domain objects of a given type (first argument, `parentType`) can contain a given object (second argument, `child`). +* `composition`: Determines whether or not a given domain object(first argument, `parent`) can contain a candidate child object (second argument, `child`). * `view`: Determines whether or not a view is applicable for a domain object. The candidate argument is the view's extension definition; the context argument is the `DomainObject` to be viewed. diff --git a/platform/commonUI/edit/test/creation/CreateWizardSpec.js b/platform/commonUI/edit/test/creation/CreateWizardSpec.js index 3973afc945..22ed996e8b 100644 --- a/platform/commonUI/edit/test/creation/CreateWizardSpec.js +++ b/platform/commonUI/edit/test/creation/CreateWizardSpec.js @@ -161,6 +161,7 @@ define( 'otherType', ['getKey'] ), + //Create a form structure with location structure = wizard.getFormStructure(true), sections = structure.sections, @@ -174,7 +175,7 @@ define( // can actually contain objects of this type expect(mockPolicyService.allow).toHaveBeenCalledWith( 'composition', - mockOtherType, + mockDomainObj, mockDomainObject ); }); diff --git a/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js b/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js new file mode 100644 index 0000000000..4615582176 --- /dev/null +++ b/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js @@ -0,0 +1,104 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2016, 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/policies/EditPersistableObjectsPolicy"], + function (EditPersistableObjectsPolicy) { + + describe("The Edit persistable objects policy", function () { + var mockDomainObject, + mockEditAction, + mockPropertiesAction, + mockOtherAction, + mockAPI, + mockObjectAPI, + testContext, + policy; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ + 'getId' + ] + ); + + mockObjectAPI = jasmine.createSpyObj('objectAPI', [ + 'getProvider' + ]); + + mockAPI = { + objects: mockObjectAPI + }; + + mockEditAction = jasmine.createSpyObj('edit', ['getMetadata']); + mockPropertiesAction = jasmine.createSpyObj('properties', ['getMetadata']); + mockOtherAction = jasmine.createSpyObj('other', ['getMetadata']); + + mockEditAction.getMetadata.andReturn({ key: 'edit' }); + mockPropertiesAction.getMetadata.andReturn({ key: 'properties' }); + mockOtherAction.getMetadata.andReturn({key: 'other'}); + + mockDomainObject.getId.andReturn('test:testId'); + + testContext = { + domainObject: mockDomainObject, + category: 'view-control' + }; + + policy = new EditPersistableObjectsPolicy(mockAPI); + }); + + it("Applies to edit action", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + + policy.allow(mockEditAction, testContext); + expect(mockObjectAPI.getProvider).toHaveBeenCalled(); + }); + + it("Applies to properties action", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + + policy.allow(mockPropertiesAction, testContext); + expect(mockObjectAPI.getProvider).toHaveBeenCalled(); + }); + + it("does not apply to other actions", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + + policy.allow(mockOtherAction, testContext); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + }); + + it("Tests object provider for editability", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(policy.allow(mockEditAction, testContext)).toBe(false); + expect(mockObjectAPI.getProvider).toHaveBeenCalled(); + mockObjectAPI.getProvider.andReturn({save: function () {}}); + expect(policy.allow(mockEditAction, testContext)).toBe(true); + }); + }); + } +); diff --git a/platform/containment/src/PersistableCompositionPolicy.js b/platform/containment/src/PersistableCompositionPolicy.js index d30ade8add..0a1b3c9aa9 100644 --- a/platform/containment/src/PersistableCompositionPolicy.js +++ b/platform/containment/src/PersistableCompositionPolicy.js @@ -37,7 +37,6 @@ define( * Only allow changes to composition if the changes can be saved. This in * effect prevents selection of objects from the locator that do not * support persistence. - * * @param parent * @param child * @returns {boolean} diff --git a/platform/containment/test/ComposeActionPolicySpec.js b/platform/containment/test/ComposeActionPolicySpec.js index b1b0aaff80..f3bcf453c7 100644 --- a/platform/containment/test/ComposeActionPolicySpec.js +++ b/platform/containment/test/ComposeActionPolicySpec.js @@ -78,7 +78,7 @@ define( expect(mockPolicyService.allow).toHaveBeenCalledWith( 'composition', - mockTypes[0], + mockDomainObjects[0], mockDomainObjects[1] ); }); diff --git a/platform/containment/test/CompositionModelPolicySpec.js b/platform/containment/test/CompositionModelPolicySpec.js index 2b733434b7..3165312179 100644 --- a/platform/containment/test/CompositionModelPolicySpec.js +++ b/platform/containment/test/CompositionModelPolicySpec.js @@ -4,19 +4,25 @@ define( function (CompositionModelPolicy) { describe("The composition model policy", function () { - var mockType, + var mockObject, + mockType, policy; beforeEach(function () { mockType = jasmine.createSpyObj('type', ['getInitialModel']); + mockObject = { + getCapability: function () { + return mockType; + } + }; policy = new CompositionModelPolicy(); }); it("only allows composition for types which will have a composition property", function () { mockType.getInitialModel.andReturn({}); - expect(policy.allow(mockType)).toBeFalsy(); + expect(policy.allow(mockObject)).toBeFalsy(); mockType.getInitialModel.andReturn({ composition: [] }); - expect(policy.allow(mockType)).toBeTruthy(); + expect(policy.allow(mockObject)).toBeTruthy(); }); }); diff --git a/platform/containment/test/CompositionMutabilityPolicySpec.js b/platform/containment/test/CompositionMutabilityPolicySpec.js index 9f011aedd9..22a38fa2ec 100644 --- a/platform/containment/test/CompositionMutabilityPolicySpec.js +++ b/platform/containment/test/CompositionMutabilityPolicySpec.js @@ -25,18 +25,24 @@ define( function (CompositionMutabilityPolicy) { describe("The composition mutability policy", function () { - var mockType, + var mockObject, + mockType, policy; beforeEach(function () { mockType = jasmine.createSpyObj('type', ['hasFeature']); + mockObject = { + getCapability: function () { + return mockType; + } + }; policy = new CompositionMutabilityPolicy(); }); it("only allows composition for types which can be created/modified", function () { - expect(policy.allow(mockType)).toBeFalsy(); + expect(policy.allow(mockObject)).toBeFalsy(); mockType.hasFeature.andReturn(true); - expect(policy.allow(mockType)).toBeTruthy(); + expect(policy.allow(mockObject)).toBeTruthy(); expect(mockType.hasFeature).toHaveBeenCalledWith('creation'); }); }); diff --git a/platform/containment/test/CompositionPolicySpec.js b/platform/containment/test/CompositionPolicySpec.js index 23261ef5de..e322836469 100644 --- a/platform/containment/test/CompositionPolicySpec.js +++ b/platform/containment/test/CompositionPolicySpec.js @@ -24,13 +24,18 @@ define( ["../src/CompositionPolicy"], function (CompositionPolicy) { describe("Composition policy", function () { - var typeA, + var mockParentObject, + typeA, typeB, typeC, mockChildObject, policy; beforeEach(function () { + mockParentObject = jasmine.createSpyObj('domainObject', [ + 'getCapability' + ]); + typeA = jasmine.createSpyObj( 'type A-- the particular kind', ['getKey', 'getDefinition'] @@ -70,27 +75,31 @@ define( describe('enforces simple containment rules', function () { it('allows when type matches', function () { + mockParentObject.getCapability.andReturn(typeA); + mockChildObject.getCapability.andReturn(typeA); - expect(policy.allow(typeA, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); - expect(policy.allow(typeB, mockChildObject)) + mockParentObject.getCapability.andReturn(typeB); + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); mockChildObject.getCapability.andReturn(typeB); - expect(policy.allow(typeB, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); }); it('disallows when type doesn\'t match', function () { + mockParentObject.getCapability.andReturn(typeA); mockChildObject.getCapability.andReturn(typeB); - expect(policy.allow(typeA, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeFalsy(); mockChildObject.getCapability.andReturn(typeC); - expect(policy.allow(typeA, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeFalsy(); }); @@ -98,8 +107,10 @@ define( describe('enforces capability-based containment rules', function () { it('allows when object has capability', function () { + mockParentObject.getCapability.andReturn(typeC); + mockChildObject.hasCapability.andReturn(true); - expect(policy.allow(typeC, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); expect(mockChildObject.hasCapability) .toHaveBeenCalledWith('telemetry'); @@ -107,7 +118,10 @@ define( it('skips when object doesn\'t have capability', function () { mockChildObject.hasCapability.andReturn(false); - expect(policy.allow(typeC, mockChildObject)) + + mockParentObject.getCapability.andReturn(typeC); + + expect(policy.allow(mockParentObject, mockChildObject)) .toBeFalsy(); expect(mockChildObject.hasCapability) .toHaveBeenCalledWith('telemetry'); diff --git a/platform/containment/test/PersistableCompositionPolicySpec.js b/platform/containment/test/PersistableCompositionPolicySpec.js new file mode 100644 index 0000000000..56c4ce6575 --- /dev/null +++ b/platform/containment/test/PersistableCompositionPolicySpec.js @@ -0,0 +1,85 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2016, 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/PersistableCompositionPolicy"], + function (PersistableCompositionPolicy) { + describe("Persistable Composition policy", function () { + var objectAPI; + var mockOpenMCT; + var persistableCompositionPolicy; + var mockParent; + var mockChild; + var mockEditorCapability; + + beforeEach(function () { + objectAPI = jasmine.createSpyObj('objectsAPI', [ + 'getProvider' + ]); + + mockOpenMCT = { + objects: objectAPI + }; + mockParent = jasmine.createSpyObj('domainObject', [ + 'hasCapability', + 'getCapability', + 'getId' + ]); + mockParent.hasCapability.andReturn(true); + mockParent.getId.andReturn('someNamespace:someId'); + mockChild = {}; + mockEditorCapability = jasmine.createSpyObj('domainObject', [ + 'isEditContextRoot' + ]); + mockParent.getCapability.andReturn(mockEditorCapability); + + objectAPI.getProvider.andReturn({ + save: function () {} + }); + persistableCompositionPolicy = new PersistableCompositionPolicy(mockOpenMCT); + }); + + //Parent + // - getCapability ('editor') + // - isEditContextRoot + // - openMct.objects.getProvider + + it("Does not allow composition for objects that are not persistable", function () { + mockEditorCapability.isEditContextRoot.andReturn(false); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); + objectAPI.getProvider.andReturn({}); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(false); + }); + + it("Always allows composition of objects in edit mode to support object creation", function () { + mockEditorCapability.isEditContextRoot.andReturn(true); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); + expect(objectAPI.getProvider).not.toHaveBeenCalled(); + + mockEditorCapability.isEditContextRoot.andReturn(false); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); + expect(objectAPI.getProvider).toHaveBeenCalled(); + }); + + }); + } +); diff --git a/platform/entanglement/test/services/CopyServiceSpec.js b/platform/entanglement/test/services/CopyServiceSpec.js index bcd25cf825..fde19e185f 100644 --- a/platform/entanglement/test/services/CopyServiceSpec.js +++ b/platform/entanglement/test/services/CopyServiceSpec.js @@ -103,7 +103,7 @@ define( validate(); expect(policyService.allow).toHaveBeenCalledWith( "composition", - parentCandidate.capabilities.type, + parentCandidate, object ); }); diff --git a/platform/entanglement/test/services/LinkServiceSpec.js b/platform/entanglement/test/services/LinkServiceSpec.js index 6dcd9480b8..6bd294c43b 100644 --- a/platform/entanglement/test/services/LinkServiceSpec.js +++ b/platform/entanglement/test/services/LinkServiceSpec.js @@ -113,7 +113,7 @@ define( validate(); expect(mockPolicyService.allow).toHaveBeenCalledWith( "composition", - parentCandidate.capabilities.type, + parentCandidate, object ); }); diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index 687559ee56..80fbdf1867 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -123,7 +123,7 @@ define( validate(); expect(policyService.allow).toHaveBeenCalledWith( "composition", - parentCandidate.capabilities.type, + parentCandidate, object ); }); diff --git a/platform/features/layout/test/LayoutCompositionPolicySpec.js b/platform/features/layout/test/LayoutCompositionPolicySpec.js index 7d7abb2bcd..321e1cced5 100644 --- a/platform/features/layout/test/LayoutCompositionPolicySpec.js +++ b/platform/features/layout/test/LayoutCompositionPolicySpec.js @@ -25,6 +25,7 @@ define( function (LayoutCompositionPolicy) { describe("Layout's composition policy", function () { var mockChild, + mockCandidateObj, mockCandidate, mockContext, candidateType, @@ -41,6 +42,11 @@ define( mockContext = jasmine.createSpyObj('contextType', ['instanceOf']); + mockCandidateObj = jasmine.createSpyObj('domainObj', [ + 'getCapability' + ]); + mockCandidateObj.getCapability.andReturn(mockCandidate); + mockChild.getCapability.andReturn(mockContext); mockCandidate.instanceOf.andCallFake(function (t) { @@ -56,19 +62,19 @@ define( it("disallows folders in layouts", function () { candidateType = 'layout'; contextType = 'folder'; - expect(policy.allow(mockCandidate, mockChild)).toBe(false); + expect(policy.allow(mockCandidateObj, mockChild)).toBe(false); }); it("does not disallow folders elsewhere", function () { candidateType = 'nonlayout'; contextType = 'folder'; - expect(policy.allow(mockCandidate, mockChild)).toBe(true); + expect(policy.allow(mockCandidateObj, mockChild)).toBe(true); }); it("allows things other than folders in layouts", function () { candidateType = 'layout'; contextType = 'nonfolder'; - expect(policy.allow(mockCandidate, mockChild)).toBe(true); + expect(policy.allow(mockCandidateObj, mockChild)).toBe(true); }); });