lib/covered/forks.rb



# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2023, by Samuel Williams.

require_relative 'wrapper'

module Covered
	class Forks < Wrapper
		def start
			super
			
			Handler.start(self)
		end
		
		def finish
			Handler.finish
			
			super
		end
		
		module Handler
			LOCK = Mutex.new
			
			class << self
				attr :coverage
				
				def start(coverage)
					LOCK.synchronize do
						if @coverage
							raise ArgumentError, "Coverage is already being tracked!"
						end
						
						@coverage = coverage
					end
				end
				
				def finish
					LOCK.synchronize do
						@coverage = nil
					end
				end
				
				def after_fork
					return unless coverage = Handler.coverage
					pid = Process.pid
					
					# Any pre-existing coverage is being tracked by the parent process, so discard it.
					coverage.clear
					
					at_exit do
						# Don't break forked children:
						if Process.pid == pid
							coverage.finish
						end
					end
				end
			end
			
			def _fork
				pid = super
				
				if pid.zero?
					Handler.after_fork
				end
				
				return pid
			end
			
			::Process.singleton_class.prepend(self)
		end
		
		private_constant :Handler
	end
end