File: mock.rb

package info (click to toggle)
ruby-ref 1.0.5%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 332 kB
  • ctags: 186
  • sloc: ruby: 1,107; java: 92; makefile: 2
file content (150 lines) | stat: -rw-r--r-- 4,541 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
module Ref
  # This module provides mock weak and strong references that are designed to be
  # used in tests. You can define a block where all weak and soft references created
  # will be mock references. You can then mimic running the garbage collector on
  # the objects pointed to by the references.
  #
  # Example usage:
  #
  #   Ref::Mock.use do
  #     obj = Object.new
  #     ref = Ref::WeakReference.new(obj)
  #     ref.object   # obj
  #     Ref::Mock.gc(obj)  # mimics the garbage collector reclaiming the referenced object
  #     ref.object   # nil
  #   end
  module Mock
    class << self
      # Use the mock implementation inside a block and then restore the original implementation.
      def use
        if object_space
          yield
        else
          setup
          begin
            yield
          ensure
            cleanup
          end
        end
      end
      
      # Start using mock references.
      def setup
        raise "Ref::Mock already setup" if object_space
        
        @object_space = {}
        
        class << ObjectSpace
          unless method_defined?(:define_finalizer_with_mock_reference)
            def define_finalizer_with_mock_reference(obj, finalizer)
              if ::Ref::Mock.object_space.include?(obj.__id__)
                ::Ref::Mock.object_space[obj.__id__] << finalizer
              else
                define_finalizer_without_mock_reference(obj, finalizer)
              end
            end
          end
          
          alias_method :define_finalizer_without_mock_reference, :define_finalizer
          alias_method :define_finalizer, :define_finalizer_with_mock_reference
        end
        
        class << WeakReference
          unless method_defined?(:new_with_mock_reference)
            def new_with_mock_reference(obj)
              if self == Mock::MockWeakReference
                new_without_mock_reference(obj)
              else
                Mock::MockWeakReference.new(obj)
              end
            end
          end
          
          alias_method :new_without_mock_reference, :new
          alias_method :new, :new_with_mock_reference
        end
        
        class << SoftReference
          unless method_defined?(:new_with_mock_reference)
            def new_with_mock_reference(obj)
              if self == Mock::MockSoftReference
                new_without_mock_reference(obj)
              else
                Mock::MockSoftReference.new(obj)
              end
            end
          end
          
          alias_method :new_without_mock_reference, :new
          alias_method :new, :new_with_mock_reference
        end
      end
      
      # Stop using mock references.
      def cleanup
        @object_space = nil
        class << ObjectSpace
          alias_method :define_finalizer_with_mock_reference, :define_finalizer
          alias_method :define_finalizer, :define_finalizer_without_mock_reference
        end
        
        class << WeakReference
          alias_method :new_with_mock_reference, :new
          alias_method :new, :new_without_mock_reference
        end
        
        class << SoftReference
          alias_method :new_with_mock_reference, :new
          alias_method :new, :new_without_mock_reference
        end
      end

      def object_space # :nodoc:
        @object_space if instance_variable_defined?(:@object_space)
      end

      # Simulate garbage collection of the objects passed in as arguments. If no objects
      # are specified, all objects will be reclaimed.
      def gc(*objects)
        objects = if objects.empty?
          object_space.keys
        else
          objects.map { |obj| obj.__id__ }
        end

        objects.each do |id|
          finalizers = object_space.delete(id)
          if finalizers
            finalizers.each{|finalizer| finalizer.call(id)}
          end
        end
      end
    end
    
    module MockReference #:nodoc:
      def initialize(obj)
        @object = obj
        @referenced_object_id = obj.__id__
        raise "Reference::Mock not setup yet" unless Mock.object_space
        Mock.object_space[obj.__id__] ||= []
      end
    
      def object
        if @object && Mock.object_space.include?(@object.__id__)
          @object
        else
          @object = nil
        end
      end
    end
  
    class MockWeakReference < WeakReference #:nodoc:
      include MockReference
    end
  
    class MockSoftReference < SoftReference #:nodoc:
      include MockReference
    end
  end  
end