scarpe-components 0.1.0 → 0.3.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/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)
|