github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/format/syftjson/to_format_model_test.go (about)

     1  package syftjson
     2  
     3  import (
     4  	"encoding/json"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/google/go-cmp/cmp/cmpopts"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
    13  	"github.com/anchore/syft/syft/file"
    14  	"github.com/anchore/syft/syft/format/syftjson/model"
    15  	"github.com/anchore/syft/syft/internal/sourcemetadata"
    16  	"github.com/anchore/syft/syft/pkg"
    17  	"github.com/anchore/syft/syft/source"
    18  )
    19  
    20  func Test_toSourceModel_IgnoreBase(t *testing.T) {
    21  	tests := []struct {
    22  		name string
    23  		src  source.Description
    24  	}{
    25  		{
    26  			name: "directory",
    27  			src: source.Description{
    28  				ID: "test-id",
    29  				Metadata: source.DirectoryMetadata{
    30  					Path: "some/path",
    31  					Base: "some/base",
    32  				},
    33  			},
    34  		},
    35  	}
    36  	for _, test := range tests {
    37  		t.Run(test.name, func(t *testing.T) {
    38  			// assert the model transformation is correct
    39  			actual := toSourceModel(test.src)
    40  
    41  			by, err := json.Marshal(actual)
    42  			require.NoError(t, err)
    43  			assert.NotContains(t, string(by), "some/base")
    44  		})
    45  	}
    46  }
    47  
    48  func Test_toSourceModel(t *testing.T) {
    49  	tracker := sourcemetadata.NewCompletionTester(t)
    50  
    51  	tests := []struct {
    52  		name     string
    53  		src      source.Description
    54  		expected model.Source
    55  	}{
    56  		{
    57  			name: "directory",
    58  			src: source.Description{
    59  				ID:      "test-id",
    60  				Name:    "some-name",
    61  				Version: "some-version",
    62  				Metadata: source.DirectoryMetadata{
    63  					Path: "some/path",
    64  					Base: "some/base",
    65  				},
    66  			},
    67  			expected: model.Source{
    68  				ID:      "test-id",
    69  				Name:    "some-name",
    70  				Version: "some-version",
    71  				Type:    "directory",
    72  				Metadata: source.DirectoryMetadata{
    73  					Path: "some/path",
    74  					Base: "some/base",
    75  				},
    76  			},
    77  		},
    78  		{
    79  			name: "file",
    80  			src: source.Description{
    81  				ID:      "test-id",
    82  				Name:    "some-name",
    83  				Version: "some-version",
    84  				Metadata: source.FileMetadata{
    85  					Path:     "some/path",
    86  					Digests:  []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
    87  					MIMEType: "text/plain",
    88  				},
    89  			},
    90  			expected: model.Source{
    91  				ID:      "test-id",
    92  				Name:    "some-name",
    93  				Version: "some-version",
    94  				Type:    "file",
    95  				Metadata: source.FileMetadata{
    96  					Path:     "some/path",
    97  					Digests:  []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
    98  					MIMEType: "text/plain",
    99  				},
   100  			},
   101  		},
   102  		{
   103  			name: "image",
   104  			src: source.Description{
   105  				ID:      "test-id",
   106  				Name:    "some-name",
   107  				Version: "some-version",
   108  				Metadata: source.ImageMetadata{
   109  					UserInput:      "user-input",
   110  					ID:             "id...",
   111  					ManifestDigest: "digest...",
   112  					MediaType:      "type...",
   113  				},
   114  			},
   115  			expected: model.Source{
   116  				ID:      "test-id",
   117  				Name:    "some-name",
   118  				Version: "some-version",
   119  				Type:    "image",
   120  				Metadata: source.ImageMetadata{
   121  					UserInput:      "user-input",
   122  					ID:             "id...",
   123  					ManifestDigest: "digest...",
   124  					MediaType:      "type...",
   125  					RepoDigests:    []string{},
   126  					Tags:           []string{},
   127  				},
   128  			},
   129  		},
   130  		// below are regression tests for when the name/version are not provided
   131  		// historically we've hoisted up the name/version from the metadata, now it is a simple pass-through
   132  		{
   133  			name: "directory - no name/version",
   134  			src: source.Description{
   135  				ID: "test-id",
   136  				Metadata: source.DirectoryMetadata{
   137  					Path: "some/path",
   138  					Base: "some/base",
   139  				},
   140  			},
   141  			expected: model.Source{
   142  				ID:   "test-id",
   143  				Type: "directory",
   144  				Metadata: source.DirectoryMetadata{
   145  					Path: "some/path",
   146  					Base: "some/base",
   147  				},
   148  			},
   149  		},
   150  		{
   151  			name: "file - no name/version",
   152  			src: source.Description{
   153  				ID: "test-id",
   154  				Metadata: source.FileMetadata{
   155  					Path:     "some/path",
   156  					Digests:  []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
   157  					MIMEType: "text/plain",
   158  				},
   159  			},
   160  			expected: model.Source{
   161  				ID:   "test-id",
   162  				Type: "file",
   163  				Metadata: source.FileMetadata{
   164  					Path:     "some/path",
   165  					Digests:  []file.Digest{{Algorithm: "sha256", Value: "some-digest"}},
   166  					MIMEType: "text/plain",
   167  				},
   168  			},
   169  		},
   170  		{
   171  			name: "image - no name/version",
   172  			src: source.Description{
   173  				ID: "test-id",
   174  				Metadata: source.ImageMetadata{
   175  					UserInput:      "user-input",
   176  					ID:             "id...",
   177  					ManifestDigest: "digest...",
   178  					MediaType:      "type...",
   179  				},
   180  			},
   181  			expected: model.Source{
   182  				ID:   "test-id",
   183  				Type: "image",
   184  				Metadata: source.ImageMetadata{
   185  					UserInput:      "user-input",
   186  					ID:             "id...",
   187  					ManifestDigest: "digest...",
   188  					MediaType:      "type...",
   189  					RepoDigests:    []string{},
   190  					Tags:           []string{},
   191  				},
   192  			},
   193  		},
   194  	}
   195  	for _, test := range tests {
   196  		t.Run(test.name, func(t *testing.T) {
   197  			// assert the model transformation is correct
   198  			actual := toSourceModel(test.src)
   199  			assert.Equal(t, test.expected, actual)
   200  
   201  			// track each scheme tested (passed or not)
   202  			tracker.Tested(t, test.expected.Metadata)
   203  		})
   204  	}
   205  }
   206  
   207  func Test_toFileType(t *testing.T) {
   208  
   209  	badType := stereoscopeFile.Type(0x1337)
   210  	var allTypesTested []stereoscopeFile.Type
   211  	tests := []struct {
   212  		ty   stereoscopeFile.Type
   213  		name string
   214  	}{
   215  		{
   216  			ty:   stereoscopeFile.TypeRegular,
   217  			name: "RegularFile",
   218  		},
   219  		{
   220  			ty:   stereoscopeFile.TypeDirectory,
   221  			name: "Directory",
   222  		},
   223  		{
   224  			ty:   stereoscopeFile.TypeSymLink,
   225  			name: "SymbolicLink",
   226  		},
   227  		{
   228  			ty:   stereoscopeFile.TypeHardLink,
   229  			name: "HardLink",
   230  		},
   231  		{
   232  			ty:   stereoscopeFile.TypeSocket,
   233  			name: "Socket",
   234  		},
   235  		{
   236  			ty:   stereoscopeFile.TypeCharacterDevice,
   237  			name: "CharacterDevice",
   238  		},
   239  		{
   240  			ty:   stereoscopeFile.TypeBlockDevice,
   241  			name: "BlockDevice",
   242  		},
   243  		{
   244  			ty:   stereoscopeFile.TypeFIFO,
   245  			name: "FIFONode",
   246  		},
   247  		{
   248  			ty:   stereoscopeFile.TypeIrregular,
   249  			name: "IrregularFile",
   250  		},
   251  		{
   252  			ty:   badType,
   253  			name: "Unknown",
   254  		},
   255  	}
   256  	for _, tt := range tests {
   257  		t.Run(tt.name, func(t *testing.T) {
   258  			assert.Equalf(t, tt.name, toFileType(tt.ty), "toFileType(%v)", tt.ty)
   259  			if tt.ty != badType {
   260  				allTypesTested = append(allTypesTested, tt.ty)
   261  			}
   262  		})
   263  	}
   264  
   265  	assert.ElementsMatch(t, allTypesTested, stereoscopeFile.AllTypes(), "not all file.Types are under test")
   266  }
   267  
   268  func Test_toFileMetadataEntry(t *testing.T) {
   269  	coords := file.Coordinates{
   270  		RealPath:     "/path",
   271  		FileSystemID: "x",
   272  	}
   273  	tests := []struct {
   274  		name     string
   275  		metadata *file.Metadata
   276  		want     *model.FileMetadataEntry
   277  	}{
   278  		{
   279  			name: "no metadata",
   280  		},
   281  		{
   282  			name: "no file info",
   283  			metadata: &file.Metadata{
   284  				FileInfo: nil,
   285  			},
   286  			want: &model.FileMetadataEntry{
   287  				Type: stereoscopeFile.TypeRegular.String(),
   288  			},
   289  		},
   290  		{
   291  			name: "with file info",
   292  			metadata: &file.Metadata{
   293  				FileInfo: &stereoscopeFile.ManualInfo{
   294  					ModeValue: 1,
   295  				},
   296  			},
   297  			want: &model.FileMetadataEntry{
   298  				Mode: 1,
   299  				Type: stereoscopeFile.TypeRegular.String(),
   300  			},
   301  		},
   302  	}
   303  	for _, tt := range tests {
   304  		t.Run(tt.name, func(t *testing.T) {
   305  			assert.Equal(t, tt.want, toFileMetadataEntry(coords, tt.metadata))
   306  		})
   307  	}
   308  }
   309  
   310  func Test_toPackageModel_metadataType(t *testing.T) {
   311  	tests := []struct {
   312  		name string
   313  		p    pkg.Package
   314  		cfg  EncoderConfig
   315  		want model.Package
   316  	}{
   317  		{
   318  			name: "empty config",
   319  			p: pkg.Package{
   320  				Metadata: pkg.RpmDBEntry{},
   321  			},
   322  			cfg: EncoderConfig{},
   323  			want: model.Package{
   324  				PackageCustomData: model.PackageCustomData{
   325  					MetadataType: "rpm-db-entry",
   326  					Metadata:     pkg.RpmDBEntry{},
   327  				},
   328  			},
   329  		},
   330  		{
   331  			name: "legacy config",
   332  			p: pkg.Package{
   333  				Metadata: pkg.RpmDBEntry{},
   334  			},
   335  			cfg: EncoderConfig{
   336  				Legacy: true,
   337  			},
   338  			want: model.Package{
   339  				PackageCustomData: model.PackageCustomData{
   340  					MetadataType: "RpmMetadata",
   341  					Metadata:     pkg.RpmDBEntry{},
   342  				},
   343  			},
   344  		},
   345  	}
   346  	for _, tt := range tests {
   347  		t.Run(tt.name, func(t *testing.T) {
   348  			if d := cmp.Diff(tt.want, toPackageModel(tt.p, tt.cfg), cmpopts.EquateEmpty()); d != "" {
   349  				t.Errorf("unexpected package (-want +got):\n%s", d)
   350  			}
   351  		})
   352  	}
   353  }