surveyor_gui 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +44 -0
  3. data/.travis.yml +17 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +21 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +159 -0
  8. data/Rakefile +66 -0
  9. data/app/controllers/answers_controller.rb +3 -0
  10. data/app/controllers/application_controller.rb +3 -0
  11. data/app/controllers/dependencys_controller.rb +286 -0
  12. data/app/controllers/question_groups_controller.rb +84 -0
  13. data/app/controllers/questions_controller.rb +187 -0
  14. data/app/controllers/survey_sections_controller.rb +80 -0
  15. data/app/controllers/surveyforms_controller.rb +4 -0
  16. data/app/controllers/surveyor_controller.rb +89 -0
  17. data/app/controllers/surveyor_gui/reports_controller.rb +339 -0
  18. data/app/controllers/surveyor_gui/responses_controller.rb +39 -0
  19. data/app/controllers/surveyor_gui/survey_controller.rb +16 -0
  20. data/app/facades/report_formatter.rb +44 -0
  21. data/app/facades/report_preview_wrapper.rb +11 -0
  22. data/app/facades/report_response_generator.rb +147 -0
  23. data/app/helpers/application_helper.rb +2 -0
  24. data/app/helpers/dependency_helper.rb +5 -0
  25. data/app/helpers/question_helper.rb +22 -0
  26. data/app/helpers/surveyform_helper.rb +179 -0
  27. data/app/helpers/surveyor_gui/report_helper.rb +19 -0
  28. data/app/helpers/surveyor_helper.rb +4 -0
  29. data/app/inputs/currency_input.rb +5 -0
  30. data/app/inputs/date_picker_input.rb +7 -0
  31. data/app/inputs/datetime_picker_input.rb +5 -0
  32. data/app/inputs/percent_input.rb +5 -0
  33. data/app/inputs/time_picker_input.rb +5 -0
  34. data/app/mailers/.gitkeep +0 -0
  35. data/app/models/.gitkeep +0 -0
  36. data/app/models/answer.rb +4 -0
  37. data/app/models/column.rb +3 -0
  38. data/app/models/dependency.rb +4 -0
  39. data/app/models/dependency_condition.rb +4 -0
  40. data/app/models/permitted_params_decorator.rb +80 -0
  41. data/app/models/question.rb +4 -0
  42. data/app/models/question_group.rb +4 -0
  43. data/app/models/question_type.rb +7 -0
  44. data/app/models/response.rb +4 -0
  45. data/app/models/response_set.rb +4 -0
  46. data/app/models/row.rb +3 -0
  47. data/app/models/survey.rb +4 -0
  48. data/app/models/survey_section.rb +4 -0
  49. data/app/models/surveyform.rb +103 -0
  50. data/app/uploaders/blob_uploader.rb +48 -0
  51. data/app/views/dependencys/_column.html.erb +1 -0
  52. data/app/views/dependencys/_dependency.html.erb +22 -0
  53. data/app/views/dependencys/_dependency_condition_fields.html.erb +48 -0
  54. data/app/views/dependencys/_form.html.erb +20 -0
  55. data/app/views/dependencys/blank.html.erb +0 -0
  56. data/app/views/dependencys/edit.html.erb +1 -0
  57. data/app/views/dependencys/new.html.erb +1 -0
  58. data/app/views/layouts/application.html.erb +14 -0
  59. data/app/views/layouts/surveyor_gui_blank.html.erb +12 -0
  60. data/app/views/layouts/surveyor_gui_default.html.erb +16 -0
  61. data/app/views/layouts/surveyor_modified.html.erb +14 -0
  62. data/app/views/partials/_answer.html.haml +33 -0
  63. data/app/views/partials/_question.html.haml +33 -0
  64. data/app/views/partials/_question_group.html.haml +73 -0
  65. data/app/views/partials/_section.html.haml +13 -0
  66. data/app/views/question_groups/_form.html.erb +56 -0
  67. data/app/views/question_groups/_group_inline_field.html.erb +21 -0
  68. data/app/views/question_groups/_group_inline_fields.html.erb +25 -0
  69. data/app/views/question_groups/blank.html.erb +0 -0
  70. data/app/views/question_groups/edit.html.erb +1 -0
  71. data/app/views/question_groups/new.html.erb +1 -0
  72. data/app/views/questions/_answer_fields.html.erb +23 -0
  73. data/app/views/questions/_answer_options.html.erb +28 -0
  74. data/app/views/questions/_form.html.erb +65 -0
  75. data/app/views/questions/_grid_dropdown_columns.html.erb +10 -0
  76. data/app/views/questions/_grid_dropdown_fields.html.erb +42 -0
  77. data/app/views/questions/_grid_fields.html.erb +9 -0
  78. data/app/views/questions/_no_picks.html.erb +29 -0
  79. data/app/views/questions/_pick.html +21 -0
  80. data/app/views/questions/_picks.html.erb +12 -0
  81. data/app/views/questions/blank.html.erb +0 -0
  82. data/app/views/questions/edit.html.erb +1 -0
  83. data/app/views/questions/new.html.erb +1 -0
  84. data/app/views/survey_sections/_form.html.erb +13 -0
  85. data/app/views/survey_sections/blank.html.erb +0 -0
  86. data/app/views/survey_sections/edit.html.erb +1 -0
  87. data/app/views/survey_sections/new.html.erb +1 -0
  88. data/app/views/surveyforms/_form.html.erb +50 -0
  89. data/app/views/surveyforms/_question_field.html.erb +148 -0
  90. data/app/views/surveyforms/_question_group.html.erb +116 -0
  91. data/app/views/surveyforms/_question_group_fields.html.erb +3 -0
  92. data/app/views/surveyforms/_question_name_and_number.html.erb +6 -0
  93. data/app/views/surveyforms/_question_section.html.erb +15 -0
  94. data/app/views/surveyforms/_question_wrapper.html.erb +109 -0
  95. data/app/views/surveyforms/_survey_section_fields.html.erb +138 -0
  96. data/app/views/surveyforms/clone_survey.html.erb +13 -0
  97. data/app/views/surveyforms/edit.html.erb +5 -0
  98. data/app/views/surveyforms/index.html.erb +40 -0
  99. data/app/views/surveyforms/new.html.erb +1 -0
  100. data/app/views/surveyforms/show.html.erb +5 -0
  101. data/app/views/surveyor_gui/reports/_graphs.html.haml +21 -0
  102. data/app/views/surveyor_gui/reports/_grid.html.haml +42 -0
  103. data/app/views/surveyor_gui/reports/_grid_dropdown.html.haml +56 -0
  104. data/app/views/surveyor_gui/reports/_repeater.html.haml +28 -0
  105. data/app/views/surveyor_gui/reports/_show_report.html.haml +33 -0
  106. data/app/views/surveyor_gui/reports/_single_question.html.haml +70 -0
  107. data/app/views/surveyor_gui/reports/show.html.erb +14 -0
  108. data/app/views/surveyor_gui/responses/_grid.html.haml +20 -0
  109. data/app/views/surveyor_gui/responses/_grid_dropdown.html.haml +20 -0
  110. data/app/views/surveyor_gui/responses/_repeater.html.haml +22 -0
  111. data/app/views/surveyor_gui/responses/_survey_results.html.haml +40 -0
  112. data/app/views/surveyor_gui/responses/index.html.haml +24 -0
  113. data/app/views/surveyor_gui/responses/show.html.haml +42 -0
  114. data/app/views/surveyor_gui/shared/_grid_comments.html.haml +10 -0
  115. data/app/views/surveyor_gui/shared/_new_line.html.haml +2 -0
  116. data/app/views/surveyor_gui/shared/_pick_comments.html.haml +15 -0
  117. data/app/views/surveyor_gui/shared/_question_number.html.haml +9 -0
  118. data/app/views/surveyor_gui/shared/_report_data.html.haml +24 -0
  119. data/app/views/surveyor_gui/shared/_stars_report_data.html.haml +14 -0
  120. data/config.ru +4 -0
  121. data/config/environment.rb +0 -0
  122. data/config/routes.rb +71 -0
  123. data/db/migrate/20140307204049_add_template_to_surveys.rb +5 -0
  124. data/db/migrate/20140307235607_add_test_data_to_response_sets.rb +5 -0
  125. data/db/migrate/20140308171947_add_original_choice_to_answers.rb +5 -0
  126. data/db/migrate/20140308172118_add_blob_to_responses.rb +5 -0
  127. data/db/migrate/20140308172417_add_modifiable_to_survey_section.rb +5 -0
  128. data/db/migrate/20140308174532_add_modifiable_to_question.rb +5 -0
  129. data/db/migrate/20140308175305_add_dynamically_generate_to_questions.rb +5 -0
  130. data/db/migrate/20140311032923_add_dummy_blob_to_questions.rb +5 -0
  131. data/db/migrate/20140311160609_add_dynamic_source_to_questions.rb +5 -0
  132. data/db/migrate/20140311161714_add_report_code_to_questions.rb +5 -0
  133. data/db/migrate/20140530181134_add_is_comment_to_questions.rb +5 -0
  134. data/db/migrate/20140531012006_add_is_comment_to_answers.rb +5 -0
  135. data/db/migrate/20140531225529_create_rows.rb +9 -0
  136. data/db/migrate/20140601011151_create_columns.rb +11 -0
  137. data/db/migrate/20140602030330_add_column_id_to_answers.rb +5 -0
  138. data/db/migrate/20140603155606_add_column_id_to_responses.rb +5 -0
  139. data/db/migrate/20140606023527_add_column_id_to_dependency_conditions.rb +5 -0
  140. data/db/migrate/20140815165307_add_user_id_to_survey.rb +5 -0
  141. data/lib/assets/.gitkeep +0 -0
  142. data/lib/assets/images/addicon.png +0 -0
  143. data/lib/assets/images/datepicker.gif +0 -0
  144. data/lib/assets/images/delete.gif +0 -0
  145. data/lib/assets/images/delete.png +0 -0
  146. data/lib/assets/images/images/border.png +0 -0
  147. data/lib/assets/images/images/controls.png +0 -0
  148. data/lib/assets/images/images/loading.gif +0 -0
  149. data/lib/assets/images/images/loading_background.png +0 -0
  150. data/lib/assets/images/images/overlay.png +0 -0
  151. data/lib/assets/images/rails.png +0 -0
  152. data/lib/assets/images/star.gif +0 -0
  153. data/lib/assets/javascripts/.gitkeep +0 -0
  154. data/lib/assets/javascripts/surveyor_gui/jquery.MetaData.js +121 -0
  155. data/lib/assets/javascripts/surveyor_gui/jquery.blockUI.js +619 -0
  156. data/lib/assets/javascripts/surveyor_gui/jquery.rating.js +377 -0
  157. data/lib/assets/javascripts/surveyor_gui/jquery.validate.js +1188 -0
  158. data/lib/assets/javascripts/surveyor_gui/surveyor_add_ons.js +10 -0
  159. data/lib/assets/javascripts/surveyor_gui/surveyor_gui.js +1417 -0
  160. data/lib/assets/stylesheets/.gitkeep +0 -0
  161. data/lib/assets/stylesheets/surveyor_gui/jquery.rating.css +12 -0
  162. data/lib/assets/stylesheets/surveyor_gui/surveyor_add_ons.css +3 -0
  163. data/lib/assets/stylesheets/surveyor_gui/surveyor_gui.sass +650 -0
  164. data/lib/enumerable_extenders.rb +31 -0
  165. data/lib/generators/surveyor_gui/install_generator.rb +57 -0
  166. data/lib/generators/surveyor_gui/templates/app/assets/javascripts/surveyor_add_ons.js +2 -0
  167. data/lib/generators/surveyor_gui/templates/app/assets/javascripts/surveyor_gui_all.js +24 -0
  168. data/lib/generators/surveyor_gui/templates/app/assets/stylesheets/surveyor_add_ons.css.sass +1 -0
  169. data/lib/generators/surveyor_gui/templates/app/assets/stylesheets/surveyor_gui_all.css.sass +8 -0
  170. data/lib/generators/surveyor_gui/templates/app/helpers/surveyor_helper.rb +4 -0
  171. data/lib/generators/surveyor_gui/templates/app/models/response_set_user.rb +13 -0
  172. data/lib/generators/surveyor_gui/templates/app/views/layouts/surveyor_gui_default.html.erb +16 -0
  173. data/lib/generators/surveyor_gui/templates/config/initializers/simple_form.rb +140 -0
  174. data/lib/generators/surveyor_gui/templates/config/locales/en.yml +5 -0
  175. data/lib/surveyor_gui.rb +17 -0
  176. data/lib/surveyor_gui/engine.rb +30 -0
  177. data/lib/surveyor_gui/helpers/surveyor_helper_methods.rb +19 -0
  178. data/lib/surveyor_gui/models/answer_methods.rb +24 -0
  179. data/lib/surveyor_gui/models/column_methods.rb +43 -0
  180. data/lib/surveyor_gui/models/dependency_condition_methods.rb +53 -0
  181. data/lib/surveyor_gui/models/dependency_methods.rb +83 -0
  182. data/lib/surveyor_gui/models/question_and_group_shared_methods.rb +11 -0
  183. data/lib/surveyor_gui/models/question_group_methods.rb +55 -0
  184. data/lib/surveyor_gui/models/question_methods.rb +435 -0
  185. data/lib/surveyor_gui/models/question_type_methods.rb +493 -0
  186. data/lib/surveyor_gui/models/response_methods.rb +67 -0
  187. data/lib/surveyor_gui/models/response_set_methods.rb +54 -0
  188. data/lib/surveyor_gui/models/row_methods.rb +11 -0
  189. data/lib/surveyor_gui/models/survey_methods.rb +32 -0
  190. data/lib/surveyor_gui/models/survey_section_methods.rb +32 -0
  191. data/lib/surveyor_gui/surveyforms_controller_methods.rb +258 -0
  192. data/lib/surveyor_gui/version.rb +3 -0
  193. data/lib/tasks/.gitkeep +0 -0
  194. data/lib/tasks/surveyor_gui_tasks.rake +4 -0
  195. data/lib/templates/erb/scaffold/_form.html.erb +13 -0
  196. data/spec/controllers/surveyforms_controller_spec.rb +361 -0
  197. data/spec/controllers/surveyor_controller_spec.rb +303 -0
  198. data/spec/factories.rb +181 -0
  199. data/spec/features/create_survey_spec.rb +418 -0
  200. data/spec/features/dependencies_spec.rb +61 -0
  201. data/spec/features/rearrange_survey_spec.rb +118 -0
  202. data/spec/features/ui_spec.rb +469 -0
  203. data/spec/fixtures/REDCapDemoDatabase_DataDictionary.csv +127 -0
  204. data/spec/fixtures/chinese_survey.rb +14 -0
  205. data/spec/fixtures/everything.rb +215 -0
  206. data/spec/fixtures/favorites-ish.rb +22 -0
  207. data/spec/fixtures/favorites.rb +22 -0
  208. data/spec/fixtures/feelings.rb +38 -0
  209. data/spec/fixtures/lifestyle.rb +55 -0
  210. data/spec/fixtures/numbers.rb +21 -0
  211. data/spec/fixtures/redcap_new_headers.csv +1 -0
  212. data/spec/fixtures/redcap_siblings.csv +1 -0
  213. data/spec/fixtures/redcap_whitespace.csv +1 -0
  214. data/spec/helpers/formtastic_custom_input_spec.rb +15 -0
  215. data/spec/helpers/surveyor_helper_spec.rb +116 -0
  216. data/spec/lib/common_spec.rb +37 -0
  217. data/spec/lib/parser_spec.rb +393 -0
  218. data/spec/lib/rake_kitchen_sink.rb +42 -0
  219. data/spec/lib/redcap_parser_spec.rb +129 -0
  220. data/spec/lib/unparser_spec.rb +126 -0
  221. data/spec/models/answer_spec.rb +144 -0
  222. data/spec/models/dependency_condition_spec.rb +428 -0
  223. data/spec/models/dependency_spec.rb +90 -0
  224. data/spec/models/question_group_spec.rb +66 -0
  225. data/spec/models/question_spec.rb +176 -0
  226. data/spec/models/response_set_spec.rb +452 -0
  227. data/spec/models/response_spec.rb +208 -0
  228. data/spec/models/survey_section_spec.rb +58 -0
  229. data/spec/models/survey_spec.rb +155 -0
  230. data/spec/models/surveyor_gui/question_spec.rb +60 -0
  231. data/spec/models/surveyor_gui/question_type_spec.rb +268 -0
  232. data/spec/models/validation_condition_spec.rb +98 -0
  233. data/spec/models/validation_spec.rb +64 -0
  234. data/spec/spec.opts +4 -0
  235. data/spec/spec_helper.rb +119 -0
  236. data/spec/support/scenario_outline_helper.rb +39 -0
  237. data/spec/support/shared.rb +10 -0
  238. data/spec/support/surveyforms_creation_helpers.rb +312 -0
  239. data/spec/support/surveyforms_rearrangement_helpers.rb +170 -0
  240. data/spec/support/surveyor_api_helpers.rb +15 -0
  241. data/spec/support/surveyor_ui_helpers.rb +108 -0
  242. data/spec/support/wait_for_ajax.rb +11 -0
  243. data/spec/views/questions/edit.html.erb_spec.rb +73 -0
  244. data/spec/views/surveyforms/edit.html.erb_spec.rb +126 -0
  245. data/surveyor_gui.gemspec +52 -0
  246. data/test/dummy/README.rdoc +261 -0
  247. data/test/dummy/Rakefile +7 -0
  248. data/test/dummy/app/assets/javascripts/application.js +15 -0
  249. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  250. data/test/dummy/app/controllers/application_controller.rb +3 -0
  251. data/test/dummy/app/helpers/application_helper.rb +2 -0
  252. data/test/dummy/app/mailers/.gitkeep +0 -0
  253. data/test/dummy/app/models/.gitkeep +0 -0
  254. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  255. data/test/dummy/config.ru +4 -0
  256. data/test/dummy/config/application.rb +59 -0
  257. data/test/dummy/config/boot.rb +10 -0
  258. data/test/dummy/config/database.yml +25 -0
  259. data/test/dummy/config/environment.rb +5 -0
  260. data/test/dummy/config/environments/development.rb +37 -0
  261. data/test/dummy/config/environments/production.rb +67 -0
  262. data/test/dummy/config/environments/test.rb +37 -0
  263. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  264. data/test/dummy/config/initializers/inflections.rb +15 -0
  265. data/test/dummy/config/initializers/mime_types.rb +5 -0
  266. data/test/dummy/config/initializers/secret_token.rb +7 -0
  267. data/test/dummy/config/initializers/session_store.rb +8 -0
  268. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  269. data/test/dummy/config/locales/en.yml +5 -0
  270. data/test/dummy/config/routes.rb +58 -0
  271. data/test/dummy/lib/assets/.gitkeep +0 -0
  272. data/test/dummy/log/.gitkeep +0 -0
  273. data/test/dummy/public/404.html +26 -0
  274. data/test/dummy/public/422.html +26 -0
  275. data/test/dummy/public/500.html +25 -0
  276. data/test/dummy/public/favicon.ico +0 -0
  277. data/test/dummy/script/rails +6 -0
  278. data/test/surveyor-gui_test.rb +7 -0
  279. data/test/test_helper.rb +15 -0
  280. data/vendor/assets/stylesheets/.gitkeep +0 -0
  281. data/vendor/assets/stylesheets/custom.sass +5 -0
  282. data/vendor/plugins/.gitkeep +0 -0
  283. metadata +664 -0
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'rake'
3
+
4
+ describe Surveyor::Parser do
5
+ before do
6
+ @rake = Rake::Application.new
7
+ Rake.application = @rake
8
+ Rake.application.add_import "#{gem_path('surveyor')}/lib/tasks/surveyor_tasks.rake"
9
+ Rake.application.load_imports
10
+ Rake::Task.define_task(:environment)
11
+ end
12
+ it "should return properly parse the kitchen sink survey" do
13
+ ENV["FILE"]="surveys/kitchen_sink_survey.rb"
14
+ @rake["surveyor"].invoke
15
+
16
+ Survey.count.should == 1
17
+ SurveySection.count.should == 2
18
+ Question.count.should == 51
19
+ Answer.count.should == 252
20
+ Dependency.count.should == 8
21
+ DependencyCondition.count.should == 12
22
+ QuestionGroup.count.should == 6
23
+
24
+ Survey.all.map(&:destroy)
25
+ end
26
+ it "should return properly parse a UTF8 survey" do
27
+ pending "failing - not clear why - await update of surveyor"
28
+ ENV["FILE"]="../spec/fixtures/chinese_survey.rb"
29
+ @rake["surveyor"].invoke
30
+
31
+ Survey.count.should == 1
32
+ SurveySection.count.should == 1
33
+ Question.count.should == 3
34
+ Answer.count.should == 15
35
+ Dependency.count.should == 0
36
+ DependencyCondition.count.should == 0
37
+ QuestionGroup.count.should == 1
38
+
39
+ Survey.all.map(&:destroy)
40
+ end
41
+
42
+ end
@@ -0,0 +1,129 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Surveyor::RedcapParser do
4
+ let(:parser){ Surveyor::RedcapParser.new }
5
+ it "returns a survey object" do
6
+ x = %("Variable / Field Name","Form Name","Field Units","Section Header","Field Type","Field Label","Choices OR Calculations","Field Note","Text Validation Type","Text Validation Min","Text Validation Max",Identifier?,"Branching Logic (Show field only if...)","Required Field?"\nstudy_id,demographics,,,text,"Study ID",,,,,,,,)
7
+ parser.parse(x, "redcaptest").is_a?(Survey).should be_true
8
+ end
9
+ context "parses" do
10
+ it "basic questions from REDCap" do
11
+ file = "REDCapDemoDatabase_DataDictionary.csv"
12
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
13
+ expect(Survey.count).to eq(1)
14
+ expect(Question.count).to eq(143)
15
+ expect(Answer.count).to eq(233)
16
+ expect(Dependency.count).to eq(2)
17
+ expect(DependencyCondition.count).to eq(3)
18
+ dependencies = [{rule: "A", question_reference_identifier: "given_birth"},
19
+ {rule: "A and B", question_reference_identifier: "num_children"}]
20
+ dependencies.each{|attrs| (expect(Dependency.where(rule: attrs[:rule]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
21
+ dependency_conditions_a = [{rule_key: "A", operator: "==", question_reference_identifier: "sex", answer_reference_identifier: "0"}]
22
+ dependency_conditions_ab = [{rule_key: "A", operator: "==", question_reference_identifier: "sex", answer_reference_identifier: "0"},
23
+ {rule_key: "B", operator: "==", question_reference_identifier: "given_birth", answer_reference_identifier: "1"}]
24
+ dependency_conditions_a.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.answer.reference_identifier).to eq(attrs[:answer_reference_identifier])) if attrs[:answer_reference_identifier] }
25
+ dependency_conditions_a.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
26
+ dependency_conditions_a.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.operator).to eq(attrs[:operator])) if attrs[:operator] }
27
+ dependency_conditions_ab.each{|attrs| (expect(Dependency.where(rule: "A and B").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.answer.reference_identifier).to eq(attrs[:answer_reference_identifier])) if attrs[:answer_reference_identifier] }
28
+ dependency_conditions_ab.each{|attrs| (expect(Dependency.where(rule: "A and B").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
29
+ dependency_conditions_ab.each{|attrs| (expect(Dependency.where(rule: "A and B").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.operator).to eq(attrs[:operator])) if attrs[:operator] }
30
+ end
31
+ it "question level dependencies from REDCap" do
32
+ file = "redcap_siblings.csv"
33
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
34
+ expect(Dependency.count).to eq(1)
35
+ expect(DependencyCondition.count).to eq(1)
36
+ dependencies = [{rule: "A", question_reference_identifier: "sib1yob"}]
37
+ dependencies.each{|attrs| (expect(Dependency.where(rule: attrs[:rule]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
38
+ dependency_conditions = [{rule_key: "A", operator: ">", question_reference_identifier: "sibs"}]
39
+ dependency_conditions.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.question.reference_identifier).to eq(attrs[:question_reference_identifier])) if attrs[:question_reference_identifier] }
40
+ dependency_conditions.each{|attrs| (expect(Dependency.where(rule: "A").first.dependency_conditions.where(rule_key: attrs[:rule_key]).first.operator).to eq(attrs[:operator])) if attrs[:operator] }
41
+ end
42
+ it "different headers from REDCap" do
43
+ file = "redcap_new_headers.csv"
44
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
45
+ expect(Survey.count).to eq(1)
46
+ expect(Question.count).to eq(1)
47
+ expect(Answer.count).to eq(2)
48
+ end
49
+ it "different whitespace from REDCap" do
50
+ file = "redcap_whitespace.csv"
51
+ parser.parse File.read(File.join(Rails.root, '..', 'spec', 'fixtures', file)), file
52
+ expect(Survey.count).to eq(1)
53
+ expect(Question.count).to eq(2)
54
+ expect(Answer.count).to eq(7)
55
+ answers = [{reference_identifier: "1", text: "Lexapro"},
56
+ {reference_identifier: "2", text: "Celexa"},
57
+ {reference_identifier: "3", text: "Prozac"},
58
+ {reference_identifier: "4", text: "Paxil"},
59
+ {reference_identifier: "5", text: "Zoloft"},
60
+ {reference_identifier: "0", text: "No"},
61
+ {reference_identifier: "1", text: "Yes"}]
62
+ answers.each{|attrs| (expect(Answer.where(text: attrs[:text]).first.reference_identifier).to eq(attrs[:reference_identifier]))}
63
+ end
64
+ end
65
+ context "helper methods" do
66
+ it "requires specific columns" do
67
+ # with standard fields
68
+ x = %w(field_units choices_or_calculations text_validation_type variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
69
+ parser.missing_columns(x).should be_blank
70
+ # without field_units
71
+ y = %w(choices_or_calculations text_validation_type variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
72
+ parser.missing_columns(y).should be_blank
73
+ # choices_or_calculations => choices_calculations_or_slider_labels
74
+ z = %w(field_units choices_calculations_or_slider_labels text_validation_type variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
75
+ parser.missing_columns(z).should be_blank
76
+ # text_validation_type => text_validation_type_or_show_slider_number
77
+ a = %w(field_units choices_or_calculations text_validation_type_or_show_slider_number variable__field_name form_name section_header field_type field_label field_note text_validation_min text_validation_max identifier branching_logic_show_field_only_if required_field)
78
+ parser.missing_columns(a).should be_blank
79
+ end
80
+ it "decomposes dependency rules" do
81
+ # basic
82
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q12]="1"').should == {:rule => "A", :components => ['[f1_q12]="1"']}
83
+ # spacing
84
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q9] = "1"').should == {:rule => "A", :components => ['[f1_q9] = "1"']}
85
+ # and
86
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[pre_q88]="1" and [pre_q90]="1"').should == {:rule => "A and B", :components => ['[pre_q88]="1"', '[pre_q90]="1"']}
87
+ # or
88
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[second_q111]="1" or [second_q111]="3"').should == {:rule => "A or B", :components => ['[second_q111]="1"', '[second_q111]="3"']}
89
+ # or and
90
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[second_q100]="1" or [second_q100]="3" and [second_q101]="1"').should == {:rule => "A or B and C", :components => ['[second_q100]="1"', '[second_q100]="3"', '[second_q101]="1"']}
91
+ # and or
92
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[second_q4]="1" and [second_q11]="1" or [second_q11]="98"').should == {:rule => "A and B or C", :components => ['[second_q4]="1"', '[second_q11]="1"', '[second_q11]="98"']}
93
+ # or or or
94
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[pre_q74]="1" or [pre_q74]="2" or [pre_q74]="4" or [pre_q74]="5"').should == {:rule => "A or B or C or D", :components => ['[pre_q74]="1"', '[pre_q74]="2"', '[pre_q74]="4"', '[pre_q74]="5"']}
95
+ # and with different operator
96
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q15] >= 21 and [f1_q28] ="1"').should == {:rule => "A and B", :components => ['[f1_q15] >= 21', '[f1_q28] ="1"']}
97
+ end
98
+ it "decomposes nested dependency rules" do
99
+ # external parenthesis
100
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('([pre_q74]="1" or [pre_q74]="2" or [pre_q74]="4" or [pre_q74]="5") and [pre_q76]="2"').should == {:rule => "(A or B or C or D) and E", :components => ['[pre_q74]="1"', '[pre_q74]="2"', '[pre_q74]="4"', '[pre_q74]="5"', '[pre_q76]="2"']}
101
+ # internal parenthesis
102
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[f1_q10(4)]="1"').should == {:rule => "A", :components => ['[f1_q10(4)]="1"']}
103
+ # internal and external parenthesis
104
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('([f1_q7(11)] = "1" or [initial_52] = "1") and [pre_q76]="2"').should == {:rule => "(A or B) and C", :components => ['[f1_q7(11)] = "1"', '[initial_52] = "1"', '[pre_q76]="2"']}
105
+ end
106
+ it "decomposes shortcut dependency rules" do
107
+ # 'or' on the right of the operator
108
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_108] = "1" or "2"').should == {:rule => "A or B", :components => ['[initial_108] = "1"', '[initial_108] = "2"']}
109
+ # multiple 'or' on the right
110
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_52] = "1" or "2" or "3"').should == {:rule => "A or B or C", :components => ['[initial_52] = "1"', '[initial_52] = "2"', '[initial_52] = "3"']}
111
+ # commas on the right
112
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_189] = "1, 2, 3"').should == {:rule => "(A and B and C)", :components => ['[initial_189] = "1"', '[initial_189] = "2"', '[initial_189] = "3"']}
113
+ # multiple internal parenthesis on the left
114
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_rule('[initial_119(1)(2)(3)(4)(5)] = "1"').should == {:rule => "(A and B and C and D and E)", :components => ['[initial_119(1)] = "1"', '[initial_119(2)] = "1"', '[initial_119(3)] = "1"', '[initial_119(4)] = "1"', '[initial_119(5)] = "1"']}
115
+ end
116
+ it "decomposes components" do
117
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component('[initial_52] = "1"').should == {:question_reference => 'initial_52', :operator => '==', :answer_reference => '1'}
118
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component('[initial_119(2)] = "1"').should == {:question_reference => 'initial_119', :operator => '==', :answer_reference => '2'}
119
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component('[f1_q15] >= 21').should == {:question_reference => 'f1_q15', :operator => '>=', :integer_value => '21'}
120
+ # basic, blanks
121
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[f1_q15]=''").should == {:question_reference => 'f1_q15', :operator => '==', :answer_reference => ''}
122
+ # basic, negatives
123
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[f1_q15]='-2'").should == {:question_reference => 'f1_q15', :operator => '==', :answer_reference => '-2'}
124
+ # internal parenthesis
125
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[hiprep_heat2(97)] = '1'").should == {:question_reference => 'hiprep_heat2', :operator => '==', :answer_reference => '97'}
126
+ Dependency.new.extend(SurveyorRedcapParserDependencyMethods).decompose_component("[hi_event1_type] <> ''").should == {:question_reference => 'hi_event1_type', :operator => '!=', :answer_reference => ''}
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,126 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Surveyor::Unparser do
4
+ before(:each) do
5
+ @survey = Survey.new(:title => "Simple survey", :description => "very simple")
6
+ @section = @survey.sections.build(:title => "Simple section")
7
+ end
8
+
9
+ it "should unparse a basic survey, section, and question" do
10
+ q1 = @section.questions.build(:text => "What is your favorite color?", :reference_identifier => 1, :pick => :one)
11
+ a11 = q1.answers.build(:text => "red", :response_class => "answer", :reference_identifier => 1, :question => q1)
12
+ a12 = q1.answers.build(:text => "green", :response_class => "answer", :reference_identifier => 2, :question => q1)
13
+ a13 = q1.answers.build(:text => "blue", :response_class => "answer", :reference_identifier => 3, :question => q1)
14
+ a14 = q1.answers.build(:text => "Other", :response_class => "string", :reference_identifier => 4, :question => q1)
15
+ a15 = q1.answers.build(:text => "Omit", :reference_identifier => 5, :question => q1, :is_exclusive => true)
16
+ q2 = @section.questions.build(:text => "What is your name?", :reference_identifier => 2, :pick => :none)
17
+ a21 = q2.answers.build(:response_class => "string", :reference_identifier => 1, :question => q2)
18
+ Surveyor::Unparser.unparse(@survey).should ==
19
+ <<-dsl
20
+ survey "Simple survey", :description=>"very simple" do
21
+ section "Simple section" do
22
+
23
+ q_1 "What is your favorite color?", :pick=>"one"
24
+ a_1 "red"
25
+ a_2 "green"
26
+ a_3 "blue"
27
+ a_4 :other, :string
28
+ a_5 :omit
29
+
30
+ q_2 "What is your name?"
31
+ a_1 :string
32
+ end
33
+ end
34
+ dsl
35
+ end
36
+
37
+ it "should unparse groups" do
38
+ q3 = @section.questions.build(:text => "Happy?")
39
+ a31 = q3.answers.build(:text => "Yes", :question => q3)
40
+ a32 = q3.answers.build(:text => "Maybe", :question => q3)
41
+ a33 = q3.answers.build(:text => "No", :question => q3)
42
+
43
+ q4 = @section.questions.build(:text => "Energized?")
44
+ a41 = q4.answers.build(:text => "Yes", :question => q4)
45
+ a42 = q4.answers.build(:text => "Maybe", :question => q4)
46
+ a43 = q4.answers.build(:text => "No", :question => q4)
47
+
48
+ g1 = q3.build_question_group(:text => "How are you feeling?", :display_type => "grid")
49
+ q4.question_group = g1
50
+ g1.questions = [q3, q4]
51
+
52
+ q5 = @section.questions.build(:text => "Model")
53
+ a51 = q5.answers.build(:response_class => "string", :question => q3)
54
+
55
+ g2 = q5.build_question_group(:text => "Tell us about the cars you own", :display_type => "repeater")
56
+ g2.questions = [q5]
57
+
58
+ Surveyor::Unparser.unparse(@survey).should ==
59
+ <<-dsl
60
+ survey "Simple survey", :description=>"very simple" do
61
+ section "Simple section" do
62
+
63
+ grid "How are you feeling?" do
64
+ a "Yes"
65
+ a "Maybe"
66
+ a "No"
67
+ q "Happy?"
68
+ q "Energized?"
69
+ end
70
+
71
+ repeater "Tell us about the cars you own" do
72
+ q "Model"
73
+ a :string
74
+ end
75
+ end
76
+ end
77
+ dsl
78
+ end
79
+
80
+ it "should unparse a basic survey, section, and question" do
81
+ q6 = @section.questions.build(:text => "What... is your name? (e.g. It is 'Arthur', King of the Britons)", :reference_identifier => "montypython3")
82
+ a61 = q6.answers.build(:response_class => "string", :reference_identifier => 1, :question => q6)
83
+
84
+ q7 = @section.questions.build(:text => "What... is your quest? (e.g. To seek the Holy Grail)", :display_type => "label")
85
+ d1 = q7.build_dependency(:rule => "A", :question => q7)
86
+ dc1 = d1.dependency_conditions.build(:dependency => d1, :question => q6, :answer => a61, :operator => "==", :string_value => "It is 'Arthur', King of the Britons", :rule_key => "A")
87
+
88
+ q8 = @section.questions.build(:text => "How many pets do you own?")
89
+ a81 = q8.answers.build(:response_class => "integer", :question => q8)
90
+ v1 = a81.validations.build(:rule => "A", :answer => a81)
91
+ vc1 = v1.validation_conditions.build(:operator => ">=", :integer_value => 0, :validation => v1, :rule_key => "A")
92
+
93
+ q9 = @section.questions.build(:text => "Pick your favorite date AND time", :custom_renderer => "/partials/custom_question")
94
+ a91 = q9.answers.build(:response_class => "datetime", :question => q9)
95
+
96
+ q10 = @section.questions.build(:text => "What time do you usually take a lunch break?", :reference_identifier => "time_lunch")
97
+ a101 = q10.answers.build(:response_class => "time", :reference_identifier => 1, :question => q10)
98
+
99
+ Surveyor::Unparser.unparse(@survey).should ==
100
+ <<-dsl
101
+ survey "Simple survey", :description=>"very simple" do
102
+ section "Simple section" do
103
+
104
+ q_montypython3 "What... is your name? (e.g. It is 'Arthur', King of the Britons)"
105
+ a_1 :string
106
+
107
+ label "What... is your quest? (e.g. To seek the Holy Grail)"
108
+ dependency :rule=>"A"
109
+ condition_A :q_montypython3, "==", {:string_value=>"It is 'Arthur', King of the Britons", :answer_reference=>"1"}
110
+
111
+ q "How many pets do you own?"
112
+ a :integer
113
+ validation :rule=>"A"
114
+ condition_A ">=", :integer_value=>0
115
+
116
+ q "Pick your favorite date AND time", :custom_renderer=>"/partials/custom_question"
117
+ a :datetime
118
+
119
+ q_time_lunch "What time do you usually take a lunch break?"
120
+ a_1 :time
121
+ end
122
+ end
123
+ dsl
124
+ end
125
+ end
126
+
@@ -0,0 +1,144 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe Answer do
5
+ let(:answer){ FactoryGirl.create(:answer) }
6
+
7
+ context "when creating" do
8
+ it { answer.should be_valid }
9
+ it "deletes validation when deleted" do
10
+ v_id = FactoryGirl.create(:validation, :answer => answer).id
11
+ answer.destroy
12
+ Validation.find_by_id(v_id).should be_nil
13
+ end
14
+ end
15
+
16
+ context "with mustache text substitution" do
17
+ require 'mustache'
18
+ let(:mustache_context){ Class.new(::Mustache){ def site; "Northwestern"; end; def foo; "bar"; end } }
19
+ it "subsitutes Mustache context variables" do
20
+ answer.text = "You are in {{site}}"
21
+ answer.in_context(answer.text, mustache_context).should == "You are in Northwestern"
22
+ answer.text_for(nil, mustache_context).should == "You are in Northwestern"
23
+
24
+ answer.help_text = "{{site}} is your site"
25
+ answer.in_context(answer.help_text, mustache_context).should == "Northwestern is your site"
26
+ answer.help_text_for(mustache_context).should == "Northwestern is your site"
27
+
28
+ answer.default_value = "{{site}}"
29
+ answer.in_context(answer.default_value, mustache_context).should == "Northwestern"
30
+ answer.default_value_for(mustache_context).should == "Northwestern"
31
+ end
32
+ end
33
+
34
+ context "with translations" do
35
+ require 'yaml'
36
+ let(:survey){ FactoryGirl.create(:survey) }
37
+ let(:survey_section){ FactoryGirl.create(:survey_section) }
38
+ let(:survey_translation){
39
+ FactoryGirl.create(:survey_translation, :locale => :es, :translation => {
40
+ :questions => {
41
+ :name => {
42
+ :answers => {
43
+ :name => {
44
+ :help_text => "Mi nombre es..."
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }.to_yaml)
50
+ }
51
+ let(:question){ FactoryGirl.create(:question, :reference_identifier => "name") }
52
+ before do
53
+ answer.reference_identifier = "name"
54
+ answer.help_text = "My name is..."
55
+ answer.text = nil
56
+ answer.question = question
57
+ question.survey_section = survey_section
58
+ survey_section.survey = survey
59
+ survey.translations << survey_translation
60
+ end
61
+ it "returns its own translation" do
62
+ answer.translation(:es)[:help_text].should == "Mi nombre es..."
63
+ end
64
+ it "returns translations in views" do
65
+ answer.help_text_for(nil, :es).should == "Mi nombre es..."
66
+ end
67
+ it "returns its own default values" do
68
+ answer.translation(:de).should == {"text" => nil, "help_text" => "My name is...", "default_value" => nil}
69
+ end
70
+ it "returns default values in views" do
71
+ answer.help_text_for(nil, :de).should == "My name is..."
72
+ end
73
+ end
74
+
75
+ context "handling strings" do
76
+ it "#split preserves strings" do
77
+ answer.split(answer.text).should == "My favorite color is clear"
78
+ end
79
+ it "#split(:pre) preserves strings" do
80
+ answer.split(answer.text, :pre).should == "My favorite color is clear"
81
+ end
82
+ it "#split(:post) preserves strings" do
83
+ answer.split(answer.text, :post).should == ""
84
+ end
85
+ it "#split splits strings" do
86
+ answer.text = "before|after|extra"
87
+ answer.split(answer.text).should == "before|after|extra"
88
+ end
89
+ it "#split(:pre) splits strings" do
90
+ answer.text = "before|after|extra"
91
+ answer.split(answer.text, :pre).should == "before"
92
+ end
93
+ it "#split(:post) splits strings" do
94
+ answer.text = "before|after|extra"
95
+ answer.split(answer.text, :post).should == "after|extra"
96
+ end
97
+ end
98
+
99
+ context "for views" do
100
+ it "#text_for with #display_type == image" do
101
+ answer.text = "rails.png"
102
+ answer.display_type = :image
103
+ answer.text_for.should =~ /<img alt="Rails" src="\/(images|assets)\/rails\.png" \/>/
104
+ end
105
+ it "#text_for with #display_type == hidden_label" do
106
+ answer.text = "Red"
107
+ answer.text_for.should == "Red"
108
+ answer.display_type = "hidden_label"
109
+ answer.text_for.should == ""
110
+ end
111
+ it "#default_value_for"
112
+ it "#help_text_for"
113
+ it "reports DOM ready #css_class from #custom_class" do
114
+ answer.custom_class = "foo bar"
115
+ answer.css_class.should == "foo bar"
116
+ end
117
+ it "reports DOM ready #css_class from #custom_class and #is_exclusive" do
118
+ answer.custom_class = "foo bar"
119
+ answer.is_exclusive = true
120
+ answer.css_class.should == "exclusive foo bar"
121
+ end
122
+ it "#text_for preserves strings" do
123
+ answer.text_for.should == "My favorite color is clear"
124
+ end
125
+ it "#text_for(:pre) preserves strings" do
126
+ answer.text_for(:pre).should == "My favorite color is clear"
127
+ end
128
+ it "#text_for(:post) preserves strings" do
129
+ answer.text_for(:post).should == ""
130
+ end
131
+ it "#text_for splits strings" do
132
+ answer.text = "before|after|extra"
133
+ answer.text_for.should == "before|after|extra"
134
+ end
135
+ it "#text_for(:pre) splits strings" do
136
+ answer.text = "before|after|extra"
137
+ answer.text_for(:pre).should == "before"
138
+ end
139
+ it "#text_for(:post) splits strings" do
140
+ answer.text = "before|after|extra"
141
+ answer.text_for(:post).should == "after|extra"
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,428 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+
4
+ describe DependencyCondition do
5
+ it "should have a list of operators" do
6
+ %w(== != < > <= >=).each do |operator|
7
+ DependencyCondition.operators.include?(operator).should be_true
8
+ end
9
+ end
10
+
11
+ describe "instance" do
12
+ before(:each) do
13
+ @dependency_condition = DependencyCondition.new(
14
+ :dependency_id => 1, :question_id => 45, :operator => "==",
15
+ :answer_id => 23, :rule_key => "A")
16
+ end
17
+
18
+ it "should be valid" do
19
+ @dependency_condition.should be_valid
20
+ end
21
+
22
+ it "should be invalid without a parent dependency_id, question_id" do
23
+ # this causes issues with building and saving
24
+ # @dependency_condition.dependency_id = nil
25
+ # @dependency_condition.should have(1).errors_on(:dependency_id)
26
+ # @dependency_condition.question_id = nil
27
+ # @dependency_condition.should have(1).errors_on(:question_id)
28
+ end
29
+
30
+ it "should be invalid without an operator" do
31
+ @dependency_condition.operator = nil
32
+ @dependency_condition.should have(2).errors_on(:operator)
33
+ end
34
+
35
+ it "should be invalid without a rule_key" do
36
+ @dependency_condition.should be_valid
37
+ @dependency_condition.rule_key = nil
38
+ @dependency_condition.should_not be_valid
39
+ @dependency_condition.should have(1).errors_on(:rule_key)
40
+ end
41
+
42
+ it "should have unique rule_key within the context of a dependency" do
43
+ @dependency_condition.should be_valid
44
+ DependencyCondition.create(
45
+ :dependency_id => 2, :question_id => 46, :operator => "==",
46
+ :answer_id => 14, :rule_key => "B")
47
+ @dependency_condition.rule_key = "B" # rule key uniquness is scoped by dependency_id
48
+ @dependency_condition.dependency_id = 2
49
+ @dependency_condition.should_not be_valid
50
+ @dependency_condition.should have(1).errors_on(:rule_key)
51
+ end
52
+
53
+ it "should have an operator in DependencyCondition.operators" do
54
+ DependencyCondition.operators.each do |o|
55
+ @dependency_condition.operator = o
56
+ @dependency_condition.should have(0).errors_on(:operator)
57
+ end
58
+ @dependency_condition.operator = "#"
59
+ @dependency_condition.should have(1).error_on(:operator)
60
+ end
61
+ it "should have a properly formed count operator" do
62
+ %w(count>1 count<1 count>=1 count<=1 count==1 count!=1).each do |o|
63
+ @dependency_condition.operator = o
64
+ @dependency_condition.should have(0).errors_on(:operator)
65
+ end
66
+ %w(count> count< count>= count<= count== count!=).each do |o|
67
+ @dependency_condition.operator = o
68
+ @dependency_condition.should have(1).errors_on(:operator)
69
+ end
70
+ %w(count=1 count><1 count<>1 count!1 count!!1 count=>1 count=<1).each do |o|
71
+ @dependency_condition.operator = o
72
+ @dependency_condition.should have(1).errors_on(:operator)
73
+ end
74
+ %w(count= count>< count<> count! count!! count=> count=< count> count< count>= count<= count== count!=).each do |o|
75
+ @dependency_condition.operator = o
76
+ @dependency_condition.should have(1).errors_on(:operator)
77
+ end
78
+ end
79
+ end
80
+
81
+ it "returns true for != with no responses" do
82
+ question = FactoryGirl.create(:question)
83
+ dependency_condition = FactoryGirl.create(:dependency_condition, :rule_key => "C", :question => question)
84
+ rs = FactoryGirl.create(:response_set)
85
+ dependency_condition.to_hash(rs).should == {:C => false}
86
+ end
87
+
88
+
89
+ it "should not assume that Response#as is not nil" do
90
+ # q_HEIGHT_FT "Portion of height in whole feet (e.g., 5)",
91
+ # :pick=>:one
92
+ # a :integer
93
+ # a_neg_1 "Refused"
94
+ # a_neg_2 "Don't know"
95
+ # label "Provided value is outside of the suggested range (4 to 7 feet). This value is admissible, but you may wish to verify."
96
+ # dependency :rule=>"A or B"
97
+ # condition_A :q_HEIGHT_FT, "<", {:integer_value => "4"}
98
+ # condition_B :q_HEIGHT_FT, ">", {:integer_value => "7"}
99
+
100
+ answer = FactoryGirl.create(:answer, :response_class => :integer)
101
+ @dependency_condition = DependencyCondition.new(
102
+ :dependency => FactoryGirl.create(:dependency),
103
+ :question => answer.question,
104
+ :answer => answer,
105
+ :operator => ">",
106
+ :integer_value => 4,
107
+ :rule_key => "A")
108
+
109
+ response = FactoryGirl.create(:response, :answer => answer, :question => answer.question)
110
+ response_set = response.response_set
111
+ response.integer_value.should == nil
112
+
113
+ @dependency_condition.to_hash(response_set).should == {:A => false}
114
+ end
115
+
116
+ describe "evaluate '==' operator" do
117
+ before(:each) do
118
+ @a = FactoryGirl.create(:answer, :response_class => "answer")
119
+ @b = FactoryGirl.create(:answer, :question => @a.question)
120
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a)
121
+ @rs = @r.response_set
122
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => "==", :rule_key => "D")
123
+ @dc.as(:answer).should == @r.as(:answer)
124
+ end
125
+
126
+ it "with checkbox/radio type response" do
127
+ @dc.to_hash(@rs).should == {:D => true}
128
+ @dc.answer = @b
129
+ @dc.to_hash(@rs).should == {:D => false}
130
+ end
131
+
132
+ it "with string value response" do
133
+ @a.update_attributes(:response_class => "string")
134
+ @r.update_attributes(:string_value => "hello123")
135
+ @dc.string_value = "hello123"
136
+ @dc.to_hash(@rs).should == {:D => true}
137
+ @r.update_attributes(:string_value => "foo_abc")
138
+ @dc.to_hash(@rs).should == {:D => false}
139
+ end
140
+
141
+ it "with a text value response" do
142
+ @a.update_attributes(:response_class => "text")
143
+ @r.update_attributes(:text_value => "hello this is some text for comparison")
144
+ @dc.text_value = "hello this is some text for comparison"
145
+ @dc.to_hash(@rs).should == {:D => true}
146
+ @r.update_attributes(:text_value => "Not the same text")
147
+ @dc.to_hash(@rs).should == {:D => false}
148
+ end
149
+
150
+ it "with an integer value response" do
151
+ @a.update_attributes(:response_class => "integer")
152
+ @r.update_attributes(:integer_value => 10045)
153
+ @dc.integer_value = 10045
154
+ @dc.to_hash(@rs).should == {:D => true}
155
+ @r.update_attributes(:integer_value => 421)
156
+ @dc.to_hash(@rs).should == {:D => false}
157
+ end
158
+
159
+ it "with a float value response" do
160
+ @a.update_attributes(:response_class => "float")
161
+ @r.update_attributes(:float_value => 121.1)
162
+ @dc.float_value = 121.1
163
+ @dc.to_hash(@rs).should == {:D => true}
164
+ @r.update_attributes(:float_value => 130.123)
165
+ @dc.to_hash(@rs).should == {:D => false}
166
+ end
167
+ end
168
+
169
+ describe "evaluate '!=' operator" do
170
+ before(:each) do
171
+ @a = FactoryGirl.create(:answer)
172
+ @b = FactoryGirl.create(:answer, :question => @a.question)
173
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a)
174
+ @rs = @r.response_set
175
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => "!=", :rule_key => "E")
176
+ @dc.as(:answer).should == @r.as(:answer)
177
+ end
178
+
179
+ it "with checkbox/radio type response" do
180
+ @dc.to_hash(@rs).should == {:E => false}
181
+ @dc.answer_id = @a.id.to_i+1
182
+ @dc.to_hash(@rs).should == {:E => true}
183
+ end
184
+
185
+ it "with string value response" do
186
+ @a.update_attributes(:response_class => "string")
187
+ @r.update_attributes(:string_value => "hello123")
188
+ @dc.string_value = "hello123"
189
+ @dc.to_hash(@rs).should == {:E => false}
190
+ @r.update_attributes(:string_value => "foo_abc")
191
+ @dc.to_hash(@rs).should == {:E => true}
192
+ end
193
+
194
+ it "with a text value response" do
195
+ @a.update_attributes(:response_class => "text")
196
+ @r.update_attributes(:text_value => "hello this is some text for comparison")
197
+ @dc.text_value = "hello this is some text for comparison"
198
+ @dc.to_hash(@rs).should == {:E => false}
199
+ @r.update_attributes(:text_value => "Not the same text")
200
+ @dc.to_hash(@rs).should == {:E => true}
201
+ end
202
+
203
+ it "with an integer value response" do
204
+ @a.update_attributes(:response_class => "integer")
205
+ @r.update_attributes(:integer_value => 10045)
206
+ @dc.integer_value = 10045
207
+ @dc.to_hash(@rs).should == {:E => false}
208
+ @r.update_attributes(:integer_value => 421)
209
+ @dc.to_hash(@rs).should == {:E => true}
210
+ end
211
+
212
+ it "with a float value response" do
213
+ @a.update_attributes(:response_class => "float")
214
+ @r.update_attributes(:float_value => 121.1)
215
+ @dc.float_value = 121.1
216
+ @dc.to_hash(@rs).should == {:E => false}
217
+ @r.update_attributes(:float_value => 130.123)
218
+ @dc.to_hash(@rs).should == {:E => true}
219
+ end
220
+ end
221
+
222
+ describe "evaluate the '<' operator" do
223
+ before(:each) do
224
+ @a = FactoryGirl.create(:answer)
225
+ @b = FactoryGirl.create(:answer, :question => @a.question)
226
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a)
227
+ @rs = @r.response_set
228
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => "<", :rule_key => "F")
229
+ @dc.as(:answer).should == @r.as(:answer)
230
+ end
231
+
232
+ it "with an integer value response" do
233
+ @a.update_attributes(:response_class => "integer")
234
+ @r.update_attributes(:integer_value => 50)
235
+ @dc.integer_value = 100
236
+ @dc.to_hash(@rs).should == {:F => true}
237
+ @r.update_attributes(:integer_value => 421)
238
+ @dc.to_hash(@rs).should == {:F => false}
239
+ end
240
+
241
+ it "with a float value response" do
242
+ @a.update_attributes(:response_class => "float")
243
+ @r.update_attributes(:float_value => 5.1)
244
+ @dc.float_value = 121.1
245
+ @dc.to_hash(@rs).should == {:F => true}
246
+ @r.update_attributes(:float_value => 130.123)
247
+ @dc.to_hash(@rs).should == {:F => false}
248
+ end
249
+ end
250
+
251
+ describe "evaluate the '<=' operator" do
252
+ before(:each) do
253
+ @a = FactoryGirl.create(:answer)
254
+ @b = FactoryGirl.create(:answer, :question => @a.question)
255
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a)
256
+ @rs = @r.response_set
257
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => "<=", :rule_key => "G")
258
+ @dc.as(:answer).should == @r.as(:answer)
259
+ end
260
+
261
+ it "with an integer value response" do
262
+ @a.update_attributes(:response_class => "integer")
263
+ @r.update_attributes(:integer_value => 50)
264
+ @dc.integer_value = 100
265
+ @dc.to_hash(@rs).should == {:G => true}
266
+ @r.update_attributes(:integer_value => 100)
267
+ @dc.to_hash(@rs).should == {:G => true}
268
+ @r.update_attributes(:integer_value => 421)
269
+ @dc.to_hash(@rs).should == {:G => false}
270
+ end
271
+
272
+ it "with a float value response" do
273
+ @a.update_attributes(:response_class => "float")
274
+ @r.update_attributes(:float_value => 5.1)
275
+ @dc.float_value = 121.1
276
+ @dc.to_hash(@rs).should == {:G => true}
277
+ @r.update_attributes(:float_value => 121.1)
278
+ @dc.to_hash(@rs).should == {:G => true}
279
+ @r.update_attributes(:float_value => 130.123)
280
+ @dc.to_hash(@rs).should == {:G => false}
281
+ end
282
+
283
+ end
284
+
285
+ describe "evaluate the '>' operator" do
286
+ before(:each) do
287
+ @a = FactoryGirl.create(:answer)
288
+ @b = FactoryGirl.create(:answer, :question => @a.question)
289
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a)
290
+ @rs = @r.response_set
291
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => ">", :rule_key => "H")
292
+ @dc.as(:answer).should == @r.as(:answer)
293
+ end
294
+
295
+ it "with an integer value response" do
296
+ @a.update_attributes(:response_class => "integer")
297
+ @r.update_attributes(:integer_value => 50)
298
+ @dc.integer_value = 100
299
+ @dc.to_hash(@rs).should == {:H => false}
300
+ @r.update_attributes(:integer_value => 421)
301
+ @dc.to_hash(@rs).should == {:H => true}
302
+ end
303
+
304
+ it "with a float value response" do
305
+ @a.update_attributes(:response_class => "float")
306
+ @r.update_attributes(:float_value => 5.1)
307
+ @dc.float_value = 121.1
308
+ @dc.to_hash(@rs).should == {:H => false}
309
+ @r.update_attributes(:float_value => 130.123)
310
+ @dc.to_hash(@rs).should == {:H => true}
311
+ end
312
+ end
313
+
314
+ describe "evaluate the '>=' operator" do
315
+ before(:each) do
316
+ @a = FactoryGirl.create(:answer)
317
+ @b = FactoryGirl.create(:answer, :question => @a.question)
318
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a)
319
+ @rs = @r.response_set
320
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => ">=", :rule_key => "I")
321
+ @dc.as(:answer).should == @r.as(:answer)
322
+ end
323
+
324
+ it "with an integer value response" do
325
+ @a.update_attributes(:response_class => "integer")
326
+ @r.update_attributes(:integer_value => 50)
327
+ @dc.integer_value = 100
328
+ @dc.to_hash(@rs).should == {:I => false}
329
+ @r.update_attributes(:integer_value => 100)
330
+ @dc.to_hash(@rs).should == {:I => true}
331
+ @r.update_attributes(:integer_value => 421)
332
+ @dc.to_hash(@rs).should == {:I => true}
333
+ end
334
+
335
+ it "with a float value response" do
336
+ @a.update_attributes(:response_class => "float")
337
+ @r.update_attributes(:float_value => 5.1)
338
+ @dc.float_value = 121.1
339
+ @dc.to_hash(@rs).should == {:I => false}
340
+ @r.update_attributes(:float_value => 121.1)
341
+ @dc.to_hash(@rs).should == {:I => true}
342
+ @r.update_attributes(:float_value => 130.123)
343
+ @dc.to_hash(@rs).should == {:I => true}
344
+ end
345
+ end
346
+
347
+ describe "evaluating with response_class string" do
348
+ it "should compare answer ids when the dependency condition string_value is nil" do
349
+ @a = FactoryGirl.create(:answer, :response_class => "string")
350
+ @b = FactoryGirl.create(:answer, :question => @a.question)
351
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a, :string_value => "")
352
+ @rs = @r.response_set
353
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => "==", :rule_key => "J")
354
+ @dc.to_hash(@rs).should == {:J => true}
355
+ end
356
+
357
+ it "should compare strings when the dependency condition string_value is not nil, even if it is blank" do
358
+ @a = FactoryGirl.create(:answer, :response_class => "string")
359
+ @b = FactoryGirl.create(:answer, :question => @a.question)
360
+ @r = FactoryGirl.create(:response, :question => @a.question, :answer => @a, :string_value => "foo")
361
+ @rs = @r.response_set
362
+ @dc = FactoryGirl.create(:dependency_condition, :question => @a.question, :answer => @a, :operator => "==", :rule_key => "K", :string_value => "foo")
363
+ @dc.to_hash(@rs).should == {:K => true}
364
+
365
+ @r.update_attributes(:string_value => "")
366
+ @dc.string_value = ""
367
+ @dc.to_hash(@rs).should == {:K => true}
368
+ end
369
+ end
370
+
371
+ describe "evaluate 'count' operator" do
372
+ before(:each) do
373
+ @q = FactoryGirl.create(:question)
374
+ @dc = DependencyCondition.new(:operator => "count>2", :rule_key => "M", :question => @q)
375
+ @as = []
376
+ 3.times do
377
+ @as << FactoryGirl.create(:answer, :question => @q, :response_class => "answer")
378
+ end
379
+ @rs = FactoryGirl.create(:response_set)
380
+ @as.slice(0,2).each do |a|
381
+ FactoryGirl.create(:response, :question => @q, :answer => a, :response_set => @rs)
382
+ end
383
+ @rs.save
384
+ end
385
+
386
+ it "with operator with >" do
387
+ @dc.to_hash(@rs).should == {:M => false}
388
+ FactoryGirl.create(:response, :question => @q, :answer => @as.last, :response_set => @rs)
389
+ @rs.reload.responses.count.should == 3
390
+ @dc.to_hash(@rs.reload).should == {:M => true}
391
+ end
392
+
393
+ it "with operator with <" do
394
+ @dc.operator = "count<2"
395
+ @dc.to_hash(@rs).should == {:M => false}
396
+ @dc.operator = "count<3"
397
+ @dc.to_hash(@rs).should == {:M => true}
398
+ end
399
+
400
+ it "with operator with <=" do
401
+ @dc.operator = "count<=1"
402
+ @dc.to_hash(@rs).should == {:M => false}
403
+ @dc.operator = "count<=2"
404
+ @dc.to_hash(@rs).should == {:M => true}
405
+ @dc.operator = "count<=3"
406
+ @dc.to_hash(@rs).should == {:M => true}
407
+ end
408
+
409
+ it "with operator with >=" do
410
+ @dc.operator = "count>=1"
411
+ @dc.to_hash(@rs).should == {:M => true}
412
+ @dc.operator = "count>=2"
413
+ @dc.to_hash(@rs).should == {:M => true}
414
+ @dc.operator = "count>=3"
415
+ @dc.to_hash(@rs).should == {:M => false}
416
+ end
417
+
418
+ it "with operator with !=" do
419
+ @dc.operator = "count!=1"
420
+ @dc.to_hash(@rs).should == {:M => true}
421
+ @dc.operator = "count!=2"
422
+ @dc.to_hash(@rs).should == {:M => false}
423
+ @dc.operator = "count!=3"
424
+ @dc.to_hash(@rs).should == {:M => true}
425
+ end
426
+ end
427
+
428
+ end