github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/os/rpm/metadata/metadata_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 metadata_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/google/go-cmp/cmp"
    21  	"github.com/google/osv-scalibr/extractor/filesystem/os/rpm/metadata"
    22  	"google.golang.org/protobuf/proto"
    23  	"google.golang.org/protobuf/testing/protocmp"
    24  
    25  	pb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto"
    26  )
    27  
    28  func TestSetProto(t *testing.T) {
    29  	testCases := []struct {
    30  		desc string
    31  		m    *metadata.Metadata
    32  		p    *pb.Package
    33  		want *pb.Package
    34  	}{
    35  		{
    36  			desc: "nil_metadata",
    37  			m:    nil,
    38  			p:    &pb.Package{Name: "some-package"},
    39  			want: &pb.Package{Name: "some-package"},
    40  		},
    41  		{
    42  			desc: "nil_package",
    43  			m: &metadata.Metadata{
    44  				PackageName: "name",
    45  			},
    46  			p:    nil,
    47  			want: nil,
    48  		},
    49  		{
    50  			desc: "set_metadata",
    51  			m: &metadata.Metadata{
    52  				PackageName: "name",
    53  			},
    54  			p: &pb.Package{Name: "some-package"},
    55  			want: &pb.Package{
    56  				Name: "some-package",
    57  				Metadata: &pb.Package_RpmMetadata{
    58  					RpmMetadata: &pb.RPMPackageMetadata{
    59  						PackageName: "name",
    60  					},
    61  				},
    62  			},
    63  		},
    64  		{
    65  			desc: "override_metadata",
    66  			m: &metadata.Metadata{
    67  				PackageName: "another-name",
    68  			},
    69  			p: &pb.Package{
    70  				Name: "some-package",
    71  				Metadata: &pb.Package_RpmMetadata{
    72  					RpmMetadata: &pb.RPMPackageMetadata{
    73  						PackageName: "name",
    74  					},
    75  				},
    76  			},
    77  			want: &pb.Package{
    78  				Name: "some-package",
    79  				Metadata: &pb.Package_RpmMetadata{
    80  					RpmMetadata: &pb.RPMPackageMetadata{
    81  						PackageName: "another-name",
    82  					},
    83  				},
    84  			},
    85  		},
    86  		{
    87  			desc: "set_all_fields",
    88  			m: &metadata.Metadata{
    89  				PackageName:  "name",
    90  				SourceRPM:    "source-rpm",
    91  				Epoch:        1,
    92  				OSName:       "os-name",
    93  				OSPrettyName: "os-pretty-name",
    94  				OSID:         "os-id",
    95  				OSVersionID:  "os-version-id",
    96  				OSBuildID:    "os-build-id",
    97  				Vendor:       "vendor",
    98  				Architecture: "architecture",
    99  				OSCPEName:    "os-cpe-name",
   100  			},
   101  			p: &pb.Package{Name: "some-package"},
   102  			want: &pb.Package{
   103  				Name: "some-package",
   104  				Metadata: &pb.Package_RpmMetadata{
   105  					RpmMetadata: &pb.RPMPackageMetadata{
   106  						PackageName:  "name",
   107  						SourceRpm:    "source-rpm",
   108  						Epoch:        1,
   109  						OsName:       "os-name",
   110  						OsPrettyName: "os-pretty-name",
   111  						OsId:         "os-id",
   112  						OsVersionId:  "os-version-id",
   113  						OsBuildId:    "os-build-id",
   114  						Vendor:       "vendor",
   115  						Architecture: "architecture",
   116  						OsCpeName:    "os-cpe-name",
   117  					},
   118  				},
   119  			},
   120  		},
   121  	}
   122  
   123  	for _, tc := range testCases {
   124  		t.Run(tc.desc, func(t *testing.T) {
   125  			p := proto.Clone(tc.p).(*pb.Package)
   126  			tc.m.SetProto(p)
   127  			opts := []cmp.Option{
   128  				protocmp.Transform(),
   129  			}
   130  			if diff := cmp.Diff(tc.want, p, opts...); diff != "" {
   131  				t.Errorf("Metatadata{%+v}.SetProto(%+v): (-want +got):\n%s", tc.m, tc.p, diff)
   132  			}
   133  
   134  			// Test the reverse conversion for completeness.
   135  
   136  			if tc.p == nil && tc.want == nil {
   137  				return
   138  			}
   139  
   140  			got := metadata.ToStruct(p.GetRpmMetadata())
   141  			if diff := cmp.Diff(tc.m, got); diff != "" {
   142  				t.Errorf("ToStruct(%+v): (-want +got):\n%s", p.GetRpmMetadata(), diff)
   143  			}
   144  		})
   145  	}
   146  }
   147  
   148  func TestToStruct(t *testing.T) {
   149  	testCases := []struct {
   150  		desc string
   151  		m    *pb.RPMPackageMetadata
   152  		want *metadata.Metadata
   153  	}{
   154  		{
   155  			desc: "nil",
   156  			m:    nil,
   157  			want: nil,
   158  		},
   159  		{
   160  			desc: "some_fields",
   161  			m: &pb.RPMPackageMetadata{
   162  				PackageName: "name",
   163  			},
   164  			want: &metadata.Metadata{
   165  				PackageName: "name",
   166  			},
   167  		},
   168  		{
   169  			desc: "all_fields",
   170  			m: &pb.RPMPackageMetadata{
   171  				PackageName:  "name",
   172  				SourceRpm:    "source-rpm",
   173  				Epoch:        1,
   174  				OsName:       "os-name",
   175  				OsPrettyName: "os-pretty-name",
   176  				OsId:         "os-id",
   177  				OsVersionId:  "os-version-id",
   178  				OsBuildId:    "os-build-id",
   179  				Vendor:       "vendor",
   180  				Architecture: "architecture",
   181  				OsCpeName:    "os-cpe-name",
   182  			},
   183  			want: &metadata.Metadata{
   184  				PackageName:  "name",
   185  				SourceRPM:    "source-rpm",
   186  				Epoch:        1,
   187  				OSName:       "os-name",
   188  				OSPrettyName: "os-pretty-name",
   189  				OSID:         "os-id",
   190  				OSVersionID:  "os-version-id",
   191  				OSBuildID:    "os-build-id",
   192  				Vendor:       "vendor",
   193  				Architecture: "architecture",
   194  				OSCPEName:    "os-cpe-name",
   195  			},
   196  		},
   197  	}
   198  
   199  	for _, tc := range testCases {
   200  		t.Run(tc.desc, func(t *testing.T) {
   201  			got := metadata.ToStruct(tc.m)
   202  			if diff := cmp.Diff(tc.want, got); diff != "" {
   203  				t.Errorf("ToStruct(%+v): (-want +got):\n%s", tc.m, diff)
   204  			}
   205  
   206  			if tc.m == nil {
   207  				return
   208  			}
   209  
   210  			// Test the reverse conversion for completeness.
   211  
   212  			gotP := &pb.Package{}
   213  			wantP := &pb.Package{
   214  				Metadata: &pb.Package_RpmMetadata{
   215  					RpmMetadata: tc.m,
   216  				},
   217  			}
   218  			got.SetProto(gotP)
   219  			opts := []cmp.Option{
   220  				protocmp.Transform(),
   221  			}
   222  			if diff := cmp.Diff(wantP, gotP, opts...); diff != "" {
   223  				t.Errorf("Metatadata{%+v}.SetProto(%+v): (-want +got):\n%s", got, wantP, diff)
   224  			}
   225  		})
   226  	}
   227  }
   228  
   229  func TestOpenEulerEcosystemSuffix(t *testing.T) {
   230  	testCases := []struct {
   231  		desc string
   232  		meta *metadata.Metadata
   233  		want string
   234  	}{
   235  		{
   236  			desc: "base_version_from_pretty_name",
   237  			meta: &metadata.Metadata{
   238  				OSPrettyName: "openEuler 24.03",
   239  			},
   240  			want: "24.03",
   241  		},
   242  		{
   243  			desc: "lts_qualifier",
   244  			meta: &metadata.Metadata{
   245  				OSPrettyName: "openEuler 24.03 (LTS)",
   246  			},
   247  			want: "24.03-LTS",
   248  		},
   249  		{
   250  			desc: "lts_space_qualifier",
   251  			meta: &metadata.Metadata{
   252  				OSPrettyName: "openEuler 24.03 (LTS SP1)",
   253  			},
   254  			want: "24.03-LTS-SP1",
   255  		},
   256  		{
   257  			desc: "lts_hyphen_qualifier",
   258  			meta: &metadata.Metadata{
   259  				OSPrettyName: "openEuler 24.03 (LTS-SP1)",
   260  			},
   261  			want: "24.03-LTS-SP1",
   262  		},
   263  		{
   264  			desc: "fallback_to_version_id",
   265  			meta: &metadata.Metadata{
   266  				OSVersionID: "24.03",
   267  			},
   268  			want: "24.03",
   269  		},
   270  		{
   271  			desc: "non_openEuler_pretty_name",
   272  			meta: &metadata.Metadata{
   273  				OSPrettyName: "Fedora Linux 38 (Container Image)",
   274  				OSVersionID:  "38",
   275  			},
   276  			want: "38",
   277  		},
   278  		{
   279  			desc: "no_details",
   280  			meta: &metadata.Metadata{},
   281  			want: "",
   282  		},
   283  	}
   284  
   285  	for _, tc := range testCases {
   286  		t.Run(tc.desc, func(t *testing.T) {
   287  			if got := tc.meta.OpenEulerEcosystemSuffix(); got != tc.want {
   288  				t.Fatalf("OpenEulerEcosystemSuffix() = %q, want %q", got, tc.want)
   289  			}
   290  		})
   291  	}
   292  }