Class: XCTestList

Inherits:
Object
  • Object
show all
Defined in:
lib/xctest_list.rb

Overview

A class to parse xctest bundles and return a list of tests that are in the bundle’s binary.

Class Method Summary collapse

Class Method Details

.binary_path(xctest_bundle_path) ⇒ Object

add the expected binary to the bundle path and validate that it exists



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/xctest_list.rb', line 21

def self.binary_path(xctest_bundle_path)
  validate_bundle(xctest_bundle_path)

  xctest_binary_name = File.basename(xctest_bundle_path, '.*')
  xctest_binary_path = File.join(xctest_bundle_path, xctest_binary_name)
  unless File.exist?(xctest_binary_path)
    xctest_binary_path = File.join(xctest_bundle_path, 'Contents', 'MacOS', xctest_binary_name)
  end

  unless File.exist?(xctest_binary_path)
    raise "Missing xctest binary: '#{xctest_binary_path}'"
  end

  xctest_binary_path
end

.objc_tests(xctest_bundle_path) ⇒ Object

find the Objective-C symbols in the bundle’s binary



38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/xctest_list.rb', line 38

def self.objc_tests(xctest_bundle_path)
  tests = []
  objc_symbols_command_output_tempfile = Tempfile.new(File.basename(xctest_bundle_path) + "objc")
  system("nm -U '#{binary_path(xctest_bundle_path)}' > '#{objc_symbols_command_output_tempfile.path}'")
  tests = []
  File.foreach(objc_symbols_command_output_tempfile.path) do |line|
    regex = / t -\[(?<testclass>\w+) (?<testmethod>test\w*)\]/
    if (matches = regex.match(line))
      tests << "#{matches[:testclass]}/#{matches[:testmethod]}"
    end
  end
  tests
end

.swift_symbol_dump_command(xctest_binary_path, swift_test_prefix: "test") ⇒ Object



52
53
54
55
56
57
58
59
# File 'lib/xctest_list.rb', line 52

def self.swift_symbol_dump_command(xctest_binary_path, swift_test_prefix: "test")
  nm_version_string = `nm -version | head -n 1 | sed -E 's/Apple LLVM version ([0-9]+\.[0-9]+\.[0-9]+).*/\\1/'`.chomp
  if Gem::Version.new(nm_version_string) < Gem::Version.new('9.0.0')
    "nm -gU '#{xctest_binary_path}' | cut -d' ' -f3 | xcrun swift-demangle | grep -E '^\\S+\\.test[^.]+\\(\\)$' | sed 's/ () -> ()/()/'"
  else
    "nm -gU '#{xctest_binary_path}' | cut -d' ' -f3 | xargs -s 131072 xcrun swift-demangle | cut -d' ' -f3 | grep -e '[\\.|_]'#{swift_test_prefix}"
  end
end

.swift_tests(xctest_bundle_path, swift_test_prefix: "test") ⇒ Object

find the Swift symbols in the bundle’s binary



62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/xctest_list.rb', line 62

def self.swift_tests(xctest_bundle_path, swift_test_prefix: "test")
  swift_symbols_command_output_tempfile = Tempfile.new(File.basename(xctest_bundle_path) + "swift")
  system("#{swift_symbol_dump_command(binary_path(xctest_bundle_path), swift_test_prefix: swift_test_prefix)}  > '#{swift_symbols_command_output_tempfile.path}'")
  tests = []
  File.foreach(swift_symbols_command_output_tempfile.path) do |line|
    regex = /\w+\.(?<testclass>[^\.]+)\.(?<testmethod>#{swift_test_prefix}[^\(]*)\(/
    if /.*-\[.*\]/ !~ line && (matches = regex.match(line))
      tests << "#{matches[:testclass]}/#{matches[:testmethod]}"
    end
  end
  tests
end

.system(command) ⇒ Object

refactored into its own method to allow mocking in the spec



8
9
10
# File 'lib/xctest_list.rb', line 8

def self.system(command)
  `#{command}`
end

.tests(xctest_bundle_path, swift_test_prefix: 'test') ⇒ Object

find the Objective-C and Swift tests in the binary’s bundle



76
77
78
# File 'lib/xctest_list.rb', line 76

def self.tests(xctest_bundle_path, swift_test_prefix: 'test')
  objc_tests(xctest_bundle_path) | swift_tests(xctest_bundle_path, swift_test_prefix: swift_test_prefix)
end

.validate_bundle(xctest_bundle_path) ⇒ Object

validate that the basic bundle parts exist



13
14
15
16
17
18
# File 'lib/xctest_list.rb', line 13

def self.validate_bundle(xctest_bundle_path)
  raise "Cannot find xctest bundle at path: '#{xctest_bundle_path}'" unless Dir.exist?(xctest_bundle_path)

  is_xctest_bundle = File.extname(xctest_bundle_path) == '.xctest'
  raise "Invalid xctest bundle given: '#{xctest_bundle_path}'" unless is_xctest_bundle
end