mumuki-sqlite-runner 2.2.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e574ef63ec53b93d7841532738042a3be0899079
4
- data.tar.gz: a87d92c79f8af4546ef46eb34e6faa7e0d26572c
2
+ SHA256:
3
+ metadata.gz: 2ff96b8daaf98e39b42e29a2e4a0fda7447ede4b33db3a496bbe09d76b021456
4
+ data.tar.gz: 124dd0f35e776db7a7ffde818afdb6e3cd4779d8f1c248d0e61e3391dfd5dc08
5
5
  SHA512:
6
- metadata.gz: 28dca88c0eae83a3d5e34173b47b6702d805e1bc3d3ff70a99d7d546001c157386f91ca9d6e8b93c13b43561576caf0b1d2e0e4329b598d79c73e5ab1f8ca4b4
7
- data.tar.gz: aeba550111b462b085d48c9b590822ddd03fdefa874303ccadb13c89867c55120c06612ded7402f871fb3cdaffb95c3d2297e45cd4310c2af36a167ed4e66240
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, (I18n.t 'failure.columns'))
15
+ failed(name, result, solution, 'columns')
16
16
  when :distinct_rows
17
- failed(name, result, solution, (I18n.t 'failure.rows'))
17
+ failed(name, result, solution, 'rows')
18
18
  else
19
- failed(name, result, solution, (I18n.t 'failure.query'))
19
+ failed(name, result, solution, 'query')
20
20
  end
21
21
  end
22
22
 
23
23
  def success(name, result)
24
- [name, :passed, render_success(result)]
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
- @header = result[:dataset].header
8
- @rows = result[:dataset].rows
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
- success:
4
- query: 'Correct Query!'
5
- failure:
6
- columns: 'Columns do not match'
7
- rows: 'Rows do not match'
8
- query: 'Queries do not match'
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
- success:
4
- query: '¡Consulta correcta!'
5
- failure:
6
- columns: 'Las columnas no coinciden'
7
- rows: 'Las filas no coinciden'
8
- query: 'Las consultas no coinciden'
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,10 @@
1
+ module Sqlite
2
+ class FinalDatasetTestParser < DatasetTestParser
3
+
4
+ def initialize(test)
5
+ super(test)
6
+ @final = test[:query] || test[:final]
7
+ end
8
+
9
+ end
10
+ 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 './dataset_solution_parser'
22
- require_relative './query_solution_parser'
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
- # Define the .json file template from request structure
23
- # Input: request = {
24
- # test: (yaml string) teacher's code that define which testing verification student code should pass,
25
- # extra: (sql string) teacher's code that prepare field where student code should run,
26
- # content: (sql string) student code,
27
- # expectations: [] not using for now
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
- solution, data = parse_test request.test
32
-
33
- content = {
34
- init: request.extra.strip,
35
- solution: solution,
36
- student: request.content.strip,
37
- datasets: data
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
- # "solutions": [
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
- # "results": [
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
- solutions, results = parse_output output
61
- framework.test solutions, results
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
- results = output['results']
73
- solutions = output['solutions']
74
- unless @solution_parser.nil?
75
- solutions = @solution_parser.choose solutions
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(solutions, results)
89
+ diff(expected, student)
79
90
  end
80
91
 
81
- def diff(solutions, results)
82
- zipped = solutions.zip(results).map do |solution, result|
83
-
84
- diff = Diffy::SplitDiff.new result << "\n", solution << "\n"
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
- # Test should have one of these formats:
122
+ # This method receives a list of test cases.
123
+ # Each one could be like one of these:
116
124
  #
117
- # Solution by query:
118
- # { solution_type: 'query',
119
- # solution_query: 'SELECT * FROM ...',
120
- # examples: [
121
- # { data: "INSERT INTO..." }
122
- # ]
123
- # }
125
+ # type: query
126
+ # seed: INSERT INTO ...
127
+ # expected: SELECT * FROM ...
124
128
  #
125
- # Solution by datasets:
126
- # { solution_type: 'datasets',
127
- # examples: [
128
- # { data: "INSERT INTO...",
129
- # solution: "id|field\n1|row1..."
130
- # }
131
- # ]
132
- # }
133
- def parse_test(test)
134
- test = OpenStruct.new YAML.load(test).deep_symbolize_keys
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
- @solution_parser.parse_test test
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
@@ -1,3 +1,3 @@
1
1
  module SqliteVersionHook
2
- VERSION = '2.2.1'
2
+ VERSION = '3.0.0'
3
3
  end
@@ -20,7 +20,7 @@
20
20
  }
21
21
  </style>
22
22
 
23
- <h5><%= I18n.t 'success.query' %></h5>
23
+ <h5><%= message %></h5>
24
24
  <table class="table table-bordered sqlite_success">
25
25
  <thead>
26
26
  <tr>
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: 2.2.1
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-10-12 00:00:00.000000000 Z
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/query_solution_parser.rb
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.6.14
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,6 +0,0 @@
1
-
2
- class Hash
3
- def to_yaml
4
- super.sub('---', '').strip
5
- end
6
- 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