mattly-exegesis 0.0.10 → 0.2.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.
data/test/design_test.rb CHANGED
@@ -1,112 +1,192 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
2
 
3
- class FoosDesign < Exegesis::Design; end
4
- class BarsDesign < Exegesis::Design
5
- use_design_doc_name :something_else
3
+ class DesignTestDoc
4
+ include Exegesis::Document
5
+
6
6
  end
7
7
 
8
- class TestForDesign < Exegesis::Document; end
8
+ class DesignTestDatabase
9
+ include Exegesis::Database
10
+
11
+ designs_directory "#{File.dirname(__FILE__)}/fixtures/designs"
12
+
13
+ design :tags do
14
+ docs :by_tag
15
+ hash :count, :view => :by_tag
16
+ end
17
+
18
+ design :stuff, :name => 'things', :directory => 'app/designs/stuff' do
19
+
20
+ end
21
+ end
9
22
 
10
23
  class ExegesisDesignTest < Test::Unit::TestCase
11
24
 
12
- before do
25
+ def setup_db(with_doc=true)
13
26
  reset_db
14
- @doc = FoosDesign.new(@db)
27
+ @db = DesignTestDatabase.new('exegesis-test')
28
+ if with_doc
29
+ @db.save({
30
+ '_id' => '_design/tags',
31
+ 'views' => {
32
+ 'by_tag' => {
33
+ 'map' => 'function(doc) { for (var tag in doc.tags) { emit(doc.tags[tag], 1); } }',
34
+ 'reduce' => 'function(keys, values, rereduce) { return sum(values); }'
35
+ }}
36
+ })
37
+ end
15
38
  end
16
39
 
17
- expect { @doc.database.will == @db }
18
- expect { @doc.design_doc_name.will == "foos" }
19
-
20
- expect { FoosDesign.design_doc_name.will == "foos" }
21
- expect { BarsDesign.design_doc_name.will == "something_else" }
40
+ context "design instances" do
41
+ before { setup_db }
42
+ expect { @db.tags.database.will == @db }
43
+ end
22
44
 
23
- context "retrieving documents with #get" do
24
- before do
25
- @db.save_doc '_id' => 'foo', 'foo' => 'bar', '.kind' => 'TestForDesign'
26
- @obj = @doc.get('foo')
27
- end
28
-
29
- expect { @obj.will be_kind_of(TestForDesign) }
30
- expect { @obj['foo'].will == 'bar' }
45
+ context "design declarations" do
46
+ before { setup_db }
47
+ expect { @db.tags.class.will == DesignTestDatabase::TagsDesign }
48
+ expect { @db.tags.is_a?(Exegesis::Design).will == true }
49
+ expect { @db.tags.design_name.will == 'tags' }
31
50
  end
32
51
 
33
- context "retreiving views" do
52
+ context "view declarations" do
34
53
  before do
35
- @raw_docs = [
36
- {'_id' => 'bar', 'foo' => 'bar', 'bar' => 'bar', '.kind' => 'TestForDesign'},
37
- {'_id' => 'baz', 'foo' => 'baz', 'bar' => 'baz', '.kind' => 'TestForDesign'},
38
- {'_id' => 'foo', 'foo' => 'foo', 'bar' => 'foo', '.kind' => 'TestForDesign'}
54
+ setup_db
55
+ @docs = [
56
+ {'class' => 'DesignTestDoc', 'tags' => %w(foo bar bee)},
57
+ {'class' => 'DesignTestDoc', 'tags' => %w(foo bar baz)},
58
+ {'class' => 'DesignTestDoc', 'tags' => %w(foo bee ruby)}
39
59
  ]
40
- @db.bulk_save @raw_docs
41
- @db.save_doc({
42
- '_id' => '_design/foos',
43
- 'views' => {
44
- 'test' => { 'map'=>'function(doc) {emit(doc.foo, doc.bar);}' },
45
- }
46
- })
60
+ @db.save(@docs)
47
61
  end
48
62
 
49
- context "parsing options" do
50
- context "when the key is a range" do
51
- before { @opts = @doc.parse_opts(:key => 'bar'..'baz') }
52
-
53
- expect { @opts[:key].will == nil }
54
- expect { @opts[:startkey].will == 'bar' }
55
- expect { @opts[:endkey].will == 'baz' }
63
+ context "declared docs" do
64
+ describe "with default key" do
65
+ before { @response = @db.tags.by_tag('foo') }
66
+ expect { @response.kind_of?(Array).will == true }
67
+ expect { @response.size.will == @docs.select{|d| d['tags'].include?('foo')}.size }
68
+ expect { @response.all? {|d| d.kind_of?(DesignTestDoc) }.will == true }
69
+ expect { @response.all? {|d| d['tags'].include?('foo') }.will == true }
56
70
  end
57
71
 
58
- context "when the key is an array with a range in it" do
59
- before { @opts = @doc.parse_opts(:key => ['published', '2008'..'2008/13']) }
60
-
61
- expect { @opts[:key].will be(nil) }
62
- expect { @opts[:startkey].will == ['published', '2008'] }
63
- expect { @opts[:endkey].will == ['published', '2008/13'] }
72
+ describe "with multiple keys" do
73
+ before { @response = @db.tags.by_tag :keys => %w(bar bee) }
74
+ expect { @response.kind_of?(Array).will == true }
75
+ expect { @response.size.will == 3 }
76
+ # expect { @response.size.will == @docs.select{|d| (d['tags'] & %w(bar bee)).size > 0}.size }
77
+ expect { @response.all? {|d| d.kind_of?(DesignTestDoc) }.will == true }
64
78
  end
65
-
66
- context "when a keys option is empty" do
67
- before { @opts = @doc.parse_opts(:keys => []) }
68
-
69
- expect { @opts[:keys].will be(nil) }
79
+ end
80
+
81
+ context "declared hashes" do
82
+ before do
83
+ @counts = Hash.new(0)
84
+ @docs.each {|doc| doc['tags'].each {|tag| @counts[tag] += 1 } }
70
85
  end
86
+ expect { @db.tags.count.should == @counts }
87
+ expect { @db.tags.count(:group => false).should == @counts.values.inject(0){|sum,n| sum+=n } }
88
+ expect { @db.tags.count('foo').should == @counts['foo'] }
71
89
  end
90
+ end
91
+
92
+ context "parsing query options" do
93
+ before { setup_db }
72
94
 
73
- context "when no key, keys, startkey or all option is present" do
74
- before { @response = @doc.view :test }
75
-
76
- expect { @response.will == [] }
95
+ context "with a key as an initial arguemnt" do
96
+ expect { @db.tags.parse_opts('foo').will == {:key => 'foo'} }
97
+ expect { @db.tags.parse_opts('foo', :include_docs => true).will == {:key => 'foo', :include_docs => true} }
98
+ expect { @db.tags.parse_opts('foo', {:stale => 'ok'}, {:include_docs => true}).will == {:key => 'foo', :stale => 'ok', :include_docs => true }}
77
99
  end
78
-
79
- context "with an all key" do
80
- before { @response = @doc.view :test, :all => true }
81
-
82
- expect { @response.will == @raw_docs.map{|d| {'id' => d['_id'], 'key' => d['foo'], 'value' => d['bar']} } }
100
+
101
+ context "without an implied key" do
102
+ expect { @db.tags.parse_opts(:key => 'foo').will == {:key => 'foo'} }
103
+ expect { @db.tags.parse_opts({:key => 'foo'}, nil, {:stale => 'ok'}).will == {:key => 'foo', :stale => 'ok'} }
83
104
  end
84
-
85
- context "with docs" do
86
- before { @response = @doc.docs_for :test, :key => 'foo' }
87
105
 
88
- expect { @response.will be_kind_of(Array) }
89
- expect { @response.size.will == 1 }
90
- expect { @response.first.will be_kind_of(TestForDesign) }
91
- expect { @response.first['foo'].will == 'foo' }
106
+ context "when a keys option is empty" do
107
+ expect { @db.tags.parse_opts(:keys => []).will == {} }
92
108
  end
93
109
 
94
- context "for the view's data" do
95
- before { @response = @doc.values_for :test, :all => true }
110
+ context "for ranges" do
111
+ context "when the key _is_ a range" do
112
+ before { @opts = @db.tags.parse_opts(:key => 'bar'..'baz') }
113
+ expect { @opts.has_key?(:key).will == false }
114
+ expect { @opts[:startkey].will == 'bar' }
115
+ expect { @opts[:endkey].will == 'baz'}
116
+ end
96
117
 
97
- expect { @response.will == %w(bar baz foo) }
118
+ context "when the key is an array that includes a range" do
119
+ before { @opts = @db.tags.parse_opts(:key => ['published', '2009'..'2009/04']) }
120
+ expect { @opts.has_key?(:key).will == false }
121
+ expect { @opts[:startkey].will == ['published', '2009'] }
122
+ expect { @opts[:endkey].will == ['published', '2009/04'] }
123
+ end
124
+
125
+ context "for non inclusive ranges" do; end
126
+ context "when descending:true is an option" do
127
+ context "and first value is greater than the end value" do; end
128
+ end
129
+ context "when the first value is greater than the end value" do; end
130
+
131
+ context "invalid option configurations" do
132
+ expect { lambda {@db.tags.parse_opts(:startkey => 'foo')}.will raise_error(ArgumentError) }
133
+ end
134
+ end
135
+ end
136
+
137
+ context "design doc meta declarations" do
138
+ expect { DesignTestDatabase::StuffDesign.design_name.will == "things" }
139
+ expect { DesignTestDatabase::StuffDesign.design_directory.will == Pathname.new("app/designs/stuff") }
140
+ end
141
+
142
+ context "the design document" do
143
+ before do
144
+ @canonical = DesignTestDatabase::TagsDesign.canonical_design
98
145
  end
99
146
 
100
- context "for the view's matching keys" do
101
- before { @response = @doc.keys_for :test, :key => 'bar'..'baz' }
147
+ context "composing the canonical version" do
148
+ context "from files" do
149
+ expect { @canonical['views']['by_tag']['map'].will == File.read(fixtures_path('designs/tags/views/by_tag/map.js')) }
150
+ expect { @canonical['views']['by_tag']['reduce'].will == File.read(fixtures_path('designs/tags/views/by_tag/reduce.js')) }
151
+ end
102
152
 
103
- expect { @response.will == %w(bar baz) }
153
+ context "from class declarations" do
154
+ # tk
155
+ end
104
156
  end
105
157
 
106
- context "for the view's matching ids" do
107
- before { @response = @doc.ids_for :test, :key => 'bar'..'foo'}
158
+ context "syncronizing" do
159
+ context "when the design_doc doesn't exist in the db yet" do
160
+ before do
161
+ setup_db(false)
162
+ @db.tags
163
+ end
164
+ expect { lambda{@db.get('_design/tags')}.wont raise_error }
165
+ expect { @db.tags['views'].will == @canonical['views'] }
166
+ expect { @db.tags.rev.will =~ /\d-\d{10}/ }
167
+ end
168
+
169
+ context "when the design_doc exists but is not canonical" do
170
+ before do
171
+ # there are no line breaks in the version that setup_db posts
172
+ setup_db
173
+ @old = @db.get('_design/tags')
174
+ @db.tags
175
+ end
176
+
177
+ expect { @db.tags.rev.wont == @old['_rev'] }
178
+ end
108
179
 
109
- expect { @response.will == %w(bar baz foo) }
180
+ context "when the design_doc exists and is canonical" do
181
+ before do
182
+ setup_db(false)
183
+ @db.put('_design/tags', DesignTestDatabase::TagsDesign.canonical_design)
184
+ @old = @db.get('_design/tags')
185
+ @db.tags
186
+ end
187
+
188
+ expect { @db.tags.rev.will == @old['_rev'] }
189
+ end
110
190
  end
111
191
  end
112
192
 
@@ -0,0 +1,159 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+
3
+ class TestDocument
4
+ include Exegesis::Document
5
+ expose :foo
6
+ end
7
+
8
+ class TimestampTestDocument
9
+ include Exegesis::Document
10
+ timestamps!
11
+ end
12
+
13
+ class UniqueIdTestDocument
14
+ include Exegesis::Document
15
+ unique_id :set_id
16
+ def set_id attempt
17
+ attempt.zero? ? "snowflake" : "snowflake-#{attempt}"
18
+ end
19
+ end
20
+
21
+ class UniqueIdBlockTestDocument
22
+ include Exegesis::Document
23
+ unique_id {|doc, attempt| attempt.zero? ? doc['pk'] : "#{doc['pk']}-#{attempt}" }
24
+ end
25
+
26
+ class ExegesisDocumentClassDefinitionsTest < Test::Unit::TestCase
27
+
28
+ context "class definitions" do
29
+ context "with timestamps" do
30
+ before do
31
+ reset_db
32
+ @obj = TimestampTestDocument.new({}, @db)
33
+ @obj.save
34
+ @obj = @db.get(@obj.id)
35
+ end
36
+
37
+ context "initial save" do
38
+ expect { @obj.created_at.to_f.will be_close(Time.now.to_f, 2) }
39
+ expect { @obj.updated_at.to_f.will be_close(Time.now.to_f, 2) }
40
+ end
41
+
42
+ context "when created_at already exists" do
43
+ before do
44
+ @obj['created_at'] = Time.now - 3600
45
+ @obj.save
46
+ @obj = @db.get(@obj.id)
47
+ end
48
+
49
+ expect { @obj.created_at.to_f.will be_close((Time.now - 3600).to_f, 2) }
50
+ expect { @obj.updated_at.to_f.will be_close(Time.now.to_f, 2) }
51
+ end
52
+
53
+ end
54
+
55
+ context "with a custom unique_id setter" do
56
+ context "as a method" do
57
+ before do
58
+ reset_db
59
+ @obj = UniqueIdTestDocument.new({}, @db)
60
+ end
61
+
62
+ context "when the id isn't in place yet" do
63
+ before do
64
+ @obj.save
65
+ end
66
+
67
+ expect { @obj.id.will == "snowflake" }
68
+ end
69
+
70
+ context "when there is an id in place already" do
71
+ before do
72
+ @obj['_id'] = 'foo'
73
+ @obj.save
74
+ end
75
+
76
+ expect { @obj.id.will == "foo" }
77
+ end
78
+
79
+ context "when the desired id is already in use" do
80
+ before do
81
+ @db.put('snowflake', {'_id' => 'snowflake', 'foo' => 'bar'})
82
+ @obj.save
83
+ end
84
+
85
+ expect { @obj.id.will == 'snowflake-1' }
86
+ end
87
+ end
88
+
89
+ context "as a block" do
90
+ before do
91
+ reset_db
92
+ @obj = UniqueIdBlockTestDocument.new({'pk'=>'bar'}, @db)
93
+ end
94
+
95
+ context "when the id doesn't yet exist and no id in place" do
96
+ before { @obj.save }
97
+ expect { @obj.id.will == @obj['pk'] }
98
+ end
99
+
100
+ context "when the document has an id in place already" do
101
+ before do
102
+ @obj['_id'] = 'foo'
103
+ @obj.save
104
+ end
105
+ expect { @obj.id.will == 'foo' }
106
+ end
107
+
108
+ context "when the desired id is already in use" do
109
+ before do
110
+ @db.put('bar', {'_id' => 'bar', 'pk' => 'bar'})
111
+ @obj.save
112
+ end
113
+ expect { @obj.id.will == 'bar-1'}
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ context "instance methods" do
120
+ before do
121
+ reset_db
122
+ end
123
+
124
+ context "updating_attributes" do
125
+
126
+ context "an existing doc" do
127
+ before do
128
+ @doc = TestDocument.new({'foo' => 'bar'}, @db)
129
+ @doc.save
130
+ @old_rev = @doc.rev
131
+ end
132
+
133
+ context "without a matching rev" do
134
+ expect { lambda {@doc.update_attributes({'foo' => 'bee'})}.will raise_error(ArgumentError) }
135
+ expect { lambda {@doc.update_attributes({'foo' => 'bee', '_rev' => 'z'})}.will raise_error(ArgumentError) }
136
+ end
137
+
138
+ context "with a matching rev" do
139
+ before do
140
+ @doc.update_attributes({'_rev' => @doc.rev, 'foo' => 'bee'})
141
+ end
142
+
143
+ expect { @doc['foo'].will == 'bee' }
144
+ expect { @doc.rev.wont == @old_rev }
145
+ end
146
+
147
+ context "when given keys without writers" do
148
+ before do
149
+ @action = lambda {@doc.update_attributes({'_rev' => @doc.rev, 'bar' => 'boo'})}
150
+ end
151
+
152
+ expect { @action.will raise_error(NoMethodError) }
153
+ end
154
+ end
155
+
156
+ end
157
+ end
158
+
159
+ end
@@ -0,0 +1,8 @@
1
+ function(doc) {
2
+ if (doc.tags) {
3
+ // assumes doc.tags is an array of strings
4
+ for (var tag in doc.tags) {
5
+ emit(doc.tags[tag], 1);
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,3 @@
1
+ function(keys, values, rereduce) {
2
+ return sum(values);
3
+ }
data/test/http_test.rb ADDED
@@ -0,0 +1,79 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+ require 'restclient'
3
+ require 'json'
4
+
5
+ class HttpTest < Test::Unit::TestCase
6
+
7
+ context "url formatting" do
8
+ context "with no params" do
9
+ before do
10
+ @url = "/some_url"
11
+ @action = lambda {|params| Exegesis::Http.format_url(@url, params) }
12
+ end
13
+
14
+ expect { @action.call(nil).will == "/some_url" }
15
+ expect { @action.call({}).will == "/some_url" }
16
+ end
17
+
18
+ context "with normal params" do
19
+ before do
20
+ @url = "/some_url"
21
+ @params = {
22
+ :one => 1,
23
+ :two => 2
24
+ }
25
+ @expected = ["/some_url?one=1&two=2", "/some_url?two=2&one=1"]
26
+ end
27
+
28
+ expect { @expected.will include(Exegesis::Http.format_url(@url, @params)) }
29
+ end
30
+ end
31
+
32
+ context "making requests" do
33
+ before(:all) do
34
+ @db = 'http://localhost:5984/exegesis-test'
35
+ RestClient.delete(@db) rescue nil
36
+ RestClient.put(@db, '')
37
+ end
38
+
39
+ after(:all) do
40
+ RestClient.delete(@db) rescue nil
41
+ end
42
+
43
+ context "get requests" do
44
+ before do
45
+ @response = Exegesis::Http.get(@db)
46
+ end
47
+
48
+ expect { @response['db_name'].will == 'exegesis-test' }
49
+ end
50
+
51
+ context "post requests" do
52
+ before do
53
+ @response = Exegesis::Http.post(@db, {'test' => 'value'})
54
+ end
55
+
56
+ expect { @response['ok'].will == true }
57
+ end
58
+
59
+ context "put requests" do
60
+ before do
61
+ @response = Exegesis::Http.put("#{@db}/test-document", {'test' => 'value'})
62
+ end
63
+
64
+ expect { @response['ok'].will == true }
65
+
66
+ after { RestClient.delete("#{@db}/test-document?rev=#{@response['rev']}") }
67
+ end
68
+
69
+ context "delete requests" do
70
+ before do
71
+ @doc = JSON.parse RestClient.put("#{@db}/test-document", {'test' => 'value'}.to_json)
72
+ @response = RestClient.delete("#{@db}/test-document?rev=#{@doc['rev']}")
73
+ end
74
+
75
+ expect { @response['ok'].will == 'ok' }
76
+ end
77
+ end
78
+
79
+ end