github.com/google/osv-scalibr@v0.4.1/semantic/parse_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package semantic_test
    16  
    17  import (
    18  	"errors"
    19  	"testing"
    20  
    21  	"github.com/google/osv-scalibr/semantic"
    22  )
    23  
    24  var ecosystems = []string{
    25  	"AlmaLinux",
    26  	"Alpaquita",
    27  	"Alpine",
    28  	"BellSoft Hardened Containers",
    29  	"Bioconductor",
    30  	"Bitnami",
    31  	"Chainguard",
    32  	"ConanCenter",
    33  	"CRAN",
    34  	"crates.io",
    35  	"Debian",
    36  	"GHC",
    37  	"Go",
    38  	"Hex",
    39  	"Julia",
    40  	"Mageia",
    41  	"Maven",
    42  	"MinimOS",
    43  	"npm",
    44  	"NuGet",
    45  	"openEuler",
    46  	"openSUSE",
    47  	"Packagist",
    48  	"Pub",
    49  	"PyPI",
    50  	"Rocky Linux",
    51  	"RubyGems",
    52  	"SUSE",
    53  	"SwiftURL",
    54  	"Ubuntu",
    55  	"Wolfi",
    56  }
    57  
    58  func TestParse(t *testing.T) {
    59  	for _, ecosystem := range ecosystems {
    60  		_, err := semantic.Parse("", ecosystem)
    61  
    62  		if errors.Is(err, semantic.ErrUnsupportedEcosystem) {
    63  			t.Errorf("'%s' is not a supported ecosystem", ecosystem)
    64  		}
    65  	}
    66  }
    67  
    68  func TestParse_EcosystemWithSuffix(t *testing.T) {
    69  	ecosystems := []string{
    70  		"Debian:13",
    71  		"Alpine:v3.9",
    72  		"Red Hat:ansible_automation_platform:2.0::el8",
    73  		"Ubuntu:Pro:24.04:LTS",
    74  	}
    75  	for _, ecosystem := range ecosystems {
    76  		_, err := semantic.Parse("", ecosystem)
    77  
    78  		if errors.Is(err, semantic.ErrUnsupportedEcosystem) {
    79  			t.Errorf("'%s' is not a supported ecosystem", ecosystem)
    80  		}
    81  	}
    82  }
    83  
    84  func TestParse_InvalidVersions(t *testing.T) {
    85  	type args struct {
    86  		versions  []string
    87  		ecosystem string
    88  	}
    89  	tests := []struct {
    90  		name string
    91  		args args
    92  	}{
    93  		{
    94  			name: "invalid_cran_versions",
    95  			args: args{
    96  				versions:  []string{"!", "?", "1.a.2", "z.c.3"},
    97  				ecosystem: "CRAN",
    98  			},
    99  		},
   100  		{
   101  			name: "invalid_debian_versions",
   102  			args: args{
   103  				versions:  []string{"1.2.3-not-a-debian:version!@#$"},
   104  				ecosystem: "Debian",
   105  			},
   106  		},
   107  		{
   108  			name: "invalid_hackage_versions",
   109  			args: args{
   110  				versions:  []string{"1.2.3.4.5-notallowed"},
   111  				ecosystem: "Hackage",
   112  			},
   113  		},
   114  	}
   115  	for _, tt := range tests {
   116  		t.Run(tt.name, func(t *testing.T) {
   117  			for _, version := range tt.args.versions {
   118  				_, err := semantic.Parse(version, tt.args.ecosystem)
   119  
   120  				if err == nil {
   121  					t.Errorf("expected error for '%s', got nil", version)
   122  
   123  					continue
   124  				}
   125  
   126  				if !errors.Is(err, semantic.ErrInvalidVersion) {
   127  					t.Errorf("expected ErrInvalidVersion for '%s', got '%v'", version, err)
   128  				}
   129  			}
   130  		})
   131  	}
   132  }
   133  
   134  func TestMustParse(t *testing.T) {
   135  	defer func() {
   136  		if r := recover(); r != nil {
   137  			t.Errorf("unexpected panic - '%s'", r)
   138  		}
   139  	}()
   140  
   141  	for _, ecosystem := range ecosystems {
   142  		semantic.MustParse("", ecosystem)
   143  	}
   144  }
   145  
   146  func TestMustParse_InvalidVersions(t *testing.T) {
   147  	type args struct {
   148  		versions  []string
   149  		ecosystem string
   150  	}
   151  	tests := []struct {
   152  		name string
   153  		args args
   154  	}{
   155  		{
   156  			name: "invalid_ecosystem",
   157  			args: args{
   158  				versions:  []string{""},
   159  				ecosystem: "<unknown>",
   160  			},
   161  		},
   162  		{
   163  			name: "invalid_cran_versions",
   164  			args: args{
   165  				versions:  []string{"!", "?", "1.a.2", "z.c.3"},
   166  				ecosystem: "CRAN",
   167  			},
   168  		},
   169  		{
   170  			name: "invalid_debian_versions",
   171  			args: args{
   172  				versions:  []string{"1.2.3-not-a-debian:version!@#$"},
   173  				ecosystem: "Debian",
   174  			},
   175  		},
   176  		{
   177  			name: "invalid_hackage_versions",
   178  			args: args{
   179  				versions:  []string{"1.2.3.4.5-notallowed"},
   180  				ecosystem: "Hackage",
   181  			},
   182  		},
   183  	}
   184  	for _, tt := range tests {
   185  		t.Run(tt.name, func(t *testing.T) {
   186  			defer func() {
   187  				if r := recover(); r == nil {
   188  					t.Errorf("expected panic, got nil")
   189  				}
   190  			}()
   191  
   192  			for _, version := range tt.args.versions {
   193  				semantic.MustParse(version, tt.args.ecosystem)
   194  
   195  				// if we reached here, then we can't have panicked
   196  				t.Errorf("function did not panic when given invalid version '%s'", version)
   197  			}
   198  		})
   199  	}
   200  }