diff --git a/Taskfile.yml b/Taskfile.yml index 8e4ae0683..130ba1ff8 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -41,7 +41,7 @@ tasks: schema:compile: desc: Compile JSON schema cmds: - - npx ajv-cli compile -s "./etc/schema/*.json" + - npx ajv-cli compile -s "./etc/schemas/*.json" check: desc: Lint and check formatting of all files diff --git a/etc/schemas/arduino-boards-txt-definitions-schema.json b/etc/schemas/arduino-boards-txt-definitions-schema.json new file mode 100644 index 000000000..5f01879e4 --- /dev/null +++ b/etc/schemas/arduino-boards-txt-definitions-schema.json @@ -0,0 +1,981 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-definitions-schema.json", + "title": "Shared definitions for the Arduino boards.txt schemas", + "definitions": { + "propertiesObjects": { + "menu": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/menuMenuID/permissive/object" + } + }, + "additionalProperties": false + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/menuMenuID/specification/object" + } + }, + "additionalProperties": false + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menu/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/menuMenuID/permissive/object" + } + }, + "additionalProperties": false + } + ] + } + } + }, + "menuMenuID": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menuMenuID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menuMenuID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menuMenuID/base/object" + } + ] + } + } + }, + "boardID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/boardIDName/permissive/object" + }, + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/permissive/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/permissive/object" + }, + "hide": { + "$ref": "#/definitions/propertiesObjects/boardIDHide/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": { + "menu\\..+\\..+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" + }, + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/permissive/object" + }, + { + "$ref": "#/definitions/requiredObjects/boardID/permissive/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/boardIDName/specification/object" + }, + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/specification/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/specification/object" + }, + "hide": { + "$ref": "#/definitions/propertiesObjects/boardIDHide/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": { + "menu\\..+\\..+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" + }, + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/specification/object" + }, + { + "$ref": "#/definitions/requiredObjects/boardID/specification/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/boardIDName/strict/object" + }, + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/strict/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/strict/object" + }, + "hide": { + "$ref": "#/definitions/propertiesObjects/boardIDHide/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": { + "menu\\..+\\..+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" + }, + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/object" + }, + { + "$ref": "#/definitions/requiredObjects/boardID/strict/object" + } + ] + } + } + }, + "boardIDName": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDName/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDName/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDName/base/object" + } + ] + } + } + }, + "boardIDBuildBoard": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + } + }, + "boardIDBuildCore": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + } + }, + "boardIDHide": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDHide/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDHide/base/object" + }, + { + "enum": [""] + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDHide/specification/object" + } + ] + } + } + }, + "boardIDMenuMenuIDOptionID": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + } + ] + } + } + }, + "boardIDSerialDisableDTR": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/base/object" + } + ] + } + } + }, + "boardIDSerialDisableRTS": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/base/object" + } + ] + } + } + }, + "boardIDUploadMaximumSize": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "pattern": "^[0-9]+$" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/base/object" + } + ] + } + } + }, + "boardIDUploadMaximumDataSize": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "pattern": "^[0-9]+$" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/base/object" + } + ] + } + } + }, + "boardIDUploadProtocol": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/base/object" + } + ] + } + } + }, + "boardIDUploadTool": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/base/object" + } + ] + } + } + }, + "boardIDUploadUse1200bpsTouch": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/base/object" + } + ] + } + } + }, + "boardIDUploadWaitForUploadPort": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/base/object" + } + ] + } + } + }, + "boardIDXidN": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "pattern": "^0[xX][0-9a-fA-F]{4}$" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/base/object" + } + ] + } + } + } + }, + "propertyNamesObjects": { + "base": { + "object": {} + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertyNamesObjects/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertyNamesObjects/base/object" + } + ] + } + }, + "strict": { + "definitions": { + "userExtraFlagsProperties": { + "propertyNames": { + "not": { + "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy.eep)|(elf2hex))\\.extra_flags$" + } + } + } + }, + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertyNamesObjects/base/object" + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/definitions/userExtraFlagsProperties" + } + ] + } + } + }, + "requiredObjects": { + "boardID": { + "base": { + "object": { + "allOf": [ + { + "required": ["name", "build.core", "upload.tool"] + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/boardID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/boardID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/boardID/base/object" + }, + { + "required": ["build.board", "upload.maximum_size", "upload.maximum_data_size"] + } + ] + } + } + } + }, + "enumObjects": { + "booleanString": { + "enum": ["true", "false"] + } + } + } +} diff --git a/etc/schemas/arduino-boards-txt-permissive-schema.json b/etc/schemas/arduino-boards-txt-permissive-schema.json new file mode 100644 index 000000000..e9709c457 --- /dev/null +++ b/etc/schemas/arduino-boards-txt-permissive-schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-permissive-schema.json", + "title": "Arduino boards.txt JSON permissive schema", + "description": "boards.txt contains the boards definitions of Arduino platforms. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + "$comment": "For information on the boards.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "properties": { + "menu": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/menu/permissive/object" + } + }, + "patternProperties": { + "^([^m].*|m([^e].*)?|me([^n].*)?|men([^u].*)?|menu.+)$": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/boardID/permissive/object" + } + } +} diff --git a/etc/schemas/arduino-boards-txt-schema.json b/etc/schemas/arduino-boards-txt-schema.json new file mode 100644 index 000000000..74fca4f29 --- /dev/null +++ b/etc/schemas/arduino-boards-txt-schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-schema.json", + "title": "Arduino boards.txt JSON schema", + "description": "boards.txt contains the boards definitions of Arduino platforms. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + "$comment": "For information on the boards.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "properties": { + "menu": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/menu/specification/object" + } + }, + "patternProperties": { + "^([^m].*|m([^e].*)?|me([^n].*)?|men([^u].*)?|menu.+)$": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/boardID/specification/object" + } + } +} diff --git a/etc/schemas/arduino-boards-txt-strict-schema.json b/etc/schemas/arduino-boards-txt-strict-schema.json new file mode 100644 index 000000000..4603c4e1f --- /dev/null +++ b/etc/schemas/arduino-boards-txt-strict-schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-strict-schema.json", + "title": "Arduino boards.txt JSON strict schema", + "description": "boards.txt contains the boards definitions of Arduino platforms. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + "$comment": "For information on the boards.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "properties": { + "menu": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/menu/strict/object" + } + }, + "patternProperties": { + "^([^m].*|m([^e].*)?|me([^n].*)?|men([^u].*)?|menu.+)$": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/boardID/strict/object" + } + } +} diff --git a/etc/schemas/arduino-library-properties-definitions-schema.json b/etc/schemas/arduino-library-properties-definitions-schema.json index 03e7aac2a..acb398704 100644 --- a/etc/schemas/arduino-library-properties-definitions-schema.json +++ b/etc/schemas/arduino-library-properties-definitions-schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-definitions-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-definitions-schema.json", "title": "Shared definitions for the Arduino library.properties schemas", "type": "object", "definitions": { diff --git a/etc/schemas/arduino-library-properties-permissive-schema.json b/etc/schemas/arduino-library-properties-permissive-schema.json index 3b51ecb55..9bf33b109 100644 --- a/etc/schemas/arduino-library-properties-permissive-schema.json +++ b/etc/schemas/arduino-library-properties-permissive-schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-permissive-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-permissive-schema.json", "title": "Arduino library.properties JSON permissive schema", "description": "library.properties is the metadata file for Arduino libraries. This schema defines the minimum requirements for this file. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-metadata", "$comment": "For information on the Arduino library.properties format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", diff --git a/etc/schemas/arduino-library-properties-schema.json b/etc/schemas/arduino-library-properties-schema.json index 847c234a1..ab1cadda2 100644 --- a/etc/schemas/arduino-library-properties-schema.json +++ b/etc/schemas/arduino-library-properties-schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-schema.json", "title": "Arduino library.properties JSON schema", "description": "library.properties is the metadata file for Arduino libraries. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-metadata", "$comment": "For information on the Arduino library.properties format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", diff --git a/etc/schemas/arduino-library-properties-strict-schema.json b/etc/schemas/arduino-library-properties-strict-schema.json index b8b169a44..dc708edcc 100644 --- a/etc/schemas/arduino-library-properties-strict-schema.json +++ b/etc/schemas/arduino-library-properties-strict-schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-strict-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-strict-schema.json", "title": "Arduino library.properties strict JSON schema", "description": "library.properties is the metadata file for Arduino libraries. This schema defines the recommended format. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-metadata", "$comment": "For information on the Arduino library.properties format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", diff --git a/etc/schemas/arduino-programmers-txt-definitions-schema.json b/etc/schemas/arduino-programmers-txt-definitions-schema.json new file mode 100644 index 000000000..d59967dc0 --- /dev/null +++ b/etc/schemas/arduino-programmers-txt-definitions-schema.json @@ -0,0 +1,208 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-definitions-schema.json", + "title": "Shared definitions for the Arduino programmers.txt schemas", + "definitions": { + "propertiesObjects": { + "programmerID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/programmerIDName/permissive/object" + }, + "program.tool": { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/permissive/object" + } + } + }, + { + "$ref": "#/definitions/requiredObjects/programmerID/permissive/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/programmerIDName/specification/object" + }, + "program.tool": { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/specification/object" + } + } + }, + { + "$ref": "#/definitions/requiredObjects/programmerID/specification/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/programmerIDName/strict/object" + }, + "program.tool": { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/strict/object" + } + } + }, + { + "$ref": "#/definitions/requiredObjects/programmerID/strict/object" + } + ] + } + } + }, + "programmerIDName": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDName/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDName/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDName/base/object" + } + ] + } + } + }, + "programmerIDProgramTool": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/base/object" + } + ] + } + } + } + }, + "requiredObjects": { + "programmerID": { + "base": { + "object": { + "allOf": [ + { + "required": ["name", "program.tool"] + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/programmerID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/programmerID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/programmerID/base/object" + } + ] + } + } + } + } + } +} diff --git a/etc/schemas/arduino-programmers-txt-permissive-schema.json b/etc/schemas/arduino-programmers-txt-permissive-schema.json new file mode 100644 index 000000000..7a1cd4468 --- /dev/null +++ b/etc/schemas/arduino-programmers-txt-permissive-schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-permissive-schema.json", + "title": "Arduino programmers.txt JSON permissive schema", + "description": "programmers.txt contains the definitions of Arduino hardware programmers. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + "$comment": "For information on the programmers.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "patternProperties": { + ".+": { + "$ref": "arduino-programmers-txt-definitions-schema.json#/definitions/propertiesObjects/programmerID/permissive/object" + } + } +} diff --git a/etc/schemas/arduino-programmers-txt-schema.json b/etc/schemas/arduino-programmers-txt-schema.json new file mode 100644 index 000000000..fd101f23d --- /dev/null +++ b/etc/schemas/arduino-programmers-txt-schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-schema.json", + "title": "Arduino programmers.txt JSON schema", + "description": "programmers.txt contains the definitions of Arduino hardware programmers. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + "$comment": "For information on the programmers.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "patternProperties": { + ".+": { + "$ref": "arduino-programmers-txt-definitions-schema.json#/definitions/propertiesObjects/programmerID/specification/object" + } + } +} diff --git a/etc/schemas/arduino-programmers-txt-strict-schema.json b/etc/schemas/arduino-programmers-txt-strict-schema.json new file mode 100644 index 000000000..6f8c45daa --- /dev/null +++ b/etc/schemas/arduino-programmers-txt-strict-schema.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-strict-schema.json", + "title": "Arduino programmers.txt JSON strict schema", + "description": "programmers.txt contains the definitions of Arduino hardware programmers. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + "$comment": "For information on the programmers.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "patternProperties": { + ".+": { + "$ref": "arduino-programmers-txt-definitions-schema.json#/definitions/propertiesObjects/programmerID/strict/object" + } + } +} diff --git a/etc/schemas/general-definitions-schema.json b/etc/schemas/general-definitions-schema.json index 3c192b1a5..513aff82c 100644 --- a/etc/schemas/general-definitions-schema.json +++ b/etc/schemas/general-definitions-schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/general-definitions-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/general-definitions-schema.json", "title": "Shared definitions", "description": "Definitions for use in schemas.", "type": "object", diff --git a/internal/project/general/general.go b/internal/project/general/general.go new file mode 100644 index 000000000..7f730aefd --- /dev/null +++ b/internal/project/general/general.go @@ -0,0 +1,44 @@ +// This file is part of arduino-lint. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-lint. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +// Package general provides functions that apply to multiple project types. +package general + +import ( + "github.com/arduino/go-properties-orderedmap" +) + +/* +PropertiesToFirstLevelExpandedMap converts properties.Map data structures to map[string]interface that maps between . +Even though boards/properties.txt have a multi-level nested data structure, the format has the odd characteristic of +allowing a key to be both an object and a string simultaneously, which is not compatible with Golang maps or JSON. So +the data structure used is a map of the first level keys (necessary to accommodate the board/prograrmmer IDs) to the +full remainder of the keys (rather than recursing through each key level individually), to string values. +*/ +func PropertiesToFirstLevelExpandedMap(flatProperties *properties.Map) map[string]interface{} { + propertiesInterface := make(map[string]interface{}) + keys := flatProperties.FirstLevelKeys() + for _, key := range keys { + subtreeMap := flatProperties.SubTree(key).AsMap() + // This level also must be converted to map[string]interface{}. + subtreeInterface := make(map[string]interface{}) + for subtreeKey, subtreeValue := range subtreeMap { + subtreeInterface[subtreeKey] = subtreeValue + } + propertiesInterface[key] = subtreeInterface + } + + return propertiesInterface +} diff --git a/internal/project/general/general_test.go b/internal/project/general/general_test.go new file mode 100644 index 000000000..a8699c3e0 --- /dev/null +++ b/internal/project/general/general_test.go @@ -0,0 +1,47 @@ +// This file is part of arduino-lint. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-lint. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package general + +import ( + "reflect" + "testing" + + "github.com/arduino/go-properties-orderedmap" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPropertiesToFirstLevelExpandedMap(t *testing.T) { + rawProperties := []byte(` + foo.bar=asdf + foo.baz=zxcv + bar.bat.bam=123 + `) + propertiesInput, err := properties.LoadFromBytes(rawProperties) + require.Nil(t, err) + + expectedMapOutput := map[string]interface{}{ + "foo": map[string]interface{}{ + "bar": "asdf", + "baz": "zxcv", + }, + "bar": map[string]interface{}{ + "bat.bam": "123", + }, + } + + assert.True(t, reflect.DeepEqual(expectedMapOutput, PropertiesToFirstLevelExpandedMap(propertiesInput))) +} diff --git a/internal/project/library/libraryproperties/libraryproperties.go b/internal/project/library/libraryproperties/libraryproperties.go index 7bf4f5f26..40b1b7591 100644 --- a/internal/project/library/libraryproperties/libraryproperties.go +++ b/internal/project/library/libraryproperties/libraryproperties.go @@ -46,9 +46,17 @@ func Validate(libraryProperties *properties.Map) map[compliancelevel.Type]schema schemaObject[compliancelevel.Strict] = schema.Compile("arduino-library-properties-strict-schema.json", referencedSchemaFilenames, schemadata.Asset) } - validationResults[compliancelevel.Permissive] = schema.Validate(libraryProperties, schemaObject[compliancelevel.Permissive]) - validationResults[compliancelevel.Specification] = schema.Validate(libraryProperties, schemaObject[compliancelevel.Specification]) - validationResults[compliancelevel.Strict] = schema.Validate(libraryProperties, schemaObject[compliancelevel.Strict]) + // Convert the library.properties data from the native properties.Map type to the interface type required by the schema + // validation package. + libraryPropertiesMap := libraryProperties.AsMap() + libraryPropertiesInterface := make(map[string]interface{}, len(libraryPropertiesMap)) + for k, v := range libraryPropertiesMap { + libraryPropertiesInterface[k] = v + } + + validationResults[compliancelevel.Permissive] = schema.Validate(libraryPropertiesInterface, schemaObject[compliancelevel.Permissive]) + validationResults[compliancelevel.Specification] = schema.Validate(libraryPropertiesInterface, schemaObject[compliancelevel.Specification]) + validationResults[compliancelevel.Strict] = schema.Validate(libraryPropertiesInterface, schemaObject[compliancelevel.Strict]) return validationResults } diff --git a/internal/project/platform/boardstxt/boardstxt.go b/internal/project/platform/boardstxt/boardstxt.go index e46848f29..860b8f60f 100644 --- a/internal/project/platform/boardstxt/boardstxt.go +++ b/internal/project/platform/boardstxt/boardstxt.go @@ -20,11 +20,63 @@ See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boards package boardstxt import ( + "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" + "github.com/arduino/arduino-lint/internal/rule/schema/schemadata" "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" ) -// Properties parses the library.properties from the given path and returns the data. +// Properties parses the boards.txt from the given path and returns the data. func Properties(platformPath *paths.Path) (*properties.Map, error) { - return properties.SafeLoadFromPath(platformPath.Join("boards.txt")) + return properties.LoadFromPath(platformPath.Join("boards.txt")) +} + +var schemaObject = make(map[compliancelevel.Type]schema.Schema) + +// Validate validates boards.txt data against the JSON schema and returns a map of the result for each compliance level. +func Validate(boardsTxt *properties.Map) map[compliancelevel.Type]schema.ValidationResult { + referencedSchemaFilenames := []string{ + "general-definitions-schema.json", + "arduino-boards-txt-definitions-schema.json", + } + + var validationResults = make(map[compliancelevel.Type]schema.ValidationResult) + + if schemaObject[compliancelevel.Permissive].Compiled == nil { // Only compile the schemas once. + schemaObject[compliancelevel.Permissive] = schema.Compile("arduino-boards-txt-permissive-schema.json", referencedSchemaFilenames, schemadata.Asset) + schemaObject[compliancelevel.Specification] = schema.Compile("arduino-boards-txt-schema.json", referencedSchemaFilenames, schemadata.Asset) + schemaObject[compliancelevel.Strict] = schema.Compile("arduino-boards-txt-strict-schema.json", referencedSchemaFilenames, schemadata.Asset) + } + + //Convert the boards.txt data from the native properties.Map type to the interface type required by the schema validation package. + boardsTxtInterface := general.PropertiesToFirstLevelExpandedMap(boardsTxt) + + validationResults[compliancelevel.Permissive] = schema.Validate(boardsTxtInterface, schemaObject[compliancelevel.Permissive]) + validationResults[compliancelevel.Specification] = schema.Validate(boardsTxtInterface, schemaObject[compliancelevel.Specification]) + validationResults[compliancelevel.Strict] = schema.Validate(boardsTxtInterface, schemaObject[compliancelevel.Strict]) + + return validationResults +} + +// MenuIDs returns the list of menu IDs from the given boards.txt properties. +func MenuIDs(boardsTxt *properties.Map) []string { + // Each menu must have a property defining its title with the format `menu.MENU_ID=MENU_TITLE`. + return boardsTxt.SubTree("menu").FirstLevelKeys() +} + +// BoardIDs returns the list of board IDs from the given boards.txt properties. +func BoardIDs(boardsTxt *properties.Map) []string { + boardIDs := boardsTxt.FirstLevelKeys() + boardIDCount := 0 + for _, boardID := range boardIDs { + if boardID != "menu" { + // This element is a board ID, retain it in the section of the array that will be returned. + boardIDs[boardIDCount] = boardID + boardIDCount++ + } + } + + return boardIDs[:boardIDCount] } diff --git a/internal/project/platform/boardstxt/boardstxt_test.go b/internal/project/platform/boardstxt/boardstxt_test.go new file mode 100644 index 000000000..b7be0850b --- /dev/null +++ b/internal/project/platform/boardstxt/boardstxt_test.go @@ -0,0 +1,94 @@ +// This file is part of arduino-lint. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-lint. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package boardstxt + +import ( + "testing" + + "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var testDataPath *paths.Path + +var validBoardsTxtMap map[string]string + +func init() { + workingDirectory, err := paths.Getwd() + if err != nil { + panic(err) + } + testDataPath = workingDirectory.Join("testdata") + + validBoardsTxtMap = map[string]string{ + "uno.name": "Arduino Uno", + "uno.build.board": "AVR_UNO", + "uno.build.core": "arduino", + "uno.upload.tool": "avrdude", + "uno.upload.maximum_size": "123", + "uno.upload.maximum_data_size": "123", + } +} + +func TestProperties(t *testing.T) { + propertiesOutput, err := Properties(testDataPath.Join("valid")) + require.Nil(t, err) + + assert.True(t, properties.NewFromHashmap(validBoardsTxtMap).Equals(propertiesOutput)) +} + +func TestValidate(t *testing.T) { + boardsTxt := properties.NewFromHashmap(validBoardsTxtMap) + validationResult := Validate(boardsTxt) + + assert.Nil(t, validationResult[compliancelevel.Permissive].Result) + assert.Nil(t, validationResult[compliancelevel.Specification].Result) + assert.Nil(t, validationResult[compliancelevel.Strict].Result) + + boardsTxt.Remove("uno.name") // Remove required property. + validationResult = Validate(boardsTxt) + assert.NotNil(t, validationResult[compliancelevel.Permissive].Result) + assert.NotNil(t, validationResult[compliancelevel.Specification].Result) + assert.NotNil(t, validationResult[compliancelevel.Strict].Result) +} + +func TestMenuIDs(t *testing.T) { + boardsTxt := properties.NewFromHashmap(validBoardsTxtMap) + + assert.ElementsMatch(t, []string{}, MenuIDs(boardsTxt), "No menu IDs") + + boardsTxt.Set("menu", "noooo") + assert.ElementsMatch(t, []string{}, MenuIDs(boardsTxt), "Some silly defined a menu property without a subproperty") + + boardsTxt.Set("menu.foo", "asdf") + boardsTxt.Set("menu.bar", "zxcv") + boardsTxt.Set("baz.name", "qwer") + assert.ElementsMatch(t, []string{"foo", "bar"}, MenuIDs(boardsTxt), "Has menu IDs") +} + +func TestBoardIDs(t *testing.T) { + boardsTxt := properties.NewFromHashmap(validBoardsTxtMap) + + assert.ElementsMatch(t, []string{"uno"}, BoardIDs(boardsTxt)) + + boardsTxt.Set("menu.foo", "asdf") + boardsTxt.Set("menu.bar", "zxcv") + boardsTxt.Set("baz.name", "qwer") + assert.ElementsMatch(t, []string{"uno", "baz"}, BoardIDs(boardsTxt)) +} diff --git a/internal/project/platform/boardstxt/boardstxtschema_test.go b/internal/project/platform/boardstxt/boardstxtschema_test.go new file mode 100644 index 000000000..ea3ad2b42 --- /dev/null +++ b/internal/project/platform/boardstxt/boardstxtschema_test.go @@ -0,0 +1,341 @@ +// This file is part of arduino-lint. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-lint. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +// This file contains tests for the boards.txt JSON schema. +package boardstxt_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/arduino/arduino-lint/internal/project/platform/boardstxt" + "github.com/arduino/arduino-lint/internal/rule/schema" + "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" + "github.com/arduino/go-properties-orderedmap" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var validBoardsTxtRaw = []byte(` + menu.cpu=Processor + nano.name=Arduino Nano + nano.upload.tool=avrdude + nano.upload.protocol=arduino + nano.upload.maximum_size=123 + nano.upload.maximum_data_size=123 + nano.build.board=AVR_NANO + nano.build.core=arduino + nano.menu.cpu.atmega328=ATmega328P +`) + +func TestSchemaValid(t *testing.T) { + validBoardsTxtProperties, err := properties.LoadFromBytes(validBoardsTxtRaw) + require.Nil(t, err) + + validationResult := boardstxt.Validate(validBoardsTxtProperties) + + assert.Nil(t, validationResult[compliancelevel.Permissive].Result) + assert.Nil(t, validationResult[compliancelevel.Specification].Result) + assert.Nil(t, validationResult[compliancelevel.Strict].Result) +} + +func TestMinLength(t *testing.T) { + testTables := []struct { + propertyName string + validationErrorPropertyName string + minLength int + complianceLevel compliancelevel.Type + }{ + {"menu.foo", "menu/foo", 1, compliancelevel.Permissive}, + {"menu.foo", "menu/foo", 1, compliancelevel.Specification}, + {"menu.foo", "menu/foo", 1, compliancelevel.Strict}, + + {"foo.name", "foo/name", 1, compliancelevel.Permissive}, + {"foo.name", "foo/name", 1, compliancelevel.Specification}, + {"foo.name", "foo/name", 1, compliancelevel.Strict}, + + {"foo.build.board", "foo/build\\.board", 1, compliancelevel.Permissive}, + {"foo.build.board", "foo/build\\.board", 1, compliancelevel.Specification}, + {"foo.build.board", "foo/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.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}, + } + + // Test schema validation results with value length < minimum. + for _, testTable := range testTables { + boardsTxt, err := properties.LoadFromBytes(validBoardsTxtRaw) + require.Nil(t, err) + boardsTxt.Set(testTable.propertyName, strings.Repeat("a", testTable.minLength-1)) + + t.Run(fmt.Sprintf("%s less than minimum length of %d (%s)", testTable.propertyName, testTable.minLength, testTable.complianceLevel), func(t *testing.T) { + assert.True(t, schema.PropertyLessThanMinLength(testTable.propertyName, boardstxt.Validate(boardsTxt)[testTable.complianceLevel])) + }) + + // Test schema validation results with minimum value length. + boardsTxt, err = properties.LoadFromBytes(validBoardsTxtRaw) + require.Nil(t, err) + boardsTxt.Set(testTable.propertyName, strings.Repeat("a", testTable.minLength)) + + t.Run(fmt.Sprintf("%s at minimum length of %d (%s)", testTable.propertyName, testTable.minLength, testTable.complianceLevel), func(t *testing.T) { + assert.False(t, schema.PropertyLessThanMinLength(testTable.validationErrorPropertyName, boardstxt.Validate(boardsTxt)[testTable.complianceLevel])) + }) + } +} + +func TestEmpty(t *testing.T) { + // None of the root properties are required, so an empty boards.txt is valid. + validBoardsTxtProperties, err := properties.LoadFromBytes([]byte{}) + require.Nil(t, err) + + validationResult := boardstxt.Validate(validBoardsTxtProperties) + + assert.Nil(t, validationResult[compliancelevel.Permissive].Result) + assert.Nil(t, validationResult[compliancelevel.Specification].Result) + assert.Nil(t, validationResult[compliancelevel.Strict].Result) +} + +func TestRequired(t *testing.T) { + testTables := []struct { + propertyName string + validationErrorPropertyName string + complianceLevel compliancelevel.Type + assertion assert.BoolAssertionFunc + }{ + {"menu.cpu", "menu", compliancelevel.Permissive, assert.False}, + {"menu.cpu", "menu", compliancelevel.Specification, assert.False}, + {"menu.cpu", "menu", compliancelevel.Strict, assert.False}, + + {"nano.name", "nano/name", compliancelevel.Permissive, assert.True}, + {"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}, + } + + for _, testTable := range testTables { + boardsTxt, err := properties.LoadFromBytes(validBoardsTxtRaw) + require.Nil(t, err) + boardsTxt.Remove(testTable.propertyName) + + validationResult := boardstxt.Validate(boardsTxt) + t.Run(fmt.Sprintf("%s (%s)", testTable.propertyName, testTable.complianceLevel), func(t *testing.T) { + testTable.assertion(t, schema.RequiredPropertyMissing(testTable.validationErrorPropertyName, validationResult[testTable.complianceLevel])) + }) + } +} + +func TestEnum(t *testing.T) { + testTables := []struct { + propertyName string + validationErrorPropertyName string + propertyValue string + complianceLevel compliancelevel.Type + assertion assert.BoolAssertionFunc + }{ + {"nano.hide", "nano/hide", "true", compliancelevel.Permissive, assert.False}, + {"nano.hide", "nano/hide", "true", compliancelevel.Specification, assert.True}, + {"nano.hide", "nano/hide", "true", compliancelevel.Strict, assert.True}, + {"nano.hide", "nano/hide", "false", compliancelevel.Permissive, assert.False}, + {"nano.hide", "nano/hide", "false", compliancelevel.Specification, assert.True}, + {"nano.hide", "nano/hide", "false", compliancelevel.Strict, assert.True}, + {"nano.hide", "nano/hide", "", compliancelevel.Permissive, assert.False}, + {"nano.hide", "nano/hide", "", compliancelevel.Specification, assert.False}, + {"nano.hide", "nano/hide", "", compliancelevel.Strict, assert.False}, + + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "true", compliancelevel.Permissive, assert.False}, + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "true", compliancelevel.Specification, assert.False}, + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "true", compliancelevel.Strict, assert.False}, + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "false", compliancelevel.Permissive, assert.False}, + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "false", compliancelevel.Specification, assert.False}, + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "false", compliancelevel.Strict, assert.False}, + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "foo", compliancelevel.Permissive, assert.True}, + {"nano.serial.disableDTR", "nano/serial\\.disableDTR", "foo", compliancelevel.Specification, assert.True}, + {"nano.serial.disableDTR", "nano/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}, + {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "false", compliancelevel.Permissive, assert.False}, + {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "false", compliancelevel.Specification, assert.False}, + {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "false", compliancelevel.Strict, assert.False}, + {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "foo", compliancelevel.Permissive, assert.True}, + {"nano.serial.disableRTS", "nano/serial\\.disableRTS", "foo", compliancelevel.Specification, assert.True}, + {"nano.serial.disableRTS", "nano/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}, + {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "false", compliancelevel.Permissive, assert.False}, + {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "false", compliancelevel.Specification, assert.False}, + {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "false", compliancelevel.Strict, assert.False}, + {"nano.upload.use_1200bps_touch", "nano/upload\\.use_1200bps_touch", "foo", compliancelevel.Permissive, assert.True}, + {"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.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}, + {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "false", compliancelevel.Permissive, assert.False}, + {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "false", compliancelevel.Specification, assert.False}, + {"nano.upload.wait_for_upload_port", "nano/upload\\.wait_for_upload_port", "false", compliancelevel.Strict, assert.False}, + {"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}, + } + + for _, testTable := range testTables { + boardsTxt, err := properties.LoadFromBytes(validBoardsTxtRaw) + require.Nil(t, err) + boardsTxt.Set(testTable.propertyName, testTable.propertyValue) + + validationResult := boardstxt.Validate(boardsTxt) + + t.Run(fmt.Sprintf("%s: %s (%s)", testTable.propertyName, testTable.propertyValue, testTable.complianceLevel), func(t *testing.T) { + testTable.assertion(t, schema.PropertyEnumMismatch(testTable.validationErrorPropertyName, validationResult[testTable.complianceLevel])) + }) + } +} + +func TestPattern(t *testing.T) { + testTables := []struct { + propertyName string + validationErrorPropertyName string + propertyValue string + complianceLevel compliancelevel.Type + assertion assert.BoolAssertionFunc + }{ + {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "123", compliancelevel.Permissive, assert.False}, + {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "123", compliancelevel.Specification, assert.False}, + {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "123", compliancelevel.Strict, assert.False}, + {"nano.upload.maximum_size", "nano/upload\\.maximum_size", "foo", compliancelevel.Permissive, assert.True}, + {"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.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}, + {"nano.upload.maximum_data_size", "nano/upload\\.maximum_data_size", "foo", compliancelevel.Permissive, assert.True}, + {"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.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}, + {"nano.vid.0", "nano/vid\\.0", "foo", compliancelevel.Permissive, assert.True}, + {"nano.vid.0", "nano/vid\\.0", "foo", compliancelevel.Specification, assert.True}, + {"nano.vid.0", "nano/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}, + } + + for _, testTable := range testTables { + boardsTxt, err := properties.LoadFromBytes(validBoardsTxtRaw) + require.Nil(t, err) + boardsTxt.Set(testTable.propertyName, testTable.propertyValue) + + validationResult := boardstxt.Validate(boardsTxt) + + t.Run(fmt.Sprintf("%s: %s (%s)", testTable.propertyName, testTable.propertyValue, testTable.complianceLevel), func(t *testing.T) { + testTable.assertion(t, schema.PropertyPatternMismatch(testTable.validationErrorPropertyName, validationResult[testTable.complianceLevel])) + }) + } +} + +func TestPropertyNames(t *testing.T) { + testTables := []struct { + propertyName string + validationErrorPropertyName string + complianceLevel compliancelevel.Type + assertion assert.BoolAssertionFunc + }{ + {"nano.compiler.c.extra_flags", "nano/compiler\\.c\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.compiler.c.extra_flags", "nano/compiler\\.c\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.compiler.c.extra_flags", "nano/compiler\\.c\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"nano.compiler.c.elf.extra_flags", "nano/compiler\\.c\\.elf\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.compiler.c.elf.extra_flags", "nano/compiler\\.c\\.elf\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.compiler.c.elf.extra_flags", "nano/compiler\\.c\\.elf\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"nano.compiler.S.extra_flags", "nano/compiler\\.S\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.compiler.S.extra_flags", "nano/compiler\\.S\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.compiler.S.extra_flags", "nano/compiler\\.S\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"nano.compiler.cpp.extra_flags", "nano/compiler\\.cpp\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.compiler.cpp.extra_flags", "nano/compiler\\.cpp\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.compiler.cpp.extra_flags", "nano/compiler\\.cpp\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"nano.compiler.ar.extra_flags", "nano/compiler\\.ar\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.compiler.ar.extra_flags", "nano/compiler\\.ar\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.compiler.ar.extra_flags", "nano/compiler\\.ar\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"nano.compiler.objcopy.eep.extra_flags", "nano/compiler\\.objcopy\\.eep\\.extra_flags", compliancelevel.Permissive, assert.False}, + {"nano.compiler.objcopy.eep.extra_flags", "nano/compiler\\.objcopy\\.eep\\.extra_flags", compliancelevel.Specification, assert.False}, + {"nano.compiler.objcopy.eep.extra_flags", "nano/compiler\\.objcopy\\.eep\\.extra_flags", compliancelevel.Strict, assert.True}, + + {"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}, + } + + for _, testTable := range testTables { + boardsTxt, err := properties.LoadFromBytes(validBoardsTxtRaw) + require.Nil(t, err) + boardsTxt.Set(testTable.propertyName, "foo") + + validationResult := boardstxt.Validate(boardsTxt) + + t.Run(fmt.Sprintf("%s (%s)", testTable.propertyName, testTable.complianceLevel), func(t *testing.T) { + testTable.assertion(t, schema.ValidationErrorMatch("#/"+testTable.validationErrorPropertyName, "/userExtraFlagsProperties/", "", "", validationResult[testTable.complianceLevel])) + }) + } +} diff --git a/internal/project/platform/boardstxt/testdata/valid/boards.txt b/internal/project/platform/boardstxt/testdata/valid/boards.txt new file mode 100644 index 000000000..f2e1a11eb --- /dev/null +++ b/internal/project/platform/boardstxt/testdata/valid/boards.txt @@ -0,0 +1,6 @@ +uno.name=Arduino Uno +uno.build.board=AVR_UNO +uno.build.core=arduino +uno.upload.tool=avrdude +uno.upload.maximum_size=123 +uno.upload.maximum_data_size=123 diff --git a/internal/project/platform/programmerstxt/programmerstxt.go b/internal/project/platform/programmerstxt/programmerstxt.go new file mode 100644 index 000000000..a3ae6d905 --- /dev/null +++ b/internal/project/platform/programmerstxt/programmerstxt.go @@ -0,0 +1,65 @@ +// This file is part of arduino-lint. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-lint. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +/* +Package programmerstxt provides functions specific to linting the programmers.txt configuration files of Arduino programmers platforms. +See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt +*/ +package programmerstxt + +import ( + "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" + "github.com/arduino/arduino-lint/internal/rule/schema/schemadata" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" +) + +// Properties parses the programmers.txt from the given path and returns the data. +func Properties(platformPath *paths.Path) (*properties.Map, error) { + return properties.LoadFromPath(platformPath.Join("programmers.txt")) +} + +var schemaObject = make(map[compliancelevel.Type]schema.Schema) + +// Validate validates programmers.txt data against the JSON schema and returns the result. +func Validate(programmersTxt *properties.Map) map[compliancelevel.Type]schema.ValidationResult { + referencedSchemaFilenames := []string{ + "arduino-programmers-txt-definitions-schema.json", + } + + var validationResults = make(map[compliancelevel.Type]schema.ValidationResult) + + if schemaObject[compliancelevel.Permissive].Compiled == nil { // Only compile the schemas once. + schemaObject[compliancelevel.Permissive] = schema.Compile("arduino-programmers-txt-permissive-schema.json", referencedSchemaFilenames, schemadata.Asset) + schemaObject[compliancelevel.Specification] = schema.Compile("arduino-programmers-txt-schema.json", referencedSchemaFilenames, schemadata.Asset) + schemaObject[compliancelevel.Strict] = schema.Compile("arduino-programmers-txt-strict-schema.json", referencedSchemaFilenames, schemadata.Asset) + } + + //Convert the programmers.txt data from the native properties.Map type to the interface type required by the schema validation package. + programmersTxtInterface := general.PropertiesToFirstLevelExpandedMap(programmersTxt) + + validationResults[compliancelevel.Permissive] = schema.Validate(programmersTxtInterface, schemaObject[compliancelevel.Permissive]) + validationResults[compliancelevel.Specification] = schema.Validate(programmersTxtInterface, schemaObject[compliancelevel.Specification]) + validationResults[compliancelevel.Strict] = schema.Validate(programmersTxtInterface, schemaObject[compliancelevel.Strict]) + + return validationResults +} + +// ProgrammerIDs returns the list of programmer IDs from the given programmers.txt properties. +func ProgrammerIDs(programmersTxt *properties.Map) []string { + return programmersTxt.FirstLevelKeys() +} diff --git a/internal/project/platform/programmerstxt/programmerstxt_test.go b/internal/project/platform/programmerstxt/programmerstxt_test.go new file mode 100644 index 000000000..886ada27a --- /dev/null +++ b/internal/project/platform/programmerstxt/programmerstxt_test.go @@ -0,0 +1,74 @@ +// This file is part of arduino-lint. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-lint. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package programmerstxt + +import ( + "testing" + + "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var testDataPath *paths.Path + +var validProgrammersTxtMap map[string]string + +func init() { + workingDirectory, err := paths.Getwd() + if err != nil { + panic(err) + } + testDataPath = workingDirectory.Join("testdata") + + validProgrammersTxtMap = map[string]string{ + "usbasp.name": "USBasp", + "usbasp.program.tool": "avrdude", + "usbasp.program.extra_params": "-Pusb", + "arduinoasisp.name": "Arduino as ISP", + "arduinoasisp.program.tool": "avrdude", + } +} + +func TestProperties(t *testing.T) { + propertiesOutput, err := Properties(testDataPath.Join("valid")) + require.Nil(t, err) + + assert.True(t, properties.NewFromHashmap(validProgrammersTxtMap).Equals(propertiesOutput)) +} + +func TestValidate(t *testing.T) { + programmersTxt := properties.NewFromHashmap(validProgrammersTxtMap) + validationResult := Validate(programmersTxt) + + assert.Nil(t, validationResult[compliancelevel.Permissive].Result) + assert.Nil(t, validationResult[compliancelevel.Specification].Result) + assert.Nil(t, validationResult[compliancelevel.Strict].Result) + + programmersTxt.Remove("usbasp.name") // Remove required property. + validationResult = Validate(programmersTxt) + assert.NotNil(t, validationResult[compliancelevel.Permissive].Result) + assert.NotNil(t, validationResult[compliancelevel.Specification].Result) + assert.NotNil(t, validationResult[compliancelevel.Strict].Result) +} + +func TestProgrammerIDs(t *testing.T) { + programmersTxt := properties.NewFromHashmap(validProgrammersTxtMap) + + assert.ElementsMatch(t, []string{"usbasp", "arduinoasisp"}, ProgrammerIDs(programmersTxt)) +} diff --git a/internal/project/platform/programmerstxt/programmerstxtschema_test.go b/internal/project/platform/programmerstxt/programmerstxtschema_test.go new file mode 100644 index 000000000..b989d3f49 --- /dev/null +++ b/internal/project/platform/programmerstxt/programmerstxtschema_test.go @@ -0,0 +1,128 @@ +// This file is part of arduino-lint. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-lint. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +// This file contains tests for the programmers.txt JSON schema. +package programmerstxt_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/arduino/arduino-lint/internal/project/platform/programmerstxt" + "github.com/arduino/arduino-lint/internal/rule/schema" + "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" + "github.com/arduino/go-properties-orderedmap" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var validProgrammersTxtRaw = []byte(` + usbasp.name=USBasp + usbasp.protocol=usbasp + usbasp.program.tool=avrdude +`) + +func TestSchemaValid(t *testing.T) { + validProgrammersTxtProperties, err := properties.LoadFromBytes(validProgrammersTxtRaw) + require.Nil(t, err) + + validationResult := programmerstxt.Validate(validProgrammersTxtProperties) + + assert.Nil(t, validationResult[compliancelevel.Permissive].Result) + assert.Nil(t, validationResult[compliancelevel.Specification].Result) + assert.Nil(t, validationResult[compliancelevel.Strict].Result) +} + +func TestMinLength(t *testing.T) { + testTables := []struct { + propertyName string + validationErrorPropertyName string + minLength int + complianceLevel compliancelevel.Type + }{ + {"foo.name", "foo/name", 1, compliancelevel.Permissive}, + {"foo.name", "foo/name", 1, compliancelevel.Specification}, + {"foo.name", "foo/name", 1, compliancelevel.Strict}, + + {"foo.program.tool", "foo/program\\.tool", 1, compliancelevel.Permissive}, + {"foo.program.tool", "foo/program\\.tool", 1, compliancelevel.Specification}, + {"foo.program.tool", "foo/program\\.tool", 1, compliancelevel.Strict}, + } + + // Test schema validation results with value length < minimum. + for _, testTable := range testTables { + programmersTxt, err := properties.LoadFromBytes(validProgrammersTxtRaw) + require.Nil(t, err) + programmersTxt.Set(testTable.propertyName, strings.Repeat("a", testTable.minLength-1)) + + t.Run(fmt.Sprintf("%s less than minimum length of %d (%s)", testTable.propertyName, testTable.minLength, testTable.complianceLevel), func(t *testing.T) { + assert.True(t, schema.PropertyLessThanMinLength(testTable.propertyName, programmerstxt.Validate(programmersTxt)[testTable.complianceLevel])) + }) + + // Test schema validation results with minimum value length. + programmersTxt, err = properties.LoadFromBytes(validProgrammersTxtRaw) + require.Nil(t, err) + programmersTxt.Set(testTable.propertyName, strings.Repeat("a", testTable.minLength)) + + t.Run(fmt.Sprintf("%s at minimum length of %d (%s)", testTable.propertyName, testTable.minLength, testTable.complianceLevel), func(t *testing.T) { + assert.False(t, schema.PropertyLessThanMinLength(testTable.validationErrorPropertyName, programmerstxt.Validate(programmersTxt)[testTable.complianceLevel])) + }) + } +} + +func TestEmpty(t *testing.T) { + // None of the root properties are required, so an empty programmers.txt is valid. + programmersTxt, err := properties.LoadFromBytes([]byte{}) + require.Nil(t, err) + + validationResult := programmerstxt.Validate(programmersTxt) + + assert.Nil(t, validationResult[compliancelevel.Permissive].Result) + assert.Nil(t, validationResult[compliancelevel.Specification].Result) + assert.Nil(t, validationResult[compliancelevel.Strict].Result) +} + +func TestRequired(t *testing.T) { + testTables := []struct { + propertyName string + validationErrorPropertyName string + complianceLevel compliancelevel.Type + assertion assert.BoolAssertionFunc + }{ + {"usbasp.name", "usbasp/name", compliancelevel.Permissive, assert.True}, + {"usbasp.name", "usbasp/name", compliancelevel.Specification, assert.True}, + {"usbasp.name", "usbasp/name", compliancelevel.Strict, assert.True}, + + {"usbasp.program.tool", "usbasp/program\\.tool", compliancelevel.Permissive, assert.True}, + {"usbasp.program.tool", "usbasp/program\\.tool", compliancelevel.Specification, assert.True}, + {"usbasp.program.tool", "usbasp/program\\.tool", compliancelevel.Strict, assert.True}, + + {"usbasp.foo.bar", "usbasp/foo\\.bar", compliancelevel.Permissive, assert.False}, + {"usbasp.foo.bar", "usbasp/foo\\.bar", compliancelevel.Specification, assert.False}, + {"usbasp.foo.bar", "usbasp/foo\\.bar", compliancelevel.Strict, assert.False}, + } + + for _, testTable := range testTables { + programmersTxt, err := properties.LoadFromBytes(validProgrammersTxtRaw) + require.Nil(t, err) + programmersTxt.Remove(testTable.propertyName) + + validationResult := programmerstxt.Validate(programmersTxt) + t.Run(fmt.Sprintf("%s (%s)", testTable.propertyName, testTable.complianceLevel), func(t *testing.T) { + testTable.assertion(t, schema.RequiredPropertyMissing(testTable.validationErrorPropertyName, validationResult[testTable.complianceLevel])) + }) + } +} diff --git a/internal/project/platform/programmerstxt/testdata/valid/programmers.txt b/internal/project/platform/programmerstxt/testdata/valid/programmers.txt new file mode 100644 index 000000000..482646020 --- /dev/null +++ b/internal/project/platform/programmerstxt/testdata/valid/programmers.txt @@ -0,0 +1,6 @@ +usbasp.name=USBasp +usbasp.program.tool=avrdude +usbasp.program.extra_params=-Pusb + +arduinoasisp.name=Arduino as ISP +arduinoasisp.program.tool=avrdude diff --git a/internal/project/projectdata/platform.go b/internal/project/projectdata/platform.go index abe5b846b..943df121d 100644 --- a/internal/project/projectdata/platform.go +++ b/internal/project/projectdata/platform.go @@ -18,12 +18,37 @@ package projectdata import ( "github.com/arduino/arduino-lint/internal/project" "github.com/arduino/arduino-lint/internal/project/platform/boardstxt" + "github.com/arduino/arduino-lint/internal/project/platform/programmerstxt" + "github.com/arduino/arduino-lint/internal/rule/schema" + "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" "github.com/arduino/go-properties-orderedmap" + "github.com/sirupsen/logrus" ) // InitializeForPlatform gathers the platform rule data for the specified project. func InitializeForPlatform(project project.Type) { boardsTxt, boardsTxtLoadError = boardstxt.Properties(ProjectPath()) + if boardsTxtLoadError != nil { + logrus.Errorf("Error loading boards.txt from %s: %s", project.Path, boardsTxtLoadError) + boardsTxtSchemaValidationResult = nil + } else { + boardsTxtSchemaValidationResult = boardstxt.Validate(boardsTxt) + + boardsTxtMenuIds = boardstxt.MenuIDs(boardsTxt) + boardsTxtBoardIds = boardstxt.BoardIDs(boardsTxt) + } + + programmersTxtExists = ProjectPath().Join("programmers.txt").Exist() + + programmersTxt, programmersTxtLoadError = programmerstxt.Properties(ProjectPath()) + if programmersTxtLoadError != nil { + logrus.Errorf("Error loading programmers.txt from %s: %s", project.Path, programmersTxtLoadError) + programmersTxtSchemaValidationResult = nil + } else { + programmersTxtSchemaValidationResult = programmerstxt.Validate(programmersTxt) + + programmersTxtProgrammerIds = programmerstxt.ProgrammerIDs(programmersTxt) + } } var boardsTxt *properties.Map @@ -39,3 +64,59 @@ var boardsTxtLoadError error func BoardsTxtLoadError() error { return boardsTxtLoadError } + +var boardsTxtSchemaValidationResult map[compliancelevel.Type]schema.ValidationResult + +// BoardsTxtSchemaValidationResult returns the result of validating boards.txt against the JSON schema. +func BoardsTxtSchemaValidationResult() map[compliancelevel.Type]schema.ValidationResult { + return boardsTxtSchemaValidationResult +} + +var boardsTxtMenuIds []string + +// BoardsTxtMenuIds returns the list of menu IDs present in the platform's boards.txt. +func BoardsTxtMenuIds() []string { + return boardsTxtMenuIds +} + +var boardsTxtBoardIds []string + +// BoardsTxtMenuIds returns the list of board IDs present in the platform's boards.txt. +func BoardsTxtBoardIds() []string { + return boardsTxtBoardIds +} + +var programmersTxtExists bool + +// ProgrammersTxtExists returns whether the platform contains a programmer.txt file. +func ProgrammersTxtExists() bool { + return programmersTxtExists +} + +var programmersTxt *properties.Map + +// ProgrammersTxt returns the data from the programmers.txt configuration file. +func ProgrammersTxt() *properties.Map { + return programmersTxt +} + +var programmersTxtLoadError error + +// ProgrammersTxtLoadError returns the error output from loading the programmers.txt configuration file. +func ProgrammersTxtLoadError() error { + return programmersTxtLoadError +} + +var programmersTxtSchemaValidationResult map[compliancelevel.Type]schema.ValidationResult + +// ProgrammersTxtSchemaValidationResult returns the result of validating programmers.txt against the JSON schema. +func ProgrammersTxtSchemaValidationResult() map[compliancelevel.Type]schema.ValidationResult { + return programmersTxtSchemaValidationResult +} + +var programmersTxtProgrammerIds []string + +// ProgrammersTxtProgrammerIds returns the list of board IDs present in the platform's programmers.txt. +func ProgrammersTxtProgrammerIds() []string { + return programmersTxtProgrammerIds +} diff --git a/internal/project/projectdata/platform_test.go b/internal/project/projectdata/platform_test.go index f83baaec8..77520a4f4 100644 --- a/internal/project/projectdata/platform_test.go +++ b/internal/project/projectdata/platform_test.go @@ -43,7 +43,7 @@ func TestInitializeForPlatform(t *testing.T) { }{ {"Valid", "valid-boards.txt", assert.NotNil, assert.Nil}, {"Invalid", "invalid-boards.txt", assert.Nil, assert.NotNil}, - {"Missing", "missing-boards.txt", assert.NotNil, assert.Nil}, + {"Missing", "missing-boards.txt", assert.Nil, assert.NotNil}, } for _, testTable := range testTables { diff --git a/internal/rule/ruleconfiguration/ruleconfiguration.go b/internal/rule/ruleconfiguration/ruleconfiguration.go index 675dfe2d5..9a6dae06e 100644 --- a/internal/rule/ruleconfiguration/ruleconfiguration.go +++ b/internal/rule/ruleconfiguration/ruleconfiguration.go @@ -1465,6 +1465,438 @@ var configurations = []Type{ ErrorModes: []rulemode.Type{rulemode.Default}, RuleFunction: rulefunction.BoardsTxtFormat, }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF003", + Brief: "missing boardID.name", + Description: "", + MessageTemplate: "Missing name property for board ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDNameMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF004", + Brief: "boardID.name < min length", + Description: "", + MessageTemplate: "name value for board ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDNameLTMinLength, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF005", + Brief: "missing build.board", + Description: "", + MessageTemplate: "Missing build.board property for board ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: []rulemode.Type{rulemode.Default}, + ErrorModes: []rulemode.Type{rulemode.Strict}, + RuleFunction: rulefunction.BoardsTxtBoardIDBuildBoardMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF006", + Brief: "build.board < min length", + Description: "", + MessageTemplate: "build.board value for board ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDBuildBoardLTMinLength, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF007", + Brief: "missing build.core", + Description: "", + MessageTemplate: "Missing build.core property for board ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#cores", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDBuildCoreMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF008", + Brief: "build.core < min length", + Description: "", + MessageTemplate: "build.core value for board ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#cores", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDBuildCoreLTMinLength, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF009", + Brief: "use of compiler.x.extra_flags", + Description: "", + MessageTemplate: "Board ID(s) {{.}} use compiler.x.extra_flags properties. These are intended to be left for use by the user.", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: []rulemode.Type{rulemode.Default}, + ErrorModes: []rulemode.Type{rulemode.Strict}, + RuleFunction: rulefunction.BoardsTxtUserExtraFlagsUsage, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF011", + Brief: "non-empty hide value", + Description: "", + MessageTemplate: "hide value for board ID(s) {{.}} is not empty. The value of this property is ignored. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#hiding-boards", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: []rulemode.Type{rulemode.Default}, + ErrorModes: []rulemode.Type{rulemode.Strict}, + RuleFunction: rulefunction.BoardsTxtBoardIDHideInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF012", + Brief: "menu title < min length", + Description: "", + MessageTemplate: "title for menu ID(s) {{.}} are 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.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, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF014", + Brief: "serial.disableDTR value invalid", + Description: "", + MessageTemplate: "serial.disableDTR value for board ID(s) {{.}} is invalid. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#serial-monitor-control-signal-configuration", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDSerialDisableDTRInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF015", + Brief: "serial.disableRTS value invalid", + Description: "", + MessageTemplate: "serial.disableRTS value for board ID(s) {{.}} is invalid. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#serial-monitor-control-signal-configuration", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDSerialDisableRTSInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF016", + Brief: "missing upload.tool", + Description: "", + MessageTemplate: "Missing upload.tool property for board ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#sketch-upload-configuration", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadToolMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF017", + Brief: "upload.tool < min length", + Description: "", + MessageTemplate: "upload.tool value for board ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#sketch-upload-configuration", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadToolLTMinLength, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF018", + Brief: "missing upload.maximum_size", + Description: "Although not required, this provides the build system and the user with very useful information so should be provided.", + MessageTemplate: "Missing upload.maximum_size property for board ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-compute-binary-sketch-size", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: []rulemode.Type{rulemode.Default}, + ErrorModes: []rulemode.Type{rulemode.Strict}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadMaximumSizeMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF019", + Brief: "upload.maximum_size not a number", + Description: "", + MessageTemplate: "upload.maximum_size value for board ID(s) {{.}} is not a number. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-compute-binary-sketch-size", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadMaximumSizeInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF020", + Brief: "missing upload.maximum_data_size", + Description: "Although not required, this provides the build system and the user with very useful information so should be provided.", + MessageTemplate: "Missing upload.maximum_data_size property for board ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-compute-binary-sketch-size", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: []rulemode.Type{rulemode.Default}, + ErrorModes: []rulemode.Type{rulemode.Strict}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadMaximumDataSizeMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF021", + Brief: "upload.maximum_data_size not a number", + Description: "", + MessageTemplate: "upload.maximum_data_size value for board ID(s) {{.}} is not a number. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#recipes-to-compute-binary-sketch-size", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadMaximumDataSizeInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF022", + Brief: "upload.use_1200bps_touch value invalid", + Description: "", + MessageTemplate: "upload.use_1200bps_touch value for board ID(s) {{.}} is invalid. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#1200-bps-bootloader-reset", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadUse1200bpsTouchInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF023", + Brief: "upload.wait_for_upload_port value invalid", + Description: "", + MessageTemplate: "upload.wait_for_upload_port value for board ID(s) {{.}} is invalid. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#1200-bps-bootloader-reset", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDUploadWaitForUploadPortInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF024", + Brief: "vid.n value invalid format", + Description: "", + MessageTemplate: "vid.n value for board ID(s) {{.}} has invalid format. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#board-vidpid", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDVidNInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "boards.txt", + ID: "PF025", + Brief: "pid.n value invalid format", + Description: "", + MessageTemplate: "pid.n value for board ID(s) {{.}} has invalid format. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#board-vidpid", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.BoardsTxtBoardIDPidNInvalid, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "programmers.txt", + ID: "PF026", + Brief: "invalid programmers.txt", + Description: "", + MessageTemplate: "programmers.txt has an invalid format: {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.ProgrammersTxtFormat, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "programmers.txt", + ID: "PF027", + Brief: "missing programmerID.name", + Description: "", + MessageTemplate: "Missing name property for programmer ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.ProgrammersTxtProgrammerIDNameMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "programmers.txt", + ID: "PF028", + Brief: "programmerID.name < min length", + Description: "", + MessageTemplate: "name value for programmer ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.ProgrammersTxtProgrammerIDNameLTMinLength, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "programmers.txt", + ID: "PF029", + Brief: "missing programmerID.program.tool", + Description: "", + MessageTemplate: "Missing program.tool property for programmer ID(s) {{.}}. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.ProgrammersTxtProgrammerIDProgramToolMissing, + }, + { + ProjectType: projecttype.Platform, + SuperprojectType: projecttype.All, + Category: "configuration files", + Subcategory: "programmers.txt", + ID: "PF030", + Brief: "programmerID.program.tool < min length", + Description: "", + MessageTemplate: "program.tool value for programmer ID(s) {{.}} is less than the minimum length. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.ProgrammersTxtProgrammerIDProgramToolLTMinLength, + }, { ProjectType: projecttype.Platform, SuperprojectType: projecttype.All, diff --git a/internal/rule/rulefunction/platform.go b/internal/rule/rulefunction/platform.go index d517dfd7a..8d58eccac 100644 --- a/internal/rule/rulefunction/platform.go +++ b/internal/rule/rulefunction/platform.go @@ -16,8 +16,12 @@ package rulefunction import ( + "strings" + "github.com/arduino/arduino-lint/internal/project/projectdata" "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" ) // The rule functions for platforms. @@ -49,3 +53,624 @@ func BoardsTxtFormat() (result ruleresult.Type, output string) { return ruleresult.Fail, projectdata.BoardsTxtLoadError().Error() } + +// BoardsTxtBoardIDNameMissing checks if any of the boards are missing name properties. +func BoardsTxtBoardIDNameMissing() (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 := boardIDMissingRequiredProperty("name", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDNameLTMinLength checks if any of the board names are less than the minimum length. +func BoardsTxtBoardIDNameLTMinLength() (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 := boardIDValueLTMinLength("name", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDBuildBoardMissing checks if any of the boards are missing build.board properties. +func BoardsTxtBoardIDBuildBoardMissing() (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 := boardIDMissingRequiredProperty("build\\.board", compliancelevel.Strict) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDBuildBoardLTMinLength checks if any of the board build.board values are less than the minimum length. +func BoardsTxtBoardIDBuildBoardLTMinLength() (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 := boardIDValueLTMinLength("build\\.board", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDBuildCoreMissing checks if any of the boards are missing build.core properties. +func BoardsTxtBoardIDBuildCoreMissing() (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 := boardIDMissingRequiredProperty("build\\.core", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDBuildCoreLTMinLength checks if any of the board build.core values are less than the minimum length. +func BoardsTxtBoardIDBuildCoreLTMinLength() (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 := boardIDValueLTMinLength("build\\.core", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtUserExtraFlagsUsage checks if the user's compiler.x.extra_flags properties are used in boards.txt. +func BoardsTxtUserExtraFlagsUsage() (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 := []string{} + for _, boardID := range projectdata.BoardsTxtBoardIds() { + if schema.ValidationErrorMatch("#/"+boardID, "/userExtraFlagsProperties/", "", "", projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Strict]) { + nonCompliantBoardIDs = append(nonCompliantBoardIDs, boardID) + } + } + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDHideInvalid checks if any of the board hide values are less than the minimum length. +func BoardsTxtBoardIDHideInvalid() (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 := boardIDValueEnumMismatch("hide", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtMenuMenuIDLTMinLength checks if any of the menu titles are less than the minimum length. +func BoardsTxtMenuMenuIDLTMinLength() (result ruleresult.Type, output string) { + if projectdata.BoardsTxtLoadError() != nil { + return ruleresult.NotRun, "Couldn't load boards.txt" + } + + if len(projectdata.BoardsTxtMenuIds()) == 0 { + return ruleresult.Skip, "boards.txt has no menus" + } + + nonCompliantMenuIDs := []string{} + for _, menuID := range projectdata.BoardsTxtMenuIds() { + if schema.PropertyLessThanMinLength("menu/"+menuID, projectdata.BoardsTxtSchemaValidationResult()[compliancelevel.Specification]) { + nonCompliantMenuIDs = append(nonCompliantMenuIDs, menuID) + } + } + + if len(nonCompliantMenuIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantMenuIDs, ", ") + } + + 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 := boardIDValueLTMinLength("menu\\..+\\..+", 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 { + return ruleresult.NotRun, "Couldn't load boards.txt" + } + + if len(projectdata.BoardsTxtBoardIds()) == 0 { + return ruleresult.Skip, "boards.txt has no boards" + } + + nonCompliantBoardIDs := boardIDValueEnumMismatch("serial\\.disableDTR", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDSerialDisableRTSInvalid checks if any of the board serial.disableRTS values are invalid. +func BoardsTxtBoardIDSerialDisableRTSInvalid() (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 := boardIDValueEnumMismatch("serial\\.disableRTS", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadToolMissing checks if any of the boards are missing upload.tool properties. +func BoardsTxtBoardIDUploadToolMissing() (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 := boardIDMissingRequiredProperty("upload\\.tool", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadToolLTMinLength checks if any of the board upload.tool values are less than the minimum length. +func BoardsTxtBoardIDUploadToolLTMinLength() (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 := boardIDValueLTMinLength("upload\\.tool", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadMaximumSizeMissing checks if any of the boards are missing upload.maximum_size properties. +func BoardsTxtBoardIDUploadMaximumSizeMissing() (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 := boardIDMissingRequiredProperty("upload\\.maximum_size", compliancelevel.Strict) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadMaximumSizeInvalid checks if any of the board upload.maximum_size values have an invalid format. +func BoardsTxtBoardIDUploadMaximumSizeInvalid() (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 := boardIDValuePatternMismatch("upload\\.maximum_size", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadMaximumDataSizeMissing checks if any of the boards are missing upload.maximum_data_size properties. +func BoardsTxtBoardIDUploadMaximumDataSizeMissing() (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 := boardIDMissingRequiredProperty("upload\\.maximum_data_size", compliancelevel.Strict) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadMaximumDataSizeInvalid checks if any of the board upload.maximum_data_size values have an invalid format. +func BoardsTxtBoardIDUploadMaximumDataSizeInvalid() (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 := boardIDValuePatternMismatch("upload\\.maximum_data_size", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadUse1200bpsTouchInvalid checks if any of the board upload.use_1200bps_touch values are invalid. +func BoardsTxtBoardIDUploadUse1200bpsTouchInvalid() (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 := boardIDValueEnumMismatch("upload\\.use_1200bps_touch", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDUploadWaitForUploadPortInvalid checks if any of the board upload.wait_for_upload_port values are invalid. +func BoardsTxtBoardIDUploadWaitForUploadPortInvalid() (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 := boardIDValueEnumMismatch("upload\\.wait_for_upload_port", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDVidNInvalid checks if any of the board vid.n values have an invalid format. +func BoardsTxtBoardIDVidNInvalid() (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 := boardIDValuePatternMismatch("vid\\.[0-9]+", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// BoardsTxtBoardIDPidNInvalid checks if any of the board pid.n values have an invalid format. +func BoardsTxtBoardIDPidNInvalid() (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 := boardIDValuePatternMismatch("pid\\.[0-9]+", compliancelevel.Specification) + + if len(nonCompliantBoardIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantBoardIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// ProgrammersTxtFormat checks for invalid programmers.txt format. +func ProgrammersTxtFormat() (result ruleresult.Type, output string) { + if !projectdata.ProgrammersTxtExists() { + return ruleresult.Skip, "Platform has no programmers.txt" + } + + if projectdata.ProgrammersTxtLoadError() == nil { + return ruleresult.Pass, "" + } + + return ruleresult.Fail, projectdata.ProgrammersTxtLoadError().Error() +} + +// ProgrammersTxtProgrammerIDNameMissing checks if any of the programmers are missing name properties. +func ProgrammersTxtProgrammerIDNameMissing() (result ruleresult.Type, output string) { + if !projectdata.ProgrammersTxtExists() { + return ruleresult.Skip, "Platform has no programmers.txt" + } + + if projectdata.ProgrammersTxtLoadError() != nil { + return ruleresult.NotRun, "Couldn't load programmers.txt" + } + + if len(projectdata.ProgrammersTxtProgrammerIds()) == 0 { + return ruleresult.Skip, "programmers.txt has no programmers" + } + + nonCompliantProgrammerIDs := programmerIDMissingRequiredProperty("name", compliancelevel.Specification) + + if len(nonCompliantProgrammerIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantProgrammerIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// ProgrammersTxtProgrammerIDNameLTMinLength checks if any of the programmer names are less than the minimum length. +func ProgrammersTxtProgrammerIDNameLTMinLength() (result ruleresult.Type, output string) { + if !projectdata.ProgrammersTxtExists() { + return ruleresult.Skip, "Platform has no programmers.txt" + } + + if projectdata.ProgrammersTxtLoadError() != nil { + return ruleresult.NotRun, "Couldn't load programmers.txt" + } + + if len(projectdata.ProgrammersTxtProgrammerIds()) == 0 { + return ruleresult.Skip, "programmers.txt has no programmers" + } + + nonCompliantProgrammerIDs := programmerIDValueLTMinLength("name", compliancelevel.Specification) + + if len(nonCompliantProgrammerIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantProgrammerIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// ProgrammersTxtProgrammerIDProgramToolMissing checks if any of the programmers are missing program.tool properties. +func ProgrammersTxtProgrammerIDProgramToolMissing() (result ruleresult.Type, output string) { + if !projectdata.ProgrammersTxtExists() { + return ruleresult.Skip, "Platform has no programmers.txt" + } + + if projectdata.ProgrammersTxtLoadError() != nil { + return ruleresult.NotRun, "Couldn't load programmers.txt" + } + + if len(projectdata.ProgrammersTxtProgrammerIds()) == 0 { + return ruleresult.Skip, "programmers.txt has no programmers" + } + + nonCompliantProgrammerIDs := programmerIDMissingRequiredProperty("program\\.tool", compliancelevel.Specification) + + if len(nonCompliantProgrammerIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantProgrammerIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// ProgrammersTxtProgrammerIDProgramToolLTMinLength checks if any of the programmer program.tool properties are less than the minimum length. +func ProgrammersTxtProgrammerIDProgramToolLTMinLength() (result ruleresult.Type, output string) { + if !projectdata.ProgrammersTxtExists() { + return ruleresult.Skip, "Platform has no programmers.txt" + } + + if projectdata.ProgrammersTxtLoadError() != nil { + return ruleresult.NotRun, "Couldn't load programmers.txt" + } + + if len(projectdata.ProgrammersTxtProgrammerIds()) == 0 { + return ruleresult.Skip, "programmers.txt has no programmers" + } + + nonCompliantProgrammerIDs := programmerIDValueLTMinLength("program\\.tool", compliancelevel.Specification) + + if len(nonCompliantProgrammerIDs) > 0 { + return ruleresult.Fail, strings.Join(nonCompliantProgrammerIDs, ", ") + } + + return ruleresult.Pass, "" +} + +// boardIDMissingRequiredProperty returns the list of board IDs missing the given required property. +func boardIDMissingRequiredProperty(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + return iDMissingRequiredProperty(projectdata.BoardsTxtBoardIds(), propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) +} + +// boardIDValueLTMinLength returns the list of board IDs with value of the given property less than the minimum length. +func boardIDValueLTMinLength(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + return iDValueLTMinLength(projectdata.BoardsTxtBoardIds(), propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) +} + +// boardIDValueEnumMismatch returns the list of board IDs with value of the given property not matching the JSON schema enum. +func boardIDValueEnumMismatch(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + return iDValueEnumMismatch(projectdata.BoardsTxtBoardIds(), propertyNameQuery, projectdata.BoardsTxtSchemaValidationResult()[complianceLevel]) +} + +// boardIDValueEnumMismatch returns the list of board IDs with value of the given property not matching the JSON schema pattern. +func boardIDValuePatternMismatch(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + return iDValuePatternMismatch(projectdata.BoardsTxtBoardIds(), 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]) +} + +// programmerIDValueLTMinLength returns the list of programmer IDs with value of the given property less than the minimum length. +func programmerIDValueLTMinLength(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + return iDValueLTMinLength(projectdata.ProgrammersTxtProgrammerIds(), propertyNameQuery, projectdata.ProgrammersTxtSchemaValidationResult()[complianceLevel]) +} + +// programmerIDValueEnumMismatch returns the list of programmer IDs with value of the given property not matching the JSON schema enum. +func programmerIDValueEnumMismatch(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + return iDValueEnumMismatch(projectdata.ProgrammersTxtProgrammerIds(), propertyNameQuery, projectdata.ProgrammersTxtSchemaValidationResult()[complianceLevel]) +} + +// programmerIDValueEnumMismatch returns the list of programmer IDs with value of the given property not matching the JSON schema pattern. +func programmerIDValuePatternMismatch(propertyNameQuery string, complianceLevel compliancelevel.Type) []string { + return iDValuePatternMismatch(projectdata.ProgrammersTxtProgrammerIds(), propertyNameQuery, projectdata.ProgrammersTxtSchemaValidationResult()[complianceLevel]) +} + +// iDMissingRequiredProperty returns the list of first level keys missing the given required property. +func iDMissingRequiredProperty(iDs []string, propertyNameQuery string, validationResult schema.ValidationResult) []string { + nonCompliantIDs := []string{} + for _, iD := range iDs { + if schema.RequiredPropertyMissing(iD+"/"+propertyNameQuery, validationResult) { + nonCompliantIDs = append(nonCompliantIDs, iD) + } + } + + return nonCompliantIDs +} + +// iDValueLTMinLength returns the list of first level keys with value of the given property less than the minimum length. +func iDValueLTMinLength(iDs []string, propertyNameQuery string, validationResult schema.ValidationResult) []string { + nonCompliantIDs := []string{} + for _, iD := range iDs { + if schema.PropertyLessThanMinLength(iD+"/"+propertyNameQuery, validationResult) { + nonCompliantIDs = append(nonCompliantIDs, iD) + } + } + + return nonCompliantIDs +} + +// iDValueEnumMismatch returns the list of first level keys with value of the given property not matching the JSON schema enum. +func iDValueEnumMismatch(iDs []string, propertyNameQuery string, validationResult schema.ValidationResult) []string { + nonCompliantIDs := []string{} + for _, iD := range iDs { + if schema.PropertyEnumMismatch(iD+"/"+propertyNameQuery, validationResult) { + nonCompliantIDs = append(nonCompliantIDs, iD) + } + } + + return nonCompliantIDs +} + +// iDValueEnumMismatch returns the list of first level keys with value of the given property not matching the JSON schema pattern. +func iDValuePatternMismatch(iDs []string, propertyNameQuery string, validationResult schema.ValidationResult) []string { + nonCompliantIDs := []string{} + for _, iD := range iDs { + if schema.PropertyPatternMismatch(iD+"/"+propertyNameQuery, validationResult) { + nonCompliantIDs = append(nonCompliantIDs, iD) + } + } + + return nonCompliantIDs +} diff --git a/internal/rule/rulefunction/platform_test.go b/internal/rule/rulefunction/platform_test.go index b06b75452..dcf43db45 100644 --- a/internal/rule/rulefunction/platform_test.go +++ b/internal/rule/rulefunction/platform_test.go @@ -80,3 +80,315 @@ func TestBoardsTxtFormat(t *testing.T) { checkPlatformRuleFunction(BoardsTxtFormat, testTables, t) } + +func TestBoardsTxtBoardIDNameMissing(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 missing", "boardID-name-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDNameMissing, testTables, t) +} + +func TestBoardsTxtBoardIDNameLTMinLength(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-name-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDNameLTMinLength, testTables, t) +} + +func TestBoardsTxtBoardIDBuildBoardMissing(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 missing", "boardID-build-board-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDBuildBoardMissing, testTables, t) +} + +func TestBoardsTxtBoardIDBuildBoardLTMinLength(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-build-board-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDBuildBoardLTMinLength, testTables, t) +} + +func TestBoardsTxtBoardIDBuildCoreMissing(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 missing", "boardID-build-core-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDBuildCoreMissing, testTables, t) +} + +func TestBoardsTxtBoardIDBuildCoreLTMinLength(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-build-core-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDBuildCoreLTMinLength, testTables, t) +} + +func TestBoardsTxtUserExtraFlagsUsage(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, ""}, + {"Use of user extra flags", "boardID-compiler-x-extra_flags-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtUserExtraFlagsUsage, testTables, t) +} + +func TestBoardsTxtBoardIDHideInvalid(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-hide-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDHideInvalid, testTables, t) +} + +func TestBoardsTxtMenuMenuIDLTMinLength(t *testing.T) { + testTables := []platformRuleFunctionTestTable{ + {"Missing", "missing-boards.txt", ruleresult.NotRun, ""}, + {"Invalid", "invalid-boards.txt", ruleresult.NotRun, ""}, + {"No menus", "no-menus-boards.txt", ruleresult.Skip, ""}, + {"Menu title too short", "menu-menuID-LT-boards.txt", ruleresult.Fail, "foo, baz"}, + {"Menu title valid", "menu-menuID-valid-boards.txt", ruleresult.Pass, ""}, + } + + 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"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDSerialDisableDTRInvalid, testTables, t) +} + +func TestBoardsTxtBoardIDSerialDisableRTSInvalid(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-disableRTS-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDSerialDisableRTSInvalid, testTables, t) +} + +func TestBoardsTxtBoardIDUploadToolMissing(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 missing", "boardID-upload-tool-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadToolMissing, testTables, t) +} + +func TestBoardsTxtBoardIDUploadToolLTMinLength(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-upload-tool-LT-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadToolLTMinLength, testTables, t) +} + +func TestBoardsTxtBoardIDUploadMaximumSizeMissing(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 missing", "boardID-upload-maximum_size-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadMaximumSizeMissing, testTables, t) +} + +func TestBoardsTxtBoardIDUploadMaximumSizeInvalid(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-upload-maximum_size-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadMaximumSizeInvalid, testTables, t) +} + +func TestBoardsTxtBoardIDUploadMaximumDataSizeMissing(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 missing", "boardID-upload-maximum_data_size-missing-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadMaximumDataSizeMissing, testTables, t) +} + +func TestBoardsTxtBoardIDUploadMaximumDataSizeInvalid(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-upload-maximum_data_size-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadMaximumDataSizeInvalid, testTables, t) +} + +func TestBoardsTxtBoardIDUploadUse1200bpsTouchInvalid(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-upload-use_1200bps_touch-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadUse1200bpsTouchInvalid, testTables, t) +} + +func TestBoardsTxtBoardIDUploadWaitForUploadPortInvalid(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-upload-wait_for_upload_port-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDUploadWaitForUploadPortInvalid, testTables, t) +} + +func TestBoardsTxtBoardIDVidNInvalid(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-vid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDVidNInvalid, testTables, t) +} + +func TestBoardsTxtBoardIDPidNInvalid(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-pid-n-invalid-boards.txt", ruleresult.Fail, "buno, funo"}, + {"Valid", "valid-boards.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(BoardsTxtBoardIDPidNInvalid, testTables, t) +} + +func TestProgrammersTxtProgrammerIDNameMissing(t *testing.T) { + testTables := []platformRuleFunctionTestTable{ + {"Missing", "missing-programmers.txt", ruleresult.Skip, ""}, + {"Invalid", "invalid-programmers.txt", ruleresult.NotRun, ""}, + {"No programmers", "no-programmers-programmers.txt", ruleresult.Skip, ""}, + {"Property missing", "programmerID-name-missing-programmers.txt", ruleresult.Fail, "foo, bar"}, + {"Valid", "valid-programmers.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(ProgrammersTxtProgrammerIDNameMissing, testTables, t) +} + +func TestProgrammersTxtProgrammerIDNameLTMinLength(t *testing.T) { + testTables := []platformRuleFunctionTestTable{ + {"Missing", "missing-programmers.txt", ruleresult.Skip, ""}, + {"Invalid", "invalid-programmers.txt", ruleresult.NotRun, ""}, + {"No programmers", "no-programmers-programmers.txt", ruleresult.Skip, ""}, + {"Property LT min", "programmerID-name-LT-programmers.txt", ruleresult.Fail, "foo, bar"}, + {"Valid", "valid-programmers.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(ProgrammersTxtProgrammerIDNameLTMinLength, testTables, t) +} + +func TestProgrammersTxtProgrammerIDProgramToolMissing(t *testing.T) { + testTables := []platformRuleFunctionTestTable{ + {"Missing", "missing-programmers.txt", ruleresult.Skip, ""}, + {"Invalid", "invalid-programmers.txt", ruleresult.NotRun, ""}, + {"No programmers", "no-programmers-programmers.txt", ruleresult.Skip, ""}, + {"Property missing", "programmerID-program-tool-missing-programmers.txt", ruleresult.Fail, "foo, bar"}, + {"Valid", "valid-programmers.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(ProgrammersTxtProgrammerIDProgramToolMissing, testTables, t) +} + +func TestProgrammersTxtProgrammerIDProgramToolLTMinLength(t *testing.T) { + testTables := []platformRuleFunctionTestTable{ + {"Missing", "missing-programmers.txt", ruleresult.Skip, ""}, + {"Invalid", "invalid-programmers.txt", ruleresult.NotRun, ""}, + {"No programmers", "no-programmers-programmers.txt", ruleresult.Skip, ""}, + {"Property LT min", "programmerID-program-tool-LT-programmers.txt", ruleresult.Fail, "foo, bar"}, + {"Valid", "valid-programmers.txt", ruleresult.Pass, ""}, + } + + checkPlatformRuleFunction(ProgrammersTxtProgrammerIDProgramToolLTMinLength, testTables, t) +} 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 new file mode 100644 index 000000000..f0cd6bd1a --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-LT-boards.txt/boards.txt @@ -0,0 +1,23 @@ +buno.name=Buno +buno.build.board= +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board= +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..9da39ca00 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-board-missing-boards.txt/boards.txt @@ -0,0 +1,21 @@ +buno.name=Buno +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..02ec763f3 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-LT-boards.txt/boards.txt @@ -0,0 +1,23 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core= +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core= +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..96a3e3e7b --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-build-core-missing-boards.txt/boards.txt @@ -0,0 +1,21 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..e3399fa0e --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-compiler-x-extra_flags-boards.txt/boards.txt @@ -0,0 +1,25 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.compiler.c.extra_flags=bar +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.compiler.objcopy.eep.extra_flags=foo +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-debug-tool-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-debug-tool-LT-boards.txt/boards.txt new file mode 100644 index 000000000..3e97e0859 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-debug-tool-LT-boards.txt/boards.txt @@ -0,0 +1,26 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.debug.tool= +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.debug.tool=asdf +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.debug.tool= +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..9a28652c6 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-hide-invalid-boards.txt/boards.txt @@ -0,0 +1,26 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.hide=true +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.hide= +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.hide=false +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/boardID-menu-menuID-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/boardID-menu-menuID-LT-boards.txt/boards.txt new file mode 100644 index 000000000..113e609a1 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-menu-menuID-LT-boards.txt/boards.txt @@ -0,0 +1,26 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.menu.bar.asdf= +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.menu.baz.zxcv=qwer +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.menu.foo.tyui= +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..6e26f4271 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-name-LT-boards.txt/boards.txt @@ -0,0 +1,23 @@ +buno.name= +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name= +funo.build.board=BUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..5287f67e0 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-name-missing-boards.txt/boards.txt @@ -0,0 +1,21 @@ +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..5896bfb53 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-pid-n-invalid-boards.txt/boards.txt @@ -0,0 +1,29 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 +buno.vid.0=0xABCD +buno.pid.0=bar + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 +uno.vid.0=0xABCD +uno.pid.0=0x1234 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 +funo.vid.0=0xABCD +funo.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 new file mode 100644 index 000000000..ec066e92b --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableDTR-invalid-boards.txt/boards.txt @@ -0,0 +1,26 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.serial.disableDTR=bar +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.serial.disableDTR=true +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.serial.disableDTR=foo +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..b6aca5d08 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-serial-disableRTS-invalid-boards.txt/boards.txt @@ -0,0 +1,26 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.serial.disableRTS=bar +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.serial.disableRTS=true +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.serial.disableRTS=foo +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..8670c7cfe --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-invalid-boards.txt/boards.txt @@ -0,0 +1,23 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=bar + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=fpp 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 new file mode 100644 index 000000000..737e0e819 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_data_size-missing-boards.txt/boards.txt @@ -0,0 +1,21 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 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 new file mode 100644 index 000000000..3dd41ae07 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-invalid-boards.txt/boards.txt @@ -0,0 +1,23 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=bar +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=foo +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..43cb6eb9b --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-maximum_size-missing-boards.txt/boards.txt @@ -0,0 +1,21 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..432282836 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-LT-boards.txt/boards.txt @@ -0,0 +1,23 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool= +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool= +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..8ac786b2a --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-tool-missing-boards.txt/boards.txt @@ -0,0 +1,21 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 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 new file mode 100644 index 000000000..ab8afe811 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-use_1200bps_touch-invalid-boards.txt/boards.txt @@ -0,0 +1,26 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 +buno.upload.use_1200bps_touch=bar + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 +uno.upload.use_1200bps_touch=true + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 +funo.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 new file mode 100644 index 000000000..fc75822b5 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-upload-wait_for_upload_port-invalid-boards.txt/boards.txt @@ -0,0 +1,26 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 +buno.upload.wait_for_upload_port=bar + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 +uno.upload.wait_for_upload_port=false + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 +funo.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 new file mode 100644 index 000000000..0bf439586 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/boardID-vid-n-invalid-boards.txt/boards.txt @@ -0,0 +1,29 @@ +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 +buno.vid.0=bar +buno.pid.0=0xABCD + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 +uno.vid.0=0xABCD +uno.pid.0=0xABCD + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 +funo.vid.0=foo +funo.pid.0=0xABCD diff --git a/internal/rule/rulefunction/testdata/platforms/invalid-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/invalid-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/invalid-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/invalid-programmers.txt/programmers.txt b/internal/rule/rulefunction/testdata/platforms/invalid-programmers.txt/programmers.txt new file mode 100644 index 000000000..126cc32ba --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/invalid-programmers.txt/programmers.txt @@ -0,0 +1 @@ +This makes the format invalid diff --git a/internal/rule/rulefunction/testdata/platforms/menu-menuID-LT-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/menu-menuID-LT-boards.txt/boards.txt new file mode 100644 index 000000000..527da5c83 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/menu-menuID-LT-boards.txt/boards.txt @@ -0,0 +1,11 @@ +menu.foo= +menu.bar=asdf +menu.baz= + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/menu-menuID-valid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/menu-menuID-valid-boards.txt/boards.txt new file mode 100644 index 000000000..71216dbd7 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/menu-menuID-valid-boards.txt/boards.txt @@ -0,0 +1,10 @@ +menu.foo=asdf +menu.bar=zxcv + +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/missing-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/missing-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/missing-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/no-boards-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/no-boards-boards.txt/boards.txt new file mode 100644 index 000000000..e69de29bb diff --git a/internal/rule/rulefunction/testdata/platforms/no-menus-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/no-menus-boards.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/no-menus-boards.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/no-programmers-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/no-programmers-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/no-programmers-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/no-programmers-programmers.txt/programmers.txt b/internal/rule/rulefunction/testdata/platforms/no-programmers-programmers.txt/programmers.txt new file mode 100644 index 000000000..e69de29bb diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-name-LT-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-name-LT-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-name-LT-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-name-LT-programmers.txt/programmers.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-name-LT-programmers.txt/programmers.txt new file mode 100644 index 000000000..7ccf017e0 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-name-LT-programmers.txt/programmers.txt @@ -0,0 +1,12 @@ +foo.name= +foo.program.tool=avrdude + +usbasp.name=USBasp +usbasp.communication=usb +usbasp.protocol=usbasp +usbasp.program.protocol=usbasp +usbasp.program.tool=avrdude +usbasp.program.extra_params=-Pusb + +bar.name= +bar.program.tool=bartool diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-name-missing-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-name-missing-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-name-missing-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-name-missing-programmers.txt/programmers.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-name-missing-programmers.txt/programmers.txt new file mode 100644 index 000000000..1bd6285be --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-name-missing-programmers.txt/programmers.txt @@ -0,0 +1,10 @@ +foo.program.tool=avrdude + +usbasp.name=USBasp +usbasp.communication=usb +usbasp.protocol=usbasp +usbasp.program.protocol=usbasp +usbasp.program.tool=avrdude +usbasp.program.extra_params=-Pusb + +bar.program.tool=bartool diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-LT-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-LT-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-LT-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-LT-programmers.txt/programmers.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-LT-programmers.txt/programmers.txt new file mode 100644 index 000000000..6c2a8ad8d --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-LT-programmers.txt/programmers.txt @@ -0,0 +1,12 @@ +foo.name=Foo +foo.program.tool= + +usbasp.name=USBasp +usbasp.communication=usb +usbasp.protocol=usbasp +usbasp.program.protocol=usbasp +usbasp.program.tool=avrdude +usbasp.program.extra_params=-Pusb + +bar.name=Bar +bar.program.tool= diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-missing-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-missing-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-missing-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-missing-programmers.txt/programmers.txt b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-missing-programmers.txt/programmers.txt new file mode 100644 index 000000000..43750bca9 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/programmerID-program-tool-missing-programmers.txt/programmers.txt @@ -0,0 +1,10 @@ +foo.name=Foo + +usbasp.name=USBasp +usbasp.communication=usb +usbasp.protocol=usbasp +usbasp.program.protocol=usbasp +usbasp.program.tool=avrdude +usbasp.program.extra_params=-Pusb + +bar.name=Bar diff --git a/internal/rule/rulefunction/testdata/platforms/valid-boards.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/valid-boards.txt/boards.txt index 28dddb078..1866d3c44 100644 --- a/internal/rule/rulefunction/testdata/platforms/valid-boards.txt/boards.txt +++ b/internal/rule/rulefunction/testdata/platforms/valid-boards.txt/boards.txt @@ -1,8 +1,23 @@ -uno.name=Arduino Uno +buno.name=Buno +buno.build.board=BUNO +buno.build.core=arduino +buno.build.variant=standard +buno.upload.tool=avrdude +buno.upload.maximum_size=32256 +buno.upload.maximum_data_size=2048 +uno.name=Arduino Uno +uno.build.board=UNO uno.build.core=arduino uno.build.variant=standard - uno.upload.tool=avrdude uno.upload.maximum_size=32256 uno.upload.maximum_data_size=2048 + +funo.name=Funo +funo.build.board=FUNO +funo.build.core=arduino +funo.build.variant=standard +funo.upload.tool=avrdude +funo.upload.maximum_size=32256 +funo.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/valid-programmers.txt/boards.txt b/internal/rule/rulefunction/testdata/platforms/valid-programmers.txt/boards.txt new file mode 100644 index 000000000..075d9bc34 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/valid-programmers.txt/boards.txt @@ -0,0 +1,7 @@ +uno.name=Arduino Uno +uno.build.board=UNO +uno.build.core=arduino +uno.build.variant=standard +uno.upload.tool=avrdude +uno.upload.maximum_size=32256 +uno.upload.maximum_data_size=2048 diff --git a/internal/rule/rulefunction/testdata/platforms/valid-programmers.txt/programmers.txt b/internal/rule/rulefunction/testdata/platforms/valid-programmers.txt/programmers.txt new file mode 100644 index 000000000..b3b383141 --- /dev/null +++ b/internal/rule/rulefunction/testdata/platforms/valid-programmers.txt/programmers.txt @@ -0,0 +1,12 @@ +foo.name=Foo +foo.program.tool=avrdude + +usbasp.name=USBasp +usbasp.communication=usb +usbasp.protocol=usbasp +usbasp.program.protocol=usbasp +usbasp.program.tool=avrdude +usbasp.program.extra_params=-Pusb + +bar.name=Bar +bar.program.tool=bartool diff --git a/internal/rule/schema/schema.go b/internal/rule/schema/schema.go index db81e158f..21fb16fa5 100644 --- a/internal/rule/schema/schema.go +++ b/internal/rule/schema/schema.go @@ -24,7 +24,6 @@ import ( "io/ioutil" "path" - "github.com/arduino/go-properties-orderedmap" "github.com/ory/jsonschema/v3" "github.com/sirupsen/logrus" "github.com/xeipuuv/gojsonreference" @@ -80,15 +79,7 @@ func Compile(schemaFilename string, referencedSchemaFilenames []string, dataLoad // Validate validates an instance against a JSON schema and returns nil if it was success, or the // jsonschema.ValidationError object otherwise. -func Validate(instanceObject *properties.Map, schemaObject Schema) ValidationResult { - // Convert the instance data from the native properties.Map type to the interface type required by the schema - // validation package. - instanceObjectMap := instanceObject.AsMap() - instanceInterface := make(map[string]interface{}, len(instanceObjectMap)) - for k, v := range instanceObjectMap { - instanceInterface[k] = v - } - +func Validate(instanceInterface map[string]interface{}, schemaObject Schema) ValidationResult { validationError := schemaObject.Compiled.ValidateInterface(instanceInterface) result, _ := validationError.(*jsonschema.ValidationError) validationResult := ValidationResult{ diff --git a/internal/rule/schema/schema_test.go b/internal/rule/schema/schema_test.go index d5a07bbe4..b51689416 100644 --- a/internal/rule/schema/schema_test.go +++ b/internal/rule/schema/schema_test.go @@ -46,6 +46,23 @@ func init() { ) } +// propertiesToMap converts properties.Map data structures to map[string]interface. +func propertiesToMap(propertiesInput *properties.Map) map[string]interface{} { + mapOutput := make(map[string]interface{}) + keys := propertiesInput.FirstLevelKeys() + for _, key := range keys { + subTree := propertiesInput.SubTree(key) + if subTree.Size() > 0 { + // This key contains a map, recurse it. + mapOutput[key] = propertiesToMap(subTree) + } else { + // This key contains a string, no more recursion is possible. + mapOutput[key] = propertiesInput.Get(key) + } + } + return mapOutput +} + func TestCompile(t *testing.T) { require.Panics(t, func() { Compile("valid-schema-with-references.json", []string{"nonexistent.json"}, testdata.Asset) @@ -82,35 +99,35 @@ func TestCompile(t *testing.T) { func TestValidate(t *testing.T) { schemaObject := Compile("valid-schema.json", []string{}, testdata.Asset) propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, schemaObject) + validationResult := Validate(propertiesToMap(propertiesMap), schemaObject) require.Nil(t, validationResult.Result) - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.Nil(t, validationResult.Result) propertiesMap.Set("property1", "a") - validationResult = Validate(propertiesMap, schemaObject) + validationResult = Validate(propertiesToMap(propertiesMap), schemaObject) require.Equal(t, "#/property1", validationResult.Result.InstancePtr) require.Equal(t, "#/properties/property1/minLength", validationResult.Result.SchemaPtr) } func TestRequiredPropertyMissing(t *testing.T) { propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, validSchemaWithReferences) + validationResult := Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, RequiredPropertyMissing("property1", validationResult)) propertiesMap.Remove("property1") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.True(t, RequiredPropertyMissing("property1", validationResult)) } func TestPropertyPatternMismatch(t *testing.T) { propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, validSchemaWithReferences) + validationResult := Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, PropertyPatternMismatch("property2", validationResult)) propertiesMap.Set("property2", "fOo") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.True(t, PropertyPatternMismatch("property2", validationResult)) require.False(t, PropertyPatternMismatch("property1", validationResult)) @@ -118,51 +135,51 @@ func TestPropertyPatternMismatch(t *testing.T) { func TestPropertyLessThanMinLength(t *testing.T) { propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, validSchemaWithReferences) + validationResult := Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, PropertyLessThanMinLength("property1", validationResult)) propertiesMap.Set("property1", "a") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.True(t, PropertyLessThanMinLength("property1", validationResult)) } func TestPropertyGreaterThanMaxLength(t *testing.T) { propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, validSchemaWithReferences) + validationResult := Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, PropertyGreaterThanMaxLength("property1", validationResult)) propertiesMap.Set("property1", "12345") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.True(t, PropertyGreaterThanMaxLength("property1", validationResult)) } func TestPropertyEnumMismatch(t *testing.T) { propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, validSchemaWithReferences) + validationResult := Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, PropertyEnumMismatch("property3", validationResult)) propertiesMap.Set("property3", "invalid") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.True(t, PropertyEnumMismatch("property3", validationResult)) } func TestMisspelledOptionalPropertyFound(t *testing.T) { propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, validSchemaWithReferences) + validationResult := Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, MisspelledOptionalPropertyFound(validationResult)) propertiesMap.Set("porperties", "foo") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.True(t, MisspelledOptionalPropertyFound(validationResult)) } func TestValidationErrorMatch(t *testing.T) { propertiesMap := properties.NewFromHashmap(validMap) - validationResult := Validate(propertiesMap, validSchemaWithReferences) + validationResult := Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, ValidationErrorMatch("", "", "", "", validationResult)) propertiesMap.Set("property2", "fOo") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, ValidationErrorMatch("nomatch", "nomatch", "nomatch", "nomatch", validationResult)) require.False(t, ValidationErrorMatch("^#/property2$", "nomatch", "nomatch", "nomatch", validationResult)) require.False(t, ValidationErrorMatch("^#/property2$", "/pattern$", "nomatch", "nomatch", validationResult)) @@ -171,12 +188,12 @@ func TestValidationErrorMatch(t *testing.T) { require.True(t, ValidationErrorMatch("", "", "", "", validationResult)) propertiesMap.Set("property3", "bAz") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.True(t, ValidationErrorMatch("^#/property3$", "/pattern$", "", "", validationResult), "Match pointer below logic inversion keyword") propertiesMap = properties.NewFromHashmap(validMap) propertiesMap.Remove("property1") - validationResult = Validate(propertiesMap, validSchemaWithReferences) + validationResult = Validate(propertiesToMap(propertiesMap), validSchemaWithReferences) require.False(t, ValidationErrorMatch("nomatch", "nomatch", "nomatch", "nomatch", validationResult)) require.True(t, ValidationErrorMatch("", "", "", "^#/property1$", validationResult)) } diff --git a/internal/rule/schema/schemadata/bindata.go b/internal/rule/schema/schemadata/bindata.go index fb847fb1d..ff0443f6f 100644 --- a/internal/rule/schema/schemadata/bindata.go +++ b/internal/rule/schema/schemadata/bindata.go @@ -1,9 +1,17 @@ // Package schemadata Code generated by go-bindata. (@generated) DO NOT EDIT. // sources: +// etc/schemas/arduino-boards-txt-definitions-schema.json +// etc/schemas/arduino-boards-txt-permissive-schema.json +// etc/schemas/arduino-boards-txt-schema.json +// etc/schemas/arduino-boards-txt-strict-schema.json // etc/schemas/arduino-library-properties-definitions-schema.json // etc/schemas/arduino-library-properties-permissive-schema.json // etc/schemas/arduino-library-properties-schema.json // etc/schemas/arduino-library-properties-strict-schema.json +// etc/schemas/arduino-programmers-txt-definitions-schema.json +// etc/schemas/arduino-programmers-txt-permissive-schema.json +// etc/schemas/arduino-programmers-txt-schema.json +// etc/schemas/arduino-programmers-txt-strict-schema.json // etc/schemas/general-definitions-schema.json package schemadata @@ -58,9 +66,1112 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } +var _arduinoBoardsTxtDefinitionsSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-definitions-schema.json", + "title": "Shared definitions for the Arduino boards.txt schemas", + "definitions": { + "propertiesObjects": { + "menu": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/menuMenuID/permissive/object" + } + }, + "additionalProperties": false + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menu/base/object" + }, + { + "patternProperties": { + "^.+$": { + "$ref": "#/definitions/propertiesObjects/menuMenuID/specification/object" + } + }, + "additionalProperties": false + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menu/base/object" + }, + { + "patternProperties": { + ".+": { + "$ref": "#/definitions/propertiesObjects/menuMenuID/permissive/object" + } + }, + "additionalProperties": false + } + ] + } + } + }, + "menuMenuID": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menuMenuID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menuMenuID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/menuMenuID/base/object" + } + ] + } + } + }, + "boardID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/boardIDName/permissive/object" + }, + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/permissive/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/permissive/object" + }, + "hide": { + "$ref": "#/definitions/propertiesObjects/boardIDHide/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": { + "menu\\..+\\..+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/permissive/object" + }, + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/permissive/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/permissive/object" + }, + { + "$ref": "#/definitions/requiredObjects/boardID/permissive/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/boardIDName/specification/object" + }, + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/specification/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/specification/object" + }, + "hide": { + "$ref": "#/definitions/propertiesObjects/boardIDHide/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": { + "menu\\..+\\..+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/specification/object" + }, + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/specification/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/specification/object" + }, + { + "$ref": "#/definitions/requiredObjects/boardID/specification/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/boardIDName/strict/object" + }, + "build.board": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/strict/object" + }, + "build.core": { + "$ref": "#/definitions/propertiesObjects/boardIDBuildCore/strict/object" + }, + "hide": { + "$ref": "#/definitions/propertiesObjects/boardIDHide/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": { + "menu\\..+\\..+$": { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/strict/object" + }, + "^[vp]id\\.[0-9]+$": { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/strict/object" + } + } + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/object" + }, + { + "$ref": "#/definitions/requiredObjects/boardID/strict/object" + } + ] + } + } + }, + "boardIDName": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDName/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDName/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDName/base/object" + } + ] + } + } + }, + "boardIDBuildBoard": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + } + }, + "boardIDBuildCore": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDBuildBoard/base/object" + } + ] + } + } + }, + "boardIDHide": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDHide/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDHide/base/object" + }, + { + "enum": [""] + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDHide/specification/object" + } + ] + } + } + }, + "boardIDMenuMenuIDOptionID": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDMenuMenuIDOptionID/base/object" + } + ] + } + } + }, + "boardIDSerialDisableDTR": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableDTR/base/object" + } + ] + } + } + }, + "boardIDSerialDisableRTS": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDSerialDisableRTS/base/object" + } + ] + } + } + }, + "boardIDUploadMaximumSize": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "pattern": "^[0-9]+$" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumSize/base/object" + } + ] + } + } + }, + "boardIDUploadMaximumDataSize": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "pattern": "^[0-9]+$" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadMaximumDataSize/base/object" + } + ] + } + } + }, + "boardIDUploadProtocol": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadProtocol/base/object" + } + ] + } + } + }, + "boardIDUploadTool": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadTool/base/object" + } + ] + } + } + }, + "boardIDUploadUse1200bpsTouch": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadUse1200bpsTouch/base/object" + } + ] + } + } + }, + "boardIDUploadWaitForUploadPort": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/enumObjects/booleanString" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDUploadWaitForUploadPort/base/object" + } + ] + } + } + }, + "boardIDXidN": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "pattern": "^0[xX][0-9a-fA-F]{4}$" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/boardIDXidN/base/object" + } + ] + } + } + } + }, + "propertyNamesObjects": { + "base": { + "object": {} + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertyNamesObjects/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertyNamesObjects/base/object" + } + ] + } + }, + "strict": { + "definitions": { + "userExtraFlagsProperties": { + "propertyNames": { + "not": { + "pattern": "^compiler\\.((c)|(c\\.elf)|(S)|(cpp)|(ar)|(objcopy.eep)|(elf2hex))\\.extra_flags$" + } + } + } + }, + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertyNamesObjects/base/object" + }, + { + "$ref": "#/definitions/propertyNamesObjects/strict/definitions/userExtraFlagsProperties" + } + ] + } + } + }, + "requiredObjects": { + "boardID": { + "base": { + "object": { + "allOf": [ + { + "required": ["name", "build.core", "upload.tool"] + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/boardID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/boardID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/boardID/base/object" + }, + { + "required": ["build.board", "upload.maximum_size", "upload.maximum_data_size"] + } + ] + } + } + } + }, + "enumObjects": { + "booleanString": { + "enum": ["true", "false"] + } + } + } +} +`) + +func arduinoBoardsTxtDefinitionsSchemaJsonBytes() ([]byte, error) { + return _arduinoBoardsTxtDefinitionsSchemaJson, nil +} + +func arduinoBoardsTxtDefinitionsSchemaJson() (*asset, error) { + bytes, err := arduinoBoardsTxtDefinitionsSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-boards-txt-definitions-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _arduinoBoardsTxtPermissiveSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-permissive-schema.json", + "title": "Arduino boards.txt JSON permissive schema", + "description": "boards.txt contains the boards definitions of Arduino platforms. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + "$comment": "For information on the boards.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "properties": { + "menu": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/menu/permissive/object" + } + }, + "patternProperties": { + "^([^m].*|m([^e].*)?|me([^n].*)?|men([^u].*)?|menu.+)$": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/boardID/permissive/object" + } + } +} +`) + +func arduinoBoardsTxtPermissiveSchemaJsonBytes() ([]byte, error) { + return _arduinoBoardsTxtPermissiveSchemaJson, nil +} + +func arduinoBoardsTxtPermissiveSchemaJson() (*asset, error) { + bytes, err := arduinoBoardsTxtPermissiveSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-boards-txt-permissive-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _arduinoBoardsTxtSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-schema.json", + "title": "Arduino boards.txt JSON schema", + "description": "boards.txt contains the boards definitions of Arduino platforms. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + "$comment": "For information on the boards.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "properties": { + "menu": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/menu/specification/object" + } + }, + "patternProperties": { + "^([^m].*|m([^e].*)?|me([^n].*)?|men([^u].*)?|menu.+)$": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/boardID/specification/object" + } + } +} +`) + +func arduinoBoardsTxtSchemaJsonBytes() ([]byte, error) { + return _arduinoBoardsTxtSchemaJson, nil +} + +func arduinoBoardsTxtSchemaJson() (*asset, error) { + bytes, err := arduinoBoardsTxtSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-boards-txt-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _arduinoBoardsTxtStrictSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-boards-txt-strict-schema.json", + "title": "Arduino boards.txt JSON strict schema", + "description": "boards.txt contains the boards definitions of Arduino platforms. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#boardstxt", + "$comment": "For information on the boards.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "properties": { + "menu": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/menu/strict/object" + } + }, + "patternProperties": { + "^([^m].*|m([^e].*)?|me([^n].*)?|men([^u].*)?|menu.+)$": { + "$ref": "arduino-boards-txt-definitions-schema.json#/definitions/propertiesObjects/boardID/strict/object" + } + } +} +`) + +func arduinoBoardsTxtStrictSchemaJsonBytes() ([]byte, error) { + return _arduinoBoardsTxtStrictSchemaJson, nil +} + +func arduinoBoardsTxtStrictSchemaJson() (*asset, error) { + bytes, err := arduinoBoardsTxtStrictSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-boards-txt-strict-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _arduinoLibraryPropertiesDefinitionsSchemaJson = []byte(`{ "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-definitions-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-definitions-schema.json", "title": "Shared definitions for the Arduino library.properties schemas", "type": "object", "definitions": { @@ -942,7 +2053,7 @@ func arduinoLibraryPropertiesDefinitionsSchemaJson() (*asset, error) { var _arduinoLibraryPropertiesPermissiveSchemaJson = []byte(`{ "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-permissive-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-permissive-schema.json", "title": "Arduino library.properties JSON permissive schema", "description": "library.properties is the metadata file for Arduino libraries. This schema defines the minimum requirements for this file. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-metadata", "$comment": "For information on the Arduino library.properties format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", @@ -1022,7 +2133,7 @@ func arduinoLibraryPropertiesPermissiveSchemaJson() (*asset, error) { var _arduinoLibraryPropertiesSchemaJson = []byte(`{ "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-schema.json", "title": "Arduino library.properties JSON schema", "description": "library.properties is the metadata file for Arduino libraries. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-metadata", "$comment": "For information on the Arduino library.properties format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", @@ -1102,7 +2213,7 @@ func arduinoLibraryPropertiesSchemaJson() (*asset, error) { var _arduinoLibraryPropertiesStrictSchemaJson = []byte(`{ "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/arduino-library-properties-strict-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-library-properties-strict-schema.json", "title": "Arduino library.properties strict JSON schema", "description": "library.properties is the metadata file for Arduino libraries. This schema defines the recommended format. See: https://arduino.github.io/arduino-cli/latest/library-specification/#library-metadata", "$comment": "For information on the Arduino library.properties format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", @@ -1180,9 +2291,324 @@ func arduinoLibraryPropertiesStrictSchemaJson() (*asset, error) { return a, nil } +var _arduinoProgrammersTxtDefinitionsSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-definitions-schema.json", + "title": "Shared definitions for the Arduino programmers.txt schemas", + "definitions": { + "propertiesObjects": { + "programmerID": { + "base": { + "object": { + "allOf": [ + { + "type": "object" + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/programmerIDName/permissive/object" + }, + "program.tool": { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/permissive/object" + } + } + }, + { + "$ref": "#/definitions/requiredObjects/programmerID/permissive/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/programmerIDName/specification/object" + }, + "program.tool": { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/specification/object" + } + } + }, + { + "$ref": "#/definitions/requiredObjects/programmerID/specification/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerID/base/object" + }, + { + "properties": { + "name": { + "$ref": "#/definitions/propertiesObjects/programmerIDName/strict/object" + }, + "program.tool": { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/strict/object" + } + } + }, + { + "$ref": "#/definitions/requiredObjects/programmerID/strict/object" + } + ] + } + } + }, + "programmerIDName": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDName/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDName/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDName/base/object" + } + ] + } + } + }, + "programmerIDProgramTool": { + "base": { + "object": { + "allOf": [ + { + "type": "string" + }, + { + "minLength": 1 + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/propertiesObjects/programmerIDProgramTool/base/object" + } + ] + } + } + } + }, + "requiredObjects": { + "programmerID": { + "base": { + "object": { + "allOf": [ + { + "required": ["name", "program.tool"] + } + ] + } + }, + "permissive": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/programmerID/base/object" + } + ] + } + }, + "specification": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/programmerID/base/object" + } + ] + } + }, + "strict": { + "object": { + "allOf": [ + { + "$ref": "#/definitions/requiredObjects/programmerID/base/object" + } + ] + } + } + } + } + } +} +`) + +func arduinoProgrammersTxtDefinitionsSchemaJsonBytes() ([]byte, error) { + return _arduinoProgrammersTxtDefinitionsSchemaJson, nil +} + +func arduinoProgrammersTxtDefinitionsSchemaJson() (*asset, error) { + bytes, err := arduinoProgrammersTxtDefinitionsSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-programmers-txt-definitions-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _arduinoProgrammersTxtPermissiveSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-permissive-schema.json", + "title": "Arduino programmers.txt JSON permissive schema", + "description": "programmers.txt contains the definitions of Arduino hardware programmers. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + "$comment": "For information on the programmers.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "patternProperties": { + ".+": { + "$ref": "arduino-programmers-txt-definitions-schema.json#/definitions/propertiesObjects/programmerID/permissive/object" + } + } +} +`) + +func arduinoProgrammersTxtPermissiveSchemaJsonBytes() ([]byte, error) { + return _arduinoProgrammersTxtPermissiveSchemaJson, nil +} + +func arduinoProgrammersTxtPermissiveSchemaJson() (*asset, error) { + bytes, err := arduinoProgrammersTxtPermissiveSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-programmers-txt-permissive-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _arduinoProgrammersTxtSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-schema.json", + "title": "Arduino programmers.txt JSON schema", + "description": "programmers.txt contains the definitions of Arduino hardware programmers. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + "$comment": "For information on the programmers.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "patternProperties": { + ".+": { + "$ref": "arduino-programmers-txt-definitions-schema.json#/definitions/propertiesObjects/programmerID/specification/object" + } + } +} +`) + +func arduinoProgrammersTxtSchemaJsonBytes() ([]byte, error) { + return _arduinoProgrammersTxtSchemaJson, nil +} + +func arduinoProgrammersTxtSchemaJson() (*asset, error) { + bytes, err := arduinoProgrammersTxtSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-programmers-txt-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _arduinoProgrammersTxtStrictSchemaJson = []byte(`{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/arduino-programmers-txt-strict-schema.json", + "title": "Arduino programmers.txt JSON strict schema", + "description": "programmers.txt contains the definitions of Arduino hardware programmers. See: https://arduino.github.io/arduino-cli/latest/platform-specification/#programmerstxt", + "$comment": "For information on the programmers.txt format, see https://godoc.org/github.com/arduino/go-properties-orderedmap", + "type": "object", + "patternProperties": { + ".+": { + "$ref": "arduino-programmers-txt-definitions-schema.json#/definitions/propertiesObjects/programmerID/strict/object" + } + } +} +`) + +func arduinoProgrammersTxtStrictSchemaJsonBytes() ([]byte, error) { + return _arduinoProgrammersTxtStrictSchemaJson, nil +} + +func arduinoProgrammersTxtStrictSchemaJson() (*asset, error) { + bytes, err := arduinoProgrammersTxtStrictSchemaJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "arduino-programmers-txt-strict-schema.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _generalDefinitionsSchemaJson = []byte(`{ "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schema/general-definitions-schema.json", + "$id": "https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/schemas/general-definitions-schema.json", "title": "Shared definitions", "description": "Definitions for use in schemas.", "type": "object", @@ -1268,10 +2694,18 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ + "arduino-boards-txt-definitions-schema.json": arduinoBoardsTxtDefinitionsSchemaJson, + "arduino-boards-txt-permissive-schema.json": arduinoBoardsTxtPermissiveSchemaJson, + "arduino-boards-txt-schema.json": arduinoBoardsTxtSchemaJson, + "arduino-boards-txt-strict-schema.json": arduinoBoardsTxtStrictSchemaJson, "arduino-library-properties-definitions-schema.json": arduinoLibraryPropertiesDefinitionsSchemaJson, "arduino-library-properties-permissive-schema.json": arduinoLibraryPropertiesPermissiveSchemaJson, "arduino-library-properties-schema.json": arduinoLibraryPropertiesSchemaJson, "arduino-library-properties-strict-schema.json": arduinoLibraryPropertiesStrictSchemaJson, + "arduino-programmers-txt-definitions-schema.json": arduinoProgrammersTxtDefinitionsSchemaJson, + "arduino-programmers-txt-permissive-schema.json": arduinoProgrammersTxtPermissiveSchemaJson, + "arduino-programmers-txt-schema.json": arduinoProgrammersTxtSchemaJson, + "arduino-programmers-txt-strict-schema.json": arduinoProgrammersTxtStrictSchemaJson, "general-definitions-schema.json": generalDefinitionsSchemaJson, } @@ -1316,10 +2750,18 @@ type bintree struct { } var _bintree = &bintree{nil, map[string]*bintree{ + "arduino-boards-txt-definitions-schema.json": &bintree{arduinoBoardsTxtDefinitionsSchemaJson, map[string]*bintree{}}, + "arduino-boards-txt-permissive-schema.json": &bintree{arduinoBoardsTxtPermissiveSchemaJson, map[string]*bintree{}}, + "arduino-boards-txt-schema.json": &bintree{arduinoBoardsTxtSchemaJson, map[string]*bintree{}}, + "arduino-boards-txt-strict-schema.json": &bintree{arduinoBoardsTxtStrictSchemaJson, map[string]*bintree{}}, "arduino-library-properties-definitions-schema.json": &bintree{arduinoLibraryPropertiesDefinitionsSchemaJson, map[string]*bintree{}}, "arduino-library-properties-permissive-schema.json": &bintree{arduinoLibraryPropertiesPermissiveSchemaJson, map[string]*bintree{}}, "arduino-library-properties-schema.json": &bintree{arduinoLibraryPropertiesSchemaJson, map[string]*bintree{}}, "arduino-library-properties-strict-schema.json": &bintree{arduinoLibraryPropertiesStrictSchemaJson, map[string]*bintree{}}, + "arduino-programmers-txt-definitions-schema.json": &bintree{arduinoProgrammersTxtDefinitionsSchemaJson, map[string]*bintree{}}, + "arduino-programmers-txt-permissive-schema.json": &bintree{arduinoProgrammersTxtPermissiveSchemaJson, map[string]*bintree{}}, + "arduino-programmers-txt-schema.json": &bintree{arduinoProgrammersTxtSchemaJson, map[string]*bintree{}}, + "arduino-programmers-txt-strict-schema.json": &bintree{arduinoProgrammersTxtStrictSchemaJson, map[string]*bintree{}}, "general-definitions-schema.json": &bintree{generalDefinitionsSchemaJson, map[string]*bintree{}}, }}