mumukit 2.17.0 → 2.27.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/lib/locales/en.yml +3 -1
- data/lib/locales/es.yml +2 -0
- data/lib/locales/pt.yml +17 -0
- data/lib/mumukit/defaults/default_precompile_hook.rb +5 -0
- data/lib/mumukit/defaults.rb +2 -1
- data/lib/mumukit/metatest/checker.rb +42 -7
- data/lib/mumukit/metatest/interactive_checker.rb +28 -11
- data/lib/mumukit/runner.rb +24 -5
- data/lib/mumukit/runtime/info.rb +13 -10
- data/lib/mumukit/server/app.rb +3 -6
- data/lib/mumukit/server/test_server.rb +19 -5
- data/lib/mumukit/templates/expectations_hook.rb +81 -0
- data/lib/mumukit/templates/file_hook.rb +0 -1
- data/lib/mumukit/templates/mulang_expectations_hook.rb +10 -30
- data/lib/mumukit/templates/multi_file_precompile_hook.rb +49 -0
- data/lib/mumukit/templates/try_hook.rb +3 -1
- data/lib/mumukit/templates/with_multiple_files.rb +6 -0
- data/lib/mumukit/templates.rb +7 -3
- data/lib/mumukit/version.rb +1 -1
- data/lib/mumukit.rb +8 -1
- metadata +30 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa9b52569d8acc92b3996ab2797748cb26b04c8b424eabe47c8ea1fcd8f554a0
|
|
4
|
+
data.tar.gz: 18a004a9b5ccf64c278952ac02ac3fc1f5942c3acbd06ed583c5623c8c422f49
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c403421b59fde8fb7a27ca8448d43a1331b86d590199278b5bf26f7ae76c165220ab67d97bf6eff63c8a082aa1b3de59ab51e1b90968dbf7056c2db36182603
|
|
7
|
+
data.tar.gz: a03dba8b04f49b4dfa4a0127db26021f47d6d9ca550ef8bd0ac30c2578c660ac990701622e887120293369c7c2efdebd290c87a2cf8c4b6763ab9abe2a7b44fb
|
data/lib/locales/en.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
en:
|
|
2
2
|
mumukit:
|
|
3
|
-
memory_exceeded: Memory limit exceeded. Is your program trying to allocate
|
|
3
|
+
memory_exceeded: Memory limit exceeded. Is your program trying to allocate too much memory?
|
|
4
4
|
time_exceeded: Execution time limit of %{limit}s exceeded. Is your program performing an infinite loop or recursion?
|
|
5
5
|
masked_tempfile_basename: solution
|
|
6
6
|
interactive:
|
|
@@ -8,6 +8,8 @@ en:
|
|
|
8
8
|
check_last_query_fails: "query should fail but it passed"
|
|
9
9
|
check_last_query_matches: "query does not match regex %{regex}"
|
|
10
10
|
check_last_query_outputs: "query output should be '%{expected}' but was '%{actual}'"
|
|
11
|
+
check_last_query_includes: "query output should include '%{expected}' but was '%{actual}'"
|
|
12
|
+
check_last_query_like: "query output should be like '%{expected}' but was '%{actual}'"
|
|
11
13
|
check_last_query_passes: "query should pass but it failed"
|
|
12
14
|
check_query_fails: "query '%{query}' should fail but it passed"
|
|
13
15
|
check_query_outputs: "query '%{query}' output should be '%{expected}' but was '%{actual}'"
|
data/lib/locales/es.yml
CHANGED
|
@@ -8,6 +8,8 @@ es:
|
|
|
8
8
|
check_last_query_fails: "La consulta debería fallar pero pasó"
|
|
9
9
|
check_last_query_matches: "La consulta no cumple con la expresión regular %{regex}"
|
|
10
10
|
check_last_query_outputs: "La consulta debería devolver '%{expected}' pero devolvió '%{actual}'"
|
|
11
|
+
check_last_query_includes: "La consulta debería incluir '%{expected}' pero devolvió '%{actual}'"
|
|
12
|
+
check_last_query_like: "La consulta debería ser como '%{expected}' pero devolvió '%{actual}'"
|
|
11
13
|
check_last_query_passes: "La consulta debería pasar pero falló"
|
|
12
14
|
check_query_fails: "La consulta '%{query}' debería fallar pero pasó"
|
|
13
15
|
check_query_outputs: "La consulta '%{query}' debería devolver '%{expected}' pero devolvió '%{actual}'"
|
data/lib/locales/pt.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
pt:
|
|
2
|
+
mumukit:
|
|
3
|
+
memory_exceeded: Limite de memoria excedido. ¿Tu programa está alocando demasiada memoria?
|
|
4
|
+
time_exceeded: Limite de tempo de execução de %{limit}s excedido. O seu programa está executando um loop ou recursão infinito?
|
|
5
|
+
masked_tempfile_basename: solução
|
|
6
|
+
interactive:
|
|
7
|
+
check_last_query_equals: "a consulta deve ser '%{expected}' mas foi '%{actual}'"
|
|
8
|
+
check_last_query_fails: "a consulta deve falhar, mas passou"
|
|
9
|
+
check_last_query_matches: "A consulta não corresponde a regex %{regex}"
|
|
10
|
+
check_last_query_outputs: "O resultado da consulta deve ser '%{expected}', mas foi '%{actual}'"
|
|
11
|
+
check_last_query_includes: "O resultado da consulta deve incluir '%{expected}', mas foi '%{actual}'"
|
|
12
|
+
check_last_query_like: "O resultado da consulta deve ser como '%{expected}', mas foi '%{actual}'"
|
|
13
|
+
check_last_query_passes: "A consulta deve passar, mas falhou"
|
|
14
|
+
check_query_fails: "a consulta '%{query}' deve falhar, mas passou"
|
|
15
|
+
check_query_outputs: "a consulta '%{query}' deve ser '%{expected}', mas foi '%{actual}'"
|
|
16
|
+
check_query_passes: "a consulta '%{query}' deve passar, mas falhou"
|
|
17
|
+
goal_passed: "O objetivo foi alcançado com sucesso"
|
data/lib/mumukit/defaults.rb
CHANGED
|
@@ -9,5 +9,6 @@ require_relative './defaults/default_query_hook'
|
|
|
9
9
|
require_relative './defaults/default_feedback_hook'
|
|
10
10
|
require_relative './defaults/default_validation_hook'
|
|
11
11
|
require_relative './defaults/default_test_hook'
|
|
12
|
+
require_relative './defaults/default_precompile_hook'
|
|
12
13
|
require_relative './defaults/default_try_hook'
|
|
13
|
-
require_relative './defaults/default_metadata_hook'
|
|
14
|
+
require_relative './defaults/default_metadata_hook'
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
module Mumukit::Metatest
|
|
2
2
|
class Checker
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
|
|
4
|
+
## Check an input against a metatest example.
|
|
5
|
+
## The example has the following shape:
|
|
6
|
+
##
|
|
7
|
+
## ```
|
|
8
|
+
## {
|
|
9
|
+
## name: 'an example name',
|
|
10
|
+
## postconditions: {
|
|
11
|
+
## an_assertion: assertion_config,
|
|
12
|
+
## another_assertion: assertion_config,
|
|
13
|
+
## }
|
|
14
|
+
## }
|
|
15
|
+
## ```
|
|
16
|
+
##
|
|
17
|
+
## Alternatively, the `postconditions` key may be omitted:
|
|
18
|
+
##
|
|
19
|
+
## ```
|
|
20
|
+
## {
|
|
21
|
+
## name: 'an example name',
|
|
22
|
+
## an_assertion: assertion_config,
|
|
23
|
+
## another_assertion: assertion_config,
|
|
24
|
+
## }
|
|
25
|
+
##
|
|
26
|
+
def check(input, example)
|
|
27
|
+
check_assertions input, postconditions_for(example), example
|
|
28
|
+
[example[:name], :passed, render_success_output(input)]
|
|
6
29
|
rescue => e
|
|
7
|
-
[example[:name], :failed, render_error_output(
|
|
30
|
+
[example[:name], :failed, render_error_output(input, e.message)]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
## If no postconditions are included in the example,
|
|
34
|
+
## all the example except by the name is considered as postconditions
|
|
35
|
+
def postconditions_for(example)
|
|
36
|
+
example[:postconditions] || example.except(:name)
|
|
8
37
|
end
|
|
9
38
|
|
|
10
39
|
def render_success_output(value)
|
|
@@ -15,8 +44,14 @@ module Mumukit::Metatest
|
|
|
15
44
|
error
|
|
16
45
|
end
|
|
17
46
|
|
|
18
|
-
def
|
|
19
|
-
|
|
47
|
+
def check_assertions(input, assertions_hash, example)
|
|
48
|
+
assertions_hash.each do |assertion_name, assertion_config|
|
|
49
|
+
check_assertion assertion_name, input, assertion_config, example
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def check_assertion(assertion_name, input, assertion_config, _example)
|
|
54
|
+
send "check_#{assertion_name}", input, assertion_config
|
|
20
55
|
end
|
|
21
56
|
|
|
22
57
|
def fail(message)
|
|
@@ -31,4 +66,4 @@ module Mumukit::Metatest
|
|
|
31
66
|
raise Mumukit::Metatest::Errored, message
|
|
32
67
|
end
|
|
33
68
|
end
|
|
34
|
-
end
|
|
69
|
+
end
|
|
@@ -6,42 +6,54 @@ module Mumukit::Metatest
|
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def check_last_query_equals(_result, goal)
|
|
9
|
-
expected = goal[:
|
|
10
|
-
actual = @request.query
|
|
9
|
+
expected = goal[:value]
|
|
10
|
+
actual = @request.query.strip
|
|
11
11
|
fail_t :check_last_query_equals, expected: expected, actual: actual unless expected == actual
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def check_last_query_matches(_result, goal)
|
|
15
|
-
regex = goal[:
|
|
15
|
+
regex = goal[:regexp]
|
|
16
16
|
fail_t :check_last_query_matches, regex: regex.inspect unless regex.matches? @request.query
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def check_last_query_fails(result, _goal)
|
|
20
|
-
fail_t :check_last_query_fails unless result[:query][:status]
|
|
20
|
+
fail_t :check_last_query_fails unless result[:query][:status].failed?
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def check_last_query_outputs(result, goal)
|
|
24
|
-
expected
|
|
24
|
+
compare_last_query_by(:check_last_query_outputs, result, goal) { |expected, actual| expected == actual }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check_last_query_output_includes(result, goal)
|
|
28
|
+
compare_last_query_by(:check_last_query_output_includes, result, goal) { |expected, actual| actual.include? expected }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def check_last_query_output_like(result, goal)
|
|
32
|
+
compare_last_query_by(:check_last_query_output_like, result, goal) { |expected, actual| normalize(expected) == normalize(actual) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def compare_last_query_by(sym, result, goal, &condition)
|
|
36
|
+
expected = goal[:output]
|
|
25
37
|
actual = result[:query][:result]
|
|
26
|
-
fail_t
|
|
38
|
+
fail_t sym, expected: expected, actual: actual unless condition.call expected, actual
|
|
27
39
|
end
|
|
28
40
|
|
|
29
41
|
def check_last_query_passes(result, _goal)
|
|
30
|
-
fail_t :check_last_query_passes unless result[:query][:status]
|
|
42
|
+
fail_t :check_last_query_passes unless result[:query][:status].passed?
|
|
31
43
|
end
|
|
32
44
|
|
|
33
45
|
def check_query_passes(result, goal)
|
|
34
|
-
fail_t :check_query_passes, query: goal
|
|
46
|
+
fail_t :check_query_passes, query: goal[:query] unless result[:status].passed?
|
|
35
47
|
end
|
|
36
48
|
|
|
37
49
|
def check_query_fails(result, goal)
|
|
38
|
-
fail_t :check_query_fails, query: goal
|
|
50
|
+
fail_t :check_query_fails, query: goal[:query] unless result[:status].failed?
|
|
39
51
|
end
|
|
40
52
|
|
|
41
53
|
def check_query_outputs(result, goal)
|
|
42
|
-
expected = goal
|
|
54
|
+
expected = goal[:output]
|
|
43
55
|
actual = result[:goal]
|
|
44
|
-
fail_t :check_query_outputs, query: goal
|
|
56
|
+
fail_t :check_query_outputs, query: goal[:query], expected: expected, actual: actual unless expected == actual
|
|
45
57
|
end
|
|
46
58
|
|
|
47
59
|
def render_success_output(_value)
|
|
@@ -55,5 +67,10 @@ module Mumukit::Metatest
|
|
|
55
67
|
def locale(sym)
|
|
56
68
|
'mumukit.interactive.' + sym.to_s
|
|
57
69
|
end
|
|
70
|
+
|
|
71
|
+
def normalize(a_string)
|
|
72
|
+
a_string.delete(" \t\r\n").downcase
|
|
73
|
+
end
|
|
74
|
+
|
|
58
75
|
end
|
|
59
76
|
end
|
data/lib/mumukit/runner.rb
CHANGED
|
@@ -11,6 +11,12 @@ class Mumukit::Runner
|
|
|
11
11
|
yield @config
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def reconfigure(&block)
|
|
15
|
+
@config = nil
|
|
16
|
+
@pipeline = nil
|
|
17
|
+
configure &block
|
|
18
|
+
end
|
|
19
|
+
|
|
14
20
|
def configure_runtime(config)
|
|
15
21
|
@runtime = Mumukit::Runtime.new(config)
|
|
16
22
|
end
|
|
@@ -30,16 +36,29 @@ class Mumukit::Runner
|
|
|
30
36
|
def new_directives_pipeline
|
|
31
37
|
if config.preprocessor_enabled
|
|
32
38
|
Mumukit::Directives::Pipeline.new(
|
|
33
|
-
[
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
[new_sections_directive,
|
|
40
|
+
new_interpolations_directive('test'),
|
|
41
|
+
new_interpolations_directive('extra'),
|
|
42
|
+
new_interpolations_directive('content'),
|
|
43
|
+
new_flags_directive],
|
|
37
44
|
config.comment_type)
|
|
38
45
|
else
|
|
39
46
|
Mumukit::Directives::NullPipeline
|
|
40
47
|
end
|
|
41
48
|
end
|
|
42
49
|
|
|
50
|
+
def new_interpolations_directive(key)
|
|
51
|
+
Mumukit::Directives::Interpolations.new(key)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def new_sections_directive
|
|
55
|
+
Mumukit::Directives::Sections.new nest_sections: Mumukit.config.multifile
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def new_flags_directive
|
|
59
|
+
Mumukit::Directives::Flags.new
|
|
60
|
+
end
|
|
61
|
+
|
|
43
62
|
def self.default_config
|
|
44
63
|
@default_config
|
|
45
64
|
end
|
|
@@ -48,4 +67,4 @@ class Mumukit::Runner
|
|
|
48
67
|
@default_config ||= OpenStruct.new
|
|
49
68
|
yield @default_config
|
|
50
69
|
end
|
|
51
|
-
end
|
|
70
|
+
end
|
data/lib/mumukit/runtime/info.rb
CHANGED
|
@@ -6,19 +6,22 @@ module Mumukit::RuntimeInfo
|
|
|
6
6
|
escualo_base_version: ENV['ESCUALO_BASE_VERSION'],
|
|
7
7
|
escualo_service_version: ENV['ESCUALO_SERVICE_VERSION'],
|
|
8
8
|
mumukit_version: Mumukit::VERSION,
|
|
9
|
+
worker_image: Mumukit.config.docker_image,
|
|
9
10
|
output_content_type: Mumukit.config.content_type,
|
|
10
11
|
comment_type: Mumukit.config.comment_type,
|
|
11
12
|
features: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
precompile: precompile_hook?,
|
|
14
|
+
query: query_hook?,
|
|
15
|
+
try: try_hook?,
|
|
16
|
+
expectations: expectations_hook?,
|
|
17
|
+
feedback: feedback_hook?,
|
|
18
|
+
secure: validation_hook?,
|
|
19
|
+
stateful: Mumukit.config.stateful,
|
|
20
|
+
multifile: Mumukit.config.multifile,
|
|
21
|
+
preprocessor: Mumukit.config.preprocessor_enabled,
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
sandboxed: any_hook_include?([:test, :query], Mumukit::Templates::WithIsolatedEnvironment),
|
|
24
|
+
structured: any_hook_include?([:test], Mumukit::Templates::WithStructuredResults) || Mumukit.config.structured
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
end
|
|
@@ -28,4 +31,4 @@ module Mumukit::RuntimeInfo
|
|
|
28
31
|
def any_hook_include?(hooks, mixin)
|
|
29
32
|
hooks.any? { |it| hook_includes?(it, mixin) }
|
|
30
33
|
end
|
|
31
|
-
end
|
|
34
|
+
end
|
data/lib/mumukit/server/app.rb
CHANGED
|
@@ -6,7 +6,7 @@ require 'json'
|
|
|
6
6
|
class Mumukit::Server::App < Sinatra::Base
|
|
7
7
|
configure do
|
|
8
8
|
set :mumuki_url, 'http://mumuki.io'
|
|
9
|
-
set :show_exceptions,
|
|
9
|
+
set :show_exceptions, false
|
|
10
10
|
enable :logging
|
|
11
11
|
end
|
|
12
12
|
|
|
@@ -65,11 +65,8 @@ class Mumukit::Server::App < Sinatra::Base
|
|
|
65
65
|
|
|
66
66
|
error StandardError do
|
|
67
67
|
content_type :json
|
|
68
|
-
status
|
|
69
|
-
|
|
68
|
+
status 500
|
|
70
69
|
message = Mumukit::ContentType::Plain.format_exception env['sinatra.error']
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{status: :errored, exit: message}.to_json
|
|
70
|
+
{exit: :errored, out: message}.to_json
|
|
74
71
|
end
|
|
75
72
|
end
|
|
@@ -10,7 +10,10 @@ class Mumukit::Server::TestServer
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def info(url)
|
|
13
|
-
runtime.info
|
|
13
|
+
runtime.info
|
|
14
|
+
.merge(repo_url: default_repo_url)
|
|
15
|
+
.merge(runtime.metadata_hook.metadata)
|
|
16
|
+
.merge(url: url)
|
|
14
17
|
end
|
|
15
18
|
|
|
16
19
|
def start_request!(_request)
|
|
@@ -58,13 +61,13 @@ class Mumukit::Server::TestServer
|
|
|
58
61
|
end
|
|
59
62
|
|
|
60
63
|
def run_tests!(request)
|
|
61
|
-
return ['', :passed] if request.test
|
|
64
|
+
return ['', :passed] if should_skip_tests?(request.test)
|
|
62
65
|
|
|
63
66
|
compile_and_run runtime.test_hook, request
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
def run_expectations!(request)
|
|
67
|
-
return [] if
|
|
70
|
+
return [] if should_skip_expectations?(request)
|
|
68
71
|
|
|
69
72
|
compile_and_run runtime.expectations_hook, request
|
|
70
73
|
end
|
|
@@ -91,19 +94,30 @@ class Mumukit::Server::TestServer
|
|
|
91
94
|
end
|
|
92
95
|
|
|
93
96
|
def preprocess(request)
|
|
94
|
-
Mumukit.directives_pipeline.transform(request)
|
|
97
|
+
runtime.precompile_hook.compile Mumukit.directives_pipeline.transform(request)
|
|
95
98
|
end
|
|
96
99
|
|
|
97
100
|
def validate_request!(request)
|
|
98
101
|
runtime.validation_hook.validate! request
|
|
99
102
|
end
|
|
100
103
|
|
|
104
|
+
def should_skip_expectations?(request)
|
|
105
|
+
request.expectations.nil? || (request.content.nil? && !Mumukit.config.process_expectations_on_empty_content)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def should_skip_tests?(tests)
|
|
109
|
+
tests.blank? && !Mumukit.config.run_test_hook_on_empty_test
|
|
110
|
+
end
|
|
111
|
+
|
|
101
112
|
def respond_to(request)
|
|
102
113
|
yield preprocess request.tap { |r| validate_request! r }
|
|
103
114
|
rescue Mumukit::RequestValidationError => e
|
|
104
115
|
{exit: :aborted, out: e.message}
|
|
105
|
-
rescue
|
|
116
|
+
rescue => e
|
|
106
117
|
{exit: :errored, out: content_type.format_exception(e)}
|
|
107
118
|
end
|
|
108
119
|
|
|
120
|
+
def default_repo_url
|
|
121
|
+
"https://github.com/mumuki/mumuki-#{Mumukit.runner_name}-runner"
|
|
122
|
+
end
|
|
109
123
|
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'mumukit/inspection'
|
|
2
|
+
|
|
3
|
+
module Mumukit
|
|
4
|
+
class Templates::ExpectationsHook < Mumukit::Hook
|
|
5
|
+
SOURCE_EXPECTATION_EVALUATORS = {
|
|
6
|
+
'SourceRepeats' => lambda { |source, target| source.scan(target).count > 1 },
|
|
7
|
+
'SourceContains' => lambda { |source, target| source.include? target },
|
|
8
|
+
'SourceEquals' => lambda { |source, target| source == target },
|
|
9
|
+
'SourceEqualsIgnoreSpaces' => lambda { |source, target| source.delete(' ') == target.delete(' ') }
|
|
10
|
+
}
|
|
11
|
+
SOURCE_EXPECTATIONS = SOURCE_EXPECTATION_EVALUATORS.keys.flat_map { |it| [it, "Not:#{it}"] }
|
|
12
|
+
|
|
13
|
+
def compile(request)
|
|
14
|
+
{ request: request, expectations: compile_expectations(request) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run!(spec)
|
|
18
|
+
spec[:expectations][:source].map { |it| it.evaluate spec[:request][:content] }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def compile_expectations(request)
|
|
24
|
+
expectations = {ast: [], source: [], exceptions: []}
|
|
25
|
+
request[:expectations].each do |it|
|
|
26
|
+
fill_expectations it.deep_symbolize_keys, expectations
|
|
27
|
+
end
|
|
28
|
+
expectations
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def fill_expectations(expectation, expectations)
|
|
32
|
+
inspection = expectation[:inspection]
|
|
33
|
+
if inspection&.start_with? 'Except:'
|
|
34
|
+
expectations[:exceptions] << inspection[7..-1]
|
|
35
|
+
elsif SOURCE_EXPECTATIONS.any? { |it| inspection.starts_with? it }
|
|
36
|
+
expectations[:source] << compile_source_expectation(expectation)
|
|
37
|
+
else
|
|
38
|
+
expectations[:ast] << compile_expectation(expectation)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def compile_expectation(expectation)
|
|
43
|
+
Mumukit::Inspection::Expectation.parse(expectation).as_v2.to_h
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def compile_source_expectation(expectation)
|
|
47
|
+
SourceExpectation.parse(expectation)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class SourceExpectation
|
|
51
|
+
def initialize(expectation, evaluator)
|
|
52
|
+
@expectation = expectation
|
|
53
|
+
@evaluator = evaluator
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def evaluate(content)
|
|
57
|
+
{ result: evaluate_inspection(content), expectation: @expectation.to_h }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def inspection
|
|
61
|
+
@expectation.inspection
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.parse(expectation)
|
|
65
|
+
parsed = Mumukit::Inspection::Expectation.parse(expectation)
|
|
66
|
+
evaluator = parse_evaluator(parsed.inspection)
|
|
67
|
+
new parsed, evaluator
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def evaluate_inspection(content)
|
|
73
|
+
inspection.negated? ^ @evaluator.call(content, inspection.target.value)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.parse_evaluator(inspection)
|
|
77
|
+
SOURCE_EXPECTATION_EVALUATORS[inspection.type]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -1,29 +1,31 @@
|
|
|
1
|
-
require 'mumukit/inspection'
|
|
2
1
|
require 'mulang'
|
|
3
2
|
|
|
4
3
|
module Mumukit
|
|
5
|
-
class Templates::MulangExpectationsHook < Mumukit::
|
|
4
|
+
class Templates::MulangExpectationsHook < Mumukit::Templates::ExpectationsHook
|
|
6
5
|
LOGIC_SMELLS = %w(UsesCut UsesFail UsesUnificationOperator HasRedundantReduction)
|
|
7
6
|
FUNCTIONAL_SMELLS = %w(HasRedundantParameter HasRedundantGuards)
|
|
8
7
|
OBJECT_ORIENTED_SMELLS = %w(DoesNullTest ReturnsNull)
|
|
9
8
|
IMPERATIVE_SMELLS = %w(HasRedundantLocalVariableReturn HasAssignmentReturn)
|
|
10
9
|
EXPRESSIVENESS_SMELLS = %w(HasTooShortBindings HasWrongCaseBindings HasMisspelledBindings)
|
|
11
|
-
GENERIC_SMELLS = %w(IsLongCode HasCodeDuplication HasRedundantLambda HasRedundantIf DoesTypeTest HasRedundantBooleanComparison)
|
|
10
|
+
GENERIC_SMELLS = %w(IsLongCode HasCodeDuplication HasRedundantLambda HasRedundantIf DoesTypeTest HasRedundantBooleanComparison HasEmptyIfBranches)
|
|
12
11
|
|
|
13
12
|
required :language, 'You have to provide a Mulang-compatible language in order to use this hook'
|
|
14
13
|
|
|
15
|
-
def
|
|
16
|
-
|
|
14
|
+
def run!(spec)
|
|
15
|
+
super(spec) + run_mulang_analysis(compile_mulang_analysis(spec[:request], spec[:expectations]))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def compile_mulang_analysis(request, expectations)
|
|
17
19
|
mulang_code(request).analysis(
|
|
18
|
-
expectations: expectations,
|
|
20
|
+
expectations: expectations[:ast],
|
|
19
21
|
smellsSet: {
|
|
20
22
|
tag: 'AllSmells',
|
|
21
|
-
exclude: (exceptions + default_smell_exceptions)
|
|
23
|
+
exclude: (expectations[:exceptions] + default_smell_exceptions)
|
|
22
24
|
},
|
|
23
25
|
domainLanguage: domain_language)
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
def
|
|
28
|
+
def run_mulang_analysis(analysis)
|
|
27
29
|
parse_response Mulang.analyse(analysis)
|
|
28
30
|
rescue JSON::ParserError
|
|
29
31
|
raise Mumukit::CompilationError, "Can not handle mulang results for analysis #{analysis}"
|
|
@@ -50,32 +52,10 @@ module Mumukit
|
|
|
50
52
|
language == 'Mulang' ? Mulang::Language::External.new : Mulang::Language::Native.new(language)
|
|
51
53
|
end
|
|
52
54
|
|
|
53
|
-
def compile_expectations_and_exceptions(request)
|
|
54
|
-
expectations = []
|
|
55
|
-
exceptions = []
|
|
56
|
-
request[:expectations].each do |it|
|
|
57
|
-
fill_expectations_and_excetions it.deep_symbolize_keys, expectations, exceptions
|
|
58
|
-
end
|
|
59
|
-
[expectations, exceptions]
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def fill_expectations_and_excetions(expectation, expectations, exceptions)
|
|
63
|
-
inspection = expectation[:inspection]
|
|
64
|
-
if inspection&.start_with? 'Except:'
|
|
65
|
-
exceptions << inspection[7..-1]
|
|
66
|
-
else
|
|
67
|
-
expectations << compile_expectation(expectation)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
55
|
def compile_content(content)
|
|
72
56
|
content
|
|
73
57
|
end
|
|
74
58
|
|
|
75
|
-
def compile_expectation(expectation)
|
|
76
|
-
Mumukit::Inspection::Expectation.parse(expectation).as_v2.to_h
|
|
77
|
-
end
|
|
78
|
-
|
|
79
59
|
def parse_response(response)
|
|
80
60
|
if response['tag'] == 'AnalysisFailed'
|
|
81
61
|
raise Mumukit::CompilationError, response['reason']
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Mumukit
|
|
2
|
+
class Templates::MultiFilePrecompileHook < Mumukit::Hook
|
|
3
|
+
include Mumukit::Templates::WithMultipleFiles
|
|
4
|
+
|
|
5
|
+
def compile(request)
|
|
6
|
+
request
|
|
7
|
+
.to_h
|
|
8
|
+
.merge(content: files_content(request))
|
|
9
|
+
.to_struct
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def main_file
|
|
13
|
+
raise NotImplementedError
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def consolidate(main_content, files)
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def files_content(request)
|
|
23
|
+
files = files_of request
|
|
24
|
+
if files.empty?
|
|
25
|
+
no_files_content request
|
|
26
|
+
elsif files.count == 1
|
|
27
|
+
single_file_content files
|
|
28
|
+
else
|
|
29
|
+
multi_file_content files
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def no_files_content(request)
|
|
34
|
+
request.content
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def single_file_content(files)
|
|
38
|
+
files.values.first
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def multi_file_content(files)
|
|
42
|
+
consolidate main_file_content(files), files
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def main_file_content(files)
|
|
46
|
+
files[main_file] || ''
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
module Mumukit
|
|
2
2
|
class Templates::TryHook < Templates::FileHook
|
|
3
3
|
def compile(request)
|
|
4
|
-
|
|
4
|
+
request_goal = request.goal.with_indifferent_access
|
|
5
|
+
|
|
6
|
+
@goal = {postconditions: [[request_goal[:kind], request_goal]]}
|
|
5
7
|
@checker = Metatest::InteractiveChecker.new request
|
|
6
8
|
super request
|
|
7
9
|
end
|
data/lib/mumukit/templates.rb
CHANGED
|
@@ -3,8 +3,6 @@ module Mumukit
|
|
|
3
3
|
end
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
-
require_relative './templates/file_hook'
|
|
7
|
-
require_relative './templates/try_hook'
|
|
8
6
|
require_relative './templates/with_structured_results'
|
|
9
7
|
require_relative './templates/with_metatest'
|
|
10
8
|
require_relative './templates/with_metatest_results'
|
|
@@ -12,6 +10,12 @@ require_relative './templates/with_mashup_file_content'
|
|
|
12
10
|
require_relative './templates/with_embedded_environment'
|
|
13
11
|
require_relative './templates/with_isolated_environment'
|
|
14
12
|
require_relative './templates/with_line_number_offset'
|
|
15
|
-
require_relative './templates/
|
|
13
|
+
require_relative './templates/with_multiple_files'
|
|
16
14
|
require_relative './templates/with_code_smells'
|
|
17
15
|
require_relative './templates/with_cookie'
|
|
16
|
+
|
|
17
|
+
require_relative './templates/file_hook'
|
|
18
|
+
require_relative './templates/try_hook'
|
|
19
|
+
require_relative './templates/expectations_hook'
|
|
20
|
+
require_relative './templates/mulang_expectations_hook'
|
|
21
|
+
require_relative './templates/multi_file_precompile_hook'
|
data/lib/mumukit/version.rb
CHANGED
data/lib/mumukit.rb
CHANGED
|
@@ -22,12 +22,16 @@ module Mumukit
|
|
|
22
22
|
current_runner.name
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def self.runner_url
|
|
26
|
+
Rack::Request.new(Mumukit::Env.env).base_url
|
|
27
|
+
end
|
|
28
|
+
|
|
25
29
|
def self.configure_defaults(&block)
|
|
26
30
|
Mumukit::Runner.configure_defaults(&block)
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
class << self
|
|
30
|
-
delegate :prefix, :config, :configure, :runtime, :configure_runtime, :directives_pipeline, to: :current_runner
|
|
34
|
+
delegate :prefix, :config, :configure, :reconfigure, :runtime, :configure_runtime, :directives_pipeline, to: :current_runner
|
|
31
35
|
end
|
|
32
36
|
end
|
|
33
37
|
|
|
@@ -42,6 +46,9 @@ Mumukit.configure_defaults do |config|
|
|
|
42
46
|
config.stateful = false
|
|
43
47
|
config.command_time_limit = 4
|
|
44
48
|
config.command_size_limit = 1024
|
|
49
|
+
config.process_expectations_on_empty_content = false
|
|
50
|
+
config.run_test_hook_on_empty_test = false
|
|
51
|
+
config.multifile = false
|
|
45
52
|
end
|
|
46
53
|
|
|
47
54
|
require 'mumukit/content_type'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mumukit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.27.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Franco Leonardo Bulgarelli
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2018-10-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -80,6 +80,20 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rack-test
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
83
97
|
- !ruby/object:Gem::Dependency
|
|
84
98
|
name: sinatra
|
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,14 +184,14 @@ dependencies:
|
|
|
170
184
|
requirements:
|
|
171
185
|
- - "~>"
|
|
172
186
|
- !ruby/object:Gem::Version
|
|
173
|
-
version: '
|
|
187
|
+
version: '4.0'
|
|
174
188
|
type: :runtime
|
|
175
189
|
prerelease: false
|
|
176
190
|
version_requirements: !ruby/object:Gem::Requirement
|
|
177
191
|
requirements:
|
|
178
192
|
- - "~>"
|
|
179
193
|
- !ruby/object:Gem::Version
|
|
180
|
-
version: '
|
|
194
|
+
version: '4.0'
|
|
181
195
|
- !ruby/object:Gem::Dependency
|
|
182
196
|
name: mumukit-inspection
|
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -196,36 +210,30 @@ dependencies:
|
|
|
196
210
|
name: mumukit-core
|
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
|
198
212
|
requirements:
|
|
199
|
-
- - "
|
|
200
|
-
- !ruby/object:Gem::Version
|
|
201
|
-
version: '0.2'
|
|
202
|
-
- - "<"
|
|
213
|
+
- - "~>"
|
|
203
214
|
- !ruby/object:Gem::Version
|
|
204
|
-
version: '
|
|
215
|
+
version: '1.3'
|
|
205
216
|
type: :runtime
|
|
206
217
|
prerelease: false
|
|
207
218
|
version_requirements: !ruby/object:Gem::Requirement
|
|
208
219
|
requirements:
|
|
209
|
-
- - "
|
|
210
|
-
- !ruby/object:Gem::Version
|
|
211
|
-
version: '0.2'
|
|
212
|
-
- - "<"
|
|
220
|
+
- - "~>"
|
|
213
221
|
- !ruby/object:Gem::Version
|
|
214
|
-
version: '
|
|
222
|
+
version: '1.3'
|
|
215
223
|
- !ruby/object:Gem::Dependency
|
|
216
224
|
name: mumukit-directives
|
|
217
225
|
requirement: !ruby/object:Gem::Requirement
|
|
218
226
|
requirements:
|
|
219
227
|
- - "~>"
|
|
220
228
|
- !ruby/object:Gem::Version
|
|
221
|
-
version: '0.
|
|
229
|
+
version: '0.4'
|
|
222
230
|
type: :runtime
|
|
223
231
|
prerelease: false
|
|
224
232
|
version_requirements: !ruby/object:Gem::Requirement
|
|
225
233
|
requirements:
|
|
226
234
|
- - "~>"
|
|
227
235
|
- !ruby/object:Gem::Version
|
|
228
|
-
version: '0.
|
|
236
|
+
version: '0.4'
|
|
229
237
|
- !ruby/object:Gem::Dependency
|
|
230
238
|
name: mumukit-content-type
|
|
231
239
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -256,6 +264,7 @@ files:
|
|
|
256
264
|
- bin/limit
|
|
257
265
|
- lib/locales/en.yml
|
|
258
266
|
- lib/locales/es.yml
|
|
267
|
+
- lib/locales/pt.yml
|
|
259
268
|
- lib/mumukit.rb
|
|
260
269
|
- lib/mumukit/compilation_error.rb
|
|
261
270
|
- lib/mumukit/cookie.rb
|
|
@@ -263,6 +272,7 @@ files:
|
|
|
263
272
|
- lib/mumukit/defaults/default_expectations_hook.rb
|
|
264
273
|
- lib/mumukit/defaults/default_feedback_hook.rb
|
|
265
274
|
- lib/mumukit/defaults/default_metadata_hook.rb
|
|
275
|
+
- lib/mumukit/defaults/default_precompile_hook.rb
|
|
266
276
|
- lib/mumukit/defaults/default_query_hook.rb
|
|
267
277
|
- lib/mumukit/defaults/default_test_hook.rb
|
|
268
278
|
- lib/mumukit/defaults/default_try_hook.rb
|
|
@@ -291,8 +301,10 @@ files:
|
|
|
291
301
|
- lib/mumukit/server/test_pipeline.rb
|
|
292
302
|
- lib/mumukit/server/test_server.rb
|
|
293
303
|
- lib/mumukit/templates.rb
|
|
304
|
+
- lib/mumukit/templates/expectations_hook.rb
|
|
294
305
|
- lib/mumukit/templates/file_hook.rb
|
|
295
306
|
- lib/mumukit/templates/mulang_expectations_hook.rb
|
|
307
|
+
- lib/mumukit/templates/multi_file_precompile_hook.rb
|
|
296
308
|
- lib/mumukit/templates/try_hook.rb
|
|
297
309
|
- lib/mumukit/templates/with_code_smells.rb
|
|
298
310
|
- lib/mumukit/templates/with_cookie.rb
|
|
@@ -302,6 +314,7 @@ files:
|
|
|
302
314
|
- lib/mumukit/templates/with_mashup_file_content.rb
|
|
303
315
|
- lib/mumukit/templates/with_metatest.rb
|
|
304
316
|
- lib/mumukit/templates/with_metatest_results.rb
|
|
317
|
+
- lib/mumukit/templates/with_multiple_files.rb
|
|
305
318
|
- lib/mumukit/templates/with_structured_results.rb
|
|
306
319
|
- lib/mumukit/version.rb
|
|
307
320
|
- lib/mumukit/with_command_line.rb
|
|
@@ -328,7 +341,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
328
341
|
version: '0'
|
|
329
342
|
requirements: []
|
|
330
343
|
rubyforge_project:
|
|
331
|
-
rubygems_version: 2.7.
|
|
344
|
+
rubygems_version: 2.7.7
|
|
332
345
|
signing_key:
|
|
333
346
|
specification_version: 4
|
|
334
347
|
summary: Mumuki Test Server Development Kit
|