Skip to content
This repository has been archived by the owner on Mar 8, 2020. It is now read-only.

Commit

Permalink
make readonly flag parameterless (#4587)
Browse files Browse the repository at this point in the history
Signed-off-by: nkl199@yahoo.co.uk <nkl199@yahoo.co.uk>
  • Loading branch information
nklincoln authored and mbwhite committed Jan 31, 2019
1 parent 5adbb35 commit a828b05
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 62 deletions.
1 change: 0 additions & 1 deletion packages/composer-common/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ class ModelManager {
}
class ReadOnlyDecorator extends Decorator {
+ void constructor(Object) throws IllegalModelException
+ boolean getValue()
}
class ReadOnlyDecoratorFactory extends DecoratorFactory {
+ Decorator newDecorator(Object)
Expand Down
3 changes: 3 additions & 0 deletions packages/composer-common/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
# Note that the latest public API is documented using JSDocs and is available in api.txt.
#

Version 0.19.20 {308d962120667e982b2600107d0b8b13} 2019-01-29
- Modify readonly decorator to be parameterless

Version 0.19.20 {5ff216eab17b2d990c43636c51a585b5} 2018-12-18
- Add readonly decorator factory

Expand Down
17 changes: 2 additions & 15 deletions packages/composer-common/lib/readonlydecorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,9 @@ class ReadOnlyDecorator extends Decorator {
process() {
super.process();
const args = this.getArguments();
if (args.length !== 1) {
throw new IllegalModelException(`@readonly decorator expects 1 argument, but ${args.length} arguments were specified.`, this.parent.getModelFile(), this.ast.location);
if (args.length !== 0) {
throw new IllegalModelException(`@readonly decorator expects 0 arguments, but ${args.length} arguments were specified.`, this.parent.getModelFile(), this.ast.location);
}
const arg = args[0];
if (typeof arg !== 'boolean') {
throw new IllegalModelException(`@readonly decorator expects a boolean argument, but an argument of type ${typeof arg} was specified.`, this.parent.getModelFile(), this.ast.location);
}
this.value = arg;
}

/**
* Get the value of this commit decorator.
* @return {boolean} The value of this commit decorator.
*/
getValue() {
return this.value;
}

}
Expand Down
2 changes: 1 addition & 1 deletion packages/composer-common/test/businessnetworkdefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ describe('BusinessNetworkDefinition', () => {
const modelManager = bnd.getModelManager();
modelManager.addModelFile(`
namespace org.acme
@readonly(true)
@readonly
transaction T{ }`);
const transactionDeclaration = modelManager.getType('org.acme.T');
const decorator = transactionDeclaration.getDecorator('readonly');
Expand Down
32 changes: 3 additions & 29 deletions packages/composer-common/test/readonlydecorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const ModelManager = require('../lib/modelmanager');

require('chai').should();

describe('RaedOnlyDecorator', () => {
describe('ReadOnlyDecorator', () => {

let modelManager;
let transactionDeclaration;
Expand All @@ -37,38 +37,12 @@ describe('RaedOnlyDecorator', () => {

describe('#process', () => {

it('should throw if no arguments are specified', () => {
(() => {
new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [] } });
}).should.throw(/@readonly decorator expects 1 argument, but 0 arguments were specified. Line 1 column 1, to line 1 column 23./);
});

it('should throw if two arguments are specified', () => {
it('should throw if arguments are specified', () => {
(() => {
new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: true }, { value: false } ] } });
}).should.throw(/@readonly decorator expects 1 argument, but 2 arguments were specified. Line 1 column 1, to line 1 column 23./);
}).should.throw(/@readonly decorator expects 0 arguments, but 2 arguments were specified. Line 1 column 1, to line 1 column 23./);
});

it('should throw if a an incorrectly typed argument is specified', () => {
(() => {
new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: 'hello world' } ] } });
}).should.throw(/@readonly decorator expects a boolean argument, but an argument of type string was specified. Line 1 column 1, to line 1 column 23./);
});

});

describe('#getValue', () => {

it('should return true if the argument is true', () => {
const decorator = new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: true } ] } });
decorator.getValue().should.be.true;
});

it('should return false if the argument is false', () => {
const decorator = new ReadOnlyDecorator(transactionDeclaration, { location: { start: { offset: 0, line: 1, column: 1 }, end: { offset: 22, line: 1, column: 23 } }, name: 'readonly', arguments: { list: [ { value: false } ] } });
decorator.getValue().should.be.false;
});

});

});
2 changes: 1 addition & 1 deletion packages/composer-common/test/readonlydecoratorfactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('ReadOnlyDecoratorDecoratorFactory', () => {
});

it('should return a readonly decorator instance for a @readonly decorator', () => {
const decorator = factory.newDecorator(transactionDeclaration, { name: 'readonly', arguments: { list: [ { value: false } ] } });
const decorator = factory.newDecorator(transactionDeclaration, { name: 'readonly' });
decorator.should.be.an.instanceOf(ReadOnlyDecorator);
});

Expand Down
3 changes: 1 addition & 2 deletions packages/composer-runtime/lib/engine.transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,7 @@ class EngineTransactions {
// Get the type and resolved type.
const transactionDeclaration = transaction.getClassDeclaration();
const returnsDecorator = transactionDeclaration.getDecorator('returns');
const readOnlyDecorator = transactionDeclaration.getDecorator('readonly');
const readOnly = readOnlyDecorator ? readOnlyDecorator.getValue() : false;
const readOnly = transactionDeclaration.getDecorator('readonly') ? true : false;
const returnValueType = returnsDecorator.getType();
const returnValueResolvedType = returnsDecorator.getResolvedType();
const isArray = returnsDecorator.isArray();
Expand Down
42 changes: 29 additions & 13 deletions packages/composer-runtime/test/engine.transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,12 @@ describe('EngineTransactions', () => {
}
@returns(MyAsset)
@readonly(true)
@readonly
transaction MyTransactionThatReturnsAsset {
o String value
}
@returns(MyAsset[])
@readonly(false)
@readonly
transaction MyTransactionThatReturnsAssetArray {
o String value
}
Expand Down Expand Up @@ -342,6 +342,17 @@ describe('EngineTransactions', () => {
})]).should.be.rejectedWith(/such error/);
});

it('should correctly identify a readonly decorator', () => {
let transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsConcept');
let result = transaction.getClassDeclaration().getDecorator('readonly');
should.not.exist(result);

transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsAsset');
result = transaction.getClassDeclaration().getDecorator('readonly');
should.exist(result);
result.name.should.equal('readonly');
});

});

describe('#_executeTransaction', () => {
Expand Down Expand Up @@ -668,29 +679,34 @@ describe('EngineTransactions', () => {
}]);
});

it('should handle a readonly(true) Asset return value', () => {
it('should handle a concept return value that is not readonly but contains a $original component', () => {
const transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsConcept');
const concept = factory.newConcept('org.acme', 'MyConcept');
concept.value = 'hello world';
concept.$original = 'not to be seen';
engine._processComplexReturnValue(mockContext, transaction, concept).should.deep.equal({
$class: 'org.acme.MyConcept',
value: 'hello world'
});
});

it('should handle a readonly Asset return value', () => {
const transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsAsset');
const asset = factory.newResource('org.acme', 'MyAsset','001');
asset.value = 'hello world';
asset.$original = 'penguin';
engine._processComplexReturnValue(mockContext, transaction, asset).should.equal('penguin');
});

it('should handle a readonly(false) Asset[] return value', () => {
it('should handle a readonly Asset[] return value', () => {
const transaction = factory.newTransaction('org.acme', 'MyTransactionThatReturnsAssetArray');
const asset1 = factory.newResource('org.acme', 'MyAsset','001');
asset1.value = 'hello world';
asset1.$original = 'penguin';
const asset2 = factory.newResource('org.acme', 'MyAsset','002');
asset2.value = 'hello again world';
engine._processComplexReturnValue(mockContext, transaction, [asset1, asset2]).should.deep.equal([{
$class: 'org.acme.MyAsset',
assetId: '001',
value: 'hello world'
}, {
$class: 'org.acme.MyAsset',
assetId: '002',
value: 'hello again world'
}]);
asset2.$original = 'power';
engine._processComplexReturnValue(mockContext, transaction, [asset1, asset2]).should.deep.equal(['penguin', 'power']);
});

it('should throw for an invalid (wrong type) concept return value', () => {
Expand Down

0 comments on commit a828b05

Please sign in to comment.