class XCTestList
A class to parse xctest bundles and return a list of tests that are in the bundle's binary.
Public Class Methods
binary_path(xctest_bundle_path)
click to toggle source
add the expected binary to the bundle path and validate that it exists
# 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)
click to toggle source
find the Objective-C symbols in the bundle's binary
# 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")
click to toggle source
# 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")
click to toggle source
find the Swift symbols in the bundle's binary
# 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)
click to toggle source
refactored into its own method to allow mocking in the spec
# File lib/xctest_list.rb, line 8 def self.system(command) `#{command}` end
tests(xctest_bundle_path, swift_test_prefix: 'test')
click to toggle source
find the Objective-C and Swift tests in the binary's bundle
# 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)
click to toggle source
validate that the basic bundle parts exist
# 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