From 44e5acc20a2e729773e90a6768f2f6be3e63e581 Mon Sep 17 00:00:00 2001 From: Marcelo Lv Cabral Date: Thu, 4 Apr 2024 15:25:29 -0700 Subject: [PATCH] Implement `ifArraySizeInfo` in `roArray` (#62) * Implemented `ifArraySizeInfo` in `roArray` * Removing empty line * Fixed warning message --- src/brsTypes/components/BrsObjects.ts | 6 +- src/brsTypes/components/RoArray.ts | 251 ++++++++++++++-------- src/brsTypes/components/RoByteArray.ts | 51 +++-- src/brsTypes/components/RoList.ts | 2 +- src/brsTypes/components/RoSGNode.ts | 8 +- src/interpreter/index.ts | 13 ++ src/stdlib/CreateObject.ts | 9 +- test/e2e/BrsComponents.test.js | 10 + test/e2e/resources/components/roArray.brs | 34 +-- 9 files changed, 248 insertions(+), 136 deletions(-) diff --git a/src/brsTypes/components/BrsObjects.ts b/src/brsTypes/components/BrsObjects.ts index bb790483d..95269c959 100644 --- a/src/brsTypes/components/BrsObjects.ts +++ b/src/brsTypes/components/BrsObjects.ts @@ -28,7 +28,11 @@ import { RoPath } from "./RoPath"; /** Map containing a list of BrightScript components that can be created. */ export const BrsObjects = new Map([ ["roassociativearray", (_: Interpreter) => new RoAssociativeArray([])], - ["roarray", (_: Interpreter) => new RoArray([])], + [ + "roarray", + (interpreter: Interpreter, capacity: Int32 | Float, resizable: BrsBoolean) => + new RoArray(capacity, resizable), + ], ["rolist", (_: Interpreter) => new RoList([])], ["robytearray", (_: Interpreter) => new RoByteArray()], ["rodatetime", (_: Interpreter) => new RoDateTime()], diff --git a/src/brsTypes/components/RoArray.ts b/src/brsTypes/components/RoArray.ts index fd22e37b0..cde61acb4 100644 --- a/src/brsTypes/components/RoArray.ts +++ b/src/brsTypes/components/RoArray.ts @@ -5,85 +5,33 @@ import { Callable, StdlibArgument } from "../Callable"; import { Interpreter } from "../../interpreter"; import { RoAssociativeArray } from "./RoAssociativeArray"; -/** - * Gives the order for sorting different types in a mixed array - * - * Mixed Arrays seem to get sorted in this order (tested with Roku OS 9.4): - * - * numbers in numeric order - * strings in alphabetical order, - * assocArrays in original order - * everything else in original order - */ -function getTypeSortIndex(a: BrsType): number { - if (isBrsNumber(a)) { - return 0; - } else if (isBrsString(a)) { - return 1; - } else if (a instanceof RoAssociativeArray) { - return 2; - } - return 3; -} - -/** - * Sorts two BrsTypes in the order that Roku would sort them - * @param originalArray A copy of the original array. Used to get the order of items - * @param a - * @param b - * @param caseInsensitive Should strings be compared case insensitively? defaults to false - * @param sortInsideTypes Should two numbers or two strings be sorted? defaults to true - * @return compare value for array.sort() - */ -function sortCompare( - originalArray: BrsType[], - a: BrsType, - b: BrsType, - caseInsensitive: boolean = false, - sortInsideTypes: boolean = true -): number { - let compare = 0; - if (a !== undefined && b !== undefined) { - const aSortOrder = getTypeSortIndex(a); - const bSortOrder = getTypeSortIndex(b); - if (aSortOrder < bSortOrder) { - compare = -1; - } else if (bSortOrder < aSortOrder) { - compare = 1; - } else if (sortInsideTypes && isBrsNumber(a)) { - // two numbers are in numeric order - compare = (a as Comparable).greaterThan(b).toBoolean() ? 1 : -1; - } else if (sortInsideTypes && isBrsString(a)) { - // two strings are in alphabetical order - let aStr = a.toString(); - let bStr = b.toString(); - if (caseInsensitive) { - aStr = aStr.toLowerCase(); - bStr = bStr.toLowerCase(); - } - // roku does not use locale for sorting strings - compare = aStr > bStr ? 1 : -1; - } else { - // everything else is in the same order as the original - const aOriginalIndex = originalArray.indexOf(a); - const bOriginalIndex = originalArray.indexOf(b); - if (aOriginalIndex > -1 && bOriginalIndex > -1) { - compare = aOriginalIndex - bOriginalIndex; - } - } - } - return compare; -} - export class RoArray extends BrsComponent implements BrsValue, BrsIterable { readonly kind = ValueKind.Object; + private maxSize = 0; + private resizable = true; + private enumIndex: number; elements: BrsType[]; - enumIndex: number; - constructor(elements: BrsType[]) { + constructor(elements: BrsType[]); + constructor(capacity: Int32 | Float, resizable: BrsBoolean); + constructor(...args: any) { super("roArray"); - this.elements = elements; - this.enumIndex = elements.length ? 0 : -1; + this.elements = []; + if (args.length === 1 && Array.isArray(args[0])) { + this.elements = args[0]; + } else if ( + args.length === 2 && + (args[0] instanceof Int32 || args[0] instanceof Float) && + (args[1] instanceof BrsBoolean || isBrsNumber(args[1])) + ) { + this.maxSize = args[0].getValue(); + this.resizable = args[1].toBoolean(); + } else { + throw new Error( + `BRIGHTSCRIPT: ERROR: Runtime: "roArray": invalid number of parameters:` + ); + } + this.enumIndex = this.elements.length ? 0 : -1; this.registerMethods({ ifArray: [ this.peek, @@ -101,6 +49,7 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { ifArrayJoin: [this.join], ifArraySort: [this.sort, this.sortBy, this.reverse], ifArraySlice: [this.slice], + ifArraySizeInfo: [this.capacity, this.isResizable], ifEnum: [this.isEmpty, this.isNext, this.next, this.reset], }); } @@ -176,6 +125,22 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { } } + updateCapacity(growthFactor = 0) { + if (this.resizable && growthFactor > 0) { + if (this.elements.length > 0 && this.elements.length > this.maxSize) { + let count = this.elements.length - 1; + let newCap = Math.trunc(count * growthFactor); + if (newCap - this.maxSize < 10) { + this.maxSize = Math.trunc(10 * (count / 10 + 1)); + } else { + this.maxSize = newCap; + } + } + } else { + this.maxSize = Math.max(this.elements.length, this.maxSize); + } + } + aaCompare( fieldName: BrsString, flags: BrsString, @@ -229,9 +194,17 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { args: [new StdlibArgument("talue", ValueKind.Dynamic)], returns: ValueKind.Void, }, - impl: (_: Interpreter, tvalue: BrsType) => { - this.elements.push(tvalue); - this.updateNext(); + impl: (interpreter: Interpreter, tvalue: BrsType) => { + if (this.resizable || this.elements.length < this.maxSize) { + this.elements.push(tvalue); + this.updateNext(); + this.updateCapacity(1.25); + } else { + let location = interpreter.formatLocation(); + interpreter.stderr.write( + `BRIGHTSCRIPT: ERROR: roArray.Push: set ignored for index out of bounds on non-resizable array: ${location}\n` + ); + } return BrsInvalid.Instance; }, }); @@ -253,9 +226,17 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { args: [new StdlibArgument("tvalue", ValueKind.Dynamic)], returns: ValueKind.Void, }, - impl: (_: Interpreter, tvalue: BrsType) => { - this.elements.unshift(tvalue); - this.updateNext(); + impl: (interpreter: Interpreter, tvalue: BrsType) => { + if (this.resizable || this.elements.length < this.maxSize) { + this.elements.unshift(tvalue); + this.updateNext(); + this.updateCapacity(1.25); + } else { + let location = interpreter.formatLocation(); + interpreter.stderr.write( + `BRIGHTSCRIPT: ERROR: roArray.Unshift: set ignored for index out of bounds on non-resizable array: ${location}\n` + ); + } return BrsInvalid.Instance; }, }); @@ -304,18 +285,21 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, array: BrsComponent) => { if (!(array instanceof RoArray)) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roArray.Append: invalid parameter type ${array.getComponentName()}: ${location}\n` ); return BrsInvalid.Instance; } - this.elements = [ - ...this.elements, - ...array.elements.filter((element) => !!element), // don't copy "holes" where no value exists - ]; - this.updateNext(); + if (this.resizable || this.elements.length + array.elements.length <= this.maxSize) { + this.elements = [ + ...this.elements, + ...array.elements.filter((element) => !!element), // don't copy "holes" where no value exists + ]; + this.updateNext(); + this.updateCapacity(); + } return BrsInvalid.Instance; }, }); @@ -363,6 +347,7 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { return new BrsString(this.elements.join(separator.value)); }, }); + // ifArraySort private sort = new Callable("sort", { signature: { @@ -447,6 +432,30 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { }, }); + // ifArraySizeInfo + + /** Returns the maximum number of entries that can be stored in the array. */ + private capacity = new Callable("capacity", { + signature: { + args: [], + returns: ValueKind.Int32, + }, + impl: (_: Interpreter) => { + return new Int32(this.maxSize); + }, + }); + + /** Returns true if the array can be resized. */ + private isResizable = new Callable("isResizable", { + signature: { + args: [], + returns: ValueKind.Boolean, + }, + impl: (_: Interpreter) => { + return BrsBoolean.from(this.resizable); + }, + }); + // ifEnum /** Checks whether the array contains no elements. */ @@ -494,3 +503,73 @@ export class RoArray extends BrsComponent implements BrsValue, BrsIterable { }, }); } + +/** + * Gives the order for sorting different types in a mixed array + * + * Mixed Arrays seem to get sorted in this order (tested with Roku OS 9.4): + * + * numbers in numeric order + * strings in alphabetical order, + * assocArrays in original order + * everything else in original order + */ +function getTypeSortIndex(a: BrsType): number { + if (isBrsNumber(a)) { + return 0; + } else if (isBrsString(a)) { + return 1; + } else if (a instanceof RoAssociativeArray) { + return 2; + } + return 3; +} + +/** + * Sorts two BrsTypes in the order that Roku would sort them + * @param originalArray A copy of the original array. Used to get the order of items + * @param a + * @param b + * @param caseInsensitive Should strings be compared case insensitively? defaults to false + * @param sortInsideTypes Should two numbers or two strings be sorted? defaults to true + * @return compare value for array.sort() + */ +function sortCompare( + originalArray: BrsType[], + a: BrsType, + b: BrsType, + caseInsensitive: boolean = false, + sortInsideTypes: boolean = true +): number { + let compare = 0; + if (a !== undefined && b !== undefined) { + const aSortOrder = getTypeSortIndex(a); + const bSortOrder = getTypeSortIndex(b); + if (aSortOrder < bSortOrder) { + compare = -1; + } else if (bSortOrder < aSortOrder) { + compare = 1; + } else if (sortInsideTypes && isBrsNumber(a)) { + // two numbers are in numeric order + compare = (a as Comparable).greaterThan(b).toBoolean() ? 1 : -1; + } else if (sortInsideTypes && isBrsString(a)) { + // two strings are in alphabetical order + let aStr = a.toString(); + let bStr = b.toString(); + if (caseInsensitive) { + aStr = aStr.toLowerCase(); + bStr = bStr.toLowerCase(); + } + // roku does not use locale for sorting strings + compare = aStr > bStr ? 1 : -1; + } else { + // everything else is in the same order as the original + const aOriginalIndex = originalArray.indexOf(a); + const bOriginalIndex = originalArray.indexOf(b); + if (aOriginalIndex > -1 && bOriginalIndex > -1) { + compare = aOriginalIndex - bOriginalIndex; + } + } + } + return compare; +} diff --git a/src/brsTypes/components/RoByteArray.ts b/src/brsTypes/components/RoByteArray.ts index 998b6e99f..225f88958 100644 --- a/src/brsTypes/components/RoByteArray.ts +++ b/src/brsTypes/components/RoByteArray.ts @@ -8,10 +8,9 @@ import { crc32 } from "crc"; export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { readonly kind = ValueKind.Object; - private elements: Uint8Array; - private _capacity = 0; - private _resizable = true; - + private maxSize = 0; + private resizable = true; + elements: Uint8Array; enumIndex: number; constructor(); @@ -141,18 +140,18 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { } updateCapacity(growthFactor = 0) { - if (this._resizable && growthFactor > 0) { - if (this.elements.length > 0 && this.elements.length > this._capacity) { + if (this.resizable && growthFactor > 0) { + if (this.elements.length > 0 && this.elements.length > this.maxSize) { let count = this.elements.length - 1; let newCap = Math.trunc(count * growthFactor); - if (newCap - this._capacity < 16) { - this._capacity = Math.trunc(16 * (count / 16 + 1)); + if (newCap - this.maxSize < 16) { + this.maxSize = Math.trunc(16 * (count / 16 + 1)); } else { - this._capacity = newCap; + this.maxSize = newCap; } } } else { - this._capacity = Math.max(this.elements.length, this._capacity); + this.maxSize = Math.max(this.elements.length, this.maxSize); } } isLittleEndian() { @@ -185,7 +184,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { let end = length.getValue() < 1 ? undefined : start + length.getValue(); array = array.slice(start, end); } - if (this._resizable || array.length <= this._capacity) { + if (this.resizable || array.length <= this.maxSize) { this.elements = array; this.updateNext(); this.updateCapacity(); @@ -284,7 +283,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (_: Interpreter, asciiStr: BrsString) => { const array = new Uint8Array(Buffer.from(asciiStr.value, "utf8")); - if (this._resizable || array.length <= this._capacity) { + if (this.resizable || array.length <= this.maxSize) { this.elements = array; this.updateNext(); this.updateCapacity(); @@ -311,7 +310,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (_: Interpreter, hexStr: BrsString) => { const value = hexStr.value.replace(/[^0-9A-Fa-f]/g, "0"); - if (value.length % 2 === 0 && (this._resizable || value.length / 2 <= this._capacity)) { + if (value.length % 2 === 0 && (this.resizable || value.length / 2 <= this.maxSize)) { this.elements = new Uint8Array(Buffer.from(value, "hex")); this.updateNext(); this.updateCapacity(); @@ -340,7 +339,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (_: Interpreter, hexStr: BrsString) => { const array = new Uint8Array(Buffer.from(hexStr.value, "base64")); - if (this._resizable || array.length <= this._capacity) { + if (this.resizable || array.length <= this.maxSize) { this.elements = array; this.updateNext(); this.updateCapacity(); @@ -423,8 +422,8 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { returns: ValueKind.Void, }, impl: (_: Interpreter, minSize: Int32 | Float, autoResize: BrsBoolean) => { - this._capacity = Math.max(Math.trunc(minSize.getValue()), this.elements.length); - this._resizable = autoResize.toBoolean(); + this.maxSize = Math.max(Math.trunc(minSize.getValue()), this.elements.length); + this.resizable = autoResize.toBoolean(); return BrsInvalid.Instance; }, }); @@ -481,7 +480,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, byte: Int32 | Float | BrsInvalid) => { if (isBrsNumber(byte)) { - if (this._resizable || this.elements.length < this._capacity) { + if (this.resizable || this.elements.length < this.maxSize) { let array = new Uint8Array(this.elements.length + 1); array.set(this.elements, 0); array[this.elements.length] = byte.getValue(); @@ -489,13 +488,13 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { this.updateNext(); this.updateCapacity(1.5); } else { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roByteArray.Push: set ignored for index out of bounds on non-resizable array: ${location}\n` ); } } else { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roByteArray.Push: set ignored for non-numeric value: ${location}\n` ); @@ -530,7 +529,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, byte: Int32 | Float | BrsInvalid) => { if (isBrsNumber(byte)) { - if (this._resizable || this.elements.length < this._capacity) { + if (this.resizable || this.elements.length < this.maxSize) { let array = new Uint8Array(this.elements.length + 1); array[0] = byte.getValue(); array.set(this.elements, 1); @@ -538,7 +537,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { this.updateNext(); this.updateCapacity(1.25); } else { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roByteArray.Unshift: unshift ignored for full non-resizable array: ${location}\n` ); @@ -603,13 +602,13 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, array: BrsComponent) => { if (!(array instanceof RoByteArray)) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roByteArray.Append: invalid parameter type ${array.getComponentName()}: ${location}\n` ); return BrsInvalid.Instance; } - if (this._resizable || this.elements.length + array.elements.length <= this._capacity) { + if (this.resizable || this.elements.length + array.elements.length <= this.maxSize) { this.elements = new Uint8Array([...this.elements, ...array.elements]); this.updateNext(); this.updateCapacity(); @@ -644,7 +643,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, index: Int32 | Float, value: BrsType) => { if (!isBrsNumber(value)) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roByteArray.SetEntry: set ignored for non-numeric value: ${location}\n` ); @@ -662,7 +661,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { returns: ValueKind.Int32, }, impl: (_: Interpreter) => { - return new Int32(this._capacity); + return new Int32(this.maxSize); }, }); @@ -673,7 +672,7 @@ export class RoByteArray extends BrsComponent implements BrsValue, BrsIterable { returns: ValueKind.Boolean, }, impl: (_: Interpreter) => { - return BrsBoolean.from(this._resizable); + return BrsBoolean.from(this.resizable); }, }); diff --git a/src/brsTypes/components/RoList.ts b/src/brsTypes/components/RoList.ts index 42fbfb66b..522ebefc1 100644 --- a/src/brsTypes/components/RoList.ts +++ b/src/brsTypes/components/RoList.ts @@ -385,7 +385,7 @@ export class RoList extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, array: BrsComponent) => { if (!(array instanceof RoList)) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roList.Append: invalid parameter type ${array.getComponentName()}: ${location}\n` ); diff --git a/src/brsTypes/components/RoSGNode.ts b/src/brsTypes/components/RoSGNode.ts index f4833ea8b..5b4b7871b 100644 --- a/src/brsTypes/components/RoSGNode.ts +++ b/src/brsTypes/components/RoSGNode.ts @@ -927,7 +927,7 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable { let callableFunction = interpreter.getCallableFunction(functionname.value); let subscriber = interpreter.environment.hostNode; if (!subscriber) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roSGNode.ObserveField: no active host node: ${location}\n` ); @@ -961,7 +961,7 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, fieldname: BrsString, functionname: BrsString) => { if (!interpreter.environment.hostNode) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roSGNode.unObserveField: no active host node: ${location}\n` ); @@ -991,7 +991,7 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable { let callableFunction = interpreter.getCallableFunction(functionname.value); let subscriber = interpreter.environment.hostNode; if (!subscriber) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roSGNode.ObserveField: no active host node: ${location}\n` ); @@ -1022,7 +1022,7 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable { }, impl: (interpreter: Interpreter, fieldname: BrsString, functionname: BrsString) => { if (!interpreter.environment.hostNode) { - let location = `${interpreter.location.file}:(${interpreter.location.start.line})`; + let location = interpreter.formatLocation(); interpreter.stderr.write( `BRIGHTSCRIPT: ERROR: roSGNode.unObserveField: no active host node: ${location}\n` ); diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts index 4b397737d..ac7e1c087 100644 --- a/src/interpreter/index.ts +++ b/src/interpreter/index.ts @@ -1701,6 +1701,19 @@ export class Interpreter implements Expr.Visitor, Stmt.Visitor return debugMsg; } + /** Method to return a string with the current source code location + * @returns a string representation of the location + */ + formatLocation(location: Location = this.location) { + let formattedLocation: string; + if (location.start.line) { + formattedLocation = `pkg:/${location.file}(${location.start.line})`; + } else { + formattedLocation = `pkg:/${location.file}(??)`; + } + return formattedLocation; + } + /** * Emits an error via this processor's `events` property, then throws it. * @param err the ParseError to emit then throw diff --git a/src/stdlib/CreateObject.ts b/src/stdlib/CreateObject.ts index 7b26275b9..3e2e74e1e 100644 --- a/src/stdlib/CreateObject.ts +++ b/src/stdlib/CreateObject.ts @@ -41,6 +41,13 @@ export const CreateObject = new Callable("CreateObject", { } let ctor = BrsObjects.get(objName.value.toLowerCase()); - return ctor ? ctor(interpreter, ...additionalArgs) : BrsInvalid.Instance; + if (ctor) { + try { + return ctor(interpreter, ...additionalArgs); + } catch (err: any) { + interpreter.stderr.write(`${err.message} ${interpreter.formatLocation()}\n`); + } + } + return BrsInvalid.Instance; }, }); diff --git a/test/e2e/BrsComponents.test.js b/test/e2e/BrsComponents.test.js index 205d0a6e6..6092eac20 100644 --- a/test/e2e/BrsComponents.test.js +++ b/test/e2e/BrsComponents.test.js @@ -42,6 +42,16 @@ describe("end to end brightscript functions", () => { "true", "can empty itself: ", "true", + "array length: ", + " 5", + "array capacity: ", + " 5", + "no change after push: ", + " 5", + "can empty itself: ", + "true", + "same capacity after clear: ", + " 5", "camel,duck,elephant", "camel,duck", "bison,camel,duck,elephant", diff --git a/test/e2e/resources/components/roArray.brs b/test/e2e/resources/components/roArray.brs index b4cb07897..8ba967d82 100644 --- a/test/e2e/resources/components/roArray.brs +++ b/test/e2e/resources/components/roArray.brs @@ -1,4 +1,5 @@ sub Main() + ' resizable array tests arr = createObject("roArray", 5, true) arr.append(["ipsum", "dolor"]) arr.push("sit") @@ -12,24 +13,23 @@ sub Main() arr.clear() print "can empty itself: " arr.isEmpty() ' => true + ' fixed size array tests animals = ["ant", "bison", "camel", "duck", "elephant"] + fixSize = createObject("roArray", 5, false) + fixSize.append(animals) + print "array length: " fixSize.count() ' => 5 + print "array capacity: " fixSize.capacity() ' => 5 + fixSize.push("fox") + print "no change after push: " fixSize.count() ' => 5 + fixSize.clear() + print "can empty itself: " arr.isEmpty() ' => true + print "same capacity after clear: " fixSize.capacity() ' => 5 ' slice tests - print animals.slice(2).join(",") - ' Expected output: camel,duck,elephant - - print animals.slice(2, 4).join(",") - ' Expected output: camel,duck - - print animals.slice(1, 5).join(",") - ' Expected output: bison,camel,duck,elephant - - print animals.slice(-2).join(",") - ' Expected output: duck,elephant - - print animals.slice(2, -1).join(",") - ' Expected output: camel,duck - - print animals.slice().join(",") - ' Expected output: ant,bison,camel,duck,elephant + print animals.slice(2).join(",") ' => camel,duck,elephant + print animals.slice(2, 4).join(",") ' => camel,duck + print animals.slice(1, 5).join(",") ' => bison,camel,duck,elephant + print animals.slice(-2).join(",") ' => duck,elephant + print animals.slice(2, -1).join(",")' => camel,duck + print animals.slice().join(",") ' => ant,bison,camel,duck,elephant end sub