16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
# File 'lib/canopus/test_runner/minitest.rb', line 16
def discover(root, path:, limit:, cancelled:)
require "prism"
path = path.dup.freeze
tests, visited = [], 0
stack = [[root, [].freeze, :none, nil]]
until stack.empty? || tests.length >= limit
break if cancelled.call
node, groups, scope, spec_count = stack.pop
break if (visited += 1) > MAX_NODES
case node
when Prism::ClassNode
group = name(node.constant_path, rootless: true)
children = group && groups.length < MAX_GROUP_DEPTH ? [*groups, group].freeze : groups
class_scope = spec_class?(node) ? :spec_class : :class
stack << [node.body, children, class_scope, class_scope == :spec_class ? [0] : nil] if node.body
when Prism::ModuleNode
group = name(node.constant_path, rootless: true)
children = group && groups.length < MAX_GROUP_DEPTH ? [*groups, group].freeze : groups
stack << [node.body, children, :none, nil] if node.body
when Prism::SingletonClassNode
next
when Prism::DefNode
method_name = name(node.name.to_s)
if [:class, :spec_class].include?(scope) && !node.receiver && method_name&.start_with?("test_")
add(tests, path, method_name, groups, node, method_name)
end
when Prism::CallNode
if group_call?(node) && groups.length < MAX_GROUP_DEPTH && (group = group_name(node))
parent = [:spec, :spec_class].include?(scope) ? groups : []
stack << [node.block.body, [*parent, group].freeze, :spec, [0]] if node.block.body
elsif spec_test_call?(node, scope)
selector = format("test_%04d_%s", spec_count[0] += 1, (test_name = literal_argument_name(node)))
add(tests, path, test_name, groups, node, selector) if test_name
elsif class_test_call?(node, scope) && (test_name = literal_argument_name(node))
add(tests, path, test_name, groups, node, "test_#{test_name.gsub(/\s+/, "_")}")
else
push_children(stack, node, groups, scope, spec_count) unless node.block
end
else
push_children(stack, node, groups, scope, spec_count)
end
end
tests.freeze
end
|