groonga-command 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/Gemfile +21 -0
  2. data/README.md +47 -0
  3. data/Rakefile +44 -0
  4. data/doc/text/lgpl-2.1.txt +502 -0
  5. data/doc/text/news.md +5 -0
  6. data/groonga-command.gemspec +64 -0
  7. data/lib/groonga/command.rb +20 -0
  8. data/lib/groonga/command/base.rb +138 -0
  9. data/lib/groonga/command/column-create.rb +39 -0
  10. data/lib/groonga/command/column-remove.rb +36 -0
  11. data/lib/groonga/command/column-rename.rb +37 -0
  12. data/lib/groonga/command/delete.rb +38 -0
  13. data/lib/groonga/command/error.rb +24 -0
  14. data/lib/groonga/command/get.rb +39 -0
  15. data/lib/groonga/command/load.rb +56 -0
  16. data/lib/groonga/command/parser.rb +424 -0
  17. data/lib/groonga/command/select.rb +69 -0
  18. data/lib/groonga/command/suggest.rb +47 -0
  19. data/lib/groonga/command/table-create.rb +39 -0
  20. data/lib/groonga/command/table-remove.rb +35 -0
  21. data/lib/groonga/command/table-rename.rb +36 -0
  22. data/lib/groonga/command/truncate.rb +35 -0
  23. data/lib/groonga/command/version.rb +23 -0
  24. data/test/command/test-base.rb +114 -0
  25. data/test/command/test-column-create.rb +47 -0
  26. data/test/command/test-column-remove.rb +41 -0
  27. data/test/command/test-column-rename.rb +43 -0
  28. data/test/command/test-delete.rb +45 -0
  29. data/test/command/test-get.rb +44 -0
  30. data/test/command/test-load.rb +49 -0
  31. data/test/command/test-select.rb +60 -0
  32. data/test/command/test-suggest.rb +68 -0
  33. data/test/command/test-table-create.rb +48 -0
  34. data/test/command/test-table-remove.rb +39 -0
  35. data/test/command/test-table-rename.rb +41 -0
  36. data/test/command/test-truncate.rb +39 -0
  37. data/test/groonga-command-test-utils.rb +102 -0
  38. data/test/run-test.rb +39 -0
  39. data/test/test-parser.rb +353 -0
  40. metadata +237 -0
@@ -0,0 +1,41 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ class TableRenameCommandTest < Test::Unit::TestCase
20
+ class CommandLineTest < self
21
+ include GroongaCommandTestUtils::CommandLineCommandParser
22
+
23
+ def test_ordered_arguments
24
+ name = "Users"
25
+ new_name = "People"
26
+
27
+ command = parse(name, new_name)
28
+ assert_instance_of(Groonga::Command::TableRename, command)
29
+ assert_equal({
30
+ :name => name,
31
+ :new_name => new_name,
32
+ },
33
+ command.arguments)
34
+ end
35
+
36
+ private
37
+ def parse(*arguments)
38
+ super("table_rename", arguments, :output_type => false)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,39 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ class TruncateCommandTest < Test::Unit::TestCase
20
+ class CommandLineTest < self
21
+ include GroongaCommandTestUtils::CommandLineCommandParser
22
+
23
+ def test_ordered_arguments
24
+ table = "Users"
25
+
26
+ command = parse(table)
27
+ assert_instance_of(Groonga::Command::Truncate, command)
28
+ assert_equal({
29
+ :table => table,
30
+ },
31
+ command.arguments)
32
+ end
33
+
34
+ private
35
+ def parse(*arguments)
36
+ super("truncate", arguments, :output_type => false)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,102 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "cgi"
20
+ require "stringio"
21
+
22
+ require "groonga/command"
23
+
24
+ module GroongaCommandTestUtils
25
+ module CommandParser
26
+ private
27
+ def command(name, arguments)
28
+ Groonga::Command.find(name).new(name, arguments)
29
+ end
30
+
31
+ def parse_http_path(command, arguments, options={})
32
+ path = "/d/#{command}"
33
+ case options[:output_type]
34
+ when false
35
+ when nil
36
+ path << ".json"
37
+ else
38
+ path << ".#{options[:output_type]}"
39
+ end
40
+
41
+ unless arguments.empty?
42
+ uri_arguments = arguments.collect do |key, value|
43
+ [CGI.escape(key.to_s), CGI.escape(value.to_s)].join("=")
44
+ end
45
+ path << "?"
46
+ path << uri_arguments.join("&")
47
+ end
48
+
49
+ Groonga::Command::Parser.parse(path)
50
+ end
51
+
52
+ def parse_command_line(command, arguments, options={})
53
+ command_line = "#{command}"
54
+ case options[:output_type]
55
+ when false
56
+ when nil
57
+ command_line << " --output_type json"
58
+ else
59
+ command_line << " --output_type #{options[:output_type]}"
60
+ end
61
+
62
+ if arguments.is_a?(Hash)
63
+ arguments.each do |key, value|
64
+ escaped_value = escape_command_line_value(value)
65
+ command_line << " --#{key} #{escaped_value}"
66
+ end
67
+ else
68
+ arguments.each do |argument|
69
+ command_line << " #{escape_command_line_value(argument)}"
70
+ end
71
+ end
72
+
73
+ Groonga::Command::Parser.parse(command_line)
74
+ end
75
+
76
+ def escape_command_line_value(value)
77
+ if /"| / =~ value
78
+ '"' + value.gsub(/"/, '\"') + '"'
79
+ else
80
+ value
81
+ end
82
+ end
83
+ end
84
+
85
+ module HTTPCommandParser
86
+ include CommandParser
87
+
88
+ private
89
+ def parse(command, arguments={}, options={})
90
+ parse_http_path(command, arguments, options)
91
+ end
92
+ end
93
+
94
+ module CommandLineCommandParser
95
+ include CommandParser
96
+
97
+ private
98
+ def parse(command, arguments={}, options={})
99
+ parse_command_line(command, arguments, options)
100
+ end
101
+ end
102
+ end
data/test/run-test.rb ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ $VERBOSE = true
20
+
21
+ $KCODE = "u" if RUBY_VERSION < "1.9"
22
+
23
+ base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
24
+ lib_dir = File.join(base_dir, "lib")
25
+ test_dir = File.join(base_dir, "test")
26
+
27
+ require "test-unit"
28
+ require "test/unit/notify"
29
+
30
+ Test::Unit::Priority.enable
31
+
32
+ $LOAD_PATH.unshift(lib_dir)
33
+ $LOAD_PATH.unshift(test_dir)
34
+
35
+ require "groonga-command-test-utils"
36
+
37
+ ENV["TEST_UNIT_MAX_DIFF_TARGET_STRING_SIZE"] ||= "5000"
38
+
39
+ exit Test::Unit::AutoRunner.run(true, test_dir)
@@ -0,0 +1,353 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ class ParserTest < Test::Unit::TestCase
20
+ module ParseTests
21
+ def test_parameters
22
+ select = parse("select",
23
+ :table => "Users",
24
+ :filter => "age<=30")
25
+ assert_equal(command("select",
26
+ "table" => "Users",
27
+ "filter" => "age<=30",
28
+ "output_type" => "json"),
29
+ select)
30
+ end
31
+ end
32
+
33
+ class HTTPTest < self
34
+ include GroongaCommandTestUtils::HTTPCommandParser
35
+
36
+ def test_uri_format?
37
+ command = parse("status")
38
+ assert_predicate(command, :uri_format?)
39
+ end
40
+
41
+ def test_command_format?
42
+ command = parse("status")
43
+ assert_not_predicate(command, :command_format?)
44
+ end
45
+
46
+ class ParseTest < self
47
+ include ParseTests
48
+ end
49
+ end
50
+
51
+ class CommandLineTest < self
52
+ include GroongaCommandTestUtils::CommandLineCommandParser
53
+
54
+ def test_uri_format?
55
+ command = parse("status")
56
+ assert_not_predicate(command, :uri_format?)
57
+ end
58
+
59
+ def test_command_format?
60
+ command = parse("status")
61
+ assert_predicate(command, :command_format?)
62
+ end
63
+
64
+ class ParseTest < self
65
+ include ParseTests
66
+ end
67
+
68
+ class EventTest < self
69
+ def setup
70
+ @parser = Groonga::Command::Parser.new
71
+ end
72
+
73
+ class CommandTest < self
74
+ def test_newline
75
+ parsed_command = nil
76
+ @parser.on_command do |command|
77
+ parsed_command = command
78
+ end
79
+
80
+ @parser << "status"
81
+ assert_nil(parsed_command)
82
+ @parser << "\n"
83
+ assert_equal("status", parsed_command.name)
84
+ end
85
+
86
+ def test_finish
87
+ parsed_command = nil
88
+ @parser.on_command do |command|
89
+ parsed_command = command
90
+ end
91
+
92
+ @parser << "status"
93
+ assert_nil(parsed_command)
94
+ @parser.finish
95
+ assert_equal("status", parsed_command.name)
96
+ end
97
+
98
+ def test_empty_line
99
+ parsed_command = nil
100
+ @parser.on_command do |command|
101
+ parsed_command = command
102
+ end
103
+
104
+ @parser << "\n"
105
+ assert_nil(parsed_command)
106
+
107
+ @parser << "status\n"
108
+ assert_equal("status", parsed_command.name)
109
+ end
110
+ end
111
+
112
+ class LoadTest < self
113
+ def setup
114
+ super
115
+ @events = []
116
+ @parser.on_load_start do |command|
117
+ @events << [:load_start, command.original_source.dup]
118
+ end
119
+ @parser.on_load_columns do |command, header|
120
+ @events << [:load_columns, command.original_source.dup, header]
121
+ end
122
+ @parser.on_load_value do |command, value|
123
+ @events << [:load_value, command.original_source.dup, value]
124
+ end
125
+ @parser.on_load_complete do |command|
126
+ @events << [:load_complete, command.original_source.dup]
127
+ end
128
+ end
129
+
130
+ class InlineTest < self
131
+ class BracketTest < self
132
+ def test_have_columns
133
+ command_line =
134
+ "load " +
135
+ "--columns '_key, name' " +
136
+ "--values '[[\"alice\", \"Alice\"]]' " +
137
+ "--table Users"
138
+ @parser << command_line
139
+ assert_equal([], @events)
140
+ @parser << "\n"
141
+ assert_equal([
142
+ [:load_start, command_line],
143
+ [:load_columns, command_line, ["_key", "name"]],
144
+ [:load_value, command_line, ["alice", "Alice"]],
145
+ [:load_complete, command_line],
146
+ ],
147
+ @events)
148
+ end
149
+
150
+ def test_no_columns
151
+ command_line = "load --values '[[\"_key\"], [1]]' --table IDs"
152
+ @parser << command_line
153
+ assert_equal([], @events)
154
+ @parser << "\n"
155
+ assert_equal([
156
+ [:load_start, command_line],
157
+ [:load_columns, command_line, ["_key"]],
158
+ [:load_value, command_line, [1]],
159
+ [:load_complete, command_line],
160
+ ],
161
+ @events)
162
+ end
163
+ end
164
+
165
+ def test_brace
166
+ command_line = "load --values '[{\"_key\": 1}]' --table IDs"
167
+ @parser << command_line
168
+ assert_equal([], @events)
169
+ @parser << "\n"
170
+ assert_equal([
171
+ [:load_start, command_line],
172
+ [:load_value, command_line, {"_key" => 1}],
173
+ [:load_complete, command_line],
174
+ ],
175
+ @events)
176
+ end
177
+ end
178
+
179
+ class MultiLineTest < self
180
+ class BracketTest < self
181
+ def test_have_columns
182
+ @parser << <<-EOC
183
+ load --table Users --columns "_key, name"
184
+ [
185
+ ["alice", "Alice"]
186
+ ]
187
+ EOC
188
+ expected_events = []
189
+ expected_events << [:load_start, <<-EOC.chomp]
190
+ load --table Users --columns "_key, name"
191
+ EOC
192
+ expected_events << [:load_columns, <<-EOC.chomp, ["_key", "name"]]
193
+ load --table Users --columns "_key, name"
194
+ EOC
195
+ expected_events << [:load_value, <<-EOC.chomp, ["alice", "Alice"]]
196
+ load --table Users --columns "_key, name"
197
+ [
198
+ ["alice", "Alice"]
199
+ EOC
200
+ expected_events << [:load_complete, <<-EOC.chomp]
201
+ load --table Users --columns "_key, name"
202
+ [
203
+ ["alice", "Alice"]
204
+ ]
205
+ EOC
206
+ assert_equal(expected_events, @events)
207
+ end
208
+
209
+ def test_no_columns
210
+ @parser << <<-EOC
211
+ load --table Users
212
+ [
213
+ ["_key", "name"],
214
+ ["alice", "Alice"]
215
+ ]
216
+ EOC
217
+ expected_events = []
218
+ expected_events << [:load_start, <<-EOC.chomp]
219
+ load --table Users
220
+ EOC
221
+ expected_events << [:load_columns, <<-EOC.chomp, ["_key", "name"]]
222
+ load --table Users
223
+ [
224
+ ["_key", "name"]
225
+ EOC
226
+ expected_events << [:load_value, <<-EOC.chomp, ["alice", "Alice"]]
227
+ load --table Users
228
+ [
229
+ ["_key", "name"],
230
+ ["alice", "Alice"]
231
+ EOC
232
+ expected_events << [:load_complete, <<-EOC.chomp]
233
+ load --table Users
234
+ [
235
+ ["_key", "name"],
236
+ ["alice", "Alice"]
237
+ ]
238
+ EOC
239
+ assert_equal(expected_events, @events)
240
+ end
241
+ end
242
+
243
+ def test_brace
244
+ @parser << <<-EOC
245
+ load --table Users
246
+ [
247
+ {"_key": "alice", "name": "Alice"},
248
+ {"_key": "bob", "name": "Bob"}
249
+ ]
250
+ EOC
251
+ expected_events = []
252
+ expected_events << [:load_start, <<-EOC.chomp]
253
+ load --table Users
254
+ EOC
255
+ value = {"_key" => "alice", "name" => "Alice"}
256
+ expected_events << [:load_value, <<-EOC.chomp, value]
257
+ load --table Users
258
+ [
259
+ {"_key": "alice", "name": "Alice"}
260
+ EOC
261
+ value = {"_key" => "bob", "name" => "Bob"}
262
+ expected_events << [:load_value, <<-EOC.chomp, value]
263
+ load --table Users
264
+ [
265
+ {"_key": "alice", "name": "Alice"},
266
+ {"_key": "bob", "name": "Bob"}
267
+ EOC
268
+ expected_events << [:load_complete, <<-EOC.chomp]
269
+ load --table Users
270
+ [
271
+ {"_key": "alice", "name": "Alice"},
272
+ {"_key": "bob", "name": "Bob"}
273
+ ]
274
+ EOC
275
+ assert_equal(expected_events, @events)
276
+ end
277
+ end
278
+
279
+ class ErrorTest < self
280
+ def test_location
281
+ message = "record separate comma is missing"
282
+ before = "{\"_key\": \"alice\", \"name\": \"Alice\"}"
283
+ after = "\n{\"_key\": \"bob\""
284
+ error = Groonga::Command::ParseError.new(message, before, after)
285
+ assert_equal(<<-EOS.chomp, error.message)
286
+ record separate comma is missing:
287
+ {"_key": "alice", "name": "Alice"}
288
+ ^
289
+ {"_key": "bob"
290
+ EOS
291
+ end
292
+
293
+ def test_no_record_separate_comma
294
+ message = "record separate comma is missing"
295
+ before = "{\"_key\": \"alice\", \"name\": \"Alice\"}"
296
+ after = "\n{\"_key\": \"bob\""
297
+ error = Groonga::Command::ParseError.new(message, before, after)
298
+ assert_raise(error) do
299
+ @parser << <<-EOC
300
+ load --table Users
301
+ [
302
+ {"_key": "alice", "name": "Alice"}
303
+ {"_key": "bob", "name": "Bob"}
304
+ EOC
305
+ end
306
+ end
307
+
308
+ def test_garbage_before_json
309
+ message = "there are garbages before JSON"
310
+ before = "load --table Users\n"
311
+ after = "XXX\n"
312
+ error = Groonga::Command::ParseError.new(message, before, after)
313
+ assert_raise(error) do
314
+ @parser << <<-EOC
315
+ load --table Users
316
+ XXX
317
+ [
318
+ {"_key": "alice", "name": "Alice"}
319
+ ]
320
+ EOC
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ class CommentTest < self
327
+ def test_newline
328
+ parsed_comment = nil
329
+ @parser.on_comment do |comment|
330
+ parsed_comment = comment
331
+ end
332
+
333
+ @parser << "# status"
334
+ assert_nil(parsed_comment)
335
+ @parser << "\n"
336
+ assert_equal(" status", parsed_comment)
337
+ end
338
+
339
+ def test_finish
340
+ parsed_comment = nil
341
+ @parser.on_comment do |comment|
342
+ parsed_comment = comment
343
+ end
344
+
345
+ @parser << "# status"
346
+ assert_nil(parsed_comment)
347
+ @parser.finish
348
+ assert_equal(" status", parsed_comment)
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end