dm-spec 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jakub Stastny aka Botanicus
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ h1. About
2
+
3
+ RSpec matchers for DataMapper.
4
+
5
+ h1. Usage
6
+
7
+ You must include DataMapperMatchers to your specs. It can be done in *spec/spec_helper.rb*:
8
+
9
+ <pre>
10
+ $: << File.dirname(__FILE__) + "/../lib"
11
+ require "dm-core"
12
+ require "dm-spec"
13
+
14
+ DataMapper.setup(:default, "sqlite3::memory")
15
+
16
+ Spec::Runner.configure do |config|
17
+ config.include(DataMapperMatchers)
18
+ config.before(:each) do
19
+ DataMapper.auto_migrate!
20
+ end
21
+ end
22
+ </pre>
23
+
24
+ That's it. Now just use these matchers in your specs. All the matchers you should call on model class, not on model instance.
25
+
26
+ <pre>
27
+ Post.should has_property(:title)
28
+ Post.should has_many(:comments)
29
+ Post.should has_and_belongs_to_many(:tags)
30
+ Post.should belongs_to(:category)
31
+ Post.should has_timestamps # created_at, updated_at
32
+ Post.should has_timestamps(:at) # created_at, updated_at
33
+ Post.should has_timestamps(:on) # created_on, updated_on
34
+ Post.should has_timestamps(:created_at)
35
+ </pre>
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ GEM_NAME = "dm-spec"
5
+ AUTHOR = "Jakub Stastny aka Botanicus"
6
+ EMAIL = "knava.bestvinensis@gmail.com"
7
+ HOMEPAGE = "http://101Ideas.cz/"
8
+ SUMMARY = "RSpec matchers for DataMapper."
9
+ GEM_VERSION = "0.9.10"
10
+
11
+ spec = Gem::Specification.new do |s|
12
+ s.name = GEM_NAME
13
+ s.version = GEM_VERSION
14
+ s.platform = Gem::Platform::RUBY
15
+ s.has_rdoc = true
16
+ s.extra_rdoc_files = ["README.textile", "LICENSE"]
17
+ s.summary = SUMMARY
18
+ s.description = s.summary
19
+ s.author = AUTHOR
20
+ s.email = EMAIL
21
+ s.homepage = HOMEPAGE
22
+ s.require_path = 'lib'
23
+ s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
24
+ end
25
+
26
+ Rake::GemPackageTask.new(spec) do |pkg|
27
+ pkg.gem_spec = spec
28
+ end
29
+
30
+ desc "Create a gemspec file"
31
+ task :gemspec do
32
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
33
+ file.puts spec.to_ruby
34
+ end
35
+ end
36
+
37
+ def sudo_gem(cmd)
38
+ sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
39
+ end
40
+
41
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
42
+ task :install => [ :package ] do
43
+ sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
44
+ end
45
+
46
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
47
+ task :uninstall => [ :clobber ] do
48
+ sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -Ix"
49
+ end
50
+
51
+ require 'spec/rake/spectask'
52
+ desc 'Default: run spec examples'
53
+ task :default => 'spec'
54
+
data/TODO ADDED
@@ -0,0 +1,133 @@
1
+ - check property options
2
+ - more flexible way for checking associations
3
+
4
+ be_timestamped
5
+ be_key
6
+ validace
7
+ Category.should # => Expectation
8
+ Category.should has_property(:name) # => true
9
+ Category.my_property.should be_private
10
+ ... soo ...
11
+ should true => OK
12
+ => just return self instead of true => chain
13
+ @category.should has(1).error_on(:name).with("Nazev...")
14
+
15
+ irb(main):012:0> Product.slug
16
+ => #<Property:Product:slug>
17
+ irb(main):014:0> Product.slug.to_yaml_properties
18
+ => ["@custom", "@default", "@extra_options", "@field", "@fields", "@getter", "@index", "@instance_variable_name", "@key", "@lazy", "@length", "@model", "@name", "@nullable", "@options", "@primitive", "@reader_visibility", "@serial", "@track", "@type", "@unique_index", "@writer_visibility"]
19
+ irb(main):015:0> Product.slug.key?
20
+ => true
21
+ irb(main):018:0> Product.slug.serial?
22
+ => false
23
+ irb(main):019:0> Product.slug.default
24
+ => nil
25
+ irb(main):022:0> Product.slug.extra_options
26
+ => {:writter=>:private}
27
+ irb(main):027:0> Product.slug.unique_index
28
+ => false
29
+ rb(main):030:0> Product.slug.reader_visibility
30
+ => :public
31
+ irb(main):032:0> Product.slug.options
32
+ => {:key=>true, :nullable=>false, :auto_validation=>false}
33
+ irb(main):004:0> Product.slug.nullable?
34
+ => false
35
+ irb(main):006:0> Product.slug.args_and_options
36
+ => [[], {}]
37
+ irb(main):007:0> Product.slug.blank?
38
+ => false
39
+ irb(main):008:0> Product.slug.present?
40
+ => true
41
+ irb(main):009:0> Product.slug.index
42
+ => false
43
+ irb(main):010:0> Product.slug.size
44
+ => 50
45
+ irb(main):011:0> Product.slug.primitive
46
+ => String
47
+ irb(main):012:0> Product.slug.unique
48
+ => true
49
+
50
+
51
+ irb(main):022:0> OrderItem.field_naming_convention
52
+ NameError: undefined local variable or method `args' for DataMapper:Module
53
+ irb(main):023:0> OrderItem.to_yaml_properties
54
+ => ["@_valid_relations", "@field_naming_conventions", "@properties", "@relationships", "@storage_names", "@validations"]
55
+ irb(main):024:0> OrderItem.eager_properties
56
+ => [#<Property:OrderItem:id>, #<Property:OrderItem:inverted>, #<Property:OrderItem:count>, #<Property:OrderItem:size>, #<Property:OrderItem:color>, #<Property:OrderItem:unit_price>, #<Property:OrderItem:product_slug>, #<Property:OrderItem:order_variable_symbol>, #<Property:OrderItem:color_id>, #<Property:OrderItem:size_height>, #<Property:OrderItem:size_width>]
57
+ irb(main):025:0> OrderItem.opts_from_validator_args
58
+ ArgumentError: wrong number of arguments (0 for 1)
59
+ irb(main):026:0> OrderItem.registered_as_hook?
60
+ ArgumentError: wrong number of arguments (0 for 2)
61
+ irb(main):027:0> OrderItem.first_or_create
62
+ ArgumentError: wrong number of arguments (0 for 1)
63
+ irb(main):028:0> OrderItem.property :count
64
+ ArgumentError: wrong number of arguments (1 for 2)
65
+ irb(main):029:0> OrderItem.hook_method_name
66
+ ArgumentError: wrong number of arguments (0 for 3)
67
+ irb(main):030:0> cattr_reader
68
+ NameError: undefined local variable or method `cattr_reader' for #<Object:0xb7d1894c>
69
+ irb(main):031:0> OrderItem.properties_with_subclasses
70
+ => #<PropertySet:{#<Property:OrderItem:id>,#<Property:OrderItem:inverted>,#<Property:OrderItem:count>,#<Property:OrderItem:size>,#<Property:OrderItem:color>,#<Property:OrderItem:unit_price>,#<Property:OrderItem:product_slug>,#<Property:OrderItem:order_variable_symbol>,#<Property:OrderItem:color_id>,#<Property:OrderItem:size_height>,#<Property:OrderItem:size_width>}>
71
+ irb(main):032:0> OrderItem.timestamps
72
+ ArgumentError: You need to pass at least one argument
73
+ irb(main):033:0> OrderItem.relationships
74
+ => {:product=>#<DataMapper::Associations::Relationship:0xb6cd62c8 @repository_name=:default, @parent_model=Product, @parent_properties=nil, @name=:product, @child_key=#<PropertySet:{#<Property:OrderItem:product_slug>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Product:slug>}>, @options={}, @query={}, @child_properties=nil>, :order=>#<DataMapper::Associations::Relationship:0xb6cd7268 @repository_name=:default, @parent_model=Order, @parent_properties=nil, @name=:order, @child_key=#<PropertySet:{#<Property:OrderItem:order_variable_symbol>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Order:variable_symbol>}>, @options={}, @query={}, @child_properties=nil>, :color=>#<DataMapper::Associations::Relationship:0xb6cd5350 @repository_name=:default, @parent_model=Color, @parent_properties=nil, @name=:color, @child_key=#<PropertySet:{#<Property:OrderItem:color_id>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Color:id>}>, @options={}, @query={}, @child_properties=nil>}
75
+ irb(main):034:0> OrderItem.name
76
+ => "OrderItem"
77
+ irb(main):035:0> OrderItem.validatable?
78
+ => false
79
+ irb(main):036:0> OrderItem.default_order
80
+ => [#<DataMapper::Query::Direction #<Property:OrderItem:id> asc>]
81
+ irb(main):037:0> OrderItem.class_variables
82
+ => []
83
+ irb(main):038:0> OrderItem.base_model
84
+ => OrderItem
85
+ irb(main):039:0> OrderItem.default_scope
86
+ => {}
87
+ irb(main):040:0> OrderItem.ancestors
88
+ => [OrderItem, DataMapper::Validate, DataMapper::Timestamp, #<Module:0xb6cdf0f8>, #<Module:0xb6ce00ac>, #<Module:0xb6ce0f98>, #<Module:0xb6ce1e48>, Extlib::Hook, DataMapper::Hook, DataMapper::Resource, DataMapper::Types, DataMapper::Resource::Transaction, DataMapper::Assertions, Object, Spec::Extensions::Main, Spec::Expectations::ObjectExpectations, DataMapper::Sweatshop::Unique, Base64::Deprecated, Base64, JSON::Ext::Generator::GeneratorMethods::Object, Kernel]
89
+ irb(main):041:0> OrderItem.generate_attributes
90
+ DataMapper::Sweatshop::NoFixtureExist: default fixture was not found for class OrderItem
91
+ irb(main):042:0> OrderItem.paranoid_properties
92
+ => {}
93
+ irb(main):043:0> OrderItem.make
94
+ DataMapper::Sweatshop::NoFixtureExist: default fixture was not found for class OrderItem
95
+ irb(main):044:0> OrderItem.to_yaml
96
+ TypeError: can't dump anonymous class Class
97
+ irb(main):045:0> OrderItem.chainable
98
+ => #<Module:0xb6fdd73c>
99
+ irb(main):046:0> OrderItem._valid_model
100
+ => nil
101
+ irb(main):047:0> OrderItem.properties
102
+ => #<PropertySet:{#<Property:OrderItem:id>,#<Property:OrderItem:inverted>,#<Property:OrderItem:count>,#<Property:OrderItem:size>,#<Property:OrderItem:color>,#<Property:OrderItem:unit_price>,#<Property:OrderItem:product_slug>,#<Property:OrderItem:order_variable_symbol>,#<Property:OrderItem:color_id>,#<Property:OrderItem:size_height>,#<Property:OrderItem:size_width>}>
103
+ irb(main):048:0> Order.tap
104
+ LocalJumpError: no block given
105
+ irb(main):049:0> Order.type
106
+ (irb):49: warning: Object#type is deprecated; use Object#class
107
+ => Class
108
+ irb(main):050:0> o = Order
109
+ => Order
110
+ irb(main):051:0> o.gen_attrs
111
+ NoMethodError: undefined method `new_record?' for "#ffff":String
112
+ from :0irb(main):052:0> o.validators
113
+ => #<DataMapper::Validate::ContextualValidators:0xb6fdd020 @contexts={:default=>[#<DataMapper::Validate::RequiredFieldValidator:0xb6fdd084 @if_clause=nil, @options={:message=>"Zákazník musí být vyplněn", :context=>:default}, @unless_clause=nil, @field_name=:customer>, #<DataMapper::Validate::WithinValidator:0xb6fd0eb0 @if_clause=nil, @options={:message=>nil, :context=>:default, :set=>[:paypal, :personally, :cod, :transfer]}, @unless_clause=nil, @field_name=:payment_type>, #<DataMapper::Validate::WithinValidator:0xb6fca6dc @if_clause=nil, @options={:message=>nil, :context=>:default, :set=>[:unprocessed, :processed]}, @unless_clause=nil, @field_name=:status>, #<DataMapper::Validate::PrimitiveValidator:0xb6fc6988 @if_clause=nil, @options={:message=>nil, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:created_at>, #<DataMapper::Validate::PrimitiveValidator:0xb6fbbac4 @if_clause=nil, @options={:message=>nil, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:updated_at>, #<DataMapper::Validate::LengthValidator:0xb6fb16a0 @range=nil, @if_clause=nil, @min=nil, @equal=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @validation_method=:max, @unless_clause=nil, @max=50, @field_name=:referer>, #<DataMapper::Validate::PrimitiveValidator:0xb6faddac @if_clause=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:referer>, #<DataMapper::Validate::LengthValidator:0xb6e66430 @range=nil, @if_clause=nil, @min=nil, @equal=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @validation_method=:max, @unless_clause=nil, @max=50, @field_name=:customer_email>, #<DataMapper::Validate::PrimitiveValidator:0xb6e6493c @if_clause=nil, @options={:message=>nil, :maximum=>50, :context=>:default, :allow_nil=>true}, @unless_clause=nil, @field_name=:customer_email>]}>
114
+ irb(main):053:0> o.options
115
+ => nil
116
+ irb(main):054:0> o.to_yaml_style
117
+ => nil
118
+ irb(main):055:0> o.subclass
119
+ ArgumentError: wrong number of arguments (0 for 1)
120
+ irb(main):056:0> o.present?
121
+ => true
122
+ irb(main):057:0> o.args_for
123
+ ArgumentError: wrong number of arguments (0 for 1)
124
+ irb(main):058:0> o.in?
125
+ ArgumentError: wrong number of arguments (0 for 1)
126
+ irb(main):059:0> o.to_query
127
+ ArgumentError: wrong number of arguments (0 for 2)
128
+ irb(main):060:0> o.orig_auto_generate_validations
129
+ ArgumentError: wrong number of arguments (0 for 1)
130
+ irb(main):061:0> o.many_to_one_relationships
131
+ => [#<DataMapper::Associations::Relationship:0xb6fd9d58 @repository_name=:default, @parent_model=Customer, @parent_properties=nil, @name=:customer, @child_key=#<PropertySet:{#<Property:Order:customer_email>}>, @child_model=Order, @parent_key=#<PropertySet:{#<Property:Customer:email>}>, @options={}, @query={}, @child_properties=nil>]
132
+ irb(main):062:0> o.unique
133
+ NoMethodError: undefined method `arity' for nil:NilClass
@@ -0,0 +1,23 @@
1
+ begin
2
+ require "rubygems/specification"
3
+ rescue SecurityError
4
+ # http://gems.github.com
5
+ end
6
+
7
+ VERSION = "0.9.10"
8
+ SPECIFICATION = ::Gem::Specification.new do |s|
9
+ s.name = "dm-spec"
10
+ # s.version = Rango::VERSION
11
+ s.version = VERSION
12
+ s.authors = ["Jakub Šťastný aka Botanicus"]
13
+ s.homepage = "http://github.com/botanicus/dm-spec"
14
+ s.summary = "Some rSpec matchers for DataMapper"
15
+ # s.description = "" # TODO: long description
16
+ s.cert_chain = nil
17
+ s.email = ["knava.bestvinensis", "gmail.com"].join("@")
18
+ s.files = Dir.glob("**/*") - Dir.glob("pkg/*")
19
+ s.add_dependency "dm-core"
20
+ s.require_paths = ["lib"]
21
+ # s.required_ruby_version = ::Gem::Requirement.new(">= 1.9.1")
22
+ # s.rubyforge_project = "rango"
23
+ end
@@ -0,0 +1,5 @@
1
+ require "spec/matchers/dm/has_property"
2
+ require "spec/matchers/dm/belongs_to"
3
+ require "spec/matchers/dm/has_many"
4
+ require "spec/matchers/dm/has_and_belongs_to_many"
5
+ require "spec/matchers/dm/has_timestamps"
@@ -0,0 +1,42 @@
1
+ # belongs to
2
+ # Product.relationships[:category]
3
+ #<DataMapper::Associations::Relationship @parent_model=Category, @name=:category, @child_key=#<PropertySet:{#<Property:Product:category_slug>}>, @child_model=Product, @parent_key=#<PropertySet:{#<Property:Category:slug>}>, @options={}>
4
+
5
+ module DataMapperMatchers
6
+ class BelongsTo
7
+ # args<Symbol>: :products
8
+ def initialize(name)
9
+ @name = name
10
+ end
11
+
12
+ # args<Model>: Category
13
+ def matches?(model)
14
+ @model = model
15
+ relationship = @model.relationships[@name]
16
+ return false unless relationship
17
+ relationship.name == @name && relationship.child_model == @model
18
+ end
19
+
20
+ def description
21
+ "belongs to"
22
+ end
23
+
24
+ def failure_message
25
+ belonging = @model.relationships.select { |name, relationship| relationship.name == @name && relationship.child_model == @model }
26
+ belonging.map! { |array| array.first }
27
+ if belonging.empty?
28
+ "expected to belongs to #@name, but does not belongs to any model"
29
+ else
30
+ "expected to belongs to #@name, but belongs to just the following relationships: #{belonging.inspect}"
31
+ end
32
+ end
33
+
34
+ def negative_failure_message
35
+ "expected not to belongs to #@name, but belonged"
36
+ end
37
+ end
38
+
39
+ def belongs_to(name)
40
+ BelongsTo.new(name)
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ # habtm
2
+ # Product.relationships[:colors]
3
+ #<DataMapper::Associations::RelationshipChain @parent_model=Product, @name=:color_products, @mutable=true, @child_key=#<PropertySet:{#<Property:ColorProduct:product_slug>}>, @child_model="Color", @parent_key=#<PropertySet:{#<Property:Product:slug>}>, @remote_relationship_name="colors", @options={:repository_name=>:default, :near_relationship_name=>:color_products, :parent_key=>nil, :child_key=>nil, :remote_relationship_name=>"colors", :child_model=>"Color", :min=>0, :parent_model=>Product, :max=>Infinity}, @near_relationship_name=:color_products>
4
+
5
+ module DataMapperMatchers
6
+ class HasAndBelongsToMany
7
+ # args<Symbol>: :products
8
+ def initialize(name)
9
+ @name = name
10
+ end
11
+
12
+ # args<Model>: Category
13
+ def matches?(model)
14
+ @model = model
15
+ relationship = @model.relationships[@name]
16
+ return false unless relationship
17
+ relationship.class == DataMapper::Associations::RelationshipChain && relationship.child_model == @model
18
+ end
19
+
20
+ def description
21
+ "has and belongs to many"
22
+ end
23
+
24
+ def failure_message
25
+ # TODO: filter just n:n relationships
26
+ relationships = @model.relationships.map { |name, relationship| relationship.name }.inspect
27
+ "expected to has and belongs to many #@name, but has just the following relationships: #{relationships}"
28
+ end
29
+
30
+ def negative_failure_message
31
+ "expected not to has and belongs to many #@name, but had"
32
+ end
33
+ end
34
+
35
+ def has_and_belongs_to_many(name)
36
+ HasAndBelongsToMany.new(name)
37
+ end
38
+ end
@@ -0,0 +1,48 @@
1
+ # has 1
2
+ # Product.relationships[:item]
3
+ #<DataMapper::Associations::Relationship @parent_model=Product, @name=:item, @child_key=#<PropertySet:{#<Property:OrderItem:product_slug>}>, @child_model=OrderItem, @parent_key=#<PropertySet:{#<Property:Product:slug>}>, @options={:min=>1, :class_name=>"OrderItem", :max=>1}>
4
+
5
+ # has n
6
+ # Category.relationships[:products]
7
+ #<DataMapper::Associations::Relationship @parent_model=Category, @name=:products, @child_key=#<PropertySet:{#<Property:Product:category_slug>}>, @child_model=Product, @parent_key=#<PropertySet:{#<Property:Category:slug>}>, @options={:min=>0, :max=>Infinity}>
8
+
9
+ module DataMapperMatchers
10
+ class HasMany
11
+ def initialize(name, options)
12
+ @name = name
13
+ @options = options
14
+ end
15
+
16
+ # args<Model>: Category
17
+ def matches?(model)
18
+ @model = model
19
+ relationship = @model.relationships[@name]
20
+ return false unless relationship
21
+ relationship.parent_model == @model && @options.all? { |key, value| relationship.options[key] == value }
22
+ end
23
+
24
+ def description
25
+ "has many"
26
+ end
27
+
28
+ def failure_message
29
+ # TODO: filter just has many relationships
30
+ properties = @model.properties.entries.map { |property| property.name }.inspect
31
+ "expected to has many #@name, but has just the following properties: #{properties}"
32
+ end
33
+
34
+ def negative_failure_message
35
+ "expected to not has many #@name, but had"
36
+ end
37
+ end
38
+
39
+ def has_many(name, options = Hash.new)
40
+ defaults = {:min => 0, :max => 1.0 / 0}
41
+ HasMany.new(name, defaults.merge(options))
42
+ end
43
+
44
+ def has_one(name, options = Hash.new)
45
+ defaults = {:min => 1, :max => 1}
46
+ HasMany.new(name, defaults.merge(options))
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ # Category.properties[:expected]
2
+ # => #<Property:Category:expected>
3
+ # Category.properties.has_property? :expected
4
+ # => true
5
+
6
+ module DataMapperMatchers
7
+ class HasProperty
8
+ def initialize(expected)
9
+ @expected = expected
10
+ end
11
+
12
+ # Category.should has_property(:id)
13
+ def matches?(model)
14
+ @model = model
15
+ return @model.properties.has_property?(@expected)
16
+ end
17
+
18
+ def description
19
+ "has property"
20
+ end
21
+
22
+ def failure_message
23
+ properties = @model.properties.entries.map { |property| property.name }
24
+ "expected to has property #@expected, but has just the following properties: #{properties}"
25
+ end
26
+
27
+ def negative_failure_message
28
+ "expected to not has property #@expected, but had"
29
+ end
30
+ end
31
+
32
+ def has_property(expected)
33
+ HasProperty.new(expected)
34
+ end
35
+ end
@@ -0,0 +1,55 @@
1
+ # Category.properties[:expected]
2
+ # => #<Timestamps:Category:expected>
3
+ # Category.properties.has_timestamps? :expected
4
+ # => true
5
+
6
+ module DataMapperMatchers
7
+ class HasTimestamps
8
+ def initialize(*expected)
9
+ # Post.should has_timestamps => :created_at, :updated_at
10
+ expected.push(:at) if expected.empty?
11
+ if [:at, :on].include?(expected.first)
12
+ # Post.should has_timestamps(:at)
13
+ @expected = ["created_#{expected}", "updated_#{expected}"]
14
+ else
15
+ # Post.should has_timestamps(:created_at)
16
+ @expected = expected
17
+ end
18
+ end
19
+
20
+ # Category.should has_timestamps(:id)
21
+ def matches?(model)
22
+ @model = model
23
+ loaded && included && has_timestamps
24
+ end
25
+
26
+ def loaded
27
+ $LOADED_FEATURES.any? { |file| File.basename(file).eql?("dm-timestamps.rb") }
28
+ end
29
+
30
+ def included
31
+ @model.respond_to?(:timestamps) # DataMapper::Timestamp model is included
32
+ end
33
+
34
+ def has_timestamps
35
+ @expected.all { |method| model.new.respond_to?(method) }
36
+ end
37
+
38
+ def description
39
+ "has timestamps"
40
+ end
41
+
42
+ def failure_message
43
+ properties = @model.properties.entries.map { |timestamps| timestamps.name }
44
+ "expected to has timestamps #@expected, but has just the following properties: #{properties}"
45
+ end
46
+
47
+ def negative_failure_message
48
+ "expected not to not timestamps #@expected, but had"
49
+ end
50
+ end
51
+
52
+ def has_timestamps(expected)
53
+ HasTimestamps.new(expected)
54
+ end
55
+ end
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), '..', "spec_helper")
2
+ require "spec/matchers/dm/belongs_to"
3
+
4
+ class Post
5
+ include DataMapper::Resource
6
+ property :id, Serial
7
+ belongs_to :category
8
+ end
9
+
10
+ class Category
11
+ include DataMapper::Resource
12
+ property :id, Serial
13
+ has n, :posts
14
+ end
15
+
16
+ describe DataMapperMatchers::BelongsTo do
17
+ it "should pass for working associations" do
18
+ lambda { Post.should belongs_to(:category) }.should_not fail
19
+ end
20
+
21
+ it "should fail for non existing working associations" do
22
+ lambda { Post.should_not belongs_to(:category) }.should fail_with("expected not to belongs to category, but belonged")
23
+ end
24
+
25
+ it "should fail for non existing working associations" do
26
+ lambda { Post.should belongs_to(:items) }.should fail_with("expected to belongs to items, but does not belongs to any model")
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), '..', "spec_helper")
2
+ require "spec/matchers/dm/has_and_belongs_to_many"
3
+
4
+ class Post
5
+ include DataMapper::Resource
6
+ property :id, Serial
7
+ has n, :tags, :through => Resource
8
+ end
9
+
10
+ class Tag
11
+ include DataMapper::Resource
12
+ property :id, Serial
13
+ has n, :posts, :through => Resource
14
+ end
15
+
16
+ describe DataMapperMatchers::BelongsTo do
17
+ it "should pass for working associations" do
18
+ Post.should has_and_belongs_to_many(:tags)
19
+ Tag.should has_and_belongs_to_many(:posts)
20
+ end
21
+
22
+ it "should fail for non existing working associations" do
23
+ lambda { Post.should_not has_and_belongs_to_many(:tags) }.should fail
24
+ end
25
+
26
+ it "should fail for non existing working associations" do
27
+ lambda { Post.should has_and_belongs_to_many(:items) }.should fail_with("expected to has and belongs to many items, but has just the following relationships: [:post_tags, :post_tags, :category]")
28
+ end
29
+ end
File without changes
File without changes
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), '..', "spec_helper")
2
+ require "spec/matchers/dm/has_timestamps"
3
+
4
+ class Post
5
+ include DataMapper::Resource
6
+ property :id, Serial
7
+ belongs_to :category
8
+ end
9
+
10
+ class Category
11
+ include DataMapper::Resource
12
+ property :id, Serial
13
+ has n, :posts
14
+ end
15
+
16
+ describe DataMapperMatchers::HasTimestamps do
17
+ it "should pass for working associations" do
18
+ Post.should belongs_to(:category)
19
+ end
20
+
21
+ it "should fail for non existing working associations" do
22
+ lambda { Post.should_not belongs_to(:category) }.should fail_with("expected not to belongs to category, but belonged")
23
+ end
24
+
25
+ it "should fail for non existing working associations" do
26
+ lambda { Post.should belongs_to(:items) }.should fail_with("expected to belongs to items, but has just the following relationships: [:post_tags, :post_tags, :category]")
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
@@ -0,0 +1,108 @@
1
+ $: << File.dirname(__FILE__) + "/../lib"
2
+ require "dm-core"
3
+
4
+ DataMapper.setup(:default, "sqlite3::memory")
5
+
6
+ # must be initialized for include
7
+ module DataMapperMatchers
8
+ end
9
+
10
+ Spec::Runner.configure do |config|
11
+ config.include(DataMapperMatchers)
12
+ config.before(:each) do
13
+ DataMapper.auto_migrate!
14
+ end
15
+ end
16
+
17
+ ##############
18
+ # from rspec #
19
+ ##############
20
+ module Spec
21
+ module Example
22
+ class NonStandardError < Exception; end
23
+ end
24
+
25
+ module Matchers
26
+ def fail
27
+ raise_error(Spec::Expectations::ExpectationNotMetError)
28
+ end
29
+
30
+ def fail_with(message)
31
+ raise_error(Spec::Expectations::ExpectationNotMetError, message)
32
+ end
33
+
34
+ def exception_from(&block)
35
+ exception = nil
36
+ begin
37
+ yield
38
+ rescue StandardError => e
39
+ exception = e
40
+ end
41
+ exception
42
+ end
43
+
44
+ def run_with(options)
45
+ ::Spec::Runner::CommandLine.run(options)
46
+ end
47
+
48
+ def with_ruby(version)
49
+ yield if RUBY_VERSION =~ Regexp.compile("^#{version.to_s}")
50
+ end
51
+ end
52
+ end
53
+
54
+ def with_sandboxed_options
55
+ attr_reader :options
56
+
57
+ before(:each) do
58
+ @original_rspec_options = ::Spec::Runner.options
59
+ ::Spec::Runner.use(@options = ::Spec::Runner::Options.new(StringIO.new, StringIO.new))
60
+ end
61
+
62
+ after(:each) do
63
+ ::Spec::Runner.use(@original_rspec_options)
64
+ end
65
+
66
+ yield
67
+ end
68
+
69
+ def with_sandboxed_config
70
+ attr_reader :config
71
+
72
+ before(:each) do
73
+ @config = ::Spec::Runner::Configuration.new
74
+ @original_configuration = ::Spec::Runner.configuration
75
+ spec_configuration = @config
76
+ ::Spec::Runner.instance_eval {@configuration = spec_configuration}
77
+ end
78
+
79
+ after(:each) do
80
+ original_configuration = @original_configuration
81
+ ::Spec::Runner.instance_eval {@configuration = original_configuration}
82
+ ::Spec::Example::ExampleGroupFactory.reset
83
+ end
84
+
85
+ yield
86
+ end
87
+
88
+ module Spec
89
+ module Example
90
+ module Resettable
91
+ def reset # :nodoc:
92
+ @before_all_parts = nil
93
+ @after_all_parts = nil
94
+ @before_each_parts = nil
95
+ @after_each_parts = nil
96
+ end
97
+ end
98
+ class ExampleGroup
99
+ extend Resettable
100
+ end
101
+ class ExampleGroupDouble < ExampleGroup
102
+ ::Spec::Runner.options.remove_example_group self
103
+ def register_example_group(klass)
104
+ #ignore
105
+ end
106
+ end
107
+ end
108
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-spec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.10
5
+ platform: ruby
6
+ authors:
7
+ - "Jakub \xC5\xA0\xC5\xA5astn\xC3\xBD aka Botanicus"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ date: 2009-11-26 00:00:00 +00:00
12
+ default_executable:
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: dm-core
16
+ type: :runtime
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ description:
25
+ email: knava.bestvinensis@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - dm-spec.gemspec
34
+ - lib/dm-spec.rb
35
+ - lib/spec/matchers/dm/belongs_to.rb
36
+ - lib/spec/matchers/dm/has_and_belongs_to_many.rb
37
+ - lib/spec/matchers/dm/has_many.rb
38
+ - lib/spec/matchers/dm/has_property.rb
39
+ - lib/spec/matchers/dm/has_timestamps.rb
40
+ - LICENSE
41
+ - Rakefile
42
+ - README.textile
43
+ - spec/dm/belongs_to_spec.rb
44
+ - spec/dm/has_and_belongs_to_many_spec.rb
45
+ - spec/dm/has_many_spec.rb
46
+ - spec/dm/has_property_spec.rb
47
+ - spec/dm/has_timestamps_spec.rb
48
+ - spec/spec.opts
49
+ - spec/spec_helper.rb
50
+ - TODO
51
+ has_rdoc: true
52
+ homepage: http://github.com/botanicus/dm-spec
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.5
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Some rSpec matchers for DataMapper
79
+ test_files: []
80
+