From 014bb0a5b0c73ca443ab9ab96aa85efc5a9e8468 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sat, 9 Jan 2021 14:19:53 -0800 Subject: [PATCH] Check custom board options for required properties boards.txt properties may be defined either directly under the board ID, or in the custom board options. So the schema and rule functions must be made to check both places. Unfortunately, JSON schema doesn't have the capability to define required properties that can be defined at either path, so those rules are now handled in pure Go code. --- ...arduino-boards-txt-definitions-schema.json | 278 ++++++++++++++++-- .../project/platform/boardstxt/boardstxt.go | 27 +- .../boardstxt/boardstxtschema_test.go | 113 +++++-- .../ruleconfiguration/ruleconfiguration.go | 16 - internal/rule/rulefunction/platform.go | 127 +++++--- internal/rule/rulefunction/platform_test.go | 38 +-- .../boards.txt | 8 + .../boards.txt | 10 + .../boards.txt | 8 + .../boards.txt | 8 + .../boards.txt | 9 + .../boards.txt | 9 + .../boardID-name-LT-boards.txt/boards.txt | 9 + .../boards.txt | 8 + .../boards.txt | 10 + .../boards.txt | 9 + .../boards.txt | 9 + .../boards.txt | 8 + .../boards.txt | 8 + .../boards.txt | 8 + .../boards.txt | 8 + .../boards.txt | 8 + .../boards.txt | 8 + .../boards.txt | 9 + .../boards.txt | 9 + .../boards.txt | 10 + internal/rule/schema/schemadata/bindata.go | 278 ++++++++++++++++-- 27 files changed, 911 insertions(+), 139 deletions(-) diff --git a/etc/schemas/arduino-boards-txt-definitions-schema.json b/etc/schemas/arduino-boards-txt-definitions-schema.json index b765a908..86c0567d 100644 --- a/etc/schemas/arduino-boards-txt-definitions-schema.json +++ b/etc/schemas/arduino-boards-txt-definitions-schema.json @@ -137,6 +137,9 @@ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/permissive/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/permissive/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" }, @@ -165,9 +168,6 @@ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" } @@ -202,6 +202,9 @@ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/specification/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/specification/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" }, @@ -230,9 +233,6 @@ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" } @@ -267,6 +267,9 @@ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/strict/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/strict/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" }, @@ -295,9 +298,6 @@ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" } @@ -477,15 +477,130 @@ } } }, - "boardIDMenuMenuIDOptionID": { + "boardIDMenu": { "base": { "object": { "allOf": [ { - "type": "string" + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" }, { - "minLength": 1 + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuIDOptionID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" } ] } @@ -495,6 +610,50 @@ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/permissive/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/permissive/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/permissive/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/permissive/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/permissive/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/permissive/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/permissive/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/permissive/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/permissive/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/permissive/object" } ] } @@ -504,6 +663,50 @@ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/specification/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/specification/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/specification/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/specification/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/specification/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/specification/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/specification/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/specification/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/specification/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/specification/object" } ] } @@ -513,6 +716,50 @@ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/strict/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/strict/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/strict/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/strict/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/strict/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/strict/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/strict/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/strict/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/strict/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/object" } ] } @@ -912,7 +1159,7 @@ "userExtraFlagsProperties": { "propertyNames": { "not": { - "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy.eep)|(elf2hex))\\.extra_flags$" + "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy\\.eep)|(elf2hex))\\.extra_flags$" } } } @@ -935,7 +1182,7 @@ "object": { "allOf": [ { - "required": ["name", "build.core", "upload.tool"] + "required": ["name"] } ] } @@ -963,9 +1210,6 @@ "allOf": [ { "$ref": "#/definitions/requiredObjects/boardID/base/object" - }, - { - "required": ["build.board", "upload.maximum_size", "upload.maximum_data_size"] } ] } diff --git a/internal/project/platform/boardstxt/boardstxt.go b/internal/project/platform/boardstxt/boardstxt.go index 5ee62e23..990ce87c 100644 --- a/internal/project/platform/boardstxt/boardstxt.go +++ b/internal/project/platform/boardstxt/boardstxt.go @@ -20,6 +20,8 @@ See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boards package boardstxt import ( + "strings" + "github.com/arduino/arduino-lint/internal/project/general" "github.com/arduino/arduino-lint/internal/rule/schema" "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" @@ -51,7 +53,30 @@ func Validate(boardsTxt *properties.Map) map[compliancelevel.Type]schema.Validat } //Convert the boards.txt data from the native properties.Map type to the interface type required by the schema validation package. - boardsTxtInterface := general.PropertiesToMap(boardsTxt, 2) + boardsTxtInterface := make(map[string]interface{}) + keys := boardsTxt.FirstLevelKeys() + for _, key := range keys { + if key == "menu" { + // Menu title subproperties are flat. + boardsTxtInterface[key] = general.PropertiesToMap(boardsTxt.SubTree(key), 1) + } else { + boardIDInterface := make(map[string]interface{}) + boardIDProperties := boardsTxt.SubTree(key) + boardIDKeys := boardIDProperties.Keys() + + // Add the standard properties for the board. + for _, boardIDKey := range boardIDKeys { + if !strings.HasPrefix(boardIDKey, "menu.") { + boardIDInterface[boardIDKey] = boardIDProperties.Get(boardIDKey) + } + } + + // Add the custom board option properties for the board, nested down to OPTION_ID. + boardIDInterface["menu"] = general.PropertiesToMap(boardIDProperties.SubTree("menu"), 3) + + boardsTxtInterface[key] = boardIDInterface + } + } validationResults[compliancelevel.Permissive] = schema.Validate(boardsTxtInterface, schemaObject[compliancelevel.Permissive]) validationResults[compliancelevel.Specification] = schema.Validate(boardsTxtInterface, schemaObject[compliancelevel.Specification]) diff --git a/internal/project/platform/boardstxt/boardstxtschema_test.go b/internal/project/platform/boardstxt/boardstxtschema_test.go index ba389000..860e3d50 100644 --- a/internal/project/platform/boardstxt/boardstxtschema_test.go +++ b/internal/project/platform/boardstxt/boardstxtschema_test.go @@ -39,6 +39,7 @@ var validBoardsTxtRaw = []byte(` nano.build.board=AVR_NANO nano.build.core=arduino nano.menu.cpu.atmega328=ATmega328P + nano.menu.cpu.atmega328.upload.maximum_size=30720 `) func TestSchemaValid(t *testing.T) { @@ -71,17 +72,25 @@ func TestMinLength(t *testing.T) { {"foo.build.board", "foo/build\\.board", 1, compliancelevel.Specification}, {"foo.build.board", "foo/build\\.board", 1, compliancelevel.Strict}, + {"foo.menu.bar.baz.build.board", "foo/menu/bar/baz/build\\.board", 1, compliancelevel.Permissive}, + {"foo.menu.bar.baz.build.board", "foo/menu/bar/baz/build\\.board", 1, compliancelevel.Specification}, + {"foo.menu.bar.baz.build.board", "foo/menu/bar/baz/build\\.board", 1, compliancelevel.Strict}, + {"foo.build.core", "foo/build\\.core", 1, compliancelevel.Permissive}, {"foo.build.core", "foo/build\\.core", 1, compliancelevel.Specification}, {"foo.build.core", "foo/build\\.core", 1, compliancelevel.Strict}, - {"foo.menu.bar.baz", "foo/menu\\.bar\\.baz", 1, compliancelevel.Permissive}, - {"foo.menu.bar.baz", "foo/menu\\.bar\\.baz", 1, compliancelevel.Specification}, - {"foo.menu.bar.baz", "foo/menu\\.bar\\.baz", 1, compliancelevel.Strict}, + {"foo.menu.bar.baz.build.core", "foo/menu/bar/baz/build\\.core", 1, compliancelevel.Permissive}, + {"foo.menu.bar.baz.build.core", "foo/menu/bar/baz/build\\.core", 1, compliancelevel.Specification}, + {"foo.menu.bar.baz.build.core", "foo/menu/bar/baz/build\\.core", 1, compliancelevel.Strict}, {"foo.upload.tool", "foo/upload\\.tool", 1, compliancelevel.Permissive}, {"foo.upload.tool", "foo/upload\\.tool", 1, compliancelevel.Specification}, {"foo.upload.tool", "foo/upload\\.tool", 1, compliancelevel.Strict}, + + {"foo.menu.bar.baz.upload.tool", "foo/menu/bar/baz/upload\\.tool", 1, compliancelevel.Permissive}, + {"foo.menu.bar.baz.upload.tool", "foo/menu/bar/baz/upload\\.tool", 1, compliancelevel.Specification}, + {"foo.menu.bar.baz.upload.tool", "foo/menu/bar/baz/upload\\.tool", 1, compliancelevel.Strict}, } // Test schema validation results with value length < minimum. @@ -132,29 +141,9 @@ func TestRequired(t *testing.T) { {"nano.name", "nano/name", compliancelevel.Specification, assert.True}, {"nano.name", "nano/name", compliancelevel.Strict, assert.True}, - {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Permissive, assert.True}, - {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Specification, assert.True}, - {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Strict, assert.True}, - - {"nano.upload.maximum_size", "nano/upload\\.maximum_size", compliancelevel.Permissive, assert.False}, - {"nano.upload.maximum_size", "nano/upload\\.maximum_size", compliancelevel.Specification, assert.False}, - {"nano.upload.maximum_size", "nano/upload\\.maximum_size", compliancelevel.Strict, assert.True}, - - {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", compliancelevel.Permissive, assert.False}, - {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", compliancelevel.Specification, assert.False}, - {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", compliancelevel.Strict, assert.True}, - - {"nano.upload.protocol", "nano/upload\\.protocol", compliancelevel.Permissive, assert.False}, - {"nano.upload.protocol", "nano/upload\\.protocol", compliancelevel.Specification, assert.False}, - {"nano.upload.protocol", "nano/upload\\.protocol", compliancelevel.Strict, assert.False}, - - {"nano.build.board", "nano/build\\.board", compliancelevel.Permissive, assert.False}, - {"nano.build.board", "nano/build\\.board", compliancelevel.Specification, assert.False}, - {"nano.build.board", "nano/build\\.board", compliancelevel.Strict, assert.True}, - - {"nano.build.core", "nano/build\\.core", compliancelevel.Permissive, assert.True}, - {"nano.build.core", "nano/build\\.core", compliancelevel.Specification, assert.True}, - {"nano.build.core", "nano/build\\.core", compliancelevel.Strict, assert.True}, + {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Permissive, assert.False}, + {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Specification, assert.False}, + {"nano.upload.tool", "nano/upload\\.tool", compliancelevel.Strict, assert.False}, } for _, testTable := range testTables { @@ -197,6 +186,16 @@ func TestEnum(t *testing.T) { {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "foo", compliancelevel.Specification, assert.True}, {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.serial.disableDTR", "nano/menu/bar/baz/serial\\.disableDTR", "foo", compliancelevel.Strict, assert.True}, + {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "true", compliancelevel.Permissive, assert.False}, {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "true", compliancelevel.Specification, assert.False}, {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "true", compliancelevel.Strict, assert.False}, @@ -207,6 +206,16 @@ func TestEnum(t *testing.T) { {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "foo", compliancelevel.Specification, assert.True}, {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.serial.disableRTS", "nano/menu/bar/baz/serial\\.disableRTS", "foo", compliancelevel.Strict, assert.True}, + {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "true", compliancelevel.Permissive, assert.False}, {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "true", compliancelevel.Specification, assert.False}, {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "true", compliancelevel.Strict, assert.False}, @@ -217,6 +226,16 @@ func TestEnum(t *testing.T) { {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.use_1200bps_touch", "nano/menu/bar/baz/upload\\.use_1200bps_touch", "foo", compliancelevel.Strict, assert.True}, + {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "true", compliancelevel.Permissive, assert.False}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "true", compliancelevel.Specification, assert.False}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "true", compliancelevel.Strict, assert.False}, @@ -226,6 +245,16 @@ func TestEnum(t *testing.T) { {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "foo", compliancelevel.Permissive, assert.True}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "foo", compliancelevel.Strict, assert.True}, + + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "true", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "true", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "true", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "false", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "false", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "false", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.wait_for_upload_port", "nano/menu/bar/baz/upload\\.wait_for_upload_port", "foo", compliancelevel.Strict, assert.True}, } for _, testTable := range testTables { @@ -256,6 +285,13 @@ func TestPattern(t *testing.T) { {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "123", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "123", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "123", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.maximum_size", "nano/menu/bar/baz/upload\\.maximum_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "123", compliancelevel.Permissive, assert.False}, {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "123", compliancelevel.Specification, assert.False}, {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "123", compliancelevel.Strict, assert.False}, @@ -263,6 +299,13 @@ func TestPattern(t *testing.T) { {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "foo", compliancelevel.Specification, assert.True}, {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "123", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "123", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "123", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.upload.maximum_data_size", "nano/menu/bar/baz/upload\\.maximum_data_size", "foo", compliancelevel.Strict, assert.True}, + {"nano.vid.0", "nano/vid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, {"nano.vid.0", "nano/vid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, {"nano.vid.0", "nano/vid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, @@ -270,12 +313,26 @@ func TestPattern(t *testing.T) { {"nano.vid.0", "nano/vid\\.0", "foo", compliancelevel.Specification, assert.True}, {"nano.vid.0", "nano/vid\\.0", "foo", compliancelevel.Strict, assert.True}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.vid.0", "nano/menu/bar/baz/vid\\.0", "foo", compliancelevel.Strict, assert.True}, + {"nano.pid.0", "nano/pid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, {"nano.pid.0", "nano/pid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, {"nano.pid.0", "nano/pid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, {"nano.pid.0", "nano/pid\\.0", "foo", compliancelevel.Permissive, assert.True}, {"nano.pid.0", "nano/pid\\.0", "foo", compliancelevel.Specification, assert.True}, {"nano.pid.0", "nano/pid\\.0", "foo", compliancelevel.Strict, assert.True}, + + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "0xABCD", compliancelevel.Permissive, assert.False}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "0xABCD", compliancelevel.Specification, assert.False}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "0xABCD", compliancelevel.Strict, assert.False}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "foo", compliancelevel.Permissive, assert.True}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "foo", compliancelevel.Specification, assert.True}, + {"nano.menu.bar.baz.pid.0", "nano/menu/bar/baz/pid\\.0", "foo", compliancelevel.Strict, assert.True}, } for _, testTable := range testTables { @@ -325,6 +382,10 @@ func TestPropertyNames(t *testing.T) { {"nano.compiler.elf2hex.extra_flags", "nano/compiler\\.elf2hex\\.extra_flags", compliancelevel.Permissive, assert.False}, {"nano.compiler.elf2hex.extra_flags", "nano/compiler\\.elf2hex\\.extra_flags", compliancelevel.Specification, assert.False}, {"nano.compiler.elf2hex.extra_flags", "nano/compiler\\.elf2hex\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"nano.menu.foo.bar.compiler.c.extra_flags", "nano/menu/foo/bar/compiler\\.c\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.menu.foo.bar.compiler.c.extra_flags", "nano/menu/foo/bar/compiler\\.c\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.menu.foo.bar.compiler.c.extra_flags", "nano/menu/foo/bar/compiler\\.c\\.extra_flags", compliancelevel.Strict, assert.True}, } for _, testTable := range testTables { diff --git a/internal/rule/ruleconfiguration/ruleconfiguration.go b/internal/rule/ruleconfiguration/ruleconfiguration.go index eb8afb33..604dcc3c 100644 --- a/internal/rule/ruleconfiguration/ruleconfiguration.go +++ b/internal/rule/ruleconfiguration/ruleconfiguration.go @@ -1609,22 +1609,6 @@ var configurations = []Type{ ErrorModes: []rulemode.Type{rulemode.Default}, RuleFunction: rulefunction.BoardsTxtMenuMenuIDLTMinLength, }, - { - ProjectType: projecttype.Platform, - SuperprojectType: projecttype.All, - Category: "configuration files", - Subcategory: "boards.txt", - ID: "PF013", - Brief: "board option < min length", - Description: "", - MessageTemplate: "Custom board option value for board ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#custom-board-options", - DisableModes: nil, - EnableModes: []rulemode.Type{rulemode.Default}, - InfoModes: nil, - WarningModes: nil, - ErrorModes: []rulemode.Type{rulemode.Default}, - RuleFunction: rulefunction.BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength, - }, { ProjectType: projecttype.Platform, SuperprojectType: projecttype.All, diff --git a/internal/rule/rulefunction/platform.go b/internal/rule/rulefunction/platform.go index 8cc61a52..c3d4d2bb 100644 --- a/internal/rule/rulefunction/platform.go +++ b/internal/rule/rulefunction/platform.go @@ -22,6 +22,7 @@ import ( "github.com/arduino/arduino-lint/internal/rule/ruleresult" "github.com/arduino/arduino-lint/internal/rule/schema" "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" + "github.com/sirupsen/logrus" ) // The rule functions for platforms. @@ -83,7 +84,7 @@ func BoardsTxtBoardIDNameLTMinLength() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "name", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "name", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -102,7 +103,7 @@ func BoardsTxtBoardIDBuildBoardMissing() (result ruleresult.Type, output string) return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtBoardIds(), "build\\.board", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtBoardIds(), "build.board") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -121,7 +122,7 @@ func BoardsTxtBoardIDBuildBoardLTMinLength() (result ruleresult.Type, output str return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "build\\.board", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "build\\.board", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -140,7 +141,7 @@ func BoardsTxtBoardIDBuildCoreMissing() (result ruleresult.Type, output string) return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "build\\.core", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "build.core") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -159,7 +160,7 @@ func BoardsTxtBoardIDBuildCoreLTMinLength() (result ruleresult.Type, output stri return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtVisibleBoardIds(), "build\\.core", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtVisibleBoardIds(), "build\\.core", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -202,7 +203,7 @@ func BoardsTxtBoardIDHideInvalid() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "hide", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "hide", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -235,25 +236,6 @@ func BoardsTxtMenuMenuIDLTMinLength() (result ruleresult.Type, output string) { return ruleresult.Pass, "" } -// BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength checks if any of the board menu.MENU_ID.OPTION_ID values are less than the minimum length. -func BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength() (result ruleresult.Type, output string) { - if projectdata.BoardsTxtLoadError() != nil { - return ruleresult.NotRun, "Couldn't load boards.txt" - } - - if len(projectdata.BoardsTxtBoardIds()) == 0 { - return ruleresult.Skip, "boards.txt has no boards" - } - - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "menu\\.[^.]+\\.[^.]+", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) - - if len(nonCompliantBoardIDs) > 0 { - return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") - } - - return ruleresult.Pass, "" -} - // BoardsTxtBoardIDSerialDisableDTRInvalid checks if any of the board serial.disableDTR values are invalid. func BoardsTxtBoardIDSerialDisableDTRInvalid() (result ruleresult.Type, output string) { if projectdata.BoardsTxtLoadError() != nil { @@ -264,7 +246,7 @@ func BoardsTxtBoardIDSerialDisableDTRInvalid() (result ruleresult.Type, output s return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableDTR", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableDTR", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -283,7 +265,7 @@ func BoardsTxtBoardIDSerialDisableRTSInvalid() (result ruleresult.Type, output s return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableRTS", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "serial\\.disableRTS", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -302,7 +284,7 @@ func BoardsTxtBoardIDUploadToolMissing() (result ruleresult.Type, output string) return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload\\.tool", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.tool") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -321,7 +303,7 @@ func BoardsTxtBoardIDUploadToolLTMinLength() (result ruleresult.Type, output str return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "upload\\.tool", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueLTMinLength(projectdata.BoardsTxtBoardIds(), "upload\\.tool", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -340,7 +322,7 @@ func BoardsTxtBoardIDUploadMaximumSizeMissing() (result ruleresult.Type, output return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload\\.maximum_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_size") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -359,7 +341,7 @@ func BoardsTxtBoardIDUploadMaximumSizeInvalid() (result ruleresult.Type, output return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_size", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -378,7 +360,7 @@ func BoardsTxtBoardIDUploadMaximumDataSizeMissing() (result ruleresult.Type, out return ruleresult.Skip, "boards.txt has no visible boards" } - nonCompliantBoardIDs := iDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload\\.maximum_data_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) + nonCompliantBoardIDs := boardIDMissingRequiredProperty(projectdata.BoardsTxtVisibleBoardIds(), "upload.maximum_data_size") if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -397,7 +379,7 @@ func BoardsTxtBoardIDUploadMaximumDataSizeInvalid() (result ruleresult.Type, out return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_data_size", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.maximum_data_size", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -416,7 +398,7 @@ func BoardsTxtBoardIDUploadUse1200bpsTouchInvalid() (result ruleresult.Type, out return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.use_1200bps_touch", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.use_1200bps_touch", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -435,7 +417,7 @@ func BoardsTxtBoardIDUploadWaitForUploadPortInvalid() (result ruleresult.Type, o return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.wait_for_upload_port", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), "upload\\.wait_for_upload_port", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -454,7 +436,7 @@ func BoardsTxtBoardIDVidNInvalid() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "vid\\.[0-9]+", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "vid\\.[0-9]+", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -473,7 +455,7 @@ func BoardsTxtBoardIDPidNInvalid() (result ruleresult.Type, output string) { return ruleresult.Skip, "boards.txt has no boards" } - nonCompliantBoardIDs := iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "pid\\.[0-9]+", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) + nonCompliantBoardIDs := boardIDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), "pid\\.[0-9]+", compliancelevel.Specification) if len(nonCompliantBoardIDs) > 0 { return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") @@ -1760,6 +1742,77 @@ func PlatformTxtBootloaderPatternMissing() (result ruleresult.Type, output strin return ruleresult.Pass, "" } +/* +boardIDMissingRequiredProperty returns the list of board IDs missing the given property. +Unlike iDMissingRequiredProperty(), this function does a direct check on the properties, rather than using the JSON schema validation. +This is necessary because JSON schema does not have the capability to account for the custom board options system. +This function should not be used in cases where the JSON schema does cover a required property. +*/ +func boardIDMissingRequiredProperty(boardIDs []string, propertyName string) []string { + nonCompliantBoardIDs := []string{} + for _, boardID := range boardIDs { + logrus.Tracef("Board ID: %s", boardID) + boardIDHasProperty := func(boardID string, propertyName string) bool { + if projectdata.BoardsTxt().ContainsKey(boardID + "." + propertyName) { + logrus.Trace("Property defined at top level\n") + return true // The board has a first level definition of the property. No need to check custom board options. + + } + + // There is no first level definition of the property, so check if it is provided by the custom board options. + menuProvidesProperty := false + boardMenuProperties := projectdata.BoardsTxt().SubTree(boardID + ".menu") + boardMenuIDs := boardMenuProperties.FirstLevelKeys() + for _, boardMenuID := range boardMenuIDs { + logrus.Tracef("Menu ID: %s\n", boardMenuID) + menuProvidesProperty = true + + boardOptionProperties := boardMenuProperties.SubTree(boardMenuID) + boardOptionIDs := boardOptionProperties.FirstLevelKeys() + for _, boardOptionID := range boardOptionIDs { + if !boardOptionProperties.ContainsKey(boardOptionID + "." + propertyName) { + logrus.Tracef("Option ID %s doesn't provide property\n", boardOptionID) + menuProvidesProperty = false // Every option associated with the menuID must define the property. + break + } + } + + if menuProvidesProperty { + // The menu provided the property so no need to continue. + logrus.Trace("Menu provides property\n") + return true + } + } + + return false // None of the menus provided the property. + } + + if !boardIDHasProperty(boardID, propertyName) { + nonCompliantBoardIDs = append(nonCompliantBoardIDs, boardID) + } + } + + return nonCompliantBoardIDs +} + +// boardIDValueLTMinLength returns the list of board IDs with value of the given property less than the minimum length. +func boardIDValueLTMinLength(boardIDs []string, propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + nonCompliantBoardIDs := iDValueLTMinLength(boardIDs, propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) + return append(nonCompliantBoardIDs, iDValueLTMinLength(boardIDs, "menu/[^.]+/[^.]+/"+propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel])...) +} + +// boardIDValueEnumMismatch returns the list of board IDs with value of the given property less than the minimum length. +func boardIDValueEnumMismatch(boardIDs []string, propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + nonCompliantBoardIDs := iDValueEnumMismatch(boardIDs, propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) + return append(nonCompliantBoardIDs, iDValueEnumMismatch(boardIDs, "menu/[^.]+/[^.]+/"+propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel])...) +} + +// boardIDValuePatternMismatch returns the list of board IDs with value of the given property less than the minimum length. +func boardIDValuePatternMismatch(boardIDs []string, propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + nonCompliantBoardIDs := iDValuePatternMismatch(boardIDs, propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) + return append(nonCompliantBoardIDs, iDValuePatternMismatch(boardIDs, "menu/[^.]+/[^.]+/"+propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel])...) +} + // programmerIDMissingRequiredProperty returns the list of programmer IDs missing the given required property. func programmerIDMissingRequiredProperty(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { return iDMissingRequiredProperty(projectdata.ProgrammersTxtProgrammerIds(), propertyNameQuery, projectdata.ProgrammersTxtSchemaValidationResult()[complianceLevel]) diff --git a/internal/rule/rulefunction/platform_test.go b/internal/rule/rulefunction/platform_test.go index aa83ec0f..0679f715 100644 --- a/internal/rule/rulefunction/platform_test.go +++ b/internal/rule/rulefunction/platform_test.go @@ -87,7 +87,7 @@ func TestBoardsTxtBoardIDNameMissing(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property missing", "boardID-name-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property missing", "boardID-name-missing-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -123,7 +123,7 @@ func TestBoardsTxtBoardIDBuildBoardLTMinLength(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-build-board-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property LT min", "boardID-build-board-LT-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -147,7 +147,7 @@ func TestBoardsTxtBoardIDBuildCoreLTMinLength(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-build-core-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property LT min", "boardID-build-core-LT-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -159,7 +159,7 @@ func TestBoardsTxtUserExtraFlagsUsage(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Use of user extra flags", "boardID-compiler-x-extra_flags-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Use of user extra flags", "boardID-compiler-x-extra_flags-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -190,24 +190,12 @@ func TestBoardsTxtMenuMenuIDLTMinLength(t *testing.T) { checkPlatformRuleFunction(BoardsTxtMenuMenuIDLTMinLength, testTables, t) } -func TestBoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength(t *testing.T) { - testTables := []platformRuleFunctionTestTable{ - {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, - {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, - {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-menu-menuID-LT-boards.txt", ruleresult.Fail, "buno, funo"}, - {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, - } - - checkPlatformRuleFunction(BoardsTxtBoardIDMenuMenuIDOptionIDLTMinLength, testTables, t) -} - func TestBoardsTxtBoardIDSerialDisableDTRInvalid(t *testing.T) { testTables := []platformRuleFunctionTestTable{ {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-serial-disableDTR-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-serial-disableDTR-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -219,7 +207,7 @@ func TestBoardsTxtBoardIDSerialDisableRTSInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-serial-disableRTS-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-serial-disableRTS-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -243,7 +231,7 @@ func TestBoardsTxtBoardIDUploadToolLTMinLength(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property LT min", "boardID-upload-tool-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property LT min", "boardID-upload-tool-LT-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -267,7 +255,7 @@ func TestBoardsTxtBoardIDUploadMaximumSizeInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-maximum_size-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-maximum_size-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -291,7 +279,7 @@ func TestBoardsTxtBoardIDUploadMaximumDataSizeInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-maximum_data_size-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-maximum_data_size-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -303,7 +291,7 @@ func TestBoardsTxtBoardIDUploadUse1200bpsTouchInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-use_1200bps_touch-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-use_1200bps_touch-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -315,7 +303,7 @@ func TestBoardsTxtBoardIDUploadWaitForUploadPortInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-upload-wait_for_upload_port-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-upload-wait_for_upload_port-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -327,7 +315,7 @@ func TestBoardsTxtBoardIDVidNInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-vid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-vid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } @@ -339,7 +327,7 @@ func TestBoardsTxtBoardIDPidNInvalid(t *testing.T) { {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, {"No boards", "no-boards-boards.txt", ruleresult.Skip, ""}, - {"Property invalid", "boardID-pid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Property invalid", "boardID-pid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo, zuno"}, {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, } diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt index f0cd6bd1..78036f25 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.board= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt index 9da39ca0..56352639 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt @@ -19,3 +19,13 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.board=ZUNO +zuno.menu.foo.baz.asdf=ZUNO +#zuno.menu.foo.bar.build.board=ZUNO diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt index 02ec763f..511d4e43 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.core= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt index 96a3e3e7..5a0a051f 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.build.core=arduino diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt index e3399fa0..6b1d7f07 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt @@ -23,3 +23,12 @@ funo.compiler.objcopy.eep.extra_flags=foo funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.compiler.cpp.extra_flags=bar diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt index 9a28652c..14678f13 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.hide=false funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.hide=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt index 6e26f427..1ecdb79e 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt @@ -21,3 +21,12 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.name= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt index 5287f67e..26e45663 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.name=zuno diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt index 5896bfb5..b27b144f 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt @@ -27,3 +27,13 @@ funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.vid.0=0xABCD funo.pid.0=foo + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.vid.0=0xABCD +zuno.menu.foo.bar.pid.0=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt index ec066e92..3c2bdb15 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.serial.disableDTR=foo funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.serial.disableDTR=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt index b6aca5d0..8b240560 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.serial.disableRTS=foo funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.serial.disableRTS=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt index 8670c7cf..4cc0c147 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=fpp + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.menu.foo.bar.upload.maximum_data_size=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt index 737e0e81..31496046 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.core=arduino funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=32256 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.menu.foo.bar.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt index 3dd41ae0..40ac46f9 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_size=foo funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.maximum_size=baz diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt index 43cb6eb9..1bd680a7 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.core=arduino funo.build.variant=standard funo.upload.tool=avrdude funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.maximum_size=32256 diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt index 43228283..098c8075 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt @@ -21,3 +21,11 @@ funo.build.variant=standard funo.upload.tool= funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.tool= diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt index 8ac786b2..7116593b 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt @@ -19,3 +19,11 @@ funo.build.core=arduino funo.build.variant=standard funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.tool=avrdude diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt index ab8afe81..27b68f20 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.upload.use_1200bps_touch=foo + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.use_1200bps_touch=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt index fc75822b..1100a9c8 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt @@ -24,3 +24,12 @@ funo.upload.tool=avrdude funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.upload.wait_for_upload_port=foo + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.upload.wait_for_upload_port=foo diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt index 0bf43958..5fb03f66 100644 --- a/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt @@ -27,3 +27,13 @@ funo.upload.maximum_size=32256 funo.upload.maximum_data_size=2048 funo.vid.0=foo funo.pid.0=0xABCD + +zuno.name=Zuno +zuno.build.board=ZUNO +zuno.build.core=arduino +zuno.build.variant=standard +zuno.upload.tool=avrdude +zuno.upload.maximum_size=32256 +zuno.upload.maximum_data_size=2048 +zuno.menu.foo.bar.vid.0=foo +zuno.menu.foo.bar.pid.0=0xABCD diff --git a/internal/rule/schema/schemadata/bindata.go b/internal/rule/schema/schemadata/bindata.go index 2d5f1ada..9ae12045 100644 --- a/internal/rule/schema/schemadata/bindata.go +++ b/internal/rule/schema/schemadata/bindata.go @@ -209,6 +209,9 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/permissive/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/permissive/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" }, @@ -237,9 +240,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" } @@ -274,6 +274,9 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/specification/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/specification/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" }, @@ -302,9 +305,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" } @@ -339,6 +339,9 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "hide": { "$ref": "#/definitions/propertiesObjects/boardIDHide/strict/object" }, + "menu": { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/strict/object" + }, "serial.disableDTR": { "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" }, @@ -367,9 +370,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ }, { "patternProperties": { - "^menu\\.[^.]+\\.[^.]+$": { - "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" - }, "^[vp]id\\.[0-9]+$": { "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" } @@ -549,15 +549,130 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ } } }, - "boardIDMenuMenuIDOptionID": { + "boardIDMenu": { "base": { "object": { "allOf": [ { - "type": "string" + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" }, { - "minLength": 1 + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenu/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" + } + } + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" + } + } + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuID/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" + } + } + } + ] + } + } + }, + "boardIDMenuMenuIDOptionID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" } ] } @@ -567,6 +682,50 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/permissive/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/permissive/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/permissive/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/permissive/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/permissive/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/permissive/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/permissive/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/permissive/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/permissive/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/permissive/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/permissive/object" } ] } @@ -576,6 +735,50 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/specification/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/specification/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/specification/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/specification/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/specification/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/specification/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/specification/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/specification/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/specification/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/specification/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/specification/object" } ] } @@ -585,6 +788,50 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + }, + { + "properties": { + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/strict/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/strict/object" + }, + "serial.disableDTR": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/strict/object" + }, + "serial.disableRTS": { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/strict/object" + }, + "upload.maximum_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/strict/object" + }, + "upload.maximum_data_size": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/strict/object" + }, + "upload.protocol": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/strict/object" + }, + "upload.tool": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/strict/object" + }, + "upload.use_1200bps_touch": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/strict/object" + }, + "upload.wait_for_upload_port": { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/strict/object" + } + } + }, + { + "patternProperties": { + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/object" } ] } @@ -984,7 +1231,7 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "userExtraFlagsProperties": { "propertyNames": { "not": { - "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy.eep)|(elf2hex))\\.extra_flags$" + "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy\\.eep)|(elf2hex))\\.extra_flags$" } } } @@ -1007,7 +1254,7 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "object": { "allOf": [ { - "required": ["name", "build.core", "upload.tool"] + "required": ["name"] } ] } @@ -1035,9 +1282,6 @@ var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ "allOf": [ { "$ref": "#/definitions/requiredObjects/boardID/base/object" - }, - { - "required": ["build.board", "upload.maximum_size", "upload.maximum_data_size"] } ] }