github.com/google/osv-scalibr@v0.4.1/inventory/osvecosystem/parsed_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 osvecosystem_test contains tests for the osvecosystem package.
    16  package osvecosystem_test
    17  
    18  import (
    19  	"encoding/json"
    20  	"reflect"
    21  	"testing"
    22  
    23  	"github.com/google/osv-scalibr/inventory/osvecosystem"
    24  	"github.com/ossf/osv-schema/bindings/go/osvconstants"
    25  )
    26  
    27  type testCase struct {
    28  	string string
    29  	parsed osvecosystem.Parsed
    30  }
    31  
    32  func buildCases(t *testing.T) []testCase {
    33  	t.Helper()
    34  
    35  	return []testCase{
    36  		{
    37  			string: "crates.io",
    38  			parsed: osvecosystem.Parsed{
    39  				Ecosystem: osvconstants.EcosystemCratesIO,
    40  				Suffix:    "",
    41  			},
    42  		},
    43  		{
    44  			string: "npm",
    45  			parsed: osvecosystem.Parsed{
    46  				Ecosystem: osvconstants.EcosystemNPM,
    47  				Suffix:    "",
    48  			},
    49  		},
    50  		{
    51  			string: "Debian: ",
    52  			parsed: osvecosystem.Parsed{
    53  				Ecosystem: osvconstants.EcosystemDebian,
    54  				Suffix:    " ",
    55  			},
    56  		},
    57  		{
    58  			string: "Debian::",
    59  			parsed: osvecosystem.Parsed{
    60  				Ecosystem: osvconstants.EcosystemDebian,
    61  				Suffix:    ":",
    62  			},
    63  		},
    64  		{
    65  			string: "Alpine",
    66  			parsed: osvecosystem.Parsed{
    67  				Ecosystem: osvconstants.EcosystemAlpine,
    68  				Suffix:    "",
    69  			},
    70  		},
    71  		{
    72  			string: "Alpine:v",
    73  			parsed: osvecosystem.Parsed{
    74  				Ecosystem: osvconstants.EcosystemAlpine,
    75  				Suffix:    "v",
    76  			},
    77  		},
    78  		{
    79  			string: "Alpine:v3.16",
    80  			parsed: osvecosystem.Parsed{
    81  				Ecosystem: osvconstants.EcosystemAlpine,
    82  				Suffix:    "v3.16",
    83  			},
    84  		},
    85  		{
    86  			string: "Alpine:3.16",
    87  			parsed: osvecosystem.Parsed{
    88  				Ecosystem: osvconstants.EcosystemAlpine,
    89  				Suffix:    "3.16",
    90  			},
    91  		},
    92  		{
    93  			string: "Maven",
    94  			parsed: osvecosystem.Parsed{
    95  				Ecosystem: osvconstants.EcosystemMaven,
    96  				Suffix:    "",
    97  			},
    98  		},
    99  		{
   100  			string: "Maven:https://maven.google.com",
   101  			parsed: osvecosystem.Parsed{
   102  				Ecosystem: osvconstants.EcosystemMaven,
   103  				Suffix:    "https://maven.google.com",
   104  			},
   105  		},
   106  		{
   107  			string: "Photon OS",
   108  			parsed: osvecosystem.Parsed{
   109  				Ecosystem: osvconstants.EcosystemPhotonOS,
   110  				Suffix:    "",
   111  			},
   112  		},
   113  		{
   114  			string: "Photon OS:abc",
   115  			parsed: osvecosystem.Parsed{
   116  				Ecosystem: osvconstants.EcosystemPhotonOS,
   117  				Suffix:    "abc",
   118  			},
   119  		},
   120  		{
   121  			string: "Photon OS:3.0",
   122  			parsed: osvecosystem.Parsed{
   123  				Ecosystem: osvconstants.EcosystemPhotonOS,
   124  				Suffix:    "3.0",
   125  			},
   126  		},
   127  		{
   128  			string: "Red Hat",
   129  			parsed: osvecosystem.Parsed{
   130  				Ecosystem: osvconstants.EcosystemRedHat,
   131  				Suffix:    "",
   132  			},
   133  		},
   134  		{
   135  			string: "Red Hat:abc",
   136  			parsed: osvecosystem.Parsed{
   137  				Ecosystem: osvconstants.EcosystemRedHat,
   138  				Suffix:    "abc",
   139  			},
   140  		},
   141  		{
   142  			string: "Red Hat:rhel_aus:8.4::appstream",
   143  			parsed: osvecosystem.Parsed{
   144  				Ecosystem: osvconstants.EcosystemRedHat,
   145  				Suffix:    "rhel_aus:8.4::appstream",
   146  			},
   147  		},
   148  		{
   149  			string: "Ubuntu",
   150  			parsed: osvecosystem.Parsed{
   151  				Ecosystem: osvconstants.EcosystemUbuntu,
   152  				Suffix:    "",
   153  			},
   154  		},
   155  		{
   156  			string: "Ubuntu:Pro",
   157  			parsed: osvecosystem.Parsed{
   158  				Ecosystem: osvconstants.EcosystemUbuntu,
   159  				Suffix:    "Pro",
   160  			},
   161  		},
   162  		{
   163  			string: "Ubuntu:Pro:18.04:LTS",
   164  			parsed: osvecosystem.Parsed{
   165  				Ecosystem: osvconstants.EcosystemUbuntu,
   166  				Suffix:    "Pro:18.04:LTS",
   167  			},
   168  		},
   169  	}
   170  }
   171  
   172  func TestParsed_UnmarshalJSON(t *testing.T) {
   173  	tests := buildCases(t)
   174  	for _, tt := range tests {
   175  		t.Run(tt.string, func(t *testing.T) {
   176  			var got osvecosystem.Parsed
   177  
   178  			if err := json.Unmarshal([]byte(`"`+tt.string+`"`), &got); err != nil {
   179  				t.Fatalf("Unmarshal() = %v; want no error", err)
   180  			}
   181  
   182  			// ensure that the string is unmarshalled into a struct
   183  			if !reflect.DeepEqual(got, tt.parsed) {
   184  				t.Errorf("Unmarshal() = %v; want %v", got, tt.parsed)
   185  			}
   186  		})
   187  	}
   188  }
   189  
   190  func TestParsed_UnmarshalJSON_Errors(t *testing.T) {
   191  	tests := []struct {
   192  		input string
   193  		err   string
   194  	}{
   195  		{"1", "json: cannot unmarshal number into Go value of type string"},
   196  		{"{}", "json: cannot unmarshal object into Go value of type string"},
   197  		{"{\"ecosystem\": \"npm\"}", "json: cannot unmarshal object into Go value of type string"},
   198  		{"{\"ecosystem\": \"npm\", \"suffix\": \"\"}", "json: cannot unmarshal object into Go value of type string"},
   199  		{"{\"Ecosystem\": \"npm\", \"Suffix\": \"\"}", "json: cannot unmarshal object into Go value of type string"},
   200  		{"[]", "json: cannot unmarshal array into Go value of type string"},
   201  	}
   202  	for _, tt := range tests {
   203  		t.Run(tt.input, func(t *testing.T) {
   204  			var got osvecosystem.Parsed
   205  			err := json.Unmarshal([]byte(tt.input), &got)
   206  
   207  			if err == nil {
   208  				t.Fatalf("Unmarshal() = %v; want an error", err)
   209  			}
   210  
   211  			if err.Error() != tt.err {
   212  				t.Fatalf("Unmarshal() = %v; want %v", err.Error(), tt.err)
   213  			}
   214  
   215  			if got != (osvecosystem.Parsed{}) {
   216  				t.Fatalf("Unmarshal() = %v; want %v", got, osvecosystem.Parsed{})
   217  			}
   218  		})
   219  	}
   220  }
   221  
   222  func TestParsed_MarshalJSON(t *testing.T) {
   223  	tests := buildCases(t)
   224  	for _, tt := range tests {
   225  		t.Run(tt.string, func(t *testing.T) {
   226  			got, err := json.Marshal(tt.parsed)
   227  
   228  			if err != nil {
   229  				t.Fatalf("Marshal() = %v; want no error", err)
   230  			}
   231  
   232  			// ensure that the struct is marshaled as a string
   233  			want := `"` + tt.string + `"`
   234  			if string(got) != want {
   235  				t.Errorf("Marshal() = %v; want %v", string(got), want)
   236  			}
   237  		})
   238  	}
   239  }
   240  
   241  func TestParsed_String(t *testing.T) {
   242  	tests := buildCases(t)
   243  	for _, tt := range tests {
   244  		t.Run(tt.string, func(t *testing.T) {
   245  			if got := tt.parsed.String(); got != tt.string {
   246  				t.Errorf("String() = %v, want %v", got, tt.string)
   247  			}
   248  		})
   249  	}
   250  }
   251  
   252  func TestParse(t *testing.T) {
   253  	tests := buildCases(t)
   254  	for _, tt := range tests {
   255  		t.Run(tt.string, func(t *testing.T) {
   256  			if got := osvecosystem.MustParse(tt.string); !reflect.DeepEqual(got, tt.parsed) {
   257  				t.Errorf("Parse() = %v, want %v", got, tt.parsed)
   258  			}
   259  		})
   260  	}
   261  }