github.com/ChicK00o/awgo@v0.29.4/workflow_test.go (about) 1 // Copyright (c) 2018 Dean Jackson <deanishe@deanishe.net> 2 // MIT Licence - http://opensource.org/licenses/MIT 3 4 package aw 5 6 import ( 7 "encoding/json" 8 "errors" 9 "fmt" 10 11 "log" 12 "os" 13 "strings" 14 "testing" 15 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 "go.deanishe.net/env" 19 20 "github.com/ChicK00o/awgo/util" 21 ) 22 23 // TestWorkflowValues tests workflow name, bundle ID etc. 24 func TestWorkflowValues(t *testing.T) { 25 t.Parallel() 26 27 withTestWf(func(wf *Workflow) { 28 assert.Equal(t, tName, wf.Name(), "unexpected name") 29 assert.Equal(t, tBundleID, wf.BundleID(), "unexpected bundle ID") 30 }) 31 } 32 33 // TestInvalidEnv executes workflow in an invalid environment. 34 func TestInvalidEnv(t *testing.T) { 35 assert.Panics(t, func() { NewFromEnv(env.MapEnv{}) }) 36 } 37 38 // Options correctly alter Workflow. 39 func TestNew(t *testing.T) { 40 t.Parallel() 41 42 tests := []struct { 43 opt Option // option to set 44 test func(wf *Workflow) bool // function to verify change was made 45 desc string // test title 46 }{ 47 { 48 HelpURL("http://www.example.com"), 49 func(wf *Workflow) bool { return wf.helpURL == "http://www.example.com" }, 50 "Set HelpURL"}, 51 { 52 MaxResults(10), 53 func(wf *Workflow) bool { return wf.maxResults == 10 }, 54 "Set MaxResults"}, 55 { 56 LogPrefix("blah"), 57 func(wf *Workflow) bool { return wf.logPrefix == "blah" }, 58 "Set LogPrefix"}, 59 { 60 SessionName("SESH"), 61 func(wf *Workflow) bool { return wf.sessionName == "SESH" }, 62 "Set SessionName"}, 63 { 64 SortOptions(), 65 func(wf *Workflow) bool { return wf.sortOptions == nil }, 66 "Set SortOptions"}, 67 { 68 SuppressUIDs(true), 69 func(wf *Workflow) bool { return wf.Feedback.NoUIDs == true }, 70 "Set SuppressUIDs"}, 71 { 72 MagicPrefix("aw:"), 73 func(wf *Workflow) bool { return wf.magicPrefix == "aw:" }, 74 "Set MagicPrefix"}, 75 { 76 MaxLogSize(2048), 77 func(wf *Workflow) bool { return wf.maxLogSize == 2048 }, 78 "Set MaxLogSize"}, 79 { 80 TextErrors(true), 81 func(wf *Workflow) bool { return wf.textErrors == true }, 82 "Set TextErrors"}, 83 { 84 AddMagic(&mockMA{}), 85 func(wf *Workflow) bool { return wf.magicActions.actions["test"] != nil }, 86 "Add Magic"}, 87 { 88 RemoveMagic(logMA{}), 89 func(wf *Workflow) bool { return wf.magicActions.actions["log"] == nil }, 90 "Remove Magic"}, 91 } 92 93 for _, td := range tests { 94 td := td // capture variable 95 t.Run(fmt.Sprintf("Option(%#v)", td.opt), func(t *testing.T) { 96 t.Parallel() 97 wf := New(td.opt) 98 assert.True(t, td.test(wf), "option failed") 99 }) 100 } 101 } 102 103 func TestWorkflow_Run(t *testing.T) { 104 withTestWf(func(wf *Workflow) { 105 var called bool 106 107 run := func() { called = true } 108 wf.Run(run) 109 110 assert.True(t, called, "run wasn't called") 111 }) 112 } 113 114 func TestWorkflow_Run_Rescue(t *testing.T) { 115 withTestWf(func(wf *Workflow) { 116 me := &mockExit{} 117 exitFunc = me.Exit 118 defer func() { exitFunc = os.Exit }() 119 wf.Run(func() { panic("aaaargh!") }) 120 assert.Equal(t, 1, me.code, "workflow did not catch panic") 121 }) 122 } 123 124 // TestWorkflowDir verifies that AwGo finds the right directory. 125 func TestWorkflow_Dir(t *testing.T) { 126 t.Parallel() 127 128 var ( 129 cwd string 130 err error 131 ) 132 133 cwd, err = os.Getwd() 134 require.Nil(t, err, "Getwd failed") 135 136 tests := []struct { 137 in, x string 138 }{ 139 {"testdata", "testdata"}, 140 {"testdata/subdir", "testdata"}, 141 {".", "."}, 142 {"", ""}, 143 } 144 145 for _, td := range tests { 146 td := td 147 t.Run(fmt.Sprintf("findWorkflowRoot(%q)", td.in), func(t *testing.T) { 148 t.Parallel() 149 assert.Equal(t, td.x, findWorkflowRoot(td.in), "unexpected root") 150 }) 151 } 152 153 wf := New() 154 assert.Equal(t, cwd, wf.Dir(), "unexpected workflow dir") 155 } 156 157 // Check that AW's directories exist 158 func TestWorkflow_awDirs(t *testing.T) { 159 t.Parallel() 160 161 withTestWf(func(wf *Workflow) { 162 p := wf.awCacheDir() 163 assert.True(t, util.PathExists(p), "AW cache dir does not exist") 164 assert.True(t, strings.HasSuffix(p, "_aw"), "AW cache is not called '_aw'") 165 166 p = wf.awDataDir() 167 assert.True(t, util.PathExists(p), "AW data dir does not exist") 168 assert.True(t, strings.HasSuffix(p, "_aw"), "AW data is not called '_aw'") 169 }) 170 } 171 172 // Check log is rotated 173 func TestWorkflow_logRotate(t *testing.T) { 174 logInitialized = false // ensure log is created 175 withTestWf(func(wf *Workflow) { 176 wf.Configure(MaxLogSize(10)) 177 log.Print("more than 10 bytes") 178 179 assert.True(t, util.PathExists(wf.LogFile()), "log file does not exist") 180 181 logInitialized = false // ensure log is created 182 wf.initializeLogging() 183 assert.True(t, util.PathExists(wf.LogFile()+".1"), "log file not rotated") 184 }) 185 } 186 187 // Variables are correctly set 188 func TestWorkflow_Vars(t *testing.T) { 189 t.Parallel() 190 191 vars := map[string]string{ 192 "key1": "val1", 193 "key2": "val2", 194 "key3": "val3", 195 "key4": "val4", 196 "key5": "val5", 197 } 198 199 withTestWf(func(wf *Workflow) { 200 for k, v := range vars { 201 wf.Var(k, v) 202 } 203 assert.Equal(t, vars, wf.Vars(), "Unexpected Vars") 204 }) 205 } 206 207 func TestWorkflow_Rerun(t *testing.T) { 208 t.Parallel() 209 210 withTestWf(func(wf *Workflow) { 211 v := 0.1 212 wf.Rerun(v) 213 assert.Equal(t, v, wf.Feedback.rerun, "Unexpected Rerun") 214 }) 215 } 216 217 func TestWorkflow_Fatal(t *testing.T) { 218 var exit bool 219 exitFunc = func(code int) { exit = true } 220 withTestWf(func(wf *Workflow) { 221 wf.Fatal("") 222 assert.True(t, exit, "Fatal did not exit") 223 }) 224 225 exit = false 226 withTestWf(func(wf *Workflow) { 227 wf.FatalError(errors.New("some error")) 228 assert.True(t, exit, "FatalError did not exit") 229 }) 230 231 exit = false 232 withTestWf(func(wf *Workflow) { 233 wf.Fatalf("die") 234 assert.True(t, exit, "Fatalf did not exit") 235 }) 236 } 237 238 func TestRunCommand(t *testing.T) { 239 t.Parallel() 240 241 err := runCommand("/usr/bin/true") 242 assert.Nil(t, err, `call "/usr/bin/true" failed`) 243 err = runCommand("/does/not/exist") 244 assert.NotNil(t, err, `call to "/does/not/exist" returned no error`) 245 } 246 247 // New initialises a Workflow with the default settings. Name, 248 // bundle ID, version etc. are read from the environment variables set by Alfred. 249 func ExampleNew() { 250 wf := New() 251 // Name is read from environment 252 fmt.Println(wf.Name()) 253 // BundleID is read from environment 254 fmt.Println(wf.BundleID()) 255 // Version is from info.plist 256 fmt.Println(wf.Version()) 257 // Output: 258 // AwGo 259 // net.deanishe.awgo 260 // 1.2.0 261 } 262 263 // Pass one or more Options to New() to configure the created Workflow. 264 func ExampleNew_withOptions() { 265 wf := New(HelpURL("http://www.example.com"), MaxResults(200)) 266 fmt.Println(wf.helpURL) 267 fmt.Println(wf.maxResults) 268 // Output: 269 // http://www.example.com 270 // 200 271 } 272 273 // The normal way to create a new Item, but not the normal way to use it. 274 // 275 // Typically, when you're done adding Items, you call SendFeedback() to 276 // send the results to Alfred. 277 func ExampleWorkflow_NewItem() { 278 wf := New() 279 // Create a new item via the Workflow object, which will 280 // track the Item and send it to Alfred when you call 281 // Workflow.SendFeedback() 282 // 283 // Title is the only required value. 284 it := wf.NewItem("First Result"). 285 Subtitle("Some details here") 286 287 // Just to see what it looks like... 288 data, _ := json.Marshal(it) 289 fmt.Println(string(data)) 290 // Output: {"title":"First Result","subtitle":"Some details here","valid":false} 291 } 292 293 // Change Workflow's configuration after creation, then revert it. 294 func ExampleWorkflow_Configure() { 295 wf := New() 296 // Default settings (false and 0) 297 fmt.Println(wf.textErrors) 298 fmt.Println(wf.maxResults) 299 // Turn text errors on, set max results and save Option to revert 300 // to previous configuration 301 previous := wf.Configure(TextErrors(true), MaxResults(200)) 302 fmt.Println(wf.textErrors) 303 fmt.Println(wf.maxResults) 304 // Revert to previous configuration 305 wf.Configure(previous) 306 fmt.Println(wf.textErrors) 307 fmt.Println(wf.maxResults) 308 // Output: 309 // false 310 // 0 311 // true 312 // 200 313 // false 314 // 0 315 } 316 317 func ExampleWorkflow_Warn() { 318 wf := New() 319 // Add some items 320 wf.NewItem("Item One"). 321 Subtitle("Subtitle one") 322 wf.NewItem("Item Two"). 323 Subtitle("Subtitle two") 324 325 // Delete existing items, add a warning, then 326 // immediately send feedback 327 wf.Warn("Bad Items", "Those items are boring") 328 329 // Output: 330 // { 331 // "variables": { 332 // "AW_SESSION_ID": "test-session-id" 333 // }, 334 // "items": [ 335 // { 336 // "title": "Bad Items", 337 // "subtitle": "Those items are boring", 338 // "valid": false, 339 // "icon": { 340 // "path": "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertCautionBadgeIcon.icns" 341 // } 342 // } 343 // ] 344 // } 345 } 346 347 func ExampleArgVars() { 348 // Set workflow variables from Alfred's Run Script Action 349 av := NewArgVars() 350 av.Arg("baz") // Set output (i.e. next action's {query}) to "baz" 351 av.Var("foo", "bar") // Set workflow variable "foo" to "bar" 352 if err := av.Send(); err != nil { 353 panic(err) 354 } 355 // Output: {"alfredworkflow":{"arg":"baz","variables":{"foo":"bar"}}} 356 }