diff --git a/apps/cli/src/config.ts b/apps/cli/src/config.ts index ba1c2622..413e3d9c 100644 --- a/apps/cli/src/config.ts +++ b/apps/cli/src/config.ts @@ -292,7 +292,10 @@ const parseBytes = (value: TomlPrimitive, defaultValue: number): number => { } else if (typeof value === "bigint") { return Number(value); } else if (typeof value === "number" || typeof value === "string") { - return bytes.parse(value); + const output = bytes.parse(value); + if (output !== null) { + return output; + } } throw new InvalidBytesValueError(value); }; diff --git a/apps/cli/test/config.test.ts b/apps/cli/test/config.test.ts index 1845308b..39207482 100644 --- a/apps/cli/test/config.test.ts +++ b/apps/cli/test/config.test.ts @@ -13,8 +13,8 @@ import { RequiredFieldError, } from "../src/config.js"; -describe("config", () => { - it("default config", () => { +describe("when parsing a cartesi.toml config", () => { + it("should load the default config when file is empty", () => { const config = parse(""); expect(config).toEqual(defaultConfig()); }); @@ -45,132 +45,195 @@ shared = true`); }); }); - it("invalid drive", () => { - expect(parse("drives = 42")).toEqual(defaultConfig()); - expect(parse("drives.root = true")).toEqual(defaultConfig()); - expect(parse("drives.root = 42")).toEqual(defaultConfig()); + /** + * [machine] + */ + describe("when parsing [machine]", () => { + const config = ` + [machine] + no-rollup = true + `; + it("machine-config", () => { + expect(parse(config)).toEqual({ + ...defaultConfig(), + machine: { + ...defaultMachineConfig(), + noRollup: true, + }, + }); + }); + it("should fail for invalid bootargs", () => { + const invalidConfig = ` + ${config} + bootargs = ["no4lvl", "quiet", false] + `; + expect(() => parse(invalidConfig)).toThrowError( + new InvalidStringValueError(false), + ); + }); }); - it("invalid drive: invalid builder", () => { - expect(() => parse('[drives.root]\nbuilder = "invalid"')).toThrowError( - new InvalidBuilderError("invalid"), - ); - expect(() => parse("[drives.root]\nbuilder = true")).toThrowError( - new InvalidBuilderError(true), - ); - expect(() => parse("[drives.root]\nbuilder = 10")).toThrowError( - new InvalidBuilderError(10), - ); - expect(() => parse("[drives.root]\nbuilder = {}")).toThrowError( - new InvalidBuilderError({}), - ); - }); + /** + * [drives] + */ + describe("when parsing [drives]", () => { + it("should fail for invalid configuration", () => { + expect(parse("drives = 42")).toEqual(defaultConfig()); + expect(parse("drives.root = true")).toEqual(defaultConfig()); + expect(parse("drives.root = 42")).toEqual(defaultConfig()); + }); - it("invalid drive: invalid format", () => { - expect(() => parse('[drives.root]\nformat = "invalid"')).toThrowError( - new InvalidDriveFormatError("invalid"), - ); - expect(() => parse("[drives.root]\nformat = true")).toThrowError( - new InvalidDriveFormatError(true), - ); - expect(() => parse("[drives.root]\nformat = 10")).toThrowError( - new InvalidDriveFormatError(10), - ); - expect(() => parse("[drives.root]\nformat = {}")).toThrowError( - new InvalidDriveFormatError({}), - ); - }); + it("should fail for invalid builder", () => { + expect(() => + parse('[drives.root]\nbuilder = "invalid"'), + ).toThrowError(new InvalidBuilderError("invalid")); + expect(() => parse("[drives.root]\nbuilder = true")).toThrowError( + new InvalidBuilderError(true), + ); + expect(() => parse("[drives.root]\nbuilder = 10")).toThrowError( + new InvalidBuilderError(10), + ); + expect(() => parse("[drives.root]\nbuilder = {}")).toThrowError( + new InvalidBuilderError({}), + ); + }); - it("invalid drive: invalid extension", () => { - const builderNone = ` - [drives.none] - builder = "none" - filename = "./games/doom.xyzfs" - mount = "/usr/local/games/doom" - `; - expect(() => parse(builderNone)).toThrowError( - new InvalidDriveFormatError(".xyzfs"), - ); - }); + it("should fail for invalid format", () => { + expect(() => + parse('[drives.root]\nformat = "invalid"'), + ).toThrowError(new InvalidDriveFormatError("invalid")); + expect(() => parse("[drives.root]\nformat = true")).toThrowError( + new InvalidDriveFormatError(true), + ); + expect(() => parse("[drives.root]\nformat = 10")).toThrowError( + new InvalidDriveFormatError(10), + ); + expect(() => parse("[drives.root]\nformat = {}")).toThrowError( + new InvalidDriveFormatError({}), + ); + }); - it("invalid drive: invalid mount", () => { - expect(() => parse("[drives.data]\nmount = 42")).toThrowError( - new InvalidStringValueError(42), - ); - }); + it("should fail for invalid filename extension", () => { + const builderNone = ` + [drives.none] + builder = "none" + filename = "./games/doom.xyzfs" + mount = "/usr/local/games/doom" + `; + expect(() => parse(builderNone)).toThrowError( + new InvalidDriveFormatError(".xyzfs"), + ); + }); - it("invalid empty drive: invalid fomat", () => { - expect(() => - parse("[drives.data]\nbuilder = 'empty'\nformat = 42"), - ).toThrowError(new InvalidEmptyDriveFormatError(42)); - }); + it("should fail for invalid mount", () => { + expect(() => parse("[drives.data]\nmount = 42")).toThrowError( + new InvalidStringValueError(42), + ); + }); - it("invalid boolean value", () => { - expect(() => parse("[machine]\nno-rollup = 42")).toThrowError( - new InvalidBooleanValueError(42), - ); + it("should fail for invalid empty drive format", () => { + expect(() => + parse("[drives.data]\nbuilder = 'empty'\nformat = 42"), + ).toThrowError(new InvalidEmptyDriveFormatError(42)); + }); }); - it("invalid number value", () => { - expect(() => parse("[machine]\nmax-mcycle = 'abc'")).toThrowError( - new InvalidNumberValueError("abc"), - ); - }); + /** + * field types + */ + describe("when parsing fields types", () => { + it("should fail for invalid boolean value", () => { + expect(() => parse("[machine]\nno-rollup = 42")).toThrowError( + new InvalidBooleanValueError(42), + ); + }); - it("invalid string value", () => { - const invalidTarDrive = ` - [drives.data] - builder = "tar" - filename = 42 # invalid - format = "ext2" - `; - expect(() => parse(invalidTarDrive)).toThrowError( - new InvalidStringValueError(42), - ); - }); + it("should fail for invalid number value", () => { + expect(() => parse("[machine]\nmax-mcycle = 'abc'")).toThrowError( + new InvalidNumberValueError("abc"), + ); + }); - it("invalid bytes value", () => { - expect(() => parse("[machine]\nram-length = 'abc'")).toThrowError( - new InvalidBytesValueError("abc"), - ); - }); + it("should fail for invalid string value", () => { + const invalidTarDrive = ` + [drives.data] + builder = "tar" + filename = 42 # invalid + format = "ext2" + `; + expect(() => parse(invalidTarDrive)).toThrowError( + new InvalidStringValueError(42), + ); + }); - it("invalid boolean", () => { - expect(() => - parse("[machine]\nassert_rolling_update = 42"), - ).toThrowError(new InvalidBooleanValueError(42)); - }); + it("should fail for invalid bytes value", () => { + const invalidTarDrive = ` + [drives.data] + builder = "tar" + extraSize = "abc" + filename = "data.tar" + format = "ext2" + `; + expect(() => parse(invalidTarDrive)).toThrowError( + new InvalidBytesValueError("abc"), + ); + }); - it("required field", () => { - const invalidDirectoryDrive = ` - [drives.data] - builder = "directory" - # directory = '' # required - `; - expect(() => parse(invalidDirectoryDrive)).toThrowError( - new RequiredFieldError("directory"), //XXX: how to know which field was required - ); - }); + it("should pass for valid bytes value", () => { + // nukmber + expect(() => + parse( + `[drives.data] + builder = "directory" + directory = "/data" + extra-size = 128 + `, + ), + ).not.toThrow(); + // string + expect(() => + parse( + `[drives.data] + builder = "directory" + directory = "/data" + extra-size = "128MB" + `, + ), + ).not.toThrow(); + // bigint + const bigInt = BigInt(128); + expect(() => + parse( + `[drives.data] + builder = "directory" + directory = "/data" + extra-size = ${bigInt} + `, + ), + ).not.toThrow(); + }); - it("machine-config", () => { - const config = ` - [machine] - no-rollup = true - `; - expect(parse(config)).toEqual({ - ...defaultConfig(), - machine: { - ...defaultMachineConfig(), - noRollup: true, - }, + it("should fail for invalid boolean value", () => { + expect(() => parse("[machine]\nfinal-hash = 42")).toThrowError( + new InvalidBooleanValueError(42), + ); }); - const invalidConfig = ` - ${config} - bootargs = ["no4lvl", "quiet", false] - `; - expect(() => parse(invalidConfig)).toThrowError( - new InvalidStringValueError(false), - ); + it("should fail for invalid optional boolean value", () => { + expect(() => + parse("[machine]\nassert-rolling-template = 42"), + ).toThrowError(new InvalidBooleanValueError(42)); + }); + + it("should fail when required field is not defined", () => { + const invalidDirectoryDrive = ` + [drives.data] + builder = "directory" + # directory = '' # required + `; + expect(() => parse(invalidDirectoryDrive)).toThrowError( + new RequiredFieldError("directory"), //XXX: how to know which field was required + ); + }); }); }); diff --git a/apps/cli/test/configs/full.toml b/apps/cli/test/configs/full.toml index 18e6a903..3cfd8a0c 100644 --- a/apps/cli/test/configs/full.toml +++ b/apps/cli/test/configs/full.toml @@ -3,7 +3,7 @@ # runtime = "lambada" # [machine] -# assert_rolling_update = true +# assert-rolling-update = true # bootargs = ["no4lvl", "quiet", "earlycon=sbi", "console=hvc0", "rootfstype=ext2", "root=/dev/pmem0", "rw", "init=/usr/sbin/cartesi-init"] # entrypoint = "/usr/local/bin/app" # final-hash = true