From b15c9ad43c43ffae13864db66247397d27b5ef79 Mon Sep 17 00:00:00 2001 From: "Mike JS. Choi" Date: Fri, 18 May 2018 13:10:36 -0500 Subject: [PATCH] Test: Add tests for summary.go --- conflict/command_test.go | 16 +++++++ editor/content.go | 46 +++++++++++++++++++ editor/editor.go | 91 +++++++++++++++++++++++++++++++++++++ main.go | 2 +- summary.go | 35 +++++++------- summary_test.go | 98 ++++++++++++++++++++++++++++------------ 6 files changed, 241 insertions(+), 47 deletions(-) create mode 100644 conflict/command_test.go create mode 100755 editor/content.go create mode 100755 editor/editor.go diff --git a/conflict/command_test.go b/conflict/command_test.go new file mode 100644 index 0000000..f26f5da --- /dev/null +++ b/conflict/command_test.go @@ -0,0 +1,16 @@ +package conflict + +import ( + "testing" +) + +var commands = []struct { + command string + ok bool +}{ + {"time", true}, + {"foobar", false}, +} + +func TestRun(t *testing.T) { +} diff --git a/editor/content.go b/editor/content.go new file mode 100755 index 0000000..c824dd9 --- /dev/null +++ b/editor/content.go @@ -0,0 +1,46 @@ +package editor + +import ( + "bufio" + "io" + "os" + "strings" +) + +// Content represents a the in- and output of an extedit session. +type Content struct { + c []string + reader io.Reader +} + +func (c Content) Read(b []byte) (int, error) { + return c.reader.Read(b) +} + +func (c Content) String() string { + return strings.Join(c.c, "\n") +} + +// contentFromReader creates a new Content object by scanning an io.Reader using a bufio.SplitFunc +func contentFromReader(content io.Reader, split bufio.SplitFunc) (Content, error) { + c := Content{} + scanner := bufio.NewScanner(content) + scanner.Split(split) + + for scanner.Scan() { + c.c = append(c.c, scanner.Text()) + } + c.reader = strings.NewReader(c.String()) + + return c, scanner.Err() +} + +func contentFromFile(filename string, split bufio.SplitFunc) (Content, error) { + file, err := os.Open(filename) + if err != nil { + return Content{}, err + } + defer file.Close() + + return contentFromReader(file, split) +} diff --git a/editor/editor.go b/editor/editor.go new file mode 100755 index 0000000..a9d8928 --- /dev/null +++ b/editor/editor.go @@ -0,0 +1,91 @@ +package editor + +import ( + "bufio" + "io" + "io/ioutil" + "os" + "os/exec" + "strings" + + "github.com/mkchoi212/fac/conflict" +) + +const defaultEditor = "vim" + +type Session struct { + input Content + result Content + SplitFunc bufio.SplitFunc +} + +// Open starts a text-editor with the contents of content. +// It returns edited content after user closes the editor +func Open(conf *conflict.Conflict) (output []string, err error) { + s := NewSession() + + lines := append([]string{}, conf.LocalLines...) + lines = append(lines, "=======\n") + lines = append(lines, conf.IncomingLines...) + + content := strings.NewReader(strings.Join(lines, "")) + input, err := contentFromReader(content, s.SplitFunc) + + if err != nil { + return + } + + fileName, err := writeTmpFile(input) + if err != nil { + return + } + + cmd := editorCmd(fileName) + err = cmd.Run() + if err != nil { + return + } + + newContent, err := contentFromFile(fileName, s.SplitFunc) + if err != nil { + return + } + + output = newContent.c + + return +} + +func NewSession() *Session { + return &Session{SplitFunc: bufio.ScanLines} +} + +// writeTmpFile writes content to a temporary file and returns +// the path to the file +func writeTmpFile(content io.Reader) (string, error) { + f, err := ioutil.TempFile("", "") + + if err != nil { + return "", err + } + + io.Copy(f, content) + f.Close() + return f.Name(), nil +} + +// editorCmd creates a os/exec.Cmd to open +// filename in an editor ready to be run() +func editorCmd(filename string) *exec.Cmd { + editorPath := os.Getenv("EDITOR") + if editorPath == "" { + editorPath = defaultEditor + } + editor := exec.Command(editorPath, filename) + + editor.Stdin = os.Stdin + editor.Stdout = os.Stdout + editor.Stderr = os.Stderr + + return editor +} diff --git a/main.go b/main.go index bf7c01b..9573aa6 100644 --- a/main.go +++ b/main.go @@ -134,5 +134,5 @@ func main() { fmt.Println(color.Red(color.Underline, "%s\n", err)) } } - printSummary() + printSummary(conflicts) } diff --git a/summary.go b/summary.go index 7fd33d8..e417717 100644 --- a/summary.go +++ b/summary.go @@ -3,32 +3,35 @@ package main import ( "bytes" "fmt" + "io" + + "github.com/mkchoi212/fac/conflict" - "github.com/jroimartin/gocui" "github.com/mkchoi212/fac/color" ) -func printHelp(v *gocui.View) { - instruction := ` - w - show more lines up - s - show more lines down - a - use local version - d - use incoming version +var instruction = ` +w - show more lines up +s - show more lines down +a - use local version +d - use incoming version + +j - scroll down +k - scroll up - j - scroll down - k - scroll up +v - [v]iew orientation +n - [n]ext conflict +p - [p]revious conflict - v - [v]iew orientation - n - [n]ext conflict - p - [p]revious conflict +h | ? - [h]elp +q | Ctrl+c - [q]uit +` - h | ? - [h]elp - q | Ctrl+c - [q]uit - ` +func printHelp(v io.Writer) { fmt.Fprintf(v, color.Blue(color.Regular, instruction)) } -func printSummary() { +func printSummary(conflicts []*conflict.Conflict) { resolvedCnt := 0 var line string diff --git a/summary_test.go b/summary_test.go index 1ec91ca..7d04c60 100644 --- a/summary_test.go +++ b/summary_test.go @@ -1,45 +1,83 @@ package main import ( + "bytes" + "io/ioutil" + "os" + "reflect" "strings" "testing" + "github.com/mkchoi212/fac/color" "github.com/mkchoi212/fac/conflict" ) -func TestFinalizeChanges(t *testing.T) { - c := conflict.Conflict{} - c.Choice = Local - c.Start = 4 - c.End = 10 - c.LocalPureLines = []string{ - "$ go get github.com/mkchoi212/fac\n", +var dummyFile = conflict.File{Name: "Foobar"} +var dummyConflicts = []*conflict.Conflict{ + {Choice: conflict.Local, File: &dummyFile}, + {Choice: conflict.Local, File: &dummyFile}, + {Choice: 0, File: &dummyFile}, +} + +var expected_two_resolved = []string{ + "[32;1m✔ Foobar: 0", + "[32;1m✔ Foobar: 0", + "[31;1m✘ Foobar: 0", + "", + "Resolved 2 conflict(s) out of 3", +} + +var expected_all_resolved = []string{ + "[32;1m✔ Foobar: 0", + "[32;1m✔ Foobar: 0", + "[32;1m✔ Foobar: 0", + "[32;1m", + "Fixed All Conflicts 🎉", + "", +} + +func TestPrintHelp(t *testing.T) { + var b bytes.Buffer + printHelp(&b) + + out := b.String() + if out != color.Blue(color.Regular, instruction) { + t.Errorf("PrintHelp failed: wanted blue colored %s..., got %s", instruction[:45], out) } +} + +func TestSummary(t *testing.T) { + // Capture stdout + oldStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + printSummary(dummyConflicts) + dummyConflicts[2].Choice = conflict.Local + printSummary(dummyConflicts) - dummyLines := []string{ - "## 👷 Installation\n", - "Execute:\n", - "```bash\n", - "<<<<<<< Updated upstream:assets/README.md\n", - "$ go get github.com/mkchoi212/fac\n", - "||||||| merged common ancestors\n", - "$ go get github.com/parliament/fac\n", - "=======\n", - "$ go get github.com/parliament/facc\n", - ">>>>>>> Stashed changes:README.md\n", - "```\n", + w.Close() + out, _ := ioutil.ReadAll(r) + os.Stdout = oldStdout + output := strings.Split(string(out), "\n") + expected := append(expected_two_resolved, expected_all_resolved...) + + if len(expected) != len(output) { + t.Errorf("Summary failed: got \n%v, wanted \n%v", output, expected) } - output := strings.Join(FinalizeChanges([]conflict.Conflict{c}, dummyLines), "") - expected := strings.Join([]string{ - "## 👷 Installation\n", - "Execute:\n", - "```bash\n", - "$ go get github.com/mkchoi212/fac\n", - "```\n", - }, "") - - if output != expected { - t.Errorf("FinalizeChanges was incorrect: got \n%s, want \n%s", output, expected) + for i := range expected { + expectedLine := []byte(expected[i]) + outputLine := []byte(output[i]) + // Remove ESC bytes + outputLine = bytes.Trim(outputLine, string([]byte{27})) + + if len(expectedLine) == 0 { + continue + } + + if !(reflect.DeepEqual(expectedLine, outputLine)) { + t.Errorf("Summary failed: got %s, wanted %s", outputLine, expectedLine) + } } }