; Functions names start with `Test`
(((function_declaration
  name: (_) @run
  (#match? @run "^Test.*")
  (#not-match? @run "^TestMain$"))) @_
  (#set! tag go-test))

; Suite test methods (testify/suite)
((method_declaration
  receiver: (parameter_list
    (parameter_declaration
      type: [
        (pointer_type
          (type_identifier) @_suite_name)
        (type_identifier) @_suite_name
      ]))
  name: (field_identifier) @run @_subtest_name
  (#match? @_subtest_name "^Test.*")
  (#match? @_suite_name ".*Suite")) @_
  (#set! tag go-testify-suite))

; `go:generate` comments
(((comment) @_comment @run
  (#match? @_comment "^//go:generate"))
  (#set! tag go-generate))

; `t.Run`
(((call_expression
  function: (selector_expression
    field: _ @run @_name
    (#eq? @_name "Run"))
  arguments: (argument_list
    .
    [
      (interpreted_string_literal)
      (raw_string_literal)
    ] @_subtest_name
    .
    (func_literal
      parameters: (parameter_list
        (parameter_declaration
          name: (identifier) @_param_name
          type: (pointer_type
            (qualified_type
              package: (package_identifier) @_pkg
              name: (type_identifier) @_type
              (#eq? @_pkg "testing")
              (#eq? @_type "T")))))) @_second_argument))) @_
  (#set! tag go-subtest))

; Functions names start with `Example`
(((function_declaration
  name: (_) @run @_name
  (#match? @_name "^Example.*"))) @_
  (#set! tag go-example))

; Functions names start with `Benchmark`
(((function_declaration
  name: (_) @run @_name
  (#match? @_name "^Benchmark.*"))) @_
  (#set! tag go-benchmark))

; Functions names start with `Fuzz`
(((function_declaration
  name: (_) @run @_name
  (#match? @_name "^Fuzz"))) @_
  (#set! tag go-fuzz))

; go run
(((function_declaration
  name: (_) @run
  (#eq? @run "main"))) @_
  (#set! tag go-main))

; Table test cases - slice and map with explicit variable
((short_var_declaration
  left: (expression_list
    (identifier) @_collection_var)
  right: (expression_list
    (composite_literal
      type: [
        (slice_type)
        (map_type
          key: (type_identifier) @_key_type
          (#eq? @_key_type "string"))
      ]
      body: (literal_value
        [
          (literal_element
            (literal_value
              (keyed_element
                (literal_element
                  (identifier) @_field_name)
                (literal_element
                  [
                    (interpreted_string_literal) @run @_table_test_case_name
                    (raw_string_literal) @run @_table_test_case_name
                  ]))))
          (keyed_element
            (literal_element
              [
                (interpreted_string_literal) @run @_table_test_case_name
                (raw_string_literal) @run @_table_test_case_name
              ]))
        ]))))
  (for_statement
    (range_clause
      left: (expression_list
        [
          ((identifier)
            (identifier) @_loop_var_inner)
          (identifier) @_loop_var_outer
        ])
      right: (identifier) @_range_var
      (#eq? @_range_var @_collection_var))
    body: (block
      (statement_list
        (expression_statement
          (call_expression
            function: (selector_expression
              operand: (identifier)
              field: (field_identifier) @_run_method
              (#eq? @_run_method "Run"))
            arguments: (argument_list
              .
              [
                (selector_expression
                  operand: (identifier) @_tc_var
                  (#eq? @_tc_var @_loop_var_inner)
                  field: (field_identifier) @_field_check
                  (#eq? @_field_check @_field_name))
                (identifier) @_arg_var
                (#eq? @_arg_var @_loop_var_outer)
              ]
              .
              (func_literal
                parameters: (parameter_list
                  (parameter_declaration
                    type: (pointer_type
                      (qualified_type
                        package: (package_identifier) @_pkg
                        name: (type_identifier) @_type
                        (#eq? @_pkg "testing")
                        (#eq? @_type "T")))))))))))) @_
  (#set! tag go-table-test-case))

; Table test cases - slice and map declared right inside the loop without
; explicit variable
((for_statement
  (range_clause
    left: (expression_list
      [
        ((identifier)
          (identifier) @_loop_var_inner)
        (identifier) @_loop_var_outer
      ])
    right: (composite_literal
      type: [
        (slice_type)
        (map_type
          key: (type_identifier) @_key_type
          (#eq? @_key_type "string"))
      ]
      body: (literal_value
        [
          (literal_element
            (literal_value
              (keyed_element
                (literal_element
                  (identifier) @_field_name)
                (literal_element
                  [
                    (interpreted_string_literal) @run @_table_test_case_name
                    (raw_string_literal) @run @_table_test_case_name
                  ]))))
          (keyed_element
            (literal_element
              [
                (interpreted_string_literal) @run @_table_test_case_name
                (raw_string_literal) @run @_table_test_case_name
              ]))
        ])))
  body: (block
    (statement_list
      (expression_statement
        (call_expression
          function: (selector_expression
            operand: (identifier)
            field: (field_identifier) @_run_method
            (#eq? @_run_method "Run"))
          arguments: (argument_list
            .
            [
              (selector_expression
                operand: (identifier) @_tc_var
                (#eq? @_tc_var @_loop_var_inner)
                field: (field_identifier) @_field_check
                (#eq? @_field_check @_field_name))
              (identifier) @_arg_var
              (#eq? @_arg_var @_loop_var_outer)
            ]
            .
            (func_literal
              parameters: (parameter_list
                (parameter_declaration
                  type: (pointer_type
                    (qualified_type
                      package: (package_identifier) @_pkg
                      name: (type_identifier) @_type
                      (#eq? @_pkg "testing")
                      (#eq? @_type "T")))))))))))) @_
  (#set! tag go-table-test-case-without-explicit-variable))
