xcode-result-bundle-processor 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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