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 }