@@ -883,6 +883,136 @@ func TestHasPrefix(t *testing.T) {
883883 }
884884}
885885
886+ func TestHasPatternPrefix (t * testing.T ) {
887+ tests := []struct {
888+ name string
889+ path string
890+ pattern string
891+ expected bool
892+ }{
893+ {
894+ name : "empty pattern" ,
895+ path : "a.b.c" ,
896+ pattern : "" ,
897+ expected : true ,
898+ },
899+ {
900+ name : "empty path" ,
901+ path : "" ,
902+ pattern : "a" ,
903+ expected : false ,
904+ },
905+ {
906+ name : "exact match no wildcards" ,
907+ path : "config" ,
908+ pattern : "config" ,
909+ expected : true ,
910+ },
911+ {
912+ name : "simple prefix no wildcards" ,
913+ path : "a.b" ,
914+ pattern : "a" ,
915+ expected : true ,
916+ },
917+
918+ // .* wildcard
919+ {
920+ name : "dot star matches field" ,
921+ path : "tasks.my_task.notebook_task" ,
922+ pattern : "tasks.*.notebook_task" ,
923+ expected : true ,
924+ },
925+ {
926+ name : "dot star matches any field" ,
927+ path : "tasks.other.notebook_task" ,
928+ pattern : "tasks.*.notebook_task" ,
929+ expected : true ,
930+ },
931+ {
932+ name : "dot star matches index" ,
933+ path : "items[0].name" ,
934+ pattern : "items.*.name" ,
935+ expected : true ,
936+ },
937+ {
938+ name : "dot star as prefix" ,
939+ path : "items[0].name.value" ,
940+ pattern : "items.*" ,
941+ expected : true ,
942+ },
943+
944+ // [*] wildcard
945+ {
946+ name : "bracket star matches index" ,
947+ path : "items[0].name" ,
948+ pattern : "items[*].name" ,
949+ expected : true ,
950+ },
951+ {
952+ name : "bracket star matches field" ,
953+ path : "tasks.my_task.notebook_task" ,
954+ pattern : "tasks[*].notebook_task" ,
955+ expected : true ,
956+ },
957+ {
958+ name : "bracket star matches key-value" ,
959+ path : "tasks[task_key='my_task'].notebook_task" ,
960+ pattern : "tasks[*].notebook_task" ,
961+ expected : true ,
962+ },
963+
964+ // Multiple wildcards
965+ {
966+ name : "multiple wildcards" ,
967+ path : "tasks[0].params[1].value" ,
968+ pattern : "tasks[*].params[*].value" ,
969+ expected : true ,
970+ },
971+
972+ // Non-matches
973+ {
974+ name : "wildcard but wrong suffix" ,
975+ path : "tasks[0].notebook_task" ,
976+ pattern : "tasks[*].spark_task" ,
977+ expected : false ,
978+ },
979+ {
980+ name : "pattern longer than path" ,
981+ path : "tasks[0]" ,
982+ pattern : "tasks[*].notebook_task" ,
983+ expected : false ,
984+ },
985+ {
986+ name : "no wildcard mismatch" ,
987+ path : "a.b.c" ,
988+ pattern : "a.x.c" ,
989+ expected : false ,
990+ },
991+ }
992+
993+ for _ , tt := range tests {
994+ t .Run (tt .name , func (t * testing.T ) {
995+ path , err := ParsePath (tt .path )
996+ require .NoError (t , err )
997+
998+ pattern , err := ParsePattern (tt .pattern )
999+ require .NoError (t , err )
1000+
1001+ result := path .HasPatternPrefix (pattern )
1002+ assert .Equal (t , tt .expected , result , "path.HasPatternPrefix(pattern) where path=%q, pattern=%q" , tt .path , tt .pattern )
1003+
1004+ // If the full pattern matches, every prefix of it must also match.
1005+ if tt .expected {
1006+ for n := range pattern .Len () + 1 {
1007+ prefix := pattern .Prefix (n )
1008+ assert .True (t , path .HasPatternPrefix (prefix ),
1009+ "path=%q pattern=%q prefix_len=%d prefix=%s" , tt .path , tt .pattern , n , prefix )
1010+ }
1011+ }
1012+ })
1013+ }
1014+ }
1015+
8861016func TestPathNodeYAMLMarshal (t * testing.T ) {
8871017 tests := []struct {
8881018 name string
0 commit comments