github.com/datreeio/datree@v1.9.22-rc/pkg/fileReader/reader_test.go (about)

     1  package fileReader
     2  
     3  import (
     4  	"io/fs"
     5  	"os"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/mock"
    12  )
    13  
    14  type ioMock struct {
    15  	mock.Mock
    16  }
    17  
    18  func (c *ioMock) ReadFile(filename string) ([]byte, error) {
    19  	args := c.Called(filename)
    20  	return args.Get(0).([]byte), args.Error(1)
    21  }
    22  
    23  type readFileContentTestCase struct {
    24  	name string
    25  	args struct {
    26  		path string
    27  	}
    28  	mock struct {
    29  		readFilFn struct {
    30  			response []byte
    31  			err      error
    32  		}
    33  	}
    34  	expected struct {
    35  		calledWith string
    36  		isCalled   bool
    37  		response   string
    38  		err        error
    39  	}
    40  }
    41  
    42  func TestReadFileContent(t *testing.T) {
    43  	io := ioMock{}
    44  
    45  	tests := []readFileContentTestCase{
    46  		{
    47  			name: "success - should override with opts.methods and return response",
    48  			args: struct{ path string }{
    49  				path: "path/file.yaml",
    50  			},
    51  			mock: struct {
    52  				readFilFn struct {
    53  					response []byte
    54  					err      error
    55  				}
    56  			}{
    57  				readFilFn: struct {
    58  					response []byte
    59  					err      error
    60  				}{
    61  					response: []byte("content in file"),
    62  					err:      nil,
    63  				},
    64  			},
    65  			expected: struct {
    66  				calledWith string
    67  				isCalled   bool
    68  				response   string
    69  				err        error
    70  			}{
    71  				calledWith: "path/file.yaml",
    72  				isCalled:   true,
    73  				response:   "content in file",
    74  				err:        nil,
    75  			},
    76  		},
    77  	}
    78  
    79  	for _, tt := range tests {
    80  		t.Run(tt.name, func(t *testing.T) {
    81  			io.On("ReadFile", mock.Anything).Return(tt.mock.readFilFn.response, tt.mock.readFilFn.err)
    82  			fileReader := &FileReader{
    83  				glob:     nil,
    84  				readFile: io.ReadFile,
    85  			}
    86  
    87  			res, err := fileReader.ReadFileContent(tt.args.path)
    88  			io.AssertCalled(t, "ReadFile", tt.expected.calledWith)
    89  			assert.Equal(t, tt.expected.response, res)
    90  			assert.Equal(t, tt.expected.err, err)
    91  		})
    92  	}
    93  }
    94  
    95  type globMock struct {
    96  	mock.Mock
    97  }
    98  
    99  func (c *globMock) Glob(pattern string) (matches []string, err error) {
   100  	args := c.Called(pattern)
   101  	return args.Get(0).([]string), args.Error(1)
   102  }
   103  
   104  type statMock struct {
   105  	mock.Mock
   106  }
   107  
   108  func (c *statMock) Stat(name string) (os.FileInfo, error) {
   109  	args := c.Called(name)
   110  	return args.Get(0).(os.FileInfo), args.Error(1)
   111  }
   112  
   113  type absMock struct {
   114  	mock.Mock
   115  }
   116  
   117  func (c *absMock) Abs(path string) (string, error) {
   118  	args := c.Called(path)
   119  	return args.Get(0).(string), args.Error(1)
   120  }
   121  
   122  type filterFilesTestCase struct {
   123  	name string
   124  	args struct {
   125  		paths          []string
   126  		excludePattern string
   127  	}
   128  	mock struct {
   129  		stat struct {
   130  			response fs.FileInfo
   131  			err      error
   132  		}
   133  	}
   134  	expected struct {
   135  		filePaths []string
   136  	}
   137  }
   138  
   139  func TestFilterFiles(t *testing.T) {
   140  	stat := statMock{}
   141  	fileInfo := &MockFileInfo{}
   142  
   143  	tests := []filterFilesTestCase{
   144  		{
   145  			name: "success",
   146  			args: struct {
   147  				paths          []string
   148  				excludePattern string
   149  			}{
   150  				paths:          []string{"file1.yaml", "file2.yaml", "file3-exclude.yaml", "file4.yaml", "file5-exclude.yaml"},
   151  				excludePattern: "exclude.yaml",
   152  			},
   153  			mock: struct {
   154  				stat struct {
   155  					response fs.FileInfo
   156  					err      error
   157  				}
   158  			}{
   159  				stat: struct {
   160  					response fs.FileInfo
   161  					err      error
   162  				}{
   163  					response: fileInfo,
   164  					err:      nil,
   165  				},
   166  			},
   167  			expected: struct{ filePaths []string }{
   168  				filePaths: []string{"file1.yaml", "file2.yaml", "file4.yaml"},
   169  			},
   170  		},
   171  	}
   172  
   173  	for _, tt := range tests {
   174  		t.Run(tt.name, func(t *testing.T) {
   175  			stat.On("Stat", mock.Anything).Return(tt.mock.stat.response, tt.mock.stat.err)
   176  			fileInfo.On("IsDir", mock.Anything).Return(false)
   177  			fileReader := &FileReader{
   178  				glob: nil,
   179  				stat: stat.Stat,
   180  			}
   181  
   182  			filteredfiles, _ := fileReader.FilterFiles(tt.args.paths, tt.args.excludePattern)
   183  			stat.AssertCalled(t, "Stat", tt.expected.filePaths[0])
   184  			fileInfo.AssertCalled(t, "IsDir")
   185  			assert.Equal(t, tt.expected.filePaths, filteredfiles)
   186  		})
   187  	}
   188  }
   189  
   190  func TestCreateFileReader(t *testing.T) {
   191  	glob := globMock{}
   192  	io := ioMock{}
   193  	stat := statMock{}
   194  	abs := absMock{}
   195  
   196  	opt := &FileReaderOptions{
   197  		Glob:     glob.Glob,
   198  		ReadFile: io.ReadFile,
   199  		Stat:     stat.Stat,
   200  		Abs:      abs.Abs,
   201  	}
   202  
   203  	fileReader := CreateFileReader(opt)
   204  
   205  	expectedGlobFnValue := reflect.ValueOf(glob.Glob)
   206  	actualGlobFnValue := reflect.ValueOf(fileReader.glob)
   207  
   208  	assert.Equal(t, expectedGlobFnValue.Pointer(), actualGlobFnValue.Pointer())
   209  }
   210  
   211  type getFilesPathsTestCase struct {
   212  	name string
   213  	args struct {
   214  		paths []string
   215  	}
   216  	mock struct {
   217  		stat struct {
   218  			response os.FileInfo
   219  			err      error
   220  		}
   221  		abs struct {
   222  			response string
   223  			err      error
   224  		}
   225  	}
   226  	expected struct {
   227  		stat struct {
   228  			calledWith string
   229  			isCalled   bool
   230  		}
   231  		abs struct {
   232  			calledWith string
   233  			isCalled   bool
   234  		}
   235  		response []string
   236  		err      []error
   237  	}
   238  }
   239  
   240  func getFilesPaths_noMatchesTestCase() getFilesPathsTestCase {
   241  	return getFilesPathsTestCase{
   242  		name: "success no matches",
   243  		args: struct{ paths []string }{
   244  			paths: []string{},
   245  		},
   246  		mock: struct {
   247  			stat struct {
   248  				response os.FileInfo
   249  				err      error
   250  			}
   251  			abs struct {
   252  				response string
   253  				err      error
   254  			}
   255  		}{
   256  			stat: struct {
   257  				response os.FileInfo
   258  				err      error
   259  			}{
   260  				response: nil,
   261  				err:      nil,
   262  			},
   263  			abs: struct {
   264  				response string
   265  				err      error
   266  			}{
   267  				response: "",
   268  				err:      nil,
   269  			},
   270  		},
   271  		expected: struct {
   272  			stat struct {
   273  				calledWith string
   274  				isCalled   bool
   275  			}
   276  			abs struct {
   277  				calledWith string
   278  				isCalled   bool
   279  			}
   280  			response []string
   281  			err      []error
   282  		}{
   283  			stat: struct {
   284  				calledWith string
   285  				isCalled   bool
   286  			}{
   287  				calledWith: "",
   288  				isCalled:   false,
   289  			},
   290  			abs: struct {
   291  				calledWith string
   292  				isCalled   bool
   293  			}{
   294  				calledWith: "",
   295  				isCalled:   false,
   296  			},
   297  			response: nil,
   298  			err:      nil,
   299  		},
   300  	}
   301  }
   302  
   303  type MockFileInfo struct {
   304  	mock.Mock
   305  	FileName    string
   306  	IsDirectory bool
   307  }
   308  
   309  func (mfi MockFileInfo) Name() string       { return mfi.FileName }
   310  func (mfi MockFileInfo) Size() int64        { return int64(8) }
   311  func (mfi MockFileInfo) Mode() os.FileMode  { return os.ModePerm }
   312  func (mfi MockFileInfo) ModTime() time.Time { return time.Now() }
   313  func (mfi MockFileInfo) Sys() interface{}   { return nil }
   314  
   315  func (c *MockFileInfo) IsDir() bool {
   316  	args := c.Called()
   317  	return args.Get(0).(bool)
   318  }
   319  
   320  func getFilesPaths_withMatchesTestCase() getFilesPathsTestCase {
   321  	mockFileInfo := &MockFileInfo{}
   322  	mockFileInfo.On("IsDir").Return(false)
   323  
   324  	return getFilesPathsTestCase{
   325  		name: "success with matches",
   326  		args: struct{ paths []string }{
   327  			paths: []string{"./fail-30.yaml"},
   328  		},
   329  		mock: struct {
   330  			stat struct {
   331  				response os.FileInfo
   332  				err      error
   333  			}
   334  			abs struct {
   335  				response string
   336  				err      error
   337  			}
   338  		}{
   339  			stat: struct {
   340  				response os.FileInfo
   341  				err      error
   342  			}{
   343  				response: mockFileInfo,
   344  				err:      nil,
   345  			},
   346  			abs: struct {
   347  				response string
   348  				err      error
   349  			}{
   350  				response: "path",
   351  				err:      nil,
   352  			},
   353  		},
   354  		expected: struct {
   355  			stat struct {
   356  				calledWith string
   357  				isCalled   bool
   358  			}
   359  			abs struct {
   360  				calledWith string
   361  				isCalled   bool
   362  			}
   363  			response []string
   364  			err      []error
   365  		}{
   366  			stat: struct {
   367  				calledWith string
   368  				isCalled   bool
   369  			}{
   370  				calledWith: "./fail-30.yaml",
   371  				isCalled:   true,
   372  			},
   373  			abs: struct {
   374  				calledWith string
   375  				isCalled   bool
   376  			}{
   377  				calledWith: "./fail-30.yaml",
   378  				isCalled:   true,
   379  			},
   380  			response: []string{"path"},
   381  			err:      nil,
   382  		},
   383  	}
   384  }