ianwhite-pickle 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +11 -0
- data/License.txt +20 -0
- data/README.textile +67 -0
- data/Todo.txt +5 -0
- data/lib/pickle/injector.rb +18 -0
- data/lib/pickle/parser.rb +82 -0
- data/lib/pickle/session.rb +106 -0
- data/lib/pickle/steps.rb +27 -0
- data/lib/pickle.rb +47 -0
- data/spec/lib/pickle_config_spec.rb +46 -0
- data/spec/lib/pickle_injector_spec.rb +22 -0
- data/spec/lib/pickle_parser_spec.rb +164 -0
- data/spec/lib/pickle_session_spec.rb +281 -0
- metadata +70 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Ian White - ian.w.white@ardes.com
|
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.
|
data/README.textile
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
h1. Pickle [Experimental: In development]
|
2
|
+
|
3
|
+
Stick this in vendor/plugins to have cucumber steps that create your models easily from factory_girl/machinist
|
4
|
+
|
5
|
+
References to the models are stored, not for the purpose of checking the db (although you could use it for
|
6
|
+
that), but for enabling easy reference to urls, and for building complex givens which require a bunch of
|
7
|
+
models collaborating
|
8
|
+
|
9
|
+
h2. Example
|
10
|
+
|
11
|
+
If you have a user model, which has admin? and moderator? predicate methods
|
12
|
+
and let's say you have an :admin, :user, and :moderator factory, you can do this in a Scenario:
|
13
|
+
|
14
|
+
And an admin exists
|
15
|
+
And a moderator exists
|
16
|
+
|
17
|
+
# the following is just to show how refs work, obviously you'd not want to test this
|
18
|
+
Then the moderator should be a moderator
|
19
|
+
And the admin should be an admin
|
20
|
+
And the moderator should not be an admin
|
21
|
+
|
22
|
+
h2. Usage
|
23
|
+
|
24
|
+
script/generate pickle
|
25
|
+
|
26
|
+
h2. API
|
27
|
+
|
28
|
+
h3. Regexps for us in your own steps
|
29
|
+
|
30
|
+
If you want to use pickle expressions in your own steps, make sure you
|
31
|
+
require pickle in that file
|
32
|
+
|
33
|
+
require 'pickle'
|
34
|
+
|
35
|
+
For matching english versions of model names you get
|
36
|
+
|
37
|
+
#match_model, #capture_model
|
38
|
+
|
39
|
+
Given /^#{capture_model} exists$/ do |model_name|
|
40
|
+
model(model_name).should_not == nil
|
41
|
+
end
|
42
|
+
|
43
|
+
Then /^I should be at the (.*?) page$/ |page|
|
44
|
+
if page =~ /#{match_model}'s/
|
45
|
+
url_for(model(page.sub("'s",''))
|
46
|
+
else
|
47
|
+
# ...
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
For matching a field string, you get
|
52
|
+
|
53
|
+
#match_fields, #capture_fields
|
54
|
+
|
55
|
+
Given /^#{capture_model} exists with #{capture_fields}$/ do |model_name, fields|
|
56
|
+
create_model(model_name, fields)
|
57
|
+
end
|
58
|
+
|
59
|
+
Take a look at features/step_definitions/pickle_steps.rb for more examples
|
60
|
+
|
61
|
+
h3. Creating and tracking models
|
62
|
+
|
63
|
+
#create_model(<model_name>[, <field string>])
|
64
|
+
|
65
|
+
#find_model(<model_name>[, <field string>])
|
66
|
+
|
67
|
+
#model(<model_model>) # refers to a model that has already been created/found (ie. referred to in a scenario)
|
data/Todo.txt
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pickle
|
2
|
+
module Injector
|
3
|
+
def self.inject(session, options = {})
|
4
|
+
target = options[:into] || ActionController::Integration::Session
|
5
|
+
session_name = session.name.underscore.gsub('/','_')
|
6
|
+
|
7
|
+
target.class_eval <<-end_eval, __FILE__, __LINE__
|
8
|
+
def #{session_name}
|
9
|
+
@#{session_name} ||= #{session.name}.new
|
10
|
+
end
|
11
|
+
end_eval
|
12
|
+
|
13
|
+
delegate_methods = session.instance_methods - Object.instance_methods
|
14
|
+
delegate_methods << {:to => session_name}
|
15
|
+
target.delegate *delegate_methods
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Pickle
|
2
|
+
module Parser
|
3
|
+
module Match
|
4
|
+
Ordinal = '(?:\d+(?:st|nd|rd|th))'
|
5
|
+
Index = "(?:first|last|#{Ordinal})"
|
6
|
+
Prefix = '(?:1 |a |an |another |the |that )'
|
7
|
+
Quoted = '(?:[^\\"]|\\.)*'
|
8
|
+
Name = '(?::? "' + Quoted + '")'
|
9
|
+
|
10
|
+
# model matching - depends on Parse::Config, so load before this if non standard config requried
|
11
|
+
ModelMapping = "(?:#{Pickle::Config.mappings.map(&:first).map{|s| "(?:#{s})"}.join('|')})"
|
12
|
+
ModelName = "(?:#{Pickle::Config.names.map{|n| n.to_s.gsub('_','[_ ]').gsub('/','[:\/ ]')}.join('|')})"
|
13
|
+
IndexedModel = "(?:(?:#{Index} )?#{ModelName})"
|
14
|
+
NamedModel = "(?:#{ModelName}#{Name}?)"
|
15
|
+
Model = "(?:#{ModelMapping}|#{Prefix}?(?:#{IndexedModel}|#{NamedModel}))"
|
16
|
+
Field = '(?:\w+: (?:' + Model + '|"' + Quoted + '"))'
|
17
|
+
Fields = "(?:#{Field}, )*#{Field}"
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
# these are expressions which capture a sub expression
|
22
|
+
module Capture
|
23
|
+
Ordinal = '(?:(\d+)(?:st|nd|rd|th))'
|
24
|
+
Name = '(?::? "(' + Match::Quoted + ')")'
|
25
|
+
Field = '(?:(\w+): "(' + Match::Quoted + ')")'
|
26
|
+
end
|
27
|
+
|
28
|
+
# given a string like 'foo: "bar", bar: "baz"' returns {"foo" => "bar", "bar" => "baz"}
|
29
|
+
def parse_fields(fields)
|
30
|
+
if fields.blank?
|
31
|
+
{}
|
32
|
+
elsif fields =~ /^#{Match::Fields}$/
|
33
|
+
fields.scan(/(#{Match::Field})(?:,|$)/).inject({}) do |m, match|
|
34
|
+
m.merge(parse_field(match[0]))
|
35
|
+
end
|
36
|
+
else
|
37
|
+
raise ArgumentError, "The fields string is not in the correct format.\n\n'#{fields}' did not match: #{Match::Fields}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# given a string like 'foo: "bar"' returns {key => value}
|
42
|
+
def parse_field(field)
|
43
|
+
if field =~ /^#{Capture::Field}$/
|
44
|
+
{ $1 => $2 }
|
45
|
+
else
|
46
|
+
raise ArgumentError, "The field argument is not in the correct format.\n\n'#{field}' did not match: #{Match::Field}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# returns really underscored name
|
51
|
+
def canonical(str)
|
52
|
+
str.to_s.gsub(' ','_').underscore
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_index(index)
|
56
|
+
case index
|
57
|
+
when '', /last/ then -1
|
58
|
+
when /#{Capture::Ordinal}/ then $1.to_i - 1
|
59
|
+
when /first/ then 0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
# return [factory, name or integer index]
|
65
|
+
def parse_model(name)
|
66
|
+
apply_mappings!(name)
|
67
|
+
if /(#{Match::ModelName})#{Capture::Name}$/ =~ name
|
68
|
+
[canonical($1), canonical($2)]
|
69
|
+
elsif /(#{Match::Index}) (#{Match::ModelName})$/ =~ name
|
70
|
+
[canonical($2), parse_index($1)]
|
71
|
+
else
|
72
|
+
/(#{Match::ModelName})#{Capture::Name}?$/ =~ name && [canonical($1), canonical($2)]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def apply_mappings!(string)
|
77
|
+
Pickle::Config.mappings.each do |(search, replace)|
|
78
|
+
string.sub! /^(?:#{search})$/, replace
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Pickle
|
2
|
+
class Session
|
3
|
+
include Parser
|
4
|
+
|
5
|
+
def create_model(a_model_name, fields = nil)
|
6
|
+
factory, name = *parse_model(a_model_name)
|
7
|
+
raise ArgumentError, "Can't create a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
|
8
|
+
record = Factory(factory, parse_fields(fields))
|
9
|
+
store_model(factory, name, record)
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_model(a_model_name, fields)
|
13
|
+
model, name = *parse_model(a_model_name)
|
14
|
+
raise ArgumentError, "Can't find a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
|
15
|
+
model_class = model.classify.constantize
|
16
|
+
if record = model_class.find(:first, :conditions => convert_models_to_attributes(model_class, parse_fields(fields)))
|
17
|
+
store_model(model, name, record)
|
18
|
+
else
|
19
|
+
raise ActiveRecord::RecordNotFound, "Couldn't find #{model} with #{fields}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# return the original model stored by create_model or find_model
|
24
|
+
def original_model(a_model_name)
|
25
|
+
factory, name_or_index = *parse_model(a_model_name)
|
26
|
+
|
27
|
+
if name_or_index.blank?
|
28
|
+
models_by_factory(factory).last
|
29
|
+
elsif name_or_index.is_a?(Integer)
|
30
|
+
models_by_factory(factory)[name_or_index]
|
31
|
+
else
|
32
|
+
models_by_name(factory)[name_or_index] or raise "model: #{a_model_name} does not refer to known model in this scenario"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# predicate version which raises no errors
|
37
|
+
def original_model?(a_model_name)
|
38
|
+
(original_model(a_model_name) rescue nil) ? true : false
|
39
|
+
end
|
40
|
+
|
41
|
+
# return a newly selected model
|
42
|
+
def model(a_model_name)
|
43
|
+
if model = original_model(a_model_name)
|
44
|
+
model.class.find(model.id) or raise ActiveRecord::RecordNotFound, "model: #{a_model_name} could not be found in the database"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# predicate version which raises no errors
|
49
|
+
def model?(a_model_name)
|
50
|
+
(model(a_model_name) rescue nil) ? true : false
|
51
|
+
end
|
52
|
+
|
53
|
+
# return all original models of specified type
|
54
|
+
def original_models(factory)
|
55
|
+
models_by_factory(factory)
|
56
|
+
end
|
57
|
+
|
58
|
+
# return all models of specified type (freshly selected from the database)
|
59
|
+
def models(factory)
|
60
|
+
original_models(factory).map do |model|
|
61
|
+
model.class.find(model.id)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_field_with_model(field)
|
66
|
+
if field =~ /^(\w+): (#{Match::Model})$/
|
67
|
+
{$1 => model($2)}
|
68
|
+
else
|
69
|
+
parse_field_without_model(field)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
alias_method_chain :parse_field, :model
|
73
|
+
|
74
|
+
private
|
75
|
+
def convert_models_to_attributes(ar_class, attrs)
|
76
|
+
attrs.each do |key, val|
|
77
|
+
if val.is_a?(ActiveRecord::Base) && ar_class.column_names.include?("#{key}_id")
|
78
|
+
attrs["#{key}_id"] = val.id
|
79
|
+
attrs["#{key}_type"] = val.class.name if ar_class.column_names.include?("#{key}_type")
|
80
|
+
attrs.delete(key)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def models_by_name(factory)
|
86
|
+
@models_by_name ||= {}
|
87
|
+
@models_by_name[factory] ||= {}
|
88
|
+
end
|
89
|
+
|
90
|
+
def models_by_factory(factory)
|
91
|
+
@models_by_factory ||= {}
|
92
|
+
@models_by_factory[factory] ||= []
|
93
|
+
end
|
94
|
+
|
95
|
+
# if the factory name != the model name, store under both names
|
96
|
+
def store_model(factory, name, record)
|
97
|
+
store_record(canonical(record.class.name), name, record) if canonical(record.class.name) != factory
|
98
|
+
store_record(factory, name, record)
|
99
|
+
end
|
100
|
+
|
101
|
+
def store_record(factory, name, record)
|
102
|
+
models_by_name(factory)[name] = record
|
103
|
+
models_by_factory(factory) << record
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/pickle/steps.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# inject the pickle session into integration session
|
2
|
+
Pickle::Injector.inject Pickle::Session, :into => ActionController::Integration::Session
|
3
|
+
|
4
|
+
# make some Regexp shortcuts for use in steps
|
5
|
+
MatchModel = Pickle::Parser::Match::Model
|
6
|
+
MatchFields = Pickle::Parser::Match::Fields
|
7
|
+
|
8
|
+
# start with some obvious steps
|
9
|
+
Given(/^(#{MatchModel}) exists$/) do |name|
|
10
|
+
create_model(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
Given(/^(#{MatchModel}) exists with (#{MatchFields})$/) do |name, fields|
|
14
|
+
create_model(name, fields)
|
15
|
+
end
|
16
|
+
|
17
|
+
Then(/^(#{MatchModel}) should exist with (#{MatchFields})$/) do |name, fields|
|
18
|
+
find_model(name, fields).should_not == nil
|
19
|
+
end
|
20
|
+
|
21
|
+
Then(/^(#{MatchModel}) should be (?:an? )?"(.*?)"$/) do |name, predicate|
|
22
|
+
model(name).should send("be_#{predicate.gsub(' ','_')}")
|
23
|
+
end
|
24
|
+
|
25
|
+
Then(/^(#{MatchModel}) should not be (?:an? )?"(.*?)"$/) do |name, predicate|
|
26
|
+
model(name).should_not send("be_#{predicate.gsub(' ','_')}")
|
27
|
+
end
|
data/lib/pickle.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Pickle == cucumber + factory
|
2
|
+
#
|
3
|
+
# = Usage
|
4
|
+
# # in features/steps/_env.rb
|
5
|
+
# require 'pickle/steps'
|
6
|
+
#
|
7
|
+
# If you need to configure pickle, do it like this
|
8
|
+
#
|
9
|
+
# Pickle::Config.map 'I|me|my', :to => 'user: "me"'
|
10
|
+
# require 'pickle/steps'
|
11
|
+
module Pickle
|
12
|
+
module Version
|
13
|
+
Major = 0
|
14
|
+
Minor = 1
|
15
|
+
Tiny = 1
|
16
|
+
|
17
|
+
String = [Major, Minor, Tiny].join('.')
|
18
|
+
end
|
19
|
+
|
20
|
+
module Config
|
21
|
+
class << self
|
22
|
+
attr_writer :model_names, :factory_names, :names, :mappings
|
23
|
+
|
24
|
+
def model_names
|
25
|
+
@model_names ||= Dir["#{RAILS_ROOT}/app/models/**/*.rb"].reject{|f| f =~ /observer.rb$/}.map{|f| f.sub("#{RAILS_ROOT}/app/models/",'').sub(".rb",'')}
|
26
|
+
end
|
27
|
+
|
28
|
+
def factory_names
|
29
|
+
require 'factory_girl'
|
30
|
+
@factory_names ||= Factory.factories.keys.map(&:to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def names
|
34
|
+
@names ||= (model_names | factory_names)
|
35
|
+
end
|
36
|
+
|
37
|
+
def mappings
|
38
|
+
@mappings ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
def map(search, options)
|
42
|
+
raise ArgumentError, "Usage: map 'search', :to => 'replace'" unless search.is_a?(String) && options[:to].is_a?(String)
|
43
|
+
self.mappings << [search, options[:to]]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Config do
|
4
|
+
before do
|
5
|
+
# zero pickle config before each example
|
6
|
+
[:names, :model_names, :factory_names, :mappings].each do |config_var|
|
7
|
+
instance_variable_set "@orig_#{config_var}", Pickle::Config.send(config_var)
|
8
|
+
Pickle::Config.send("#{config_var}=", nil)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
# restore pickle config back after each example
|
14
|
+
[:model_names, :factory_names, :names, :mappings].each do |config_var|
|
15
|
+
Pickle::Config.send "#{config_var}=", instance_variable_get("@orig_#{config_var}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it ":factory_names should default to stringified keys of Factory.factories" do
|
20
|
+
Factory.factories.should_receive(:keys).and_return([:one, :two])
|
21
|
+
Pickle::Config.factory_names.should == ['one', 'two']
|
22
|
+
end
|
23
|
+
|
24
|
+
it ":model_names should default to directory listing of app/models excluding observers" do
|
25
|
+
models_path = "#{RAILS_ROOT}/app/models"
|
26
|
+
Dir.should_receive(:[]).with("#{models_path}/**/*.rb").and_return([
|
27
|
+
"#{models_path}/one.rb",
|
28
|
+
"#{models_path}/one/a.rb",
|
29
|
+
"#{models_path}/one/b.rb",
|
30
|
+
"#{models_path}/one/b/i.rb",
|
31
|
+
"#{models_path}/one_observer.rb",
|
32
|
+
"#{models_path}/two.rb"
|
33
|
+
])
|
34
|
+
Pickle::Config.model_names.should == ['one', 'one/a', 'one/b', 'one/b/i', 'two']
|
35
|
+
end
|
36
|
+
|
37
|
+
it ":names should default to set (Array) :factory and :model names" do
|
38
|
+
Pickle::Config.factory_names = ['one', 'two']
|
39
|
+
Pickle::Config.model_names = ['two', 'one/a', 'one/b']
|
40
|
+
Pickle::Config.names.sort.should == ['one', 'one/a', 'one/b', 'two']
|
41
|
+
end
|
42
|
+
|
43
|
+
it ":mappings should default to []" do
|
44
|
+
Pickle::Config.mappings.should == []
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Injector do
|
4
|
+
describe ".inject Pickle::Session, :into => <a class>" do
|
5
|
+
before do
|
6
|
+
@class = Class.new
|
7
|
+
Pickle::Injector.inject Pickle::Session, :into => @class
|
8
|
+
@object = @class.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "object should respond_to Pickle:Session methods" do
|
12
|
+
@object.should respond_to(:model)
|
13
|
+
@object.should respond_to(:create_model)
|
14
|
+
@object.should respond_to(:find_model)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "object.model (a pickle method) should call object.pickle_session.model" do
|
18
|
+
@object.pickle_session.should_receive(:model).with('a user')
|
19
|
+
@object.model('a user')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Parser do
|
4
|
+
include Pickle::Parser
|
5
|
+
|
6
|
+
describe "Match atoms" do
|
7
|
+
def self.atom_should_match(atom, strings)
|
8
|
+
Array(strings).each do |string|
|
9
|
+
it "#{atom} should match '#{string}'" do
|
10
|
+
string.should match(/^#{eval "Pickle::Parser::#{atom}"}$/)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.atom_should_not_match(atom, strings)
|
16
|
+
Array(strings).each do |string|
|
17
|
+
it "#{atom} should NOT match '#{string}'" do
|
18
|
+
string.should_not match(/^#{eval "Pickle::Parser::#{atom}"}$/)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
atom_should_match 'Match::Ordinal', ['1st', '2nd', '23rd', '104th']
|
24
|
+
atom_should_not_match 'Match::Ordinal', ['1', '2']
|
25
|
+
|
26
|
+
atom_should_match 'Match::Index', ['first', 'last', '23rd', '104th']
|
27
|
+
atom_should_not_match 'Match::Index', ['1', '2', 'foo']
|
28
|
+
|
29
|
+
atom_should_match 'Match::Name', [': "gday"', ': "gday mate"']
|
30
|
+
atom_should_not_match 'Match::Name', [': "gday""', ': gday']
|
31
|
+
|
32
|
+
atom_should_match 'Match::Field', ['foo: "this is the life"', 'bar_man: "and so is this"']
|
33
|
+
atom_should_not_match 'Match::Field', ['foo bar: "this aint workin"']
|
34
|
+
|
35
|
+
atom_should_match 'Match::Fields', ['foo: "bar"', 'foo: "bar", baz: "bah"']
|
36
|
+
atom_should_not_match 'Match::Fields', ['foo bar: "baz"', 'email: "a", password: "b", and password_confirmation: "c"']
|
37
|
+
|
38
|
+
atom_should_match 'Match::Model', ['a user', '1st fast car', 'the 23rd fast_car', 'an event:create', 'the 2nd event/create', 'that event create: "zing"']
|
39
|
+
atom_should_not_match 'Match::Model', ['a giraffe', 'a 1st faster car: "jim"', 'an event created']
|
40
|
+
|
41
|
+
atom_should_match 'Match::ModelName', ['user', 'fast car', 'fast_car', 'event:create', 'event/create', 'event create']
|
42
|
+
atom_should_not_match 'Match::ModelName', ['users', 'faster car', 'event created']
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'misc regexps' do
|
46
|
+
describe '/^(#{Pickle::Parser::Match::Model}) exists/' do
|
47
|
+
before do
|
48
|
+
@regexp = /^(#{Pickle::Parser::Match::Model}) exists$/
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should match 'a user exists'" do
|
52
|
+
'a user exists'.should match(@regexp)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should caputure 'a user' from 'a user exists'" do
|
56
|
+
'a user exists'.match(@regexp)[1].should == 'a user'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#parse_field' do
|
62
|
+
it "should return {'a' => 'b'} for 'a: \"b\"'" do
|
63
|
+
parse_field('a: "b"').should == {'a' => 'b'}
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should raise error for invalid field 'a : b'" do
|
67
|
+
lambda { parse_field('a : b') }.should raise_error(ArgumentError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#parse_fields' do
|
72
|
+
it 'should return {} for blank argument' do
|
73
|
+
parse_fields(nil).should == {}
|
74
|
+
parse_fields('').should == {}
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should raise error for invalid argument' do
|
78
|
+
lambda { parse_fields('foo foo') }.should raise_error(ArgumentError)
|
79
|
+
end
|
80
|
+
|
81
|
+
it '(\'foo: "bar"\') should == { "foo" => "bar"}' do
|
82
|
+
parse_fields('foo: "bar"').should == { "foo" => "bar"}
|
83
|
+
end
|
84
|
+
|
85
|
+
it '(\'foo: "bar", bar_man: "wonga wonga", gump: "123"\') should == {"foo" => "bar", "bar_man" => "wonga wonga", "gump" => "123"}' do
|
86
|
+
parse_fields('foo: "bar", bar_man: "wonga wonga", gump: "123"').should == {"foo" => "bar", "bar_man" => "wonga wonga", "gump" => "123"}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#parse_model' do
|
91
|
+
it '("a user") should == ["user", ""]' do
|
92
|
+
parse_model("a user").should == ["user", ""]
|
93
|
+
end
|
94
|
+
|
95
|
+
it '("the user") should == ["user", ""]' do
|
96
|
+
parse_model("the user").should == ["user", ""]
|
97
|
+
end
|
98
|
+
|
99
|
+
it '("1 fast car") should == ["fast_car", ""]' do
|
100
|
+
parse_model("1 fast car").should == ["fast_car", ""]
|
101
|
+
end
|
102
|
+
|
103
|
+
it '(\'an user: "jim jones"\') should == ["user", "jim_jones"]' do
|
104
|
+
parse_model('an user: "jim jones"').should == ["user", "jim_jones"]
|
105
|
+
end
|
106
|
+
|
107
|
+
it '(\'that fast car: "herbie"\') should == ["fast_car", "herbie"]' do
|
108
|
+
parse_model('that fast car: "herbie"').should == ["fast_car", "herbie"]
|
109
|
+
end
|
110
|
+
|
111
|
+
it '(\'the 12th user\') should == ["user", 11]' do
|
112
|
+
parse_model('the 12th user').should == ["user", 11]
|
113
|
+
end
|
114
|
+
|
115
|
+
it '(\'the last user\') should == ["user", -1]' do
|
116
|
+
parse_model('the last user').should == ["user", -1]
|
117
|
+
end
|
118
|
+
|
119
|
+
it '("the first user") should == ["user", 0]' do
|
120
|
+
parse_model('the first user').should == ["user", 0]
|
121
|
+
end
|
122
|
+
|
123
|
+
it '("the 1st user") should == ["user", 0]' do
|
124
|
+
parse_model('the 1st user').should == ["user", 0]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#parse_index" do
|
129
|
+
it '("1st") should == 0' do
|
130
|
+
parse_index("1st").should == 0
|
131
|
+
end
|
132
|
+
|
133
|
+
it '("24th") should == 23' do
|
134
|
+
parse_index("24th").should == 23
|
135
|
+
end
|
136
|
+
it '("first") should == 0' do
|
137
|
+
parse_index("first").should == 0
|
138
|
+
end
|
139
|
+
|
140
|
+
it '("last") should == -1' do
|
141
|
+
parse_index("last").should == -1
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "customised mappings" do
|
146
|
+
describe 'Pickle::Config.map "I|myself", :to => \'user: "me"\'' do
|
147
|
+
it "'I' should match /\#{Pickle::Parser::Match::Model}/" do
|
148
|
+
'I'.should match(/#{Pickle::Parser::Match::Model}/)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "'myself' should match /\#{Pickle::Parser::Match::Model}/" do
|
152
|
+
'myself'.should match(/#{Pickle::Parser::Match::Model}/)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "parse_the_model_name('I') should == ['user', 'me']" do
|
156
|
+
parse_model('I').should == ["user", "me"]
|
157
|
+
end
|
158
|
+
|
159
|
+
it "parse_the_model_name('myself') should == ['user', 'me']" do
|
160
|
+
parse_model('I').should == ["user", "me"]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
|
2
|
+
|
3
|
+
describe Pickle::Session do
|
4
|
+
before do
|
5
|
+
@session = Pickle::Session.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "after storing a single user", :shared => true do
|
9
|
+
it "original_models('user') should be array containing the original user" do
|
10
|
+
@session.original_models('user').should == [@user]
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "the original user should be retrievable with" do
|
14
|
+
it "original_model('the user')" do
|
15
|
+
@session.original_model('the user').should == @user
|
16
|
+
end
|
17
|
+
|
18
|
+
it "original_model('1st user')" do
|
19
|
+
@session.original_model('1st user').should == @user
|
20
|
+
end
|
21
|
+
|
22
|
+
it "original_model('last user')" do
|
23
|
+
@session.original_model('last user').should == @user
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "(found from db)" do
|
28
|
+
before do
|
29
|
+
@user.stub!(:id).and_return(100)
|
30
|
+
@user.class.should_receive(:find).with(100).and_return(@user_from_db = @user.dup)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "models('user') should be array containing user" do
|
34
|
+
@session.models('user').should == [@user_from_db]
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "user should be retrievable with" do
|
38
|
+
it "model('the user')" do
|
39
|
+
@session.model('the user').should == @user_from_db
|
40
|
+
end
|
41
|
+
|
42
|
+
it "model('1st user')" do
|
43
|
+
@session.model('1st user').should == @user_from_db
|
44
|
+
end
|
45
|
+
|
46
|
+
it "model('last user')" do
|
47
|
+
@session.model('last user').should == @user_from_db
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#create_model" do
|
54
|
+
before do
|
55
|
+
@user = mock_model(User)
|
56
|
+
Factory.stub!(:create).and_return(@user)
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "('a user')" do
|
60
|
+
def do_create_model
|
61
|
+
@session.create_model('a user')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should call Factory.create('user', {})" do
|
65
|
+
Factory.should_receive(:create).with('user', {}).and_return(@user)
|
66
|
+
do_create_model
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "after create," do
|
70
|
+
before { do_create_model }
|
71
|
+
|
72
|
+
it_should_behave_like "after storing a single user"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "('1 user', 'foo: \"bar\", baz: \"bing bong\"')" do
|
77
|
+
def do_create_model
|
78
|
+
@session.create_model('1 user', 'foo: "bar", baz: "bing bong"')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should call Factory.create('user', {'foo' => 'bar', 'baz' => 'bing bong'})" do
|
82
|
+
Factory.should_receive(:create).with('user', {'foo' => 'bar', 'baz' => 'bing bong'}).and_return(@user)
|
83
|
+
do_create_model
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "after create," do
|
87
|
+
before { do_create_model }
|
88
|
+
|
89
|
+
it_should_behave_like "after storing a single user"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "('an user: \"fred\")" do
|
94
|
+
def do_create_model
|
95
|
+
@session.create_model('an user: "fred"')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should call Factory.create('user', {})" do
|
99
|
+
Factory.should_receive(:create).with('user', {}).and_return(@user)
|
100
|
+
do_create_model
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "after create," do
|
104
|
+
before { do_create_model }
|
105
|
+
|
106
|
+
it_should_behave_like "after storing a single user"
|
107
|
+
|
108
|
+
it "original_model('the user: \"fred\"') should retrieve the user" do
|
109
|
+
@session.original_model('the user: "fred"').should == @user
|
110
|
+
end
|
111
|
+
|
112
|
+
it "original_model?('the user: \"shirl\"') should be false" do
|
113
|
+
@session.original_model?('the user: "shirl"').should == false
|
114
|
+
end
|
115
|
+
|
116
|
+
it "model?('the user: \"shirl\"') should be false" do
|
117
|
+
@session.model?('the user: "shirl"').should == false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#find_model' do
|
124
|
+
before do
|
125
|
+
@user = mock_model(User)
|
126
|
+
User.stub!(:find).and_return(@user)
|
127
|
+
end
|
128
|
+
|
129
|
+
def do_find_model
|
130
|
+
@session.find_model('a user', 'hair: "pink"')
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should call User.find :first, :conditions => {'hair' => 'pink'}" do
|
134
|
+
User.should_receive(:find).with(:first, :conditions => {'hair' => 'pink'}).and_return(@user)
|
135
|
+
do_find_model
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should raise RecordNotFound when no record returned" do
|
139
|
+
User.should_receive(:find).and_return(nil)
|
140
|
+
lambda { do_find_model }.should raise_error(ActiveRecord::RecordNotFound)
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "after find," do
|
144
|
+
before { do_find_model }
|
145
|
+
|
146
|
+
it_should_behave_like "after storing a single user"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe 'creating \'a super admin: "fred"\', then \'a user: "shirl"\', \'then 1 super_admin\'' do
|
151
|
+
before do
|
152
|
+
@user = @fred = mock_model(User)
|
153
|
+
@shirl = mock_model(User)
|
154
|
+
@noname = mock_model(User)
|
155
|
+
Factory.stub!(:create).and_return(@fred, @shirl, @noname)
|
156
|
+
end
|
157
|
+
|
158
|
+
def do_create_users
|
159
|
+
@session.create_model('a super admin: "fred"')
|
160
|
+
@session.create_model('a user: "shirl"')
|
161
|
+
@session.create_model('1 super_admin')
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should call Factory.create with <'super_admin'>, <'user'>, <'super_admin'>" do
|
165
|
+
Factory.should_receive(:create).with('super_admin', {}).twice
|
166
|
+
Factory.should_receive(:create).with('user', {}).once
|
167
|
+
do_create_users
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "after create," do
|
171
|
+
before do
|
172
|
+
do_create_users
|
173
|
+
end
|
174
|
+
|
175
|
+
it "original_models('user') should == [@fred, @shirl, @noname]" do
|
176
|
+
@session.original_models('user').should == [@fred, @shirl, @noname]
|
177
|
+
end
|
178
|
+
|
179
|
+
it "original_models('super_admin') should == [@fred, @noname]" do
|
180
|
+
@session.original_models('super_admin').should == [@fred, @noname]
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "#original_model" do
|
184
|
+
it "'that user' should be @noname (the last user created - as super_admins are users)" do
|
185
|
+
@session.original_model('that user').should == @noname
|
186
|
+
end
|
187
|
+
|
188
|
+
it "'the super admin' should be @noname (the last super admin created)" do
|
189
|
+
@session.original_model('that super admin').should == @noname
|
190
|
+
end
|
191
|
+
|
192
|
+
it "'the 1st super admin' should be @fred" do
|
193
|
+
@session.original_model('the 1st super admin').should == @fred
|
194
|
+
end
|
195
|
+
|
196
|
+
it "'the first user' should be @fred" do
|
197
|
+
@session.original_model('the first user').should == @fred
|
198
|
+
end
|
199
|
+
|
200
|
+
it "'the 2nd user' should be @shirl" do
|
201
|
+
@session.original_model('the 2nd user').should == @shirl
|
202
|
+
end
|
203
|
+
|
204
|
+
it "'the last user' should be @noname" do
|
205
|
+
@session.original_model('the last user').should == @noname
|
206
|
+
end
|
207
|
+
|
208
|
+
it "'the user: \"fred\" should be @fred" do
|
209
|
+
@session.original_model('the user: "fred"').should == @fred
|
210
|
+
end
|
211
|
+
|
212
|
+
it "'the user: \"shirl\" should be @shirl" do
|
213
|
+
@session.original_model('the user: "shirl"').should == @shirl
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "when 'the user: \"me\"' exists (and there is a mapping from 'I|myself' => 'user: \"me\")" do
|
220
|
+
before do
|
221
|
+
@user = mock_model(User)
|
222
|
+
User.stub!(:find).and_return(@user)
|
223
|
+
Factory.stub!(:create).and_return(@user)
|
224
|
+
@session.create_model('the user: "me"')
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'model("I") should return the user' do
|
228
|
+
@session.model('I').should == @user
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'model("myself") should return the user' do
|
232
|
+
@session.model('myself').should == @user
|
233
|
+
end
|
234
|
+
|
235
|
+
it "#parse_fields 'author: user \"JIM\"' should raise Error, as model deos not refer" do
|
236
|
+
lambda { @session.parse_fields('author: user "JIM"') }.should raise_error
|
237
|
+
end
|
238
|
+
|
239
|
+
it "#parse_fields 'author: the user' should return {\"author\" => <user>}" do
|
240
|
+
@session.parse_fields('author: the user').should == {"author" => @user}
|
241
|
+
end
|
242
|
+
|
243
|
+
it "#parse_fields 'author: myself' should return {\"author\" => <user>}" do
|
244
|
+
@session.parse_fields('author: myself').should == {"author" => @user}
|
245
|
+
end
|
246
|
+
|
247
|
+
it "#parse_fields 'author: the user, approver: I, rating: \"5\"' should return {'author' => <user>, 'approver' => <user>, 'rating' => '5'}" do
|
248
|
+
@session.parse_fields('author: the user, approver: I, rating: "5"').should == {'author' => @user, 'approver' => @user, 'rating' => '5'}
|
249
|
+
end
|
250
|
+
|
251
|
+
it "#parse_fields 'author: user: \"me\", approver: \"\"' should return {'author' => <user>, 'approver' => \"\"}" do
|
252
|
+
@session.parse_fields('author: user: "me", approver: ""').should == {'author' => @user, 'approver' => ""}
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "convert_models_to_attributes(ar_class, :user => <a user>)" do
|
257
|
+
before do
|
258
|
+
@user = mock_model(User)
|
259
|
+
end
|
260
|
+
|
261
|
+
describe "(when ar_class has column 'user_id')" do
|
262
|
+
before do
|
263
|
+
@ar_class = mock('ActiveRecord', :column_names => ['user_id'])
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should return {'user_id' => <the user.id>}" do
|
267
|
+
@session.send(:convert_models_to_attributes, @ar_class, :user => @user).should == {'user_id' => @user.id}
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "(when ar_class has columns 'user_id', 'user_type')" do
|
272
|
+
before do
|
273
|
+
@ar_class = mock('ActiveRecord', :column_names => ['user_id', 'user_type'])
|
274
|
+
end
|
275
|
+
|
276
|
+
it "should return {'user_id' => <the user.id>, 'user_type' => <the user.type>}" do
|
277
|
+
@session.send(:convert_models_to_attributes, @ar_class, :user => @user).should == {'user_id' => @user.id, 'user_type' => @user.class.name}
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ianwhite-pickle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ian White
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-27 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Easy model creation and reference in your cucumber features
|
17
|
+
email: ian.w.white@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/pickle/injector.rb
|
26
|
+
- lib/pickle/parser.rb
|
27
|
+
- lib/pickle/session.rb
|
28
|
+
- lib/pickle/steps.rb
|
29
|
+
- lib/pickle.rb
|
30
|
+
- License.txt
|
31
|
+
- README.textile
|
32
|
+
- Todo.txt
|
33
|
+
- History.txt
|
34
|
+
- spec/lib/pickle_config_spec.rb
|
35
|
+
- spec/lib/pickle_injector_spec.rb
|
36
|
+
- spec/lib/pickle_parser_spec.rb
|
37
|
+
- spec/lib/pickle_session_spec.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/ianwhite/pickle/tree
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --title
|
43
|
+
- Pickle
|
44
|
+
- --line-numbers
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: Easy model creation and reference in your cucumber features
|
66
|
+
test_files:
|
67
|
+
- spec/lib/pickle_config_spec.rb
|
68
|
+
- spec/lib/pickle_injector_spec.rb
|
69
|
+
- spec/lib/pickle_parser_spec.rb
|
70
|
+
- spec/lib/pickle_session_spec.rb
|