scarpe-components 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +22 -0
- data/Gemfile.lock +86 -0
- data/lib/scarpe/components/base64.rb +25 -0
- data/lib/scarpe/components/calzini/alert.rb +49 -0
- data/lib/scarpe/components/calzini/art_widgets.rb +203 -0
- data/lib/scarpe/components/calzini/button.rb +39 -0
- data/lib/scarpe/components/calzini/misc.rb +146 -0
- data/lib/scarpe/components/calzini/para.rb +35 -0
- data/lib/scarpe/components/calzini/slots.rb +155 -0
- data/lib/scarpe/components/calzini/text_widgets.rb +65 -0
- data/lib/scarpe/components/calzini.rb +149 -0
- data/lib/scarpe/components/errors.rb +20 -0
- data/lib/scarpe/components/file_helpers.rb +66 -0
- data/lib/scarpe/components/html.rb +131 -0
- data/lib/scarpe/components/minitest_export_reporter.rb +75 -0
- data/lib/scarpe/components/minitest_import_runnable.rb +98 -0
- data/lib/scarpe/components/minitest_result.rb +86 -0
- data/lib/scarpe/{logger.rb → components/modular_logger.rb} +11 -6
- data/lib/scarpe/components/print_logger.rb +47 -0
- data/lib/scarpe/components/promises.rb +454 -0
- data/lib/scarpe/components/segmented_file_loader.rb +189 -0
- data/lib/scarpe/components/string_helpers.rb +10 -0
- data/lib/scarpe/components/tiranti.rb +225 -0
- data/lib/scarpe/components/unit_test_helpers.rb +257 -0
- data/lib/scarpe/components/version.rb +7 -0
- metadata +28 -4
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest"
|
4
|
+
require "json"
|
5
|
+
require "json/add/exception"
|
6
|
+
|
7
|
+
module Scarpe; module Components; end; end
|
8
|
+
module Scarpe::Components::ImportRunnables
|
9
|
+
# Minitest Runnables are unusual - we expect to declare a class (like a Test) with
|
10
|
+
# a lot of methods to run. The ImportRunnable is a single Runnable. But whenever
|
11
|
+
# you tell it to import a JSON file, it will add all of the described tests to
|
12
|
+
# its runnable methods.
|
13
|
+
#
|
14
|
+
# Normally that means that your subclass tests will run up front and produce
|
15
|
+
# JSON files, then Minitest will autorun at the end and report all their
|
16
|
+
# results.
|
17
|
+
#
|
18
|
+
# It wouldn't really make sense to create these runnables during the testing
|
19
|
+
# phase, because Minitest has already decided what to run at that point.
|
20
|
+
class ImportRunnable #< Minitest::Runnable
|
21
|
+
# Import JSON from an exported Minitest run. Note that running this multiple
|
22
|
+
# times with overlapping class names may be really bad.
|
23
|
+
def self.import_json_data(data)
|
24
|
+
@imported_classes ||= {}
|
25
|
+
@imported_tests ||= {}
|
26
|
+
|
27
|
+
JSON.parse(data).each do |item|
|
28
|
+
klass = item["klass"]
|
29
|
+
meth = item["name"]
|
30
|
+
@imported_tests[klass] ||= {}
|
31
|
+
@imported_tests[klass][meth] = item
|
32
|
+
end
|
33
|
+
|
34
|
+
@imported_tests.each do |klass_name, test_method_hash|
|
35
|
+
klass = @imported_classes[klass_name]
|
36
|
+
unless klass
|
37
|
+
new_klass = Class.new(Minitest::Runnable)
|
38
|
+
@imported_classes[klass_name] = new_klass
|
39
|
+
ImportRunnable.const_set(klass_name, new_klass)
|
40
|
+
klass = new_klass
|
41
|
+
|
42
|
+
klass.define_singleton_method(:run_one_method) do |klass, method_name, reporter|
|
43
|
+
reporter.prerecord klass, method_name
|
44
|
+
imp = test_method_hash[method_name]
|
45
|
+
|
46
|
+
res = Minitest::Result.new imp["name"]
|
47
|
+
res.klass = imp["klass"]
|
48
|
+
res.assertions = imp["assertions"]
|
49
|
+
res.time = imp["time"]
|
50
|
+
res.failures = ImportRunnable.deserialize_failures imp["failures"]
|
51
|
+
res.metadata = imp["metadata"] if imp["metadata"]
|
52
|
+
|
53
|
+
# Record the synthetic result built from imported data
|
54
|
+
reporter.record res
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Update "runnables" method to reflect all current known runnable tests
|
59
|
+
klass_methods = test_method_hash.keys
|
60
|
+
klass.define_singleton_method(:runnable_methods) do
|
61
|
+
klass_methods
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.json_to_err(err_json)
|
67
|
+
klass = begin
|
68
|
+
Object.const_get(err_json["json_class"])
|
69
|
+
rescue
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
if klass && klass <= Minitest::Assertion
|
73
|
+
klass.json_create(err_json)
|
74
|
+
else
|
75
|
+
err = Exception.json_create(err_json)
|
76
|
+
Minitest::UnexpectedError.new(err)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.deserialize_failures(failures)
|
81
|
+
failures.map do |fail|
|
82
|
+
# Instantiate the Minitest::Assertion or Minitest::UnexpectedError
|
83
|
+
if fail[0] == "exception"
|
84
|
+
exc_json = JSON.parse(fail[1])
|
85
|
+
json_to_err exc_json
|
86
|
+
elsif fail[0] == "unexpected"
|
87
|
+
unexpected_json = JSON.parse(fail[1])
|
88
|
+
inner_json = JSON.parse(fail[2])
|
89
|
+
outer_err = json_to_err unexpected_json
|
90
|
+
inner_err = json_to_err inner_json
|
91
|
+
outer_err.error = inner_err
|
92
|
+
else
|
93
|
+
raise "Unknown exception data when trying to deserialize! #{fail.inspect}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "minitest"
|
4
|
+
require "json"
|
5
|
+
#require "json/add/exception"
|
6
|
+
|
7
|
+
module Scarpe; module Components; end; end
|
8
|
+
|
9
|
+
# A MinitestResult imports a JSON file from a minitest_export_reporter.
|
10
|
+
# But instead of creating a Minitest::Test to report the result, the
|
11
|
+
# MinitestResult is just a queryable Ruby object.
|
12
|
+
#
|
13
|
+
# MinitestResult assumes there will be only one class and one method
|
14
|
+
# in the JSON, which is true for Scarpe but not necessarily in general.
|
15
|
+
class Scarpe::Components::MinitestResult
|
16
|
+
attr_reader :assertions
|
17
|
+
attr_reader :method_name
|
18
|
+
attr_reader :class_name
|
19
|
+
|
20
|
+
def initialize(filename)
|
21
|
+
data = JSON.parse File.read(filename)
|
22
|
+
|
23
|
+
unless data.size == 1
|
24
|
+
# We would want a different interface to support this in general. For now we don't
|
25
|
+
# need it to work in general.
|
26
|
+
raise "Scarpe::Components::MinitestResult only supports one class and method in results!"
|
27
|
+
end
|
28
|
+
|
29
|
+
item = data.first
|
30
|
+
|
31
|
+
@assertions = item["assertions"]
|
32
|
+
@method_name = item["name"]
|
33
|
+
@class_name = item["klass"]
|
34
|
+
@time = item["time"]
|
35
|
+
@metadata = item.key?("metadata") ? item["metadata"]: {}
|
36
|
+
|
37
|
+
@skip = false
|
38
|
+
@exceptions = []
|
39
|
+
@failures = []
|
40
|
+
item["failures"].each do |f|
|
41
|
+
# JSON.parse ignores json_class and won't create an arbitrary object. That's good
|
42
|
+
# because Minitest::UnexpectedError seems to load in a bad way, so we don't want
|
43
|
+
# it to auto-instantiate.
|
44
|
+
d = JSON.parse f[1]
|
45
|
+
msg = d["m"]
|
46
|
+
case d["json_class"]
|
47
|
+
when "Minitest::UnexpectedError"
|
48
|
+
@exceptions << msg
|
49
|
+
when "Minitest::Skip"
|
50
|
+
@skip = msg
|
51
|
+
when "Minitest::Assertion"
|
52
|
+
@failures << msg
|
53
|
+
else
|
54
|
+
raise Scarpe::InternalError, "Didn't expect type #{t.inspect} as exception type when importing Minitest tests!"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def error?
|
60
|
+
!@exceptions.empty?
|
61
|
+
end
|
62
|
+
|
63
|
+
def fail?
|
64
|
+
!@failures.empty?
|
65
|
+
end
|
66
|
+
|
67
|
+
def skip?
|
68
|
+
@skip ? true : false
|
69
|
+
end
|
70
|
+
|
71
|
+
def passed?
|
72
|
+
@exceptions.empty? && @failures.empty? && !@skip
|
73
|
+
end
|
74
|
+
|
75
|
+
def error_message
|
76
|
+
@exceptions[0]
|
77
|
+
end
|
78
|
+
|
79
|
+
def fail_message
|
80
|
+
@failures[0]
|
81
|
+
end
|
82
|
+
|
83
|
+
def skip_message
|
84
|
+
@skip
|
85
|
+
end
|
86
|
+
end
|
@@ -5,10 +5,12 @@ require "json"
|
|
5
5
|
|
6
6
|
require "shoes/log"
|
7
7
|
|
8
|
-
#
|
8
|
+
# Requires the logging gem
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
module Scarpe; end
|
11
|
+
module Scarpe::Components; end
|
12
|
+
module Scarpe
|
13
|
+
class Components::ModularLogImpl
|
12
14
|
include Shoes::Log # for constants
|
13
15
|
|
14
16
|
def logger_for_component(component)
|
@@ -30,7 +32,7 @@ class Scarpe
|
|
30
32
|
when "fatal"
|
31
33
|
:fatal
|
32
34
|
else
|
33
|
-
raise "Don't know how to treat #{data.inspect} as a logger severity!"
|
35
|
+
raise Shoes::Errors::InvalidAttributeValueError, "Don't know how to treat #{data.inspect} as a logger severity!"
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
@@ -43,7 +45,7 @@ class Scarpe
|
|
43
45
|
when String
|
44
46
|
Logging.appenders.file data, layout: @custom_log_layout
|
45
47
|
else
|
46
|
-
raise "Don't know how to convert #{data.inspect} to an appender!"
|
48
|
+
raise Shoes::Errors::InvalidAttributeValueError, "Don't know how to convert #{data.inspect} to an appender!"
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
@@ -62,7 +64,7 @@ class Scarpe
|
|
62
64
|
|
63
65
|
logger.level = name_to_severity(level)
|
64
66
|
else
|
65
|
-
raise "Don't know how to use #{data.inspect} to specify a logger!"
|
67
|
+
raise Shoes::Errors::InvalidAttributeValueError, "Don't know how to use #{data.inspect} to specify a logger!"
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
@@ -106,3 +108,6 @@ class Scarpe
|
|
106
108
|
end
|
107
109
|
end
|
108
110
|
end
|
111
|
+
|
112
|
+
#Shoes::Log.instance = Scarpe::Components::ModularLogImpl.new
|
113
|
+
#Shoes::Log.configure_logger(Shoes::Log::DEFAULT_LOG_CONFIG)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "shoes/log"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module Scarpe; end
|
7
|
+
module Scarpe::Components; end
|
8
|
+
class Scarpe::Components::PrintLogImpl
|
9
|
+
include Shoes::Log # for constants
|
10
|
+
|
11
|
+
class PrintLogger
|
12
|
+
class << self
|
13
|
+
attr_accessor :silence
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(component_name)
|
17
|
+
@comp_name = component_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def error(msg)
|
21
|
+
puts "#{@comp_name} error: #{msg}" unless PrintLogger.silence
|
22
|
+
end
|
23
|
+
|
24
|
+
def warn(msg)
|
25
|
+
puts "#{@comp_name} warn: #{msg}" unless PrintLogger.silence
|
26
|
+
end
|
27
|
+
|
28
|
+
def debug(msg)
|
29
|
+
puts "#{@comp_name} debug: #{msg}" unless PrintLogger.silence
|
30
|
+
end
|
31
|
+
|
32
|
+
def info(msg)
|
33
|
+
puts "#{@comp_name} info: #{msg}" unless PrintLogger.silence
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def logger_for_component(component)
|
38
|
+
PrintLogger.new(component.to_s)
|
39
|
+
end
|
40
|
+
|
41
|
+
def configure_logger(log_config)
|
42
|
+
# For now, ignore
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#Shoes::Log.instance = Scarpe::PrintLogImpl.new
|
47
|
+
#Shoes::Log.configure_logger(Shoes::Log::DEFAULT_LOG_CONFIG)
|