You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

search_controller_test.rb 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. # Redmine - project management software
  2. # Copyright (C) 2006-2015 Jean-Philippe Lang
  3. #
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; either version 2
  7. # of the License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. require File.expand_path('../../test_helper', __FILE__)
  18. class SearchControllerTest < ActionController::TestCase
  19. fixtures :projects, :projects_trackers,
  20. :enabled_modules, :roles, :users, :members, :member_roles,
  21. :issues, :trackers, :issue_statuses, :enumerations,
  22. :workflows,
  23. :custom_fields, :custom_values,
  24. :custom_fields_projects, :custom_fields_trackers,
  25. :repositories, :changesets
  26. def setup
  27. User.current = nil
  28. end
  29. def test_search_for_projects
  30. get :index
  31. assert_response :success
  32. assert_template 'index'
  33. get :index, :q => "cook"
  34. assert_response :success
  35. assert_template 'index'
  36. assert assigns(:results).include?(Project.find(1))
  37. end
  38. def test_search_on_archived_project_should_return_404
  39. Project.find(3).archive
  40. get :index, :id => 3
  41. assert_response 404
  42. end
  43. def test_search_on_invisible_project_by_user_should_be_denied
  44. @request.session[:user_id] = 7
  45. get :index, :id => 2
  46. assert_response 403
  47. end
  48. def test_search_on_invisible_project_by_anonymous_user_should_redirect
  49. get :index, :id => 2
  50. assert_response 302
  51. end
  52. def test_search_on_private_project_by_member_should_succeed
  53. @request.session[:user_id] = 2
  54. get :index, :id => 2
  55. assert_response :success
  56. end
  57. def test_search_all_projects
  58. with_settings :default_language => 'en' do
  59. get :index, :q => 'recipe subproject commit', :all_words => ''
  60. end
  61. assert_response :success
  62. assert_template 'index'
  63. assert assigns(:results).include?(Issue.find(2))
  64. assert assigns(:results).include?(Issue.find(5))
  65. assert assigns(:results).include?(Changeset.find(101))
  66. assert_select 'dt.issue a', :text => /Add ingredients categories/
  67. assert_select 'dd', :text => /should be classified by categories/
  68. assert assigns(:result_count_by_type).is_a?(Hash)
  69. assert_equal 5, assigns(:result_count_by_type)['changesets']
  70. assert_select 'a', :text => 'Changesets (5)'
  71. end
  72. def test_search_issues
  73. get :index, :q => 'issue', :issues => 1
  74. assert_response :success
  75. assert_template 'index'
  76. assert_equal true, assigns(:all_words)
  77. assert_equal false, assigns(:titles_only)
  78. assert assigns(:results).include?(Issue.find(8))
  79. assert assigns(:results).include?(Issue.find(5))
  80. assert_select 'dt.issue.closed a', :text => /Closed/
  81. end
  82. def test_search_issues_should_search_notes
  83. Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
  84. get :index, :q => 'searchkeyword', :issues => 1
  85. assert_response :success
  86. assert_include Issue.find(2), assigns(:results)
  87. end
  88. def test_search_issues_with_multiple_matches_in_journals_should_return_issue_once
  89. Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
  90. Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
  91. get :index, :q => 'searchkeyword', :issues => 1
  92. assert_response :success
  93. assert_include Issue.find(2), assigns(:results)
  94. assert_equal 1, assigns(:results).size
  95. end
  96. def test_search_issues_should_search_private_notes_with_permission_only
  97. Journal.create!(:journalized => Issue.find(2), :notes => 'Private notes with searchkeyword', :private_notes => true)
  98. @request.session[:user_id] = 2
  99. Role.find(1).add_permission! :view_private_notes
  100. get :index, :q => 'searchkeyword', :issues => 1
  101. assert_response :success
  102. assert_include Issue.find(2), assigns(:results)
  103. Role.find(1).remove_permission! :view_private_notes
  104. get :index, :q => 'searchkeyword', :issues => 1
  105. assert_response :success
  106. assert_not_include Issue.find(2), assigns(:results)
  107. end
  108. def test_search_all_projects_with_scope_param
  109. get :index, :q => 'issue', :scope => 'all'
  110. assert_response :success
  111. assert_template 'index'
  112. assert assigns(:results).present?
  113. end
  114. def test_search_my_projects
  115. @request.session[:user_id] = 2
  116. get :index, :id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''
  117. assert_response :success
  118. assert_template 'index'
  119. assert assigns(:results).include?(Issue.find(1))
  120. assert !assigns(:results).include?(Issue.find(5))
  121. end
  122. def test_search_my_projects_without_memberships
  123. # anonymous user has no memberships
  124. get :index, :id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''
  125. assert_response :success
  126. assert_template 'index'
  127. assert assigns(:results).empty?
  128. end
  129. def test_search_project_and_subprojects
  130. get :index, :id => 1, :q => 'recipe subproject', :scope => 'subprojects', :all_words => ''
  131. assert_response :success
  132. assert_template 'index'
  133. assert assigns(:results).include?(Issue.find(1))
  134. assert assigns(:results).include?(Issue.find(5))
  135. end
  136. def test_search_without_searchable_custom_fields
  137. CustomField.update_all "searchable = #{ActiveRecord::Base.connection.quoted_false}"
  138. get :index, :id => 1
  139. assert_response :success
  140. assert_template 'index'
  141. assert_not_nil assigns(:project)
  142. get :index, :id => 1, :q => "can"
  143. assert_response :success
  144. assert_template 'index'
  145. end
  146. def test_search_with_searchable_custom_fields
  147. get :index, :id => 1, :q => "stringforcustomfield"
  148. assert_response :success
  149. results = assigns(:results)
  150. assert_not_nil results
  151. assert_equal 1, results.size
  152. assert results.include?(Issue.find(7))
  153. end
  154. def test_search_without_attachments
  155. issue = Issue.generate! :subject => 'search_attachments'
  156. attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
  157. get :index, :id => 1, :q => 'search_attachments', :attachments => '0'
  158. results = assigns(:results)
  159. assert_equal 1, results.size
  160. assert_equal issue, results.first
  161. end
  162. def test_search_attachments_only
  163. issue = Issue.generate! :subject => 'search_attachments'
  164. attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
  165. get :index, :id => 1, :q => 'search_attachments', :attachments => 'only'
  166. results = assigns(:results)
  167. assert_equal 1, results.size
  168. assert_equal attachment.container, results.first
  169. end
  170. def test_search_with_attachments
  171. Issue.generate! :subject => 'search_attachments'
  172. Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
  173. get :index, :id => 1, :q => 'search_attachments', :attachments => '1'
  174. results = assigns(:results)
  175. assert_equal 2, results.size
  176. end
  177. def test_search_open_issues
  178. Issue.generate! :subject => 'search_open'
  179. Issue.generate! :subject => 'search_open', :status_id => 5
  180. get :index, :id => 1, :q => 'search_open', :open_issues => '1'
  181. results = assigns(:results)
  182. assert_equal 1, results.size
  183. end
  184. def test_search_all_words
  185. # 'all words' is on by default
  186. get :index, :id => 1, :q => 'recipe updating saving', :all_words => '1'
  187. assert_equal true, assigns(:all_words)
  188. results = assigns(:results)
  189. assert_not_nil results
  190. assert_equal 1, results.size
  191. assert results.include?(Issue.find(3))
  192. end
  193. def test_search_one_of_the_words
  194. get :index, :id => 1, :q => 'recipe updating saving', :all_words => ''
  195. assert_equal false, assigns(:all_words)
  196. results = assigns(:results)
  197. assert_not_nil results
  198. assert_equal 3, results.size
  199. assert results.include?(Issue.find(3))
  200. end
  201. def test_search_titles_only_without_result
  202. get :index, :id => 1, :q => 'recipe updating saving', :titles_only => '1'
  203. results = assigns(:results)
  204. assert_not_nil results
  205. assert_equal 0, results.size
  206. end
  207. def test_search_titles_only
  208. get :index, :id => 1, :q => 'recipe', :titles_only => '1'
  209. assert_equal true, assigns(:titles_only)
  210. results = assigns(:results)
  211. assert_not_nil results
  212. assert_equal 2, results.size
  213. end
  214. def test_search_content
  215. Issue.where(:id => 1).update_all("description = 'This is a searchkeywordinthecontent'")
  216. get :index, :id => 1, :q => 'searchkeywordinthecontent', :titles_only => ''
  217. assert_equal false, assigns(:titles_only)
  218. results = assigns(:results)
  219. assert_not_nil results
  220. assert_equal 1, results.size
  221. end
  222. def test_search_with_pagination
  223. issue = (0..24).map {Issue.generate! :subject => 'search_with_limited_results'}.reverse
  224. get :index, :q => 'search_with_limited_results'
  225. assert_response :success
  226. assert_equal issue[0..9], assigns(:results)
  227. get :index, :q => 'search_with_limited_results', :page => 2
  228. assert_response :success
  229. assert_equal issue[10..19], assigns(:results)
  230. get :index, :q => 'search_with_limited_results', :page => 3
  231. assert_response :success
  232. assert_equal issue[20..24], assigns(:results)
  233. get :index, :q => 'search_with_limited_results', :page => 4
  234. assert_response :success
  235. assert_equal [], assigns(:results)
  236. end
  237. def test_search_with_invalid_project_id
  238. get :index, :id => 195, :q => 'recipe'
  239. assert_response 404
  240. assert_nil assigns(:results)
  241. end
  242. def test_quick_jump_to_issue
  243. # issue of a public project
  244. get :index, :q => "3"
  245. assert_redirected_to '/issues/3'
  246. # issue of a private project
  247. get :index, :q => "4"
  248. assert_response :success
  249. assert_template 'index'
  250. end
  251. def test_large_integer
  252. get :index, :q => '4615713488'
  253. assert_response :success
  254. assert_template 'index'
  255. end
  256. def test_tokens_with_quotes
  257. get :index, :id => 1, :q => '"good bye" hello "bye bye"'
  258. assert_equal ["good bye", "hello", "bye bye"], assigns(:tokens)
  259. end
  260. def test_results_should_be_escaped_once
  261. assert Issue.find(1).update_attributes(:subject => '<subject> escaped_once', :description => '<description> escaped_once')
  262. get :index, :q => 'escaped_once'
  263. assert_response :success
  264. assert_select '#search-results' do
  265. assert_select 'dt.issue a', :text => /<subject>/
  266. assert_select 'dd', :text => /<description>/
  267. end
  268. end
  269. def test_keywords_should_be_highlighted
  270. assert Issue.find(1).update_attributes(:subject => 'subject highlighted', :description => 'description highlighted')
  271. get :index, :q => 'highlighted'
  272. assert_response :success
  273. assert_select '#search-results' do
  274. assert_select 'dt.issue a span.highlight', :text => 'highlighted'
  275. assert_select 'dd span.highlight', :text => 'highlighted'
  276. end
  277. end
  278. end