github.com/BenLubar/git-last-modified@v0.1.1-0.20210215221858-9b8031919630/main_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  var stderr io.Writer = os.Stderr
    15  
    16  func pipeStderr(t *testing.T, r *os.File, wait chan<- struct{}) {
    17  	defer func() {
    18  		close(wait)
    19  		if err := r.Close(); err != nil {
    20  			t.Error(err)
    21  		}
    22  	}()
    23  
    24  	var buf [4096]byte
    25  	for {
    26  		n, err := r.Read(buf[:])
    27  		if err != nil && err != io.EOF {
    28  			t.Error(err)
    29  			return
    30  		}
    31  
    32  		n1, err1 := stderr.Write(buf[:n])
    33  		if err1 != nil {
    34  			t.Error(err1)
    35  			return
    36  		}
    37  
    38  		if n1 != n {
    39  			t.Error(io.ErrShortWrite)
    40  			return
    41  		}
    42  
    43  		if err == io.EOF {
    44  			return
    45  		}
    46  	}
    47  }
    48  
    49  func testStderr(t *testing.T, f func(), expected string) {
    50  	r, w, err := os.Pipe()
    51  	if err != nil {
    52  		panic(err)
    53  	}
    54  
    55  	realStderr := os.Stderr
    56  	os.Stderr = w
    57  	wait := make(chan struct{})
    58  	go pipeStderr(t, r, wait)
    59  
    60  	var buf bytes.Buffer
    61  	oldStderr := stderr
    62  	stderr = &buf
    63  	defer func() {
    64  		if err := w.Close(); err != nil {
    65  			t.Error(err)
    66  		}
    67  		<-wait
    68  
    69  		os.Stderr = realStderr
    70  		stderr = oldStderr
    71  		if actual := strings.Replace(buf.String(), "\r\n", "\n", -1); !strings.EqualFold(actual, expected) {
    72  			t.Error("Expected stderr does not match actual stderr.")
    73  			t.Errorf("expected: %q", expected)
    74  			t.Errorf("actual:   %q", actual)
    75  		}
    76  	}()
    77  
    78  	f()
    79  }
    80  
    81  func testExit(t *testing.T, f func(), expectedCode int) {
    82  	type exited int
    83  	oldExit := exit
    84  	exit = func(code int) {
    85  		panic(exited(code))
    86  	}
    87  	defer func() {
    88  		exit = oldExit
    89  		if r := recover(); r == nil {
    90  			t.Errorf("Expected call to exit(%d), but exit was not called.", expectedCode)
    91  		} else if code, ok := r.(exited); ok {
    92  			if int(code) != expectedCode {
    93  				t.Errorf("Expected call to exit(%d), but exit(%d) was called.", expectedCode, int(code))
    94  			}
    95  		} else {
    96  			panic(r)
    97  		}
    98  	}()
    99  
   100  	f()
   101  }
   102  
   103  func TestUsage(t *testing.T) {
   104  	testStderr(t, func() {
   105  		testExit(t, usage, 2)
   106  	}, "usage: git last-modified [<options>] [[--] <path>...]\n"+
   107  		"  -commit-date\n"+
   108  		"    \tUse the commit date for the last commit this file was involved in instead of the author date.\n"+
   109  		"  -n\tDry run. Implies -v. Don't modify any file modification times.\n"+
   110  		"  -q\tQuiet. Don't warn about files specified on the command line that are not in Git.\n"+
   111  		"  -v\tVerbose. Print each filename and modification time as they are processed.\n")
   112  }
   113  
   114  func TestCheckError(t *testing.T) {
   115  	testStderr(t, func() {
   116  		checkError(nil) // should not exit
   117  	}, "")
   118  
   119  	err := errors.New("test")
   120  
   121  	testStderr(t, func() {
   122  		testExit(t, func() {
   123  			checkError(err)
   124  		}, 1)
   125  	}, "git-last-modified: test\n")
   126  
   127  	*flagVerbose = true
   128  	defer func() {
   129  		*flagVerbose = false
   130  	}()
   131  
   132  	testStderr(t, func() {
   133  		testExit(t, func() {
   134  			checkError(err)
   135  		}, 1)
   136  	}, fmt.Sprintf("git-last-modified: test%+v\n", err.(interface{ StackTrace() errors.StackTrace }).StackTrace()))
   137  }