Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add specs
It's certainly not a best practice to wait 3 years before adding
specs for a library you are using in production, but better late
than never.

This adds specs for both ActiveRecord and Sequel, which should
have close to 100% line coverage.
  • Loading branch information
jeremyevans committed Jan 28, 2011
1 parent a22a22a commit 7ade3a7
Show file tree
Hide file tree
Showing 13 changed files with 283 additions and 6 deletions.
6 changes: 4 additions & 2 deletions .gitignore
@@ -1,2 +1,4 @@
rdoc/ /rdoc/
*.gem /*.gem
/spec/db
/coverage
15 changes: 11 additions & 4 deletions README
Expand Up @@ -7,7 +7,7 @@ the following features:
- Fixtures specify association names instead of foreign keys - Fixtures specify association names instead of foreign keys
- Support both Sequel and ActiveRecord - Support both Sequel and ActiveRecord
- Supports many_to_one/belongs_to, one_to_many/has_many, - Supports many_to_one/belongs_to, one_to_many/has_many,
many_to_many/has_and_belongs_to_many, and has_one associations many_to_many/has_and_belongs_to_many, and has_one/one_to_one associations
- Loads a fixture's dependency graph in such a manner that foreign key - Loads a fixture's dependency graph in such a manner that foreign key
constraints aren't violated constraints aren't violated
- Has a very simple API (FixtureDependencies.load(:model__fixture)) - Has a very simple API (FixtureDependencies.load(:model__fixture))
Expand Down Expand Up @@ -128,7 +128,7 @@ using the following syntax:


This would load just the jeremy fixture and its dependencies. I find this is This would load just the jeremy fixture and its dependencies. I find this is
much better than loading all fixtures in most of my test suites. Even better much better than loading all fixtures in most of my test suites. Even better
is loading just the fixtures you want instead every test method (see below). is loading just the fixtures you want inside every test method (see below).
This leads to the most robust testing. This leads to the most robust testing.


== Loading fixtures inside test methods == Loading fixtures inside test methods
Expand Down Expand Up @@ -244,6 +244,13 @@ test/test_helper.rb:
This will give a verbose description of the loading and saving of fixtures for This will give a verbose description of the loading and saving of fixtures for
every test, including the recursive loading of the dependency graph. every test, including the recursive loading of the dependency graph.


== Specs

The specs for fixture dependencies and be run with Rake. They require
the sequel, activerecord, and sqlite3 gems installed. The default rake task
runs the specs. You should run the spec_migrate task first to create the
spec database.

== Similar Ideas == Similar Ideas


Rails now supports something similar by default. Honestly, I'm not sure what Rails now supports something similar by default. Honestly, I'm not sure what
Expand All @@ -255,8 +262,8 @@ it doesn't support has_* associations.


== License == License


fixture_dependencies is released under the MIT License. See the LICENSE file fixture_dependencies is released under the MIT License. See the MIT-LICENSE
for details. file for details.


== Author == Author


Expand Down
27 changes: 27 additions & 0 deletions Rakefile
Expand Up @@ -20,3 +20,30 @@ desc "Package fixture_dependencies"
task :package do task :package do
sh %{gem build fixture_dependencies.gemspec} sh %{gem build fixture_dependencies.gemspec}
end end

begin
require 'spec/rake/spectask'

desc "Run Sequel specs"
Spec::Rake::SpecTask.new(:spec_sequel) do |t|
t.spec_files = Dir['spec/*_spec.rb']
#t.rcov = true
end

desc "Run ActiveRecord specs"
Spec::Rake::SpecTask.new(:spec_ar) do |t|
ENV['FD_AR'] = '1'
t.spec_files = Dir['spec/*_spec.rb']
#t.rcov = true
end

desc "Run Sequel and ActiveRecord specs"
task :default=>[:spec_sequel, :spec_ar]
rescue LoadError
end

desc "Create spec database"
task :spec_migrate do
sh %{mkdir -p spec/db}
sh %{sequel -m spec/migrate -E sqlite://spec/db/fd_spec.sqlite3}
end
21 changes: 21 additions & 0 deletions spec/ar_spec_helper.rb
@@ -0,0 +1,21 @@
require 'active_record'

ActiveRecord::Base.establish_connection(:adapter=>'sqlite3', :database=>File.join(File.dirname(File.expand_path(__FILE__)), 'db', 'fd_spec.sqlite3'))

class Artist < ActiveRecord::Base
has_many :albums
end

class Album < ActiveRecord::Base
belongs_to :artist
has_and_belongs_to_many :tags
end

class Tag < ActiveRecord::Base
has_and_belongs_to_many :albums
end

class SelfRef < ActiveRecord::Base
belongs_to :self_ref
has_many :self_refs
end
124 changes: 124 additions & 0 deletions spec/fd_spec.rb
@@ -0,0 +1,124 @@
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')

describe FixtureDependencies do
def load(*a) FixtureDependencies.load(*a) end
def verbose(i=3)
v = FixtureDependencies.verbose
FixtureDependencies.verbose = i
yield
ensure
FixtureDependencies.verbose = v
end

after do
# Clear tables and fixture_dependencies caches
[:self_refs, :albums_tags, :tags, :albums, :artists].each{|x| DB[x].delete}
FixtureDependencies.loaded.clear
FixtureDependencies.fixtures.clear
end

it "should load single records with underscore syntax" do
ym = load(:artist__ym)
ym.id.should == 1
ym.name.should == 'YM'
end

it "should load multiple records with underscore syntax and multiple arguments" do
rf, mo = load(:album__rf, :album__mo)
rf.id.should == 1
rf.name.should == 'RF'
mo.id.should == 2
mo.name.should == 'MO'
end

it "should load multiple records with hash syntax" do
rf, mo = load(:albums=>[:rf, :mo])
rf.id.should == 1
rf.name.should == 'RF'
mo.id.should == 2
mo.name.should == 'MO'
end

it "should load multiple records with a mix a hashes and symbols" do
rf, mo = load(:album__rf, :albums=>[:mo])
rf.id.should == 1
rf.name.should == 'RF'
mo.id.should == 2
mo.name.should == 'MO'
end

it "should load whole tables at once with single symbol" do
Artist.count.should == 0
load(:artists)
Artist.count.should == 2
end

it "should load whole tables at once with single symbol" do
Artist.count.should == 0
Album.count.should == 0
load(:artists, :albums)
Artist.count.should == 2
Album.count.should == 3
end

it "should load associated many_to_one records" do
rf = load(:album__rf)
rf.artist.id.should == 1
end

it "should load associated one_to_many records" do
nu = load(:artist__nu)
nu.albums.length.should == 1
nu.albums.first.id.should == 3
nu.albums.first.name.should == 'P'
end

it "should load associated many_to_many records and handle cycles (I->P->NU->P)" do
i = load(:tag__i)
i.albums.length.should == 1
p = i.albums.first
p.id.should == 3
p.name.should == 'P'
nu = p.artist
nu.id.should == 2
nu.name.should == 'NU'
nu.albums.length.should == 1
nu.albums.first.should == p
end

it "should not load records that were not asked for" do
ym = load(:artist__ym)
Artist.count.should == 1
Artist.first.should == ym
load(:artist__nu)
Artist.count.should == 2
end

it "should handle self referential records" do
i = load(:self_ref__i)
i.id.should == 1
i.self_ref.id.should == 1
i.self_refs.length.should == 1
i.self_refs.first.id.should == 1
end

it "should handle association cycles" do
a = load(:self_ref__a)
a.id.should == 2
b = a.self_ref
b.id.should == 3
c = b.self_ref
c.id.should == 4
c.self_ref.should == a
end

it "should raise error nonexistent fixture files" do
class Foo < Sequel::Model; end
proc{load(:foos)}.should raise_error(ArgumentError)
end

it "should raise error for unsupported model classes" do
class Bar; def self.table_name() :bars end end
proc{load(:bars)}.should raise_error(TypeError)
end
end
12 changes: 12 additions & 0 deletions spec/fixtures/albums.yml
@@ -0,0 +1,12 @@
rf:
id: 1
name: RF
artist: ym
mo:
id: 2
name: MO
artist: ym
p:
id: 3
name: P
artist: nu
7 changes: 7 additions & 0 deletions spec/fixtures/artists.yml
@@ -0,0 +1,7 @@
ym:
id: 1
name: YM
nu:
id: 2
name: NU
albums: p
2 changes: 2 additions & 0 deletions spec/fixtures/bars.yml
@@ -0,0 +1,2 @@
i:
id: 1
14 changes: 14 additions & 0 deletions spec/fixtures/self_refs.yml.erb
@@ -0,0 +1,14 @@
i:
id: 1
self_ref: i
self_refs: [i]
a:
id: 2
self_ref: b
b:
id: 3
self_ref: c
c:
id: 4
self_ref: a

7 changes: 7 additions & 0 deletions spec/fixtures/tags.yml
@@ -0,0 +1,7 @@
m:
id: 1
name: M
i:
id: 2
name: I
albums: p
10 changes: 10 additions & 0 deletions spec/migrate/001_tables.rb
@@ -0,0 +1,10 @@
Sequel.migration do
change do
create_table(:artists){primary_key :id; String :name}
create_table(:albums){primary_key :id; String :name; foreign_key :artist_id, :artists}
create_table(:tags){primary_key :id; String :name}
create_table(:albums_tags){foreign_key :album_id, :albums; foreign_key :tag_id, :tags; primary_key [:album_id, :tag_id]}

create_table(:self_refs){primary_key :id; foreign_key :self_ref_id, :self_refs}
end
end
31 changes: 31 additions & 0 deletions spec/sequel_spec_helper.rb
@@ -0,0 +1,31 @@
class Artist < Sequel::Model
one_to_many :albums
end

class Album < Sequel::Model
many_to_one :artist
many_to_many :tags
end

class Tag < Sequel::Model
many_to_many :albums
end

class SelfRef < Sequel::Model
many_to_one :self_ref
one_to_many :self_refs
end

class ComArtist < Sequel::Model
one_to_many :com_albums, :key=>[:artist_id1, :artist_id2]
end

class ComAlbum < Sequel::Model
many_to_one :com_artist, :key=>[:artist_id1, :artist_id2]
many_to_many :com_tags, :left_key=>[:album_id1, :album_id2], :right_key=>[:tag_id1, :tag_id2]
end

class ComTag < Sequel::Model
many_to_many :com_albums, :right_key=>[:album_id1, :album_id2], :left_key=>[:tag_id1, :tag_id2]
end

13 changes: 13 additions & 0 deletions spec/spec_helper.rb
@@ -0,0 +1,13 @@
require 'rubygems'
require 'sequel'

DB = Sequel.sqlite(File.join(File.dirname(File.expand_path(__FILE__)), 'db', 'fd_spec.sqlite3'))

require File.join(File.dirname(File.expand_path(__FILE__)),"#{ENV['FD_AR'] ? 'ar' : 'sequel'}_spec_helper")

$:.unshift(File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'lib'))
require 'fixture_dependencies'
FixtureDependencies.fixture_path = File.join(File.dirname(File.expand_path(__FILE__)), 'fixtures')
#FixtureDependencies.verbose = 3


0 comments on commit 7ade3a7

Please sign in to comment.