diff --git a/platform/commonUI/edit/src/creation/AddActionProvider.js b/platform/commonUI/edit/src/creation/AddActionProvider.js index 21666680d3..08b512ca55 100644 --- a/platform/commonUI/edit/src/creation/AddActionProvider.js +++ b/platform/commonUI/edit/src/creation/AddActionProvider.js @@ -54,8 +54,7 @@ define( AddActionProvider.prototype.getActions = function (actionContext) { var context = actionContext || {}, key = context.key, - destination = context.domainObject, - self = this; + destination = context.domainObject; // We only provide Add actions, and we need a // domain object to serve as the container for the @@ -66,16 +65,16 @@ define( } // Introduce one create action per type - ['timeline', 'activity'].map(function (type) { + return ['timeline', 'activity'].map(function (type) { return new AddAction( - type, + this.typeService.getType(type), destination, context, - self.$q, - self.dialogService, - self.policyService + this.$q, + this.dialogService, + this.policyService ); - }); + }, this); }; return AddActionProvider; diff --git a/platform/commonUI/edit/test/creation/AddActionProviderSpec.js b/platform/commonUI/edit/test/creation/AddActionProviderSpec.js index 560b2bd0f7..57493562e5 100644 --- a/platform/commonUI/edit/test/creation/AddActionProviderSpec.js +++ b/platform/commonUI/edit/test/creation/AddActionProviderSpec.js @@ -31,9 +31,7 @@ define( var mockTypeService, mockDialogService, mockPolicyService, - mockCreationPolicy, - mockCompositionPolicy, - mockPolicyMap = {}, + mockTypeMap, mockTypes, mockDomainObject, mockQ, @@ -55,49 +53,33 @@ define( ); mockType.hasFeature.andReturn(true); mockType.getName.andReturn(name); + mockType.getKey.andReturn(name); return mockType; } beforeEach(function () { mockTypeService = jasmine.createSpyObj( "typeService", - ["listTypes"] - ); - mockDialogService = jasmine.createSpyObj( - "dialogService", - ["getUserInput"] - ); - mockPolicyService = jasmine.createSpyObj( - "policyService", - ["allow"] + ["getType"] ); + mockDialogService = {}; + mockPolicyService = {}; + mockDomainObject = {}; - mockDomainObject = jasmine.createSpyObj( - "domainObject", - ["getCapability"] - ); - - //Mocking getCapability because AddActionProvider uses the - // type capability of the destination object. - mockDomainObject.getCapability.andReturn({}); - - mockTypes = ["A", "B", "C"].map(createMockType); + mockTypes = [ + "timeline", + "activity", + "other" + ].map(createMockType); + mockTypeMap = {}; mockTypes.forEach(function (type) { - mockPolicyMap[type.getName()] = true; + mockTypeMap[type.getKey()] = type; }); - mockCreationPolicy = function (type) { - return mockPolicyMap[type.getName()]; - }; - - mockCompositionPolicy = function () { - return true; - }; - - mockPolicyService.allow.andReturn(true); - - mockTypeService.listTypes.andReturn(mockTypes); + mockTypeService.getType.andCallFake(function (key) { + return mockTypeMap[key]; + }); provider = new AddActionProvider( mockQ, @@ -107,29 +89,16 @@ define( ); }); - it("checks for creatability", function () { - provider.getActions({ + it("provides actions for timeline and activity", function () { + var actions = provider.getActions({ key: "add", domainObject: mockDomainObject }); + expect(actions.length).toBe(2); + expect(actions[0].metadata.type).toBe('timeline'); + expect(actions[1].metadata.type).toBe('activity'); + // Make sure it was creation which was used to check - expect(mockPolicyService.allow) - .toHaveBeenCalledWith("creation", mockTypes[0]); - }); - - it("checks for composability of type", function () { - provider.getActions({ - key: "add", - domainObject: mockDomainObject - }); - - expect(mockPolicyService.allow).toHaveBeenCalledWith( - "composition", - jasmine.any(Object), - jasmine.any(Object) - ); - - expect(mockDomainObject.getCapability).toHaveBeenCalledWith('type'); }); }); } diff --git a/platform/commonUI/edit/test/creation/CreateWizardSpec.js b/platform/commonUI/edit/test/creation/CreateWizardSpec.js index a2c96db063..3973afc945 100644 --- a/platform/commonUI/edit/test/creation/CreateWizardSpec.js +++ b/platform/commonUI/edit/test/creation/CreateWizardSpec.js @@ -175,7 +175,7 @@ define( expect(mockPolicyService.allow).toHaveBeenCalledWith( 'composition', mockOtherType, - mockType + mockDomainObject ); }); diff --git a/platform/containment/src/CompositionPolicy.js b/platform/containment/src/CompositionPolicy.js index 16dda80eb3..60d0008fb0 100644 --- a/platform/containment/src/CompositionPolicy.js +++ b/platform/containment/src/CompositionPolicy.js @@ -39,9 +39,7 @@ define( } CompositionPolicy.prototype.allow = function (parentType, child) { - var childType = child.getCapability('type'); - var childTypeKey = childType.getKey(); - var parentDef = parent.getDefinition(); + var parentDef = parentType.getDefinition(); // A parent without containment rules can contain anything. if (!parentDef.contains) { @@ -53,7 +51,7 @@ define( return parentDef.contains.some(function (c) { // Simple containment rules are supported typeKeys. if (typeof c === 'string') { - return c === childTypeKey; + return c === child.getCapability('type').getKey(); } // More complicated rules require context to have all specified // capabilities. diff --git a/platform/containment/test/ComposeActionPolicySpec.js b/platform/containment/test/ComposeActionPolicySpec.js index e7e977c781..b1b0aaff80 100644 --- a/platform/containment/test/ComposeActionPolicySpec.js +++ b/platform/containment/test/ComposeActionPolicySpec.js @@ -79,7 +79,7 @@ define( expect(mockPolicyService.allow).toHaveBeenCalledWith( 'composition', mockTypes[0], - mockTypes[1] + mockDomainObjects[1] ); }); diff --git a/platform/containment/test/CompositionPolicySpec.js b/platform/containment/test/CompositionPolicySpec.js index 97659c9bc9..23261ef5de 100644 --- a/platform/containment/test/CompositionPolicySpec.js +++ b/platform/containment/test/CompositionPolicySpec.js @@ -24,60 +24,94 @@ define( ["../src/CompositionPolicy"], function (CompositionPolicy) { describe("Composition policy", function () { - var mockInjector, - mockTypeService, - mockCapabilityService, - mockTypes, + var typeA, + typeB, + typeC, + mockChildObject, policy; beforeEach(function () { - mockInjector = jasmine.createSpyObj('$injector', ['get']); - mockTypeService = jasmine.createSpyObj( - 'typeService', - ['listTypes'] + typeA = jasmine.createSpyObj( + 'type A-- the particular kind', + ['getKey', 'getDefinition'] ); - mockCapabilityService = jasmine.createSpyObj( - 'capabilityService', - ['getCapabilities'] - ); - // Both types can only contain b, let's say - mockTypes = ['a', 'b'].map(function (type) { - var mockType = jasmine.createSpyObj( - 'type-' + type, - ['getKey', 'getDefinition', 'getInitialModel'] - ); - mockType.getKey.andReturn(type); - mockType.getDefinition.andReturn({ - contains: ['b'] - }); - mockType.getInitialModel.andReturn({}); - return mockType; + typeA.getKey.andReturn('a'); + typeA.getDefinition.andReturn({ + contains: ['a'] }); - mockInjector.get.andCallFake(function (name) { - return { - typeService: mockTypeService, - capabilityService: mockCapabilityService - }[name]; + + typeB = jasmine.createSpyObj( + 'type B-- anything goes', + ['getKey', 'getDefinition'] + ); + typeB.getKey.andReturn('b'); + typeB.getDefinition.andReturn({ + contains: ['a', 'b'] }); - mockTypeService.listTypes.andReturn(mockTypes); - mockCapabilityService.getCapabilities.andReturn({}); + typeC = jasmine.createSpyObj( + 'type C-- distinguishing and interested in telemetry', + ['getKey', 'getDefinition'] + ); + typeC.getKey.andReturn('c'); + typeC.getDefinition.andReturn({ + contains: [{has: 'telemetry'}] + }); - policy = new CompositionPolicy(mockInjector); + mockChildObject = jasmine.createSpyObj( + 'childObject', + ['getCapability', 'hasCapability'] + ); + + policy = new CompositionPolicy(); }); - // Test basic composition policy here; test more closely at - // the unit level in ContainmentTable for 'has' support, et al - it("enforces containment rules defined by types", function () { - expect(policy.allow(mockTypes[0], mockTypes[1])) - .toBeTruthy(); - expect(policy.allow(mockTypes[1], mockTypes[1])) - .toBeTruthy(); - expect(policy.allow(mockTypes[1], mockTypes[0])) - .toBeFalsy(); - expect(policy.allow(mockTypes[0], mockTypes[0])) - .toBeFalsy(); + describe('enforces simple containment rules', function () { + + it('allows when type matches', function () { + mockChildObject.getCapability.andReturn(typeA); + expect(policy.allow(typeA, mockChildObject)) + .toBeTruthy(); + + expect(policy.allow(typeB, mockChildObject)) + .toBeTruthy(); + + mockChildObject.getCapability.andReturn(typeB); + expect(policy.allow(typeB, mockChildObject)) + .toBeTruthy(); + }); + + + it('disallows when type doesn\'t match', function () { + + mockChildObject.getCapability.andReturn(typeB); + expect(policy.allow(typeA, mockChildObject)) + .toBeFalsy(); + + mockChildObject.getCapability.andReturn(typeC); + expect(policy.allow(typeA, mockChildObject)) + .toBeFalsy(); + }); + + }); + + describe('enforces capability-based containment rules', function () { + it('allows when object has capability', function () { + mockChildObject.hasCapability.andReturn(true); + expect(policy.allow(typeC, mockChildObject)) + .toBeTruthy(); + expect(mockChildObject.hasCapability) + .toHaveBeenCalledWith('telemetry'); + }); + + it('skips when object doesn\'t have capability', function () { + mockChildObject.hasCapability.andReturn(false); + expect(policy.allow(typeC, mockChildObject)) + .toBeFalsy(); + expect(mockChildObject.hasCapability) + .toHaveBeenCalledWith('telemetry'); + }); }); }); diff --git a/platform/entanglement/test/services/CopyServiceSpec.js b/platform/entanglement/test/services/CopyServiceSpec.js index 926e579340..bcd25cf825 100644 --- a/platform/entanglement/test/services/CopyServiceSpec.js +++ b/platform/entanglement/test/services/CopyServiceSpec.js @@ -104,7 +104,7 @@ define( expect(policyService.allow).toHaveBeenCalledWith( "composition", parentCandidate.capabilities.type, - object.capabilities.type + object ); }); diff --git a/platform/entanglement/test/services/LinkServiceSpec.js b/platform/entanglement/test/services/LinkServiceSpec.js index 16d82e6601..6dcd9480b8 100644 --- a/platform/entanglement/test/services/LinkServiceSpec.js +++ b/platform/entanglement/test/services/LinkServiceSpec.js @@ -114,7 +114,7 @@ define( expect(mockPolicyService.allow).toHaveBeenCalledWith( "composition", parentCandidate.capabilities.type, - object.capabilities.type + object ); }); diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index ee73a9d10c..687559ee56 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -124,7 +124,7 @@ define( expect(policyService.allow).toHaveBeenCalledWith( "composition", parentCandidate.capabilities.type, - object.capabilities.type + object ); }); diff --git a/platform/features/layout/test/LayoutCompositionPolicySpec.js b/platform/features/layout/test/LayoutCompositionPolicySpec.js index f58a8e5e5c..7d7abb2bcd 100644 --- a/platform/features/layout/test/LayoutCompositionPolicySpec.js +++ b/platform/features/layout/test/LayoutCompositionPolicySpec.js @@ -24,18 +24,25 @@ define( ["../src/LayoutCompositionPolicy"], function (LayoutCompositionPolicy) { describe("Layout's composition policy", function () { - var mockCandidate, + var mockChild, + mockCandidate, mockContext, candidateType, contextType, policy; beforeEach(function () { + mockChild = jasmine.createSpyObj( + 'childObject', + ['getCapability'] + ); mockCandidate = jasmine.createSpyObj('candidateType', ['instanceOf']); mockContext = jasmine.createSpyObj('contextType', ['instanceOf']); + mockChild.getCapability.andReturn(mockContext); + mockCandidate.instanceOf.andCallFake(function (t) { return t === candidateType; }); @@ -49,19 +56,19 @@ define( it("disallows folders in layouts", function () { candidateType = 'layout'; contextType = 'folder'; - expect(policy.allow(mockCandidate, mockContext)).toBe(false); + expect(policy.allow(mockCandidate, mockChild)).toBe(false); }); it("does not disallow folders elsewhere", function () { candidateType = 'nonlayout'; contextType = 'folder'; - expect(policy.allow(mockCandidate, mockContext)).toBe(true); + expect(policy.allow(mockCandidate, mockChild)).toBe(true); }); it("allows things other than folders in layouts", function () { candidateType = 'layout'; contextType = 'nonfolder'; - expect(policy.allow(mockCandidate, mockContext)).toBe(true); + expect(policy.allow(mockCandidate, mockChild)).toBe(true); }); });