github.com/lubgr/revgrep@v0.0.0-20240125154757-7e5ee1900f8a/revgrep_test.go (about)

     1  package revgrep
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  )
    14  
    15  func setup(t *testing.T, stage, subdir string) (prevwd string, sample []byte) {
    16  	wd, err := os.Getwd()
    17  	if err != nil {
    18  		t.Fatalf("could not get working dir: %s", err)
    19  	}
    20  
    21  	// Execute make
    22  	cmd := exec.Command("./make.sh", stage)
    23  	cmd.Dir = filepath.Join(wd, "testdata")
    24  	sample, err = cmd.CombinedOutput()
    25  	if err != nil {
    26  		t.Fatalf("could not run make.sh: %v, output:\n%s", err, sample)
    27  	}
    28  
    29  	// chdir so the vcs exec commands read the correct testdata
    30  	err = os.Chdir(filepath.Join(wd, "testdata", "git", subdir))
    31  	if err != nil {
    32  		t.Fatalf("could not chdir: %v", err)
    33  	}
    34  	return wd, sample
    35  }
    36  
    37  func teardown(t *testing.T, wd string) {
    38  	err := os.Chdir(wd)
    39  	if err != nil {
    40  		t.Fatalf("could not chdir: %v", err)
    41  	}
    42  }
    43  
    44  // TestCheckerRegexp tests line matching and extraction of issue
    45  func TestCheckerRegexp(t *testing.T) {
    46  	tests := []struct {
    47  		regexp string
    48  		line   string
    49  		want   Issue
    50  	}{
    51  		{"", "file.go:1:issue", Issue{"file.go", 1, 0, 2, "file.go:1:issue", "issue"}},
    52  		{"", "file.go:1:5:issue", Issue{"file.go", 1, 5, 2, "file.go:1:5:issue", "issue"}},
    53  		{"", "file.go:1:  issue", Issue{"file.go", 1, 0, 2, "file.go:1:  issue", "issue"}},
    54  		{`.*?:(.*?\.go):([0-9]+):()(.*)`, "prefix:file.go:1:issue", Issue{"file.go", 1, 0, 2, "prefix:file.go:1:issue", "issue"}},
    55  	}
    56  
    57  	diff := []byte(`--- a/file.go
    58  +++ b/file.go
    59  @@ -1,1 +1,1 @@
    60  -func Line() {}
    61  +func NewLine() {}`)
    62  
    63  	for _, test := range tests {
    64  		checker := Checker{
    65  			Patch:  bytes.NewReader(diff),
    66  			Regexp: test.regexp,
    67  		}
    68  
    69  		issues, err := checker.Check(bytes.NewReader([]byte(test.line)), ioutil.Discard)
    70  		if err != nil {
    71  			t.Errorf("unexpected error: %v", err)
    72  		}
    73  
    74  		want := []Issue{test.want}
    75  		if !reflect.DeepEqual(issues, want) {
    76  			t.Errorf("unexpected issues for line: %q\nhave: %#v\nwant: %#v", test.line, issues, want)
    77  		}
    78  	}
    79  }
    80  
    81  // TestChangesReturn tests the writer in the argument to the Changes function
    82  // and generally tests the entire programs functionality.
    83  func TestChangesWriter(t *testing.T) {
    84  	tests := map[string]struct {
    85  		subdir  string
    86  		exp     []string // file:linenumber including trailing colon
    87  		revFrom string
    88  		revTo   string
    89  	}{
    90  		"2-untracked":            {"", []string{"main.go:3:"}, "", ""},
    91  		"3-untracked-subdir":     {"", []string{"main.go:3:", "subdir/main.go:3:"}, "", ""},
    92  		"3-untracked-subdir-cwd": {"subdir", []string{"main.go:3:"}, "", ""},
    93  		"4-commit":               {"", []string{"main.go:3:", "subdir/main.go:3:"}, "", ""},
    94  		"5-unstaged-no-warning":  {"", nil, "", ""},
    95  		"6-unstaged":             {"", []string{"main.go:6:"}, "", ""},
    96  		// From a commit, all changes should be shown
    97  		"7-commit": {"", []string{"main.go:6:"}, "HEAD~1", ""},
    98  		// From a commit+unstaged, all changes should be shown
    99  		"8-unstaged": {"", []string{"main.go:6:", "main.go:7:"}, "HEAD~1", ""},
   100  		// From a commit+unstaged+untracked, all changes should be shown
   101  		"9-untracked": {"", []string{"main.go:6:", "main.go:7:", "main2.go:2:"}, "HEAD~1", ""},
   102  		// From a commit to last commit, all changes should be shown except recent unstaged, untracked
   103  		"10-committed": {"", []string{"main.go:6:"}, "HEAD~1", "HEAD~0"},
   104  		// static analysis tools with absolute paths should be handled
   105  		"11-abs-path": {"", []string{"main.go:6:"}, "HEAD~1", "HEAD~0"},
   106  		// Removing a single line shouldn't raise any issues.
   107  		"12-removed-lines": {"", nil, "", ""},
   108  	}
   109  
   110  	for stage, test := range tests {
   111  		prevwd, sample := setup(t, stage, test.subdir)
   112  
   113  		reader := bytes.NewBuffer(sample)
   114  		var out bytes.Buffer
   115  
   116  		c := Checker{
   117  			RevisionFrom: test.revFrom,
   118  			RevisionTo:   test.revTo,
   119  		}
   120  		_, err := c.Check(reader, &out)
   121  		if err != nil {
   122  			t.Errorf("%v: unexpected error: %v", stage, err)
   123  		}
   124  
   125  		scanner := bufio.NewScanner(&out)
   126  		var i int
   127  		for i = 0; scanner.Scan(); i++ {
   128  			// Rewrite abs paths to for simpler matching
   129  			line := rewriteAbs(scanner.Text())
   130  
   131  			if i > len(test.exp)-1 {
   132  				t.Errorf("%v: unexpected line: %q", stage, line)
   133  			} else {
   134  				if !strings.HasPrefix(line, test.exp[i]) {
   135  					t.Errorf("%v: line does not have prefix: %q line: %q", stage, test.exp[i], line)
   136  				}
   137  			}
   138  		}
   139  		if i != len(test.exp) {
   140  			t.Errorf("%v: i %v, expected %v", stage, i, len(test.exp))
   141  		}
   142  		teardown(t, prevwd)
   143  	}
   144  }
   145  
   146  func rewriteAbs(line string) string {
   147  	cwd, err := os.Getwd()
   148  	if err != nil {
   149  		panic(err)
   150  	}
   151  	return strings.TrimPrefix(line, cwd+"/")
   152  }
   153  
   154  func TestGitPatchNonGitDir(t *testing.T) {
   155  	// Change to non-git dir
   156  	err := os.Chdir("/")
   157  	if err != nil {
   158  		t.Fatalf("could not chdir: %v", err)
   159  	}
   160  
   161  	patch, newfiles, err := GitPatch("", "")
   162  	if err != nil {
   163  		t.Errorf("error expected nil, got: %v", err)
   164  	}
   165  	if patch != nil {
   166  		t.Errorf("patch expected nil, got: %v", patch)
   167  	}
   168  	if newfiles != nil {
   169  		t.Errorf("newFiles expected nil, got: %v", newfiles)
   170  	}
   171  }
   172  
   173  func TestLinesChanged(t *testing.T) {
   174  	diff := []byte(`--- a/file.go
   175  +++ b/file.go
   176  @@ -1,1 +1,1 @@
   177   // comment
   178  -func Line() {}
   179  +func NewLine() {}
   180  @@ -20,1 +20,1 @@
   181   // comment
   182  -func Line() {}
   183  +func NewLine() {}
   184   // comment
   185  @@ -3,1 +30,1 @@
   186  -func Line() {}
   187  +func NewLine() {}
   188   // comment`)
   189  
   190  	checker := Checker{
   191  		Patch: bytes.NewReader(diff),
   192  	}
   193  
   194  	have := checker.linesChanged()
   195  
   196  	want := map[string][]pos{
   197  		"file.go": []pos{
   198  			{lineNo: 2, hunkPos: 3},
   199  			{lineNo: 21, hunkPos: 7},
   200  			{lineNo: 30, hunkPos: 11},
   201  		},
   202  	}
   203  
   204  	if !reflect.DeepEqual(have, want) {
   205  		t.Errorf("unexpected pos:\nhave: %#v\nwant: %#v", have, want)
   206  	}
   207  }