github.com/anchore/syft@v1.38.2/syft/format/syftjson/model/file_test.go (about)

     1  package model
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/go-cmp/cmp"
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func Test_FileMetadataEntry_UnmarshalJSON(t *testing.T) {
    12  	tests := []struct {
    13  		name     string
    14  		jsonData []byte
    15  		expected FileMetadataEntry
    16  	}{
    17  		{
    18  			name: "unmarshal current format",
    19  			jsonData: []byte(`{
    20               "mode": 644,
    21               "type": "RegularFile",
    22               "linkDestination": "/usr/bin/python3",
    23               "userID": 1000,
    24               "groupID": 1000,
    25               "mimeType": "text/plain",
    26               "size": 10174
    27            }`),
    28  			expected: FileMetadataEntry{
    29  				Mode:            644,
    30  				Type:            "RegularFile",
    31  				LinkDestination: "/usr/bin/python3",
    32  				UserID:          1000,
    33  				GroupID:         1000,
    34  				MIMEType:        "text/plain",
    35  				Size:            10174,
    36  			},
    37  		},
    38  		{
    39  			name: "unmarshal legacy image add internal document format",
    40  			jsonData: []byte(`{
    41               "FileInfo": {},
    42               "Mode": 644,
    43               "Type": "RegularFile",
    44               "LinkDestination": "/usr/bin/python3",
    45               "UserID": 1000,
    46               "GroupID": 1000,
    47               "MIMEType": "text/plain",
    48               "Size": 10174
    49            }`),
    50  			expected: FileMetadataEntry{
    51  				Mode:            420, // important! we convert this to base 10 so that all documents are consistent
    52  				Type:            "RegularFile",
    53  				LinkDestination: "/usr/bin/python3",
    54  				UserID:          1000,
    55  				GroupID:         1000,
    56  				MIMEType:        "text/plain",
    57  				Size:            10174,
    58  			},
    59  		},
    60  		{
    61  			name: "unmarshal legacy sbom import format",
    62  			jsonData: []byte(`{
    63               "FileInfo": {},
    64               "Mode": 644,
    65               "Type": 0,
    66               "LinkDestination": "/usr/bin/python3",
    67               "UserID": 1000,
    68               "GroupID": 1000,
    69               "MIMEType": "text/plain",
    70               "Size": 10174
    71            }`),
    72  			expected: FileMetadataEntry{
    73  				Mode:            644,
    74  				Type:            "RegularFile",
    75  				LinkDestination: "/usr/bin/python3",
    76  				UserID:          1000,
    77  				GroupID:         1000,
    78  				MIMEType:        "text/plain",
    79  				Size:            10174,
    80  			},
    81  		},
    82  		{
    83  			name: "unmarshal minimal current format",
    84  			jsonData: []byte(`{
    85               "mode": 0,
    86               "type": "RegularFile",
    87               "userID": 0,
    88               "groupID": 0,
    89               "size": 0
    90            }`),
    91  			expected: FileMetadataEntry{
    92  				Type: "RegularFile",
    93  			},
    94  		},
    95  		{
    96  			name: "unmarshal minimal legacy format",
    97  			jsonData: []byte(`{
    98               "FileInfo": {},
    99               "Mode": 0,
   100               "Type": "RegularFile",
   101               "UserID": 0,
   102               "GroupID": 0,
   103               "Size": 0
   104            }`),
   105  			expected: FileMetadataEntry{
   106  				Type: "RegularFile",
   107  			},
   108  		},
   109  	}
   110  
   111  	for _, test := range tests {
   112  		t.Run(test.name, func(t *testing.T) {
   113  			var actual FileMetadataEntry
   114  			err := actual.UnmarshalJSON(test.jsonData)
   115  			require.NoError(t, err)
   116  
   117  			if diff := cmp.Diff(test.expected, actual); diff != "" {
   118  				t.Errorf("FileMetadataEntry mismatch (-expected +actual):\n%s", diff)
   119  			}
   120  		})
   121  	}
   122  }
   123  
   124  func Test_intOrStringFileType_UnmarshalJSON(t *testing.T) {
   125  	tests := []struct {
   126  		name           string
   127  		jsonData       []byte
   128  		expected       string
   129  		expectedWasInt bool
   130  		wantErr        require.ErrorAssertionFunc
   131  	}{
   132  		// string inputs - should pass through unchanged
   133  		{
   134  			name:     "string RegularFile",
   135  			jsonData: []byte(`"RegularFile"`),
   136  			expected: "RegularFile",
   137  		},
   138  		{
   139  			name:     "string HardLink",
   140  			jsonData: []byte(`"HardLink"`),
   141  			expected: "HardLink",
   142  		},
   143  		{
   144  			name:     "string Directory",
   145  			jsonData: []byte(`"Directory"`),
   146  			expected: "Directory",
   147  		},
   148  		{
   149  			name:     "string custom value",
   150  			jsonData: []byte(`"CustomFileType"`),
   151  			expected: "CustomFileType",
   152  		},
   153  		// integer inputs - should convert to string representation
   154  		{
   155  			name:           "int 0 (TypeRegular)",
   156  			jsonData:       []byte(`0`),
   157  			expected:       "RegularFile",
   158  			expectedWasInt: true,
   159  		},
   160  		{
   161  			name:           "int 1 (TypeHardLink)",
   162  			jsonData:       []byte(`1`),
   163  			expected:       "HardLink",
   164  			expectedWasInt: true,
   165  		},
   166  		{
   167  			name:           "int 2 (TypeSymLink)",
   168  			jsonData:       []byte(`2`),
   169  			expected:       "SymbolicLink",
   170  			expectedWasInt: true,
   171  		},
   172  		{
   173  			name:           "int 3 (TypeCharacterDevice)",
   174  			jsonData:       []byte(`3`),
   175  			expected:       "CharacterDevice",
   176  			expectedWasInt: true,
   177  		},
   178  		{
   179  			name:           "int 4 (TypeBlockDevice)",
   180  			jsonData:       []byte(`4`),
   181  			expected:       "BlockDevice",
   182  			expectedWasInt: true,
   183  		},
   184  		{
   185  			name:           "int 5 (TypeDirectory)",
   186  			jsonData:       []byte(`5`),
   187  			expected:       "Directory",
   188  			expectedWasInt: true,
   189  		},
   190  		{
   191  			name:           "int 6 (TypeFIFO)",
   192  			jsonData:       []byte(`6`),
   193  			expected:       "FIFONode",
   194  			expectedWasInt: true,
   195  		},
   196  		{
   197  			name:           "int 7 (TypeSocket)",
   198  			jsonData:       []byte(`7`),
   199  			expected:       "Socket",
   200  			expectedWasInt: true,
   201  		},
   202  		{
   203  			name:           "int 8 (TypeIrregular)",
   204  			jsonData:       []byte(`8`),
   205  			expected:       "IrregularFile",
   206  			expectedWasInt: true,
   207  		},
   208  		{
   209  			name:           "unknown int",
   210  			jsonData:       []byte(`99`),
   211  			expected:       "Unknown",
   212  			expectedWasInt: true,
   213  		},
   214  		{
   215  			name:           "negative int",
   216  			jsonData:       []byte(`-1`),
   217  			expected:       "Unknown",
   218  			expectedWasInt: true,
   219  		},
   220  		{
   221  			name:     "null value",
   222  			jsonData: []byte(`null`),
   223  		},
   224  		{
   225  			name:     "invalid JSON",
   226  			jsonData: []byte(`{`),
   227  			wantErr:  require.Error,
   228  		},
   229  		{
   230  			name:     "boolean value",
   231  			jsonData: []byte(`true`),
   232  			wantErr:  require.Error,
   233  		},
   234  		{
   235  			name:     "array value",
   236  			jsonData: []byte(`[]`),
   237  			wantErr:  require.Error,
   238  		},
   239  		{
   240  			name:     "object value",
   241  			jsonData: []byte(`{}`),
   242  			wantErr:  require.Error,
   243  		},
   244  		{
   245  			name:     "float value",
   246  			jsonData: []byte(`1.5`),
   247  			wantErr:  require.Error,
   248  		},
   249  	}
   250  
   251  	for _, test := range tests {
   252  		t.Run(test.name, func(t *testing.T) {
   253  			if test.wantErr == nil {
   254  				test.wantErr = require.NoError
   255  			}
   256  			var ft intOrStringFileType
   257  			err := ft.UnmarshalJSON(test.jsonData)
   258  			test.wantErr(t, err)
   259  			if err != nil {
   260  				return
   261  			}
   262  			assert.Equal(t, test.expected, ft.Value)
   263  			assert.Equal(t, test.expectedWasInt, ft.WasInt)
   264  		})
   265  	}
   266  }
   267  
   268  func Test_convertBase10ToBase8(t *testing.T) {
   269  	tests := []struct {
   270  		name     string
   271  		input    int
   272  		expected int
   273  	}{
   274  		{
   275  			name:     "no permissions",
   276  			input:    0,
   277  			expected: 0,
   278  		},
   279  		{
   280  			name:     "symlink + rwxrwxrwx",
   281  			input:    134218239,
   282  			expected: 1000000777,
   283  		},
   284  	}
   285  
   286  	for _, tt := range tests {
   287  		t.Run(tt.name, func(t *testing.T) {
   288  			actual := convertBase10ToBase8(tt.input)
   289  
   290  			require.Equal(t, tt.expected, actual)
   291  		})
   292  	}
   293  }
   294  
   295  func Test_convertBase8ToBase10(t *testing.T) {
   296  	tests := []struct {
   297  		name     string
   298  		input    int
   299  		expected int
   300  	}{
   301  		{
   302  			name:     "no permissions",
   303  			input:    0,
   304  			expected: 0,
   305  		},
   306  		{
   307  			name:     "symlink + rwxrwxrwx",
   308  			input:    1000000777,
   309  			expected: 134218239,
   310  		},
   311  	}
   312  
   313  	for _, tt := range tests {
   314  		t.Run(tt.name, func(t *testing.T) {
   315  			actual := convertBase8ToBase10(tt.input)
   316  
   317  			require.Equal(t, tt.expected, actual)
   318  		})
   319  	}
   320  }