census 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +5 -0
- data/Rakefile +70 -0
- data/VERSION +1 -0
- data/app/controllers/census/data_groups_controller.rb +44 -0
- data/app/helpers/census_helper.rb +15 -0
- data/app/models/answer.rb +43 -0
- data/app/models/choice.rb +9 -0
- data/app/models/data_group.rb +10 -0
- data/app/models/question.rb +54 -0
- data/app/views/census/_question_fields.html.erb +40 -0
- data/app/views/census/_user_answers.html.erb +10 -0
- data/app/views/census/_user_questions.html.erb +10 -0
- data/app/views/census/data_groups/_choice_fields.html.erb +4 -0
- data/app/views/census/data_groups/_form.html.erb +11 -0
- data/app/views/census/data_groups/_question_fields.html.erb +22 -0
- data/app/views/census/data_groups/edit.html.erb +7 -0
- data/app/views/census/data_groups/index.html.erb +10 -0
- data/app/views/census/data_groups/new.html.erb +7 -0
- data/config/routes.rb +8 -0
- data/generators/census/USAGE +1 -0
- data/generators/census/census_generator.rb +39 -0
- data/generators/census/lib/insert_commands.rb +33 -0
- data/generators/census/lib/rake_commands.rb +22 -0
- data/generators/census/templates/README +29 -0
- data/generators/census/templates/census.js +10 -0
- data/generators/census/templates/census.rb +14 -0
- data/generators/census/templates/factories.rb +24 -0
- data/generators/census/templates/migrations/with_users.rb +60 -0
- data/generators/census/templates/migrations/without_users.rb +54 -0
- data/generators/census/templates/user.rb +3 -0
- data/lib/census/data_type.rb +33 -0
- data/lib/census/user.rb +85 -0
- data/lib/census.rb +1 -0
- data/rails/init.rb +7 -0
- data/shoulda_macros/census.rb +35 -0
- data/test/controllers/data_groups_controller_test.rb +165 -0
- data/test/models/answer_test.rb +44 -0
- data/test/models/choice_test.rb +24 -0
- data/test/models/data_group_test.rb +12 -0
- data/test/models/question_test.rb +213 -0
- data/test/models/user_test.rb +9 -0
- data/test/rails_root/app/controllers/application_controller.rb +10 -0
- data/test/rails_root/app/helpers/application_helper.rb +3 -0
- data/test/rails_root/app/models/user.rb +3 -0
- data/test/rails_root/config/boot.rb +110 -0
- data/test/rails_root/config/environment.rb +8 -0
- data/test/rails_root/config/environments/development.rb +17 -0
- data/test/rails_root/config/environments/production.rb +28 -0
- data/test/rails_root/config/environments/test.rb +32 -0
- data/test/rails_root/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_root/config/initializers/census.rb +14 -0
- data/test/rails_root/config/initializers/inflections.rb +10 -0
- data/test/rails_root/config/initializers/mime_types.rb +5 -0
- data/test/rails_root/config/initializers/new_rails_defaults.rb +21 -0
- data/test/rails_root/config/initializers/session_store.rb +15 -0
- data/test/rails_root/config/routes.rb +43 -0
- data/test/rails_root/db/migrate/20100406160306_create_census_tables.rb +60 -0
- data/test/rails_root/db/schema.rb +58 -0
- data/test/rails_root/test/factories/census.rb +24 -0
- data/test/rails_root/test/performance/browsing_test.rb +9 -0
- data/test/rails_root/test/test_helper.rb +38 -0
- data/test/rails_root/vendor/gems/acts_as_list-0.1.2/lib/acts_as_list.rb +254 -0
- data/test/rails_root/vendor/gems/acts_as_list-0.1.2/test/list_test.rb +369 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/install.rb +1 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/lib/inverse_of.rb +293 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/rails/init.rb +1 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/cases/helper.rb +28 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/cases/inverse_associations_test.rb +567 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/club.rb +13 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/face.rb +7 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/interest.rb +5 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/man.rb +9 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/sponsor.rb +4 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/models/zine.rb +3 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/test/schema/schema.rb +32 -0
- data/test/rails_root/vendor/gems/inverse_of-0.0.1/uninstall.rb +1 -0
- data/test/test_helper.rb +19 -0
- metadata +190 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
class CreateCensusTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :data_groups do |t|
|
4
|
+
t.string :name
|
5
|
+
t.integer :position
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table :questions do |t|
|
10
|
+
t.integer :data_group_id
|
11
|
+
t.string :data_type
|
12
|
+
t.string :prompt
|
13
|
+
t.boolean :multiple
|
14
|
+
t.boolean :other
|
15
|
+
t.integer :position
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
add_index :questions, :data_group_id
|
20
|
+
|
21
|
+
create_table :choices do |t|
|
22
|
+
t.integer :question_id
|
23
|
+
t.string :value
|
24
|
+
t.integer :position
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
|
28
|
+
add_index :choices, :question_id
|
29
|
+
|
30
|
+
create_table :answers do |t|
|
31
|
+
t.integer :question_id
|
32
|
+
t.integer :user_id
|
33
|
+
t.string :data
|
34
|
+
end
|
35
|
+
|
36
|
+
add_index :answers, :question_id
|
37
|
+
add_index :answers, :user_id
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.down
|
42
|
+
remove_index :answers, :question_id
|
43
|
+
remove_index :answers, :user_id
|
44
|
+
drop_table :answers
|
45
|
+
|
46
|
+
remove_index :choices, :question_id
|
47
|
+
drop_table :choices
|
48
|
+
|
49
|
+
remove_index :questions, :data_group_id
|
50
|
+
drop_table :questions
|
51
|
+
|
52
|
+
drop_table :data_groups
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Census
|
2
|
+
class DataType
|
3
|
+
attr_accessor :name
|
4
|
+
attr_accessor :sql_transform
|
5
|
+
attr_accessor :format_data
|
6
|
+
attr_accessor :validate_data
|
7
|
+
|
8
|
+
@@data_types = []
|
9
|
+
|
10
|
+
def self.all
|
11
|
+
@@data_types
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.define(name, options = {})
|
15
|
+
@@data_types << DataType.new(name, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find(name)
|
19
|
+
@@data_types.select {|dt| dt.name == name}.try(:first)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(name, options)
|
23
|
+
@name = name
|
24
|
+
@sql_transform = options[:sql_transform] || lambda {|column_name| "#{column_name}"}
|
25
|
+
@format_data = options[:format_data] || lambda {|data| data}
|
26
|
+
@validate_data = options[:validate_data] || lambda {|data| nil}
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
@name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/census/user.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
module Census
|
2
|
+
module User
|
3
|
+
|
4
|
+
# Hook for all Census::User modules.
|
5
|
+
#
|
6
|
+
# If you need to override parts of Census::User,
|
7
|
+
# extend and include à la carte.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# extend ClassMethods
|
11
|
+
# include InstanceMethods
|
12
|
+
# include Callbacks
|
13
|
+
#
|
14
|
+
# @see ClassMethods
|
15
|
+
# @see InstanceMethods
|
16
|
+
# @see Callbacks
|
17
|
+
def self.included(model)
|
18
|
+
model.extend(ClassMethods)
|
19
|
+
|
20
|
+
model.send(:include, InstanceMethods)
|
21
|
+
model.send(:include, Associations)
|
22
|
+
model.send(:include, Callbacks)
|
23
|
+
end
|
24
|
+
|
25
|
+
module Associations
|
26
|
+
# Hook for defining associations.
|
27
|
+
def self.included(model)
|
28
|
+
model.class_eval do
|
29
|
+
has_many :answers, :dependent => :destroy
|
30
|
+
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:data].blank? }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Callbacks
|
36
|
+
# Hook for callbacks.
|
37
|
+
#
|
38
|
+
# empty answers are removed after_save.
|
39
|
+
def self.included(model)
|
40
|
+
model.class_eval do
|
41
|
+
after_save :remove_empty_answers
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module InstanceMethods
|
47
|
+
#
|
48
|
+
# Returns this user's first answer for the given question, or a new empty
|
49
|
+
# answer if the user has not answered the question.
|
50
|
+
#
|
51
|
+
def first_answer_for(question)
|
52
|
+
answers.select {|a| a.question == question}.first || answers.build(:question => question, :data => '')
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Returns an array of this user's answers for the given question. The returned
|
57
|
+
# array will be empty if the user has not answered this question.
|
58
|
+
#
|
59
|
+
def all_answers_for(question)
|
60
|
+
answers.select {|a| a.question == question}
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Returns this user's answer for a specific choice under a multiple-choice
|
65
|
+
# question, or a new empty answer if the user did not select the given choice.
|
66
|
+
#
|
67
|
+
def answer_for_choice(choice)
|
68
|
+
answers.select {|a| a.question == choice.question && a.data == choice.value}.first || answers.build(:question => choice.question, :data => '')
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
#
|
74
|
+
# After save callback, used to remove blank answers
|
75
|
+
#
|
76
|
+
def remove_empty_answers
|
77
|
+
answers.each {|answer| answer.destroy if answer.data.blank? }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module ClassMethods
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/lib/census.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'census/user'
|
data/rails/init.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Census
|
2
|
+
module Shoulda
|
3
|
+
|
4
|
+
def should_accept_nested_attributes_for(*attr_names)
|
5
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
6
|
+
|
7
|
+
context "#{klass}" do
|
8
|
+
attr_names.each do |association_name|
|
9
|
+
should "accept nested attrs for #{association_name}" do
|
10
|
+
meth = "#{association_name}_attributes="
|
11
|
+
assert ([meth,meth.to_sym].any?{ |m| klass.instance_methods.include?(m) }),
|
12
|
+
"#{klass} does not accept nested attributes for #{association_name}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def should_act_as_list
|
19
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
20
|
+
|
21
|
+
context "To support acts_as_list" do
|
22
|
+
should_have_db_column('position', :type => :integer)
|
23
|
+
end
|
24
|
+
|
25
|
+
should "include ActsAsList methods" do
|
26
|
+
assert klass.include?(ActsAsList::InstanceMethods)
|
27
|
+
end
|
28
|
+
|
29
|
+
should_have_instance_methods :acts_as_list_class, :position_column, :scope_condition
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Test::Unit::TestCase.extend(Census::Shoulda)
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DataGroupsControllerTest < ActionController::TestCase
|
4
|
+
|
5
|
+
tests Census::DataGroupsController
|
6
|
+
|
7
|
+
should_route :get, '/census/admin',
|
8
|
+
:controller => 'census/data_groups', :action => 'index'
|
9
|
+
|
10
|
+
should_route :get, '/census/data_groups/new',
|
11
|
+
:controller => 'census/data_groups', :action => 'new'
|
12
|
+
|
13
|
+
should_route :post, '/census/data_groups',
|
14
|
+
:controller => 'census/data_groups', :action => 'create'
|
15
|
+
|
16
|
+
should_route :get, '/census/data_groups/1/edit',
|
17
|
+
:controller => 'census/data_groups', :action => 'edit', :id => '1'
|
18
|
+
|
19
|
+
should_route :put, '/census/data_groups/1',
|
20
|
+
:controller => 'census/data_groups', :action => 'update', :id => '1'
|
21
|
+
|
22
|
+
should_route :delete, '/census/data_groups/1',
|
23
|
+
:controller => 'census/data_groups', :action => 'destroy', :id => '1'
|
24
|
+
|
25
|
+
context 'The Census::DataGroupsController' do
|
26
|
+
|
27
|
+
context 'using GET to index' do
|
28
|
+
|
29
|
+
setup do
|
30
|
+
@group = Factory(:data_group)
|
31
|
+
get :index
|
32
|
+
end
|
33
|
+
|
34
|
+
should_respond_with :success
|
35
|
+
should_respond_with_content_type :html
|
36
|
+
should_render_template :index
|
37
|
+
should_assign_to :data_groups
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'using GET to new' do
|
42
|
+
|
43
|
+
setup do
|
44
|
+
get :new
|
45
|
+
end
|
46
|
+
|
47
|
+
should_respond_with :success
|
48
|
+
should_respond_with_content_type :html
|
49
|
+
should_render_template :new
|
50
|
+
should_assign_to :data_group
|
51
|
+
|
52
|
+
should 'have a new data group record' do
|
53
|
+
assert assigns(:data_group).new_record?
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'using POST to create' do
|
59
|
+
|
60
|
+
context 'with invalid attributes' do
|
61
|
+
|
62
|
+
setup do
|
63
|
+
DataGroup.any_instance.stubs(:valid?).returns(false)
|
64
|
+
post :create, :data_group => Factory.attributes_for(:data_group)
|
65
|
+
end
|
66
|
+
|
67
|
+
should_respond_with :unprocessable_entity
|
68
|
+
should_respond_with_content_type :html
|
69
|
+
should_render_template :new
|
70
|
+
should_assign_to :data_group
|
71
|
+
|
72
|
+
should 'not create the data group' do
|
73
|
+
assert assigns(:data_group).new_record?
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with valid attributes' do
|
79
|
+
|
80
|
+
setup do
|
81
|
+
post :create, :data_group => Factory.attributes_for(:data_group)
|
82
|
+
end
|
83
|
+
|
84
|
+
should_respond_with :redirect
|
85
|
+
should_assign_to :data_group
|
86
|
+
should_redirect_to('census admin page') { census_admin_url }
|
87
|
+
|
88
|
+
should 'create the data group' do
|
89
|
+
assert !assigns(:data_group).new_record?
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'using GET to edit' do
|
97
|
+
|
98
|
+
setup do
|
99
|
+
@group = Factory(:data_group)
|
100
|
+
get :edit, :id => @group.to_param
|
101
|
+
end
|
102
|
+
|
103
|
+
should_respond_with :success
|
104
|
+
should_respond_with_content_type :html
|
105
|
+
should_render_template :edit
|
106
|
+
should_assign_to(:data_group) { @group }
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'using PUT to update' do
|
111
|
+
|
112
|
+
context 'with valid attributes' do
|
113
|
+
|
114
|
+
setup do
|
115
|
+
@group = Factory(:data_group)
|
116
|
+
put :update, :id => @group.to_param, :data_group => {:name => 'CHANGED'}
|
117
|
+
end
|
118
|
+
|
119
|
+
should_respond_with :redirect
|
120
|
+
should_assign_to(:data_group) { @group }
|
121
|
+
should_redirect_to('census admin page') { census_admin_url }
|
122
|
+
|
123
|
+
should 'update the data group' do
|
124
|
+
assert_equal('CHANGED', @group.reload.name)
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'with invalid attributes' do
|
130
|
+
|
131
|
+
setup do
|
132
|
+
@group = Factory(:data_group)
|
133
|
+
DataGroup.any_instance.stubs(:valid? => false)
|
134
|
+
put :update, :id => @group.to_param, :data_group => {:name => 'CHANGED'}
|
135
|
+
end
|
136
|
+
|
137
|
+
should_respond_with :unprocessable_entity
|
138
|
+
should_respond_with_content_type :html
|
139
|
+
should_assign_to(:data_group) { @group }
|
140
|
+
should_render_template :edit
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'using DELETE to destroy' do
|
147
|
+
|
148
|
+
setup do
|
149
|
+
@group = Factory(:data_group)
|
150
|
+
delete :destroy, :id => @group.to_param
|
151
|
+
end
|
152
|
+
|
153
|
+
should_respond_with :redirect
|
154
|
+
should_assign_to(:data_group) { @group }
|
155
|
+
should_redirect_to('census admin page') { census_admin_url }
|
156
|
+
|
157
|
+
should 'destroy the data group' do
|
158
|
+
assert_nil(DataGroup.find_by_id(@group.id))
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AnswerTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "An Answer" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@answer = Factory(:answer)
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { @answer }
|
12
|
+
|
13
|
+
should_belong_to :question
|
14
|
+
should_belong_to :user
|
15
|
+
|
16
|
+
should_validate_presence_of :question,
|
17
|
+
:user
|
18
|
+
|
19
|
+
should_allow_mass_assignment_of :data
|
20
|
+
|
21
|
+
context "getting formatted data" do
|
22
|
+
|
23
|
+
should "format strings" do
|
24
|
+
a = Factory(:answer, :question => Factory(:question, :data_type => 'String'), :data => 'abc123')
|
25
|
+
assert_equal 'abc123', a.formatted_data
|
26
|
+
end
|
27
|
+
|
28
|
+
should "format numbers" do
|
29
|
+
a = Factory(:answer, :question => Factory(:question, :data_type => 'Number'), :data => '5389')
|
30
|
+
assert_equal 5389, a.formatted_data
|
31
|
+
end
|
32
|
+
|
33
|
+
should "format booleans" do
|
34
|
+
a = Factory(:answer, :question => Factory(:question, :data_type => 'Yes/No'), :data => '0')
|
35
|
+
assert_equal false, a.formatted_data
|
36
|
+
a.data = '1'
|
37
|
+
assert_equal true, a.formatted_data
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ChoiceTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "A Choice" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@choice = Factory(:choice)
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { @choice }
|
12
|
+
|
13
|
+
should_belong_to :question
|
14
|
+
|
15
|
+
should_act_as_list
|
16
|
+
|
17
|
+
should_validate_presence_of :value,
|
18
|
+
:question
|
19
|
+
|
20
|
+
should_allow_mass_assignment_of :value
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class QuestionTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
context "A Question" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@question = Factory(:question)
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { @question }
|
12
|
+
|
13
|
+
should_belong_to :data_group
|
14
|
+
should_have_many :choices, :dependent => :destroy
|
15
|
+
should_have_many :answers, :dependent => :destroy
|
16
|
+
|
17
|
+
should_act_as_list
|
18
|
+
|
19
|
+
should_validate_presence_of :prompt,
|
20
|
+
:data_group
|
21
|
+
|
22
|
+
should_allow_mass_assignment_of :data_type,
|
23
|
+
:prompt,
|
24
|
+
:multiple,
|
25
|
+
:other
|
26
|
+
|
27
|
+
should_accept_nested_attributes_for :choices
|
28
|
+
|
29
|
+
should "return a default sql transform" do
|
30
|
+
assert '"?"', @question.sql_transform
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with choices" do
|
34
|
+
|
35
|
+
setup do
|
36
|
+
@choice1 = Factory(:choice, :value => 'Choice 1', :question => @question)
|
37
|
+
@choice2 = Factory(:choice, :value => 'Choice 2', :question => @question)
|
38
|
+
@choice3 = Factory(:choice, :value => 'Choice 3', :question => @question)
|
39
|
+
end
|
40
|
+
|
41
|
+
should "allow answers that match the choices" do
|
42
|
+
assert Factory.build(:answer, :question => @question, :data => 'Choice 1').valid?
|
43
|
+
assert Factory.build(:answer, :question => @question, :data => 'Choice 3').valid?
|
44
|
+
end
|
45
|
+
|
46
|
+
should "not allow answers that don't match the choices" do
|
47
|
+
assert !Factory.build(:answer, :question => @question, :data => 'Blah').valid?
|
48
|
+
end
|
49
|
+
|
50
|
+
context "that allows user-supplied 'other' answer" do
|
51
|
+
|
52
|
+
setup do
|
53
|
+
@question.update_attribute(:other, true)
|
54
|
+
end
|
55
|
+
|
56
|
+
should "allow answers that don't match the choices" do
|
57
|
+
assert Factory.build(:answer, :question => @question, :data => 'Blah').valid?
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
context "that can't have multiple answers" do
|
65
|
+
|
66
|
+
setup do
|
67
|
+
@question.update_attribute(:multiple, false)
|
68
|
+
@user = Factory(:user)
|
69
|
+
end
|
70
|
+
|
71
|
+
should "not be able to create multiple answers" do
|
72
|
+
assert @question.answers.create(:data => 'Answer 1', :user => @user)
|
73
|
+
assert !Factory.build(:answer, :question => @question, :data => 'Answer 2', :user => @user).valid?
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
context "that can have multiple answers" do
|
79
|
+
|
80
|
+
setup do
|
81
|
+
@question.update_attribute(:multiple, true)
|
82
|
+
end
|
83
|
+
|
84
|
+
should "be able to create multiple answers" do
|
85
|
+
assert @question.answers.create(:data => 'Answer 1')
|
86
|
+
assert @question.answers.create(:data => 'Answer 2')
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
context "with String data type" do
|
92
|
+
|
93
|
+
setup do
|
94
|
+
@question.data_type = 'String'
|
95
|
+
end
|
96
|
+
|
97
|
+
should "return a default sql transform" do
|
98
|
+
assert_equal "?", @question.sql_transform
|
99
|
+
end
|
100
|
+
|
101
|
+
context "with answers" do
|
102
|
+
|
103
|
+
setup do
|
104
|
+
@answer1 = Factory(:answer, :question => @question, :data => 'findme')
|
105
|
+
@answer2 = Factory(:answer, :question => @question, :data => 'dont_findme')
|
106
|
+
@answer3 = Factory(:answer, :question => @question, :data => 'findme_too')
|
107
|
+
end
|
108
|
+
|
109
|
+
should "find answers matching a given string" do
|
110
|
+
assert @question.find_answers_matching('findme').include?(@answer1)
|
111
|
+
end
|
112
|
+
|
113
|
+
should "not find answers not matching the given string" do
|
114
|
+
assert !@question.find_answers_matching('findme').include?(@answer2)
|
115
|
+
end
|
116
|
+
|
117
|
+
should "find answers matching an array of strings" do
|
118
|
+
result = @question.find_answers_matching(['findme', 'findme_too'])
|
119
|
+
assert result.include?(@answer1)
|
120
|
+
assert result.include?(@answer3)
|
121
|
+
assert !result.include?(@answer2)
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
context "with Number data type" do
|
129
|
+
|
130
|
+
setup do
|
131
|
+
@question.data_type = 'Number'
|
132
|
+
end
|
133
|
+
|
134
|
+
should "return an integer sql transform" do
|
135
|
+
assert_equal "CAST(? AS SIGNED INTEGER)", @question.sql_transform
|
136
|
+
end
|
137
|
+
|
138
|
+
context "with answers" do
|
139
|
+
|
140
|
+
setup do
|
141
|
+
@answer1 = Factory(:answer, :question => @question, :data => '123')
|
142
|
+
@answer2 = Factory(:answer, :question => @question, :data => '125')
|
143
|
+
@answer3 = Factory(:answer, :question => @question, :data => '127')
|
144
|
+
end
|
145
|
+
|
146
|
+
should "find answers matching a given string" do
|
147
|
+
assert @question.find_answers_matching('123').include?(@answer1)
|
148
|
+
end
|
149
|
+
|
150
|
+
should "not find answers not matching the given string" do
|
151
|
+
assert !@question.find_answers_matching('123').include?(@answer2)
|
152
|
+
end
|
153
|
+
|
154
|
+
should "find answers matching a given number" do
|
155
|
+
assert @question.find_answers_matching(123).include?(@answer1)
|
156
|
+
end
|
157
|
+
|
158
|
+
should "not find answers not matching the given number" do
|
159
|
+
assert !@question.find_answers_matching(123).include?(@answer2)
|
160
|
+
end
|
161
|
+
|
162
|
+
should "find answers in a given range" do
|
163
|
+
result = @question.find_answers_matching(123..126)
|
164
|
+
assert result.include?(@answer1)
|
165
|
+
assert result.include?(@answer2)
|
166
|
+
assert !result.include?(@answer3)
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
context "with Yes/No data type" do
|
174
|
+
|
175
|
+
setup do
|
176
|
+
@question.data_type = 'Yes/No'
|
177
|
+
end
|
178
|
+
|
179
|
+
should "return a boolean sql transform" do
|
180
|
+
assert_equal "CAST(? AS CHAR)", @question.sql_transform
|
181
|
+
end
|
182
|
+
|
183
|
+
context "with answers" do
|
184
|
+
|
185
|
+
setup do
|
186
|
+
@answer1 = Factory(:answer, :question => @question)
|
187
|
+
@answer1.update_attribute(:data, false)
|
188
|
+
@answer2 = Factory(:answer, :question => @question, :data => true)
|
189
|
+
end
|
190
|
+
|
191
|
+
should "find answers matching true" do
|
192
|
+
assert @question.find_answers_matching(true).include?(@answer2)
|
193
|
+
end
|
194
|
+
|
195
|
+
should "not find answers not matching true" do
|
196
|
+
assert !@question.find_answers_matching(true).include?(@answer1)
|
197
|
+
end
|
198
|
+
|
199
|
+
should "find answers matching false" do
|
200
|
+
assert @question.find_answers_matching(false).include?(@answer1)
|
201
|
+
end
|
202
|
+
|
203
|
+
should "not find answers not matching false" do
|
204
|
+
assert !@question.find_answers_matching(false).include?(@answer2)
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|