github.com/quantumghost/awgo@v0.15.0/util/scripts_test.go (about)

     1  //
     2  // Copyright (c) 2018 Dean Jackson <deanishe@deanishe.net>
     3  //
     4  // MIT Licence. See http://opensource.org/licenses/MIT
     5  //
     6  // Created on 2018-02-10
     7  //
     8  
     9  package util
    10  
    11  import (
    12  	"io/ioutil"
    13  	"os"
    14  	"path/filepath"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  // Scripts in various language that write $1 to STDOUT.
    20  var testScripts = []struct {
    21  	name, script string
    22  }{
    23  	{"python.py", "import sys; print(sys.argv[1])"},
    24  	{"python_exe", `#!/usr/bin/python
    25  import sys
    26  print(sys.argv[1])`},
    27  
    28  	{"bash.sh", `echo "$1"`},
    29  	{"bash_exe", `#!/bin/bash
    30  echo "$1"`},
    31  
    32  	{"applescript.scpt", `on run(argv)
    33  	return first item of argv
    34  end run`},
    35  	{"applescript.applescript", `on run(argv)
    36  	return first item of argv
    37  end run`},
    38  	{"jxa.js", `function run(argv) { return argv[0]; }`},
    39  }
    40  
    41  // Files that should be ignored
    42  var invalidFiles = []struct {
    43  	name, content string
    44  }{
    45  	{"word.doc", "blah"},
    46  	{"plain.txt", "hello!"},
    47  	{"non-executable", "dummy"},
    48  	{"perl.pl", "$$@£@..21!55-"},
    49  }
    50  
    51  // Create and execute function in a directory containing testScripts.
    52  func withTestScripts(fun func(names []string)) {
    53  
    54  	err := inTempDir(func(dir string) {
    55  
    56  		names := []string{}
    57  
    58  		// Create test scripts
    59  		for _, ts := range testScripts {
    60  
    61  			names = append(names, ts.name)
    62  
    63  			perms := os.FileMode(0600)
    64  
    65  			// Make scripts w/o extensions executable
    66  			if filepath.Ext(ts.name) == "" {
    67  				perms = 0700
    68  			}
    69  			if err := ioutil.WriteFile(ts.name, []byte(ts.script), perms); err != nil {
    70  				panic(err)
    71  			}
    72  		}
    73  
    74  		for _, ts := range invalidFiles {
    75  
    76  			names = append(names, ts.name)
    77  
    78  			if err := ioutil.WriteFile(ts.name, []byte(ts.content), 0600); err != nil {
    79  				panic(err)
    80  			}
    81  		}
    82  
    83  		// Execute function
    84  		fun(names)
    85  	})
    86  
    87  	if err != nil {
    88  		panic(err)
    89  	}
    90  }
    91  
    92  func TestExecutableRunnerCanRun(t *testing.T) {
    93  	data := []struct {
    94  		in string
    95  		x  bool
    96  	}{
    97  		{"", false},
    98  		{"non-existent", false},
    99  		// Directories
   100  		{"/Applications", false},
   101  		{"/var", false}, // symlink on macOS
   102  		{"/", false},
   103  		{"/bin", false},
   104  		// Existing paths
   105  		{"/usr/bin/python2.7", true}, // symlink on El Cap
   106  		{"/bin/cp", true},
   107  		{"/bin/ls", true},
   108  		{"/bin/mv", true},
   109  	}
   110  
   111  	r := ExecRunner{}
   112  
   113  	for _, td := range data {
   114  		v := r.CanRun(td.in)
   115  		if v != td.x {
   116  			t.Errorf("Bad CanRun for %#v. Expected=%v, Got=%v", td.in, td.x, v)
   117  		}
   118  	}
   119  }
   120  
   121  func TestScriptRunnerCanRun(t *testing.T) {
   122  
   123  	withTestScripts(func(names []string) {
   124  
   125  		invalid := map[string]bool{}
   126  		for _, ts := range invalidFiles {
   127  			invalid[ts.name] = true
   128  		}
   129  		for _, ts := range testScripts { // can't run extension-less files
   130  			if strings.Index(ts.name, ".") < 0 {
   131  				invalid[ts.name] = true
   132  			}
   133  		}
   134  
   135  		r := ScriptRunner{DefaultInterpreters}
   136  
   137  		for _, name := range names {
   138  
   139  			v := r.CanRun(name)
   140  			if v && invalid[name] {
   141  				t.Errorf("Invalid accepted: %s", name)
   142  			}
   143  			if !v && !invalid[name] {
   144  				t.Errorf("Valid rejected: %s", name)
   145  			}
   146  		}
   147  
   148  	})
   149  
   150  }
   151  
   152  func TestRun(t *testing.T) {
   153  
   154  	withTestScripts(func(names []string) {
   155  
   156  		invalid := map[string]bool{}
   157  		for _, ts := range invalidFiles {
   158  			invalid[ts.name] = true
   159  		}
   160  
   161  		var good, bad int
   162  		// Execute scripts and compare output
   163  		for _, name := range names {
   164  
   165  			out, err := Run(name, name)
   166  			if err != nil {
   167  
   168  				if err == ErrUnknownFileType {
   169  					if !invalid[name] {
   170  						t.Errorf("Failed to run valid script (%s): %v", name, err)
   171  						continue
   172  					}
   173  					// correctly rejected
   174  					bad++
   175  					continue
   176  				}
   177  
   178  				t.Fatalf("Error running %v: %v", name, err)
   179  			}
   180  
   181  			s := strings.TrimSpace(string(out))
   182  			if s != name {
   183  				t.Errorf("Bad output. Expected=%v, Got=%v", name, s)
   184  			} else {
   185  				good++
   186  			}
   187  
   188  		}
   189  
   190  		if good != len(testScripts) {
   191  			t.Errorf("Bad script count. Expected=%v, Got=%v", len(testScripts), good)
   192  		}
   193  
   194  		if bad != len(invalidFiles) {
   195  			t.Errorf("Bad invalid file count. Expected=%v, Got=%v", len(invalidFiles), bad)
   196  		}
   197  
   198  	})
   199  }
   200  
   201  // TestNewScriptRunner verifies that ScriptRunner accepts the correct filetypes.
   202  func TestNewScriptRunner(t *testing.T) {
   203  
   204  	data := []struct {
   205  		good, bad int
   206  		m         map[string][]string
   207  	}{
   208  		// Python scripts only
   209  		{1, 6, map[string][]string{
   210  			".py": []string{"/usr/bin/python"},
   211  		}},
   212  		// AppleScripts
   213  		{3, 4, map[string][]string{
   214  			".scpt":        []string{"/usr/bin/osascript"},
   215  			".applescript": []string{"/usr/bin/osascript"},
   216  			".js":          []string{"/usr/bin/osascript", "-l", "JavaScript"},
   217  		}},
   218  	}
   219  
   220  	withTestScripts(func(names []string) {
   221  
   222  		for _, td := range data {
   223  
   224  			r := NewScriptRunner(td.m)
   225  			var good, bad int
   226  
   227  			for _, ts := range testScripts {
   228  
   229  				if v := r.CanRun(ts.name); v {
   230  					good++
   231  				} else {
   232  					bad++
   233  				}
   234  			}
   235  
   236  			if good != td.good {
   237  				t.Errorf("Bad good. Expected=%d, Got=%d", td.good, good)
   238  			}
   239  			if bad != td.bad {
   240  				t.Errorf("Bad bad. Expected=%d, Got=%d", td.bad, bad)
   241  			}
   242  		}
   243  
   244  	})
   245  
   246  }
   247  
   248  // TestQuoteJS verifies QuoteJS quoting.
   249  func TestQuoteJS(t *testing.T) {
   250  
   251  	data := []struct {
   252  		in  interface{}
   253  		out string
   254  	}{
   255  		{"", `""`},
   256  		{"onions", `"onions"`},
   257  		{"", `""`},
   258  		{[]string{"one", "two", "three"}, `["one","two","three"]`},
   259  	}
   260  
   261  	for _, td := range data {
   262  
   263  		s := QuoteJS(td.in)
   264  
   265  		if s != td.out {
   266  			t.Errorf("Bad JS for %#v. Expected=%v, Got=%v", td.in, td.out, s)
   267  		}
   268  
   269  	}
   270  }