github.com/nektos/act@v0.2.63/pkg/exprparser/interpreter_test.go (about) 1 package exprparser 2 3 import ( 4 "math" 5 "testing" 6 7 "github.com/nektos/act/pkg/model" 8 "github.com/stretchr/testify/assert" 9 ) 10 11 func TestLiterals(t *testing.T) { 12 table := []struct { 13 input string 14 expected interface{} 15 name string 16 }{ 17 {"true", true, "true"}, 18 {"false", false, "false"}, 19 {"null", nil, "null"}, 20 {"123", 123, "integer"}, 21 {"-9.7", -9.7, "float"}, 22 {"0xff", 255, "hex"}, 23 {"-2.99e-2", -2.99e-2, "exponential"}, 24 {"'foo'", "foo", "string"}, 25 {"'it''s foo'", "it's foo", "string"}, 26 } 27 28 env := &EvaluationEnvironment{} 29 30 for _, tt := range table { 31 t.Run(tt.name, func(t *testing.T) { 32 output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) 33 assert.Nil(t, err) 34 35 assert.Equal(t, tt.expected, output) 36 }) 37 } 38 } 39 40 func TestOperators(t *testing.T) { 41 table := []struct { 42 input string 43 expected interface{} 44 name string 45 error string 46 }{ 47 {"(false || (false || true))", true, "logical-grouping", ""}, 48 {"github.action", "push", "property-dereference", ""}, 49 {"github['action']", "push", "property-index", ""}, 50 {"github.action[0]", nil, "string-index", ""}, 51 {"github.action['0']", nil, "string-index", ""}, 52 {"fromJSON('[0,1]')[1]", 1.0, "array-index", ""}, 53 {"fromJSON('[0,1]')[1.1]", nil, "array-index", ""}, 54 // Disabled weird things are happening 55 // {"fromJSON('[0,1]')['1.1']", nil, "array-index", ""}, 56 {"(github.event.commits.*.author.username)[0]", "someone", "array-index-0", ""}, 57 {"fromJSON('[0,1]')[2]", nil, "array-index-out-of-bounds-0", ""}, 58 {"fromJSON('[0,1]')[34553]", nil, "array-index-out-of-bounds-1", ""}, 59 {"fromJSON('[0,1]')[-1]", nil, "array-index-out-of-bounds-2", ""}, 60 {"fromJSON('[0,1]')[-34553]", nil, "array-index-out-of-bounds-3", ""}, 61 {"!true", false, "not", ""}, 62 {"1 < 2", true, "less-than", ""}, 63 {`'b' <= 'a'`, false, "less-than-or-equal", ""}, 64 {"1 > 2", false, "greater-than", ""}, 65 {`'b' >= 'a'`, true, "greater-than-or-equal", ""}, 66 {`'a' == 'a'`, true, "equal", ""}, 67 {`'a' != 'a'`, false, "not-equal", ""}, 68 {`true && false`, false, "and", ""}, 69 {`true || false`, true, "or", ""}, 70 {`fromJSON('{}') && true`, true, "and-boolean-object", ""}, 71 {`fromJSON('{}') || false`, make(map[string]interface{}), "or-boolean-object", ""}, 72 {"github.event.commits[0].author.username != github.event.commits[1].author.username", true, "property-comparison1", ""}, 73 {"github.event.commits[0].author.username1 != github.event.commits[1].author.username", true, "property-comparison2", ""}, 74 {"github.event.commits[0].author.username != github.event.commits[1].author.username1", true, "property-comparison3", ""}, 75 {"github.event.commits[0].author.username1 != github.event.commits[1].author.username2", true, "property-comparison4", ""}, 76 {"secrets != env", nil, "property-comparison5", "Compare not implemented for types: left: map, right: map"}, 77 } 78 79 env := &EvaluationEnvironment{ 80 Github: &model.GithubContext{ 81 Action: "push", 82 Event: map[string]interface{}{ 83 "commits": []interface{}{ 84 map[string]interface{}{ 85 "author": map[string]interface{}{ 86 "username": "someone", 87 }, 88 }, 89 map[string]interface{}{ 90 "author": map[string]interface{}{ 91 "username": "someone-else", 92 }, 93 }, 94 }, 95 }, 96 }, 97 } 98 99 for _, tt := range table { 100 t.Run(tt.name, func(t *testing.T) { 101 output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) 102 if tt.error != "" { 103 assert.NotNil(t, err) 104 assert.Equal(t, tt.error, err.Error()) 105 } else { 106 assert.Nil(t, err) 107 } 108 109 assert.Equal(t, tt.expected, output) 110 }) 111 } 112 } 113 114 func TestOperatorsCompare(t *testing.T) { 115 table := []struct { 116 input string 117 expected interface{} 118 name string 119 }{ 120 {"!null", true, "not-null"}, 121 {"!-10", false, "not-neg-num"}, 122 {"!0", true, "not-zero"}, 123 {"!3.14", false, "not-pos-float"}, 124 {"!''", true, "not-empty-str"}, 125 {"!'abc'", false, "not-str"}, 126 {"!fromJSON('{}')", false, "not-obj"}, 127 {"!fromJSON('[]')", false, "not-arr"}, 128 {`null == 0 }}`, true, "null-coercion"}, 129 {`true == 1 }}`, true, "boolean-coercion"}, 130 {`'' == 0 }}`, true, "string-0-coercion"}, 131 {`'3' == 3 }}`, true, "string-3-coercion"}, 132 {`0 == null }}`, true, "null-coercion-alt"}, 133 {`1 == true }}`, true, "boolean-coercion-alt"}, 134 {`0 == '' }}`, true, "string-0-coercion-alt"}, 135 {`3 == '3' }}`, true, "string-3-coercion-alt"}, 136 {`'TEST' == 'test' }}`, true, "string-casing"}, 137 {"true > false }}", true, "bool-greater-than"}, 138 {"true >= false }}", true, "bool-greater-than-eq"}, 139 {"true >= true }}", true, "bool-greater-than-1"}, 140 {"true != false }}", true, "bool-not-equal"}, 141 {`fromJSON('{}') < 2 }}`, false, "object-with-less"}, 142 {`fromJSON('{}') < fromJSON('[]') }}`, false, "object/arr-with-lt"}, 143 {`fromJSON('{}') > fromJSON('[]') }}`, false, "object/arr-with-gt"}, 144 } 145 146 env := &EvaluationEnvironment{ 147 Github: &model.GithubContext{ 148 Action: "push", 149 }, 150 } 151 152 for _, tt := range table { 153 t.Run(tt.name, func(t *testing.T) { 154 output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) 155 assert.Nil(t, err) 156 157 assert.Equal(t, tt.expected, output) 158 }) 159 } 160 } 161 162 func TestOperatorsBooleanEvaluation(t *testing.T) { 163 table := []struct { 164 input string 165 expected interface{} 166 name string 167 }{ 168 // true && 169 {"true && true", true, "true-and"}, 170 {"true && false", false, "true-and"}, 171 {"true && null", nil, "true-and"}, 172 {"true && -10", -10, "true-and"}, 173 {"true && 0", 0, "true-and"}, 174 {"true && 10", 10, "true-and"}, 175 {"true && 3.14", 3.14, "true-and"}, 176 {"true && 0.0", 0, "true-and"}, 177 {"true && Infinity", math.Inf(1), "true-and"}, 178 // {"true && -Infinity", math.Inf(-1), "true-and"}, 179 {"true && NaN", math.NaN(), "true-and"}, 180 {"true && ''", "", "true-and"}, 181 {"true && 'abc'", "abc", "true-and"}, 182 // false && 183 {"false && true", false, "false-and"}, 184 {"false && false", false, "false-and"}, 185 {"false && null", false, "false-and"}, 186 {"false && -10", false, "false-and"}, 187 {"false && 0", false, "false-and"}, 188 {"false && 10", false, "false-and"}, 189 {"false && 3.14", false, "false-and"}, 190 {"false && 0.0", false, "false-and"}, 191 {"false && Infinity", false, "false-and"}, 192 // {"false && -Infinity", false, "false-and"}, 193 {"false && NaN", false, "false-and"}, 194 {"false && ''", false, "false-and"}, 195 {"false && 'abc'", false, "false-and"}, 196 // true || 197 {"true || true", true, "true-or"}, 198 {"true || false", true, "true-or"}, 199 {"true || null", true, "true-or"}, 200 {"true || -10", true, "true-or"}, 201 {"true || 0", true, "true-or"}, 202 {"true || 10", true, "true-or"}, 203 {"true || 3.14", true, "true-or"}, 204 {"true || 0.0", true, "true-or"}, 205 {"true || Infinity", true, "true-or"}, 206 // {"true || -Infinity", true, "true-or"}, 207 {"true || NaN", true, "true-or"}, 208 {"true || ''", true, "true-or"}, 209 {"true || 'abc'", true, "true-or"}, 210 // false || 211 {"false || true", true, "false-or"}, 212 {"false || false", false, "false-or"}, 213 {"false || null", nil, "false-or"}, 214 {"false || -10", -10, "false-or"}, 215 {"false || 0", 0, "false-or"}, 216 {"false || 10", 10, "false-or"}, 217 {"false || 3.14", 3.14, "false-or"}, 218 {"false || 0.0", 0, "false-or"}, 219 {"false || Infinity", math.Inf(1), "false-or"}, 220 // {"false || -Infinity", math.Inf(-1), "false-or"}, 221 {"false || NaN", math.NaN(), "false-or"}, 222 {"false || ''", "", "false-or"}, 223 {"false || 'abc'", "abc", "false-or"}, 224 // null && 225 {"null && true", nil, "null-and"}, 226 {"null && false", nil, "null-and"}, 227 {"null && null", nil, "null-and"}, 228 {"null && -10", nil, "null-and"}, 229 {"null && 0", nil, "null-and"}, 230 {"null && 10", nil, "null-and"}, 231 {"null && 3.14", nil, "null-and"}, 232 {"null && 0.0", nil, "null-and"}, 233 {"null && Infinity", nil, "null-and"}, 234 // {"null && -Infinity", nil, "null-and"}, 235 {"null && NaN", nil, "null-and"}, 236 {"null && ''", nil, "null-and"}, 237 {"null && 'abc'", nil, "null-and"}, 238 // null || 239 {"null || true", true, "null-or"}, 240 {"null || false", false, "null-or"}, 241 {"null || null", nil, "null-or"}, 242 {"null || -10", -10, "null-or"}, 243 {"null || 0", 0, "null-or"}, 244 {"null || 10", 10, "null-or"}, 245 {"null || 3.14", 3.14, "null-or"}, 246 {"null || 0.0", 0, "null-or"}, 247 {"null || Infinity", math.Inf(1), "null-or"}, 248 // {"null || -Infinity", math.Inf(-1), "null-or"}, 249 {"null || NaN", math.NaN(), "null-or"}, 250 {"null || ''", "", "null-or"}, 251 {"null || 'abc'", "abc", "null-or"}, 252 // -10 && 253 {"-10 && true", true, "neg-num-and"}, 254 {"-10 && false", false, "neg-num-and"}, 255 {"-10 && null", nil, "neg-num-and"}, 256 {"-10 && -10", -10, "neg-num-and"}, 257 {"-10 && 0", 0, "neg-num-and"}, 258 {"-10 && 10", 10, "neg-num-and"}, 259 {"-10 && 3.14", 3.14, "neg-num-and"}, 260 {"-10 && 0.0", 0, "neg-num-and"}, 261 {"-10 && Infinity", math.Inf(1), "neg-num-and"}, 262 // {"-10 && -Infinity", math.Inf(-1), "neg-num-and"}, 263 {"-10 && NaN", math.NaN(), "neg-num-and"}, 264 {"-10 && ''", "", "neg-num-and"}, 265 {"-10 && 'abc'", "abc", "neg-num-and"}, 266 // -10 || 267 {"-10 || true", -10, "neg-num-or"}, 268 {"-10 || false", -10, "neg-num-or"}, 269 {"-10 || null", -10, "neg-num-or"}, 270 {"-10 || -10", -10, "neg-num-or"}, 271 {"-10 || 0", -10, "neg-num-or"}, 272 {"-10 || 10", -10, "neg-num-or"}, 273 {"-10 || 3.14", -10, "neg-num-or"}, 274 {"-10 || 0.0", -10, "neg-num-or"}, 275 {"-10 || Infinity", -10, "neg-num-or"}, 276 // {"-10 || -Infinity", -10, "neg-num-or"}, 277 {"-10 || NaN", -10, "neg-num-or"}, 278 {"-10 || ''", -10, "neg-num-or"}, 279 {"-10 || 'abc'", -10, "neg-num-or"}, 280 // 0 && 281 {"0 && true", 0, "zero-and"}, 282 {"0 && false", 0, "zero-and"}, 283 {"0 && null", 0, "zero-and"}, 284 {"0 && -10", 0, "zero-and"}, 285 {"0 && 0", 0, "zero-and"}, 286 {"0 && 10", 0, "zero-and"}, 287 {"0 && 3.14", 0, "zero-and"}, 288 {"0 && 0.0", 0, "zero-and"}, 289 {"0 && Infinity", 0, "zero-and"}, 290 // {"0 && -Infinity", 0, "zero-and"}, 291 {"0 && NaN", 0, "zero-and"}, 292 {"0 && ''", 0, "zero-and"}, 293 {"0 && 'abc'", 0, "zero-and"}, 294 // 0 || 295 {"0 || true", true, "zero-or"}, 296 {"0 || false", false, "zero-or"}, 297 {"0 || null", nil, "zero-or"}, 298 {"0 || -10", -10, "zero-or"}, 299 {"0 || 0", 0, "zero-or"}, 300 {"0 || 10", 10, "zero-or"}, 301 {"0 || 3.14", 3.14, "zero-or"}, 302 {"0 || 0.0", 0, "zero-or"}, 303 {"0 || Infinity", math.Inf(1), "zero-or"}, 304 // {"0 || -Infinity", math.Inf(-1), "zero-or"}, 305 {"0 || NaN", math.NaN(), "zero-or"}, 306 {"0 || ''", "", "zero-or"}, 307 {"0 || 'abc'", "abc", "zero-or"}, 308 // 10 && 309 {"10 && true", true, "pos-num-and"}, 310 {"10 && false", false, "pos-num-and"}, 311 {"10 && null", nil, "pos-num-and"}, 312 {"10 && -10", -10, "pos-num-and"}, 313 {"10 && 0", 0, "pos-num-and"}, 314 {"10 && 10", 10, "pos-num-and"}, 315 {"10 && 3.14", 3.14, "pos-num-and"}, 316 {"10 && 0.0", 0, "pos-num-and"}, 317 {"10 && Infinity", math.Inf(1), "pos-num-and"}, 318 // {"10 && -Infinity", math.Inf(-1), "pos-num-and"}, 319 {"10 && NaN", math.NaN(), "pos-num-and"}, 320 {"10 && ''", "", "pos-num-and"}, 321 {"10 && 'abc'", "abc", "pos-num-and"}, 322 // 10 || 323 {"10 || true", 10, "pos-num-or"}, 324 {"10 || false", 10, "pos-num-or"}, 325 {"10 || null", 10, "pos-num-or"}, 326 {"10 || -10", 10, "pos-num-or"}, 327 {"10 || 0", 10, "pos-num-or"}, 328 {"10 || 10", 10, "pos-num-or"}, 329 {"10 || 3.14", 10, "pos-num-or"}, 330 {"10 || 0.0", 10, "pos-num-or"}, 331 {"10 || Infinity", 10, "pos-num-or"}, 332 // {"10 || -Infinity", 10, "pos-num-or"}, 333 {"10 || NaN", 10, "pos-num-or"}, 334 {"10 || ''", 10, "pos-num-or"}, 335 {"10 || 'abc'", 10, "pos-num-or"}, 336 // 3.14 && 337 {"3.14 && true", true, "pos-float-and"}, 338 {"3.14 && false", false, "pos-float-and"}, 339 {"3.14 && null", nil, "pos-float-and"}, 340 {"3.14 && -10", -10, "pos-float-and"}, 341 {"3.14 && 0", 0, "pos-float-and"}, 342 {"3.14 && 10", 10, "pos-float-and"}, 343 {"3.14 && 3.14", 3.14, "pos-float-and"}, 344 {"3.14 && 0.0", 0, "pos-float-and"}, 345 {"3.14 && Infinity", math.Inf(1), "pos-float-and"}, 346 // {"3.14 && -Infinity", math.Inf(-1), "pos-float-and"}, 347 {"3.14 && NaN", math.NaN(), "pos-float-and"}, 348 {"3.14 && ''", "", "pos-float-and"}, 349 {"3.14 && 'abc'", "abc", "pos-float-and"}, 350 // 3.14 || 351 {"3.14 || true", 3.14, "pos-float-or"}, 352 {"3.14 || false", 3.14, "pos-float-or"}, 353 {"3.14 || null", 3.14, "pos-float-or"}, 354 {"3.14 || -10", 3.14, "pos-float-or"}, 355 {"3.14 || 0", 3.14, "pos-float-or"}, 356 {"3.14 || 10", 3.14, "pos-float-or"}, 357 {"3.14 || 3.14", 3.14, "pos-float-or"}, 358 {"3.14 || 0.0", 3.14, "pos-float-or"}, 359 {"3.14 || Infinity", 3.14, "pos-float-or"}, 360 // {"3.14 || -Infinity", 3.14, "pos-float-or"}, 361 {"3.14 || NaN", 3.14, "pos-float-or"}, 362 {"3.14 || ''", 3.14, "pos-float-or"}, 363 {"3.14 || 'abc'", 3.14, "pos-float-or"}, 364 // Infinity && 365 {"Infinity && true", true, "pos-inf-and"}, 366 {"Infinity && false", false, "pos-inf-and"}, 367 {"Infinity && null", nil, "pos-inf-and"}, 368 {"Infinity && -10", -10, "pos-inf-and"}, 369 {"Infinity && 0", 0, "pos-inf-and"}, 370 {"Infinity && 10", 10, "pos-inf-and"}, 371 {"Infinity && 3.14", 3.14, "pos-inf-and"}, 372 {"Infinity && 0.0", 0, "pos-inf-and"}, 373 {"Infinity && Infinity", math.Inf(1), "pos-inf-and"}, 374 // {"Infinity && -Infinity", math.Inf(-1), "pos-inf-and"}, 375 {"Infinity && NaN", math.NaN(), "pos-inf-and"}, 376 {"Infinity && ''", "", "pos-inf-and"}, 377 {"Infinity && 'abc'", "abc", "pos-inf-and"}, 378 // Infinity || 379 {"Infinity || true", math.Inf(1), "pos-inf-or"}, 380 {"Infinity || false", math.Inf(1), "pos-inf-or"}, 381 {"Infinity || null", math.Inf(1), "pos-inf-or"}, 382 {"Infinity || -10", math.Inf(1), "pos-inf-or"}, 383 {"Infinity || 0", math.Inf(1), "pos-inf-or"}, 384 {"Infinity || 10", math.Inf(1), "pos-inf-or"}, 385 {"Infinity || 3.14", math.Inf(1), "pos-inf-or"}, 386 {"Infinity || 0.0", math.Inf(1), "pos-inf-or"}, 387 {"Infinity || Infinity", math.Inf(1), "pos-inf-or"}, 388 // {"Infinity || -Infinity", math.Inf(1), "pos-inf-or"}, 389 {"Infinity || NaN", math.Inf(1), "pos-inf-or"}, 390 {"Infinity || ''", math.Inf(1), "pos-inf-or"}, 391 {"Infinity || 'abc'", math.Inf(1), "pos-inf-or"}, 392 // -Infinity && 393 // {"-Infinity && true", true, "neg-inf-and"}, 394 // {"-Infinity && false", false, "neg-inf-and"}, 395 // {"-Infinity && null", nil, "neg-inf-and"}, 396 // {"-Infinity && -10", -10, "neg-inf-and"}, 397 // {"-Infinity && 0", 0, "neg-inf-and"}, 398 // {"-Infinity && 10", 10, "neg-inf-and"}, 399 // {"-Infinity && 3.14", 3.14, "neg-inf-and"}, 400 // {"-Infinity && 0.0", 0, "neg-inf-and"}, 401 // {"-Infinity && Infinity", math.Inf(1), "neg-inf-and"}, 402 // {"-Infinity && -Infinity", math.Inf(-1), "neg-inf-and"}, 403 // {"-Infinity && NaN", math.NaN(), "neg-inf-and"}, 404 // {"-Infinity && ''", "", "neg-inf-and"}, 405 // {"-Infinity && 'abc'", "abc", "neg-inf-and"}, 406 // -Infinity || 407 // {"-Infinity || true", math.Inf(-1), "neg-inf-or"}, 408 // {"-Infinity || false", math.Inf(-1), "neg-inf-or"}, 409 // {"-Infinity || null", math.Inf(-1), "neg-inf-or"}, 410 // {"-Infinity || -10", math.Inf(-1), "neg-inf-or"}, 411 // {"-Infinity || 0", math.Inf(-1), "neg-inf-or"}, 412 // {"-Infinity || 10", math.Inf(-1), "neg-inf-or"}, 413 // {"-Infinity || 3.14", math.Inf(-1), "neg-inf-or"}, 414 // {"-Infinity || 0.0", math.Inf(-1), "neg-inf-or"}, 415 // {"-Infinity || Infinity", math.Inf(-1), "neg-inf-or"}, 416 // {"-Infinity || -Infinity", math.Inf(-1), "neg-inf-or"}, 417 // {"-Infinity || NaN", math.Inf(-1), "neg-inf-or"}, 418 // {"-Infinity || ''", math.Inf(-1), "neg-inf-or"}, 419 // {"-Infinity || 'abc'", math.Inf(-1), "neg-inf-or"}, 420 // NaN && 421 {"NaN && true", math.NaN(), "nan-and"}, 422 {"NaN && false", math.NaN(), "nan-and"}, 423 {"NaN && null", math.NaN(), "nan-and"}, 424 {"NaN && -10", math.NaN(), "nan-and"}, 425 {"NaN && 0", math.NaN(), "nan-and"}, 426 {"NaN && 10", math.NaN(), "nan-and"}, 427 {"NaN && 3.14", math.NaN(), "nan-and"}, 428 {"NaN && 0.0", math.NaN(), "nan-and"}, 429 {"NaN && Infinity", math.NaN(), "nan-and"}, 430 // {"NaN && -Infinity", math.NaN(), "nan-and"}, 431 {"NaN && NaN", math.NaN(), "nan-and"}, 432 {"NaN && ''", math.NaN(), "nan-and"}, 433 {"NaN && 'abc'", math.NaN(), "nan-and"}, 434 // NaN || 435 {"NaN || true", true, "nan-or"}, 436 {"NaN || false", false, "nan-or"}, 437 {"NaN || null", nil, "nan-or"}, 438 {"NaN || -10", -10, "nan-or"}, 439 {"NaN || 0", 0, "nan-or"}, 440 {"NaN || 10", 10, "nan-or"}, 441 {"NaN || 3.14", 3.14, "nan-or"}, 442 {"NaN || 0.0", 0, "nan-or"}, 443 {"NaN || Infinity", math.Inf(1), "nan-or"}, 444 // {"NaN || -Infinity", math.Inf(-1), "nan-or"}, 445 {"NaN || NaN", math.NaN(), "nan-or"}, 446 {"NaN || ''", "", "nan-or"}, 447 {"NaN || 'abc'", "abc", "nan-or"}, 448 // "" && 449 {"'' && true", "", "empty-str-and"}, 450 {"'' && false", "", "empty-str-and"}, 451 {"'' && null", "", "empty-str-and"}, 452 {"'' && -10", "", "empty-str-and"}, 453 {"'' && 0", "", "empty-str-and"}, 454 {"'' && 10", "", "empty-str-and"}, 455 {"'' && 3.14", "", "empty-str-and"}, 456 {"'' && 0.0", "", "empty-str-and"}, 457 {"'' && Infinity", "", "empty-str-and"}, 458 // {"'' && -Infinity", "", "empty-str-and"}, 459 {"'' && NaN", "", "empty-str-and"}, 460 {"'' && ''", "", "empty-str-and"}, 461 {"'' && 'abc'", "", "empty-str-and"}, 462 // "" || 463 {"'' || true", true, "empty-str-or"}, 464 {"'' || false", false, "empty-str-or"}, 465 {"'' || null", nil, "empty-str-or"}, 466 {"'' || -10", -10, "empty-str-or"}, 467 {"'' || 0", 0, "empty-str-or"}, 468 {"'' || 10", 10, "empty-str-or"}, 469 {"'' || 3.14", 3.14, "empty-str-or"}, 470 {"'' || 0.0", 0, "empty-str-or"}, 471 {"'' || Infinity", math.Inf(1), "empty-str-or"}, 472 // {"'' || -Infinity", math.Inf(-1), "empty-str-or"}, 473 {"'' || NaN", math.NaN(), "empty-str-or"}, 474 {"'' || ''", "", "empty-str-or"}, 475 {"'' || 'abc'", "abc", "empty-str-or"}, 476 // "abc" && 477 {"'abc' && true", true, "str-and"}, 478 {"'abc' && false", false, "str-and"}, 479 {"'abc' && null", nil, "str-and"}, 480 {"'abc' && -10", -10, "str-and"}, 481 {"'abc' && 0", 0, "str-and"}, 482 {"'abc' && 10", 10, "str-and"}, 483 {"'abc' && 3.14", 3.14, "str-and"}, 484 {"'abc' && 0.0", 0, "str-and"}, 485 {"'abc' && Infinity", math.Inf(1), "str-and"}, 486 // {"'abc' && -Infinity", math.Inf(-1), "str-and"}, 487 {"'abc' && NaN", math.NaN(), "str-and"}, 488 {"'abc' && ''", "", "str-and"}, 489 {"'abc' && 'abc'", "abc", "str-and"}, 490 // "abc" || 491 {"'abc' || true", "abc", "str-or"}, 492 {"'abc' || false", "abc", "str-or"}, 493 {"'abc' || null", "abc", "str-or"}, 494 {"'abc' || -10", "abc", "str-or"}, 495 {"'abc' || 0", "abc", "str-or"}, 496 {"'abc' || 10", "abc", "str-or"}, 497 {"'abc' || 3.14", "abc", "str-or"}, 498 {"'abc' || 0.0", "abc", "str-or"}, 499 {"'abc' || Infinity", "abc", "str-or"}, 500 // {"'abc' || -Infinity", "abc", "str-or"}, 501 {"'abc' || NaN", "abc", "str-or"}, 502 {"'abc' || ''", "abc", "str-or"}, 503 {"'abc' || 'abc'", "abc", "str-or"}, 504 // extra tests 505 {"0.0 && true", 0, "float-evaluation-0-alt"}, 506 {"-1.5 && true", true, "float-evaluation-neg-alt"}, 507 } 508 509 env := &EvaluationEnvironment{ 510 Github: &model.GithubContext{ 511 Action: "push", 512 }, 513 } 514 515 for _, tt := range table { 516 t.Run(tt.name, func(t *testing.T) { 517 output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) 518 assert.Nil(t, err) 519 520 if expected, ok := tt.expected.(float64); ok && math.IsNaN(expected) { 521 assert.True(t, math.IsNaN(output.(float64))) 522 } else { 523 assert.Equal(t, tt.expected, output) 524 } 525 }) 526 } 527 } 528 529 func TestContexts(t *testing.T) { 530 table := []struct { 531 input string 532 expected interface{} 533 name string 534 }{ 535 {"github.action", "push", "github-context"}, 536 {"github.event.commits[0].message", nil, "github-context-noexist-prop"}, 537 {"fromjson('{\"commits\":[]}').commits[0].message", nil, "github-context-noexist-prop"}, 538 {"github.event.pull_request.labels.*.name", nil, "github-context-noexist-prop"}, 539 {"env.TEST", "value", "env-context"}, 540 {"job.status", "success", "job-context"}, 541 {"steps.step-id.outputs.name", "value", "steps-context"}, 542 {"steps.step-id.conclusion", "success", "steps-context-conclusion"}, 543 {"steps.step-id.conclusion && true", true, "steps-context-conclusion"}, 544 {"steps.step-id2.conclusion", "skipped", "steps-context-conclusion"}, 545 {"steps.step-id2.conclusion && true", true, "steps-context-conclusion"}, 546 {"steps.step-id.outcome", "success", "steps-context-outcome"}, 547 {"steps.step-id['outcome']", "success", "steps-context-outcome"}, 548 {"steps.step-id.outcome == 'success'", true, "steps-context-outcome"}, 549 {"steps.step-id['outcome'] == 'success'", true, "steps-context-outcome"}, 550 {"steps.step-id.outcome && true", true, "steps-context-outcome"}, 551 {"steps['step-id']['outcome'] && true", true, "steps-context-outcome"}, 552 {"steps.step-id2.outcome", "failure", "steps-context-outcome"}, 553 {"steps.step-id2.outcome && true", true, "steps-context-outcome"}, 554 // Disabled, since the interpreter is still too broken 555 // {"contains(steps.*.outcome, 'success')", true, "steps-context-array-outcome"}, 556 // {"contains(steps.*.outcome, 'failure')", true, "steps-context-array-outcome"}, 557 // {"contains(steps.*.outputs.name, 'value')", true, "steps-context-array-outputs"}, 558 {"runner.os", "Linux", "runner-context"}, 559 {"secrets.name", "value", "secrets-context"}, 560 {"vars.name", "value", "vars-context"}, 561 {"strategy.fail-fast", true, "strategy-context"}, 562 {"matrix.os", "Linux", "matrix-context"}, 563 {"needs.job-id.outputs.output-name", "value", "needs-context"}, 564 {"needs.job-id.result", "success", "needs-context"}, 565 {"inputs.name", "value", "inputs-context"}, 566 } 567 568 env := &EvaluationEnvironment{ 569 Github: &model.GithubContext{ 570 Action: "push", 571 }, 572 Env: map[string]string{ 573 "TEST": "value", 574 }, 575 Job: &model.JobContext{ 576 Status: "success", 577 }, 578 Steps: map[string]*model.StepResult{ 579 "step-id": { 580 Outputs: map[string]string{ 581 "name": "value", 582 }, 583 }, 584 "step-id2": { 585 Outcome: model.StepStatusFailure, 586 Conclusion: model.StepStatusSkipped, 587 }, 588 }, 589 Runner: map[string]interface{}{ 590 "os": "Linux", 591 "temp": "/tmp", 592 "tool_cache": "/opt/hostedtoolcache", 593 }, 594 Secrets: map[string]string{ 595 "name": "value", 596 }, 597 Vars: map[string]string{ 598 "name": "value", 599 }, 600 Strategy: map[string]interface{}{ 601 "fail-fast": true, 602 }, 603 Matrix: map[string]interface{}{ 604 "os": "Linux", 605 }, 606 Needs: map[string]Needs{ 607 "job-id": { 608 Outputs: map[string]string{ 609 "output-name": "value", 610 }, 611 Result: "success", 612 }, 613 }, 614 Inputs: map[string]interface{}{ 615 "name": "value", 616 }, 617 } 618 619 for _, tt := range table { 620 t.Run(tt.name, func(t *testing.T) { 621 output, err := NewInterpeter(env, Config{}).Evaluate(tt.input, DefaultStatusCheckNone) 622 assert.Nil(t, err) 623 624 assert.Equal(t, tt.expected, output) 625 }) 626 } 627 }