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
151
152
153
154
155
156
157
158
159
160
|
# frozen_string_literal: false
require 'test/unit'
class TestRactor < Test::Unit::TestCase
def test_shareability_of_iseq_proc
y = nil.instance_eval do
foo = []
proc { foo }
end
assert_unshareable(y, /unshareable object \[\] from variable 'foo'/)
y = [].instance_eval { proc { self } }
assert_unshareable(y, /Proc's self is not shareable/)
y = [].freeze.instance_eval { proc { self } }
assert_make_shareable(y)
end
def test_shareability_of_curried_proc
x = nil.instance_eval do
foo = []
proc { foo }.curry
end
assert_unshareable(x, /unshareable object \[\] from variable 'foo'/)
x = nil.instance_eval do
foo = 123
proc { foo }.curry
end
assert_make_shareable(x)
end
def test_shareability_of_method_proc
str = +""
x = str.instance_exec { proc { to_s } }
assert_unshareable(x, /Proc's self is not shareable/)
x = str.instance_exec { method(:to_s) }
assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
x = str.instance_exec { method(:to_s).to_proc }
assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
x = str.instance_exec { method(:itself).to_proc }
assert_unshareable(x, "can not make shareable object for #<Method: String(Kernel)#itself()>", exception: Ractor::Error)
str.freeze
x = str.instance_exec { proc { to_s } }
assert_make_shareable(x)
x = str.instance_exec { method(:to_s) }
assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
x = str.instance_exec { method(:to_s).to_proc }
assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
x = str.instance_exec { method(:itself).to_proc }
assert_unshareable(x, "can not make shareable object for #<Method: String(Kernel)#itself()>", exception: Ractor::Error)
end
def test_shareability_error_uses_inspect
x = (+"").instance_exec { method(:to_s) }
def x.to_s
raise "this should not be called"
end
assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
end
def test_default_thread_group
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
Warning[:experimental] = false
main_ractor_id = Thread.current.group.object_id
ractor_id = Ractor.new { Thread.current.group.object_id }.value
refute_equal main_ractor_id, ractor_id
end;
end
def test_class_instance_variables
assert_ractor(<<~'RUBY')
# Once we're in multi-ractor mode, the codepaths
# for class instance variables are a bit different.
Ractor.new {}.value
class TestClass
@a = 1
@b = 2
@c = 3
@d = 4
end
assert_equal 4, TestClass.remove_instance_variable(:@d)
assert_nil TestClass.instance_variable_get(:@d)
assert_equal 4, TestClass.instance_variable_set(:@d, 4)
assert_equal 4, TestClass.instance_variable_get(:@d)
RUBY
end
def test_fork_raise_isolation_error
assert_ractor(<<~'RUBY')
ractor = Ractor.new do
Process.fork
rescue Ractor::IsolationError => e
e
end
assert_equal Ractor::IsolationError, ractor.value.class
RUBY
end if Process.respond_to?(:fork)
def test_require_raises_and_no_ractor_belonging_issue
assert_ractor(<<~'RUBY')
require "tempfile"
f = Tempfile.new(["file_to_require_from_ractor", ".rb"])
f.write("raise 'uh oh'")
f.flush
err_msg = Ractor.new(f.path) do |path|
begin
require path
rescue RuntimeError => e
e.message # had confirm belonging issue here
else
nil
end
end.value
assert_equal "uh oh", err_msg
RUBY
end
def test_require_non_string
assert_ractor(<<~'RUBY')
require "tempfile"
require "pathname"
f = Tempfile.new(["file_to_require_from_ractor", ".rb"])
f.write("")
f.flush
result = Ractor.new(f.path) do |path|
require Pathname.new(path)
"success"
end.value
assert_equal "success", result
RUBY
end
def assert_make_shareable(obj)
refute Ractor.shareable?(obj), "object was already shareable"
Ractor.make_shareable(obj)
assert Ractor.shareable?(obj), "object didn't become shareable"
end
def assert_unshareable(obj, msg=nil, exception: Ractor::IsolationError)
refute Ractor.shareable?(obj), "object is already shareable"
assert_raise_with_message(exception, msg) do
Ractor.make_shareable(obj)
end
refute Ractor.shareable?(obj), "despite raising, object became shareable"
end
end
|