congo 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Binary file
Binary file
@@ -0,0 +1,152 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'ContentType' do
4
+
5
+ before(:each) do
6
+ Account.destroy_all
7
+ Congo::ProxyScoper.destroy_all
8
+ Congo::ContentType.destroy_all
9
+
10
+ @account = Account.create(:email => 'layne_stanley@acme.org')
11
+ @website = Website.new(42, 'My simple website')
12
+ end
13
+
14
+ it 'should be valid' do
15
+ build_content_type.should be_valid
16
+ end
17
+
18
+ it 'should not be valid without a name' do
19
+ type = build_content_type(:name => nil)
20
+ type.should_not be_valid
21
+ type.errors.on(:name).should_not be_nil
22
+ type.errors.on(:collection_name).should_not be_nil
23
+ end
24
+
25
+ [' BlogPost ', ' My projects', 'active posts '].each do |name|
26
+ it "should be valid with name included leading or trailing spaces (#{name})" do
27
+ type = build_content_type(:name => name)
28
+ type.should be_valid
29
+ end
30
+ end
31
+
32
+ ['42BlogPosts', ' !cool', 'Great!', 'Super-PRoject43'].each do |name|
33
+ it "should not be valid with an invalid name (#{name})" do
34
+ type = build_content_type(:name => name)
35
+ type.should_not be_valid
36
+ type.errors.on(:name).should_not be_nil
37
+ end
38
+ end
39
+
40
+ it 'should be valid without a name but with a provided collection name' do
41
+ type = build_content_type(:name => nil, :collection_name => 'My projects')
42
+ type.should be_valid
43
+ type.name.should == "MyProject"
44
+ type.slug.should == "my_projects"
45
+ end
46
+
47
+ it 'should not valid if another content type with the same name' do
48
+ type_1 = build_content_type
49
+ type_1.save.should be_true
50
+
51
+ type_2 = build_content_type
52
+ type_2.should_not be_valid
53
+ type_2.errors.on(:name).should_not be_nil
54
+ type_2.name = 'Team'
55
+ type_2.should be_valid
56
+ end
57
+
58
+ it 'should not valid if the scoper instance already has a method identical to its name' do
59
+ type = build_content_type(:name => 'Person')
60
+ type.should_not be_valid
61
+ type.errors.on(:name).should_not be_nil
62
+
63
+ type = @website.content_types.build(:name => 'Page', :metadata_keys => [{ :name => 'title' }])
64
+ type.should_not be_valid
65
+ type.errors.on(:name).should_not be_nil
66
+
67
+ type.name = nil
68
+ type.collection_name = 'pages'
69
+ type.should_not be_valid
70
+ type.errors.on(:collection_name).should_not be_nil
71
+ end
72
+
73
+ it 'should not valid if another content type with the same collection name' do
74
+ type_1 = build_content_type(:name => nil, :collection_name => 'My projects')
75
+ type_1.save.should be_true
76
+
77
+ type_2 = build_content_type(:name => nil, :collection_name => 'My projects')
78
+ type_2.should_not be_valid
79
+ type_2.errors.on(:name).should_not be_nil
80
+ type_2.errors.on(:collection_name).should_not be_nil
81
+ type_2.name = nil
82
+ type_2.collection_name = 'My team'
83
+ type_2.should be_valid
84
+ end
85
+
86
+ it 'should not valid without keys' do
87
+ type = build_content_type(:metadata_keys => [])
88
+ type.should_not be_valid
89
+ type.errors.on(:metadata_keys).should_not be_nil
90
+ end
91
+
92
+ it 'should not be valid without a scope' do
93
+ type = build_content_type
94
+ type.scope = nil
95
+ type.should_not be_valid
96
+ type.errors.on(:scope).should_not be_nil
97
+ end
98
+
99
+ it 'should not be valid with 2 identical keys (same name)' do
100
+ type = build_content_type(:metadata_keys => [ { :name => 'name' }, { :name => 'name' }, { :name => 'description' } ])
101
+ type.should_not be_valid
102
+ type.errors.on(:metadata_keys).should_not be_nil
103
+ type.metadata_keys.first.should be_valid
104
+ type.metadata_keys.last.should be_valid
105
+ type.metadata_keys[1].errors.on(:name).should_not be_nil
106
+ end
107
+
108
+ it 'should be retrieved once saved' do
109
+ type = build_content_type
110
+ type.metadata_keys.should_not be_empty
111
+ type.save!.should be_true
112
+ type.save
113
+
114
+ type = type.reload
115
+ type.metadata_keys.size.should == 2
116
+ Congo::ContentType.first.metadata_keys.size.should == 2
117
+ end
118
+
119
+ it 'should remove contents as well when removed' do
120
+ type = build_content_type
121
+ type.save!
122
+ @account.projects.create(:name => 'project #1', :description => 'bla bla')
123
+ collection_name = type.send(:mongodb_collection_name)
124
+ MongoMapper.database.collection(collection_name).count.should == 1
125
+
126
+ another_type = build_content_type(:name => 'Foo')
127
+ another_type.save
128
+
129
+ @account = @account.reload
130
+ @account.content_types.count.should == 2
131
+
132
+ type.destroy
133
+
134
+ @account = @account.reload
135
+ @account.content_types.count.should == 1
136
+ MongoMapper.database.collection(collection_name).count.should == 0
137
+ @account.foos.count.should == 0
138
+ end
139
+
140
+ def build_content_type(options = {})
141
+ default_options = {
142
+ :name => 'Project',
143
+ :embedded => false,
144
+ :metadata_keys => [
145
+ { :name => 'name' },
146
+ { :name => 'description' }
147
+ ] }
148
+
149
+ @account.content_types.build(default_options.merge(options))
150
+ end
151
+
152
+ end
@@ -0,0 +1,11 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
2
+
3
+ MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {
4
+ :logger => Logger.new(TEST_DIR + '/test.log')
5
+ })
6
+ MongoMapper.database = 'congotest'
7
+
8
+ MongoMapper.database.collection_names.each do |collection|
9
+ next if collection == 'system.indexes'
10
+ MongoMapper.database.collection(collection).drop
11
+ end
@@ -0,0 +1,47 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'Grip' do
4
+
5
+ before(:each) do
6
+ Account.destroy_all
7
+ Congo::ContentType.destroy_all
8
+
9
+ @account = Account.create(:email => 'layne_stanley@acme.org')
10
+ end
11
+
12
+ it 'should attach a file to a content' do
13
+ create_content_type
14
+ developer = @account.developers.create({
15
+ :name => 'Layne Stanley',
16
+ :bio => 'foo bar',
17
+ :picture => open_file('avatar.jpeg')
18
+ })
19
+ developer.should be_valid
20
+ developer.picture_name.should == 'avatar.jpeg'
21
+ developer.picture_content_type.should == 'image/jpeg'
22
+ developer.picture_path.should == "developer/#{developer._id}"
23
+ end
24
+
25
+ def create_content_type(options = {})
26
+ type = build_content_type
27
+ type.save!
28
+ type
29
+ end
30
+
31
+ def build_content_type(options = {})
32
+ default_options = {
33
+ :name => 'Developer',
34
+ :embedded => false,
35
+ :metadata_keys => [
36
+ { :name => 'name', :type => 'String' },
37
+ { :name => 'bio', :type => 'Text' },
38
+ { :name => 'picture', :type => 'File' }
39
+ ] }
40
+
41
+ @account.content_types.build(default_options.merge(options))
42
+ end
43
+
44
+ def open_file(name)
45
+ File.open(File.join(File.dirname(__FILE__), '..', 'assets', name))
46
+ end
47
+ end
@@ -0,0 +1,94 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'Key' do
4
+
5
+ before(:each) do
6
+ I18n.locale = :en
7
+
8
+ Account.destroy_all
9
+ Congo::ContentType.destroy_all
10
+
11
+ @account = Account.create(:email => 'layne_stanley@acme.org')
12
+ end
13
+
14
+ it 'should add items' do
15
+ create_content_type
16
+
17
+ person = build_person
18
+ person.valid?.should be_true
19
+ person.name.should == 'Layne Stanley'
20
+ person.bio.should == "That's great"
21
+ person.email.should == 'layne_stanley@acme.org'
22
+ person.save
23
+
24
+ @account = Account.first # hard reload
25
+ person = @account.developers.first
26
+ person.email.should == 'layne_stanley@acme.org'
27
+ end
28
+
29
+ it 'should not add items with invalid data (incorrect e-mail)' do
30
+ create_content_type
31
+
32
+ person = build_person(:email => 'layne_stanley-acme.org')
33
+ person.valid?.should be_false
34
+ person.errors.on(:email).should_not be_nil
35
+ end
36
+
37
+ it 'should convert date into the locale' do
38
+ create_content_type
39
+ person = build_person
40
+ person.save
41
+
42
+ @account = Account.first # hard reload
43
+ person = @account.developers.first
44
+ person.birthday.strftime(I18n.t('congo.date.formats.default')).should == '06/28/1979'
45
+
46
+ I18n.locale = :fr
47
+ person.birthday.strftime(I18n.t('congo.date.formats.default')).should == '28/06/1979'
48
+
49
+ person.birthday = '16/09/1982'
50
+ person.save
51
+
52
+ @account = Account.first # hard reload
53
+ person = @account.developers.first
54
+ person.birthday.strftime(I18n.t('congo.date.formats.default')).should == '16/09/1982'
55
+ person.localized_birthday.should == '16/09/1982'
56
+
57
+ person.localized_birthday = '29/06/2007'
58
+ person.save
59
+ @account = Account.first # hard reload
60
+ person = @account.developers.first
61
+ person.localized_birthday.should == '29/06/2007'
62
+ end
63
+
64
+ def create_content_type(options = {})
65
+ type = build_content_type
66
+ type.save!
67
+ type
68
+ end
69
+
70
+ def build_content_type(options = {})
71
+ default_options = {
72
+ :name => 'Developer',
73
+ :embedded => false,
74
+ :metadata_keys => [
75
+ { :name => 'name', :type => 'String' },
76
+ { :name => 'bio', :type => 'Text' },
77
+ { :name => 'email', :type => 'Email' },
78
+ { :name => 'birthday', :type => 'Date' }
79
+ ] }
80
+
81
+ @account.content_types.build(default_options.merge(options))
82
+ end
83
+
84
+ def build_person(options = {})
85
+ attributes = {
86
+ :name => 'Layne Stanley',
87
+ :bio => "That's great",
88
+ :email => 'layne_stanley@acme.org',
89
+ :birthday => '06/28/1979'
90
+ }
91
+ @account.developers.build attributes.merge(options)
92
+ end
93
+
94
+ end
@@ -0,0 +1,67 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'List' do
4
+
5
+ before(:all) do
6
+ class Congo::ContentType
7
+ include Congo::List
8
+ end
9
+ end
10
+
11
+ before(:each) do
12
+ Account.destroy_all
13
+ Congo::ContentType.destroy_all
14
+
15
+ @account = Account.create(:email => 'layne_stanley@acme.org')
16
+ end
17
+
18
+ it 'should increment item position once saved' do
19
+ create_content_type
20
+ person = @account.developers.create :name => 'Layne Stanley', :bio => "That's great"
21
+ person._position.should == 1
22
+ person = @account.developers.create :name => 'Kurt Cobain', :bio => "Suicide #2"
23
+ person._position.should == 2
24
+ end
25
+
26
+ it 'should decrement item position once deleted' do
27
+ populate
28
+ @account.developers.first(:conditions => { :name => 'River Phoenix' }).destroy
29
+ @account.developers.first(:conditions => { :name => 'Layne Stanley' })._position.should == 1
30
+ @account.developers.first(:conditions => { :name => 'Kurt Cobain' })._position.should == 2
31
+ end
32
+
33
+ it 'should reorder all the items of a collection' do
34
+ populate
35
+ klass = @account.content_types.first.to_const
36
+ klass.reorder_all(@account.developers.all(:order => 'name ASC').collect(&:_id))
37
+ @account.developers.first(:conditions => { :name => 'River Phoenix' })._position.should == 3
38
+ @account.developers.first(:conditions => { :name => 'Layne Stanley' })._position.should == 2
39
+ @account.developers.first(:conditions => { :name => 'Kurt Cobain' })._position.should == 1
40
+ end
41
+
42
+ def create_content_type(options = {})
43
+ type = build_content_type
44
+ type.save!
45
+ type
46
+ end
47
+
48
+ def build_content_type(options = {})
49
+ default_options = {
50
+ :name => 'Developer',
51
+ :embedded => false,
52
+ :metadata_keys => [
53
+ { :name => 'name', :type => 'String' },
54
+ { :name => 'bio', :type => 'Text' }
55
+ ] }
56
+
57
+ @account.content_types.build(default_options.merge(options))
58
+ end
59
+
60
+ def populate
61
+ create_content_type
62
+ @account.developers.create :name => 'River Phoenix', :bio => "Life is good"
63
+ @account.developers.create :name => 'Layne Stanley', :bio => "That's great"
64
+ @account.developers.create :name => 'Kurt Cobain', :bio => "Suicide #2"
65
+ end
66
+
67
+ end
@@ -0,0 +1,167 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/functional_spec_helper')
2
+
3
+ describe 'ContentType' do
4
+
5
+ before(:each) do
6
+ Account.destroy_all
7
+ Congo::ProxyScoper.destroy_all
8
+ Congo::ContentType.destroy_all
9
+
10
+ @account = Account.create(:email => 'layne_stanley@acme.org')
11
+ @content_type = @account.content_types.create!({
12
+ :name => 'Project',
13
+ :embedded => false,
14
+ :metadata_keys => [
15
+ { :name => 'name' },
16
+ { :name => 'description' },
17
+ { :name => 'date' }
18
+ ]
19
+ })
20
+ @content_type = @content_type.reload
21
+ end
22
+
23
+ it 'should create new record' do
24
+ project = @account.projects.create(:name => 'Project #1', :description => 'bla bla')
25
+ @account.projects.count.should == 1
26
+ project.out_dated?.should be_false
27
+ project.migrate!.should be_false
28
+ end
29
+
30
+ it 'should not create incremented migration since there are no documents in the collection' do
31
+ (type = build_content_type).save
32
+ type.version.should == 0
33
+ type.migrations.should be_empty
34
+
35
+ type = Congo::ContentType.first
36
+ new_metadata_keys = [type.metadata_keys.pop, Congo::Metadata::Key.new({ :name => 'date' }), type.metadata_keys.pop]
37
+ new_metadata_keys.last.name = 'title'
38
+ type.metadata_keys = new_metadata_keys
39
+ type.save
40
+ type.version.should == 0
41
+ type.migrations.should be_empty
42
+ end
43
+
44
+ it 'should create incremented migration once it has been updated AND there is at least one document in the collection' do
45
+ (type = build_content_type).save
46
+ @account.tasks.create(:name => 'foo', :description => 'bla bla')
47
+ type.version.should == 0
48
+ type.migrations.should be_empty
49
+
50
+ type = @account.content_types.all[1]
51
+ new_metadata_keys = [type.metadata_keys.pop, Congo::Metadata::Key.new({ :name => 'date' })]
52
+ new_metadata_keys.first.name = 'a_description'
53
+ type.metadata_keys = new_metadata_keys
54
+ type.save
55
+ type.version.should == 1
56
+ type.migrations.size.should == 1
57
+ type.migrations.first.tasks.size.should == 2
58
+
59
+ type.migrations.first.tasks[0][:action].should == 'rename'
60
+ type.migrations.first.tasks[0][:previous].should == 'description'
61
+ type.migrations.first.tasks[0][:next].should == 'a_description'
62
+ type.migrations.first.tasks[1][:action].should == 'drop'
63
+ type.migrations.first.tasks[1][:previous].should == 'name'
64
+
65
+ type = @account.content_types.all[1]
66
+ new_metadata_keys = [type.metadata_keys.pop]
67
+ type.metadata_keys = new_metadata_keys
68
+ type.save
69
+ type.version.should == 2
70
+ type.migrations.size.should == 2
71
+ type.migrations.last.tasks.size.should == 1
72
+ type.migrations.last.tasks[0][:action].should == 'drop'
73
+ end
74
+
75
+ it 'should migrate smoothly (renaming and dropping columns)' do
76
+ project = @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
77
+
78
+ # renaming and droppping keys
79
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys[1]]
80
+ new_keys.first.name = 'title'
81
+ @content_type.metadata_keys = new_keys
82
+ @content_type.save
83
+
84
+ @content_type.reload
85
+ @account = Account.first # we need a hard refresh :-)
86
+
87
+ project = @account.projects.first
88
+ project.title.should == 'Project #1'
89
+ project._version.should == 1
90
+ lambda { project.name }.should_not raise_error
91
+ lambda { project.date }.should raise_error
92
+
93
+ @account = Account.first # we need a hard refresh :-)
94
+ @account.associations[:projects].instance_variable_set "@klass", @account.content_types.first.to_const
95
+
96
+ another_project = @account.projects.create!(:title => 'Project #2', :description => 'bla bla')
97
+ lambda { another_project.name }.should raise_error
98
+ lambda { another_project.date }.should raise_error
99
+ end
100
+
101
+ it 'should run 2 pending migrations' do
102
+ project = @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
103
+
104
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys[1]]
105
+ new_keys.first.name = 'title'
106
+ @content_type.metadata_keys = new_keys
107
+ @content_type.save
108
+
109
+ @content_type = @content_type.reload # necessary
110
+
111
+ new_keys = [@content_type.metadata_keys.first]
112
+ new_keys.first.name = 'name'
113
+ @content_type.metadata_keys = new_keys
114
+ @content_type.save
115
+
116
+ @account = Account.first # we need a hard refresh :-)
117
+ project = @account.projects.first # two pending migrations
118
+
119
+ project._version.should == 2
120
+ project.name.should == 'Project #1'
121
+ lambda { project.title }.should raise_error
122
+ lambda { project.description }.should raise_error
123
+ lambda { project.date }.should raise_error
124
+ end
125
+
126
+ it 'should update validation if key name changes' do
127
+ @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
128
+
129
+ @content_type.metadata_validations = [{ :key => 'name', :type => 'presence_of' }]
130
+ @content_type.save
131
+
132
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys.last]
133
+ new_keys.first.name = 'title'
134
+ @content_type.metadata_keys = new_keys
135
+ @content_type.save
136
+
137
+ @content_type = Congo::ContentType.first # hard refresh
138
+ @content_type.metadata_validations.first.key.should == 'title'
139
+ end
140
+
141
+ it 'should update validation if key is droppped' do
142
+ @account.projects.create(:name => 'Project #1', :description => 'bla bla', :date => '10/09/2009')
143
+
144
+ @content_type.metadata_validations = [{ :key => 'description', :type => 'presence_of' }]
145
+ @content_type.save
146
+
147
+ new_keys = [@content_type.metadata_keys.first, @content_type.metadata_keys.last]
148
+ @content_type.metadata_keys = new_keys
149
+ @content_type.save
150
+
151
+ @content_type = Congo::ContentType.first # hard refresh
152
+ @content_type.metadata_validations.should be_empty
153
+ end
154
+
155
+ def build_content_type(options = {})
156
+ default_options = {
157
+ :name => 'Task',
158
+ :embedded => false,
159
+ :metadata_keys => [
160
+ { :name => 'name' },
161
+ { :name => 'description' }
162
+ ] }
163
+
164
+ @account.content_types.build(default_options.merge(options))
165
+ end
166
+
167
+ end