diff --git a/lib/app_info/dsym.rb b/lib/app_info/dsym.rb index f4dcf74..c60ef30 100644 --- a/lib/app_info/dsym.rb +++ b/lib/app_info/dsym.rb @@ -1,74 +1,24 @@ # frozen_string_literal: true -require 'macho' +require 'app_info/dsym/debug_info' module AppInfo # DSYM parser class DSYM < File include Helper::Archive - attr_reader :file - def file_type Format::DSYM end - def object - @object ||= ::File.basename(app_path) - end - - def macho_type - @macho_type ||= ::MachO.open(app_path) - end - - def machos - @machos ||= case macho_type - when ::MachO::MachOFile - [MachO.new(macho_type, ::File.size(app_path))] - else - size = macho_type.fat_archs.each_with_object([]) do |arch, obj| - obj << arch.size - end - - machos = [] - macho_type.machos.each_with_index do |file, i| - machos << MachO.new(file, size[i]) - end - machos - end - end - - def release_version - info.try(:[], 'CFBundleShortVersionString') - end - - def build_version - info.try(:[], 'CFBundleVersion') - end - - def identifier - info.try(:[], 'CFBundleIdentifier').sub('com.apple.xcode.dsym.', '') - end - alias bundle_id identifier - - def info - return nil unless ::File.exist?(info_path) - - @info ||= CFPropertyList.native_types(CFPropertyList::List.new(file: info_path).value) - end - - def info_path - @info_path ||= ::File.join(contents, 'Contents', 'Info.plist') + def each_file(&block) + files.each { |file| block.call(file) } end - def app_path - unless @app_path - path = ::File.join(contents, 'Contents', 'Resources', 'DWARF') - name = Dir.entries(path).reject { |f| ['.', '..'].include?(f) }.first - @app_path = ::File.join(path, name) + def files + @files ||= Dir.children(contents).each_with_object([]) do |file, obj| + obj << DebugInfo.new(::File.join(contents, file)) end - - @app_path end def clear! @@ -77,85 +27,32 @@ def clear! FileUtils.rm_rf(@contents) @contents = nil - @app_path = nil - @info = nil - @object = nil - @macho_type = nil + @files = nil end def contents - unless @contents - if ::File.directory?(@file) - @contents = @file - else - dsym_dir = nil - @contents = unarchive(@file, prefix: 'dsym') do |path, zip_file| - zip_file.each do |f| - unless dsym_dir - dsym_dir = f.name - # fix filename is xxx.app.dSYM/Contents - dsym_dir = dsym_dir.split('/')[0] if dsym_dir.include?('/') - end + @contents ||= lambda { + return @file if ::File.directory?(@file) - f_path = ::File.join(path, f.name) - FileUtils.mkdir_p(::File.dirname(f_path)) - f.extract(f_path) unless ::File.exist?(f_path) - end - end + dsym_filenames = [] + unarchive(@file, prefix: 'dsym') do |base_path, zip_file| + zip_file.each do |entry| + file_path = entry.name + next unless file_path.downcase.include?('.dsym/contents/') + next if ::File.basename(file_path).start_with?('.') - @contents = ::File.join(@contents, dsym_dir) - end - end + dsym_filename = file_path.split('/').select { |f| f.downcase.end_with?('.dsym') }.last + dsym_filenames << dsym_filename unless dsym_filenames.include?(dsym_filename) - @contents - end - - # DSYM Mach-O - class MachO - include Helper::HumanFileSize - - def initialize(file, size = 0) - @file = file - @size = size - end - - def cpu_name - @file.cpusubtype - end - - def cpu_type - @file.cputype - end - - def type - @file.filetype - end - - def size(human_size: false) - return number_to_human_size(@size) if human_size - - @size - end - - def uuid - @file[:LC_UUID][0].uuid_string - end - alias debug_id uuid - - def header - @header ||= @file.header - end + unless file_path.start_with?(dsym_filename) + file_path = file_path.split('/')[1..-1].join('/') + end - def to_h - { - uuid: uuid, - type: type, - cpu_name: cpu_name, - cpu_type: cpu_type, - size: size, - human_size: size(human_size: true) - } - end + dest_path = ::File.join(base_path, file_path) + entry.extract(dest_path) unless ::File.exist?(dest_path) + end + end + }.call end end end diff --git a/lib/app_info/dsym/debug_info.rb b/lib/app_info/dsym/debug_info.rb new file mode 100644 index 0000000..63237dc --- /dev/null +++ b/lib/app_info/dsym/debug_info.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'app_info/dsym/macho' + +module AppInfo + class DSYM < File + # DSYM Debug Information Format Struct + class DebugInfo + attr_reader :path + + def initialize(path) + @path = path + end + + def object + @object ||= ::File.basename(bin_path) + end + + def macho_type + @macho_type ||= ::MachO.open(bin_path) + end + + def machos + @machos ||= case macho_type + when ::MachO::MachOFile + [MachO.new(macho_type, ::File.size(bin_path))] + else + size = macho_type.fat_archs.each_with_object([]) do |arch, obj| + obj << arch.size + end + + machos = [] + macho_type.machos.each_with_index do |file, i| + machos << MachO.new(file, size[i]) + end + machos + end + end + + def release_version + info.try(:[], 'CFBundleShortVersionString') + end + + def build_version + info.try(:[], 'CFBundleVersion') + end + + def identifier + info.try(:[], 'CFBundleIdentifier').sub('com.apple.xcode.dsym.', '') + end + alias bundle_id identifier + + def info + return nil unless ::File.exist?(info_path) + + @info ||= CFPropertyList.native_types(CFPropertyList::List.new(file: info_path).value) + end + + def info_path + @info_path ||= ::File.join(path, 'Contents', 'Info.plist') + end + + def bin_path + @bin_path ||= lambda { + dwarf_path = ::File.join(path, 'Contents', 'Resources', 'DWARF') + name = Dir.children(dwarf_path)[0] + ::File.join(dwarf_path, name) + }.call + end + end + end +end diff --git a/lib/app_info/dsym/macho.rb b/lib/app_info/dsym/macho.rb new file mode 100644 index 0000000..c424f51 --- /dev/null +++ b/lib/app_info/dsym/macho.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'macho' + +module AppInfo + class DSYM < File + # Mach-O Struct + class MachO + include Helper::HumanFileSize + + def initialize(file, size = 0) + @file = file + @size = size + end + + def cpu_name + @file.cpusubtype + end + + def cpu_type + @file.cputype + end + + def type + @file.filetype + end + + def size(human_size: false) + return number_to_human_size(@size) if human_size + + @size + end + + def uuid + @file[:LC_UUID][0].uuid_string + end + alias debug_id uuid + + def header + @header ||= @file.header + end + + def to_h + { + uuid: uuid, + type: type, + cpu_name: cpu_name, + cpu_type: cpu_type, + size: size, + human_size: size(human_size: true) + } + end + end + end +end diff --git a/lib/app_info/helper.rb b/lib/app_info/helper.rb index bff1d7c..0ac290e 100644 --- a/lib/app_info/helper.rb +++ b/lib/app_info/helper.rb @@ -87,28 +87,28 @@ module Archive # Unarchive zip file # # source: https://github.com/soffes/lagunitas/blob/master/lib/lagunitas/ipa.rb - def unarchive(file, prefix:, base_path: '/tmp') - root_path = Dir.mktmpdir('appinfo-#{prefix}', base_path) + def unarchive(file, prefix:, dest_path: '/tmp') + base_path = Dir.mktmpdir("appinfo-#{prefix}", dest_path) Zip::File.open(file) do |zip_file| if block_given? - yield root_path, zip_file + yield base_path, zip_file else zip_file.each do |f| - f_path = ::File.join(root_path, f.name) + f_path = ::File.join(base_path, f.name) FileUtils.mkdir_p(::File.dirname(f_path)) zip_file.extract(f, f_path) unless ::File.exist?(f_path) end end end - root_path + base_path end def tempdir(file, prefix:, system: false) base_path = system ? '/tmp' : ::File.dirname(file) full_prefix = "appinfo-#{prefix}-#{::File.basename(file, '.*')}" dest_path = Dir.mktmpdir(full_prefix, base_path) - dest_file = ::File.join(dest_path, ::File.basename(file)) + ::File.join(dest_path, ::File.basename(file)) end end diff --git a/spec/app_info/dsym_spec.rb b/spec/app_info/dsym_spec.rb index 6b3c96c..ef55ee1 100644 --- a/spec/app_info/dsym_spec.rb +++ b/spec/app_info/dsym_spec.rb @@ -1,86 +1,267 @@ describe AppInfo::DSYM do - describe '#SingleMachO' do - subject { AppInfo::DSYM.new(fixture_path('dsyms/single_ios.dSYM.zip')) } + describe 'Single dSYM in a zip file' do + describe 'when single mach-o' do + subject { AppInfo::DSYM.new(fixture_path('dsyms/iOS-single-dSYM-with-single-macho.zip')) } + let(:data) { + { + type: :dsym, + uuid: 'ea9bbf2d-bfdd-3ce0-85b2-1cbe7152fca5', + cpu_type: :arm64, + cpu_name: :arm64, + size: 866_911, + human_size: '846.59 KB' + } + } + after { subject.clear! } + context do + it { expect(subject.file).to eq fixture_path('dsyms/iOS-single-dSYM-with-single-macho.zip') } + it { expect(subject.file_type).to eq AppInfo::Format::DSYM } + it { expect(subject.file_type).to eq :dsym } + it { expect(subject.files.size).to eq 1 } + it { expect(subject.files[0].object).to eq 'iOS' } + it { expect(subject.files[0].macho_type).to be_a ::MachO::MachOFile } + it { expect(subject.files[0].release_version).to eq '1.0' } + it { expect(subject.files[0].build_version).to eq '1' } + it { expect(subject.files[0].identifier).to eq 'com.icyleaf.iOS' } + it { expect(subject.files[0].bundle_id).to eq 'com.icyleaf.iOS' } + it { expect(subject.files[0].machos.size).to eq 1 } + it { expect(subject.files[0].machos[0].type).to eq data[:type] } + it { expect(subject.files[0].machos[0].uuid).to eq data[:uuid] } + it { expect(subject.files[0].machos[0].cpu_type).to eq data[:cpu_type] } + it { expect(subject.files[0].machos[0].cpu_name).to eq data[:cpu_name] } + it { expect(subject.files[0].machos[0].size).to eq data[:size] } + it { expect(subject.files[0].machos[0].size(human_size: true)).to eq data[:human_size] } + it { expect(subject.files[0].machos[0].to_h).to eq data } + end + end + + describe 'when single mach-o' do + subject { AppInfo::DSYM.new(fixture_path('dsyms/iOS-single-dSYM-with-multi-macho.zip')) } + let(:data) { + [ + { + type: :dsym, + uuid: '26dfc15d-bdce-351f-b5de-6ee9f5dd6d85', + cpu_type: :arm, + cpu_name: :armv7, + size: 866_526, + human_size: '846.22 KB' + }, + { + type: :dsym, + uuid: '17f58291-dd25-3fc8-9417-ccbe8163d33e', + cpu_type: :arm64, + cpu_name: :arm64, + size: 866_911, + human_size: '846.59 KB' + } + ] + } + after { subject.clear! } + context '.parse' do + it { expect(subject.file).to eq fixture_path('dsyms/iOS-single-dSYM-with-multi-macho.zip') } + it { expect(subject.file_type).to eq AppInfo::Format::DSYM } + it { expect(subject.file_type).to eq :dsym } + it { expect(subject.files.size).to eq 1 } + it { expect(subject.files[0].object).to eq 'iOS' } + it { expect(subject.files[0].macho_type).to be_a ::MachO::FatFile } + it { expect(subject.files[0].release_version).to eq '1.0' } + it { expect(subject.files[0].build_version).to eq '2' } + it { expect(subject.files[0].identifier).to eq 'com.icyleaf.iOS' } + it { expect(subject.files[0].bundle_id).to eq 'com.icyleaf.iOS' } + it { expect(subject.files[0].machos.size).to eq 2} + it { expect(subject.files[0].machos[0].type).to eq data[0][:type] } + it { expect(subject.files[0].machos[0].uuid).to eq data[0][:uuid] } + it { expect(subject.files[0].machos[0].cpu_type).to eq data[0][:cpu_type] } + it { expect(subject.files[0].machos[0].cpu_name).to eq data[0][:cpu_name] } + it { expect(subject.files[0].machos[0].size).to eq data[0][:size] } + it { expect(subject.files[0].machos[0].size(human_size: true)).to eq data[0][:human_size] } + it { expect(subject.files[0].machos[0].to_h).to eq data[0] } + it { expect(subject.files[0].machos[1].type).to eq data[1][:type] } + it { expect(subject.files[0].machos[1].uuid).to eq data[1][:uuid] } + it { expect(subject.files[0].machos[1].cpu_type).to eq data[1][:cpu_type] } + it { expect(subject.files[0].machos[1].cpu_name).to eq data[1][:cpu_name] } + it { expect(subject.files[0].machos[1].size).to eq data[1][:size] } + it { expect(subject.files[0].machos[1].size(human_size: true)).to eq data[1][:human_size] } + it { expect(subject.files[0].machos[1].to_h).to eq data[1] } + end + end + end + + describe 'Multi dSYM in a zip file' do after { subject.clear! } - context 'parse' do - data = { - type: :dsym, - uuid: 'ea9bbf2d-bfdd-3ce0-85b2-1cbe7152fca5', - cpu_type: :arm64, - cpu_name: :arm64, - size: 866_911, - human_size: '846.59 KB' + describe 'when dSYM in root path' do + let(:file) { fixture_path('dsyms/iOS-mutli-dSYMs-directly.zip') } + subject { AppInfo::DSYM.new(file) } + let(:data) { + [ + { + type: :dsym, + uuid: '52e65dbe-8234-3387-b733-c5044e26653f', + cpu_type: :arm64, + cpu_name: :arm64, + size: 1_029_092, + human_size: '1004.97 KB' + }, + { + type: :dsym, + uuid: '628e9796-746c-3fec-91e7-586b4bed352a', + cpu_type: :arm64, + cpu_name: :arm64, + size: 988_131, + human_size: '964.97 KB' + } + ] } - it { expect(subject.file_type).to eq AppInfo::Format::DSYM } - it { expect(subject.file_type).to eq :dsym } - it { expect(subject.object).to eq 'iOS' } - it { expect(subject.macho_type).to be_a ::MachO::MachOFile } - it { expect(subject.release_version).to eq '1.0' } - it { expect(subject.build_version).to eq '1' } - it { expect(subject.identifier).to eq 'com.icyleaf.iOS' } - it { expect(subject.bundle_id).to eq 'com.icyleaf.iOS' } - it { expect(subject.machos.size).to eq 1 } - it { expect(subject.machos[0].type).to eq data[:type] } - it { expect(subject.machos[0].uuid).to eq data[:uuid] } - it { expect(subject.machos[0].cpu_type).to eq data[:cpu_type] } - it { expect(subject.machos[0].cpu_name).to eq data[:cpu_name] } - it { expect(subject.machos[0].size).to eq data[:size] } - it { expect(subject.machos[0].size(human_size: true)).to eq data[:human_size] } - it { expect(subject.machos[0].to_h).to eq data } + context do + it { expect(subject.file).to eq file } + it { expect(subject.file_type).to eq AppInfo::Format::DSYM } + it { expect(subject.file_type).to eq :dsym } + it { expect(subject.files.size).to eq 2 } + it { expect(subject.files[0].object).to eq 'AppInfo' } + it { expect(subject.files[0].macho_type).to be_a ::MachO::MachOFile } + it { expect(subject.files[0].release_version).to eq '1.0' } + it { expect(subject.files[0].build_version).to eq '1' } + it { expect(subject.files[0].identifier).to eq 'im.ews.ios.AppInfo' } + it { expect(subject.files[0].bundle_id).to eq 'im.ews.ios.AppInfo' } + it { expect(subject.files[0].machos.size).to eq 1 } + it { expect(subject.files[0].machos[0].type).to eq data[0][:type] } + it { expect(subject.files[0].machos[0].uuid).to eq data[0][:uuid] } + it { expect(subject.files[0].machos[0].cpu_type).to eq data[0][:cpu_type] } + it { expect(subject.files[0].machos[0].cpu_name).to eq data[0][:cpu_name] } + it { expect(subject.files[0].machos[0].size).to eq data[0][:size] } + it { expect(subject.files[0].machos[0].size(human_size: true)).to eq data[0][:human_size] } + it { expect(subject.files[0].machos[0].to_h).to eq data[0] } + + it { expect(subject.files[1].object).to eq 'AppInfoNotificationCenter' } + it { expect(subject.files[1].macho_type).to be_a ::MachO::MachOFile } + it { expect(subject.files[1].release_version).to eq '1.0' } + it { expect(subject.files[1].build_version).to eq '1' } + it { expect(subject.files[1].identifier).to eq 'im.ews.ios.AppInfo.AppInfoNotificationCenter' } + it { expect(subject.files[1].bundle_id).to eq 'im.ews.ios.AppInfo.AppInfoNotificationCenter' } + it { expect(subject.files[1].machos.size).to eq 1 } + it { expect(subject.files[1].machos[0].type).to eq data[1][:type] } + it { expect(subject.files[1].machos[0].uuid).to eq data[1][:uuid] } + it { expect(subject.files[1].machos[0].cpu_type).to eq data[1][:cpu_type] } + it { expect(subject.files[1].machos[0].cpu_name).to eq data[1][:cpu_name] } + it { expect(subject.files[1].machos[0].size).to eq data[1][:size] } + it { expect(subject.files[1].machos[0].size(human_size: true)).to eq data[1][:human_size] } + it { expect(subject.files[1].machos[0].to_h).to eq data[1] } + end + + after { subject.clear! } end - end - describe '#MultiMachO' do - subject { AppInfo::DSYM.new(fixture_path('dsyms/multi_ios.dSYM.zip')) } + describe 'when dSYM in children path' do + let(:file) { fixture_path('dsyms/iOS-mutli-dSYMs-wrapped-by-folder.zip') } + subject { AppInfo::DSYM.new(file) } + let(:data) { + [ + { + type: :dsym, + uuid: '52e65dbe-8234-3387-b733-c5044e26653f', + cpu_type: :arm64, + cpu_name: :arm64, + size: 1_029_092, + human_size: '1004.97 KB' + }, + { + type: :dsym, + uuid: '628e9796-746c-3fec-91e7-586b4bed352a', + cpu_type: :arm64, + cpu_name: :arm64, + size: 988_131, + human_size: '964.97 KB' + } + ] + } - after { subject.clear! } + context do + it { expect(subject.file).to eq file } + it { expect(subject.file_type).to eq AppInfo::Format::DSYM } + it { expect(subject.file_type).to eq :dsym } + it { expect(subject.files.size).to eq 2 } + it { expect(subject.files[0].object).to eq 'AppInfo' } + it { expect(subject.files[0].macho_type).to be_a ::MachO::MachOFile } + it { expect(subject.files[0].release_version).to eq '1.0' } + it { expect(subject.files[0].build_version).to eq '1' } + it { expect(subject.files[0].identifier).to eq 'im.ews.ios.AppInfo' } + it { expect(subject.files[0].bundle_id).to eq 'im.ews.ios.AppInfo' } + it { expect(subject.files[0].machos.size).to eq 1 } + it { expect(subject.files[0].machos[0].type).to eq data[0][:type] } + it { expect(subject.files[0].machos[0].uuid).to eq data[0][:uuid] } + it { expect(subject.files[0].machos[0].cpu_type).to eq data[0][:cpu_type] } + it { expect(subject.files[0].machos[0].cpu_name).to eq data[0][:cpu_name] } + it { expect(subject.files[0].machos[0].size).to eq data[0][:size] } + it { expect(subject.files[0].machos[0].size(human_size: true)).to eq data[0][:human_size] } + it { expect(subject.files[0].machos[0].to_h).to eq data[0] } - context 'parse' do - data = [ - { - type: :dsym, - uuid: '26dfc15d-bdce-351f-b5de-6ee9f5dd6d85', - cpu_type: :arm, - cpu_name: :armv7, - size: 866_526, - human_size: '846.22 KB' - }, - { - type: :dsym, - uuid: '17f58291-dd25-3fc8-9417-ccbe8163d33e', - cpu_type: :arm64, - cpu_name: :arm64, - size: 866_911, - human_size: '846.59 KB' - } - ] + it { expect(subject.files[1].object).to eq 'AppInfoNotificationCenter' } + it { expect(subject.files[1].macho_type).to be_a ::MachO::MachOFile } + it { expect(subject.files[1].release_version).to eq '1.0' } + it { expect(subject.files[1].build_version).to eq '1' } + it { expect(subject.files[1].identifier).to eq 'im.ews.ios.AppInfo.AppInfoNotificationCenter' } + it { expect(subject.files[1].bundle_id).to eq 'im.ews.ios.AppInfo.AppInfoNotificationCenter' } + it { expect(subject.files[1].machos.size).to eq 1 } + it { expect(subject.files[1].machos[0].type).to eq data[1][:type] } + it { expect(subject.files[1].machos[0].uuid).to eq data[1][:uuid] } + it { expect(subject.files[1].machos[0].cpu_type).to eq data[1][:cpu_type] } + it { expect(subject.files[1].machos[0].cpu_name).to eq data[1][:cpu_name] } + it { expect(subject.files[1].machos[0].size).to eq data[1][:size] } + it { expect(subject.files[1].machos[0].size(human_size: true)).to eq data[1][:human_size] } + it { expect(subject.files[1].machos[0].to_h).to eq data[1] } + end - it { expect(subject.file_type).to eq AppInfo::Format::DSYM } - it { expect(subject.file_type).to eq :dsym } - it { expect(subject.object).to eq 'iOS' } - it { expect(subject.macho_type).to be_a ::MachO::FatFile } - it { expect(subject.release_version).to eq '1.0' } - it { expect(subject.build_version).to eq '2' } - it { expect(subject.identifier).to eq 'com.icyleaf.iOS' } - it { expect(subject.bundle_id).to eq 'com.icyleaf.iOS' } - it { expect(subject.machos.size).to eq 2 } - it { expect(subject.machos[0].type).to eq data[0][:type] } - it { expect(subject.machos[0].uuid).to eq data[0][:uuid] } - it { expect(subject.machos[0].cpu_type).to eq data[0][:cpu_type] } - it { expect(subject.machos[0].cpu_name).to eq data[0][:cpu_name] } - it { expect(subject.machos[0].size).to eq data[0][:size] } - it { expect(subject.machos[0].size(human_size: true)).to eq data[0][:human_size] } - it { expect(subject.machos[0].to_h).to eq data[0] } - it { expect(subject.machos[1].type).to eq data[1][:type] } - it { expect(subject.machos[1].uuid).to eq data[1][:uuid] } - it { expect(subject.machos[1].cpu_type).to eq data[1][:cpu_type] } - it { expect(subject.machos[1].cpu_name).to eq data[1][:cpu_name] } - it { expect(subject.machos[1].size).to eq data[1][:size] } - it { expect(subject.machos[1].size(human_size: true)).to eq data[1][:human_size] } - it { expect(subject.machos[1].to_h).to eq data[1] } + after { subject.clear! } end + + # context 'when dSYM in root path' do + # subject { AppInfo::DSYM.new(fixture_path('iOS-mutli-dSYMs-directly.zip')) } + # data = [ + # { + # type: :dsym, + # uuid: '26dfc15d-bdce-351f-b5de-6ee9f5dd6d85', + # cpu_type: :arm, + # cpu_name: :armv7, + # size: 866_526, + # human_size: '846.22 KB' + # }, + # { + # type: :dsym, + # uuid: '17f58291-dd25-3fc8-9417-ccbe8163d33e', + # cpu_type: :arm64, + # cpu_name: :arm64, + # size: 866_911, + # human_size: '846.59 KB' + # } + # ] + + # it { expect(subject.file_type).to eq AppInfo::Format::DSYM } + # it { expect(subject.file_type).to eq :dsym } + # it { expect(subject.object).to eq 'iOS' } + # it { expect(subject.macho_type).to be_a ::MachO::FatFile } + # it { expect(subject.release_version).to eq '1.0' } + # it { expect(subject.build_version).to eq '2' } + # it { expect(subject.identifier).to eq 'com.icyleaf.iOS' } + # it { expect(subject.bundle_id).to eq 'com.icyleaf.iOS' } + # it { expect(subject.machos.size).to eq 2 } + # it { expect(subject.machos[0].type).to eq data[0][:type] } + # it { expect(subject.machos[0].uuid).to eq data[0][:uuid] } + # it { expect(subject.machos[0].cpu_type).to eq data[0][:cpu_type] } + # it { expect(subject.machos[0].cpu_name).to eq data[0][:cpu_name] } + # it { expect(subject.machos[0].size).to eq data[0][:size] } + # it { expect(subject.machos[0].size(human_size: true)).to eq data[0][:human_size] } + # it { expect(subject.machos[0].to_h).to eq data[0] } + # it { expect(subject.machos[1].type).to eq data[1][:type] } + # it { expect(subject.machos[1].uuid).to eq data[1][:uuid] } + # it { expect(subject.machos[1].cpu_type).to eq data[1][:cpu_type] } + # it { expect(subject.machos[1].cpu_name).to eq data[1][:cpu_name] } + # it { expect(subject.machos[1].size).to eq data[1][:size] } + # it { expect(subject.machos[1].size(human_size: true)).to eq data[1][:human_size] } + # it { expect(subject.machos[1].to_h).to eq data[1] } + # end end end diff --git a/spec/app_info_spec.rb b/spec/app_info_spec.rb index ebe7d35..c793106 100644 --- a/spec/app_info_spec.rb +++ b/spec/app_info_spec.rb @@ -13,8 +13,10 @@ 'ipad.ipa' => :ipa, 'iphone.ipa' => :ipa, 'embedded.ipa' => :ipa, - 'multi_ios.dSYM.zip' => :dsym, - 'single_ios.dSYM.zip' => :dsym, + 'iOS-single-dSYM-with-single-macho.zip' => :dsym, + 'iOS-single-dSYM-with-multi-macho.zip' => :dsym, + 'iOS-mutli-dSYMs-wrapped-by-folder.zip' => :dsym, + 'iOS-mutli-dSYMs-directly.zip' => :dsym, 'bplist.mobileprovision' => :mobileprovision, 'plist.mobileprovision' => :mobileprovision, 'profile.mobileprovision' => :mobileprovision, diff --git a/spec/fixtures/dsyms/iOS-mutli-dSYMs-directly.zip b/spec/fixtures/dsyms/iOS-mutli-dSYMs-directly.zip new file mode 100644 index 0000000..69387f2 Binary files /dev/null and b/spec/fixtures/dsyms/iOS-mutli-dSYMs-directly.zip differ diff --git a/spec/fixtures/dsyms/iOS-mutli-dSYMs-wrapped-by-folder.zip b/spec/fixtures/dsyms/iOS-mutli-dSYMs-wrapped-by-folder.zip new file mode 100644 index 0000000..ceaa9ae Binary files /dev/null and b/spec/fixtures/dsyms/iOS-mutli-dSYMs-wrapped-by-folder.zip differ diff --git a/spec/fixtures/dsyms/multi_ios.dSYM.zip b/spec/fixtures/dsyms/iOS-single-dSYM-with-multi-macho.zip similarity index 100% rename from spec/fixtures/dsyms/multi_ios.dSYM.zip rename to spec/fixtures/dsyms/iOS-single-dSYM-with-multi-macho.zip diff --git a/spec/fixtures/dsyms/single_ios.dSYM.zip b/spec/fixtures/dsyms/iOS-single-dSYM-with-single-macho.zip similarity index 100% rename from spec/fixtures/dsyms/single_ios.dSYM.zip rename to spec/fixtures/dsyms/iOS-single-dSYM-with-single-macho.zip