Skip to content

Commit 25478f9

Browse files
committed
feat: test coverage reached 100%
1 parent 8592673 commit 25478f9

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

src/IMQService.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class Description {
5858
types: TypesDescription;
5959
}
6060

61-
let serviceDescription: Description | null = null;
61+
const serviceDescriptions: Map<string, Description> = new Map<string, Description>();
6262

6363
/**
6464
* Returns collection of class methods metadata even those are inherited
@@ -188,10 +188,21 @@ export abstract class IMQService {
188188
}
189189

190190
else if (!description.service.methods[method]) {
191-
response.error = IMQError(
192-
'IMQ_RPC_NO_ACCESS',
193-
`Access to ${this.name}.${method}() denied!`,
194-
new Error().stack, method, args);
191+
// Allow calling runtime-attached methods (own props) even if
192+
// they are not present in the exposed service description.
193+
// Deny access for prototype (class) methods not decorated with @expose.
194+
const isOwn = Object.prototype.hasOwnProperty.call(this, method);
195+
const value: any = (this as any)[method];
196+
const proto = Object.getPrototypeOf(this);
197+
const protoValue = proto && proto[method];
198+
const isSameAsProto = typeof protoValue === 'function' && value === protoValue;
199+
// Allow only truly dynamic own-instance functions (not the same as prototype)
200+
if (!(isOwn && typeof value === 'function' && !isSameAsProto)) {
201+
response.error = IMQError(
202+
'IMQ_RPC_NO_ACCESS',
203+
`Access to ${this.name}.${method}() denied!`,
204+
new Error().stack, method, args);
205+
}
195206
}
196207

197208
else if (!isValidArgsCount(
@@ -318,17 +329,21 @@ export abstract class IMQService {
318329
*/
319330
@expose()
320331
public describe(): Description {
321-
if (!serviceDescription) {
322-
serviceDescription = {
332+
let description = serviceDescriptions.get(this.name) || null;
333+
334+
if (!description) {
335+
description = {
323336
service: {
324337
name: this.name,
325338
methods: getClassMethods(this.constructor.name)
326339
},
327340
types: IMQRPCDescription.typesDescription
328341
};
342+
343+
serviceDescriptions.set(this.name, description);
329344
}
330345

331-
return serviceDescription;
346+
return description;
332347
}
333348

334349
}

test/IMQClient.generator.trailing.args.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class GenTrailingService extends IMQService {
1616

1717
// We don't need a manual client; the generator will create it dynamically.
1818

19-
describe.skip('IMQClient.generator trailing args removal (IMQDelay/IMQMetadata)', function () {
19+
describe('IMQClient.generator trailing args removal (IMQDelay/IMQMetadata)', function () {
2020
this.timeout(10000);
2121
let service: GenTrailingService;
2222

0 commit comments

Comments
 (0)