github.com/reviewdog/reviewdog@v0.17.5-0.20240516205324-0cd103a83d58/project/run_test.go (about)

     1  package project
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"os"
     8  	"runtime"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/reviewdog/reviewdog"
    13  	"github.com/reviewdog/reviewdog/filter"
    14  )
    15  
    16  type fakeDiffService struct {
    17  	reviewdog.DiffService
    18  	FakeDiff func() ([]byte, error)
    19  }
    20  
    21  func (f *fakeDiffService) Diff(_ context.Context) ([]byte, error) {
    22  	return f.FakeDiff()
    23  }
    24  
    25  func (f *fakeDiffService) Strip() int {
    26  	return 0
    27  }
    28  
    29  type fakeCommentService struct {
    30  	reviewdog.CommentService
    31  	FakePost func(*reviewdog.Comment) error
    32  }
    33  
    34  func (f *fakeCommentService) Post(_ context.Context, c *reviewdog.Comment) error {
    35  	return f.FakePost(c)
    36  }
    37  
    38  func TestRun(t *testing.T) {
    39  	ctx := context.Background()
    40  
    41  	t.Run("empty", func(t *testing.T) {
    42  		conf := &Config{}
    43  		if err := Run(ctx, conf, nil, nil, nil, false, filter.ModeAdded, false); err != nil {
    44  			t.Error(err)
    45  		}
    46  	})
    47  
    48  	t.Run("errorformat error", func(t *testing.T) {
    49  		conf := &Config{
    50  			Runner: map[string]*Runner{
    51  				"test": {},
    52  			},
    53  		}
    54  		if err := Run(ctx, conf, nil, nil, nil, false, filter.ModeAdded, false); err == nil {
    55  			t.Error("want error, got nil")
    56  		} else {
    57  			t.Log(err)
    58  		}
    59  	})
    60  
    61  	t.Run("diff error", func(t *testing.T) {
    62  		ds := &fakeDiffService{
    63  			FakeDiff: func() ([]byte, error) {
    64  				return nil, errors.New("err!")
    65  			},
    66  		}
    67  		conf := &Config{
    68  			Runner: map[string]*Runner{
    69  				"test": {
    70  					Cmd:         "echo 'hi'",
    71  					Errorformat: []string{`%f:%l:%c:%m`},
    72  				},
    73  			},
    74  		}
    75  		if err := Run(ctx, conf, nil, nil, ds, false, filter.ModeAdded, false); err == nil {
    76  			t.Error("want error, got nil")
    77  		} else {
    78  			t.Log(err)
    79  		}
    80  	})
    81  
    82  	t.Run("cmd error with findings (not for reviewdog to exit with error)", func(t *testing.T) {
    83  		buf := new(bytes.Buffer)
    84  		defaultTeeStderr = buf
    85  		ds := &fakeDiffService{
    86  			FakeDiff: func() ([]byte, error) {
    87  				return []byte(""), nil
    88  			},
    89  		}
    90  		cs := &fakeCommentService{
    91  			FakePost: func(c *reviewdog.Comment) error {
    92  				return nil
    93  			},
    94  		}
    95  		conf := &Config{
    96  			Runner: map[string]*Runner{
    97  				"test": {
    98  					Cmd:         "echo 'file:14:14:message'; exit 1",
    99  					Errorformat: []string{`%f:%l:%c:%m`},
   100  				},
   101  			},
   102  		}
   103  		if err := Run(ctx, conf, nil, cs, ds, false, filter.ModeAdded, false); err != nil {
   104  			t.Error(err)
   105  		}
   106  		want := ""
   107  		if got := buf.String(); got != want {
   108  			t.Errorf("got stderr %q, want %q", got, want)
   109  		}
   110  	})
   111  
   112  	t.Run("unexpected cmd error (reviewdog exits with error)", func(t *testing.T) {
   113  		buf := new(bytes.Buffer)
   114  		defaultTeeStderr = buf
   115  		ds := &fakeDiffService{
   116  			FakeDiff: func() ([]byte, error) {
   117  				return []byte(""), nil
   118  			},
   119  		}
   120  		cs := &fakeCommentService{
   121  			FakePost: func(c *reviewdog.Comment) error {
   122  				return nil
   123  			},
   124  		}
   125  		conf := &Config{
   126  			Runner: map[string]*Runner{
   127  				"test": {
   128  					Cmd:         "not found",
   129  					Errorformat: []string{`%f:%l:%c:%m`},
   130  				},
   131  			},
   132  		}
   133  		if err := Run(ctx, conf, nil, cs, ds, false, filter.ModeAdded, false); err == nil {
   134  			t.Error("want error, got nil")
   135  		} else {
   136  			t.Log(err)
   137  		}
   138  	})
   139  
   140  	t.Run("cmd error with tee", func(t *testing.T) {
   141  		buf := new(bytes.Buffer)
   142  		defaultTeeStderr = buf
   143  		ds := &fakeDiffService{
   144  			FakeDiff: func() ([]byte, error) {
   145  				return []byte(""), nil
   146  			},
   147  		}
   148  		cs := &fakeCommentService{
   149  			FakePost: func(c *reviewdog.Comment) error {
   150  				return nil
   151  			},
   152  		}
   153  		conf := &Config{
   154  			Runner: map[string]*Runner{
   155  				"test": {
   156  					Cmd:         "not-found",
   157  					Errorformat: []string{`%f:%l:%c:%m`},
   158  				},
   159  			},
   160  		}
   161  		if err := Run(ctx, conf, nil, cs, ds, true, filter.ModeAdded, false); err == nil {
   162  			t.Error("want error, got nil")
   163  		} else {
   164  			t.Log(err)
   165  		}
   166  		var want string
   167  		if runtime.GOOS == "darwin" {
   168  			want = "sh: not-found: command not found\n"
   169  		} else {
   170  			want = "sh: 1: not-found: not found\n"
   171  		}
   172  		if got := buf.String(); got != want {
   173  			t.Errorf("got stderr %q, want %q", got, want)
   174  		}
   175  	})
   176  
   177  	t.Run("success", func(t *testing.T) {
   178  		ds := &fakeDiffService{
   179  			FakeDiff: func() ([]byte, error) {
   180  				return []byte(""), nil
   181  			},
   182  		}
   183  		cs := &fakeCommentService{
   184  			FakePost: func(c *reviewdog.Comment) error {
   185  				return nil
   186  			},
   187  		}
   188  		conf := &Config{
   189  			Runner: map[string]*Runner{
   190  				"test": {
   191  					Cmd:         "echo 'hi'",
   192  					Errorformat: []string{`%f:%l:%c:%m`},
   193  				},
   194  			},
   195  		}
   196  		if err := Run(ctx, conf, nil, cs, ds, false, filter.ModeAdded, false); err != nil {
   197  			t.Error(err)
   198  		}
   199  	})
   200  
   201  	t.Run("success with tee", func(t *testing.T) {
   202  		buf := new(bytes.Buffer)
   203  		defaultTeeStdout = buf
   204  		ds := &fakeDiffService{
   205  			FakeDiff: func() ([]byte, error) {
   206  				return []byte(""), nil
   207  			},
   208  		}
   209  		cs := &fakeCommentService{
   210  			FakePost: func(c *reviewdog.Comment) error {
   211  				return nil
   212  			},
   213  		}
   214  		conf := &Config{
   215  			Runner: map[string]*Runner{
   216  				"test": {
   217  					Cmd:         "echo 'hi'",
   218  					Errorformat: []string{`%f:%l:%c:%m`},
   219  				},
   220  			},
   221  		}
   222  		if err := Run(ctx, conf, nil, cs, ds, true, filter.ModeAdded, false); err != nil {
   223  			t.Error(err)
   224  		}
   225  		want := "hi\n"
   226  		if got := buf.String(); got != want {
   227  			t.Errorf("got stdout %q, want %q", got, want)
   228  		}
   229  	})
   230  
   231  	t.Run("runners", func(t *testing.T) {
   232  		called := 0
   233  		ds := &fakeDiffService{
   234  			FakeDiff: func() ([]byte, error) {
   235  				called++
   236  				return []byte(""), nil
   237  			},
   238  		}
   239  		cs := &fakeCommentService{
   240  			FakePost: func(c *reviewdog.Comment) error {
   241  				return nil
   242  			},
   243  		}
   244  		conf := &Config{
   245  			Runner: map[string]*Runner{
   246  				"test1": {
   247  					Name:        "test1",
   248  					Cmd:         "echo 'test1'",
   249  					Errorformat: []string{`%f:%l:%c:%m`},
   250  				},
   251  				"test2": {
   252  					Name:        "test2",
   253  					Cmd:         "echo 'test2'",
   254  					Errorformat: []string{`%f:%l:%c:%m`},
   255  				},
   256  			},
   257  		}
   258  		if err := Run(ctx, conf, map[string]bool{"test2": true}, cs, ds, false, filter.ModeAdded, false); err != nil {
   259  			t.Error(err)
   260  		}
   261  		if called != 1 {
   262  			t.Errorf("Diff service called %d times, want 1 time", called)
   263  		}
   264  	})
   265  
   266  	t.Run("unknown runners", func(t *testing.T) {
   267  		ds := &fakeDiffService{
   268  			FakeDiff: func() ([]byte, error) {
   269  				return []byte(""), nil
   270  			},
   271  		}
   272  		cs := &fakeCommentService{
   273  			FakePost: func(c *reviewdog.Comment) error {
   274  				return nil
   275  			},
   276  		}
   277  		conf := &Config{
   278  			Runner: map[string]*Runner{
   279  				"test1": {
   280  					Name:        "test1",
   281  					Cmd:         "echo 'test1'",
   282  					Errorformat: []string{`%f:%l:%c:%m`},
   283  				},
   284  				"test2": {
   285  					Name:        "test2",
   286  					Cmd:         "echo 'test2'",
   287  					Errorformat: []string{`%f:%l:%c:%m`},
   288  				},
   289  			},
   290  		}
   291  		if err := Run(ctx, conf, map[string]bool{"hoge": true}, cs, ds, false, filter.ModeAdded, false); err == nil {
   292  			t.Error("got no error but want runner not found error")
   293  		}
   294  	})
   295  }
   296  
   297  func TestFilteredEnviron(t *testing.T) {
   298  	names := [...]string{
   299  		"REVIEWDOG_GITHUB_API_TOKEN",
   300  		"REVIEWDOG_GITLAB_API_TOKEN",
   301  		"REVIEWDOG_TOKEN",
   302  	}
   303  
   304  	for _, name := range names {
   305  		defer func(name, value string) {
   306  			os.Setenv(name, value)
   307  		}(name, os.Getenv(name))
   308  		os.Setenv(name, "value")
   309  	}
   310  
   311  	filtered := filteredEnviron()
   312  	if len(filtered) != len(os.Environ())-len(names) {
   313  		t.Errorf("len(filtered) != len(os.Environ())-%d, %v != %v-%d", len(names), len(filtered), len(os.Environ()), len(names))
   314  	}
   315  
   316  	for _, kv := range filtered {
   317  		for _, name := range names {
   318  			if strings.HasPrefix(kv, name) && kv != name+"=" {
   319  				t.Errorf("filtered: %v, want %v=", kv, name)
   320  			}
   321  		}
   322  	}
   323  
   324  	for _, kv := range os.Environ() {
   325  		for _, name := range names {
   326  			if strings.HasPrefix(kv, name) && kv != name+"=value" {
   327  				t.Errorf("envs: %v, want %v=value", kv, name)
   328  			}
   329  		}
   330  	}
   331  }