aboutsummaryrefslogblamecommitdiffstats
path: root/activesupport/test/file_update_checker_shared_tests.rb
blob: bd056a157617bc2327244a0478191787e1104ff4 (plain) (tree)
1
2
3
4
5
6
7
8
9
                             
 
                   
 
                                   



                                                
 


                
 


                               
 


                                                                     
 




                                                                   
 


                                                                  
 
                                        
 


                                             
 

                                                               
 
                                 
 
                                                  
 


                                             
 

                                                                    
 
                                                  
 

                       
 


                                         
 

                                                                     
 
                                 
 
                                                  
 

                       
 


                                         
 

                                                                    
 
                                 
 
                                                  
 

                      
 


                                         
 

                                                                         
 

                                                  
 

                       
 

                                           
 

                                                                          
 
                                 
 

                                                  
 

                       
 

                                           
 

                                                                         
 
                                 
 

                                                  
 

                      
 

                                           
 

                                                                         
 
                                 
 


                                                                                          
 
                                                  
 

                              
 


                                         
 

                                                                        
 
                                 
 

                                                       
 
                                                  
 

                              
 


                                         
 

                                                         
 

                                                  
 

                       
 



                                               
 

                                                                                             
 
                                                           
 

                                
 


                                         
 

                                                                                              
 
                                                          
 

                                
 


                                         
 

                                                                                                  
 
                                                                   
 

                                
 

                                         
 

                                 
 


                                         
 

                                                                                 
 
                                                            
 

                                
 


                                             
 

                                                            
 

                                                        
 

                           
 


                                         
 

                                                   
 
                                                           
 


                                  
 

                                             
 

                                             
 


                                         
 

                                                                                          
 

                                  
 
                                                                           
 

                                 
 

                                             
 


                                                                          
 

                                         
 

                                              
 


                                         
 




                                                                    

       
   
# frozen_string_literal: true

require "fileutils"

module FileUpdateCheckerSharedTests
  def self.included(kls)
    kls.class_eval do
      extend ActiveSupport::Testing::Declarative
      include FileUtils

      def tmpdir
        @tmpdir
      end

      def tmpfile(name)
        File.join(tmpdir, name)
      end

      def tmpfiles
        @tmpfiles ||= %w(foo.rb bar.rb baz.rb).map { |f| tmpfile(f) }
      end

      def run(*args)
        capture_exceptions do
          Dir.mktmpdir(nil, __dir__) { |dir| @tmpdir = dir; super }
        end
      end

      test "should not execute the block if no paths are given" do
        silence_warnings { require "listen" }
        i = 0

        checker = new_checker { i += 1 }

        assert_not checker.execute_if_updated
        assert_equal 0, i
      end

      test "should not execute the block if no files change" do
        i = 0

        FileUtils.touch(tmpfiles)

        checker = new_checker(tmpfiles) { i += 1 }

        assert_not checker.execute_if_updated
        assert_equal 0, i
      end

      test "should execute the block once when files are created" do
        i = 0

        checker = new_checker(tmpfiles) { i += 1 }

        touch(tmpfiles)
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "should execute the block once when files are modified" do
        i = 0

        FileUtils.touch(tmpfiles)

        checker = new_checker(tmpfiles) { i += 1 }

        touch(tmpfiles)
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "should execute the block once when files are deleted" do
        i = 0

        FileUtils.touch(tmpfiles)

        checker = new_checker(tmpfiles) { i += 1 }

        rm_f(tmpfiles)
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "updated should become true when watched files are created" do
        i = 0

        checker = new_checker(tmpfiles) { i += 1 }
        assert_not_predicate checker, :updated?

        touch(tmpfiles)
        wait

        assert_predicate checker, :updated?
      end

      test "updated should become true when watched files are modified" do
        i = 0

        FileUtils.touch(tmpfiles)

        checker = new_checker(tmpfiles) { i += 1 }
        assert_not_predicate checker, :updated?

        touch(tmpfiles)
        wait

        assert_predicate checker, :updated?
      end

      test "updated should become true when watched files are deleted" do
        i = 0

        FileUtils.touch(tmpfiles)

        checker = new_checker(tmpfiles) { i += 1 }
        assert_not_predicate checker, :updated?

        rm_f(tmpfiles)
        wait

        assert_predicate checker, :updated?
      end

      test "should be robust to handle files with wrong modified time" do
        i = 0

        FileUtils.touch(tmpfiles)

        now  = Time.now
        time = Time.mktime(now.year + 1, now.month, now.day) # wrong mtime from the future
        File.utime(time, time, tmpfiles[0])

        checker = new_checker(tmpfiles) { i += 1 }

        touch(tmpfiles[1..-1])
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "should return max_time for files with mtime = Time.at(0)" do
        i = 0

        FileUtils.touch(tmpfiles)

        time = Time.at(0) # wrong mtime from the future
        File.utime(time, time, tmpfiles[0])

        checker = new_checker(tmpfiles) { i += 1 }

        touch(tmpfiles[1..-1])
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "should cache updated result until execute" do
        i = 0

        checker = new_checker(tmpfiles) { i += 1 }
        assert_not_predicate checker, :updated?

        touch(tmpfiles)
        wait

        assert_predicate checker, :updated?
        checker.execute
        assert_not_predicate checker, :updated?
      end

      test "should execute the block if files change in a watched directory one extension" do
        i = 0

        checker = new_checker([], tmpdir => :rb) { i += 1 }

        touch(tmpfile("foo.rb"))
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "should execute the block if files change in a watched directory any extensions" do
        i = 0

        checker = new_checker([], tmpdir => []) { i += 1 }

        touch(tmpfile("foo.rb"))
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "should execute the block if files change in a watched directory several extensions" do
        i = 0

        checker = new_checker([], tmpdir => [:rb, :txt]) { i += 1 }

        touch(tmpfile("foo.rb"))
        wait

        assert checker.execute_if_updated
        assert_equal 1, i

        touch(tmpfile("foo.txt"))
        wait

        assert checker.execute_if_updated
        assert_equal 2, i
      end

      test "should not execute the block if the file extension is not watched" do
        i = 0

        checker = new_checker([], tmpdir => :txt) { i += 1 }

        touch(tmpfile("foo.rb"))
        wait

        assert_not checker.execute_if_updated
        assert_equal 0, i
      end

      test "does not assume files exist on instantiation" do
        i = 0

        non_existing = tmpfile("non_existing.rb")
        checker = new_checker([non_existing]) { i += 1 }

        touch(non_existing)
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "detects files in new subdirectories" do
        i = 0

        checker = new_checker([], tmpdir => :rb) { i += 1 }

        subdir = tmpfile("subdir")
        mkdir(subdir)
        wait

        assert_not checker.execute_if_updated
        assert_equal 0, i

        touch(File.join(subdir, "nested.rb"))
        wait

        assert checker.execute_if_updated
        assert_equal 1, i
      end

      test "looked up extensions are inherited in subdirectories not listening to them" do
        i = 0

        subdir = tmpfile("subdir")
        mkdir(subdir)

        checker = new_checker([], tmpdir => :rb, subdir => :txt) { i += 1 }

        touch(tmpfile("new.txt"))
        wait

        assert_not checker.execute_if_updated
        assert_equal 0, i

        # subdir does not look for Ruby files, but its parent tmpdir does.
        touch(File.join(subdir, "nested.rb"))
        wait

        assert checker.execute_if_updated
        assert_equal 1, i

        touch(File.join(subdir, "nested.txt"))
        wait

        assert checker.execute_if_updated
        assert_equal 2, i
      end

      test "initialize raises an ArgumentError if no block given" do
        assert_raise ArgumentError do
          new_checker([])
        end
      end
    end
  end
end