github.com/elves/elvish@v0.15.0/pkg/edit/highlight_test.go (about)

     1  package edit
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"testing"
     9  
    10  	"github.com/elves/elvish/pkg/cli/term"
    11  	"github.com/elves/elvish/pkg/env"
    12  	"github.com/elves/elvish/pkg/eval"
    13  	"github.com/elves/elvish/pkg/eval/vars"
    14  	"github.com/elves/elvish/pkg/parse"
    15  	"github.com/elves/elvish/pkg/testutil"
    16  	"github.com/elves/elvish/pkg/tt"
    17  )
    18  
    19  // High-level sanity test.
    20  
    21  func TestHighlighter(t *testing.T) {
    22  	f := setup()
    23  	defer f.Cleanup()
    24  
    25  	feedInput(f.TTYCtrl, "put $true")
    26  	f.TestTTY(t,
    27  		"~> put $true", Styles,
    28  		"   vvv $$$$$", term.DotHere,
    29  	)
    30  
    31  	feedInput(f.TTYCtrl, "x")
    32  	f.TestTTY(t,
    33  		"~> put $truex", Styles,
    34  		"   vvv ??????", term.DotHere, "\n",
    35  		"compilation error: 4-10 in [tty]: variable $truex not found",
    36  	)
    37  }
    38  
    39  // Fine-grained tests against the highlighter.
    40  
    41  func TestCheck(t *testing.T) {
    42  	ev := eval.NewEvaler()
    43  	ev.AddGlobal(eval.NsBuilder{"good": vars.FromInit(0)}.Ns())
    44  
    45  	tt.Test(t, tt.Fn("check", check), tt.Table{
    46  		tt.Args(ev, mustParse("")).Rets(noError),
    47  		tt.Args(ev, mustParse("echo $good")).Rets(noError),
    48  		// TODO: Check the range of the returned error
    49  		tt.Args(ev, mustParse("echo $bad")).Rets(anyError),
    50  	})
    51  }
    52  
    53  type anyErrorMatcher struct{}
    54  
    55  func (anyErrorMatcher) Match(ret tt.RetValue) bool {
    56  	err, _ := ret.(error)
    57  	return err != nil
    58  }
    59  
    60  var (
    61  	noError  = error(nil)
    62  	anyError anyErrorMatcher
    63  )
    64  
    65  const colonInFilenameOk = runtime.GOOS != "windows"
    66  
    67  func TestMakeHasCommand(t *testing.T) {
    68  	ev := eval.NewEvaler()
    69  
    70  	// Set up global functions and modules in the evaler.
    71  	goodFn := eval.NewGoFn("good", func() {})
    72  	ev.AddGlobal(eval.NsBuilder{}.
    73  		AddFn("good", goodFn).
    74  		AddNs("a",
    75  			eval.NsBuilder{}.
    76  				AddFn("good", goodFn).
    77  				AddNs("b", eval.NsBuilder{}.AddFn("good", goodFn).Ns()).
    78  				Ns()).
    79  		Ns())
    80  
    81  	// Set up environment.
    82  	testDir, cleanup := testutil.InTestDir()
    83  	defer cleanup()
    84  	oldPath := os.Getenv(env.PATH)
    85  	defer os.Setenv(env.PATH, oldPath)
    86  	if runtime.GOOS == "windows" {
    87  		oldPathExt := os.Getenv(env.PATHEXT)
    88  		defer os.Setenv(env.PATHEXT, oldPathExt)
    89  		os.Unsetenv(env.PATHEXT) // force default value
    90  	}
    91  
    92  	// Set up a directory in PATH.
    93  	os.Setenv(env.PATH, filepath.Join(testDir, "bin"))
    94  	mustMkdirAll("bin")
    95  	mustMkExecutable("bin/external")
    96  	mustMkExecutable("bin/@external")
    97  	if colonInFilenameOk {
    98  		mustMkExecutable("bin/ex:tern:al")
    99  	}
   100  
   101  	// Set up a directory not in PATH.
   102  	mustMkdirAll("a/b/c")
   103  	mustMkExecutable("a/b/c/executable")
   104  
   105  	tt.Test(t, tt.Fn("hasCommand", hasCommand), tt.Table{
   106  		// Builtin special form
   107  		tt.Args(ev, "if").Rets(true),
   108  
   109  		// Builtin function
   110  		tt.Args(ev, "put").Rets(true),
   111  		// Explicit builtin:
   112  		tt.Args(ev, "builtin:put").Rets(true),
   113  		tt.Args(ev, "builtin:bad-builtin").Rets(false),
   114  
   115  		// User-defined function
   116  		tt.Args(ev, "good").Rets(true),
   117  
   118  		// Function in modules
   119  		tt.Args(ev, "a:good").Rets(true),
   120  		tt.Args(ev, "a:b:good").Rets(true),
   121  		tt.Args(ev, "a:bad").Rets(false),
   122  		tt.Args(ev, "a:b:bad").Rets(false),
   123  
   124  		// Non-searching directory and external
   125  		tt.Args(ev, "./a").Rets(true),
   126  		tt.Args(ev, "a/b").Rets(true),
   127  		tt.Args(ev, "a/b/c/executable").Rets(true),
   128  		tt.Args(ev, "./bad").Rets(false),
   129  		tt.Args(ev, "a/bad").Rets(false),
   130  
   131  		// External in PATH
   132  		tt.Args(ev, "external").Rets(true),
   133  		tt.Args(ev, "@external").Rets(true),
   134  		tt.Args(ev, "ex:tern:al").Rets(colonInFilenameOk),
   135  		// With explicit e:
   136  		tt.Args(ev, "e:external").Rets(true),
   137  		tt.Args(ev, "e:bad-external").Rets(false),
   138  
   139  		// Non-existent
   140  		tt.Args(ev, "bad").Rets(false),
   141  		tt.Args(ev, "a:").Rets(false),
   142  	})
   143  }
   144  
   145  func mustParse(src string) parse.Tree {
   146  	tree, err := parse.Parse(parse.SourceForTest(src))
   147  	if err != nil {
   148  		panic(err)
   149  	}
   150  	return tree
   151  }
   152  
   153  func mustMkdirAll(path string) {
   154  	err := os.MkdirAll(path, 0700)
   155  	if err != nil {
   156  		panic(err)
   157  	}
   158  }
   159  
   160  func mustMkExecutable(path string) {
   161  	if runtime.GOOS == "windows" {
   162  		path += ".exe"
   163  	}
   164  	err := ioutil.WriteFile(path, nil, 0700)
   165  	if err != nil {
   166  		panic(err)
   167  	}
   168  }