go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/mqlc/mqlc_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package mqlc_test 5 6 import ( 7 "errors" 8 "fmt" 9 "sort" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 "go.mondoo.com/cnquery" 15 "go.mondoo.com/cnquery/llx" 16 "go.mondoo.com/cnquery/logger" 17 "go.mondoo.com/cnquery/mqlc" 18 "go.mondoo.com/cnquery/types" 19 20 "go.mondoo.com/cnquery/providers-sdk/v1/testutils" 21 ) 22 23 var ( 24 features = cnquery.Features{} 25 core_schema = testutils.MustLoadSchema(testutils.SchemaProvider{Provider: "core"}) 26 os_schema = testutils.MustLoadSchema(testutils.SchemaProvider{Provider: "os"}) 27 conf = mqlc.NewConfig( 28 core_schema.Add(os_schema), 29 features, 30 ) 31 ) 32 33 func init() { 34 logger.InitTestEnv() 35 } 36 37 func compileProps(t *testing.T, s string, props map[string]*llx.Primitive, f func(res *llx.CodeBundle)) { 38 res, err := mqlc.Compile(s, props, conf) 39 require.Nil(t, err) 40 require.NotNil(t, res) 41 require.NotNil(t, res.CodeV2) 42 assert.NoError(t, mqlc.Invariants.Check(res)) 43 44 assert.Nil(t, res.Suggestions) 45 require.NotEmpty(t, res.CodeV2.Blocks) 46 f(res) 47 } 48 49 func compileT(t *testing.T, s string, f func(res *llx.CodeBundle)) { 50 compileProps(t, s, nil, f) 51 } 52 53 func compileCtx(t *testing.T, s string, f func(res *llx.CodeBundle)) { 54 nuConf := conf 55 nuConf.UseAssetContext = true 56 res, err := mqlc.Compile(s, nil, nuConf) 57 assert.Nil(t, err) 58 assert.NotNil(t, res) 59 assert.NoError(t, mqlc.Invariants.Check(res)) 60 if res != nil && res.CodeV2 != nil { 61 assert.Nil(t, res.Suggestions) 62 if assert.NotEmpty(t, res.CodeV2.Blocks) { 63 f(res) 64 } 65 } 66 } 67 68 func compileEmpty(t *testing.T, s string, f func(res *llx.CodeBundle)) { 69 res, err := mqlc.Compile(s, nil, conf) 70 require.NoError(t, err) 71 require.NotNil(t, res) 72 require.Nil(t, res.Suggestions) 73 74 f(res) 75 } 76 77 func compileErroneous(t *testing.T, s string, expectedError error, f func(res *llx.CodeBundle)) { 78 res, err := mqlc.Compile(s, nil, conf) 79 80 if err != nil && expectedError != nil { 81 assert.Equal(t, expectedError.Error(), err.Error()) 82 } else { 83 assert.Equal(t, expectedError, err) 84 } 85 86 if f != nil { 87 f(res) 88 } 89 } 90 91 func assertPrimitive(t *testing.T, p *llx.Primitive, chunk *llx.Chunk) { 92 assert.Equal(t, llx.Chunk_PRIMITIVE, chunk.Call) 93 assert.Nil(t, chunk.Function) 94 assert.Equal(t, p, chunk.Primitive) 95 } 96 97 func assertFunction(t *testing.T, id string, f *llx.Function, chunk *llx.Chunk) { 98 assert.Equal(t, llx.Chunk_FUNCTION, chunk.Call) 99 assert.Equal(t, id, chunk.Id, "chunk.Id") 100 assert.Nil(t, chunk.Primitive, "it is not a primitive") 101 assert.Equal(t, f, chunk.Function, "chunk.Function") 102 } 103 104 func assertProperty(t *testing.T, name string, typ types.Type, chunk *llx.Chunk) { 105 assert.Equal(t, llx.Chunk_PROPERTY, chunk.Call) 106 assert.Equal(t, name, chunk.Id, "property name is set") 107 assert.Equal(t, &llx.Primitive{Type: string(typ)}, chunk.Primitive, "property type is set") 108 } 109 110 // =========================== 111 // 👋 VALUES + OPERATIONS 🍹 112 // =========================== 113 114 func TestCompiler_Basics(t *testing.T) { 115 data := []struct { 116 code string 117 }{ 118 {""}, 119 {"// some comment"}, 120 {"// some comment\n"}, 121 } 122 for _, v := range data { 123 t.Run(v.code, func(t *testing.T) { 124 compileEmpty(t, v.code, func(res *llx.CodeBundle) { 125 assert.Empty(t, res.CodeV2.Blocks[0].Chunks) 126 }) 127 }) 128 } 129 } 130 131 func TestCompiler_Buggy(t *testing.T) { 132 data := []struct { 133 code string 134 res []*llx.Chunk 135 err error 136 }{ 137 {`parse parse`, []*llx.Chunk{ 138 {Id: "parse", Call: llx.Chunk_FUNCTION}, 139 {Id: "parse", Call: llx.Chunk_FUNCTION}, 140 }, nil}, 141 {`parse # mondoo`, []*llx.Chunk{ 142 {Id: "parse", Call: llx.Chunk_FUNCTION}, 143 }, nil}, 144 {`parse }`, []*llx.Chunk{ 145 {Id: "parse", Call: llx.Chunk_FUNCTION}, 146 }, errors.New("mismatched symbol '}' at the end of expression")}, 147 {`parse ]`, []*llx.Chunk{ 148 {Id: "parse", Call: llx.Chunk_FUNCTION}, 149 }, errors.New("mismatched symbol ']' at the end of expression")}, 150 {`parse )`, []*llx.Chunk{ 151 {Id: "parse", Call: llx.Chunk_FUNCTION}, 152 }, errors.New("mismatched symbol ')' at the end of expression")}, 153 {`mondoo { version }`, []*llx.Chunk{ 154 {Id: "mondoo", Call: llx.Chunk_FUNCTION}, 155 {Id: "{}", Call: llx.Chunk_FUNCTION, Function: &llx.Function{ 156 Type: string(types.Block), 157 Binding: (1 << 32) | 1, 158 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 159 }}, 160 }, nil}, 161 {"# ..\nmondoo { \n# ..\nversion\n# ..\n}\n# ..", []*llx.Chunk{ 162 {Call: llx.Chunk_FUNCTION, Id: "mondoo"}, 163 {Call: llx.Chunk_FUNCTION, Id: "{}", Function: &llx.Function{ 164 Type: string(types.Block), 165 Binding: (1 << 32) | 1, 166 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 167 }}, 168 }, nil}, 169 {`users.list[]`, nil, errors.New("missing value inside of `[]` at <source>:1:12")}, 170 {`file(not-there)`, nil, errors.New("addResourceCall error: cannot find resource for identifier 'not'")}, 171 {`if(true) {`, []*llx.Chunk{ 172 {Call: llx.Chunk_FUNCTION, Id: "if", Function: &llx.Function{ 173 Type: string(types.Block), 174 Args: []*llx.Primitive{ 175 llx.BoolPrimitive(true), 176 llx.FunctionPrimitive(2 << 32), 177 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 178 }, 179 }}, 180 }, errors.New("incomplete query, missing closing '}' at <source>:1:11")}, 181 {`if(true) { return 1 } else { return 2 } return 3`, []*llx.Chunk{ 182 {Call: llx.Chunk_FUNCTION, Id: "if", Function: &llx.Function{ 183 Type: string(types.Int), 184 Args: []*llx.Primitive{ 185 llx.BoolPrimitive(true), 186 llx.FunctionPrimitive(2 << 32), 187 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 188 llx.FunctionPrimitive(3 << 32), 189 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 190 }, 191 }}, 192 }, errors.New("single valued block followed by expressions")}, 193 {`parse.date`, []*llx.Chunk{ 194 {Id: "parse", Call: llx.Chunk_FUNCTION}, 195 }, errors.New("missing arguments to parse date")}, 196 {`parse.date()`, []*llx.Chunk{ 197 {Id: "parse", Call: llx.Chunk_FUNCTION}, 198 }, errors.New("missing arguments to parse date")}, 199 {`switch(mondoo) { case`, nil, errors.New("missing expression after `case` statement")}, 200 } 201 202 for _, v := range data { 203 t.Run(v.code, func(t *testing.T) { 204 compileErroneous(t, v.code, v.err, func(res *llx.CodeBundle) { 205 if res.CodeV2 != nil { 206 assert.Equal(t, v.res, res.CodeV2.Blocks[0].Chunks) 207 } else { 208 assert.Nil(t, v.res) 209 } 210 }) 211 }) 212 } 213 } 214 215 func TestCompiler_Semicolon(t *testing.T) { 216 compileT(t, "mondoo.version;mondoo.build", func(res *llx.CodeBundle) { 217 require.Len(t, res.CodeV2.Blocks, 1) 218 require.Len(t, res.CodeV2.Blocks[0].Chunks, 4) 219 assertFunction(t, "version", 220 &llx.Function{Binding: (1 << 32) | 1, Type: string(types.String)}, 221 res.CodeV2.Blocks[0].Chunks[1]) 222 assertFunction(t, "build", 223 &llx.Function{Binding: (1 << 32) | 3, Type: string(types.String)}, 224 res.CodeV2.Blocks[0].Chunks[3]) 225 }) 226 227 compileT(t, "mondoo{version;build}", func(res *llx.CodeBundle) { 228 require.Len(t, res.CodeV2.Blocks, 2) 229 require.Len(t, res.CodeV2.Blocks[1].Chunks, 3) 230 assertFunction(t, "version", 231 &llx.Function{Binding: (2 << 32) | 1, Type: string(types.String)}, 232 res.CodeV2.Blocks[1].Chunks[1]) 233 assertFunction(t, "build", 234 &llx.Function{Binding: (2 << 32) | 1, Type: string(types.String)}, 235 res.CodeV2.Blocks[1].Chunks[2]) 236 }) 237 } 238 239 func TestCompiler_DeterministicChecksum(t *testing.T) { 240 // this is a query that in the past used to produce different checksum every now and then 241 // this test ensures that the checksum is always deterministic now 242 mql := `azure.subscription.sql.servers.all(databases.one (transparentDataEncryption["state"] == "Enabled") && encryptionProtector["serverKeyType"] == "AzureKeyVault" )` 243 azure_schema := testutils.MustLoadSchema(testutils.SchemaProvider{Provider: "azure"}) 244 245 for i := 0; i < 10_000; i++ { 246 azureConf := mqlc.NewConfig(azure_schema, features) 247 res, err := mqlc.Compile(mql, map[string]*llx.Primitive{}, azureConf) 248 require.Nil(t, err) 249 require.Equal(t, res.CodeV2.Id, "LkB8PP3xB2Q=") 250 } 251 } 252 253 func TestCompiler_Simple(t *testing.T) { 254 data := []struct { 255 code string 256 res *llx.Primitive 257 }{ 258 {"null", llx.NilPrimitive}, 259 {"false", llx.BoolPrimitive(false)}, 260 {"true", llx.BoolPrimitive(true)}, 261 {"123", llx.IntPrimitive(123)}, 262 {"010", llx.IntPrimitive(8)}, 263 {"12.3", llx.FloatPrimitive(12.3)}, 264 {"\"hi\"", llx.StringPrimitive("hi")}, 265 {"/hi/", llx.RegexPrimitive("hi")}, 266 {"[true, false]", &llx.Primitive{ 267 Type: string(types.Array(types.Bool)), 268 Array: []*llx.Primitive{ 269 llx.BoolPrimitive(true), 270 llx.BoolPrimitive(false), 271 }, 272 }}, 273 {"[1, 2]", &llx.Primitive{ 274 Type: string(types.Array(types.Int)), 275 Array: []*llx.Primitive{ 276 llx.IntPrimitive(1), 277 llx.IntPrimitive(2), 278 }, 279 }}, 280 {"[1.2,3.4]", &llx.Primitive{ 281 Type: string(types.Array(types.Float)), 282 Array: []*llx.Primitive{ 283 llx.FloatPrimitive(1.2), 284 llx.FloatPrimitive(3.4), 285 }, 286 }}, 287 {"[\"a\",\"b\"]", &llx.Primitive{ 288 Type: string(types.Array(types.String)), 289 Array: []*llx.Primitive{ 290 llx.StringPrimitive("a"), 291 llx.StringPrimitive("b"), 292 }, 293 }}, 294 {"[1.2,1]", &llx.Primitive{ 295 Type: string(types.Array(types.Any)), 296 Array: []*llx.Primitive{ 297 llx.FloatPrimitive(1.2), 298 llx.IntPrimitive(1), 299 }, 300 }}, 301 {"[\n 1.2,\n 1\n]", &llx.Primitive{ 302 Type: string(types.Array(types.Any)), 303 Array: []*llx.Primitive{ 304 llx.FloatPrimitive(1.2), 305 llx.IntPrimitive(1), 306 }, 307 }}, 308 {"{a: 123}", &llx.Primitive{ 309 Type: string(types.Map(types.String, types.Int)), 310 Map: map[string]*llx.Primitive{ 311 "a": llx.IntPrimitive(123), 312 }, 313 }}, 314 } 315 for _, v := range data { 316 t.Run(v.code, func(t *testing.T) { 317 compileT(t, v.code, func(res *llx.CodeBundle) { 318 o := res.CodeV2.Blocks[0].Chunks[0] 319 assert.Equal(t, llx.Chunk_PRIMITIVE, o.Call) 320 assert.Equal(t, v.res, o.Primitive) 321 }) 322 }) 323 } 324 } 325 326 // FIXME: this is weirdly failing 327 // func TestCompiler_SimpleArrayResource(t *testing.T) { 328 // res := compileT(t, "[mochi, mochi]").Code.Code[2] 329 // assert.Equal(t, llx.Chunk_PRIMITIVE, res.Call) 330 // assert.Equal(t, []types.Type{types.Type_ARRAY, types.Type_ANY}, res.Primitive.Type) 331 // assert.Equal(t, []*llx.Primitive{ 332 // llx.RefPrimitive(1), 333 // llx.RefPrimitive(2), 334 // }, res.Primitive.Array) 335 // assert.Nil(t, res.Primitive.Value) 336 // } 337 338 func TestCompiler_Comparisons(t *testing.T) { 339 ops := []string{"==", "!=", ">", "<", ">=", "<="} 340 vals := map[string]*llx.Primitive{ 341 "1": llx.IntPrimitive(1), 342 "1.2": llx.FloatPrimitive(1.2), 343 "true": llx.BoolPrimitive(true), 344 "\"str\"": llx.StringPrimitive("str"), 345 "/str/": llx.RegexPrimitive("str"), 346 } 347 for _, op := range ops { 348 for val, valres := range vals { 349 if types.Type(valres.Type) != types.Int && types.Type(valres.Type) != types.Float && types.Type(valres.Type) != types.String { 350 continue 351 } 352 code := val + " " + op + " " + val 353 t.Run(code, func(t *testing.T) { 354 compileT(t, code, func(res *llx.CodeBundle) { 355 o := res.CodeV2.Blocks[0].Chunks[0] 356 assert.Equal(t, valres, o.Primitive) 357 o = res.CodeV2.Blocks[0].Chunks[1] 358 assert.Equal(t, llx.Chunk_FUNCTION, o.Call) 359 assert.Equal(t, op+string(valres.Type), o.Id) 360 assert.Equal(t, uint64((1<<32)|1), o.Function.Binding) 361 assert.Equal(t, types.Bool, types.Type(o.Function.Type)) 362 assert.Equal(t, valres, o.Function.Args[0]) 363 }) 364 }) 365 } 366 } 367 } 368 369 func TestCompiler_LogicalOps(t *testing.T) { 370 ops := []string{"&&", "||"} 371 vals := map[string]*llx.Primitive{ 372 "1": llx.IntPrimitive(1), 373 "1.2": llx.FloatPrimitive(1.2), 374 "true": llx.BoolPrimitive(true), 375 "\"str\"": llx.StringPrimitive("str"), 376 "/str/": llx.RegexPrimitive("str"), 377 "[]": llx.ArrayPrimitive([]*llx.Primitive{}, types.Unset), 378 "{}": llx.MapPrimitive(map[string]*llx.Primitive{}, types.Unset), 379 } 380 for _, op := range ops { 381 for val1, valres1 := range vals { 382 for val2, valres2 := range vals { 383 code := val1 + " " + op + " " + val2 384 t.Run(code, func(t *testing.T) { 385 compileT(t, code, func(res *llx.CodeBundle) { 386 l := res.CodeV2.Blocks[0].Chunks[0] 387 assert.Equal(t, valres1, l.Primitive) 388 389 r := res.CodeV2.Blocks[0].Chunks[1] 390 assert.Equal(t, llx.Chunk_FUNCTION, r.Call) 391 assert.Equal(t, uint64((1<<32)|1), r.Function.Binding) 392 assert.Equal(t, types.Bool, types.Type(r.Function.Type)) 393 assert.Equal(t, valres2, r.Function.Args[0]) 394 395 f, err := llx.BuiltinFunctionV2(l.Type(), r.Id) 396 assert.NoError(t, err, "was able to find builtin function for llx execution") 397 assert.NotNil(t, f, "was able to get non-nil builtin function") 398 }) 399 }) 400 } 401 } 402 } 403 } 404 405 func TestCompiler_Arithmetics(t *testing.T) { 406 t.Run("concat arrays", func(t *testing.T) { 407 compileT(t, "[1,2] + [3]", func(res *llx.CodeBundle) { 408 require.NotEmpty(t, res.CodeV2) 409 require.NotEmpty(t, res.CodeV2.Blocks) 410 chunks := res.CodeV2.Blocks[0].Chunks 411 require.NotEmpty(t, chunks) 412 413 assert.Equal(t, llx.Chunk_PRIMITIVE, chunks[0].Call) 414 assert.Equal(t, llx.Chunk_FUNCTION, chunks[1].Call) 415 assert.Equal(t, "+", chunks[1].Id) 416 assert.Equal(t, 1, len(chunks[1].Function.Args)) 417 }) 418 }) 419 } 420 421 func TestCompiler_OperatorPrecedence(t *testing.T) { 422 data := []struct { 423 code string 424 idx int 425 first string 426 second string 427 }{ 428 {"1 || 2 && 3", 2, string("&&" + types.Int), string("||" + types.Bool)}, 429 {"1 && 2 || 3", 1, string("&&" + types.Int), string("||" + types.Int)}, 430 } 431 432 for _, d := range data { 433 t.Run(d.code, func(t *testing.T) { 434 compileT(t, d.code, func(res *llx.CodeBundle) { 435 fmt.Printf("compiled: %#v\n", res) 436 437 o := res.CodeV2.Blocks[0].Chunks[d.idx] 438 assert.Equal(t, d.first, o.Id) 439 440 o = res.CodeV2.Blocks[0].Chunks[d.idx+1] 441 assert.Equal(t, d.second, o.Id) 442 }) 443 }) 444 } 445 } 446 447 func TestCompiler_Assignment(t *testing.T) { 448 compileT(t, "a = 123", func(res *llx.CodeBundle) { 449 assertPrimitive(t, llx.IntPrimitive(123), res.CodeV2.Blocks[0].Chunks[0]) 450 assert.Empty(t, res.CodeV2.Entrypoints()) 451 }) 452 compileT(t, "a = 123\na", func(res *llx.CodeBundle) { 453 assertPrimitive(t, llx.RefPrimitiveV2((1<<32)|1), res.CodeV2.Blocks[0].Chunks[1]) 454 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 455 }) 456 } 457 458 func TestCompiler_Props(t *testing.T) { 459 compileProps(t, "props.name", map[string]*llx.Primitive{ 460 "name": {Type: string(types.String)}, 461 }, func(res *llx.CodeBundle) { 462 assertProperty(t, "name", types.String, res.CodeV2.Blocks[0].Chunks[0]) 463 assert.Equal(t, []uint64{(1 << 32) | 1}, res.CodeV2.Entrypoints()) 464 assert.Equal(t, map[string]string{"name": string(types.String)}, res.Props) 465 }) 466 467 // prop <op> value 468 compileProps(t, "props.name == 'bob'", map[string]*llx.Primitive{ 469 "name": {Type: string(types.String)}, 470 }, func(res *llx.CodeBundle) { 471 assertProperty(t, "name", types.String, res.CodeV2.Blocks[0].Chunks[0]) 472 assertFunction(t, "=="+string(types.String), &llx.Function{ 473 Type: string(types.Bool), 474 Binding: (1 << 32) | 1, 475 Args: []*llx.Primitive{llx.StringPrimitive("bob")}, 476 }, res.CodeV2.Blocks[0].Chunks[1]) 477 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 478 assert.Equal(t, map[string]string{"name": string(types.String)}, res.Props) 479 }) 480 481 // different compile stages yielding the same checksums 482 compileProps(t, "props.name == 'bob'", map[string]*llx.Primitive{ 483 "name": {Type: string(types.String)}, 484 }, func(res1 *llx.CodeBundle) { 485 compileProps(t, "props.name == 'bob'", map[string]*llx.Primitive{ 486 "name": {Type: string(types.String), Value: []byte("yoman")}, 487 }, func(res2 *llx.CodeBundle) { 488 assert.Equal(t, res2.CodeV2.Id, res1.CodeV2.Id) 489 }) 490 }) 491 492 compileProps(t, "props.name == props.name", map[string]*llx.Primitive{ 493 "name": {Type: string(types.String)}, 494 }, func(res *llx.CodeBundle) { 495 assertProperty(t, "name", types.String, res.CodeV2.Blocks[0].Chunks[0]) 496 assertProperty(t, "name", types.String, res.CodeV2.Blocks[0].Chunks[1]) 497 assertFunction(t, "=="+string(types.String), &llx.Function{ 498 Type: string(types.Bool), 499 Binding: (1 << 32) | 1, 500 Args: []*llx.Primitive{llx.RefPrimitiveV2((1 << 32) | 2)}, 501 }, res.CodeV2.Blocks[0].Chunks[2]) 502 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 503 assert.Equal(t, map[string]string{"name": string(types.String)}, res.Props) 504 }) 505 } 506 507 func TestCompiler_Dict(t *testing.T) { 508 compileProps(t, "props.d.A.B", map[string]*llx.Primitive{ 509 "d": {Type: string(types.Dict)}, 510 }, func(res *llx.CodeBundle) { 511 assertProperty(t, "d", types.Dict, res.CodeV2.Blocks[0].Chunks[0]) 512 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 513 assertFunction(t, "[]", &llx.Function{ 514 Type: string(types.Dict), 515 Binding: (1 << 32) | 1, 516 Args: []*llx.Primitive{llx.StringPrimitive("A")}, 517 }, res.CodeV2.Blocks[0].Chunks[1]) 518 assertFunction(t, "[]", &llx.Function{ 519 Type: string(types.Dict), 520 Binding: (1 << 32) | 2, 521 Args: []*llx.Primitive{llx.StringPrimitive("B")}, 522 }, res.CodeV2.Blocks[0].Chunks[2]) 523 assert.Equal(t, map[string]string{"d": string(types.Dict)}, res.Props) 524 }) 525 526 compileProps(t, "props.d.A-1", map[string]*llx.Primitive{ 527 "d": {Type: string(types.Dict)}, 528 }, func(res *llx.CodeBundle) { 529 assertProperty(t, "d", types.Dict, res.CodeV2.Blocks[0].Chunks[0]) 530 assert.Equal(t, []uint64{(1 << 32) | 2, (1 << 32) | 3}, res.CodeV2.Entrypoints()) 531 assertFunction(t, "[]", &llx.Function{ 532 Type: string(types.Dict), 533 Binding: (1 << 32) | 1, 534 Args: []*llx.Primitive{llx.StringPrimitive("A")}, 535 }, res.CodeV2.Blocks[0].Chunks[1]) 536 assertPrimitive(t, llx.IntPrimitive(-1), res.CodeV2.Blocks[0].Chunks[2]) 537 assert.Equal(t, map[string]string{"d": string(types.Dict)}, res.Props) 538 }) 539 } 540 541 func TestCompiler_If(t *testing.T) { 542 compileT(t, "if ( true ) { return 1 } else if ( false ) { return 2 } else { return 3 }", func(res *llx.CodeBundle) { 543 assertFunction(t, "if", &llx.Function{ 544 Type: string(types.Int), 545 Binding: 0, 546 Args: []*llx.Primitive{ 547 llx.BoolPrimitive(true), 548 llx.FunctionPrimitive(2 << 32), 549 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 550 llx.BoolPrimitive(false), 551 llx.FunctionPrimitive(3 << 32), 552 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 553 llx.FunctionPrimitive(4 << 32), 554 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 555 }, 556 }, res.CodeV2.Blocks[0].Chunks[0]) 557 assert.Equal(t, []uint64{(1 << 32) | 1}, res.CodeV2.Entrypoints()) 558 assert.Equal(t, []uint64(nil), res.CodeV2.Datapoints()) 559 560 assertPrimitive(t, llx.IntPrimitive(1), res.CodeV2.Blocks[1].Chunks[0]) 561 assertFunction(t, "return", &llx.Function{ 562 Type: string(types.Int), 563 Binding: 0, 564 Args: []*llx.Primitive{ 565 llx.RefPrimitiveV2((2 << 32) | 1), 566 }, 567 }, res.CodeV2.Blocks[1].Chunks[1]) 568 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 569 570 assertPrimitive(t, llx.IntPrimitive(2), res.CodeV2.Blocks[2].Chunks[0]) 571 assertFunction(t, "return", &llx.Function{ 572 Type: string(types.Int), 573 Binding: 0, 574 Args: []*llx.Primitive{ 575 llx.RefPrimitiveV2((3 << 32) | 1), 576 }, 577 }, res.CodeV2.Blocks[2].Chunks[1]) 578 assert.Equal(t, []uint64{(3 << 32) | 2}, res.CodeV2.Blocks[2].Entrypoints) 579 580 assertPrimitive(t, llx.IntPrimitive(3), res.CodeV2.Blocks[3].Chunks[0]) 581 assertFunction(t, "return", &llx.Function{ 582 Type: string(types.Int), 583 Binding: 0, 584 Args: []*llx.Primitive{ 585 llx.RefPrimitiveV2((4 << 32) | 1), 586 }, 587 }, res.CodeV2.Blocks[3].Chunks[1]) 588 assert.Equal(t, []uint64{(4 << 32) | 2}, res.CodeV2.Blocks[3].Entrypoints) 589 }) 590 591 compileT(t, "if ( mondoo ) { return 123 } if ( true ) { return 456 } 789", func(res *llx.CodeBundle) { 592 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 593 594 assertFunction(t, "if", &llx.Function{ 595 Type: string(types.Int), 596 Binding: 0, 597 Args: []*llx.Primitive{ 598 llx.RefPrimitiveV2((1 << 32) | 1), 599 llx.FunctionPrimitive(2 << 32), 600 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 601 llx.FunctionPrimitive(3 << 32), 602 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 603 }, 604 }, res.CodeV2.Blocks[0].Chunks[1]) 605 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 606 assert.Equal(t, []uint64(nil), res.CodeV2.Datapoints()) 607 608 assertPrimitive(t, llx.IntPrimitive(123), res.CodeV2.Blocks[1].Chunks[0]) 609 assertFunction(t, "return", &llx.Function{ 610 Type: string(types.Int), 611 Binding: 0, 612 Args: []*llx.Primitive{ 613 llx.RefPrimitiveV2((2 << 32) | 1), 614 }, 615 }, res.CodeV2.Blocks[1].Chunks[1]) 616 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 617 618 assertFunction(t, "if", &llx.Function{ 619 Type: string(types.Int), 620 Binding: 0, 621 Args: []*llx.Primitive{ 622 llx.BoolPrimitive(true), 623 llx.FunctionPrimitive(4 << 32), 624 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 625 llx.FunctionPrimitive(5 << 32), 626 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 627 }, 628 }, res.CodeV2.Blocks[2].Chunks[0]) 629 assert.Equal(t, []uint64{(3 << 32) | 1}, res.CodeV2.Blocks[2].Entrypoints) 630 631 assertPrimitive(t, llx.IntPrimitive(456), res.CodeV2.Blocks[3].Chunks[0]) 632 assertFunction(t, "return", &llx.Function{ 633 Type: string(types.Int), 634 Binding: 0, 635 Args: []*llx.Primitive{ 636 llx.RefPrimitiveV2((4 << 32) | 1), 637 }, 638 }, res.CodeV2.Blocks[3].Chunks[1]) 639 assert.Equal(t, []uint64{(4 << 32) | 2}, res.CodeV2.Blocks[3].Entrypoints) 640 641 assertPrimitive(t, llx.IntPrimitive(789), res.CodeV2.Blocks[4].Chunks[0]) 642 assert.Equal(t, []uint64{(5 << 32) | 1}, res.CodeV2.Blocks[4].Entrypoints) 643 }) 644 645 compileT(t, "if ( mondoo ) { return 123 } 456", func(res *llx.CodeBundle) { 646 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 647 648 assertFunction(t, "if", &llx.Function{ 649 Type: string(types.Int), 650 Binding: 0, 651 Args: []*llx.Primitive{ 652 llx.RefPrimitiveV2((1 << 32) | 1), 653 llx.FunctionPrimitive(2 << 32), 654 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 655 llx.FunctionPrimitive(3 << 32), 656 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 657 }, 658 }, res.CodeV2.Blocks[0].Chunks[1]) 659 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 660 assert.Equal(t, []uint64(nil), res.CodeV2.Datapoints()) 661 662 assertPrimitive(t, llx.IntPrimitive(123), res.CodeV2.Blocks[1].Chunks[0]) 663 assertFunction(t, "return", &llx.Function{ 664 Type: string(types.Int), 665 Binding: 0, 666 Args: []*llx.Primitive{ 667 llx.RefPrimitiveV2((2 << 32) | 1), 668 }, 669 }, res.CodeV2.Blocks[1].Chunks[1]) 670 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 671 672 assertPrimitive(t, llx.IntPrimitive(456), res.CodeV2.Blocks[2].Chunks[0]) 673 assert.Equal(t, []uint64{(3 << 32) | 1}, res.CodeV2.Blocks[2].Entrypoints) 674 }) 675 676 // Test empty array with filled array and type-consolidation in the compiler 677 compileT(t, "if ( mondoo ) { return [] } return [1,2,3]", func(res *llx.CodeBundle) { 678 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 679 680 assertFunction(t, "if", &llx.Function{ 681 Type: string(types.Array(types.Int)), 682 Binding: 0, 683 Args: []*llx.Primitive{ 684 llx.RefPrimitiveV2((1 << 32) | 1), 685 llx.FunctionPrimitive(2 << 32), 686 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 687 llx.FunctionPrimitive(3 << 32), 688 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 689 }, 690 }, res.CodeV2.Blocks[0].Chunks[1]) 691 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 692 assert.Equal(t, []uint64(nil), res.CodeV2.Datapoints()) 693 694 assertPrimitive(t, llx.ArrayPrimitive([]*llx.Primitive{}, types.Unset), 695 res.CodeV2.Blocks[1].Chunks[0]) 696 assertFunction(t, "return", &llx.Function{ 697 Type: string(types.Array(types.Unset)), 698 Binding: 0, 699 Args: []*llx.Primitive{ 700 llx.RefPrimitiveV2((2 << 32) | 1), 701 }, 702 }, res.CodeV2.Blocks[1].Chunks[1]) 703 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 704 }) 705 706 compileT(t, "if ( mondoo.version != null ) { 123 }", func(res *llx.CodeBundle) { 707 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 708 assertFunction(t, "version", &llx.Function{ 709 Type: string(types.String), 710 Binding: (1 << 32) | 1, 711 }, res.CodeV2.Blocks[0].Chunks[1]) 712 assertFunction(t, "!=\x02", &llx.Function{ 713 Type: string(types.Bool), 714 Binding: (1 << 32) | 2, 715 Args: []*llx.Primitive{llx.NilPrimitive}, 716 }, res.CodeV2.Blocks[0].Chunks[2]) 717 718 assertFunction(t, "if", &llx.Function{ 719 Type: string(types.Block), 720 Binding: 0, 721 Args: []*llx.Primitive{ 722 llx.RefPrimitiveV2((1 << 32) | 3), 723 llx.FunctionPrimitive(2 << 32), 724 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 725 }, 726 }, res.CodeV2.Blocks[0].Chunks[3]) 727 assert.Equal(t, []uint64{(1 << 32) | 4}, res.CodeV2.Entrypoints()) 728 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Datapoints()) 729 730 assertPrimitive(t, llx.IntPrimitive(123), res.CodeV2.Blocks[1].Chunks[0]) 731 assert.Equal(t, []uint64{(2 << 32) | 1}, res.CodeV2.Blocks[1].Entrypoints) 732 }) 733 734 compileT(t, "if ( mondoo ) { 123 } else { 456 }", func(res *llx.CodeBundle) { 735 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 736 737 assertFunction(t, "if", &llx.Function{ 738 Type: string(types.Block), 739 Binding: 0, 740 Args: []*llx.Primitive{ 741 llx.RefPrimitiveV2((1 << 32) | 1), 742 llx.FunctionPrimitive(2 << 32), 743 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 744 llx.FunctionPrimitive(3 << 32), 745 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 746 }, 747 }, res.CodeV2.Blocks[0].Chunks[1]) 748 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 749 assert.Equal(t, []uint64(nil), res.CodeV2.Datapoints()) 750 751 assertPrimitive(t, llx.IntPrimitive(123), res.CodeV2.Blocks[1].Chunks[0]) 752 assert.Equal(t, []uint64{(2 << 32) | 1}, res.CodeV2.Blocks[1].Entrypoints) 753 754 assertPrimitive(t, llx.IntPrimitive(456), res.CodeV2.Blocks[2].Chunks[0]) 755 assert.Equal(t, []uint64{(3 << 32) | 1}, res.CodeV2.Blocks[2].Entrypoints) 756 }) 757 758 compileT(t, "if ( mondoo ) { 123 } else if ( true ) { 456 } else { 789 }", func(res *llx.CodeBundle) { 759 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 760 761 assertFunction(t, "if", &llx.Function{ 762 Type: string(types.Block), 763 Binding: 0, 764 Args: []*llx.Primitive{ 765 llx.RefPrimitiveV2((1 << 32) | 1), 766 llx.FunctionPrimitive(2 << 32), 767 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 768 llx.BoolPrimitive(true), 769 llx.FunctionPrimitive(3 << 32), 770 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 771 llx.FunctionPrimitive(4 << 32), 772 llx.ArrayPrimitive([]*llx.Primitive{}, types.Ref), 773 }, 774 }, res.CodeV2.Blocks[0].Chunks[1]) 775 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 776 assert.Equal(t, []uint64(nil), res.CodeV2.Datapoints()) 777 778 assertPrimitive(t, llx.IntPrimitive(123), res.CodeV2.Blocks[1].Chunks[0]) 779 assert.Equal(t, []uint64{(2 << 32) | 1}, res.CodeV2.Blocks[1].Entrypoints) 780 781 assertPrimitive(t, llx.IntPrimitive(456), res.CodeV2.Blocks[2].Chunks[0]) 782 assert.Equal(t, []uint64{(3 << 32) | 1}, res.CodeV2.Blocks[2].Entrypoints) 783 784 assertPrimitive(t, llx.IntPrimitive(789), res.CodeV2.Blocks[3].Chunks[0]) 785 assert.Equal(t, []uint64{(4 << 32) | 1}, res.CodeV2.Blocks[3].Entrypoints) 786 }) 787 } 788 789 func TestCompiler_Switch(t *testing.T) { 790 compileT(t, "switch ( 1 ) { case _ > 0: true; default: false }", func(res *llx.CodeBundle) { 791 assertFunction(t, "switch", &llx.Function{ 792 Type: string(types.Bool), 793 Binding: 0, 794 Args: []*llx.Primitive{ 795 llx.IntPrimitive(1), 796 llx.RefPrimitiveV2((1 << 32) | 2), 797 llx.FunctionPrimitive(2 << 32), 798 llx.ArrayPrimitive([]*llx.Primitive{ 799 // TODO(jaym): this shouldn't be needed. Its already 800 // a dependency of the switch, and thus implicitly 801 // will already be available for any blocks 802 llx.RefPrimitiveV2((1 << 32) | 1), 803 }, types.Ref), 804 llx.BoolPrimitive(true), 805 llx.FunctionPrimitive(3 << 32), 806 llx.ArrayPrimitive([]*llx.Primitive{ 807 // TODO: this shouldn't be needed 808 llx.RefPrimitiveV2((1 << 32) | 1), 809 }, types.Ref), 810 }, 811 }, res.CodeV2.Blocks[0].Chunks[2]) 812 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 813 assert.Empty(t, res.CodeV2.Datapoints()) 814 }) 815 816 compileT(t, "switch { case 3 > 2: 123; default: 321 }", func(res *llx.CodeBundle) { 817 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 818 }) 819 820 t.Run("test types fall back to any", func(t *testing.T) { 821 compileT(t, "switch ( 1 ) { case _ > 0: true; case _ < 0: 'test'; default: false }", func(res *llx.CodeBundle) { 822 assert.Equal(t, types.Any, res.CodeV2.Blocks[0].Chunks[3].Type()) 823 }) 824 compileT(t, "switch ( 1 ) { case _ > 0: true; default: 'test' }", func(res *llx.CodeBundle) { 825 assert.Equal(t, types.Any, res.CodeV2.Blocks[0].Chunks[2].Type()) 826 }) 827 }) 828 } 829 830 // // ======================= 831 // // 👋 ARRAYS and MAPS 🍹 832 // // ======================= 833 834 func TestCompiler_ArrayEmptyWhere(t *testing.T) { 835 compileT(t, "[1,2,3].where()", func(res *llx.CodeBundle) { 836 assertPrimitive(t, &llx.Primitive{ 837 Type: string(types.Array(types.Int)), 838 Array: []*llx.Primitive{ 839 llx.IntPrimitive(1), 840 llx.IntPrimitive(2), 841 llx.IntPrimitive(3), 842 }, 843 }, res.CodeV2.Blocks[0].Chunks[0]) 844 assert.Equal(t, 1, len(res.CodeV2.Blocks[0].Chunks)) 845 }) 846 } 847 848 func TestCompiler_ArrayWhereStatic(t *testing.T) { 849 compileErroneous(t, "[1,2,3].where(sshd)", errors.New("called 'where' with wrong type; either provide a type int value or write it as an expression (e.g. \"_ == 123\")"), func(res *llx.CodeBundle) { 850 assertPrimitive(t, &llx.Primitive{ 851 Type: string(types.Array(types.Int)), 852 Array: []*llx.Primitive{ 853 llx.IntPrimitive(1), 854 llx.IntPrimitive(2), 855 llx.IntPrimitive(3), 856 }, 857 }, res.CodeV2.Blocks[0].Chunks[0]) 858 }) 859 860 compileT(t, "[1,2,3].where(2)", func(res *llx.CodeBundle) { 861 assertPrimitive(t, &llx.Primitive{ 862 Type: string(types.Array(types.Int)), 863 Array: []*llx.Primitive{ 864 llx.IntPrimitive(1), 865 llx.IntPrimitive(2), 866 llx.IntPrimitive(3), 867 }, 868 }, res.CodeV2.Blocks[0].Chunks[0]) 869 870 assertFunction(t, "where", &llx.Function{ 871 Type: string(types.Array(types.Int)), 872 Binding: (1 << 32) | 1, 873 Args: []*llx.Primitive{ 874 llx.RefPrimitiveV2((1 << 32) | 1), 875 llx.FunctionPrimitive(2 << 32), 876 }, 877 }, res.CodeV2.Blocks[0].Chunks[1]) 878 879 assert.Equal(t, 2, len(res.CodeV2.Blocks[0].Chunks)) 880 }) 881 } 882 883 func TestCompiler_ArrayContains(t *testing.T) { 884 compileT(t, "[1,2,3].contains(_ == 2)", func(res *llx.CodeBundle) { 885 assertPrimitive(t, &llx.Primitive{ 886 Type: string(types.Array(types.Int)), 887 Array: []*llx.Primitive{ 888 llx.IntPrimitive(1), 889 llx.IntPrimitive(2), 890 llx.IntPrimitive(3), 891 }, 892 }, res.CodeV2.Blocks[0].Chunks[0]) 893 894 assertFunction(t, "where", &llx.Function{ 895 Type: string(types.Array(types.Int)), 896 Binding: (1 << 32) | 1, 897 Args: []*llx.Primitive{ 898 llx.RefPrimitiveV2((1 << 32) | 1), 899 llx.FunctionPrimitive(2 << 32), 900 }, 901 }, res.CodeV2.Blocks[0].Chunks[1]) 902 903 assertFunction(t, "length", &llx.Function{ 904 Type: string(types.Int), 905 Binding: (1 << 32) | 2, 906 }, res.CodeV2.Blocks[0].Chunks[2]) 907 assertFunction(t, string(">"+types.Int), &llx.Function{ 908 Type: string(types.Bool), 909 Binding: (1 << 32) | 3, 910 Args: []*llx.Primitive{llx.IntPrimitive(0)}, 911 }, res.CodeV2.Blocks[0].Chunks[3]) 912 913 assert.Equal(t, 4, len(res.CodeV2.Blocks[0].Chunks)) 914 }) 915 } 916 917 func TestCompiler_ArrayOne(t *testing.T) { 918 compileT(t, "[1,2,3].one(_ == 2)", func(res *llx.CodeBundle) { 919 assertPrimitive(t, &llx.Primitive{ 920 Type: string(types.Array(types.Int)), 921 Array: []*llx.Primitive{ 922 llx.IntPrimitive(1), 923 llx.IntPrimitive(2), 924 llx.IntPrimitive(3), 925 }, 926 }, res.CodeV2.Blocks[0].Chunks[0]) 927 928 assertFunction(t, "where", &llx.Function{ 929 Type: string(types.Array(types.Int)), 930 Binding: (1 << 32) | 1, 931 Args: []*llx.Primitive{ 932 llx.RefPrimitiveV2((1 << 32) | 1), 933 llx.FunctionPrimitive(2 << 32), 934 }, 935 }, res.CodeV2.Blocks[0].Chunks[1]) 936 937 assertFunction(t, "$one", &llx.Function{ 938 Type: string(types.Bool), 939 Binding: (1 << 32) | 2, 940 }, res.CodeV2.Blocks[0].Chunks[2]) 941 assert.Equal(t, 3, len(res.CodeV2.Blocks[0].Chunks)) 942 }) 943 } 944 945 func TestCompiler_ArrayAll(t *testing.T) { 946 compileT(t, "[1,2,3].all(_ < 9)", func(res *llx.CodeBundle) { 947 assertPrimitive(t, &llx.Primitive{ 948 Type: string(types.Array(types.Int)), 949 Array: []*llx.Primitive{ 950 llx.IntPrimitive(1), 951 llx.IntPrimitive(2), 952 llx.IntPrimitive(3), 953 }, 954 }, res.CodeV2.Blocks[0].Chunks[0]) 955 956 assertFunction(t, "$whereNot", &llx.Function{ 957 Type: string(types.Array(types.Int)), 958 Binding: (1 << 32) | 1, 959 Args: []*llx.Primitive{ 960 llx.RefPrimitiveV2((1 << 32) | 1), 961 llx.FunctionPrimitive(2 << 32), 962 }, 963 }, res.CodeV2.Blocks[0].Chunks[1]) 964 965 assertFunction(t, "$all", &llx.Function{ 966 Type: string(types.Bool), 967 Binding: (1 << 32) | 2, 968 }, res.CodeV2.Blocks[0].Chunks[2]) 969 970 assert.Equal(t, 3, len(res.CodeV2.Blocks[0].Chunks)) 971 }) 972 } 973 974 func TestCompiler_All_Issue1316(t *testing.T) { 975 // https://github.com/mondoohq/cnquery/issues/1316 976 compileT(t, `files.find(from: ".", type: "file").all( permissions.other_readable == false )`, func(res *llx.CodeBundle) { 977 require.Equal(t, 3, len(res.CodeV2.Blocks)) 978 require.Equal(t, 6, len(res.CodeV2.Blocks[2].Chunks)) 979 assertPrimitive(t, &llx.Primitive{ 980 Type: string(types.Resource("file")), 981 }, res.CodeV2.Blocks[2].Chunks[0]) 982 assertFunction(t, "path", &llx.Function{ 983 Type: string(types.String), 984 Binding: (3 << 32) | 1, 985 }, res.CodeV2.Blocks[2].Chunks[1]) 986 assertFunction(t, "size", &llx.Function{ 987 Type: string(types.Int), 988 Binding: (3 << 32) | 1, 989 }, res.CodeV2.Blocks[2].Chunks[2]) 990 assertFunction(t, "permissions", &llx.Function{ 991 Type: string(types.Resource("file.permissions")), 992 Binding: (3 << 32) | 1, 993 }, res.CodeV2.Blocks[2].Chunks[3]) 994 assertFunction(t, "string", &llx.Function{ 995 Type: string(types.String), 996 Binding: (3 << 32) | 4, 997 }, res.CodeV2.Blocks[2].Chunks[4]) 998 assertFunction(t, "other_readable", &llx.Function{ 999 Type: string(types.Bool), 1000 Binding: (3 << 32) | 4, 1001 }, res.CodeV2.Blocks[2].Chunks[5]) 1002 }) 1003 } 1004 1005 // ================= 1006 // 👋 RESOURCES 🍹 1007 // ================= 1008 1009 func TestCompiler_Resource(t *testing.T) { 1010 compileT(t, "sshd", func(res *llx.CodeBundle) { 1011 assertFunction(t, "sshd", nil, res.CodeV2.Blocks[0].Chunks[0]) 1012 }) 1013 } 1014 1015 func TestCompiler_Resource_versioning(t *testing.T) { 1016 compileT(t, "sshd", func(res *llx.CodeBundle) { 1017 assert.Equal(t, "5.15.0", res.MinMondooVersion) 1018 }) 1019 } 1020 1021 func TestCompiler_Resource_versioning2(t *testing.T) { 1022 compileT(t, "file.empty", func(res *llx.CodeBundle) { 1023 assert.Equal(t, "5.18.0", res.MinMondooVersion) 1024 }) 1025 } 1026 1027 func TestCompiler_ResourceWithCall(t *testing.T) { 1028 compileT(t, "sshd()", func(res *llx.CodeBundle) { 1029 assertFunction(t, "sshd", nil, res.CodeV2.Blocks[0].Chunks[0]) 1030 }) 1031 } 1032 1033 func TestCompiler_LongResource(t *testing.T) { 1034 compileT(t, "sshd.config", func(res *llx.CodeBundle) { 1035 assertFunction(t, "sshd.config", nil, res.CodeV2.Blocks[0].Chunks[0]) 1036 }) 1037 } 1038 1039 func TestCompiler_ResourceMap(t *testing.T) { 1040 compileT(t, "sshd.config.params", func(res *llx.CodeBundle) { 1041 assertFunction(t, "sshd.config", nil, res.CodeV2.Blocks[0].Chunks[0]) 1042 assert.Equal(t, "5.15.0", res.MinMondooVersion) 1043 assertFunction(t, "params", &llx.Function{ 1044 Type: string(types.Map(types.String, types.String)), 1045 Binding: (1 << 32) | 1, 1046 }, res.CodeV2.Blocks[0].Chunks[1]) 1047 }) 1048 } 1049 1050 func TestCompiler_ResourceMapLength(t *testing.T) { 1051 compileT(t, "sshd.config.params.length", func(res *llx.CodeBundle) { 1052 assertFunction(t, "length", &llx.Function{ 1053 Type: string(types.Int), 1054 Binding: (1 << 32) | 2, 1055 }, res.CodeV2.Blocks[0].Chunks[2]) 1056 }) 1057 } 1058 1059 func TestCompiler_ResourceExpansion(t *testing.T) { 1060 var cmd string 1061 1062 cmd = "mondoo" 1063 t.Run(cmd, func(t *testing.T) { 1064 compileT(t, cmd, func(res *llx.CodeBundle) { 1065 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 1066 assertFunction(t, "{}", &llx.Function{ 1067 Binding: (1 << 32) | 1, 1068 Type: string(types.Block), 1069 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1070 }, res.CodeV2.Blocks[0].Chunks[1]) 1071 1072 assertFunction(t, "version", &llx.Function{ 1073 Binding: (2 << 32) | 1, 1074 Type: string(types.String), 1075 }, res.CodeV2.Blocks[1].Chunks[1]) 1076 1077 assert.Equal(t, map[string]uint64{res.CodeV2.Checksums[1<<32|2]: 2 << 32}, res.AutoExpand) 1078 assert.Equal(t, []uint64{1<<32 | 2}, res.CodeV2.Blocks[0].Entrypoints) 1079 }) 1080 }) 1081 1082 cmd = "users" 1083 t.Run(cmd, func(t *testing.T) { 1084 compileT(t, cmd, func(res *llx.CodeBundle) { 1085 assertFunction(t, "users", nil, res.CodeV2.Blocks[0].Chunks[0]) 1086 assertFunction(t, "list", &llx.Function{ 1087 Binding: (1 << 32) | 1, 1088 Args: nil, 1089 Type: string(types.Array(types.Resource("user"))), 1090 }, res.CodeV2.Blocks[0].Chunks[1]) 1091 assertFunction(t, "{}", &llx.Function{ 1092 Binding: (1 << 32) | 2, 1093 Type: string(types.Array(types.Block)), 1094 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1095 }, res.CodeV2.Blocks[0].Chunks[2]) 1096 1097 assertFunction(t, "name", &llx.Function{ 1098 Binding: (2 << 32) | 1, 1099 Type: string(types.String), 1100 }, res.CodeV2.Blocks[1].Chunks[1]) 1101 assertFunction(t, "uid", &llx.Function{ 1102 Binding: (2 << 32) | 1, 1103 Type: string(types.Int), 1104 }, res.CodeV2.Blocks[1].Chunks[2]) 1105 assertFunction(t, "gid", &llx.Function{ 1106 Binding: (2 << 32) | 1, 1107 Type: string(types.Int), 1108 }, res.CodeV2.Blocks[1].Chunks[3]) 1109 1110 assert.Equal(t, map[string]uint64{res.CodeV2.Checksums[1<<32|3]: 2 << 32}, res.AutoExpand) 1111 assert.Equal(t, []uint64{1<<32 | 3}, res.CodeV2.Blocks[0].Entrypoints) 1112 assert.Equal(t, []uint64{2<<32 | 2, 2<<32 | 3, 2<<32 | 4}, res.CodeV2.Blocks[1].Entrypoints) 1113 }) 1114 }) 1115 1116 cmd = "users { group }" 1117 t.Run(cmd, func(t *testing.T) { 1118 compileT(t, cmd, func(res *llx.CodeBundle) { 1119 require.Len(t, res.CodeV2.Blocks, 3) 1120 1121 assertFunction(t, "{}", &llx.Function{ 1122 Binding: (1 << 32) | 2, 1123 Type: string(types.Array(types.Block)), 1124 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1125 }, res.CodeV2.Blocks[0].Chunks[2]) 1126 1127 assertFunction(t, "group", &llx.Function{ 1128 Binding: (2 << 32) | 1, 1129 Type: string(types.Resource("group")), 1130 }, res.CodeV2.Blocks[1].Chunks[1]) 1131 assertFunction(t, "{}", &llx.Function{ 1132 Binding: (2 << 32) | 2, 1133 Type: string(types.Block), 1134 Args: []*llx.Primitive{llx.FunctionPrimitive(3 << 32)}, 1135 }, res.CodeV2.Blocks[1].Chunks[2]) 1136 1137 assertFunction(t, "name", &llx.Function{ 1138 Binding: (3 << 32) | 1, 1139 Type: string(types.String), 1140 }, res.CodeV2.Blocks[2].Chunks[1]) 1141 assertFunction(t, "gid", &llx.Function{ 1142 Binding: (3 << 32) | 1, 1143 Type: string(types.Int), 1144 }, res.CodeV2.Blocks[2].Chunks[2]) 1145 1146 assert.Equal(t, map[string]uint64{res.CodeV2.Checksums[2<<32|3]: 3 << 32}, res.AutoExpand) 1147 assert.Equal(t, []uint64{1<<32 | 3}, res.CodeV2.Blocks[0].Entrypoints) 1148 assert.Equal(t, []uint64{2<<32 | 3}, res.CodeV2.Blocks[1].Entrypoints) 1149 assert.Equal(t, []uint64{3<<32 | 2, 3<<32 | 3}, res.CodeV2.Blocks[2].Entrypoints) 1150 }) 1151 }) 1152 1153 cmd = "pam.conf.entries['.']" 1154 t.Run(cmd, func(t *testing.T) { 1155 compileT(t, cmd, func(res *llx.CodeBundle) { 1156 assertFunction(t, "[]", &llx.Function{ 1157 Binding: (1 << 32) | 2, 1158 Args: []*llx.Primitive{{ 1159 Type: string(types.String), 1160 Value: []byte("."), 1161 }}, 1162 Type: string(types.Array(types.Resource("pam.conf.serviceEntry"))), 1163 }, res.CodeV2.Blocks[0].Chunks[2]) 1164 assertFunction(t, "{}", &llx.Function{ 1165 Binding: (1 << 32) | 3, 1166 Type: string(types.Array(types.Block)), 1167 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1168 }, res.CodeV2.Blocks[0].Chunks[3]) 1169 1170 assertFunction(t, "service", &llx.Function{ 1171 Binding: (2 << 32) | 1, 1172 Type: string(types.String), 1173 }, res.CodeV2.Blocks[1].Chunks[1]) 1174 }) 1175 }) 1176 } 1177 1178 func TestCompiler_ArrayResource(t *testing.T) { 1179 var cmd string 1180 1181 cmd = "packages[123]" 1182 t.Run(cmd, func(t *testing.T) { 1183 compileT(t, cmd, func(res *llx.CodeBundle) { 1184 assertFunction(t, "list", &llx.Function{ 1185 Binding: (1 << 32) | 1, 1186 Args: nil, 1187 Type: string(types.Array(types.Resource("package"))), 1188 }, res.CodeV2.Blocks[0].Chunks[1]) 1189 assertFunction(t, "[]", &llx.Function{ 1190 Binding: (1 << 32) | 2, 1191 Args: []*llx.Primitive{llx.IntPrimitive(123)}, 1192 Type: string(types.Resource("package")), 1193 }, res.CodeV2.Blocks[0].Chunks[2]) 1194 }) 1195 }) 1196 1197 cmd = "packages.length" 1198 t.Run(cmd, func(t *testing.T) { 1199 compileT(t, cmd, func(res *llx.CodeBundle) { 1200 assertFunction(t, "list", &llx.Function{ 1201 Binding: (1 << 32) | 1, 1202 Args: nil, 1203 Type: string(types.Array(types.Resource("package"))), 1204 }, res.CodeV2.Blocks[0].Chunks[1]) 1205 assertFunction(t, "length", &llx.Function{ 1206 Binding: (1 << 32) | 1, 1207 Args: []*llx.Primitive{llx.RefPrimitiveV2((1 << 32) | 2)}, 1208 Type: string(types.Int), 1209 }, res.CodeV2.Blocks[0].Chunks[2]) 1210 }) 1211 }) 1212 1213 // FIXME: DEPRECATED, remove in v8.0 vv 1214 compileT(t, "packages.list[123]", func(res *llx.CodeBundle) { 1215 assertFunction(t, "[]", &llx.Function{ 1216 Binding: (1 << 32) | 2, 1217 Args: []*llx.Primitive{llx.IntPrimitive(123)}, 1218 Type: string(types.Resource("package")), 1219 }, res.CodeV2.Blocks[0].Chunks[2]) 1220 }) 1221 1222 compileT(t, "packages.list.length", func(res *llx.CodeBundle) { 1223 assertFunction(t, "list", &llx.Function{ 1224 Binding: (1 << 32) | 1, 1225 Type: string(types.Array(types.Resource("package"))), 1226 }, res.CodeV2.Blocks[0].Chunks[1]) 1227 assertFunction(t, "length", &llx.Function{ 1228 Binding: (1 << 32) | 2, 1229 Type: string(types.Int), 1230 }, res.CodeV2.Blocks[0].Chunks[2]) 1231 }) 1232 // ^^ 1233 } 1234 1235 func TestCompiler_ResourceFieldGlob(t *testing.T) { 1236 compileT(t, "mondoo{*}", func(res *llx.CodeBundle) { 1237 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 1238 assertFunction(t, "arch", &llx.Function{ 1239 Type: string(types.String), 1240 Binding: (2 << 32) | 1, 1241 }, res.CodeV2.Blocks[1].Chunks[1]) 1242 }) 1243 1244 compileT(t, "pam.conf { * }", func(res *llx.CodeBundle) { 1245 assertFunction(t, "pam.conf", nil, res.CodeV2.Blocks[0].Chunks[0]) 1246 assertFunction(t, "{}", &llx.Function{ 1247 Type: string(types.Block), 1248 Binding: (1 << 32) | 1, 1249 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1250 }, res.CodeV2.Blocks[0].Chunks[1]) 1251 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 1252 1253 assertPrimitive(t, &llx.Primitive{ 1254 Type: string(types.Resource("pam.conf")), 1255 }, res.CodeV2.Blocks[1].Chunks[0]) 1256 assertFunction(t, "content", &llx.Function{ 1257 Type: string(types.String), 1258 Binding: (2 << 32) | 1, 1259 }, res.CodeV2.Blocks[1].Chunks[1]) 1260 assertFunction(t, "entries", &llx.Function{ 1261 Type: string(types.Map(types.String, types.Array(types.Resource("pam.conf.serviceEntry")))), 1262 Binding: (2 << 32) | 1, 1263 }, res.CodeV2.Blocks[1].Chunks[2]) 1264 assertFunction(t, "files", &llx.Function{ 1265 Type: string(types.Array(types.Resource("file"))), 1266 Binding: (2 << 32) | 1, 1267 }, res.CodeV2.Blocks[1].Chunks[3]) 1268 assertFunction(t, "services", &llx.Function{ 1269 Type: string(types.Map(types.String, types.Array(types.String))), 1270 Binding: (2 << 32) | 1, 1271 }, res.CodeV2.Blocks[1].Chunks[4]) 1272 assertFunction(t, "{}", &llx.Function{ 1273 Type: string(types.Array(types.Block)), 1274 Binding: (2 << 32) | 4, 1275 Args: []*llx.Primitive{llx.FunctionPrimitive(3 << 32)}, 1276 }, res.CodeV2.Blocks[1].Chunks[5]) 1277 assert.Equal(t, []uint64{(2 << 32) | 2, (2 << 32) | 3, (2 << 32) | 6, (2 << 32) | 5}, 1278 res.CodeV2.Blocks[1].Entrypoints) 1279 }) 1280 } 1281 1282 func TestCompiler_ArrayResourceFieldGlob(t *testing.T) { 1283 compileT(t, "groups { * }", func(res *llx.CodeBundle) { 1284 assertFunction(t, "groups", nil, res.CodeV2.Blocks[0].Chunks[0]) 1285 assertFunction(t, "list", &llx.Function{ 1286 Binding: (1 << 32) | 1, 1287 Type: string(types.Array(types.Resource("group"))), 1288 }, res.CodeV2.Blocks[0].Chunks[1]) 1289 assertFunction(t, "{}", &llx.Function{ 1290 Type: string(types.Array(types.Block)), 1291 Binding: (1 << 32) | 2, 1292 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1293 }, res.CodeV2.Blocks[0].Chunks[2]) 1294 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 1295 1296 assertPrimitive(t, &llx.Primitive{ 1297 Type: string(types.Resource("group")), 1298 }, res.CodeV2.Blocks[1].Chunks[0]) 1299 assertFunction(t, "gid", &llx.Function{ 1300 Type: string(types.Int), 1301 Binding: (2 << 32) | 1, 1302 }, res.CodeV2.Blocks[1].Chunks[1]) 1303 assertFunction(t, "members", &llx.Function{ 1304 Type: string(types.Array(types.Resource("user"))), 1305 Binding: (2 << 32) | 1, 1306 }, res.CodeV2.Blocks[1].Chunks[2]) 1307 assertFunction(t, "name", &llx.Function{ 1308 Type: string(types.String), 1309 Binding: (2 << 32) | 1, 1310 }, res.CodeV2.Blocks[1].Chunks[3]) 1311 assertFunction(t, "sid", &llx.Function{ 1312 Type: string(types.String), 1313 Binding: (2 << 32) | 1, 1314 }, res.CodeV2.Blocks[1].Chunks[4]) 1315 assertFunction(t, "{}", &llx.Function{ 1316 Type: string(types.Array(types.Block)), 1317 Binding: (2 << 32) | 3, 1318 Args: []*llx.Primitive{llx.FunctionPrimitive(3 << 32)}, 1319 }, res.CodeV2.Blocks[1].Chunks[5]) 1320 assert.Equal(t, []uint64{(2 << 32) | 2, (2 << 32) | 6, (2 << 32) | 4, (2 << 32) | 5}, 1321 res.CodeV2.Blocks[1].Entrypoints) 1322 }) 1323 } 1324 1325 func TestCompiler_ResourceFieldArrayAccessor(t *testing.T) { 1326 compileT(t, "sshd.config.params[\"Protocol\"]", func(res *llx.CodeBundle) { 1327 assertFunction(t, "[]", &llx.Function{ 1328 Type: string(types.String), 1329 Binding: (1 << 32) | 2, 1330 Args: []*llx.Primitive{ 1331 llx.StringPrimitive("Protocol"), 1332 }, 1333 }, res.CodeV2.Blocks[0].Chunks[2]) 1334 }) 1335 } 1336 1337 func TestCompiler_ResourceWithUnnamedArgs(t *testing.T) { 1338 compileT(t, "file(\"/path\")", func(res *llx.CodeBundle) { 1339 assertFunction(t, "file", &llx.Function{ 1340 Type: string(types.Resource("file")), 1341 Binding: 0, 1342 Args: []*llx.Primitive{ 1343 llx.StringPrimitive("path"), 1344 llx.StringPrimitive("/path"), 1345 }, 1346 }, res.CodeV2.Blocks[0].Chunks[0]) 1347 }) 1348 } 1349 1350 func TestCompiler_ResourceWithNamedArgs(t *testing.T) { 1351 compileT(t, "file(path: \"/path\")", func(res *llx.CodeBundle) { 1352 assertFunction(t, "file", &llx.Function{ 1353 Type: string(types.Resource("file")), 1354 Binding: 0, 1355 Args: []*llx.Primitive{ 1356 llx.StringPrimitive("path"), 1357 llx.StringPrimitive("/path"), 1358 }, 1359 }, res.CodeV2.Blocks[0].Chunks[0]) 1360 }) 1361 } 1362 1363 func TestCompiler_LongResourceWithUnnamedArgs(t *testing.T) { 1364 compileT(t, "sshd.config(\"/path\")", func(res *llx.CodeBundle) { 1365 assertFunction(t, "sshd.config", &llx.Function{ 1366 Type: string(types.Resource("sshd.config")), 1367 Binding: 0, 1368 Args: []*llx.Primitive{ 1369 llx.StringPrimitive("path"), 1370 llx.StringPrimitive("/path"), 1371 }, 1372 }, res.CodeV2.Blocks[0].Chunks[0]) 1373 }) 1374 } 1375 1376 // FIXME: reactivate 1377 func testCompiler_EmbeddedResource(t *testing.T) { 1378 compileCtx(t, "docker.containers[0].os", func(res *llx.CodeBundle) { 1379 assertFunction(t, "os", &llx.Function{ 1380 Type: string(types.Resource("os.linux")), 1381 Binding: 1<<32 | 3, 1382 }, res.CodeV2.Blocks[0].Chunks[3]) 1383 }) 1384 } 1385 1386 func testCompiler_EmbeddedResource_Lookup(t *testing.T) { 1387 compileCtx(t, "docker.containers[0].hostname", func(res *llx.CodeBundle) { 1388 assertFunction(t, "os", &llx.Function{ 1389 Type: string(types.Resource("os.linux")), 1390 Binding: 1<<32 | 3, 1391 }, res.CodeV2.Blocks[0].Chunks[3]) 1392 1393 assertFunction(t, "unix", &llx.Function{ 1394 Type: string(types.Resource("os.unix")), 1395 Binding: 1<<32 | 4, 1396 }, res.CodeV2.Blocks[0].Chunks[4]) 1397 1398 assertFunction(t, "base", &llx.Function{ 1399 Type: string(types.Resource("os.base")), 1400 Binding: 1<<32 | 5, 1401 }, res.CodeV2.Blocks[0].Chunks[5]) 1402 1403 assertFunction(t, "hostname", &llx.Function{ 1404 Type: string(types.String), 1405 Binding: 1<<32 | 6, 1406 }, res.CodeV2.Blocks[0].Chunks[6]) 1407 }) 1408 } 1409 1410 func testCompiler_EmbeddedResource_ImplicitResource(t *testing.T) { 1411 compileCtx(t, "docker.containers[0].user(uid: 999).name", func(res *llx.CodeBundle) { 1412 assertFunction(t, "createResource", &llx.Function{ 1413 Type: string(types.Resource("os.base.user")), 1414 Args: []*llx.Primitive{ 1415 llx.RefPrimitiveV2(1<<32 | 3), 1416 llx.StringPrimitive("uid"), 1417 llx.IntPrimitive(999), 1418 }, 1419 Binding: 0, 1420 }, res.CodeV2.Blocks[0].Chunks[3]) 1421 1422 assert.Equal(t, "user", res.Labels.Labels[res.CodeV2.Checksums[1<<32|4]]) 1423 1424 assertFunction(t, "name", &llx.Function{ 1425 Type: string(types.String), 1426 Binding: 1<<32 | 4, 1427 }, res.CodeV2.Blocks[0].Chunks[4]) 1428 }) 1429 } 1430 1431 func testCompiler_EmbeddedResource_ImplicitResource_Block(t *testing.T) { 1432 compileCtx(t, "docker.containers[0].user(uid: 999) { name }", func(res *llx.CodeBundle) { 1433 assertFunction(t, "createResource", &llx.Function{ 1434 Type: string(types.Resource("os.base.user")), 1435 Binding: 0, 1436 Args: []*llx.Primitive{ 1437 llx.RefPrimitiveV2(1<<32 | 3), 1438 llx.StringPrimitive("uid"), 1439 llx.IntPrimitive(999), 1440 }, 1441 }, res.CodeV2.Blocks[0].Chunks[3]) 1442 1443 assertFunction(t, "{}", &llx.Function{ 1444 Type: string(types.Block), 1445 Binding: 1<<32 | 4, 1446 Args: []*llx.Primitive{ 1447 llx.FunctionPrimitive(2 << 32), 1448 }, 1449 }, res.CodeV2.Blocks[0].Chunks[4]) 1450 }) 1451 } 1452 1453 func testCompiler_EmbeddedResource_ImplicitResource_List(t *testing.T) { 1454 compileCtx(t, "docker.containers[0].packages", func(res *llx.CodeBundle) { 1455 assertFunction(t, "createResource", &llx.Function{ 1456 Type: string(types.Resource("os.base.packages")), 1457 Binding: 0, 1458 Args: []*llx.Primitive{ 1459 llx.RefPrimitiveV2(1<<32 | 3), 1460 }, 1461 }, res.CodeV2.Blocks[0].Chunks[3]) 1462 }) 1463 } 1464 1465 func TestCompiler_ExpectSimplest(t *testing.T) { 1466 compileT(t, "expect(true)", func(res *llx.CodeBundle) { 1467 f := res.CodeV2.Blocks[0].Chunks[0] 1468 assert.Equal(t, llx.Chunk_FUNCTION, f.Call) 1469 assert.Equal(t, "expect", f.Id) 1470 assert.Equal(t, []uint64{(1 << 32) | 1}, res.CodeV2.Entrypoints()) 1471 assert.Equal(t, &llx.Function{ 1472 Type: string(types.Bool), 1473 Binding: 0, 1474 Args: []*llx.Primitive{llx.BoolPrimitive(true)}, 1475 }, f.Function) 1476 }) 1477 } 1478 1479 func TestCompiler_ExpectEq(t *testing.T) { 1480 compileT(t, "expect(1 == \"1\")", func(res *llx.CodeBundle) { 1481 cmp := res.CodeV2.Blocks[0].Chunks[1] 1482 assert.Equal(t, llx.Chunk_FUNCTION, cmp.Call) 1483 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 1484 assert.Equal(t, string("=="+types.String), cmp.Id) 1485 assert.Equal(t, &llx.Function{ 1486 Type: string(types.Bool), 1487 Binding: (1 << 32) | 1, 1488 Args: []*llx.Primitive{ 1489 llx.StringPrimitive("1"), 1490 }, 1491 }, cmp.Function) 1492 1493 f := res.CodeV2.Blocks[0].Chunks[2] 1494 assert.Equal(t, llx.Chunk_FUNCTION, f.Call) 1495 assert.Equal(t, "expect", f.Id) 1496 assert.Equal(t, &llx.Function{ 1497 Type: string(types.Bool), 1498 Binding: 0, 1499 Args: []*llx.Primitive{llx.RefPrimitiveV2((1 << 32) | 2)}, 1500 }, f.Function) 1501 }) 1502 } 1503 1504 func TestCompiler_EmptyBlock(t *testing.T) { 1505 compileT(t, "parse { }", func(res *llx.CodeBundle) { 1506 assertFunction(t, "parse", nil, res.CodeV2.Blocks[0].Chunks[0]) 1507 assert.Equal(t, 1, len(res.CodeV2.Blocks[0].Chunks)) 1508 assert.Len(t, res.CodeV2.Blocks, 1) 1509 }) 1510 } 1511 1512 func TestCompiler_Block(t *testing.T) { 1513 compileT(t, "mondoo { version build }", func(res *llx.CodeBundle) { 1514 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 1515 assertFunction(t, "{}", &llx.Function{ 1516 Type: string(types.Block), 1517 Binding: (1 << 32) | 1, 1518 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1519 }, res.CodeV2.Blocks[0].Chunks[1]) 1520 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 1521 1522 assertPrimitive(t, &llx.Primitive{ 1523 Type: string(types.Resource("mondoo")), 1524 }, res.CodeV2.Blocks[1].Chunks[0]) 1525 assertFunction(t, "version", &llx.Function{ 1526 Type: string(types.String), 1527 Binding: (2 << 32) | 1, 1528 }, res.CodeV2.Blocks[1].Chunks[1]) 1529 assertFunction(t, "build", &llx.Function{ 1530 Type: string(types.String), 1531 Binding: (2 << 32) | 1, 1532 }, res.CodeV2.Blocks[1].Chunks[2]) 1533 assert.Equal(t, []uint64{(2 << 32) | 2, (2 << 32) | 3}, res.CodeV2.Blocks[1].Entrypoints) 1534 }) 1535 } 1536 1537 func TestCompiler_BlockWithSelf(t *testing.T) { 1538 compileT(t, "mondoo { _.version }", func(res *llx.CodeBundle) { 1539 assertFunction(t, "mondoo", nil, res.CodeV2.Blocks[0].Chunks[0]) 1540 assertFunction(t, "{}", &llx.Function{ 1541 Type: string(types.Block), 1542 Binding: (1 << 32) | 1, 1543 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1544 }, res.CodeV2.Blocks[0].Chunks[1]) 1545 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 1546 1547 assertPrimitive(t, &llx.Primitive{ 1548 Type: string(types.Resource("mondoo")), 1549 }, res.CodeV2.Blocks[1].Chunks[0]) 1550 assertFunction(t, "version", &llx.Function{ 1551 Type: string(types.String), 1552 Binding: (2 << 32) | 1, 1553 }, res.CodeV2.Blocks[1].Chunks[1]) 1554 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 1555 }) 1556 1557 compileT(t, "sshd.config.params { _['A'] != _['B'] }", func(res *llx.CodeBundle) { 1558 assertFunction(t, "sshd.config", nil, res.CodeV2.Blocks[0].Chunks[0]) 1559 assertFunction(t, "params", &llx.Function{ 1560 Type: string(types.Map(types.String, types.String)), 1561 Binding: (1 << 32) | 1, 1562 }, res.CodeV2.Blocks[0].Chunks[1]) 1563 assertFunction(t, "{}", &llx.Function{ 1564 Type: string(types.Block), 1565 Binding: (1 << 32) | 2, 1566 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1567 }, res.CodeV2.Blocks[0].Chunks[2]) 1568 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 1569 1570 assertPrimitive(t, &llx.Primitive{ 1571 Type: string(types.Map(types.String, types.String)), 1572 }, res.CodeV2.Blocks[1].Chunks[0]) 1573 assertFunction(t, "[]", &llx.Function{ 1574 Type: string(types.String), 1575 Binding: (2 << 32) | 1, 1576 Args: []*llx.Primitive{llx.StringPrimitive("A")}, 1577 }, res.CodeV2.Blocks[1].Chunks[1]) 1578 assertFunction(t, "[]", &llx.Function{ 1579 Type: string(types.String), 1580 Binding: (2 << 32) | 1, 1581 Args: []*llx.Primitive{llx.StringPrimitive("B")}, 1582 }, res.CodeV2.Blocks[1].Chunks[2]) 1583 assertFunction(t, string("!="+types.String), &llx.Function{ 1584 Type: string(types.Bool), 1585 Binding: (2 << 32) | 2, 1586 Args: []*llx.Primitive{llx.RefPrimitiveV2((2 << 32) | 3)}, 1587 }, res.CodeV2.Blocks[1].Chunks[3]) 1588 assert.Equal(t, []uint64{(2 << 32) | 4}, res.CodeV2.Blocks[1].Entrypoints) 1589 }) 1590 1591 compileT(t, "\"alice\\nbob\".lines { _ != \"alice\" && _ != \"bob\" }", func(res *llx.CodeBundle) { 1592 assertPrimitive(t, llx.StringPrimitive("alice\nbob"), res.CodeV2.Blocks[0].Chunks[0]) 1593 assertFunction(t, "lines", &llx.Function{ 1594 Type: string(types.Array(types.String)), 1595 Binding: (1 << 32) | 1, 1596 }, res.CodeV2.Blocks[0].Chunks[1]) 1597 assertFunction(t, "{}", &llx.Function{ 1598 Type: string(types.Array(types.Block)), 1599 Binding: (1 << 32) | 2, 1600 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1601 }, res.CodeV2.Blocks[0].Chunks[2]) 1602 assert.Equal(t, []uint64{(1 << 32) | 3}, res.CodeV2.Entrypoints()) 1603 1604 assertPrimitive(t, &llx.Primitive{ 1605 Type: string(types.String), 1606 }, res.CodeV2.Blocks[1].Chunks[0]) 1607 assertFunction(t, string("!="+types.String), &llx.Function{ 1608 Type: string(types.Bool), 1609 Binding: (2 << 32) | 1, 1610 Args: []*llx.Primitive{llx.StringPrimitive("alice")}, 1611 }, res.CodeV2.Blocks[1].Chunks[1]) 1612 assertFunction(t, string("!="+types.String), &llx.Function{ 1613 Type: string(types.Bool), 1614 Binding: (2 << 32) | 1, 1615 Args: []*llx.Primitive{llx.StringPrimitive("bob")}, 1616 }, res.CodeV2.Blocks[1].Chunks[2]) 1617 assertFunction(t, string("&&"+types.Bool), &llx.Function{ 1618 Type: string(types.Bool), 1619 Binding: (2 << 32) | 2, 1620 Args: []*llx.Primitive{llx.RefPrimitiveV2((2 << 32) | 3)}, 1621 }, res.CodeV2.Blocks[1].Chunks[3]) 1622 assert.Equal(t, []uint64{(2 << 32) | 4}, res.CodeV2.Blocks[1].Entrypoints) 1623 }) 1624 } 1625 1626 func TestCompiler_ContainsWithResource(t *testing.T) { 1627 compileT(t, "'hello'.contains(asset.family)", func(res *llx.CodeBundle) { 1628 assertPrimitive(t, llx.StringPrimitive("hello"), res.CodeV2.Blocks[0].Chunks[0]) 1629 assertFunction(t, "asset", nil, res.CodeV2.Blocks[0].Chunks[1]) 1630 assertFunction(t, "family", &llx.Function{ 1631 Type: string(types.Array(types.String)), 1632 Binding: (1 << 32) | 2, 1633 }, res.CodeV2.Blocks[0].Chunks[2]) 1634 assertFunction(t, "contains"+string(types.Array(types.String)), &llx.Function{ 1635 Type: string(types.Bool), 1636 Binding: (1 << 32) | 1, 1637 Args: []*llx.Primitive{llx.RefPrimitiveV2((1 << 32) | 3)}, 1638 }, res.CodeV2.Blocks[0].Chunks[3]) 1639 1640 assert.Equal(t, []uint64{(1 << 32) | 4}, res.CodeV2.Entrypoints()) 1641 }) 1642 } 1643 1644 func TestCompiler_StringContainsWithInt(t *testing.T) { 1645 compileT(t, "'hello123'.contains(23)", func(res *llx.CodeBundle) { 1646 assertPrimitive(t, llx.StringPrimitive("hello123"), res.CodeV2.Blocks[0].Chunks[0]) 1647 assertFunction(t, "contains"+string(types.Int), &llx.Function{ 1648 Type: string(types.Bool), 1649 Binding: (1 << 32) | 1, 1650 Args: []*llx.Primitive{llx.IntPrimitive(23)}, 1651 }, res.CodeV2.Blocks[0].Chunks[1]) 1652 1653 assert.Equal(t, []uint64{(1 << 32) | 2}, res.CodeV2.Entrypoints()) 1654 }) 1655 } 1656 1657 func TestCompiler_CallWithResource(t *testing.T) { 1658 compileT(t, "users { file(home) }", func(res *llx.CodeBundle) { 1659 assertFunction(t, "users", nil, res.CodeV2.Blocks[0].Chunks[0]) 1660 assertFunction(t, "list", &llx.Function{ 1661 Binding: (1 << 32) | 1, 1662 Type: string(types.Array(types.Resource("user"))), 1663 }, res.CodeV2.Blocks[0].Chunks[1]) 1664 assertFunction(t, "{}", &llx.Function{ 1665 Type: string(types.Array(types.Block)), 1666 Binding: (1 << 32) | 2, 1667 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1668 }, res.CodeV2.Blocks[0].Chunks[2]) 1669 assert.Equal(t, 3, len(res.CodeV2.Blocks[0].Chunks)) 1670 1671 assertPrimitive(t, &llx.Primitive{ 1672 Type: string(types.Resource("user")), 1673 }, res.CodeV2.Blocks[1].Chunks[0]) 1674 assertFunction(t, "home", &llx.Function{ 1675 Type: string(types.String), 1676 Binding: (2 << 32) | 1, 1677 }, res.CodeV2.Blocks[1].Chunks[1]) 1678 assertFunction(t, "file", &llx.Function{ 1679 Type: string(types.Resource("file")), 1680 Binding: 0, 1681 Args: []*llx.Primitive{ 1682 llx.StringPrimitive("path"), 1683 llx.RefPrimitiveV2((2 << 32) | 2), 1684 }, 1685 }, res.CodeV2.Blocks[1].Chunks[2]) 1686 assert.EqualValues(t, 1, res.CodeV2.Blocks[1].Parameters) 1687 }) 1688 } 1689 1690 func TestCompiler_List(t *testing.T) { 1691 compileT(t, "packages { name }", func(res *llx.CodeBundle) { 1692 assertFunction(t, "packages", nil, res.CodeV2.Blocks[0].Chunks[0]) 1693 assertFunction(t, "list", &llx.Function{ 1694 Binding: (1 << 32) | 1, 1695 Type: string(types.Array(types.Resource("package"))), 1696 }, res.CodeV2.Blocks[0].Chunks[1]) 1697 assertFunction(t, "{}", &llx.Function{ 1698 Type: string(types.Array(types.Block)), 1699 Binding: (1 << 32) | 2, 1700 Args: []*llx.Primitive{llx.FunctionPrimitive(2 << 32)}, 1701 }, res.CodeV2.Blocks[0].Chunks[2]) 1702 assert.Equal(t, 3, len(res.CodeV2.Blocks[0].Chunks)) 1703 1704 assertPrimitive(t, &llx.Primitive{ 1705 Type: string(types.Resource("package")), 1706 }, res.CodeV2.Blocks[1].Chunks[0]) 1707 assertFunction(t, "name", &llx.Function{ 1708 Type: string(types.String), 1709 Binding: (2 << 32) | 1, 1710 }, res.CodeV2.Blocks[1].Chunks[1]) 1711 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 1712 }) 1713 } 1714 1715 func TestCompiler_ResourceEmptyWhere(t *testing.T) { 1716 compileT(t, "packages.where()", func(res *llx.CodeBundle) { 1717 assertFunction(t, "packages", nil, res.CodeV2.Blocks[0].Chunks[0]) 1718 assert.Len(t, res.CodeV2.Blocks[0].Chunks, 3) 1719 assertFunction(t, "packages", nil, res.CodeV2.Blocks[0].Chunks[0]) 1720 assertFunction(t, "list", &llx.Function{ 1721 Binding: (1 << 32) | 1, 1722 Type: string(types.Array(types.Resource("package"))), 1723 }, res.CodeV2.Blocks[0].Chunks[1]) 1724 }) 1725 } 1726 1727 func TestCompiler_ResourceWhere(t *testing.T) { 1728 compileT(t, "packages.where(outdated)", func(res *llx.CodeBundle) { 1729 assertFunction(t, "packages", nil, res.CodeV2.Blocks[0].Chunks[0]) 1730 assertFunction(t, "list", &llx.Function{ 1731 Type: string(types.Array(types.Resource("package"))), 1732 Binding: (1 << 32) | 1, 1733 }, res.CodeV2.Blocks[0].Chunks[1]) 1734 assertFunction(t, "where", &llx.Function{ 1735 Type: string(types.Resource("packages")), 1736 Binding: (1 << 32) | 1, 1737 Args: []*llx.Primitive{ 1738 llx.RefPrimitiveV2((1 << 32) | 2), 1739 llx.FunctionPrimitive(2 << 32), 1740 }, 1741 }, res.CodeV2.Blocks[0].Chunks[2]) 1742 1743 assertPrimitive(t, &llx.Primitive{ 1744 Type: string(types.Resource("package")), 1745 }, res.CodeV2.Blocks[1].Chunks[0]) 1746 assertFunction(t, "outdated", &llx.Function{ 1747 Type: string(types.Bool), 1748 Binding: (2 << 32) | 1, 1749 }, res.CodeV2.Blocks[1].Chunks[1]) 1750 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 1751 }) 1752 } 1753 1754 func TestCompiler_ResourceContains(t *testing.T) { 1755 compileT(t, "packages.contains(outdated)", func(res *llx.CodeBundle) { 1756 assertFunction(t, "packages", nil, res.CodeV2.Blocks[0].Chunks[0]) 1757 assertFunction(t, "list", &llx.Function{ 1758 Type: string(types.Array(types.Resource("package"))), 1759 Binding: (1 << 32) | 1, 1760 }, res.CodeV2.Blocks[0].Chunks[1]) 1761 assertFunction(t, "where", &llx.Function{ 1762 Type: string(types.Resource("packages")), 1763 Binding: (1 << 32) | 1, 1764 Args: []*llx.Primitive{ 1765 llx.RefPrimitiveV2((1 << 32) | 2), 1766 llx.FunctionPrimitive(2 << 32), 1767 }, 1768 }, res.CodeV2.Blocks[0].Chunks[2]) 1769 assertFunction(t, "list", &llx.Function{ 1770 Type: string(types.Array(types.Resource("package"))), 1771 Binding: (1 << 32) | 3, 1772 }, res.CodeV2.Blocks[0].Chunks[3]) 1773 assertFunction(t, "length", &llx.Function{ 1774 Type: string(types.Int), 1775 Binding: (1 << 32) | 4, 1776 }, res.CodeV2.Blocks[0].Chunks[4]) 1777 assertFunction(t, string(">"+types.Int), &llx.Function{ 1778 Type: string(types.Bool), 1779 Binding: (1 << 32) | 5, 1780 Args: []*llx.Primitive{llx.IntPrimitive(0)}, 1781 }, res.CodeV2.Blocks[0].Chunks[5]) 1782 1783 assertPrimitive(t, &llx.Primitive{ 1784 Type: string(types.Resource("package")), 1785 }, res.CodeV2.Blocks[1].Chunks[0]) 1786 assertFunction(t, "outdated", &llx.Function{ 1787 Type: string(types.Bool), 1788 Binding: (2 << 32) | 1, 1789 }, res.CodeV2.Blocks[1].Chunks[1]) 1790 assert.Equal(t, []uint64{(2 << 32) | 2}, res.CodeV2.Blocks[1].Entrypoints) 1791 }) 1792 } 1793 1794 // ================ 1795 // 👋 INTERNAL 🍹 1796 // ================ 1797 1798 func TestChecksums(t *testing.T) { 1799 t.Run("no duplicate code IDs", func(t *testing.T) { 1800 dupes := []struct { 1801 qa string 1802 qb string 1803 }{ 1804 { 1805 "users.list { uid == 1 }", 1806 "users.list { uid == 2 }", 1807 }, 1808 { 1809 "asset.platform\nasset.version", 1810 "asset.platform", 1811 }, 1812 { 1813 "asset.platform\nasset.version", 1814 "asset.version", 1815 }, 1816 { 1817 "if (true) { 2 }", 1818 "if (true) { 3 }", 1819 }, 1820 { 1821 "mondoo { version == 'a'}", 1822 "mondoo { version == 'b' version == 'a'}", 1823 }, 1824 } 1825 1826 for i := range dupes { 1827 t.Run(dupes[i].qa+" != "+dupes[i].qb, func(t *testing.T) { 1828 a, err := mqlc.Compile(dupes[i].qa, nil, conf) 1829 assert.NoError(t, err) 1830 b, err := mqlc.Compile(dupes[i].qb, nil, conf) 1831 assert.NoError(t, err) 1832 assert.NotEqual(t, a.CodeV2.Id, b.CodeV2.Id) 1833 }) 1834 } 1835 }) 1836 } 1837 1838 func TestChecksums_block(t *testing.T) { 1839 a, err := mqlc.Compile("mondoo { version == 'a'}", nil, conf) 1840 assert.NoError(t, err) 1841 b, err := mqlc.Compile("mondoo { version == 'b' version == 'a'}", nil, conf) 1842 assert.NoError(t, err) 1843 // make sure the checksum for the block calls are different 1844 assert.NotEqual(t, a.CodeV2.Checksums[4294967298], b.CodeV2.Checksums[4294967298]) 1845 } 1846 1847 func TestSuggestions(t *testing.T) { 1848 tests := []struct { 1849 code string 1850 suggestions []string 1851 err error 1852 requiredFeatures cnquery.Features 1853 }{ 1854 { 1855 "does_not_get_suggestions", 1856 []string{}, 1857 errors.New("cannot find resource for identifier 'does_not_get_suggestions'"), 1858 nil, 1859 }, 1860 { 1861 // resource suggestions 1862 "ssh", 1863 []string{"os.unix.sshd", "sshd", "sshd.config", "windows.security.health"}, 1864 errors.New("cannot find resource for identifier 'ssh'"), 1865 nil, 1866 }, 1867 { 1868 // resource with empty field call 1869 "sshd.", 1870 []string{"config"}, 1871 errors.New("incomplete query, missing identifier after '.' at <source>:1:6"), 1872 nil, 1873 }, 1874 { 1875 // list resource with empty field call 1876 "users.", 1877 []string{"all", "any", "contains", "length", "list", "map", "none", "one", "where"}, 1878 errors.New("incomplete query, missing identifier after '.' at <source>:1:7"), 1879 nil, 1880 }, 1881 { 1882 // resource with partial field call 1883 "sshd.config.para", 1884 []string{"params"}, 1885 errors.New("cannot find field 'para' in sshd.config"), 1886 nil, 1887 }, 1888 { 1889 // resource with partial field call in block 1890 "sshd.config { para }", 1891 []string{"params"}, 1892 errors.New("cannot find field or resource 'para' in block for type 'sshd.config'"), 1893 nil, 1894 }, 1895 { 1896 // native type function call 1897 "sshd.config.params.leng", 1898 []string{"length"}, 1899 errors.New("cannot find field 'leng' in map[string]string"), 1900 nil, 1901 }, 1902 { 1903 // builtin calls 1904 "parse.d", 1905 []string{"date"}, 1906 errors.New("cannot find field 'd' in parse"), 1907 nil, 1908 }, 1909 { 1910 // embedded with asset context on 1911 "docker.containers[0].hostnam", 1912 []string{"hostname"}, 1913 errors.New("cannot find field 'hostnam' in docker.container"), 1914 cnquery.Features{byte(cnquery.MQLAssetContext)}, 1915 }, 1916 { 1917 // embedded with asset context off 1918 "docker.containers[0].hostnam", 1919 []string{}, 1920 errors.New("cannot find field 'hostnam' in docker.container"), 1921 nil, 1922 }, 1923 } 1924 1925 for i := range tests { 1926 cur := tests[i] 1927 t.Run(cur.code, func(t *testing.T) { 1928 nuConf := mqlc.NewConfig(conf.Schema, 1929 append(features, cur.requiredFeatures...)) 1930 res, err := mqlc.Compile(cur.code, nil, nuConf) 1931 assert.Empty(t, res.CodeV2.Entrypoints()) 1932 assert.Equal(t, cur.err.Error(), err.Error()) 1933 1934 suggestions := make([]string, len(res.Suggestions)) 1935 for i := range res.Suggestions { 1936 suggestions[i] = res.Suggestions[i].Field 1937 } 1938 sort.Strings(suggestions) 1939 assert.Equal(t, cur.suggestions, suggestions) 1940 }) 1941 } 1942 } 1943 1944 func TestImplicitSuggestion(t *testing.T) { 1945 res, _ := mqlc.Compile("sshd.", nil, conf) 1946 require.NotEmpty(t, res.Suggestions) 1947 1948 assert.Equal(t, "SSH server configuration", res.Suggestions[0].Title) 1949 } 1950 1951 func TestCompiler_Error(t *testing.T) { 1952 t.Run("unknown term", func(t *testing.T) { 1953 _, err := mqlc.Compile("sshd.config.params == enabled", nil, conf) 1954 // assert.Nil(t, res) 1955 assert.EqualError(t, err, "failed to compile: cannot find resource for identifier 'enabled'") 1956 }) 1957 } 1958 1959 func TestCompiler_Multiline(t *testing.T) { 1960 compileT(t, "1 < 2\n2 != 3", func(res *llx.CodeBundle) { 1961 assert.Equal(t, 4, len(res.CodeV2.Blocks[0].Chunks)) 1962 }) 1963 } 1964 1965 func TestCompiler_Entrypoints(t *testing.T) { 1966 tests := []struct { 1967 code string 1968 datapoints []uint64 1969 entrypoints []uint64 1970 }{ 1971 { 1972 "1", 1973 []uint64(nil), 1974 []uint64{(1 << 32) | 1}, 1975 }, 1976 { 1977 "mondoo.version == 1", 1978 []uint64{(1 << 32) | 2}, 1979 []uint64{(1 << 32) | 3}, 1980 }, 1981 { 1982 "mondoo.version == mondoo.build", 1983 []uint64{(1 << 32) | 2, (1 << 32) | 4}, 1984 []uint64{(1 << 32) | 5}, 1985 }, 1986 { 1987 ` 1988 a = "a" 1989 b = "b" 1990 a == "a" 1991 b == "b" 1992 c = "c" 1993 c == "c" 1994 `, 1995 []uint64{(1 << 32) | 3, (1 << 32) | 5, (1 << 32) | 8}, 1996 []uint64{(1 << 32) | 4, (1 << 32) | 6, (1 << 32) | 9}, 1997 }, 1998 { 1999 ` 2000 a = "a" 2001 b = "b" 2002 a == "a" 2003 b == "b" 2004 c = a == b 2005 c == false 2006 `, 2007 []uint64{(1 << 32) | 3, (1 << 32) | 5, (1 << 32) | 10}, 2008 []uint64{(1 << 32) | 4, (1 << 32) | 6, (1 << 32) | 11}, 2009 }, 2010 } 2011 2012 for i := range tests { 2013 test := tests[i] 2014 t.Run(test.code, func(t *testing.T) { 2015 compileT(t, test.code, func(res *llx.CodeBundle) { 2016 assert.ElementsMatch(t, test.entrypoints, res.CodeV2.Entrypoints()) 2017 assert.Equal(t, test.datapoints, res.CodeV2.Datapoints()) 2018 }) 2019 }) 2020 } 2021 } 2022 2023 func TestCompiler_NestedEntrypoints(t *testing.T) { 2024 tests := []struct { 2025 code string 2026 datapoints []uint64 2027 entrypoints []uint64 2028 }{ 2029 { 2030 ` 2031 if(true) { 2032 a = "a" 2033 b = "b" 2034 a == b 2035 } 2036 `, 2037 []uint64{}, 2038 []uint64{(1 << 32) | 1, (2 << 32) | 5}, 2039 }, 2040 { 2041 ` 2042 if(true) { 2043 a = "a" 2044 b = "b" 2045 a == b 2046 } else { 2047 x = "x" 2048 y = "y" 2049 x == y 2050 } 2051 `, 2052 []uint64{}, 2053 []uint64{(1 << 32) | 1, (2 << 32) | 5, (3 << 32) | 5}, 2054 }, 2055 { 2056 ` 2057 z = "z" 2058 if(z == "z") { 2059 a = "a" 2060 b = "b" 2061 a == b 2062 } else if (z == "a") { 2063 x = "x" 2064 y = "y" 2065 x == y 2066 } else { 2067 j = "j" 2068 k = "k" 2069 j == k 2070 } 2071 `, 2072 []uint64{(1 << 32) | 2}, 2073 []uint64{(1 << 32) | 6, (2 << 32) | 5, (3 << 32) | 5, (4 << 32) | 5}, 2074 }, 2075 { 2076 ` 2077 switch { 2078 case "a" == "a": 2079 a = "a" 2080 b = "b" 2081 a == b; 2082 case "b" == "b": 2083 x = "x" 2084 y = "y" 2085 x == y 2086 } 2087 `, 2088 []uint64{}, 2089 []uint64{(1 << 32) | 5, (2 << 32) | 5, (3 << 32) | 5}, 2090 }, 2091 { 2092 ` 2093 mondoo { 2094 a = "a" 2095 b = "b" 2096 a == b 2097 } 2098 `, 2099 []uint64{}, 2100 []uint64{(1 << 32) | 2, (2 << 32) | 6}, 2101 }, 2102 { 2103 ` 2104 {a: "a"} { 2105 x = "x" 2106 y = "y" 2107 x == y 2108 } 2109 `, 2110 []uint64{}, 2111 []uint64{(1 << 32) | 2, (2 << 32) | 6}, 2112 }, 2113 { 2114 ` 2115 [1,2,3] { 2116 x = "x" 2117 y = "y" 2118 x == y 2119 } 2120 `, 2121 []uint64{}, 2122 []uint64{(1 << 32) | 2, (2 << 32) | 6}, 2123 }, 2124 { 2125 ` 2126 mondoo { 2127 _ 2128 } 2129 `, 2130 []uint64{}, 2131 []uint64{(1 << 32) | 2, (2 << 32) | 1}, 2132 }, 2133 { 2134 ` 2135 mondoo { 2136 a = true 2137 a 2138 } 2139 `, 2140 []uint64{}, 2141 []uint64{(1 << 32) | 2, (2 << 32) | 3}, 2142 }, 2143 { 2144 ` 2145 if(true) { 2146 a = true 2147 a 2148 } 2149 `, 2150 []uint64{}, 2151 []uint64{(1 << 32) | 1, (2 << 32) | 2}, 2152 }, 2153 } 2154 2155 for i := range tests { 2156 test := tests[i] 2157 t.Run(test.code, func(t *testing.T) { 2158 compileT(t, test.code, func(res *llx.CodeBundle) { 2159 entrypoints, datapoints := allCodepoints(res.CodeV2) 2160 assert.ElementsMatch(t, test.entrypoints, entrypoints) 2161 assert.ElementsMatch(t, test.datapoints, datapoints) 2162 }) 2163 }) 2164 } 2165 } 2166 2167 func allCodepoints(code *llx.CodeV2) ([]uint64, []uint64) { 2168 entrypoints := []uint64{} 2169 datapoints := []uint64{} 2170 2171 for _, b := range code.Blocks { 2172 entrypoints = append(entrypoints, b.Entrypoints...) 2173 datapoints = append(datapoints, b.Datapoints...) 2174 } 2175 return entrypoints, datapoints 2176 }