dm-svn 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/dm-svn.gemspec +85 -0
- data/lib/dm-svn.rb +13 -0
- data/lib/dm-svn/config.rb +38 -0
- data/lib/dm-svn/model.rb +12 -0
- data/lib/dm-svn/svn.rb +144 -0
- data/lib/dm-svn/svn/categorized.rb +113 -0
- data/lib/dm-svn/svn/changeset.rb +119 -0
- data/lib/dm-svn/svn/node.rb +128 -0
- data/lib/dm-svn/svn/sync.rb +85 -0
- data/spec/dm-svn/config_spec.rb +51 -0
- data/spec/dm-svn/database.yml +16 -0
- data/spec/dm-svn/fixtures/articles_comments.rb +95 -0
- data/spec/dm-svn/mock_models.rb +53 -0
- data/spec/dm-svn/model_spec.rb +5 -0
- data/spec/dm-svn/spec_helper.rb +50 -0
- data/spec/dm-svn/svn/categorized_spec.rb +138 -0
- data/spec/dm-svn/svn/changeset_spec.rb +42 -0
- data/spec/dm-svn/svn/node_spec.rb +125 -0
- data/spec/dm-svn/svn/sync_spec.rb +111 -0
- data/spec/dm-svn/svn_spec.rb +213 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_helper.rb +23 -0
- metadata +132 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dm-svn'
|
3
|
+
|
4
|
+
class MockArticle
|
5
|
+
include DataMapper::Resource
|
6
|
+
include DmSvn::Svn
|
7
|
+
|
8
|
+
property :id, Serial
|
9
|
+
property :title, String
|
10
|
+
property :contents, Text, :body_property => true
|
11
|
+
end
|
12
|
+
|
13
|
+
class MockArticleNoSvn
|
14
|
+
include DataMapper::Resource
|
15
|
+
|
16
|
+
property :id, Serial
|
17
|
+
property :title, String
|
18
|
+
property :contents, Text
|
19
|
+
end
|
20
|
+
|
21
|
+
class MockSyncModel
|
22
|
+
include DataMapper::Resource
|
23
|
+
include DmSvn::Svn
|
24
|
+
|
25
|
+
property :id, Serial
|
26
|
+
property :title, String
|
27
|
+
property :body, Text, :body_property => true
|
28
|
+
property :published_at, DateTime
|
29
|
+
property :random_number, Integer # because some tests need a non-datetime prop
|
30
|
+
end
|
31
|
+
|
32
|
+
class MockCategory
|
33
|
+
include DataMapper::Resource
|
34
|
+
include DmSvn::Svn
|
35
|
+
has n, :mock_categorized_articles
|
36
|
+
|
37
|
+
property :id, Serial
|
38
|
+
property :title, String
|
39
|
+
property :random_number, Integer
|
40
|
+
end
|
41
|
+
|
42
|
+
class MockCategorizedArticle
|
43
|
+
include DataMapper::Resource
|
44
|
+
include DmSvn::Svn
|
45
|
+
belongs_to :mock_category, :svn => true
|
46
|
+
|
47
|
+
property :id, Serial
|
48
|
+
property :title, String
|
49
|
+
property :article, String
|
50
|
+
property :body, Text, :body_property => true
|
51
|
+
property :published_at, DateTime
|
52
|
+
property :random_number, Integer # because some tests need a non-datetime prop
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class MockArticle
|
2
|
+
include DataMapper::Resource
|
3
|
+
include DmSvn::Svn
|
4
|
+
|
5
|
+
property :id, Integer, :serial => true
|
6
|
+
property :title, String
|
7
|
+
property :contents, Text, :body_property => true
|
8
|
+
end
|
9
|
+
|
10
|
+
class MockArticleNoSvn
|
11
|
+
include DataMapper::Resource
|
12
|
+
|
13
|
+
property :id, Integer, :serial => true
|
14
|
+
property :title, String
|
15
|
+
property :contents, Text
|
16
|
+
end
|
17
|
+
|
18
|
+
class MockSyncModel
|
19
|
+
include DataMapper::Resource
|
20
|
+
include DmSvn::Svn
|
21
|
+
|
22
|
+
property :id, Integer, :serial => true
|
23
|
+
property :title, String
|
24
|
+
property :body, Text, :body_property => true
|
25
|
+
property :published_at, DateTime
|
26
|
+
property :random_number, Integer # because some tests need a non-datetime prop
|
27
|
+
end
|
28
|
+
|
29
|
+
class MockCategory
|
30
|
+
include DataMapper::Resource
|
31
|
+
include DmSvn::Svn
|
32
|
+
has n, :mock_categorized_articles
|
33
|
+
|
34
|
+
property :id, Integer, :serial => true
|
35
|
+
property :title, String
|
36
|
+
property :random_number, Integer
|
37
|
+
end
|
38
|
+
|
39
|
+
class MockCategorizedArticle
|
40
|
+
include DataMapper::Resource
|
41
|
+
include DmSvn::Svn
|
42
|
+
belongs_to :mock_category, :svn => true
|
43
|
+
|
44
|
+
property :id, Integer, :serial => true
|
45
|
+
property :title, String
|
46
|
+
property :article, String
|
47
|
+
property :body, Text, :body_property => true
|
48
|
+
property :published_at, DateTime
|
49
|
+
property :random_number, Integer # because some tests need a non-datetime prop
|
50
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dm-svn/mock_models'
|
3
|
+
|
4
|
+
describe DmSvn::Svn::Categorized do
|
5
|
+
before(:all) do
|
6
|
+
DmSvn::Model.auto_migrate!
|
7
|
+
MockCategory.auto_migrate!
|
8
|
+
MockCategorizedArticle.auto_migrate!
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
MockCategory.all.each { |m| m.destroy }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ".belongs_to" do
|
16
|
+
it "should initialize @svn_category" do
|
17
|
+
MockCategorizedArticle.instance_variable_get('@svn_category').should ==
|
18
|
+
:mock_category
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should initialize @svn_category_model' do
|
22
|
+
MockCategorizedArticle.instance_variable_get('@svn_category_model').should ==
|
23
|
+
'MockCategory'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it '.svn_category should get name of category (as method name)' do
|
28
|
+
MockCategorizedArticle.svn_category.should == :mock_category
|
29
|
+
end
|
30
|
+
|
31
|
+
it '.svn_category_model should get name of category (as constant)' do
|
32
|
+
MockCategorizedArticle.svn_category_model.should == 'MockCategory'
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#path" do
|
36
|
+
before(:each) do
|
37
|
+
@article = MockCategorizedArticle.new(:svn_name => 'article')
|
38
|
+
@category = MockCategory.new(:svn_name => 'cat/path')
|
39
|
+
@article.mock_category = @category
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should append @svn_name to svn_category.path" do
|
43
|
+
@article.path.should == 'cat/path/article'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return just @svn_name if svn_category.path is blank" do
|
47
|
+
@category.path = ''
|
48
|
+
@article.path.should == 'article'
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return just @svn_name if svn_category is nil" do
|
52
|
+
@article.mock_category = nil
|
53
|
+
@article.path.should == 'article'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#path=" do
|
58
|
+
before(:each) do
|
59
|
+
@article = MockCategorizedArticle.new(:svn_name => 'article')
|
60
|
+
@category = MockCategory.create(:svn_name => 'cat/path')
|
61
|
+
@article.mock_category = @category
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should move instance to a different category" do
|
65
|
+
new_cat = MockCategory.create(:svn_name => 'cat/new')
|
66
|
+
@article.path = "cat/new/article"
|
67
|
+
@article.mock_category.should == new_cat
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should update @svn_name" do
|
71
|
+
@article.path = "cat/path/article2"
|
72
|
+
@article.svn_name.should == 'article2'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should remove any category if only one path level" do
|
76
|
+
MockCategory.should_not_receive(:get_or_create)
|
77
|
+
@article.path = "article"
|
78
|
+
@article.mock_category.should be_nil
|
79
|
+
@article.path.should == 'article'
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should ignore leading slash" do
|
83
|
+
new_cat = MockCategory.create(:svn_name => 'cat/new')
|
84
|
+
MockCategory.should_receive(:get_or_create).with('cat/new')
|
85
|
+
@article.path = "//cat/new/article"
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe ".get" do
|
91
|
+
it "should get an instance if possible" do
|
92
|
+
MockCategorizedArticle.should_receive(:get_by_path).
|
93
|
+
with('path/to/name').
|
94
|
+
and_return(1)
|
95
|
+
|
96
|
+
MockCategorizedArticle.get('path/to/name', true) == 1
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should try to get an instance of parent if needed (and get_parent is true)" do
|
100
|
+
MockCategorizedArticle.should_receive(:get_by_path).
|
101
|
+
with('path/to/name').
|
102
|
+
and_return(nil)
|
103
|
+
|
104
|
+
MockCategory.should_receive(:get_by_path).with('path/to/name').and_return(2)
|
105
|
+
MockCategorizedArticle.get('path/to/name', true) == 2
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should not try to get an instance of parent by default" do
|
109
|
+
MockCategorizedArticle.should_receive(:get_by_path).
|
110
|
+
with('path/to/name').
|
111
|
+
and_return(nil)
|
112
|
+
|
113
|
+
MockCategory.should_not_receive(:get_by_path)
|
114
|
+
|
115
|
+
MockCategorizedArticle.get('path/to/name').should be_nil
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
describe ".get_by_path" do
|
121
|
+
it "should scope by category" do
|
122
|
+
category = mock(MockCategory)
|
123
|
+
|
124
|
+
MockCategory.should_receive(:first).
|
125
|
+
with(:svn_name => 'path/to').
|
126
|
+
and_return(category)
|
127
|
+
|
128
|
+
category.should_receive(:id).and_return(3)
|
129
|
+
|
130
|
+
MockCategorizedArticle.should_receive(:first).
|
131
|
+
with(:svn_name => 'name', :mock_category_id => 3).
|
132
|
+
and_return(nil)
|
133
|
+
|
134
|
+
MockCategorizedArticle.get_by_path('path/to/name')
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dm-svn/mock_models'
|
3
|
+
|
4
|
+
describe DmSvn::Svn::Changeset do
|
5
|
+
before(:all) do
|
6
|
+
DmSvn::Model.auto_migrate!
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#short_path" do
|
10
|
+
before(:each) do
|
11
|
+
DmSvn::Model.all.each { |m| m.destroy }
|
12
|
+
sync = mock('DmSvn::Svn::Sync')
|
13
|
+
@config = DmSvn::Config.new
|
14
|
+
@config.extension = nil
|
15
|
+
@config.path_from_root = "/articles"
|
16
|
+
sync.stub!(:config).and_return @config
|
17
|
+
sync.stub!(:model).and_return nil
|
18
|
+
sync.stub!(:repos).and_return nil
|
19
|
+
|
20
|
+
@changeset = DmSvn::Svn::Changeset.new([], 1, '', Time.now, sync)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should remove 'leading path'" do
|
24
|
+
@changeset.__send__(:short_path, "/articles/something").should == "something"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should remove extension if configured" do
|
28
|
+
@config.extension = 'txt'
|
29
|
+
@changeset.__send__(:short_path, "/articles/something.txt").should == "something"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not remove other extensions" do
|
33
|
+
@config.extension = 'txt'
|
34
|
+
@changeset.__send__(:short_path, "/articles/something.jpg").should == "something.jpg"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not remove extension if not configured" do
|
38
|
+
@changeset.__send__(:short_path, "/articles/something.txt").should == "something.txt"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dm-svn/mock_models'
|
3
|
+
|
4
|
+
describe DmSvn::Svn::Node do
|
5
|
+
before(:all) do
|
6
|
+
@repos_uri = load_svn_fixture('articles_comments')
|
7
|
+
|
8
|
+
DmSvn::Model.auto_migrate!
|
9
|
+
@ws_model = DmSvn::Model.create(:name => 'MockSyncModel', :revision => 0)
|
10
|
+
@ws_model.config = DmSvn::Config.new
|
11
|
+
@ws_model.config.uri = @repos_uri
|
12
|
+
@sync = DmSvn::Svn::Sync.new(@ws_model)
|
13
|
+
@sync.__send__(:connect, @repos_uri)
|
14
|
+
|
15
|
+
@cs = @sync.changesets[1] # revision 2
|
16
|
+
@cs3 = @sync.changesets[2] # revision 9
|
17
|
+
@cs9 = @sync.changesets[7] # revision 9
|
18
|
+
@dir = DmSvn::Svn::Node.new(@cs, "/articles")
|
19
|
+
@file = DmSvn::Svn::Node.new(@cs3, "/articles/unpublished.txt")
|
20
|
+
end
|
21
|
+
|
22
|
+
after(:all) do
|
23
|
+
SvnFixture::Repository.destroy_all
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should get short_path" do
|
27
|
+
@file.short_path.should == "unpublished"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should check if file" do
|
31
|
+
@dir.file?.should be_false
|
32
|
+
@file.file?.should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should check if directory" do
|
36
|
+
@dir.directory?.should be_true
|
37
|
+
@file.directory?.should be_false
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should get body" do
|
41
|
+
@dir.body.should be_nil
|
42
|
+
@file.body.should == "See, it's not published.\nYou can't read it."
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should remove yaml from body" do
|
46
|
+
DmSvn::Svn::Node.new(@cs9, "/articles/turtle.txt").body.should == 'Hi, turtle.'
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#properties" do
|
50
|
+
it "should get properties from svn properties" do
|
51
|
+
@dir.properties.should ==
|
52
|
+
{
|
53
|
+
'svn_updated_at' => @dir.date,
|
54
|
+
'svn_updated_by' => @dir.author,
|
55
|
+
'svn_updated_rev' => @dir.revision,
|
56
|
+
'title' => 'Articles'
|
57
|
+
}
|
58
|
+
|
59
|
+
@file.properties.should ==
|
60
|
+
{
|
61
|
+
'svn_updated_at' => @file.date,
|
62
|
+
'svn_updated_by' => @file.author,
|
63
|
+
'svn_updated_rev' => @file.revision,
|
64
|
+
'title' => 'Private Thoughts'
|
65
|
+
}
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should get properties from yaml properties" do
|
70
|
+
dir9 = DmSvn::Svn::Node.new(@cs9, "/articles")
|
71
|
+
dir9.properties.should ==
|
72
|
+
{
|
73
|
+
'svn_updated_at' => dir9.date,
|
74
|
+
'svn_updated_by' => dir9.author,
|
75
|
+
'svn_updated_rev' => dir9.revision,
|
76
|
+
'title' => 'Lots of Articles',
|
77
|
+
'random_number' => 7
|
78
|
+
}
|
79
|
+
|
80
|
+
file9 = DmSvn::Svn::Node.new(@cs9, "/articles/turtle.txt")
|
81
|
+
file9.properties.should ==
|
82
|
+
{
|
83
|
+
'svn_updated_at' => file9.date,
|
84
|
+
'svn_updated_by' => file9.author,
|
85
|
+
'svn_updated_rev' => file9.revision,
|
86
|
+
'title' => 'Turtle',
|
87
|
+
'random_number' => 2
|
88
|
+
}
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "variables from changeset" do
|
94
|
+
before(:each) do
|
95
|
+
@cs = mock(DmSvn::Svn::Changeset)
|
96
|
+
@node = DmSvn::Svn::Node.new(@cs, 'path')
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should get revision" do
|
100
|
+
@cs.should_receive(:revision).and_return(2)
|
101
|
+
@node.revision.should == 2
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should get author" do
|
105
|
+
@cs.should_receive(:author).and_return('jmorgan')
|
106
|
+
@node.author.should == 'jmorgan'
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should get date" do
|
110
|
+
@cs.should_receive(:date).and_return('2008-05-10')
|
111
|
+
@node.date.should == '2008-05-10'
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should get repos" do
|
115
|
+
@cs.should_receive(:repos).and_return(:repos)
|
116
|
+
@node.repos.should == :repos
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should get config" do
|
120
|
+
@cs.should_receive(:config).and_return(:config)
|
121
|
+
@node.config.should == :config
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dm-svn/mock_models'
|
3
|
+
|
4
|
+
describe DmSvn::Svn::Sync do
|
5
|
+
after(:all) do
|
6
|
+
SvnFixture::Repository.destroy_all
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#run" do
|
10
|
+
before(:all) do
|
11
|
+
DmSvn::Model.auto_migrate!
|
12
|
+
MockSyncModel.auto_migrate!
|
13
|
+
@repos_uri = load_svn_fixture('articles_comments')
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
MockSyncModel.all.each { |m| m.destroy }
|
18
|
+
DmSvn::Model.all.each { |m| m.destroy }
|
19
|
+
@ws_model = DmSvn::Model.create(:name => 'MockSyncModel', :revision => 0)
|
20
|
+
@ws_model.config = DmSvn::Config.new
|
21
|
+
@ws_model.config.uri = @repos_uri
|
22
|
+
@sync = DmSvn::Svn::Sync.new(@ws_model)
|
23
|
+
end
|
24
|
+
|
25
|
+
# This is a generic "it should just work" test
|
26
|
+
it "should update database" do
|
27
|
+
@sync.run
|
28
|
+
MockSyncModel.count.should == 4
|
29
|
+
|
30
|
+
comp = MockSyncModel.first(:svn_name => "computations")
|
31
|
+
comp.body.should == 'Computers do not like salsa very much.'
|
32
|
+
comp.svn_updated_rev.to_i.should == 7
|
33
|
+
comp.svn_created_rev.to_i.should == 7
|
34
|
+
|
35
|
+
phil = MockSyncModel.first(:svn_name => "philosophy")
|
36
|
+
phil.svn_updated_rev.to_i.should == 2
|
37
|
+
phil.svn_created_rev.to_i.should == 2
|
38
|
+
|
39
|
+
pub = MockSyncModel.first(:svn_name => "just_published")
|
40
|
+
published_time = Time.parse(pub.published_at.strftime("%Y-%m-%d %H:%M:%S"))
|
41
|
+
published_time.should be_close(Time.now - 3600, 100)
|
42
|
+
pub.svn_created_by.should == "author"
|
43
|
+
pub.title.should == "Private Thoughts"
|
44
|
+
pub.svn_updated_rev.to_i.should == 7
|
45
|
+
pub.svn_created_rev.to_i.should == 3
|
46
|
+
|
47
|
+
MockSyncModel.first(:svn_name => "computers.txt").should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should update DmSvn::Model entry" do
|
51
|
+
@sync.run
|
52
|
+
DmSvn::Model.get(@ws_model.id).revision.should == 9
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return false if already at the youngest revision" do
|
56
|
+
@sync.run.should be_true
|
57
|
+
@ws_model = DmSvn::Model.get(@ws_model.id)
|
58
|
+
@ws_model.config = DmSvn::Config.new
|
59
|
+
@ws_model.config.uri = @repos_uri
|
60
|
+
@sync = DmSvn::Svn::Sync.new(@ws_model)
|
61
|
+
@sync.run.should be_false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#run (categorized)" do
|
66
|
+
before(:all) do
|
67
|
+
DmSvn::Model.auto_migrate!
|
68
|
+
MockCategory.auto_migrate!
|
69
|
+
MockCategorizedArticle.auto_migrate!
|
70
|
+
@repos_uri = load_svn_fixture('articles_comments')[0..-10]
|
71
|
+
end
|
72
|
+
|
73
|
+
before(:each) do
|
74
|
+
MockCategory.all.each { |m| m.destroy }
|
75
|
+
MockCategorizedArticle.all.each { |m| m.destroy }
|
76
|
+
DmSvn::Model.all.each { |m| m.destroy }
|
77
|
+
@ws_model = DmSvn::Model.create(:name => 'MockCategorizedArticle', :revision => 0)
|
78
|
+
@ws_model.config = DmSvn::Config.new
|
79
|
+
@ws_model.config.uri = @repos_uri
|
80
|
+
@sync = DmSvn::Svn::Sync.new(@ws_model)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should update database, when categorized" do
|
84
|
+
@sync.run
|
85
|
+
|
86
|
+
MockCategory.count.should == 2
|
87
|
+
MockCategorizedArticle.count.should == 6
|
88
|
+
|
89
|
+
comp = MockCategorizedArticle.first(:svn_name => "computations")
|
90
|
+
comp.body.should == 'Computers do not like salsa very much.'
|
91
|
+
comp.svn_updated_rev.to_i.should == 7
|
92
|
+
comp.svn_created_rev.to_i.should == 7
|
93
|
+
|
94
|
+
phil = MockCategorizedArticle.first(:svn_name => "philosophy")
|
95
|
+
phil.svn_updated_rev.to_i.should == 2
|
96
|
+
phil.svn_created_rev.to_i.should == 2
|
97
|
+
|
98
|
+
MockCategorizedArticle.first(:svn_name => "computers.txt").should be_nil
|
99
|
+
|
100
|
+
articles = MockCategory.first(:svn_name => "articles")
|
101
|
+
articles.mock_categorized_articles.length.should == 4
|
102
|
+
comp.mock_category.id.should == articles.id
|
103
|
+
articles.title.should == "Lots of Articles"
|
104
|
+
|
105
|
+
comments = MockCategory.first(:svn_name => "comments")
|
106
|
+
comments.mock_categorized_articles.length.should == 2
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|