xcode-result-bundle-processor 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +23 -0
  3. data/.csslintrc +34 -0
  4. data/.eslintrc +253 -0
  5. data/.gitignore +6 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +1171 -0
  8. data/.ruby-gemset +1 -0
  9. data/.ruby-version +1 -0
  10. data/.travis.yml +8 -0
  11. data/Gemfile +4 -0
  12. data/Gemfile.lock +83 -0
  13. data/LICENSE +36 -0
  14. data/README.md +72 -0
  15. data/Rakefile +50 -0
  16. data/bin/xcode-result-bundle-processor +37 -0
  17. data/lib/xcoderesultbundleprocessor.rb +28 -0
  18. data/lib/xcoderesultbundleprocessor/activity_log_formatter.rb +20 -0
  19. data/lib/xcoderesultbundleprocessor/element_snapshot.rb +81 -0
  20. data/lib/xcoderesultbundleprocessor/indented_string_buffer.rb +33 -0
  21. data/lib/xcoderesultbundleprocessor/keyword_struct.rb +10 -0
  22. data/lib/xcoderesultbundleprocessor/log_deserializer.rb +26 -0
  23. data/lib/xcoderesultbundleprocessor/results_bundle.rb +45 -0
  24. data/lib/xcoderesultbundleprocessor/slf0/class_name_resolver.rb +26 -0
  25. data/lib/xcoderesultbundleprocessor/slf0/deserializer.rb +45 -0
  26. data/lib/xcoderesultbundleprocessor/slf0/model/dvtdocumentlocation.rb +16 -0
  27. data/lib/xcoderesultbundleprocessor/slf0/model/dvttextdocumentlocation.rb +23 -0
  28. data/lib/xcoderesultbundleprocessor/slf0/model/ideactivitylogmessage.rb +26 -0
  29. data/lib/xcoderesultbundleprocessor/slf0/model/ideactivitylogsection.rb +29 -0
  30. data/lib/xcoderesultbundleprocessor/slf0/model/ideactivitylogunittestsection.rb +24 -0
  31. data/lib/xcoderesultbundleprocessor/slf0/model/ideconsoleitem.rb +16 -0
  32. data/lib/xcoderesultbundleprocessor/slf0/tokenizer.rb +82 -0
  33. data/lib/xcoderesultbundleprocessor/snapshot_summary.rb +47 -0
  34. data/lib/xcoderesultbundleprocessor/test_summaries/html_report.rb +156 -0
  35. data/lib/xcoderesultbundleprocessor/test_summaries/test_summaries.rb +84 -0
  36. data/lib/xcoderesultbundleprocessor/test_summaries/text_report.rb +40 -0
  37. data/lib/xcoderesultbundleprocessor/version.rb +3 -0
  38. data/static/report.css +30 -0
  39. data/static/report.js +14 -0
  40. data/xcode-result-bundle-processor.gemspec +30 -0
  41. metadata +225 -0
@@ -0,0 +1 @@
1
+ xcode-result-bundle-processor
@@ -0,0 +1 @@
1
+ ruby-2.2.3
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ os: osx
3
+ script:
4
+ - bundle exec rake
5
+ - bundle exec rake build
6
+ addons:
7
+ code_climate:
8
+ repo_token: ab0af39b165f1fd64c05d98119b404f3960343d9b46335de472b7692f1335fb2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in xcode-result-bundle-processor.gemspec
4
+ gemspec
@@ -0,0 +1,83 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ xcode-result-bundle-processor (1.0.0)
5
+ CFPropertyList (~> 2.2)
6
+ awesome_print (~> 1.6)
7
+ markaby (~> 0.8)
8
+ methadone (~> 1.9.2)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ CFPropertyList (2.3.2)
14
+ aruba (0.10.2)
15
+ childprocess (~> 0.5.6)
16
+ contracts (~> 0.9)
17
+ cucumber (>= 1.3.19)
18
+ ffi (~> 1.9.10)
19
+ rspec-expectations (>= 2.99)
20
+ thor (~> 0.19)
21
+ awesome_print (1.6.1)
22
+ builder (3.2.2)
23
+ childprocess (0.5.7)
24
+ ffi (~> 1.0, >= 1.0.11)
25
+ codeclimate-test-reporter (0.4.8)
26
+ simplecov (>= 0.7.1, < 1.0.0)
27
+ contracts (0.12.0)
28
+ cucumber (2.1.0)
29
+ builder (>= 2.1.2)
30
+ cucumber-core (~> 1.3.0)
31
+ diff-lcs (>= 1.1.3)
32
+ gherkin3 (~> 3.1.0)
33
+ multi_json (>= 1.7.5, < 2.0)
34
+ multi_test (>= 0.1.2)
35
+ cucumber-core (1.3.0)
36
+ gherkin3 (~> 3.1.0)
37
+ diff-lcs (1.2.5)
38
+ docile (1.1.5)
39
+ ffi (1.9.10)
40
+ gherkin3 (3.1.2)
41
+ json (1.8.3)
42
+ markaby (0.8.0)
43
+ builder
44
+ methadone (1.9.2)
45
+ bundler
46
+ multi_json (1.11.2)
47
+ multi_test (0.1.2)
48
+ rake (10.4.2)
49
+ rdoc (4.2.0)
50
+ rspec (3.3.0)
51
+ rspec-core (~> 3.3.0)
52
+ rspec-expectations (~> 3.3.0)
53
+ rspec-mocks (~> 3.3.0)
54
+ rspec-core (3.3.2)
55
+ rspec-support (~> 3.3.0)
56
+ rspec-expectations (3.3.1)
57
+ diff-lcs (>= 1.2.0, < 2.0)
58
+ rspec-support (~> 3.3.0)
59
+ rspec-mocks (3.3.2)
60
+ diff-lcs (>= 1.2.0, < 2.0)
61
+ rspec-support (~> 3.3.0)
62
+ rspec-support (3.3.0)
63
+ simplecov (0.10.0)
64
+ docile (~> 1.1.0)
65
+ json (~> 1.8)
66
+ simplecov-html (~> 0.10.0)
67
+ simplecov-html (0.10.0)
68
+ thor (0.19.1)
69
+
70
+ PLATFORMS
71
+ ruby
72
+
73
+ DEPENDENCIES
74
+ aruba (~> 0.10)
75
+ bundler (~> 1.6)
76
+ codeclimate-test-reporter (~> 0.4)
77
+ rake (~> 10.4)
78
+ rdoc (~> 4.2)
79
+ rspec (~> 3.3)
80
+ xcode-result-bundle-processor!
81
+
82
+ BUNDLED WITH
83
+ 1.10.6
data/LICENSE ADDED
@@ -0,0 +1,36 @@
1
+ # Copyfree Open Innovation License
2
+
3
+ This is version 0.4 of the Copyfree Open Innovation License.
4
+
5
+ ## Terms and Conditions
6
+
7
+ Redistributions, modified or unmodified, in whole or in part, must retain
8
+ applicable copyright or other legal privilege notices, these conditions, and
9
+ the following license terms and disclaimer. Subject to these conditions, the
10
+ holder(s) of copyright or other legal privileges, author(s) or assembler(s),
11
+ and contributors of this work hereby grant to any person who obtains a copy of
12
+ this work in any form:
13
+
14
+ 1. Permission to reproduce, modify, distribute, publish, sell, sublicense, use,
15
+ and/or otherwise deal in the licensed material without restriction.
16
+
17
+ 2. A perpetual, worldwide, non-exclusive, royalty-free, irrevocable patent
18
+ license to reproduce, modify, distribute, publish, sell, use, and/or otherwise
19
+ deal in the licensed material without restriction, for any and all patents:
20
+
21
+ a. Held presently or in the future by each such holder of copyright or
22
+ other legal privilege, author or assembler, or contributor, necessarily
23
+ infringed by the contributions alone or by combination with the work, of
24
+ that privilege holder, author or assembler, or contributor.
25
+
26
+ b. Necessarily infringed by the work at the time that holder of copyright
27
+ or other privilege, author or assembler, or contributor made any
28
+ contribution to the work.
29
+
30
+ NO WARRANTY OF ANY KIND IS IMPLIED BY, OR SHOULD BE INFERRED FROM, THIS LICENSE
31
+ OR THE ACT OF DISTRIBUTION UNDER THE TERMS OF THIS LICENSE, INCLUDING BUT NOT
32
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
33
+ AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, ASSEMBLERS, OR HOLDERS OF
34
+ COPYRIGHT OR OTHER LEGAL PRIVILEGE BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
35
+ LIABILITY, WHETHER IN ACTION OF CONTRACT, TORT, OR OTHERWISE ARISING FROM, OUT
36
+ OF, OR IN CONNECTION WITH THE WORK OR THE USE OF OR OTHER DEALINGS IN THE WORK.
@@ -0,0 +1,72 @@
1
+ [![Build Status](https://travis-ci.org/americanexpress/xcode-result-bundle-processor.svg?branch=master)](https://travis-ci.org/americanexpress/xcode-result-bundle-processor)
2
+ [![Code Climate](https://codeclimate.com/github/americanexpress/xcode-result-bundle-processor/badges/gpa.svg)](https://codeclimate.com/github/americanexpress/xcode-result-bundle-processor)
3
+ [![Test Coverage](https://codeclimate.com/github/americanexpress/xcode-result-bundle-processor/badges/coverage.svg)](https://codeclimate.com/github/americanexpress/xcode-result-bundle-processor/coverage)
4
+ [![Issue Count](https://codeclimate.com/github/americanexpress/xcode-result-bundle-processor/badges/issue_count.svg)](https://codeclimate.com/github/americanexpress/xcode-result-bundle-processor)
5
+
6
+ # XcodeResultBundleProcessor
7
+
8
+ This tool converts into Xcode 7's machine-readable results bundle into a human-readable HTML report including
9
+ detailed activity logs and screenshots for UI tests.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'xcode-result-bundle-processor'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install xcode-result-bundle-processor
24
+
25
+ ## Usage
26
+
27
+ First, run your UI tests using an invocation like this:
28
+
29
+ xcodebuild -workspace MyWorkspace.xcworkspace \
30
+ -scheme 'My UI Tests' \
31
+ -sdk iphonesimulator \
32
+ -resultBundlePath "my_results_bundle" \
33
+
34
+ This will put a bunch of mystery files into `my_results_bundle`, which you can transform into un-mystery files
35
+ via
36
+
37
+ bundle exec xcode-result-bundle-processor --save-html-report report my_results_bundle
38
+
39
+ The report will appear in `report/index.html`
40
+
41
+ ## Development
42
+
43
+ If you have RVM and change to the working directory, you'll be prompted to install the needed Ruby version if you
44
+ don't already have it. RVM will also handle creating a gemset.
45
+
46
+ To update the dependencies, run
47
+
48
+ bundle
49
+
50
+ To run tests, run
51
+
52
+ bundle exec rake
53
+
54
+ To build the gem, fun
55
+
56
+ bundle exec rake build
57
+
58
+ To execute the tool, run
59
+
60
+ bundle exec xcode-result-bundle-processor
61
+
62
+ ## Contributing
63
+
64
+ Contributing is easy and fun! Some guidelines:
65
+
66
+ * If you're making a non-trivial change, consider reaching out to Manuel the Maintainer (mwudka@me.com) for an
67
+ architecture/implementation chat.
68
+ * Create an issue to track your work and describe your goals
69
+ * Branch from master and make your changes in the branch
70
+ * Add tests for any new functionality
71
+ * When you're happy with your changes and the builds pass, open a PR
72
+ * If no one has addressed your PR after a day or two, prod Manuel the Maintainer (mwudka@me.com)
@@ -0,0 +1,50 @@
1
+ def dump_load_path
2
+ puts $LOAD_PATH.join("\n")
3
+ found = nil
4
+ $LOAD_PATH.each do |path|
5
+ if File.exist?(File.join(path,"rspec"))
6
+ puts "Found rspec in #{path}"
7
+ if File.exist?(File.join(path,"rspec","core"))
8
+ puts "Found core"
9
+ if File.exist?(File.join(path,"rspec","core","rake_task"))
10
+ puts "Found rake_task"
11
+ found = path
12
+ else
13
+ puts "!! no rake_task"
14
+ end
15
+ else
16
+ puts "!!! no core"
17
+ end
18
+ end
19
+ end
20
+ if found.nil?
21
+ puts "Didn't find rspec/core/rake_task anywhere"
22
+ else
23
+ puts "Found in #{path}"
24
+ end
25
+ end
26
+ require 'bundler'
27
+ require 'rake/clean'
28
+
29
+ require 'rspec/core/rake_task'
30
+
31
+ require 'cucumber'
32
+ require 'cucumber/rake/task'
33
+ gem 'rdoc' # we need the installed RDoc gem, not the system one
34
+ require 'rdoc/task'
35
+
36
+ include Rake::DSL
37
+
38
+ Bundler::GemHelper.install_tasks
39
+
40
+ RSpec::Core::RakeTask.new(:spec)
41
+
42
+ CUKE_RESULTS = 'results.html'
43
+ CLEAN << CUKE_RESULTS
44
+ Cucumber::Rake::Task.new(:features) do |t|
45
+ t.cucumber_opts = "features --format html -o #{CUKE_RESULTS} --format pretty --no-source -x"
46
+ t.fork = false
47
+ end
48
+
49
+ task :default => [:spec, :features]
50
+
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'xcoderesultbundleprocessor'
4
+
5
+ class App
6
+ include Methadone::Main
7
+ include Methadone::CLILogging
8
+
9
+ main do |results_bundle_path|
10
+ change_logger(Methadone::CLILogger.new(STDERR, STDERR))
11
+
12
+ info "Preparing report for results bundle path at #{results_bundle_path}"
13
+
14
+ results_bundle = if File.directory?(results_bundle_path)
15
+ XcodeResultBundleProcessor::DirectoryResultsBundle.new(results_bundle_path)
16
+ else
17
+ XcodeResultBundleProcessor::TarballResultsBundle.new(results_bundle_path)
18
+ end
19
+
20
+ unless options['save-html-report'].nil?
21
+ XcodeResultBundleProcessor::TestSummaries::HTMLReport.new(results_bundle).save(options['save-html-report'])
22
+ end
23
+
24
+ debug XcodeResultBundleProcessor::TestSummaries::TextReport.format(results_bundle)
25
+ info 'Success!'
26
+ end
27
+
28
+ description 'Creates friendly report from Xcode results bundle'
29
+ arg :results_bundle_path
30
+ on('--save-html-report [report output dir]', 'Save a test result HTML report to given directory')
31
+
32
+ version XcodeResultBundleProcessor::VERSION
33
+
34
+ use_log_level_option :toggle_debug_on_signal => 'USR1'
35
+
36
+ go!
37
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems/package'
2
+ require 'cfpropertylist'
3
+ require 'awesome_print'
4
+ require 'methadone'
5
+ require 'markaby'
6
+ require 'optparse'
7
+ require 'ostruct'
8
+
9
+ require 'xcoderesultbundleprocessor/version'
10
+ require 'xcoderesultbundleprocessor/keyword_struct'
11
+ require 'xcoderesultbundleprocessor/indented_string_buffer'
12
+ require 'xcoderesultbundleprocessor/slf0/tokenizer'
13
+ require 'xcoderesultbundleprocessor/slf0/class_name_resolver'
14
+ require 'xcoderesultbundleprocessor/slf0/deserializer'
15
+ require 'xcoderesultbundleprocessor/slf0/model/dvtdocumentlocation'
16
+ require 'xcoderesultbundleprocessor/slf0/model/dvttextdocumentlocation'
17
+ require 'xcoderesultbundleprocessor/slf0/model/ideactivitylogmessage'
18
+ require 'xcoderesultbundleprocessor/slf0/model/ideactivitylogsection'
19
+ require 'xcoderesultbundleprocessor/slf0/model/ideactivitylogunittestsection'
20
+ require 'xcoderesultbundleprocessor/slf0/model/ideconsoleitem'
21
+ require 'xcoderesultbundleprocessor/activity_log_formatter'
22
+ require 'xcoderesultbundleprocessor/log_deserializer'
23
+ require 'xcoderesultbundleprocessor/test_summaries/test_summaries'
24
+ require 'xcoderesultbundleprocessor/test_summaries/html_report'
25
+ require 'xcoderesultbundleprocessor/test_summaries/text_report'
26
+ require 'xcoderesultbundleprocessor/results_bundle'
27
+ require 'xcoderesultbundleprocessor/element_snapshot'
28
+ require 'xcoderesultbundleprocessor/snapshot_summary'
@@ -0,0 +1,20 @@
1
+ module XcodeResultBundleProcessor
2
+ module ActivityLogFormatter
3
+ include Methadone::CLILogging
4
+
5
+ def self.format(section)
6
+ debug "Formatting activity log section #{section.ai}"
7
+
8
+ return "\n" if section.nil?
9
+
10
+ buffer = IndentedStringBuffer.new
11
+
12
+ # The top-level section contains the complete log for all test runs, so grabbing that text is enough to
13
+ # get the full log
14
+ section = section.subsections.first
15
+
16
+ buffer << section.title << section.text.each_line
17
+ buffer.to_s
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,81 @@
1
+ module XcodeResultBundleProcessor
2
+ class ElementSnapshot < OpenStruct
3
+ def initialize(plist)
4
+ super()
5
+
6
+ @objects = plist.value.value['$objects'].value
7
+
8
+ root_object = plist.value.value['$top'].value['root']
9
+
10
+ self._deserialize_object(root_object).each do |key, value|
11
+ self[key] = value
12
+ end
13
+ end
14
+
15
+ def _deserialize_dictionary(cfdictionary)
16
+ if cfdictionary.value.key?('NS.rectval')
17
+ return self._deserialize_object(cfdictionary.value['NS.rectval'])
18
+ end
19
+
20
+ if cfdictionary.value.key?('$classname')
21
+ return cfdictionary.value['$classname'].value
22
+ end
23
+
24
+ ret = {}
25
+ if cfdictionary.value.key?('NS.keys') && cfdictionary.value.key?('NS.objects')
26
+ keys_and_values = cfdictionary.value['NS.keys'].value.zip(cfdictionary.value['NS.objects'].value)
27
+ keys_and_values.each do |key, value|
28
+ ret[self._deserialize_object(key).to_s.to_sym] = self._deserialize_object(value)
29
+ end
30
+ elsif cfdictionary.value.key?('NS.objects')
31
+ return cfdictionary.value['NS.objects'].value.map { |o| self._deserialize_object(o) }
32
+ else
33
+ cfdictionary.value.each do |key, value|
34
+ ret[key.to_sym] = self._deserialize_object(value)
35
+ end
36
+
37
+ end
38
+ ret
39
+ end
40
+
41
+ def _deserialize_object(object)
42
+ if object.is_a?(CFPropertyList::CFUid)
43
+ self._deserialize_object(@objects[object.value])
44
+ elsif object.is_a?(CFPropertyList::CFString) && object.value == '$null'
45
+ nil
46
+ elsif object.is_a?(CFPropertyList::CFDictionary)
47
+ self._deserialize_dictionary(object)
48
+ elsif object.is_a?(CFPropertyList::CFString) or object.is_a?(CFPropertyList::CFInteger) or object.is_a?(CFPropertyList::CFBoolean)
49
+ object.value
50
+ elsif object.is_a?(CFPropertyList::CFArray)
51
+ object.value.map { |o| self._deserialize_object(o) }
52
+ else
53
+ raise "Unsupported object type #{object.class}"
54
+ end
55
+ end
56
+
57
+ def _deserialize_uid(uid)
58
+ object = @objects[uid.value]
59
+
60
+ if object.is_a?(CFPropertyList::CFUid)
61
+ _deserialize_uid(uid)
62
+ elsif object.is_a?(CFPropertyList::CFString) && object.value == '$null'
63
+ nil
64
+ elsif object.is_a?(CFPropertyList::CFDictionary)
65
+ hash = {}
66
+
67
+ object.value.each do |key, value|
68
+ if value.is_a?(CFPropertyList::CFUid)
69
+ hash[key] = self._deserialize_uid(value)
70
+ else
71
+ hash[key] = value.value
72
+ end
73
+ end
74
+
75
+ hash
76
+ else
77
+ object.value
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,33 @@
1
+ module XcodeResultBundleProcessor
2
+ class IndentedStringBuffer
3
+ def initialize(buffer=nil, indent_level=0)
4
+ @buffer = buffer || ''
5
+ @indent_spaces = 2
6
+ @indent_level = indent_level
7
+ end
8
+
9
+ def <<(arg)
10
+ Array(arg).each do |line|
11
+ @buffer << ' ' * (@indent_spaces * @indent_level) << line
12
+ @buffer << "\n" unless line.end_with?("\n")
13
+ @buffer
14
+ end
15
+ self
16
+ end
17
+
18
+ def add_newline
19
+ @buffer << "\n"
20
+ self
21
+ end
22
+
23
+ def indent
24
+ IndentedStringBuffer.new(@buffer, @indent_level + 1)
25
+ end
26
+
27
+ def to_s
28
+ return "\n" if @buffer.empty?
29
+ @buffer
30
+ end
31
+
32
+ end
33
+ end