mumuki-sqlite-runner 2.2.1 → 3.0.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 +5 -5
- data/lib/checker.rb +8 -6
- data/lib/html_renderer.rb +4 -3
- data/lib/locales/en.yml +7 -6
- data/lib/locales/es.yml +7 -6
- data/lib/parsers/common_test_parser.rb +27 -0
- data/lib/parsers/dataset_test_parser.rb +34 -0
- data/lib/parsers/final_dataset_test_parser.rb +10 -0
- data/lib/parsers/invalid_test_parser.rb +18 -0
- data/lib/parsers/query_test_parser.rb +21 -0
- data/lib/sqlite_runner.rb +6 -4
- data/lib/test_hook.rb +69 -66
- data/lib/version_hook.rb +1 -1
- data/lib/view/rows_success.html.erb +1 -1
- metadata +8 -6
- data/lib/dataset_solution_parser.rb +0 -34
- data/lib/extensions/hash_extension.rb +0 -6
- data/lib/query_solution_parser.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2ff96b8daaf98e39b42e29a2e4a0fda7447ede4b33db3a496bbe09d76b021456
|
4
|
+
data.tar.gz: 124dd0f35e776db7a7ffde818afdb6e3cd4779d8f1c248d0e61e3391dfd5dc08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a503486ccbe2dddbbdfdf0274d50574585fa95b1b578e609c874578c1f8369aeaea33acbb58e4ee537c2ba0af2ccb3a3f42935e7a6e2e668dab3eb5ba340c186
|
7
|
+
data.tar.gz: 3c2e5a3d94069b7122dbe584ce81c8e76c2cf0ac6866c3987687f8995fc5e0f7671740c923632ad7e8d2a71cc141dafe406c5a2ee1aca062c95b3ccaf642ff6a
|
data/lib/checker.rb
CHANGED
@@ -12,25 +12,27 @@ module Sqlite
|
|
12
12
|
when :equals
|
13
13
|
success(name, result)
|
14
14
|
when :distinct_columns
|
15
|
-
failed(name, result, solution,
|
15
|
+
failed(name, result, solution, 'columns')
|
16
16
|
when :distinct_rows
|
17
|
-
failed(name, result, solution,
|
17
|
+
failed(name, result, solution, 'rows')
|
18
18
|
else
|
19
|
-
failed(name, result, solution,
|
19
|
+
failed(name, result, solution, 'query')
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
def success(name, result)
|
24
|
-
|
24
|
+
message = I18n.t 'message.success.query'
|
25
|
+
[name, :passed, render_success(result, message)]
|
25
26
|
end
|
26
27
|
|
27
28
|
def failed(name, result, solution, error)
|
29
|
+
error = I18n.t "message.failure.#{error}"
|
28
30
|
[name, :failed, render_error(result, solution, error)]
|
29
31
|
end
|
30
32
|
|
31
33
|
# Return success page rendered with results
|
32
|
-
def render_success(result)
|
33
|
-
renderer.render_success result
|
34
|
+
def render_success(result, message)
|
35
|
+
renderer.render_success result, message
|
34
36
|
end
|
35
37
|
|
36
38
|
# Return error page rendered with results & solutions
|
data/lib/html_renderer.rb
CHANGED
@@ -3,9 +3,10 @@ require 'active_support/inflector'
|
|
3
3
|
module Sqlite
|
4
4
|
class HtmlRenderer
|
5
5
|
|
6
|
-
def render_success(result)
|
7
|
-
@
|
8
|
-
@
|
6
|
+
def render_success(result, message)
|
7
|
+
@message = message
|
8
|
+
@header = result[:dataset].header
|
9
|
+
@rows = result[:dataset].rows
|
9
10
|
template_file_success.result binding
|
10
11
|
end
|
11
12
|
|
data/lib/locales/en.yml
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
en:
|
2
2
|
dataset: "Dataset %{number}"
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
message:
|
4
|
+
success:
|
5
|
+
query: 'Correct Query!'
|
6
|
+
failure:
|
7
|
+
columns: 'Columns do not match'
|
8
|
+
rows: 'Rows do not match'
|
9
|
+
query: 'Queries do not match'
|
data/lib/locales/es.yml
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
es:
|
2
2
|
dataset: "Set de datos %{number}"
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
message:
|
4
|
+
success:
|
5
|
+
query: '¡Consulta correcta!'
|
6
|
+
failure:
|
7
|
+
columns: 'Las columnas no coinciden'
|
8
|
+
rows: 'Las filas no coinciden'
|
9
|
+
query: 'Las consultas no coinciden'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Sqlite
|
2
|
+
module CommonTestParser
|
3
|
+
|
4
|
+
COMMENT = '-- NONE'
|
5
|
+
attr_reader :result, :final
|
6
|
+
required :parse, 'You need to implement parse method when use CommonTestParse mixin!'
|
7
|
+
|
8
|
+
def initialize(test)
|
9
|
+
@result = parse test
|
10
|
+
end
|
11
|
+
|
12
|
+
def choose(solution)
|
13
|
+
solution
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def final_parse(test, override = {})
|
19
|
+
seed = test[:seed].blank? ? '' : test[:seed].strip
|
20
|
+
{
|
21
|
+
seed: override[:seed] || seed,
|
22
|
+
expected: override[:expected] || test[:expected].strip
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Sqlite
|
2
|
+
class DatasetTestParser
|
3
|
+
|
4
|
+
include Sqlite::CommonTestParser
|
5
|
+
|
6
|
+
def initialize(test)
|
7
|
+
@test = test
|
8
|
+
@result = parse test
|
9
|
+
end
|
10
|
+
|
11
|
+
# test = {
|
12
|
+
# type: dataset,
|
13
|
+
# seed: INSERT INTO ...,
|
14
|
+
# expected: |
|
15
|
+
# id|field
|
16
|
+
# 1|row 1
|
17
|
+
# ...
|
18
|
+
# }
|
19
|
+
#
|
20
|
+
# return {
|
21
|
+
# seed: INSERT INTO ...,
|
22
|
+
# expected: -- NONE
|
23
|
+
# }
|
24
|
+
def parse(test)
|
25
|
+
@solutions = test[:expected].to_s.split("\n").map(&:strip).join("\n")
|
26
|
+
final_parse test, {expected: '-- NONE'}
|
27
|
+
end
|
28
|
+
|
29
|
+
def choose(_solution)
|
30
|
+
@solutions
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Sqlite
|
2
|
+
class InvalidTestParser
|
3
|
+
|
4
|
+
include Sqlite::CommonTestParser
|
5
|
+
|
6
|
+
# return {
|
7
|
+
# seed: -- NONE,
|
8
|
+
# expected: -- NONE
|
9
|
+
# }
|
10
|
+
def parse(test)
|
11
|
+
final_parse(test, {
|
12
|
+
seed: COMMENT,
|
13
|
+
expected: COMMENT
|
14
|
+
})
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sqlite
|
2
|
+
class QueryTestParser
|
3
|
+
|
4
|
+
include Sqlite::CommonTestParser
|
5
|
+
|
6
|
+
# test = {
|
7
|
+
# type: query,
|
8
|
+
# seed: INSERT INTO ...,
|
9
|
+
# expected: SELECT * FROM ...
|
10
|
+
# }
|
11
|
+
#
|
12
|
+
# return {
|
13
|
+
# seed: INSERT INTO ...,
|
14
|
+
# expected: SELECT * FROM ...
|
15
|
+
# }
|
16
|
+
def parse(test)
|
17
|
+
final_parse test
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/sqlite_runner.rb
CHANGED
@@ -5,12 +5,11 @@ I18n.load_translations_path File.join(__dir__, 'locales', '*.yml')
|
|
5
5
|
|
6
6
|
Mumukit.runner_name = 'sqlite'
|
7
7
|
Mumukit.configure do |config|
|
8
|
-
config.docker_image = 'mumuki/mumuki-sqlite-worker'
|
8
|
+
config.docker_image = 'mumuki/mumuki-sqlite-worker:v3-rc1'
|
9
9
|
config.content_type = 'html'
|
10
10
|
config.structured = true
|
11
11
|
end
|
12
12
|
|
13
|
-
require_relative './extensions/hash_extension'
|
14
13
|
require_relative './version_hook'
|
15
14
|
require_relative './test_hook'
|
16
15
|
require_relative './metadata_hook'
|
@@ -18,6 +17,9 @@ require_relative './checker'
|
|
18
17
|
require_relative './multiple_executions_runner'
|
19
18
|
require_relative './html_renderer'
|
20
19
|
require_relative './dataset'
|
21
|
-
require_relative './
|
22
|
-
require_relative './
|
20
|
+
require_relative './parsers/common_test_parser'
|
21
|
+
require_relative './parsers/query_test_parser'
|
22
|
+
require_relative './parsers/dataset_test_parser'
|
23
|
+
require_relative './parsers/final_dataset_test_parser'
|
24
|
+
require_relative './parsers/invalid_test_parser'
|
23
25
|
require_relative './errors'
|
data/lib/test_hook.rb
CHANGED
@@ -9,6 +9,16 @@ class SqliteTestHook < Mumukit::Templates::FileHook
|
|
9
9
|
# Define that worker runs on a freshly-cleaned environment
|
10
10
|
isolated
|
11
11
|
|
12
|
+
def initialize(config = nil)
|
13
|
+
super(config)
|
14
|
+
@test_parsers = {
|
15
|
+
query: Sqlite::QueryTestParser,
|
16
|
+
datasets: Sqlite::DatasetTestParser,
|
17
|
+
final_dataset: Sqlite::FinalDatasetTestParser,
|
18
|
+
}
|
19
|
+
@test_parsers.default = Sqlite::InvalidTestParser
|
20
|
+
end
|
21
|
+
|
12
22
|
# Just define file extension
|
13
23
|
def tempfile_extension
|
14
24
|
'.json'
|
@@ -19,35 +29,36 @@ class SqliteTestHook < Mumukit::Templates::FileHook
|
|
19
29
|
"runsql #{filename}"
|
20
30
|
end
|
21
31
|
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# test:
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
32
|
+
# Transform Mumuki Request into Docker file style
|
33
|
+
# Request = {
|
34
|
+
# test: {
|
35
|
+
# type: (string) query|dataset,
|
36
|
+
# seed: (string) sql code to populate tables,
|
37
|
+
# expected: (string) query sentence | resulting table
|
38
|
+
# },
|
39
|
+
# extra: (string) sql code to create tables,
|
40
|
+
# content: (string) student's solution,
|
41
|
+
# expectations: [] # not using
|
28
42
|
# }
|
29
43
|
#
|
30
44
|
def compile_file_content(request)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
init:
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
}
|
39
|
-
|
40
|
-
content.to_json
|
45
|
+
tests = parse_tests request.test
|
46
|
+
final = get_final_query
|
47
|
+
{
|
48
|
+
init: request.extra.strip,
|
49
|
+
student: request.content.strip << final,
|
50
|
+
tests: tests
|
51
|
+
}.to_json
|
41
52
|
end
|
42
53
|
|
43
54
|
# Define how output results
|
44
55
|
# Expected:
|
45
56
|
# {
|
46
|
-
# "
|
57
|
+
# "expected": [
|
47
58
|
# "name\nTest 1.1\nTest 1.2\nTest 1.3\n",
|
48
59
|
# "name\nTest 2.1\nTest 2.2\nTest 2.3\n"
|
49
60
|
# ],
|
50
|
-
# "
|
61
|
+
# "student": [
|
51
62
|
# "id|name\n1|Test 1.1\n2|Test 1.2\n3|Test 1.3\n",
|
52
63
|
# "id|name\n1|Test 2.1\n2|Test 2.2\n3|Test 2.3\n"
|
53
64
|
# ]
|
@@ -57,8 +68,8 @@ class SqliteTestHook < Mumukit::Templates::FileHook
|
|
57
68
|
|
58
69
|
case status
|
59
70
|
when :passed
|
60
|
-
|
61
|
-
framework.test
|
71
|
+
expected, student = parse_output output
|
72
|
+
framework.test expected, student
|
62
73
|
when :failed
|
63
74
|
[output['output'], status]
|
64
75
|
else
|
@@ -69,33 +80,29 @@ class SqliteTestHook < Mumukit::Templates::FileHook
|
|
69
80
|
protected
|
70
81
|
|
71
82
|
def parse_output(output)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
83
|
+
student = output['student']
|
84
|
+
expected = output['expected']
|
85
|
+
expected.map!.with_index do |expect, i|
|
86
|
+
@expected_parser[i].choose expect
|
76
87
|
end
|
77
88
|
|
78
|
-
diff(
|
89
|
+
diff(expected, student)
|
79
90
|
end
|
80
91
|
|
81
|
-
def diff(
|
82
|
-
zipped =
|
83
|
-
|
84
|
-
diff
|
85
|
-
|
86
|
-
if diff.left.blank?
|
87
|
-
[solution, result]
|
88
|
-
else
|
89
|
-
res = post_process_diff diff.left
|
90
|
-
sol = post_process_diff diff.right
|
91
|
-
[sol, res]
|
92
|
-
end
|
93
|
-
|
92
|
+
def diff(expected, student)
|
93
|
+
zipped = expected.zip(student).map do |expected_i, student_i|
|
94
|
+
diff = Diffy::SplitDiff.new student_i << "\n", expected_i << "\n"
|
95
|
+
choose_left_right(diff, expected_i, student_i).map { |e| post_process_diff e }
|
94
96
|
end
|
95
|
-
|
96
97
|
zipped.transpose.map { |dataset| post_process_datasets dataset }
|
97
98
|
end
|
98
99
|
|
100
|
+
def choose_left_right(diff, expected, student)
|
101
|
+
expected = diff.left unless diff.left.blank?
|
102
|
+
student = diff.right unless diff.right.blank?
|
103
|
+
[expected, student]
|
104
|
+
end
|
105
|
+
|
99
106
|
def post_process_diff(data)
|
100
107
|
data.scan(/^(\s|-|\+)(.+)/)
|
101
108
|
.map { |mark, content| mark << '|' << content }
|
@@ -112,37 +119,33 @@ class SqliteTestHook < Mumukit::Templates::FileHook
|
|
112
119
|
end
|
113
120
|
end
|
114
121
|
|
115
|
-
#
|
122
|
+
# This method receives a list of test cases.
|
123
|
+
# Each one could be like one of these:
|
116
124
|
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
# examples: [
|
121
|
-
# { data: "INSERT INTO..." }
|
122
|
-
# ]
|
123
|
-
# }
|
125
|
+
# type: query
|
126
|
+
# seed: INSERT INTO ...
|
127
|
+
# expected: SELECT * FROM ...
|
124
128
|
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
case test.solution_type.to_sym
|
137
|
-
when :query
|
138
|
-
@solution_parser = Sqlite::QuerySolutionParser.new
|
139
|
-
when :datasets
|
140
|
-
@solution_parser = Sqlite::DatasetSolutionParser.new
|
141
|
-
else
|
142
|
-
raise Sqlite::TestSolutionTypeError
|
129
|
+
# type: dataset
|
130
|
+
# seed: INSERT INTO ...
|
131
|
+
# expected: |
|
132
|
+
# id|field
|
133
|
+
# 1|row 1
|
134
|
+
# ...
|
135
|
+
def parse_tests(tests)
|
136
|
+
tests = YAML.load tests
|
137
|
+
@tests = tests.map do | test |
|
138
|
+
test = test.to_struct
|
139
|
+
@test_parsers[test.type.to_sym].new test
|
143
140
|
end
|
144
141
|
|
145
|
-
@
|
142
|
+
@expected_parser = @tests
|
143
|
+
@tests.map(&:result)
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_final_query
|
147
|
+
parsers = @expected_parser.select { |parser| !parser.final.blank? }
|
148
|
+
parsers.empty? ? '' : parsers.first.final
|
146
149
|
end
|
147
150
|
|
148
151
|
# Initialize Metatest Framework with Checker & Runner
|
data/lib/version_hook.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mumuki-sqlite-runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leandro Di Lorenzo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mumukit
|
@@ -173,15 +173,17 @@ extra_rdoc_files: []
|
|
173
173
|
files:
|
174
174
|
- lib/checker.rb
|
175
175
|
- lib/dataset.rb
|
176
|
-
- lib/dataset_solution_parser.rb
|
177
176
|
- lib/errors.rb
|
178
|
-
- lib/extensions/hash_extension.rb
|
179
177
|
- lib/html_renderer.rb
|
180
178
|
- lib/locales/en.yml
|
181
179
|
- lib/locales/es.yml
|
182
180
|
- lib/metadata_hook.rb
|
183
181
|
- lib/multiple_executions_runner.rb
|
184
|
-
- lib/
|
182
|
+
- lib/parsers/common_test_parser.rb
|
183
|
+
- lib/parsers/dataset_test_parser.rb
|
184
|
+
- lib/parsers/final_dataset_test_parser.rb
|
185
|
+
- lib/parsers/invalid_test_parser.rb
|
186
|
+
- lib/parsers/query_test_parser.rb
|
185
187
|
- lib/sqlite_runner.rb
|
186
188
|
- lib/test_hook.rb
|
187
189
|
- lib/version_hook.rb
|
@@ -207,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
209
|
version: '0'
|
208
210
|
requirements: []
|
209
211
|
rubyforge_project:
|
210
|
-
rubygems_version: 2.
|
212
|
+
rubygems_version: 2.7.3
|
211
213
|
signing_key:
|
212
214
|
specification_version: 4
|
213
215
|
summary: SQLite Runner for Mumuki
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Sqlite
|
2
|
-
class DatasetSolutionParser
|
3
|
-
|
4
|
-
# If solutions comes in an explicit datasets,
|
5
|
-
# it was stored in instance variable.
|
6
|
-
# Expected input:
|
7
|
-
# OpenStruct#{
|
8
|
-
# solution_type: 'datasets',
|
9
|
-
# examples: [
|
10
|
-
# {
|
11
|
-
# dataset: "INSERT INTO ...\nINSERT INTO ...",
|
12
|
-
# solution_dataset: "id|field\n1|row1..."
|
13
|
-
# }
|
14
|
-
# ]
|
15
|
-
# }
|
16
|
-
def parse_test(test)
|
17
|
-
data = []
|
18
|
-
@solutions = []
|
19
|
-
solution_query = '-- none'
|
20
|
-
|
21
|
-
test.examples.each do |item|
|
22
|
-
@solutions << item[:solution_dataset].scan(/(?!\|).+(?<!\|)/).join("\n")
|
23
|
-
data.append item[:data]
|
24
|
-
end
|
25
|
-
|
26
|
-
return solution_query, data
|
27
|
-
end
|
28
|
-
|
29
|
-
def choose(_solution)
|
30
|
-
@solutions
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module Sqlite
|
2
|
-
class QuerySolutionParser
|
3
|
-
|
4
|
-
# Expected input:
|
5
|
-
# OpenStruct#{
|
6
|
-
# solution_type: 'query',
|
7
|
-
# solution_query: 'select * from motores;',
|
8
|
-
# examples: [
|
9
|
-
# { dataset: "INSERT INTO ...\nINSERT INTO ..." }
|
10
|
-
# ]
|
11
|
-
# }
|
12
|
-
def parse_test(test)
|
13
|
-
data = test.examples.map do |item|
|
14
|
-
item[:data]
|
15
|
-
end
|
16
|
-
|
17
|
-
return test.solution_query, data
|
18
|
-
end
|
19
|
-
|
20
|
-
def choose(solution)
|
21
|
-
solution
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|