groonga 0.0.2 → 0.0.3
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.
- data/NEWS.ja.rdoc +18 -3
- data/NEWS.rdoc +18 -3
- data/README.ja.rdoc +2 -0
- data/README.rdoc +2 -0
- data/Rakefile +14 -5
- data/TUTORIAL.ja.rdoc +82 -16
- data/benchmark/{read-write-small-many-items.rb → read-write-many-small-items.rb} +26 -23
- data/benchmark/{write-small-many-items.rb → write-many-small-items.rb} +26 -23
- data/example/bookmark.rb +49 -5
- data/ext/rb-grn-array.c +11 -1
- data/ext/rb-grn-column.c +132 -5
- data/ext/rb-grn-context.c +85 -80
- data/ext/rb-grn-database.c +182 -9
- data/ext/rb-grn-expression-builder.c +69 -0
- data/ext/rb-grn-expression.c +314 -0
- data/ext/rb-grn-fix-size-column.c +68 -89
- data/ext/rb-grn-hash.c +14 -5
- data/ext/rb-grn-index-column.c +14 -55
- data/ext/rb-grn-object.c +206 -75
- data/ext/rb-grn-operation.c +92 -0
- data/ext/rb-grn-patricia-trie.c +10 -32
- data/ext/rb-grn-query.c +9 -9
- data/ext/rb-grn-table-cursor.c +19 -80
- data/ext/rb-grn-table-key-support.c +33 -39
- data/ext/rb-grn-table.c +436 -79
- data/ext/rb-grn-type.c +10 -3
- data/ext/rb-grn-utils.c +131 -4
- data/ext/rb-grn-variable-size-column.c +36 -0
- data/ext/rb-grn-variable.c +90 -0
- data/ext/rb-grn.h +109 -56
- data/ext/rb-groonga.c +4 -0
- data/extconf.rb +39 -13
- data/html/index.html +2 -2
- data/lib/groonga.rb +22 -0
- data/lib/groonga/expression-builder.rb +141 -0
- data/lib/groonga/record.rb +25 -1
- data/lib/groonga/schema.rb +418 -0
- data/test/test-column.rb +11 -23
- data/test/test-context.rb +1 -1
- data/test/test-database.rb +60 -19
- data/test/test-expression-builder.rb +114 -0
- data/test/test-expression.rb +55 -0
- data/test/test-fix-size-column.rb +53 -0
- data/test/test-hash.rb +10 -3
- data/test/test-index-column.rb +24 -0
- data/test/test-patricia-trie.rb +9 -0
- data/test/test-procedure.rb +5 -5
- data/test/test-record.rb +71 -4
- data/test/test-schema.rb +207 -0
- data/test/test-table.rb +94 -12
- data/test/test-type.rb +18 -11
- data/test/test-variable-size-column.rb +53 -0
- data/test/test-variable.rb +28 -0
- metadata +18 -5
data/test/test-procedure.rb
CHANGED
@@ -19,11 +19,11 @@ class ProcedureTest < Test::Unit::TestCase
|
|
19
19
|
setup :setup_database
|
20
20
|
|
21
21
|
def test_builtins
|
22
|
-
assert_equal_procedure("
|
23
|
-
assert_equal_procedure("
|
24
|
-
assert_equal_procedure("
|
25
|
-
assert_equal_procedure("
|
26
|
-
assert_equal_procedure("
|
22
|
+
assert_equal_procedure("TokenDelimit", Groonga::Procedure::DELIMIT)
|
23
|
+
assert_equal_procedure("TokenUnigram", Groonga::Procedure::UNIGRAM)
|
24
|
+
assert_equal_procedure("TokenBigram", Groonga::Procedure::BIGRAM)
|
25
|
+
assert_equal_procedure("TokenTrigram", Groonga::Procedure::TRIGRAM)
|
26
|
+
assert_equal_procedure("TokenMecab", Groonga::Procedure::MECAB)
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
data/test/test-record.rb
CHANGED
@@ -63,6 +63,10 @@ class RecordTest < Test::Unit::TestCase
|
|
63
63
|
@bookmarks_uri = @bookmarks.define_column("uri", "<shorttext>",
|
64
64
|
:path => @uri_column_path.to_s)
|
65
65
|
|
66
|
+
@rate_column_path = @columns_dir + "rate"
|
67
|
+
@bookmarks_rate = @bookmarks.define_column("rate", "<int>",
|
68
|
+
:path => @rate_column_path.to_s)
|
69
|
+
|
66
70
|
@comment_column_path = @columns_dir + "comment"
|
67
71
|
@bookmarks_comment =
|
68
72
|
@bookmarks.define_column("comment", "<text>",
|
@@ -80,11 +84,11 @@ class RecordTest < Test::Unit::TestCase
|
|
80
84
|
@bookmarks_index =
|
81
85
|
Groonga::PatriciaTrie.create(:name => "bookmarks-index",
|
82
86
|
:path => @bookmarks_index_path.to_s)
|
83
|
-
@bookmarks_index.default_tokenizer = "
|
87
|
+
@bookmarks_index.default_tokenizer = "TokenBigram"
|
84
88
|
|
85
89
|
@content_index_column_path = @columns_dir + "content-index"
|
86
90
|
@bookmarks_content_index =
|
87
|
-
@bookmarks_index.define_index_column("
|
91
|
+
@bookmarks_index.define_index_column("content", @bookmarks,
|
88
92
|
:with_section => true,
|
89
93
|
:with_weight => true,
|
90
94
|
:with_position => true,
|
@@ -93,7 +97,7 @@ class RecordTest < Test::Unit::TestCase
|
|
93
97
|
|
94
98
|
@uri_index_column_path = @columns_dir + "uri-index"
|
95
99
|
@bookmarks_uri_index =
|
96
|
-
@bookmarks_index.define_index_column("
|
100
|
+
@bookmarks_index.define_index_column("uri", @bookmarks,
|
97
101
|
:with_position => true,
|
98
102
|
:path => @uri_index_column_path.to_s)
|
99
103
|
@bookmarks_uri_index.source = @bookmarks_uri
|
@@ -117,7 +121,9 @@ class RecordTest < Test::Unit::TestCase
|
|
117
121
|
|
118
122
|
def test_get_nonexistent_column
|
119
123
|
groonga = @bookmarks.add
|
120
|
-
|
124
|
+
assert_raise(Groonga::Error) do
|
125
|
+
groonga["nonexistent"]
|
126
|
+
end
|
121
127
|
end
|
122
128
|
|
123
129
|
def test_set_nonexistent_column
|
@@ -185,4 +191,65 @@ class RecordTest < Test::Unit::TestCase
|
|
185
191
|
[record.id, record.score]
|
186
192
|
end)
|
187
193
|
end
|
194
|
+
|
195
|
+
def test_increment!
|
196
|
+
groonga = @bookmarks.add
|
197
|
+
assert_equal(0, groonga["rate"])
|
198
|
+
groonga.increment!("rate")
|
199
|
+
assert_equal(1, groonga["rate"])
|
200
|
+
groonga.increment!("rate", 2)
|
201
|
+
assert_equal(3, groonga["rate"])
|
202
|
+
groonga.increment!("rate", -2)
|
203
|
+
assert_equal(1, groonga["rate"])
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_decrement!
|
207
|
+
groonga = @bookmarks.add
|
208
|
+
assert_equal(0, groonga["rate"])
|
209
|
+
groonga.decrement!("rate")
|
210
|
+
assert_equal(-1, groonga["rate"])
|
211
|
+
groonga.decrement!("rate", 2)
|
212
|
+
assert_equal(-3, groonga["rate"])
|
213
|
+
groonga.decrement!("rate", -2)
|
214
|
+
assert_equal(-1, groonga["rate"])
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_lock
|
218
|
+
groonga = @bookmarks.add
|
219
|
+
|
220
|
+
assert_not_predicate(groonga, :locked?)
|
221
|
+
groonga.lock
|
222
|
+
assert_predicate(groonga, :locked?)
|
223
|
+
groonga.unlock
|
224
|
+
assert_not_predicate(groonga, :locked?)
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_lock_failed
|
228
|
+
groonga = @bookmarks.add
|
229
|
+
|
230
|
+
groonga.lock
|
231
|
+
assert_raise(Groonga::ResourceDeadlockAvoided) do
|
232
|
+
groonga.lock
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_lock_block
|
237
|
+
groonga = @bookmarks.add
|
238
|
+
|
239
|
+
assert_not_predicate(groonga, :locked?)
|
240
|
+
groonga.lock do
|
241
|
+
assert_predicate(groonga, :locked?)
|
242
|
+
end
|
243
|
+
assert_not_predicate(groonga, :locked?)
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_clear_lock
|
247
|
+
groonga = @bookmarks.add
|
248
|
+
|
249
|
+
assert_not_predicate(groonga, :locked?)
|
250
|
+
groonga.lock
|
251
|
+
assert_predicate(groonga, :locked?)
|
252
|
+
groonga.clear_lock
|
253
|
+
assert_not_predicate(groonga, :locked?)
|
254
|
+
end
|
188
255
|
end
|
data/test/test-schema.rb
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
# Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License version 2.1 as published by the Free Software Foundation.
|
6
|
+
#
|
7
|
+
# This library is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
10
|
+
# Lesser General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU Lesser General Public
|
13
|
+
# License along with this library; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
15
|
+
|
16
|
+
class SchemaTest < Test::Unit::TestCase
|
17
|
+
include GroongaTestUtils
|
18
|
+
|
19
|
+
setup :setup_database
|
20
|
+
|
21
|
+
def test_create_table
|
22
|
+
assert_nil(context["<posts>"])
|
23
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
24
|
+
end
|
25
|
+
assert_not_nil(context["<posts>"])
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_define_hash
|
29
|
+
Groonga::Schema.create_table("<posts>", :type => :hash) do |table|
|
30
|
+
end
|
31
|
+
assert_kind_of(Groonga::Hash, context["<posts>"])
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_define_hash_with_full_option
|
35
|
+
path = @tmp_dir + "hash.groonga"
|
36
|
+
tokenizer = context["<token:trigram>"]
|
37
|
+
Groonga::Schema.create_table("<posts>",
|
38
|
+
:type => :hash,
|
39
|
+
:key_type => "integer",
|
40
|
+
:path => path.to_s,
|
41
|
+
:value_size => 29,
|
42
|
+
:default_tokenizer => tokenizer) do |table|
|
43
|
+
end
|
44
|
+
table = context["<posts>"]
|
45
|
+
assert_equal("#<Groonga::Hash " +
|
46
|
+
"id: <#{table.id}>, " +
|
47
|
+
"name: <<posts>>, " +
|
48
|
+
"path: <#{path}>, " +
|
49
|
+
"domain: <#{context['<int>'].inspect}>, " +
|
50
|
+
"range: <nil>, " +
|
51
|
+
"encoding: <#{Groonga::Encoding.default.inspect}>, " +
|
52
|
+
"size: <0>>",
|
53
|
+
table.inspect)
|
54
|
+
assert_equal(tokenizer, table.default_tokenizer)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_define_patricia_trie
|
58
|
+
Groonga::Schema.create_table("<posts>", :type => :patricia_trie) do |table|
|
59
|
+
end
|
60
|
+
assert_kind_of(Groonga::PatriciaTrie, context["<posts>"])
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_define_patricia_trie_with_full_option
|
64
|
+
path = @tmp_dir + "patricia-trie.groonga"
|
65
|
+
Groonga::Schema.create_table("<posts>",
|
66
|
+
:type => :patricia_trie,
|
67
|
+
:key_type => "integer",
|
68
|
+
:path => path.to_s,
|
69
|
+
:value_size => 29,
|
70
|
+
:default_tokenizer => "<token:bigram>",
|
71
|
+
:key_normalize => true,
|
72
|
+
:key_with_sis => true) do |table|
|
73
|
+
end
|
74
|
+
table = context["<posts>"]
|
75
|
+
assert_equal("#<Groonga::PatriciaTrie " +
|
76
|
+
"id: <#{table.id}>, " +
|
77
|
+
"name: <<posts>>, " +
|
78
|
+
"path: <#{path}>, " +
|
79
|
+
"domain: <#{context['<int>'].inspect}>, " +
|
80
|
+
"range: <nil>, " +
|
81
|
+
"encoding: <#{Groonga::Encoding.default.inspect}>, " +
|
82
|
+
"size: <0>>",
|
83
|
+
table.inspect)
|
84
|
+
assert_equal(context["<token:bigram>"], table.default_tokenizer)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_define_array
|
88
|
+
Groonga::Schema.create_table("<posts>", :type => :array) do |table|
|
89
|
+
end
|
90
|
+
assert_kind_of(Groonga::Array, context["<posts>"])
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_define_array_with_full_option
|
94
|
+
path = @tmp_dir + "array.groonga"
|
95
|
+
Groonga::Schema.create_table("<posts>",
|
96
|
+
:type => :array,
|
97
|
+
:path => path.to_s,
|
98
|
+
:value_size => 29) do |table|
|
99
|
+
end
|
100
|
+
table = context["<posts>"]
|
101
|
+
assert_equal("#<Groonga::Array " +
|
102
|
+
"id: <#{table.id}>, " +
|
103
|
+
"name: <<posts>>, " +
|
104
|
+
"path: <#{path}>, " +
|
105
|
+
"domain: <nil>, " +
|
106
|
+
"range: <nil>, " +
|
107
|
+
"size: <0>>",
|
108
|
+
table.inspect)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_integer32_column
|
112
|
+
assert_nil(context["<posts>.rate"])
|
113
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
114
|
+
table.integer32 :rate
|
115
|
+
end
|
116
|
+
assert_equal(context["<int>"], context["<posts>.rate"].range)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_integer64_column
|
120
|
+
assert_nil(context["<posts>.rate"])
|
121
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
122
|
+
table.integer64 :rate
|
123
|
+
end
|
124
|
+
assert_equal(context["<int64>"], context["<posts>.rate"].range)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_unsigned_integer32_column
|
128
|
+
assert_nil(context["<posts>.n_viewed"])
|
129
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
130
|
+
table.unsigned_integer32 :n_viewed
|
131
|
+
end
|
132
|
+
assert_equal(context["<uint>"], context["<posts>.n_viewed"].range)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_unsigned_integer64_column
|
136
|
+
assert_nil(context["<posts>.n_viewed"])
|
137
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
138
|
+
table.unsigned_integer64 :n_viewed
|
139
|
+
end
|
140
|
+
assert_equal(context["<uint64>"], context["<posts>.n_viewed"].range)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_float_column
|
144
|
+
assert_nil(context["<posts>.rate"])
|
145
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
146
|
+
table.float :rate
|
147
|
+
end
|
148
|
+
assert_equal(context["<float>"], context["<posts>.rate"].range)
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_time_column
|
152
|
+
assert_nil(context["<posts>.last_modified"])
|
153
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
154
|
+
table.time :last_modified
|
155
|
+
end
|
156
|
+
assert_equal(context["<time>"], context["<posts>.last_modified"].range)
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_short_text_column
|
160
|
+
assert_nil(context["<posts>.title"])
|
161
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
162
|
+
table.short_text :title
|
163
|
+
end
|
164
|
+
assert_equal(context["<shorttext>"], context["<posts>.title"].range)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_text_column
|
168
|
+
assert_nil(context["<posts>.comment"])
|
169
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
170
|
+
table.text :comment
|
171
|
+
end
|
172
|
+
assert_equal(context["<text>"], context["<posts>.comment"].range)
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_long_text_column
|
176
|
+
assert_nil(context["<posts>.content"])
|
177
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
178
|
+
table.long_text :content
|
179
|
+
end
|
180
|
+
assert_equal(context["<longtext>"], context["<posts>.content"].range)
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_index
|
184
|
+
assert_nil(context["<terms>.content"])
|
185
|
+
Groonga::Schema.create_table("<posts>") do |table|
|
186
|
+
table.long_text :content
|
187
|
+
end
|
188
|
+
Groonga::Schema.create_table("<terms>") do |table|
|
189
|
+
table.index :posts_content, "<posts>.content"
|
190
|
+
end
|
191
|
+
assert_equal([context["<posts>.content"]],
|
192
|
+
context["<terms>.posts_content"].sources)
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_dump
|
196
|
+
Groonga::Schema.define do |schema|
|
197
|
+
schema.create_table("<posts>") do |table|
|
198
|
+
table.short_text :title
|
199
|
+
end
|
200
|
+
end
|
201
|
+
assert_equal(<<-EOS, Groonga::Schema.dump)
|
202
|
+
create_table("<posts>") do |table|
|
203
|
+
table.short_text("title")
|
204
|
+
end
|
205
|
+
EOS
|
206
|
+
end
|
207
|
+
end
|
data/test/test-table.rb
CHANGED
@@ -326,10 +326,21 @@ class TableTest < Test::Unit::TestCase
|
|
326
326
|
},
|
327
327
|
],
|
328
328
|
:limit => 20)
|
329
|
-
|
330
|
-
|
329
|
+
assert_equal((180..199).to_a.reverse,
|
330
|
+
results.collect {|record| record["id"]})
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_sort_simple
|
334
|
+
bookmarks = Groonga::Array.create(:name => "<bookmarks>")
|
335
|
+
id_column = bookmarks.define_column("id", "<int>")
|
336
|
+
100.times do |i|
|
337
|
+
bookmark = bookmarks.add
|
338
|
+
bookmark["id"] = i + 100
|
331
339
|
end
|
332
|
-
|
340
|
+
|
341
|
+
results = bookmarks.sort(["id"], :limit => 20)
|
342
|
+
assert_equal((100..119).to_a,
|
343
|
+
results.collect {|record| record["id"]})
|
333
344
|
end
|
334
345
|
|
335
346
|
def test_sort_without_limit
|
@@ -340,15 +351,86 @@ class TableTest < Test::Unit::TestCase
|
|
340
351
|
bookmark["id"] = i + 100
|
341
352
|
end
|
342
353
|
|
343
|
-
results = bookmarks.sort([
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
354
|
+
results = bookmarks.sort([{:key => "id", :order => :descending}])
|
355
|
+
assert_equal((100..199).to_a.reverse,
|
356
|
+
results.collect {|record| record["id"]})
|
357
|
+
end
|
358
|
+
|
359
|
+
def test_group
|
360
|
+
bookmarks = Groonga::Hash.create(:name => "<bookmarks>")
|
361
|
+
bookmarks.define_column("title", "<text>")
|
362
|
+
comments = Groonga::Array.create(:name => "<comments>")
|
363
|
+
comments.define_column("bookmark", bookmarks)
|
364
|
+
comments.define_column("content", "Text")
|
365
|
+
comments.define_column("issued", "Int32")
|
366
|
+
|
367
|
+
groonga = bookmarks.add("http://groonga.org/", :title => "groonga")
|
368
|
+
ruby = bookmarks.add("http://ruby-lang.org/", :title => "Ruby")
|
369
|
+
|
370
|
+
now = Time.now.to_i
|
371
|
+
comments.add(:bookmark => groonga,
|
372
|
+
:content => "full-text search",
|
373
|
+
:issued => now)
|
374
|
+
comments.add(:bookmark => groonga,
|
375
|
+
:content => "column store",
|
376
|
+
:issued => now)
|
377
|
+
comments.add(:bookmark => ruby,
|
378
|
+
:content => "object oriented script language",
|
379
|
+
:issued => now)
|
380
|
+
|
381
|
+
records = comments.select do |record|
|
382
|
+
record["issued"] > 0
|
383
|
+
end
|
384
|
+
assert_equal([[2, "groonga", "http://groonga.org/"],
|
385
|
+
[1, "Ruby", "http://ruby-lang.org/"]],
|
386
|
+
records.group([".bookmark"]).collect do |record|
|
387
|
+
bookmark = record.key
|
388
|
+
[record[".:nsubrecs"],
|
389
|
+
bookmark["title"],
|
390
|
+
bookmark.key]
|
391
|
+
end)
|
392
|
+
end
|
393
|
+
|
394
|
+
def test_lock
|
395
|
+
bookmarks = Groonga::Array.create(:name => "<bookmarks>")
|
396
|
+
bookmark = bookmarks.add
|
397
|
+
|
398
|
+
assert_not_predicate(bookmarks, :locked?)
|
399
|
+
bookmarks.lock
|
400
|
+
assert_predicate(bookmarks, :locked?)
|
401
|
+
bookmarks.unlock
|
402
|
+
assert_not_predicate(bookmarks, :locked?)
|
403
|
+
end
|
404
|
+
|
405
|
+
def test_lock_failed
|
406
|
+
bookmarks = Groonga::Array.create(:name => "<bookmarks>")
|
407
|
+
bookmark = bookmarks.add
|
408
|
+
|
409
|
+
bookmarks.lock
|
410
|
+
assert_raise(Groonga::ResourceDeadlockAvoided) do
|
411
|
+
bookmarks.lock
|
351
412
|
end
|
352
|
-
|
413
|
+
end
|
414
|
+
|
415
|
+
def test_lock_block
|
416
|
+
bookmarks = Groonga::Array.create(:name => "<bookmarks>")
|
417
|
+
bookmark = bookmarks.add
|
418
|
+
|
419
|
+
assert_not_predicate(bookmarks, :locked?)
|
420
|
+
bookmarks.lock do
|
421
|
+
assert_predicate(bookmarks, :locked?)
|
422
|
+
end
|
423
|
+
assert_not_predicate(bookmarks, :locked?)
|
424
|
+
end
|
425
|
+
|
426
|
+
def test_clear_lock
|
427
|
+
bookmarks = Groonga::Array.create(:name => "<bookmarks>")
|
428
|
+
bookmark = bookmarks.add
|
429
|
+
|
430
|
+
assert_not_predicate(bookmarks, :locked?)
|
431
|
+
bookmarks.lock
|
432
|
+
assert_predicate(bookmarks, :locked?)
|
433
|
+
bookmarks.clear_lock
|
434
|
+
assert_not_predicate(bookmarks, :locked?)
|
353
435
|
end
|
354
436
|
end
|