@@ -465,6 +465,51 @@ TEST_F(sinsp_with_test_input, multivalue_transformer_join) {
465465 EXPECT_THROW (eval_filter (evt, " join(\" a\" , \" b\" ) = foo" ), sinsp_exception);
466466}
467467
468+ TEST_F (sinsp_with_test_input, multivalue_transformer_concat) {
469+ add_default_init_thread ();
470+ open_inspector ();
471+
472+ sinsp_evt* evt;
473+
474+ int64_t dirfd = 3 ;
475+ const char * file_to_run = " /tmp/file_to_run" ;
476+
477+ evt = add_event_advance_ts (increasing_ts (),
478+ 1 ,
479+ PPME_SYSCALL_OPEN_X,
480+ 6 ,
481+ dirfd,
482+ file_to_run,
483+ 0 ,
484+ 0 ,
485+ 0 ,
486+ (uint64_t )0 );
487+
488+ EXPECT_TRUE (eval_filter (evt, " concat(fd.name, fd.directory) = /tmp/file_to_run/tmp" ));
489+ EXPECT_TRUE (eval_filter (evt, " concat(\" aaa\" , \" bbb\" ) = aaabbb" ));
490+ EXPECT_TRUE (eval_filter (evt, " concat(\" aaa\" , \" bbb\" , \" ccc\" ) = aaabbbccc" ));
491+ EXPECT_TRUE (eval_filter (evt, " concat(fd.name, \" aaa\" ) = /tmp/file_to_runaaa" ));
492+ EXPECT_TRUE (
493+ eval_filter (evt, " concat(fd.name, \" aaa\" , fd.directory) = /tmp/file_to_runaaa/tmp" ));
494+ EXPECT_TRUE (eval_filter (evt, " concat(toupper(fd.name), \" aaa\" ) = /TMP/FILE_TO_RUNaaa" ));
495+ EXPECT_TRUE (eval_filter (evt, " concat(\" aaa\" , toupper(fd.name)) = aaa/TMP/FILE_TO_RUN" ));
496+ EXPECT_TRUE (eval_filter (
497+ evt,
498+ " concat(fd.directory, concat(\" aaa\" , toupper(fd.name))) = /tmpaaa/TMP/FILE_TO_RUN" ));
499+ EXPECT_TRUE (eval_filter (evt, " concat(\" aaa\" , \" bbb\" ) = \" aaabbb\" " ));
500+ EXPECT_FALSE (eval_filter (evt, " concat(\" aaa\" , \" bbb\" ) = \" aaa-bbb\" " ));
501+
502+ // Validation error tests
503+ // concat() requires at least 2 arguments
504+ EXPECT_THROW (eval_filter (evt, " concat() = foo" ), sinsp_exception);
505+ EXPECT_THROW (eval_filter (evt, " concat(\" aaa\" ) = foo" ), sinsp_exception);
506+ // concat() arguments must be strings (not lists)
507+ EXPECT_THROW (eval_filter (evt, " concat(fd.types, \" a\" ) = foo" ), sinsp_exception);
508+ EXPECT_THROW (eval_filter (evt, " concat((\" a\" , \" b\" ), \" a\" ) = foo" ), sinsp_exception);
509+ EXPECT_THROW (eval_filter (evt, " concat(\" a\" , (\" a\" , \" b\" )) = foo" ), sinsp_exception);
510+ EXPECT_THROW (eval_filter (evt, " concat((\" a\" , \" b\" ), (\" a\" , \" b\" )) = foo" ), sinsp_exception);
511+ }
512+
468513TEST_F (sinsp_with_test_input, multivalue_transformer_with_outer_transformer) {
469514 add_default_init_thread ();
470515 open_inspector ();
@@ -519,6 +564,37 @@ TEST_F(sinsp_with_test_input, multivalue_transformer_with_outer_transformer) {
519564 EXPECT_TRUE (eval_filter (evt, " len(join(\" -\" , (fd.name, fd.directory))) > 20" ));
520565 EXPECT_TRUE (eval_filter (evt, " len(join(\" -\" , (fd.name, fd.directory))) >= 21" ));
521566 EXPECT_TRUE (eval_filter (evt, " len(join(\" -\" , (fd.name, fd.directory))) < 22" ));
567+
568+ // Apply toupper to concat result
569+ EXPECT_TRUE (eval_filter (evt, " toupper(concat(fd.name, fd.directory)) = /TMP/FILE_TO_RUN/TMP" ));
570+ EXPECT_TRUE (eval_filter (evt, " toupper(concat(\" aaa\" , \" bbb\" )) = AAABBB" ));
571+
572+ // Apply tolower to concat result
573+ EXPECT_TRUE (eval_filter (evt, " tolower(concat(fd.name, fd.directory)) = /tmp/file_to_run/tmp" ));
574+ EXPECT_TRUE (eval_filter (evt, " tolower(concat(\" AAA\" , \" BBB\" )) = aaabbb" ));
575+
576+ // Apply len to concat result
577+ // fd.name = /tmp/file_to_run (16 chars), fd.directory = /tmp (4 chars)
578+ // Total = 16 + 4 = 20
579+ EXPECT_TRUE (eval_filter (evt, " len(concat(fd.name, fd.directory)) = 20" ));
580+ EXPECT_TRUE (eval_filter (evt, " len(concat(\" aaa\" , \" bbb\" )) = 6" ));
581+
582+ // Apply b64 to concat result
583+ // "aaabbb" in base64 is "YWFhYmJi"
584+ EXPECT_TRUE (eval_filter (evt, " concat(\" aaa\" , \" bbb\" ) = \" aaabbb\" " ));
585+ EXPECT_TRUE (eval_filter (evt, " b64(concat(\" YWFh\" , \" YmJi\" )) = \" aaabbb\" " ));
586+
587+ // Chain multiple transformers on concat result
588+ EXPECT_TRUE (
589+ eval_filter (evt,
590+ " toupper(tolower(concat(fd.name, fd.directory))) = /TMP/FILE_TO_RUN/TMP" ));
591+
592+ // Combine with comparison operators
593+ EXPECT_TRUE (eval_filter (evt, " toupper(concat(fd.name, fd.directory)) contains /TMP" ));
594+ EXPECT_TRUE (eval_filter (evt, " toupper(concat(fd.name, fd.directory)) startswith /TMP" ));
595+ EXPECT_TRUE (eval_filter (evt, " len(concat(fd.name, fd.directory)) > 19" ));
596+ EXPECT_TRUE (eval_filter (evt, " len(concat(fd.name, fd.directory)) >= 20" ));
597+ EXPECT_TRUE (eval_filter (evt, " len(concat(fd.name, fd.directory)) < 21" ));
522598}
523599
524600TEST (multivalue_transformer, argument_types) {
@@ -584,3 +660,44 @@ TEST(multivalue_transformer, result_type) {
584660 EXPECT_EQ (result.type , PT_CHARBUF);
585661 EXPECT_FALSE (result.is_list );
586662}
663+
664+ TEST (multivalue_transformer_concat, argument_types) {
665+ // Create arguments for concat: multiple strings
666+ std::vector<std::unique_ptr<sinsp_filter_check>> args;
667+
668+ // First argument: a string
669+ args.push_back (std::make_unique<rawstring_check>(" aaa" ));
670+
671+ // Second argument: another string
672+ args.push_back (std::make_unique<rawstring_check>(" bbb" ));
673+
674+ // Third argument: another string
675+ args.push_back (std::make_unique<rawstring_check>(" ccc" ));
676+
677+ // Create the concat transformer
678+ sinsp_filter_multivalue_transformer_concat concat_transformer (std::move (args));
679+
680+ // Test argument_types()
681+ const auto & arg_types = concat_transformer.argument_types ();
682+
683+ ASSERT_EQ (arg_types.size (), 3 );
684+
685+ // All arguments should be PT_CHARBUF and not lists
686+ for (size_t i = 0 ; i < arg_types.size (); i++) {
687+ EXPECT_EQ (arg_types[i].type , PT_CHARBUF);
688+ EXPECT_FALSE (arg_types[i].is_list );
689+ }
690+ }
691+
692+ TEST (multivalue_transformer_concat, result_type) {
693+ std::vector<std::unique_ptr<sinsp_filter_check>> args;
694+ args.push_back (std::make_unique<rawstring_check>(" aaa" ));
695+ args.push_back (std::make_unique<rawstring_check>(" bbb" ));
696+
697+ sinsp_filter_multivalue_transformer_concat concat_transformer (std::move (args));
698+
699+ // concat should return PT_CHARBUF and not a list
700+ auto result = concat_transformer.result_type ();
701+ EXPECT_EQ (result.type , PT_CHARBUF);
702+ EXPECT_FALSE (result.is_list );
703+ }
0 commit comments