dotpretty 0.8.1 → 0.9.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.
- checksums.yaml +4 -4
- data/bin/dotpretty +11 -13
- data/lib/dotpretty/http/client.rb +26 -0
- data/lib/dotpretty/http/null_client.rb +10 -0
- data/lib/dotpretty/options.rb +45 -0
- data/lib/dotpretty/parser.rb +157 -60
- data/lib/dotpretty/reporters/basic.rb +13 -7
- data/lib/dotpretty/reporters/browser.rb +60 -0
- data/lib/dotpretty/reporters/factory.rb +5 -0
- data/lib/dotpretty/reporters/json.rb +12 -7
- data/lib/dotpretty/reporters/names.rb +3 -1
- data/lib/dotpretty/reporters/progress.rb +14 -5
- data/lib/dotpretty/runner.rb +64 -10
- data/lib/dotpretty/version.rb +1 -1
- metadata +20 -3
- data/lib/dotpretty/aggregator.rb +0 -146
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c19f485b3423444380bc1288152ab158d27b1b3f0a80909d094e745ae24df8ec
|
|
4
|
+
data.tar.gz: ecea2dab730e241d3774d9ec13e9f216ae3b780c7d331e82791f25a0ead8579c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 39193f4dc7bc9566e5a87702610d70286cacbc9c1775aa6b58964a62cc21108db20fa4bb5ab73efbcb1fb5030e83dee6aead8aeaf5cb47374f8340a37479077e
|
|
7
|
+
data.tar.gz: 215b44b59aadcedd0a638701354124ebdd23a8c6cf3b22547ed4d98d57d82a1f95bf804862b752d3115efc844fa9da4c45e5fc566ff0a13187c630fb49c66c09
|
data/bin/dotpretty
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
require "dotpretty/color_palettes/bash"
|
|
6
|
-
require "dotpretty/color_palettes/null"
|
|
7
|
-
require "dotpretty/reporters/names"
|
|
3
|
+
require "dotpretty/options"
|
|
8
4
|
require "dotpretty/runner"
|
|
5
|
+
require "dotpretty/reporters/names"
|
|
9
6
|
require "dotpretty/version"
|
|
10
7
|
require "optparse"
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
command_line_args = {}
|
|
13
10
|
OptionParser.new do |opts|
|
|
14
11
|
|
|
15
12
|
opts.banner = "Usage: dotnet test -v=normal Test.Project/ | dotnet [options]"
|
|
16
13
|
|
|
17
14
|
opts.on("-c", "--color", "Enable color output") do |color|
|
|
18
|
-
|
|
15
|
+
command_line_args[:color] = color
|
|
19
16
|
end
|
|
20
17
|
|
|
21
18
|
opts.on("-h", "--help", "Display this help") do
|
|
@@ -26,7 +23,7 @@ OptionParser.new do |opts|
|
|
|
26
23
|
all_reporter_names = Dotpretty::Reporters::Names::ALL
|
|
27
24
|
reporter_message = ["Set reporter. Defaults to basic", "Available reporters: #{all_reporter_names.join(", ")}"]
|
|
28
25
|
opts.on("-rREPORTER", "--reporter=REPORTER", *reporter_message) do |reporter_name|
|
|
29
|
-
|
|
26
|
+
command_line_args[:reporter_name] = reporter_name
|
|
30
27
|
end
|
|
31
28
|
|
|
32
29
|
if STDIN.tty?
|
|
@@ -37,11 +34,12 @@ OptionParser.new do |opts|
|
|
|
37
34
|
|
|
38
35
|
end.parse!
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
color_palette: color_palette,
|
|
37
|
+
options = Dotpretty::Options.build({
|
|
38
|
+
color: command_line_args.fetch(:color, false),
|
|
43
39
|
output: STDOUT,
|
|
44
|
-
reporter_name:
|
|
40
|
+
reporter_name: command_line_args.fetch(:reporter_name, Dotpretty::Reporters::Names::BASIC)
|
|
45
41
|
})
|
|
46
|
-
|
|
42
|
+
|
|
43
|
+
runner = Dotpretty::Runner.new({ reporter: options.reporter })
|
|
44
|
+
STDIN.each_line { |line| runner.input_received(line) }
|
|
47
45
|
runner.done_with_input
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "httparty"
|
|
2
|
+
|
|
3
|
+
module Dotpretty
|
|
4
|
+
module Http
|
|
5
|
+
class Client
|
|
6
|
+
|
|
7
|
+
def initialize(api_root:)
|
|
8
|
+
self.api_root = api_root
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def post_json(route, data=nil)
|
|
12
|
+
HTTParty.post("#{api_root}#{route}", {
|
|
13
|
+
body: data.to_json,
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json"
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
attr_accessor :api_root
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require "dotpretty/color_palettes/bash"
|
|
2
|
+
require "dotpretty/color_palettes/null"
|
|
3
|
+
require "dotpretty/http/client"
|
|
4
|
+
require "dotpretty/http/null_client"
|
|
5
|
+
require "dotpretty/reporters/factory"
|
|
6
|
+
|
|
7
|
+
module Dotpretty
|
|
8
|
+
class Options
|
|
9
|
+
|
|
10
|
+
def self.build(command_line_args)
|
|
11
|
+
color_palette = command_line_args[:color] ? Dotpretty::ColorPalettes::Bash : Dotpretty::ColorPalettes::Null
|
|
12
|
+
http_client = Dotpretty::Http::Client.new({
|
|
13
|
+
api_root: "http://localhost:4567"
|
|
14
|
+
})
|
|
15
|
+
reporter_name = command_line_args.fetch(:reporter_name)
|
|
16
|
+
return Dotpretty::Options.new({
|
|
17
|
+
color_palette: color_palette,
|
|
18
|
+
http_client: http_client,
|
|
19
|
+
output: command_line_args.fetch(:output),
|
|
20
|
+
reporter_name: reporter_name
|
|
21
|
+
})
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize(color_palette:, http_client: Dotpretty::Http::NullClient.new, output:, reporter_name:)
|
|
25
|
+
self.color_palette = color_palette
|
|
26
|
+
self.http_client = http_client
|
|
27
|
+
self.output = output
|
|
28
|
+
self.reporter_name = reporter_name
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def reporter
|
|
32
|
+
return Dotpretty::Reporters::Factory.build_reporter(reporter_name, {
|
|
33
|
+
color_palette: color_palette,
|
|
34
|
+
http_client: http_client,
|
|
35
|
+
output: output
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
attr_accessor :color_palette, :http_client, :output, :reporter_name
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/dotpretty/parser.rb
CHANGED
|
@@ -1,76 +1,173 @@
|
|
|
1
|
-
require "dotpretty/aggregator"
|
|
2
|
-
require "dotpretty/reporters/basic"
|
|
3
|
-
require "dotpretty/state_machine/state_machine_builder"
|
|
4
|
-
|
|
5
1
|
module Dotpretty
|
|
6
2
|
class Parser
|
|
7
3
|
|
|
4
|
+
BUILD_STARTED = /^Build started/
|
|
5
|
+
BUILD_COMPLETED = /^Build completed/
|
|
6
|
+
BUILD_FAILED = /^Build FAILED.$/
|
|
7
|
+
TEST_FAILED = /^Failed/
|
|
8
|
+
TEST_PASSED = /^Passed/
|
|
9
|
+
TEST_SKIPPED = /^Skipped/
|
|
10
|
+
TEST_SUMMARY = /^Total tests/
|
|
11
|
+
TESTS_STARTED = /^Starting test execution, please wait...$/
|
|
12
|
+
|
|
13
|
+
attr_accessor :state_machine
|
|
14
|
+
|
|
8
15
|
def initialize(reporter:)
|
|
9
|
-
self.
|
|
10
|
-
self.
|
|
11
|
-
state :waiting do
|
|
12
|
-
transition :build_started, :build_in_progress, :build_started
|
|
13
|
-
end
|
|
14
|
-
state :build_in_progress do
|
|
15
|
-
transition :received_build_input, :parsing_build_input
|
|
16
|
-
end
|
|
17
|
-
state :parsing_build_input do
|
|
18
|
-
on_entry :parse_build_input
|
|
19
|
-
transition :build_completed, :ready_to_run_tests, :build_completed
|
|
20
|
-
transition :build_failed, :reading_build_failure_details, :reset_build_failure_details
|
|
21
|
-
transition :received_build_input, :build_in_progress
|
|
22
|
-
end
|
|
23
|
-
state :reading_build_failure_details do
|
|
24
|
-
transition :received_build_failure_details, :reading_build_failure_details, :track_build_failure_details
|
|
25
|
-
transition :end_of_input, :done, :report_failing_build
|
|
26
|
-
end
|
|
27
|
-
state :ready_to_run_tests do
|
|
28
|
-
transition :received_input_line, :determining_if_tests_started
|
|
29
|
-
end
|
|
30
|
-
state :determining_if_tests_started do
|
|
31
|
-
on_entry :determine_if_tests_started
|
|
32
|
-
transition :tests_started, :waiting_for_test_input, :starting_tests
|
|
33
|
-
transition :tests_did_not_start, :ready_to_run_tests
|
|
34
|
-
end
|
|
35
|
-
state :waiting_for_test_input do
|
|
36
|
-
transition :test_input_received, :parsing_test_input
|
|
37
|
-
end
|
|
38
|
-
state :parsing_test_input do
|
|
39
|
-
on_entry :parse_test_input
|
|
40
|
-
transition :received_other_input, :waiting_for_test_input
|
|
41
|
-
transition :test_failed, :waiting_for_failure_details, :reset_current_failing_test
|
|
42
|
-
transition :test_passed, :waiting_for_test_input, :test_passed
|
|
43
|
-
transition :test_skipped, :waiting_for_test_input, :test_skipped
|
|
44
|
-
transition :tests_completed, :done, :show_test_summary
|
|
45
|
-
end
|
|
46
|
-
state :waiting_for_failure_details do
|
|
47
|
-
transition :received_failure_details, :reading_failure_details
|
|
48
|
-
end
|
|
49
|
-
state :reading_failure_details do
|
|
50
|
-
on_entry :parse_failure_line
|
|
51
|
-
transition :done_reading_failure, :parsing_test_input, :report_failing_test
|
|
52
|
-
transition :received_failure_output, :waiting_for_failure_details, :track_failure_details
|
|
53
|
-
end
|
|
54
|
-
state :parsing_failure_line do
|
|
55
|
-
on_entry :parse_failure_line
|
|
56
|
-
transition :received_failure_output, :reading_failure_details, :track_failure_details
|
|
57
|
-
transition :tests_completed, :done, :show_test_summary
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
aggregator.state_machine = state_machine
|
|
16
|
+
self.raw_input_inlines = []
|
|
17
|
+
self.reporter = reporter
|
|
61
18
|
end
|
|
62
19
|
|
|
63
20
|
def parse_line(input_line)
|
|
64
|
-
|
|
21
|
+
raw_input_inlines << input_line
|
|
22
|
+
case state_machine.current_state_name
|
|
23
|
+
when :waiting_for_build_to_start
|
|
24
|
+
state_machine.trigger(:received_input_line, input_line)
|
|
25
|
+
when :build_in_progress
|
|
26
|
+
state_machine.trigger(:received_build_input, input_line)
|
|
27
|
+
when :reading_build_failure_details
|
|
28
|
+
state_machine.trigger(:received_build_failure_details, input_line)
|
|
29
|
+
when :ready_to_run_tests
|
|
30
|
+
state_machine.trigger(:received_input_line, input_line)
|
|
31
|
+
when :waiting_for_test_input
|
|
32
|
+
state_machine.trigger(:test_input_received, input_line)
|
|
33
|
+
when :waiting_for_failure_details
|
|
34
|
+
state_machine.trigger(:received_failure_details, input_line)
|
|
35
|
+
when :reading_failure_details
|
|
36
|
+
state_machine.trigger(:received_input_line, input_line)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def handle_end_of_input
|
|
41
|
+
case state_machine.current_state_name
|
|
42
|
+
when :waiting_for_build_to_start
|
|
43
|
+
state_machine.trigger(:build_failed_to_start)
|
|
44
|
+
else
|
|
45
|
+
state_machine.trigger(:end_of_input)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def parse_prebuild_input(input_line)
|
|
50
|
+
if input_line.match(BUILD_STARTED)
|
|
51
|
+
state_machine.trigger(:build_started)
|
|
52
|
+
else
|
|
53
|
+
state_machine.trigger(:build_did_not_start)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def build_failed_to_start
|
|
58
|
+
reporter.build_failed_to_start(raw_input_inlines)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def parse_build_input(input_line)
|
|
62
|
+
if input_line.match(BUILD_COMPLETED)
|
|
63
|
+
state_machine.trigger(:build_completed)
|
|
64
|
+
elsif input_line.match(BUILD_FAILED)
|
|
65
|
+
state_machine.trigger(:build_failed)
|
|
66
|
+
else
|
|
67
|
+
state_machine.trigger(:received_build_input)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def determine_if_tests_started(input_line)
|
|
72
|
+
if input_line.match(TESTS_STARTED)
|
|
73
|
+
state_machine.trigger(:tests_started)
|
|
74
|
+
else
|
|
75
|
+
state_machine.trigger(:tests_did_not_start)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def parse_test_input(input_line)
|
|
80
|
+
if input_line.match(TEST_PASSED)
|
|
81
|
+
match = input_line.match(/^Passed\s+(.+)$/)
|
|
82
|
+
state_machine.trigger(:test_passed, match[1])
|
|
83
|
+
elsif input_line.match(TEST_FAILED)
|
|
84
|
+
match = input_line.match(/^Failed\s+(.+)$/)
|
|
85
|
+
state_machine.trigger(:test_failed, match[1])
|
|
86
|
+
elsif input_line.match(TEST_SKIPPED)
|
|
87
|
+
match = input_line.match(/^Skipped\s+(.+)$/)
|
|
88
|
+
state_machine.trigger(:test_skipped, match[1])
|
|
89
|
+
elsif input_line.match(TEST_SUMMARY)
|
|
90
|
+
state_machine.trigger(:tests_completed, input_line)
|
|
91
|
+
else
|
|
92
|
+
state_machine.trigger(:received_other_input)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def build_completed
|
|
97
|
+
reporter.build_completed
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def build_started
|
|
101
|
+
reporter.build_started
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def reset_build_failure_details
|
|
105
|
+
self.build_failure_details = []
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def track_build_failure_details(input_line)
|
|
109
|
+
build_failure_details << input_line
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def report_failing_build
|
|
113
|
+
reporter.build_failed(build_failure_details)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def track_failure_details(details)
|
|
117
|
+
current_failing_test[:details] << details.rstrip if details.rstrip != ""
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def show_test_summary(summary)
|
|
121
|
+
match = summary.match(/^Total tests: (\d+). Passed: (\d+). Failed: (\d+). Skipped: (\d+)./)
|
|
122
|
+
reporter.show_test_summary({
|
|
123
|
+
failedTests: match[3].to_i,
|
|
124
|
+
passedTests: match[2].to_i,
|
|
125
|
+
skippedTests: match[4].to_i,
|
|
126
|
+
totalTests: match[1].to_i
|
|
127
|
+
})
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def report_failing_test(*_)
|
|
131
|
+
reporter.test_failed({
|
|
132
|
+
details: current_failing_test[:details],
|
|
133
|
+
name: current_failing_test[:name]
|
|
134
|
+
})
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def parse_failure_line(input_line)
|
|
138
|
+
if input_line.match(TEST_PASSED)
|
|
139
|
+
state_machine.trigger(:done_reading_failure, input_line)
|
|
140
|
+
elsif input_line.match(TEST_SUMMARY)
|
|
141
|
+
state_machine.trigger(:done_reading_failure, input_line)
|
|
142
|
+
elsif input_line.match(TEST_FAILED)
|
|
143
|
+
state_machine.trigger(:done_reading_failure, input_line)
|
|
144
|
+
else
|
|
145
|
+
state_machine.trigger(:received_failure_output, input_line)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def starting_tests
|
|
150
|
+
reporter.starting_tests
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def reset_current_failing_test(test_name)
|
|
154
|
+
self.current_failing_test = {
|
|
155
|
+
details: [],
|
|
156
|
+
name: test_name
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def test_passed(name)
|
|
161
|
+
reporter.test_passed({ name: name })
|
|
65
162
|
end
|
|
66
163
|
|
|
67
|
-
def
|
|
68
|
-
|
|
164
|
+
def test_skipped(name)
|
|
165
|
+
reporter.test_skipped({ name: name })
|
|
69
166
|
end
|
|
70
167
|
|
|
71
168
|
private
|
|
72
169
|
|
|
73
|
-
attr_accessor :
|
|
170
|
+
attr_accessor :build_failure_details, :current_failing_test, :raw_input_inlines, :reporter
|
|
74
171
|
|
|
75
172
|
end
|
|
76
173
|
end
|
|
@@ -14,6 +14,12 @@ module Dotpretty
|
|
|
14
14
|
output.puts("Build started")
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def build_failed_to_start(raw_input_inlines)
|
|
18
|
+
raw_input_inlines.each do |raw_input_line|
|
|
19
|
+
output.puts(raw_input_line)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
17
23
|
def build_completed
|
|
18
24
|
output.puts("Build completed")
|
|
19
25
|
output.puts("")
|
|
@@ -30,17 +36,17 @@ module Dotpretty
|
|
|
30
36
|
output.puts("Starting test execution...")
|
|
31
37
|
end
|
|
32
38
|
|
|
33
|
-
def test_passed(
|
|
34
|
-
output.puts("#{green("Passed")} #{
|
|
39
|
+
def test_passed(name:)
|
|
40
|
+
output.puts("#{green("Passed")} #{name}")
|
|
35
41
|
end
|
|
36
42
|
|
|
37
|
-
def test_skipped(
|
|
38
|
-
output.puts("#{yellow("Skipped")} #{
|
|
43
|
+
def test_skipped(name:)
|
|
44
|
+
output.puts("#{yellow("Skipped")} #{name}")
|
|
39
45
|
end
|
|
40
46
|
|
|
41
|
-
def test_failed(
|
|
42
|
-
output.puts("#{red("Failed")} #{
|
|
43
|
-
|
|
47
|
+
def test_failed(name:, details:)
|
|
48
|
+
output.puts("#{red("Failed")} #{name}")
|
|
49
|
+
details.each do |line|
|
|
44
50
|
output.puts(line)
|
|
45
51
|
end
|
|
46
52
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Dotpretty
|
|
2
|
+
module Reporters
|
|
3
|
+
class Browser
|
|
4
|
+
|
|
5
|
+
def initialize(http_client:)
|
|
6
|
+
self.http_client = http_client
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def build_completed
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def build_failed_to_start(raw_input_inlines)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def build_failed(failure_details)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def build_started
|
|
19
|
+
http_client.post_json("/build_started")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def show_test_summary(test_summary)
|
|
23
|
+
http_client.post_json("/update_results", {
|
|
24
|
+
tests: tests
|
|
25
|
+
})
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def starting_tests
|
|
29
|
+
self.tests = []
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_failed(name:, details:)
|
|
33
|
+
tests << {
|
|
34
|
+
details: details,
|
|
35
|
+
name: name,
|
|
36
|
+
result: "failed"
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_passed(name:)
|
|
41
|
+
tests << {
|
|
42
|
+
name: name,
|
|
43
|
+
result: "passed"
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_skipped(name:)
|
|
48
|
+
tests << {
|
|
49
|
+
name: name,
|
|
50
|
+
result: "skipped"
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
attr_accessor :http_client, :tests
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require "dotpretty/color_palettes/null"
|
|
2
2
|
require "dotpretty/reporters/basic"
|
|
3
|
+
require "dotpretty/reporters/browser"
|
|
3
4
|
require "dotpretty/reporters/json"
|
|
4
5
|
require "dotpretty/reporters/names"
|
|
5
6
|
require "dotpretty/reporters/progress"
|
|
@@ -10,6 +11,10 @@ module Dotpretty
|
|
|
10
11
|
|
|
11
12
|
def self.build_reporter(name, options = {})
|
|
12
13
|
case name
|
|
14
|
+
when Dotpretty::Reporters::Names::BROWSER
|
|
15
|
+
return Dotpretty::Reporters::Browser.new({
|
|
16
|
+
http_client: options.fetch(:http_client)
|
|
17
|
+
})
|
|
13
18
|
when Dotpretty::Reporters::Names::JSON
|
|
14
19
|
return Dotpretty::Reporters::Json.new(options.fetch(:output))
|
|
15
20
|
when Dotpretty::Reporters::Names::PROGRESS
|
|
@@ -12,6 +12,9 @@ module Dotpretty
|
|
|
12
12
|
def build_started
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
def build_failed_to_start(raw_input_inlines)
|
|
16
|
+
end
|
|
17
|
+
|
|
15
18
|
def build_completed
|
|
16
19
|
end
|
|
17
20
|
|
|
@@ -21,24 +24,26 @@ module Dotpretty
|
|
|
21
24
|
def starting_tests
|
|
22
25
|
end
|
|
23
26
|
|
|
24
|
-
def test_passed(
|
|
27
|
+
def test_passed(name:)
|
|
25
28
|
tests << {
|
|
26
|
-
name:
|
|
29
|
+
name: name,
|
|
27
30
|
result: "passed"
|
|
28
31
|
}
|
|
29
32
|
end
|
|
30
33
|
|
|
31
|
-
def test_skipped(
|
|
34
|
+
def test_skipped(name:)
|
|
32
35
|
tests << {
|
|
33
|
-
name:
|
|
36
|
+
name: name,
|
|
34
37
|
result: "skipped"
|
|
35
38
|
}
|
|
36
39
|
end
|
|
37
40
|
|
|
38
|
-
def test_failed(
|
|
39
|
-
tests <<
|
|
41
|
+
def test_failed(name:, details:)
|
|
42
|
+
tests << {
|
|
43
|
+
details: details,
|
|
44
|
+
name: name,
|
|
40
45
|
result: "failed"
|
|
41
|
-
}
|
|
46
|
+
}
|
|
42
47
|
end
|
|
43
48
|
|
|
44
49
|
def show_test_summary(summary)
|
|
@@ -15,6 +15,12 @@ module Dotpretty
|
|
|
15
15
|
output.puts("")
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def build_failed_to_start(raw_input_inlines)
|
|
19
|
+
raw_input_inlines.each do |raw_input_line|
|
|
20
|
+
output.puts(raw_input_line)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
18
24
|
def build_started
|
|
19
25
|
output.puts("Build started")
|
|
20
26
|
end
|
|
@@ -38,17 +44,20 @@ module Dotpretty
|
|
|
38
44
|
output.puts("Starting test execution")
|
|
39
45
|
end
|
|
40
46
|
|
|
41
|
-
def test_failed(
|
|
42
|
-
failing_tests <<
|
|
47
|
+
def test_failed(name:, details:)
|
|
48
|
+
failing_tests << {
|
|
49
|
+
details: details,
|
|
50
|
+
name: name
|
|
51
|
+
}
|
|
43
52
|
output.print(red("F"))
|
|
44
53
|
end
|
|
45
54
|
|
|
46
|
-
def test_passed(
|
|
55
|
+
def test_passed(name:)
|
|
47
56
|
output.print(green("."))
|
|
48
57
|
end
|
|
49
58
|
|
|
50
|
-
def test_skipped(
|
|
51
|
-
skipped_test_names <<
|
|
59
|
+
def test_skipped(name:)
|
|
60
|
+
skipped_test_names << name
|
|
52
61
|
output.print(yellow("*"))
|
|
53
62
|
end
|
|
54
63
|
|
data/lib/dotpretty/runner.rb
CHANGED
|
@@ -1,28 +1,82 @@
|
|
|
1
1
|
require "dotpretty/parser"
|
|
2
|
-
require "dotpretty/reporters/
|
|
2
|
+
require "dotpretty/reporters/basic"
|
|
3
|
+
require "dotpretty/state_machine/state_machine_builder"
|
|
3
4
|
|
|
4
5
|
module Dotpretty
|
|
5
6
|
class Runner
|
|
6
7
|
|
|
7
|
-
def initialize(
|
|
8
|
-
reporter = Dotpretty::Reporters::Factory.build_reporter(reporter_name, {
|
|
9
|
-
output: output,
|
|
10
|
-
color_palette: color_palette
|
|
11
|
-
})
|
|
8
|
+
def initialize(reporter:)
|
|
12
9
|
self.parser = Dotpretty::Parser.new({ reporter: reporter })
|
|
10
|
+
self.state_machine = Dotpretty::StateMachine::StateMachineBuilder.build(parser) do
|
|
11
|
+
state :waiting_for_build_to_start do
|
|
12
|
+
transition :build_failed_to_start, :done, :build_failed_to_start
|
|
13
|
+
transition :received_input_line, :determining_if_build_started
|
|
14
|
+
end
|
|
15
|
+
state :determining_if_build_started do
|
|
16
|
+
on_entry :parse_prebuild_input
|
|
17
|
+
transition :build_started, :build_in_progress, :build_started
|
|
18
|
+
transition :build_did_not_start, :waiting_for_build_to_start
|
|
19
|
+
end
|
|
20
|
+
state :build_in_progress do
|
|
21
|
+
transition :received_build_input, :parsing_build_input
|
|
22
|
+
end
|
|
23
|
+
state :parsing_build_input do
|
|
24
|
+
on_entry :parse_build_input
|
|
25
|
+
transition :build_completed, :ready_to_run_tests, :build_completed
|
|
26
|
+
transition :build_failed, :reading_build_failure_details, :reset_build_failure_details
|
|
27
|
+
transition :received_build_input, :build_in_progress
|
|
28
|
+
end
|
|
29
|
+
state :reading_build_failure_details do
|
|
30
|
+
transition :received_build_failure_details, :reading_build_failure_details, :track_build_failure_details
|
|
31
|
+
transition :end_of_input, :done, :report_failing_build
|
|
32
|
+
end
|
|
33
|
+
state :ready_to_run_tests do
|
|
34
|
+
transition :received_input_line, :determining_if_tests_started
|
|
35
|
+
end
|
|
36
|
+
state :determining_if_tests_started do
|
|
37
|
+
on_entry :determine_if_tests_started
|
|
38
|
+
transition :tests_started, :waiting_for_test_input, :starting_tests
|
|
39
|
+
transition :tests_did_not_start, :ready_to_run_tests
|
|
40
|
+
end
|
|
41
|
+
state :waiting_for_test_input do
|
|
42
|
+
transition :test_input_received, :parsing_test_input
|
|
43
|
+
end
|
|
44
|
+
state :parsing_test_input do
|
|
45
|
+
on_entry :parse_test_input
|
|
46
|
+
transition :received_other_input, :waiting_for_test_input
|
|
47
|
+
transition :test_failed, :waiting_for_failure_details, :reset_current_failing_test
|
|
48
|
+
transition :test_passed, :waiting_for_test_input, :test_passed
|
|
49
|
+
transition :test_skipped, :waiting_for_test_input, :test_skipped
|
|
50
|
+
transition :tests_completed, :done, :show_test_summary
|
|
51
|
+
end
|
|
52
|
+
state :waiting_for_failure_details do
|
|
53
|
+
transition :received_failure_details, :reading_failure_details
|
|
54
|
+
end
|
|
55
|
+
state :reading_failure_details do
|
|
56
|
+
on_entry :parse_failure_line
|
|
57
|
+
transition :done_reading_failure, :parsing_test_input, :report_failing_test
|
|
58
|
+
transition :received_failure_output, :waiting_for_failure_details, :track_failure_details
|
|
59
|
+
end
|
|
60
|
+
state :parsing_failure_line do
|
|
61
|
+
on_entry :parse_failure_line
|
|
62
|
+
transition :received_failure_output, :reading_failure_details, :track_failure_details
|
|
63
|
+
transition :tests_completed, :done, :show_test_summary
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
parser.state_machine = state_machine
|
|
13
67
|
end
|
|
14
68
|
|
|
15
|
-
def
|
|
16
|
-
parser.parse_line(
|
|
69
|
+
def input_received(input_line)
|
|
70
|
+
parser.parse_line(input_line)
|
|
17
71
|
end
|
|
18
72
|
|
|
19
73
|
def done_with_input
|
|
20
|
-
parser.
|
|
74
|
+
parser.handle_end_of_input
|
|
21
75
|
end
|
|
22
76
|
|
|
23
77
|
private
|
|
24
78
|
|
|
25
|
-
attr_accessor :parser
|
|
79
|
+
attr_accessor :parser, :output, :state_machine
|
|
26
80
|
|
|
27
81
|
end
|
|
28
82
|
end
|
data/lib/dotpretty/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dotpretty
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eric Meyer
|
|
@@ -9,7 +9,21 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2019-05-02 00:00:00.000000000 Z
|
|
12
|
-
dependencies:
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: httparty
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.17'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.17'
|
|
13
27
|
description: A gem to parse and improve the output of the dotnet command
|
|
14
28
|
email:
|
|
15
29
|
executables:
|
|
@@ -18,11 +32,14 @@ extensions: []
|
|
|
18
32
|
extra_rdoc_files: []
|
|
19
33
|
files:
|
|
20
34
|
- bin/dotpretty
|
|
21
|
-
- lib/dotpretty/aggregator.rb
|
|
22
35
|
- lib/dotpretty/color_palettes/bash.rb
|
|
23
36
|
- lib/dotpretty/color_palettes/null.rb
|
|
37
|
+
- lib/dotpretty/http/client.rb
|
|
38
|
+
- lib/dotpretty/http/null_client.rb
|
|
39
|
+
- lib/dotpretty/options.rb
|
|
24
40
|
- lib/dotpretty/parser.rb
|
|
25
41
|
- lib/dotpretty/reporters/basic.rb
|
|
42
|
+
- lib/dotpretty/reporters/browser.rb
|
|
26
43
|
- lib/dotpretty/reporters/factory.rb
|
|
27
44
|
- lib/dotpretty/reporters/json.rb
|
|
28
45
|
- lib/dotpretty/reporters/names.rb
|
data/lib/dotpretty/aggregator.rb
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
module Dotpretty
|
|
2
|
-
class Aggregator
|
|
3
|
-
|
|
4
|
-
BUILD_COMPLETED = /^Build completed/
|
|
5
|
-
BUILD_FAILED = /^Build FAILED.$/
|
|
6
|
-
TEST_FAILED = /^Failed/
|
|
7
|
-
TEST_PASSED = /^Passed/
|
|
8
|
-
TEST_SKIPPED = /^Skipped/
|
|
9
|
-
TEST_SUMMARY = /^Total tests/
|
|
10
|
-
TESTS_STARTED = /^Starting test execution, please wait...$/
|
|
11
|
-
|
|
12
|
-
attr_accessor :state_machine
|
|
13
|
-
|
|
14
|
-
def initialize(reporter:)
|
|
15
|
-
self.reporter = reporter
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def parse_line(input_line)
|
|
19
|
-
case state_machine.current_state_name
|
|
20
|
-
when :waiting
|
|
21
|
-
state_machine.trigger(:build_started)
|
|
22
|
-
when :build_in_progress
|
|
23
|
-
state_machine.trigger(:received_build_input, input_line)
|
|
24
|
-
when :reading_build_failure_details
|
|
25
|
-
state_machine.trigger(:received_build_failure_details, input_line)
|
|
26
|
-
when :ready_to_run_tests
|
|
27
|
-
state_machine.trigger(:received_input_line, input_line)
|
|
28
|
-
when :waiting_for_test_input
|
|
29
|
-
state_machine.trigger(:test_input_received, input_line)
|
|
30
|
-
when :waiting_for_failure_details
|
|
31
|
-
state_machine.trigger(:received_failure_details, input_line)
|
|
32
|
-
when :reading_failure_details
|
|
33
|
-
state_machine.trigger(:received_input_line, input_line)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def parse_build_input(input_line)
|
|
38
|
-
if input_line.match(BUILD_COMPLETED)
|
|
39
|
-
state_machine.trigger(:build_completed)
|
|
40
|
-
elsif input_line.match(BUILD_FAILED)
|
|
41
|
-
state_machine.trigger(:build_failed)
|
|
42
|
-
else
|
|
43
|
-
state_machine.trigger(:received_build_input)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def determine_if_tests_started(input_line)
|
|
48
|
-
if input_line.match(TESTS_STARTED)
|
|
49
|
-
state_machine.trigger(:tests_started)
|
|
50
|
-
else
|
|
51
|
-
state_machine.trigger(:tests_did_not_start)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def parse_test_input(input_line)
|
|
56
|
-
if input_line.match(TEST_PASSED)
|
|
57
|
-
match = input_line.match(/^Passed\s+(.+)$/)
|
|
58
|
-
state_machine.trigger(:test_passed, match[1])
|
|
59
|
-
elsif input_line.match(TEST_FAILED)
|
|
60
|
-
match = input_line.match(/^Failed\s+(.+)$/)
|
|
61
|
-
state_machine.trigger(:test_failed, match[1])
|
|
62
|
-
elsif input_line.match(TEST_SKIPPED)
|
|
63
|
-
match = input_line.match(/^Skipped\s+(.+)$/)
|
|
64
|
-
state_machine.trigger(:test_skipped, match[1])
|
|
65
|
-
elsif input_line.match(TEST_SUMMARY)
|
|
66
|
-
state_machine.trigger(:tests_completed, input_line)
|
|
67
|
-
else
|
|
68
|
-
state_machine.trigger(:received_other_input)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def build_completed
|
|
73
|
-
reporter.build_completed
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def build_started
|
|
77
|
-
reporter.build_started
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def reset_build_failure_details
|
|
81
|
-
self.build_failure_details = []
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def track_build_failure_details(input_line)
|
|
85
|
-
build_failure_details << input_line
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def report_failing_build
|
|
89
|
-
reporter.build_failed(build_failure_details)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def track_failure_details(details)
|
|
93
|
-
current_failing_test[:details] << details.rstrip if details.rstrip != ""
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def show_test_summary(summary)
|
|
97
|
-
match = summary.match(/^Total tests: (\d+). Passed: (\d+). Failed: (\d+). Skipped: (\d+)./)
|
|
98
|
-
reporter.show_test_summary({
|
|
99
|
-
failedTests: match[3].to_i,
|
|
100
|
-
passedTests: match[2].to_i,
|
|
101
|
-
skippedTests: match[4].to_i,
|
|
102
|
-
totalTests: match[1].to_i
|
|
103
|
-
})
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def report_failing_test(*args)
|
|
107
|
-
reporter.test_failed(current_failing_test)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def parse_failure_line(input_line)
|
|
111
|
-
if input_line.match(TEST_PASSED)
|
|
112
|
-
state_machine.trigger(:done_reading_failure, input_line)
|
|
113
|
-
elsif input_line.match(TEST_SUMMARY)
|
|
114
|
-
state_machine.trigger(:done_reading_failure, input_line)
|
|
115
|
-
elsif input_line.match(TEST_FAILED)
|
|
116
|
-
state_machine.trigger(:done_reading_failure, input_line)
|
|
117
|
-
else
|
|
118
|
-
state_machine.trigger(:received_failure_output, input_line)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def starting_tests
|
|
123
|
-
reporter.starting_tests
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def reset_current_failing_test(test_name)
|
|
127
|
-
self.current_failing_test = {
|
|
128
|
-
details: [],
|
|
129
|
-
name: test_name
|
|
130
|
-
}
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def test_passed(test_name)
|
|
134
|
-
reporter.test_passed(test_name)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def test_skipped(test_name)
|
|
138
|
-
reporter.test_skipped(test_name)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
private
|
|
142
|
-
|
|
143
|
-
attr_accessor :build_failure_details, :current_failing_test, :reporter
|
|
144
|
-
|
|
145
|
-
end
|
|
146
|
-
end
|