PageRenderTime 68ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/gems/thoughtbot-shoulda-2.10.2/lib/shoulda/context.rb

https://bitbucket.org/dummied/tweet-stitch
Ruby | 402 lines | 198 code | 43 blank | 161 comment | 13 complexity | 8d46e9462306e12858e5e4d38c702229 MD5 | raw file
Possible License(s): GPL-2.0, MIT
  1. module Shoulda
  2. class << self
  3. attr_accessor :contexts
  4. def contexts # :nodoc:
  5. @contexts ||= []
  6. end
  7. def current_context # :nodoc:
  8. self.contexts.last
  9. end
  10. def add_context(context) # :nodoc:
  11. self.contexts.push(context)
  12. end
  13. def remove_context # :nodoc:
  14. self.contexts.pop
  15. end
  16. end
  17. module ClassMethods
  18. # == Should statements
  19. #
  20. # Should statements are just syntactic sugar over normal Test::Unit test methods. A should block
  21. # contains all the normal code and assertions you're used to seeing, with the added benefit that
  22. # they can be wrapped inside context blocks (see below).
  23. #
  24. # === Example:
  25. #
  26. # class UserTest < Test::Unit::TestCase
  27. #
  28. # def setup
  29. # @user = User.new("John", "Doe")
  30. # end
  31. #
  32. # should "return its full name"
  33. # assert_equal 'John Doe', @user.full_name
  34. # end
  35. #
  36. # end
  37. #
  38. # ...will produce the following test:
  39. # * <tt>"test: User should return its full name. "</tt>
  40. #
  41. # Note: The part before <tt>should</tt> in the test name is gleamed from the name of the Test::Unit class.
  42. #
  43. # Should statements can also take a Proc as a <tt>:before </tt>option. This proc runs after any
  44. # parent context's setups but before the current context's setup.
  45. #
  46. # === Example:
  47. #
  48. # context "Some context" do
  49. # setup { puts("I run after the :before proc") }
  50. #
  51. # should "run a :before proc", :before => lambda { puts("I run before the setup") } do
  52. # assert true
  53. # end
  54. # end
  55. def should(name, options = {}, &blk)
  56. if Shoulda.current_context
  57. block_given? ? Shoulda.current_context.should(name, options, &blk) : Shoulda.current_context.should_eventually(name)
  58. else
  59. context_name = self.name.gsub(/Test/, "")
  60. context = Shoulda::Context.new(context_name, self) do
  61. block_given? ? should(name, options, &blk) : should_eventually(name)
  62. end
  63. context.build
  64. end
  65. end
  66. # == Before statements
  67. #
  68. # Before statements are should statements that run before the current
  69. # context's setup. These are especially useful when setting expectations.
  70. #
  71. # === Example:
  72. #
  73. # class UserControllerTest < Test::Unit::TestCase
  74. # context "the index action" do
  75. # setup do
  76. # @users = [Factory(:user)]
  77. # User.stubs(:find).returns(@users)
  78. # end
  79. #
  80. # context "on GET" do
  81. # setup { get :index }
  82. #
  83. # should_respond_with :success
  84. #
  85. # # runs before "get :index"
  86. # before_should "find all users" do
  87. # User.expects(:find).with(:all).returns(@users)
  88. # end
  89. # end
  90. # end
  91. # end
  92. def before_should(name, &blk)
  93. should(name, :before => blk) { assert true }
  94. end
  95. # Just like should, but never runs, and instead prints an 'X' in the Test::Unit output.
  96. def should_eventually(name, options = {}, &blk)
  97. context_name = self.name.gsub(/Test/, "")
  98. context = Shoulda::Context.new(context_name, self) do
  99. should_eventually(name, &blk)
  100. end
  101. context.build
  102. end
  103. # == Contexts
  104. #
  105. # A context block groups should statements under a common set of setup/teardown methods.
  106. # Context blocks can be arbitrarily nested, and can do wonders for improving the maintainability
  107. # and readability of your test code.
  108. #
  109. # A context block can contain setup, should, should_eventually, and teardown blocks.
  110. #
  111. # class UserTest < Test::Unit::TestCase
  112. # context "A User instance" do
  113. # setup do
  114. # @user = User.find(:first)
  115. # end
  116. #
  117. # should "return its full name"
  118. # assert_equal 'John Doe', @user.full_name
  119. # end
  120. # end
  121. # end
  122. #
  123. # This code will produce the method <tt>"test: A User instance should return its full name. "</tt>.
  124. #
  125. # Contexts may be nested. Nested contexts run their setup blocks from out to in before each
  126. # should statement. They then run their teardown blocks from in to out after each should statement.
  127. #
  128. # class UserTest < Test::Unit::TestCase
  129. # context "A User instance" do
  130. # setup do
  131. # @user = User.find(:first)
  132. # end
  133. #
  134. # should "return its full name"
  135. # assert_equal 'John Doe', @user.full_name
  136. # end
  137. #
  138. # context "with a profile" do
  139. # setup do
  140. # @user.profile = Profile.find(:first)
  141. # end
  142. #
  143. # should "return true when sent :has_profile?"
  144. # assert @user.has_profile?
  145. # end
  146. # end
  147. # end
  148. # end
  149. #
  150. # This code will produce the following methods
  151. # * <tt>"test: A User instance should return its full name. "</tt>
  152. # * <tt>"test: A User instance with a profile should return true when sent :has_profile?. "</tt>
  153. #
  154. # <b>Just like should statements, a context block can exist next to normal <tt>def test_the_old_way; end</tt>
  155. # tests</b>. This means you do not have to fully commit to the context/should syntax in a test file.
  156. def context(name, &blk)
  157. if Shoulda.current_context
  158. Shoulda.current_context.context(name, &blk)
  159. else
  160. context = Shoulda::Context.new(name, self, &blk)
  161. context.build
  162. end
  163. end
  164. # Returns the class being tested, as determined by the test class name.
  165. #
  166. # class UserTest; described_type; end
  167. # # => User
  168. def described_type
  169. self.name.gsub(/Test$/, '').constantize
  170. end
  171. # Sets the return value of the subject instance method:
  172. #
  173. # class UserTest < Test::Unit::TestCase
  174. # subject { User.first }
  175. #
  176. # # uses the existing user
  177. # should_validate_uniqueness_of :email
  178. # end
  179. def subject(&block)
  180. @subject_block = block
  181. end
  182. def subject_block # :nodoc:
  183. @subject_block
  184. end
  185. end
  186. module InstanceMethods
  187. # Returns an instance of the class under test.
  188. #
  189. # class UserTest
  190. # should "be a user" do
  191. # assert_kind_of User, subject # passes
  192. # end
  193. # end
  194. #
  195. # The subject can be explicitly set using the subject class method:
  196. #
  197. # class UserTest
  198. # subject { User.first }
  199. # should "be an existing user" do
  200. # assert !subject.new_record? # uses the first user
  201. # end
  202. # end
  203. #
  204. # If an instance variable exists named after the described class, that
  205. # instance variable will be used as the subject. This behavior is
  206. # deprecated, and will be removed in a future version of Shoulda. The
  207. # recommended approach for using a different subject is to use the subject
  208. # class method.
  209. #
  210. # class UserTest
  211. # should "be the existing user" do
  212. # @user = User.new
  213. # assert_equal @user, subject # passes
  214. # end
  215. # end
  216. #
  217. # The subject is used by all macros that require an instance of the class
  218. # being tested.
  219. def subject
  220. if subject_block
  221. instance_eval(&subject_block)
  222. else
  223. get_instance_of(self.class.described_type)
  224. end
  225. end
  226. def subject_block # :nodoc:
  227. (@shoulda_context && @shoulda_context.subject_block) || self.class.subject_block
  228. end
  229. def get_instance_of(object_or_klass) # :nodoc:
  230. if object_or_klass.is_a?(Class)
  231. klass = object_or_klass
  232. ivar = "@#{instance_variable_name_for(klass)}"
  233. if instance = instance_variable_get(ivar)
  234. warn "[WARNING] Using #{ivar} as the subject. Future versions " <<
  235. "of Shoulda will require an explicit subject using the " <<
  236. "subject class method. Add this after your setup to avoid " <<
  237. "this warning: subject { #{ivar} }"
  238. instance
  239. else
  240. klass.new
  241. end
  242. else
  243. object_or_klass
  244. end
  245. end
  246. def instance_variable_name_for(klass) # :nodoc:
  247. klass.to_s.split('::').last.underscore
  248. end
  249. end
  250. class Context # :nodoc:
  251. attr_accessor :name # my name
  252. attr_accessor :parent # may be another context, or the original test::unit class.
  253. attr_accessor :subcontexts # array of contexts nested under myself
  254. attr_accessor :setup_blocks # blocks given via setup methods
  255. attr_accessor :teardown_blocks # blocks given via teardown methods
  256. attr_accessor :shoulds # array of hashes representing the should statements
  257. attr_accessor :should_eventuallys # array of hashes representing the should eventually statements
  258. attr_accessor :subject_block
  259. def initialize(name, parent, &blk)
  260. Shoulda.add_context(self)
  261. self.name = name
  262. self.parent = parent
  263. self.setup_blocks = []
  264. self.teardown_blocks = []
  265. self.shoulds = []
  266. self.should_eventuallys = []
  267. self.subcontexts = []
  268. merge_block(&blk)
  269. Shoulda.remove_context
  270. end
  271. def merge_block(&blk)
  272. blk.bind(self).call
  273. end
  274. def context(name, &blk)
  275. self.subcontexts << Context.new(name, self, &blk)
  276. end
  277. def setup(&blk)
  278. self.setup_blocks << blk
  279. end
  280. def teardown(&blk)
  281. self.teardown_blocks << blk
  282. end
  283. def should(name, options = {}, &blk)
  284. if block_given?
  285. self.shoulds << { :name => name, :before => options[:before], :block => blk }
  286. else
  287. self.should_eventuallys << { :name => name }
  288. end
  289. end
  290. def should_eventually(name, &blk)
  291. self.should_eventuallys << { :name => name, :block => blk }
  292. end
  293. def subject(&block)
  294. self.subject_block = block
  295. end
  296. def full_name
  297. parent_name = parent.full_name if am_subcontext?
  298. return [parent_name, name].join(" ").strip
  299. end
  300. def am_subcontext?
  301. parent.is_a?(self.class) # my parent is the same class as myself.
  302. end
  303. def test_unit_class
  304. am_subcontext? ? parent.test_unit_class : parent
  305. end
  306. def create_test_from_should_hash(should)
  307. test_name = ["test:", full_name, "should", "#{should[:name]}. "].flatten.join(' ').to_sym
  308. if test_unit_class.instance_methods.include?(test_name.to_s)
  309. warn " * WARNING: '#{test_name}' is already defined"
  310. end
  311. context = self
  312. test_unit_class.send(:define_method, test_name) do
  313. @shoulda_context = context
  314. begin
  315. context.run_parent_setup_blocks(self)
  316. should[:before].bind(self).call if should[:before]
  317. context.run_current_setup_blocks(self)
  318. should[:block].bind(self).call
  319. ensure
  320. context.run_all_teardown_blocks(self)
  321. end
  322. end
  323. end
  324. def run_all_setup_blocks(binding)
  325. run_parent_setup_blocks(binding)
  326. run_current_setup_blocks(binding)
  327. end
  328. def run_parent_setup_blocks(binding)
  329. self.parent.run_all_setup_blocks(binding) if am_subcontext?
  330. end
  331. def run_current_setup_blocks(binding)
  332. setup_blocks.each do |setup_block|
  333. setup_block.bind(binding).call
  334. end
  335. end
  336. def run_all_teardown_blocks(binding)
  337. teardown_blocks.reverse.each do |teardown_block|
  338. teardown_block.bind(binding).call
  339. end
  340. self.parent.run_all_teardown_blocks(binding) if am_subcontext?
  341. end
  342. def print_should_eventuallys
  343. should_eventuallys.each do |should|
  344. test_name = [full_name, "should", "#{should[:name]}. "].flatten.join(' ')
  345. puts " * DEFERRED: " + test_name
  346. end
  347. end
  348. def build
  349. shoulds.each do |should|
  350. create_test_from_should_hash(should)
  351. end
  352. subcontexts.each { |context| context.build }
  353. print_should_eventuallys
  354. end
  355. def method_missing(method, *args, &blk)
  356. test_unit_class.send(method, *args, &blk)
  357. end
  358. end
  359. end