From ed2b9374599cc00467b1c27121318748cc0d3f49 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Sat, 28 Mar 2020 13:53:10 +0100 Subject: rename pkg/ to internal/ --- internal/rtree/shared_test.go | 204 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 internal/rtree/shared_test.go (limited to 'internal/rtree/shared_test.go') diff --git a/internal/rtree/shared_test.go b/internal/rtree/shared_test.go new file mode 100644 index 0000000..6720b1c --- /dev/null +++ b/internal/rtree/shared_test.go @@ -0,0 +1,204 @@ +/******************************************************************************* +* +* Copyright 2017 Stefan Majewsky +* +* This program is free software: you can redistribute it and/or modify it under +* the terms of the GNU General Public License as published by the Free Software +* Foundation, either version 3 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY +* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +* A PARTICULAR PURPOSE. See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see . +* +*******************************************************************************/ + +package rtree + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "github.com/majewsky/gofu/internal/cli" + yaml "gopkg.in/yaml.v2" +) + +//Path to a directory where tests can put their index files. +var indexTmpDir = filepath.Join(os.TempDir(), fmt.Sprintf("rtree-test-%d", os.Getpid())) + +func TestMain(m *testing.M) { + //make sure that test does not accidentally access user's actual rtree or index + os.Setenv("HOME", "") + os.Setenv("GOPATH", "") + //setup test configuration + RootPath = "/unittest/gopath/src" + RemoteAliases = []*RemoteAlias{ + {Alias: "gh:", Replacement: "https://github.com/"}, + {Alias: "my/", Replacement: "git@git.example.com:"}, + } + + exitCode := m.Run() + + //shared teardown + os.RemoveAll(indexTmpDir) + + os.Exit(exitCode) +} + +//Test describes a call to Main(), the environment that's given to it, and the +//assertions that are checked after the call returns. +type Test struct { + Args []string + Input string + Index Index + ExpectFailure bool + ExpectOutput string + ExpectError string + ExpectIndex *Index //if nil, .Index will be used instead + ExpectExecution []RecordedCommand +} + +func (test Test) Run(t *testing.T) { + //write index file, if any + IndexPath = filepath.Join(indexTmpDir, t.Name()+".yaml") + if test.Index.Repos != nil { + err := test.Index.Write() + if err != nil { + t.Fatalf("%s: cannot write index to %s: %s", t.Name(), IndexPath, err.Error()) + } + } + + //setup cli.Interface for test + var stdout bytes.Buffer + var stderr bytes.Buffer + cs := CommandSimulator{Cmd: test.ExpectExecution} + cli.SetupInterface(bytes.NewReader([]byte(test.Input)), &stdout, &stderr, cs.Next) + + //check exit code + exitCode := Exec(test.Args) + switch { + case exitCode == 0 && test.ExpectFailure: + t.Errorf("%s: expected failure, but returned success", t.Name()) + case exitCode != 0 && !test.ExpectFailure: + t.Errorf("%s: expected success, but returned failure", t.Name()) + } + + //check output + output := string(stdout.Bytes()) + if output != test.ExpectOutput { + t.Errorf("%s: expected stdout %#v, but got %#v", t.Name(), test.ExpectOutput, output) + } + output = string(stderr.Bytes()) + if output != test.ExpectError { + t.Errorf("%s: expected stderr %#v, but got %#v", t.Name(), test.ExpectError, output) + } + + //check index + idx := &test.Index + if test.ExpectIndex != nil { + idx = test.ExpectIndex + } + expectedIdxStr, err := yaml.Marshal(idx) + if err != nil { + t.Fatal(err.Error()) + } + actualIdxStr, err := ioutil.ReadFile(IndexPath) + if err != nil { + t.Fatalf("%s: could not read index from %s: %s", t.Name(), IndexPath, err.Error()) + } + if string(expectedIdxStr) != string(actualIdxStr) { + t.Errorf("%s: index does not match expectation after test; diff follows", t.Name()) + cmd := exec.Command("diff", "-u", "-", IndexPath) + cmd.Stdin = bytes.NewReader([]byte(expectedIdxStr)) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + t.Fatal(err.Error()) + } + } +} + +type RecordedCommand struct { + Cmd cli.Command + Stdout string + Stderr string + Fails bool +} + +//Recorded is a shortcut function for initializing a []RecordedCommand. It +//splits each line on whitespace to obtain the command line of that command, +//and recognizes a leading "@/some/path" to set the workdir. +// +//This function can only be used for RecordedCommands without output that do not fail. +func Recorded(lines ...string) (cs []RecordedCommand) { + cs = make([]RecordedCommand, len(lines)) + for idx, line := range lines { + cmdline := strings.Fields(line) + if strings.HasPrefix(cmdline[0], "@") { + cs[idx].Cmd.WorkDir = strings.TrimPrefix(cmdline[0], "@") + cmdline = cmdline[1:] + } + cs[idx].Cmd.Program = cmdline + } + return +} + +//CommandSimulator implements the cli.CommandRunner interface (via its Next +//method). When a cli.Command is given to Next(), it is matched with the next +//command in the .Cmd list, and the result from that RecordedCommand is +//returned. If the given Command is different from the one expected (or if the +//.Cmd list has been exhausted), an error is returned. +type CommandSimulator struct { + Cmd []RecordedCommand + idx int +} + +func (s *CommandSimulator) Next(c cli.Command, stdin io.Reader, stdout, stderr io.Writer) error { + //take next RecordedCommand from list + if s.idx >= len(s.Cmd) { + return errors.New("got command to execute, but recorded commands have been exhausted") + } + sc := s.Cmd[s.idx] + s.idx++ + + //check if the given Command matches the expectation + if !areStringListsEqual(sc.Cmd.Program, c.Program) { + return fmt.Errorf("expected command %#v, but got %#v", + strings.Join(sc.Cmd.Program, " "), strings.Join(c.Program, " "), + ) + } + if sc.Cmd.WorkDir != c.WorkDir { + return fmt.Errorf("expected command workdir %s, but got %s", sc.Cmd.WorkDir, c.WorkDir) + } + + stdout.Write([]byte(sc.Stdout)) + stderr.Write([]byte(sc.Stderr)) + if sc.Fails { + return fmt.Errorf("command %#v has failed", strings.Join(c.Program, " ")) + } + return nil +} + +func areStringListsEqual(a []string, b []string) bool { + if len(a) != len(b) { + return false + } + for idx := range a { + if a[idx] != b[idx] { + return false + } + } + return true +} -- cgit v1.3.1