Enums
Tests in this category ensure enum values cross the language boundary as the correct host enum member, including enums declared in dependencies.
Enum-valued properties can be read and written
Test: enumPropertiesCanBeReadAndWritten
A property declared with an enum type MUST be readable and writable from the host. Reading MUST return the enum member currently held in the kernel; writing MUST send the selected member so that subsequent reads, and kernel code that consumes the property, observe the new member.
Reference Implementation
// GIVEN
export namespace composition {
export abstract class CompositeOperation {
public stringStyle = CompositeOperation.CompositionStringStyle.NORMAL;
public decorationPrefixes = ['<<[[{{'];
public decorationPostfixes = ['}}]]>>'];
public abstract readonly expression: { toString(): string };
public toString() {
switch (this.stringStyle) {
case CompositeOperation.CompositionStringStyle.NORMAL:
return this.expression.toString();
case CompositeOperation.CompositionStringStyle.DECORATED:
return this.decorationPrefixes.join('') + this.expression.toString() + this.decorationPostfixes.join('');
}
}
}
export namespace CompositeOperation {
export enum CompositionStringStyle {
NORMAL,
DECORATED,
}
}
}
export class Calculator extends composition.CompositeOperation {
// Maintains a current value; `add` and `pow` append operations to the expression.
public add(_value: number): void {
/* ... */
}
public pow(_value: number): void {
/* ... */
}
public get expression() {
/* ... */ return { toString: () => '(((1 * (0 + 9)) * (0 + 9)) * (0 + 9))' };
}
}
// WHEN / THEN
const calc = new Calculator();
calc.add(9);
calc.pow(3);
expect(calc.stringStyle).toBe(composition.CompositeOperation.CompositionStringStyle.NORMAL);
calc.stringStyle = composition.CompositeOperation.CompositionStringStyle.DECORATED;
expect(calc.stringStyle).toBe(composition.CompositeOperation.CompositionStringStyle.DECORATED);
expect(calc.toString()).toBe('<<[[{{(((1 * (0 + 9)) * (0 + 9)) * (0 + 9))}}]]>>');
Enum members returned by the kernel deserialize correctly
Test: enumValuesReturnedByTheKernel
An enum member returned from the kernel MUST deserialize to a valid, non-absent host enum member. This MUST hold both for enums whose members are backed by strings and for enums whose members are backed by numbers.
Reference Implementation
// GIVEN
export enum StringEnum {
A = 'A!',
B = 'B?',
C = 'C.',
}
export enum AllTypesEnum {
MY_ENUM_VALUE,
YOUR_ENUM_VALUE = 100,
THIS_IS_GREAT,
}
export class EnumDispenser {
public static randomStringLikeEnum(): StringEnum {
return StringEnum.B;
}
public static randomIntegerLikeEnum(): AllTypesEnum {
return AllTypesEnum.YOUR_ENUM_VALUE;
}
}
// WHEN
const stringLike = EnumDispenser.randomStringLikeEnum();
const integerLike = EnumDispenser.randomIntegerLikeEnum();
// THEN
expect(stringLike).toBeDefined();
expect(integerLike).toBeDefined();
Enum values declared in a dependency cross the boundary
Test: enumsFromDependenciesCrossTheBoundary
An enum declared in a dependency of the module under test MUST cross the boundary as the correct member: when read from and written to a property, and when passed to and returned from methods. The host MUST resolve the enum to its declaration in the dependency, and the member MUST round-trip unchanged.
Reference Implementation
// GIVEN (declared in the dependency package)
export enum EnumFromScopedModule {
VALUE1,
VALUE2,
}
// GIVEN (declared in the module under test, which depends on the package above)
export class ReferenceEnumFromScopedPackage {
public foo?: EnumFromScopedModule = EnumFromScopedModule.VALUE2;
public loadFoo(): EnumFromScopedModule | undefined {
return this.foo;
}
public saveFoo(value: EnumFromScopedModule) {
this.foo = value;
}
}
// WHEN / THEN
const obj = new ReferenceEnumFromScopedPackage();
expect(obj.foo).toBe(EnumFromScopedModule.VALUE2);
obj.foo = EnumFromScopedModule.VALUE1;
expect(obj.loadFoo()).toBe(EnumFromScopedModule.VALUE1);
obj.saveFoo(EnumFromScopedModule.VALUE2);
expect(obj.foo).toBe(EnumFromScopedModule.VALUE2);