From 455001dfa1234abad1137389a22ab89c298c7cce Mon Sep 17 00:00:00 2001 From: per1234 Date: Tue, 1 Jun 2021 22:25:05 -0700 Subject: [PATCH 1/3] Use Arduino CLI infrastructure for querying library index In the past, I have found that using Arduino CLI infrastructure for handling projects is not always the right choice because Arduino CLI is intended to be resilient to sub-ideal project configurations when feasible, whereas Arduino Lint is intended to enforce or encourage ideal project configurations. However, Arduino Lint is not intended to lint the Library Manager index, so using Arduino CLI's code for querying the index should be safe and avoid the problems associated with the code duplication that would be the alternative. --- internal/project/projectdata/library.go | 34 +++++++++++++++++-------- internal/rule/rulefunction/library.go | 11 ++------ 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/internal/project/projectdata/library.go b/internal/project/projectdata/library.go index 211ff3db..02346a8a 100644 --- a/internal/project/projectdata/library.go +++ b/internal/project/projectdata/library.go @@ -16,12 +16,12 @@ package projectdata import ( - "encoding/json" - "io/ioutil" + "io" "net/http" "os" "github.com/arduino/arduino-cli/arduino/libraries" + "github.com/arduino/arduino-cli/arduino/libraries/librariesmanager" "github.com/arduino/arduino-lint/internal/configuration" "github.com/arduino/arduino-lint/internal/configuration/rulemode" "github.com/arduino/arduino-lint/internal/project" @@ -29,6 +29,7 @@ import ( "github.com/arduino/arduino-lint/internal/result/feedback" "github.com/arduino/arduino-lint/internal/rule/schema" "github.com/arduino/arduino-lint/internal/rule/schema/compliancelevel" + "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/client9/misspell" "github.com/sirupsen/logrus" @@ -60,23 +61,34 @@ func InitializeForLibrary(project project.Type) { // Download the Library Manager index if needed. if !configuration.RuleModes(project.SuperprojectType)[rulemode.LibraryManagerIndexing] && libraryManagerIndex == nil { - url := "http://downloads.arduino.cc/libraries/library_index.json" - httpResponse, err := http.Get(url) + // Set up the temporary folder for the index + libraryIndexFolderPath, err := paths.TempDir().MkTempDir("arduino-lint-library-index-folder") + defer libraryIndexFolderPath.RemoveAll() if err != nil { - feedback.Errorf("Unable to download Library Manager index from %s: %s", err, url) + panic(err) + } + libraryIndexPath := libraryIndexFolderPath.Join("library_index.json") + + // Download the index data + httpResponse, err := http.Get(librariesmanager.LibraryIndexURL.String()) + if err != nil { + feedback.Errorf("Unable to download Library Manager index from %s: %s", err, librariesmanager.LibraryIndexURL) os.Exit(1) } defer httpResponse.Body.Close() - bytes, err := ioutil.ReadAll(httpResponse.Body) + // Write the index data to file + libraryIndexFile, err := libraryIndexPath.Create() + defer libraryIndexFile.Close() if err != nil { panic(err) } - - err = json.Unmarshal(bytes, &libraryManagerIndex) - if err != nil { + if _, err := io.Copy(libraryIndexFile, httpResponse.Body); err != nil { panic(err) } + + libraryManagerIndex = librariesmanager.NewLibraryManager(libraryIndexFolderPath, nil) + libraryManagerIndex.LoadIndex() } if misspelledWordsReplacer == nil { // The replacer only needs to be compiled once per run. @@ -120,10 +132,10 @@ func SourceHeaders() []string { return sourceHeaders } -var libraryManagerIndex map[string]interface{} +var libraryManagerIndex *librariesmanager.LibrariesManager // LibraryManagerIndex returns the Library Manager index data. -func LibraryManagerIndex() map[string]interface{} { +func LibraryManagerIndex() *librariesmanager.LibrariesManager { return libraryManagerIndex } diff --git a/internal/rule/rulefunction/library.go b/internal/rule/rulefunction/library.go index db72dd8d..b8b07ebc 100644 --- a/internal/rule/rulefunction/library.go +++ b/internal/rule/rulefunction/library.go @@ -1461,15 +1461,8 @@ func IncorrectExamplesFolderNameCase() (result ruleresult.Type, output string) { // nameInLibraryManagerIndex returns whether there is a library in Library Manager index using the given name. func nameInLibraryManagerIndex(name string) bool { - libraries := projectdata.LibraryManagerIndex()["libraries"].([]interface{}) - for _, libraryInterface := range libraries { - library := libraryInterface.(map[string]interface{}) - if library["name"].(string) == name { - return true - } - } - - return false + library := projectdata.LibraryManagerIndex().Index.FindIndexedLibrary(&libraries.Library{Name: name}) + return library != nil } // spellCheckLibraryPropertiesFieldValue returns the value of the provided library.properties field with commonly misspelled words corrected. From 4961340130ba0e4f6d69808446b780245dab328f Mon Sep 17 00:00:00 2001 From: per1234 Date: Tue, 1 Jun 2021 20:37:50 -0700 Subject: [PATCH 2/3] Add support for version constraints in depends field Arduino CLI and the Library Manager indexer has some provisional support for specifying version constraints in the library.properties depends field. Although undocumented, this syntax is fully supported by the other tools, so Arduino Lint's previous treatment of libraries using this feature as invalid is incorrect. --- ...library-properties-definitions-schema.json | 16 ++----- .../librarypropertiesschemas_test.go | 47 +++++++++++++++++++ .../ruleconfiguration/ruleconfiguration.go | 6 +-- internal/rule/rulefunction/library.go | 4 +- internal/rule/rulefunction/library_test.go | 6 +-- .../libraries/DependsValid/library.properties | 11 +++++ .../libraries/DependsValid/src/DependsValid.h | 0 internal/rule/schema/schemadata/bindata.go | 16 ++----- 8 files changed, 72 insertions(+), 34 deletions(-) create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsValid/library.properties create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsValid/src/DependsValid.h diff --git a/etc/schemas/arduino-library-properties-definitions-schema.json b/etc/schemas/arduino-library-properties-definitions-schema.json index c9d8b938..90e4d294 100644 --- a/etc/schemas/arduino-library-properties-definitions-schema.json +++ b/etc/schemas/arduino-library-properties-definitions-schema.json @@ -21,13 +21,7 @@ "allowedCharacters": { "allOf": [ { - "$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject" - }, - { - "not": { - "$comment": "The depends property is a comma separated list of names, so a valid name pattern is a valid depends pattern with the comma excluded", - "pattern": "^.*,.*$" - } + "pattern": "^(([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))*$" } ] } @@ -494,18 +488,14 @@ }, "depends": { "base": { - "definitions": { - "patternObject": { - "pattern": "^(([a-zA-Z][a-zA-Z0-9 _\\.\\-,]*)|([0-9][a-zA-Z0-9 _\\.\\-]*[a-zA-Z][a-zA-Z0-9 _\\.\\-,]*))*$" - } - }, "object": { "allOf": [ { "type": "string" }, { - "$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject" + "$comment": "Based on #/definitions/propertiesObjects/name/base/definitions/patternObjects/allowedCharacters and general-definitions-schema.json#/definitions/patternObjects/relaxedSemver", + "pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?))?$" } ] } diff --git a/internal/project/library/libraryproperties/librarypropertiesschemas_test.go b/internal/project/library/libraryproperties/librarypropertiesschemas_test.go index 9bb064e4..f17270ca 100644 --- a/internal/project/library/libraryproperties/librarypropertiesschemas_test.go +++ b/internal/project/library/libraryproperties/librarypropertiesschemas_test.go @@ -330,6 +330,18 @@ func TestPropertiesUrlFormat(t *testing.T) { func TestPropertiesDependsPattern(t *testing.T) { testTables := []propertyValueTestTable{ + {"Valid name", "foo", compliancelevel.Permissive, assert.False}, + {"Valid name", "foo", compliancelevel.Specification, assert.False}, + {"Valid name", "foo", compliancelevel.Strict, assert.False}, + + {"Valid names", "foo,bar", compliancelevel.Permissive, assert.False}, + {"Valid names", "foo,bar", compliancelevel.Specification, assert.False}, + {"Valid names", "foo,bar", compliancelevel.Strict, assert.False}, + + {"Trailing comma", "foo,", compliancelevel.Permissive, assert.True}, + {"Trailing comma", "foo,", compliancelevel.Specification, assert.True}, + {"Trailing comma", "foo,", compliancelevel.Strict, assert.True}, + {"Invalid characters", "-foo", compliancelevel.Permissive, assert.True}, {"Invalid characters", "-foo", compliancelevel.Specification, assert.True}, {"Invalid characters", "-foo", compliancelevel.Strict, assert.True}, @@ -337,6 +349,41 @@ func TestPropertiesDependsPattern(t *testing.T) { {"Empty", "", compliancelevel.Permissive, assert.False}, {"Empty", "", compliancelevel.Specification, assert.False}, {"Empty", "", compliancelevel.Strict, assert.False}, + + {"=version", "foo (>=1.2.3)", compliancelevel.Permissive, assert.False}, + {">=version", "foo (>=1.2.3)", compliancelevel.Specification, assert.False}, + {">=version", "foo (>=1.2.3)", compliancelevel.Strict, assert.False}, + {">version", "foo (>1.2.3)", compliancelevel.Permissive, assert.False}, + {">version", "foo (>1.2.3)", compliancelevel.Specification, assert.False}, + {">version", "foo (>1.2.3)", compliancelevel.Strict, assert.False}, + + {"Relaxed version", "foo (=1.2)", compliancelevel.Permissive, assert.False}, + {"Relaxed version", "foo (=1.2)", compliancelevel.Specification, assert.False}, + {"Relaxed version", "foo (=1.2)", compliancelevel.Strict, assert.False}, + {"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Permissive, assert.False}, + {"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Specification, assert.False}, + {"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Strict, assert.False}, + + {"Invalid version", "foo (bar)", compliancelevel.Permissive, assert.True}, + {"Invalid version", "foo (bar)", compliancelevel.Specification, assert.True}, + {"Invalid version", "foo (bar)", compliancelevel.Strict, assert.True}, + + {"Version w/o space", "foo(>1.2.3)", compliancelevel.Permissive, assert.True}, + {"Version w/o space", "foo(>1.2.3)", compliancelevel.Specification, assert.True}, + {"Version w/o space", "foo(>1.2.3)", compliancelevel.Strict, assert.True}, + + {"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Permissive, assert.False}, + {"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Specification, assert.False}, + {"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Strict, assert.False}, } checkPropertyPatternMismatch("depends", testTables, t) diff --git a/internal/rule/ruleconfiguration/ruleconfiguration.go b/internal/rule/ruleconfiguration/ruleconfiguration.go index 414da657..e0fc1c3d 100644 --- a/internal/rule/ruleconfiguration/ruleconfiguration.go +++ b/internal/rule/ruleconfiguration/ruleconfiguration.go @@ -1007,15 +1007,15 @@ var configurations = []Type{ Category: "library.properties", Subcategory: "depends field", ID: "LP047", - Brief: "prohibited character in depends", + Brief: "invalid depends format", Description: "", - MessageTemplate: "Prohibited character(s) in library.properties depends field {{.}}. See: https://arduino.github.io/arduino-cli/latest/library-specification/#libraryproperties-file-format", + MessageTemplate: "Invalid format of library.properties depends field {{.}}. See: https://arduino.github.io/arduino-cli/latest/library-specification/#libraryproperties-file-format", DisableModes: nil, EnableModes: []rulemode.Type{rulemode.Default}, InfoModes: nil, WarningModes: nil, ErrorModes: []rulemode.Type{rulemode.Default}, - RuleFunction: rulefunction.LibraryPropertiesDependsFieldDisallowedCharacters, + RuleFunction: rulefunction.LibraryPropertiesDependsFieldInvalidFormat, }, { ProjectType: projecttype.Library, diff --git a/internal/rule/rulefunction/library.go b/internal/rule/rulefunction/library.go index b8b07ebc..371814b4 100644 --- a/internal/rule/rulefunction/library.go +++ b/internal/rule/rulefunction/library.go @@ -1158,8 +1158,8 @@ func LibraryPropertiesArchitecturesFieldValueCase() (result ruleresult.Type, out return ruleresult.Pass, "" } -// LibraryPropertiesDependsFieldDisallowedCharacters checks for disallowed characters in the library.properties "depends" field. -func LibraryPropertiesDependsFieldDisallowedCharacters() (result ruleresult.Type, output string) { +// LibraryPropertiesDependsFieldInvalidFormat checks for the library.properties "depends" field having an invalid format. +func LibraryPropertiesDependsFieldInvalidFormat() (result ruleresult.Type, output string) { if projectdata.LibraryPropertiesLoadError() != nil { return ruleresult.NotRun, "Couldn't load library.properties" } diff --git a/internal/rule/rulefunction/library_test.go b/internal/rule/rulefunction/library_test.go index fb2f2a3d..530427bc 100644 --- a/internal/rule/rulefunction/library_test.go +++ b/internal/rule/rulefunction/library_test.go @@ -794,15 +794,15 @@ func TestLibraryPropertiesArchitecturesFieldValueCase(t *testing.T) { checkLibraryRuleFunction(LibraryPropertiesArchitecturesFieldValueCase, testTables, t) } -func TestLibraryPropertiesDependsFieldDisallowedCharacters(t *testing.T) { +func TestLibraryPropertiesDependsFieldInvalidFormat(t *testing.T) { testTables := []libraryRuleFunctionTestTable{ {"Invalid", "InvalidLibraryProperties", ruleresult.NotRun, ""}, {"Legacy", "Legacy", ruleresult.Skip, ""}, {"Depends field has disallowed characters", "DependsHasBadChars", ruleresult.Fail, ""}, - {"Valid", "DependsIndexed", ruleresult.Pass, ""}, + {"Valid", "DependsValid", ruleresult.Pass, ""}, } - checkLibraryRuleFunction(LibraryPropertiesDependsFieldDisallowedCharacters, testTables, t) + checkLibraryRuleFunction(LibraryPropertiesDependsFieldInvalidFormat, testTables, t) } func TestLibraryPropertiesDependsFieldNotInIndex(t *testing.T) { diff --git a/internal/rule/rulefunction/testdata/libraries/DependsValid/library.properties b/internal/rule/rulefunction/testdata/libraries/DependsValid/library.properties new file mode 100644 index 00000000..313ff6f1 --- /dev/null +++ b/internal/rule/rulefunction/testdata/libraries/DependsValid/library.properties @@ -0,0 +1,11 @@ +name=DependsValid +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr +depends=Servo , Adafruit NeoPixel,Stepper (<1.1.3) , Mouse (<=1.0.0),Keyboard (=1.2.3-beta),Ethernet (>=2.0),WiFiNINA (>0.0.8) +includes=DependsValid.h diff --git a/internal/rule/rulefunction/testdata/libraries/DependsValid/src/DependsValid.h b/internal/rule/rulefunction/testdata/libraries/DependsValid/src/DependsValid.h new file mode 100644 index 00000000..e69de29b diff --git a/internal/rule/schema/schemadata/bindata.go b/internal/rule/schema/schemadata/bindata.go index 16cc58ce..76c99be6 100644 --- a/internal/rule/schema/schemadata/bindata.go +++ b/internal/rule/schema/schemadata/bindata.go @@ -1440,13 +1440,7 @@ var _arduinoLibraryPropertiesDefinitionsSchemaJson = []byte(`{ "allowedCharacters": { "allOf": [ { - "$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject" - }, - { - "not": { - "$comment": "The depends property is a comma separated list of names, so a valid name pattern is a valid depends pattern with the comma excluded", - "pattern": "^.*,.*$" - } + "pattern": "^(([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))*$" } ] } @@ -1913,18 +1907,14 @@ var _arduinoLibraryPropertiesDefinitionsSchemaJson = []byte(`{ }, "depends": { "base": { - "definitions": { - "patternObject": { - "pattern": "^(([a-zA-Z][a-zA-Z0-9 _\\.\\-,]*)|([0-9][a-zA-Z0-9 _\\.\\-]*[a-zA-Z][a-zA-Z0-9 _\\.\\-,]*))*$" - } - }, "object": { "allOf": [ { "type": "string" }, { - "$ref": "#/definitions/propertiesObjects/depends/base/definitions/patternObject" + "$comment": "Based on #/definitions/propertiesObjects/name/base/definitions/patternObjects/allowedCharacters and general-definitions-schema.json#/definitions/patternObjects/relaxedSemver", + "pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?))?$" } ] } From 4674bc7e58ba4fc619d035274a54a570c35aa0cd Mon Sep 17 00:00:00 2001 From: per1234 Date: Wed, 2 Jun 2021 00:28:06 -0700 Subject: [PATCH 3/3] Add support for dependency constraints to LP048 The library.properties depends field is used to specify the library dependencies. Although currently undocumented, Arduino CLI and the Library Manager indexer both have provisional support for dependency version constraints. Previously, LP048 did not have any support for the constraint syntax, which caused a spurious failure when they were in use. This commit adds support for the constraint syntax and also causes the constraint information to be used when checking if the dependency is provided by the index. --- internal/rule/rulefunction/library.go | 54 +++++++++++++++---- internal/rule/rulefunction/library_test.go | 5 +- .../library.properties | 11 ++++ .../src/DependsConstraintNotIndexed.h | 0 .../DependsIndexed/library.properties | 2 +- 5 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/library.properties create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/src/DependsConstraintNotIndexed.h diff --git a/internal/rule/rulefunction/library.go b/internal/rule/rulefunction/library.go index 371814b4..0417301f 100644 --- a/internal/rule/rulefunction/library.go +++ b/internal/rule/rulefunction/library.go @@ -22,9 +22,11 @@ import ( "net/http" "os" "path/filepath" + "regexp" "strings" "github.com/arduino/arduino-cli/arduino/libraries" + "github.com/arduino/arduino-cli/arduino/libraries/librariesindex" "github.com/arduino/arduino-cli/arduino/utils" "github.com/arduino/arduino-lint/internal/project/library" "github.com/arduino/arduino-lint/internal/project/projectdata" @@ -1187,21 +1189,55 @@ func LibraryPropertiesDependsFieldNotInIndex() (result ruleresult.Type, output s return ruleresult.Skip, "Field not present" } - dependencies := commaSeparatedToList(depends) + dependsList := commaSeparatedToList(depends) - dependenciesNotInIndex := []string{} - for _, dependency := range dependencies { - if dependency == "" { + var dependencyRegexp = regexp.MustCompile("^([^()]+?) *(?:\\((.+)\\))?$") + dependsNotInIndex := []string{} + for _, depend := range dependsList { + // Process raw depend string into a dependency object + if depend == "" { + // This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat() continue } - logrus.Tracef("Checking if dependency %s is in index.", dependency) - if !nameInLibraryManagerIndex(dependency) { - dependenciesNotInIndex = append(dependenciesNotInIndex, dependency) + dependencyData := dependencyRegexp.FindAllStringSubmatch(depend, -1) + if dependencyData == nil { + // This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat() + continue + } + dependencyConstraint, err := semver.ParseConstraint(dependencyData[0][2]) + if err != nil { + // This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat() + continue + } + var dependency semver.Dependency = &librariesindex.Dependency{ + Name: dependencyData[0][1], + VersionConstraint: dependencyConstraint, + } + + logrus.Tracef("Checking if dependency %s is in index.", depend) + // Get all releases of the dependency + library := projectdata.LibraryManagerIndex().Index.FindIndexedLibrary(&libraries.Library{Name: dependency.GetName()}) + if library == nil { + logrus.Tracef("Dependency is not in the index.") + dependsNotInIndex = append(dependsNotInIndex, depend) + continue + } + // Convert the dependency's libraries.Library object to a semver.Releases object + var releases semver.Releases + for _, release := range library.Releases { + releases = append(releases, release) + } + // Filter the dependency's releases according to the dependency's constraint + dependencyReleases := releases.FilterBy(dependency) + if len(dependencyReleases) == 0 { + logrus.Tracef("No releases match dependency's constraint.") + dependsNotInIndex = append(dependsNotInIndex, depend) + continue } } - if len(dependenciesNotInIndex) > 0 { - return ruleresult.Fail, strings.Join(dependenciesNotInIndex, ", ") + if len(dependsNotInIndex) > 0 { + return ruleresult.Fail, strings.Join(dependsNotInIndex, ", ") } return ruleresult.Pass, "" diff --git a/internal/rule/rulefunction/library_test.go b/internal/rule/rulefunction/library_test.go index 530427bc..b1f30462 100644 --- a/internal/rule/rulefunction/library_test.go +++ b/internal/rule/rulefunction/library_test.go @@ -808,8 +808,11 @@ func TestLibraryPropertiesDependsFieldInvalidFormat(t *testing.T) { func TestLibraryPropertiesDependsFieldNotInIndex(t *testing.T) { testTables := []libraryRuleFunctionTestTable{ {"Unable to load", "InvalidLibraryProperties", ruleresult.NotRun, ""}, + {"Legacy", "Legacy", ruleresult.Skip, ""}, + {"No depends field", "MissingFields", ruleresult.Skip, ""}, {"Dependency not in index", "DependsNotIndexed", ruleresult.Fail, "^NotIndexed$"}, - {"Dependency in index", "DependsIndexed", ruleresult.Pass, ""}, + {"Dependency constraint not in index", "DependsConstraintNotIndexed", ruleresult.Fail, "^Servo \\(=0\\.0\\.1\\)$"}, + {"Dependencies in index", "DependsIndexed", ruleresult.Pass, ""}, {"Depends field empty", "DependsEmpty", ruleresult.Pass, ""}, {"No depends", "NoDepends", ruleresult.Skip, ""}, } diff --git a/internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/library.properties b/internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/library.properties new file mode 100644 index 00000000..3b90c6f5 --- /dev/null +++ b/internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/library.properties @@ -0,0 +1,11 @@ +name=DependsConstraintNotIndexed +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr +depends=Servo (=0.0.1) +includes=DependsConstraintNotIndexed.h diff --git a/internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/src/DependsConstraintNotIndexed.h b/internal/rule/rulefunction/testdata/libraries/DependsConstraintNotIndexed/src/DependsConstraintNotIndexed.h new file mode 100644 index 00000000..e69de29b diff --git a/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties b/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties index 35691134..06d2811f 100644 --- a/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties +++ b/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties @@ -7,4 +7,4 @@ paragraph=Supports HTTP1.1 and you can do GET and POST. category=Communication url=http://example.com/ architectures=avr -depends=Servo, , Adafruit NeoPixel +depends=,(foo),foo (bar),Adafruit NeoPixel,Servo (<1.1.4),Stepper (<=1.1.3),Mouse (=1.0.0),Keyboard (>=1.0.1),WiFiNINA (>1.0.0)