trick_serial 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,76 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'trick_serial'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ =begin
11
+ if $DEBUG || ENV['DEBUG']
12
+ require 'rubygems'
13
+ gem 'ruby-debug'
14
+ require 'ruby-debug'
15
+ end
16
+ =end
17
+
18
+ RSpec.configure do |config|
19
+
20
+ end
21
+
22
+ ######################################################################
23
+ # Common test helpers
24
+ #
25
+
26
+ module TrickSerial
27
+ class Serializer
28
+ module Test
29
+ class A
30
+ attr_accessor :x, :y
31
+ end
32
+ class B
33
+ attr_accessor :x, :y
34
+ end
35
+ class PhonyActiveRecord
36
+ attr_accessor :id
37
+
38
+ @@find_map = { }
39
+ def self.find_map
40
+ @@find_map
41
+ end
42
+
43
+ @@id ||= 0
44
+ def initialize
45
+ @id = (@@id += 1)
46
+ end
47
+ def self.find(id)
48
+ obj = new
49
+ obj.id = id
50
+ # $stderr.puts " #{self}.find(#{id.inspect}) => #{obj.inspect}"
51
+ # (@@find_map[id] ||= 0) += 1 # Shouldn't Ruby parse this?
52
+ @@find_map[id] ||= 0
53
+ @@find_map[id] += 1
54
+ obj
55
+ end
56
+
57
+ def to_s
58
+ super.sub!(/>$/, " id=#{@id.inspect}>")
59
+ end
60
+ end
61
+
62
+ class Model < PhonyActiveRecord
63
+ attr_accessor :state
64
+ def initialize x = nil
65
+ super()
66
+ @state = x
67
+ end
68
+
69
+ def to_s
70
+ super.sub!(/>$/, " @state=#{@state.inspect}>")
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
@@ -0,0 +1,169 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ # Test Target:
4
+ require 'trick_serial/serializer/cgi_session'
5
+
6
+ # Test Helpers:
7
+ require 'cgi'
8
+ require 'cgi/session'
9
+ require 'cgi/session/pstore'
10
+ require 'fileutils'
11
+ require 'stringio'
12
+
13
+ $have_mem_cache_store = false
14
+ begin
15
+ require 'action_controller/session/mem_cache_store'
16
+ require 'trick_serial/serializer/cgi_session'
17
+ $have_mem_cache_store = true
18
+ rescue Exception => err
19
+ $stderr.puts "#{__FILE__}: #{err.inspect}\n #{err.backtrace * "\n "}"
20
+ end
21
+
22
+
23
+ TrickSerial::Serializer::CgiSession.activate!
24
+
25
+ describe "TrickSerial::Serializer::Cgi::Session" do
26
+
27
+ before(:each) do
28
+ @s = TrickSerial::Serializer.new
29
+ @s.class_option_map = {
30
+ TrickSerial::Serializer::Test::PhonyActiveRecord =>
31
+ { :proxy_class => TrickSerial::Serializer::ActiveRecordProxy, },
32
+ }
33
+
34
+ TrickSerial::Serializer::Test::PhonyActiveRecord.find_map.clear
35
+
36
+ @m = TrickSerial::Serializer::Test::Model.new(123)
37
+ @m_unsaved = TrickSerial::Serializer::Test::Model.new(:unsaved)
38
+ @m_unsaved.id = nil
39
+
40
+ TrickSerial::Serializer.default = @s
41
+ end
42
+
43
+ after(:each) do
44
+ TrickSerial::Serializer.default = nil
45
+ end
46
+
47
+
48
+ attr_accessor :cgi, :session
49
+
50
+ def create_session! options
51
+ @cgi = CGI.new("html4")
52
+ def @cgi.env_table; @env_table ||= { }; end
53
+ def @cgi.stdinput; @stdinput ||= StringIO.new; end
54
+
55
+ @cgi.stdinput << @header if @header
56
+
57
+ yield if block_given?
58
+
59
+ options = {
60
+ 'TrickSerial.database_manager' => @store,
61
+ 'database_manager' => TrickSerial::Serializer::CgiSession::Store,
62
+ 'tmpdir' => @tmpdir,
63
+ 'session_id' => 'abc123',
64
+ 'session_key' => '_test',
65
+ 'session_expires' => Time.now + 30 + 30,
66
+ 'prefix' => '_test',
67
+ }.merge(options)
68
+ @session = CGI::Session.new(cgi, options)
69
+ end
70
+
71
+ def test_store! store, options = { }
72
+ @tmpdir = "/tmp/#{File.basename(__FILE__)}-#{$$}"
73
+ FileUtils.mkdir_p(@tmpdir)
74
+
75
+ @store = store
76
+
77
+ create_session! options
78
+
79
+ @session['a'] = 1
80
+ @session['b'] = :b
81
+ @session['c'] = "aksjdfsd"
82
+ @session['m'] = @m
83
+ @session['m2'] = @m
84
+ @session['m_unsaved'] = @m_unsaved
85
+ @session['ary'] = [ 0, 1, @m, 3, 4, @m ]
86
+
87
+ @session.update
88
+ @session.close
89
+
90
+ create_session! options
91
+
92
+ fm = TrickSerial::Serializer::Test::PhonyActiveRecord.find_map
93
+ fm.clear
94
+ fm[@m.id].should == nil
95
+
96
+ @session['a'].should == 1
97
+ @session['b'].should == :b
98
+ @session['c'].should == "aksjdfsd"
99
+
100
+ fm[@m.id].should == nil
101
+
102
+ @session['m'].class.should == @m.class
103
+ @session['m'].object_id.should_not == @m.object_id
104
+ @session['m'].id.should == @m.id
105
+
106
+ fm[@m.id].should == 1
107
+
108
+ @session['m2'].object_id.should == @session['m'].object_id
109
+
110
+ fm[@m.id].should == 1
111
+
112
+ @session['ary'].class.should == Array
113
+
114
+ fm[@m.id].should == 1
115
+ fm.keys.size.should == 1
116
+
117
+ ensure
118
+ File.unlink(*Dir["#{@tmpdir}/*"])
119
+ FileUtils.rmdir(@tmpdir)
120
+ end
121
+
122
+ # FileStore can only handle String => String data.
123
+ it "should handle CGI::Session::FileStore" do
124
+ test_store! CGI::Session::FileStore
125
+ end
126
+
127
+ =begin
128
+ # MemoryStore is completely transparent
129
+ it "should handle CGI::Session::MemoryStore" do
130
+ test_store! CGI::Session::MemoryStore
131
+ end
132
+ =end
133
+
134
+ it "should handle CGI::Session::PStore" do
135
+ test_store! CGI::Session::PStore
136
+ end
137
+
138
+ if $have_mem_cache_store
139
+ it "should handle CGI::Session::MemCacheStore" do
140
+ begin
141
+ memcache_pid = nil
142
+ memcache_port = 45328
143
+ memcache_host = '127.0.0.1'
144
+ memcache_args = [ "memcached",
145
+ "-p", memcache_port,
146
+ "-l", memcache_host,
147
+ ]
148
+ memcache_args << "-vvv" if $DEBUG
149
+
150
+ cache = ::MemCache.new(memcache_host)
151
+ cache.servers = "#{memcache_host}:#{memcache_port}"
152
+ session_opts = {
153
+ 'cache' => cache,
154
+ }
155
+ memcache_pid = Process.fork do
156
+ memcache_args.map!{|e| e.to_s}
157
+ $stderr.puts "#{__FILE__}: starting memcache #{memcache_args.inspect}" if $DEBUG
158
+ Process.exec(*memcache_args)
159
+ end
160
+ sleep 1
161
+ test_store! CGI::Session::MemCacheStore, session_opts
162
+ ensure
163
+ sleep 1
164
+ Process.kill(9, memcache_pid) if memcache_pid
165
+ end
166
+ end
167
+ end
168
+ end
169
+
@@ -0,0 +1,268 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ require 'trick_serial/serializer/simple'
4
+
5
+ ######################################################################
6
+
7
+ describe "TrickSerial::Serializer::Simple" do
8
+ def t
9
+ TrickSerial::Serializer::Test
10
+ end
11
+ before(:each) do
12
+ @s = TrickSerial::Serializer::Simple.new
13
+ @s.class_option_map = {
14
+ t::PhonyActiveRecord => { :proxy_class => TrickSerial::Serializer::ActiveRecordProxy, },
15
+ t::A => { :instance_vars => true },
16
+ t::B => { :instance_vars => [ "@x" ] },
17
+ }
18
+ TrickSerial::Serializer::Test::PhonyActiveRecord.find_map.clear
19
+
20
+ @m = TrickSerial::Serializer::Test::Model.new(123)
21
+ @m2 = TrickSerial::Serializer::Test::Model.new(456)
22
+ @m_unsaved = TrickSerial::Serializer::Test::Model.new(:unsaved)
23
+ @m_unsaved.id = nil
24
+ @h = {
25
+ :a => 1,
26
+ 'b' => 2,
27
+ :obj => Object.new,
28
+ :m => @m,
29
+ :a => [ 0, 1, @m, 3, 4, @m ],
30
+ :m_unsaved => @m_unsaved,
31
+ }
32
+ @h[:a2] = @h[:a]
33
+ @h[:h2] = @h
34
+ end
35
+
36
+ it "should handle #encode!" do
37
+ @h[:m].should == @m
38
+ @h[:a][2].should == @m
39
+
40
+ result = @s.encode!(@h)
41
+
42
+ result.object_id.should == @h.object_id
43
+ end
44
+
45
+ it "should handle #decode!" do
46
+ @h[:m].should == @m
47
+ @h[:a][2].should == @m
48
+
49
+ result = @s.decode!(@h)
50
+
51
+ result.object_id.should == @h.object_id
52
+ end
53
+
54
+ it "should honor #enabled?" do
55
+ enabled = true
56
+ @s.enabled = lambda { | | enabled }
57
+ result = @s.encode(@h)
58
+ result.object_id.should_not == @h.object_id
59
+
60
+ enabled = false
61
+ result = @s.encode(@h)
62
+ result.object_id.should == @h.object_id
63
+ end
64
+
65
+ it "should proxy unsaved models" do
66
+ @o = @s.encode!(@h)
67
+ @o = @s.decode!(@o)
68
+ @o[:m].object_id.should_not == @m.object_id
69
+ @o[:m].class.should == @m.class
70
+ @o[:m].id.should == @m.id
71
+ end
72
+
73
+ it "should not proxy unsaved models" do
74
+ @o = @s.encode!(@h)
75
+ @o = @s.decode!(@o)
76
+ @o[:m_unsaved].object_id.should == @m_unsaved.object_id
77
+ end
78
+
79
+ it "should handle encode/decode through Hash#[]" do
80
+ @s.encode!(@h)
81
+ @s.decode!(@h)
82
+ p = @h[:m]
83
+ # pp [ :p=, p ]
84
+ p.class.should == @m.class
85
+ end
86
+
87
+ it "should handle encode/decode through Hash#values" do
88
+ @s.encode!(@h)
89
+ p = @h.values
90
+ p.select{|m| @m.class == m.class}.size.should == 1 # one of them is not proxyable.
91
+
92
+ @s.decode!(@h)
93
+ p = @h.values
94
+ p.select{|m| @m.class == m.class}.size.should == 2
95
+ end
96
+
97
+ it "should handle encode/decode through Array#[]" do
98
+ @s.encode!(@h)
99
+ p = @h[:a][2]
100
+ p.class.should_not == @m.class
101
+
102
+ @s.decode!(@h)
103
+ p = @h[:a][2]
104
+ p.class.should == @m.class
105
+ end
106
+
107
+ it "should handle encode/decode through Array#each" do
108
+ @s.encode!(@h)
109
+ p = @h[:m]
110
+ a = [ ]
111
+ @h[:a].each do | e |
112
+ a << e
113
+ end
114
+ a.should == [ 0, 1, p, 3, 4, p ]
115
+
116
+ @s.decode!(@h)
117
+ p = @h[:m]
118
+ a = [ ]
119
+ @h[:a].each do | e |
120
+ a << e
121
+ end
122
+ a.should == [ 0, 1, p, 3, 4, p ]
123
+ end
124
+
125
+ it "should handle encode/decode through Array#map" do
126
+ @s.encode!(@h)
127
+ @s.decode!(@h)
128
+ p = @h[:m]
129
+ a = @h[:a].each { | e | e }
130
+ a.should == [ 0, 1, p, 3, 4, p ]
131
+ end
132
+
133
+ it "should handle encode/decode through Array#map!" do
134
+ @s.encode!(@h)
135
+ @s.decode!(@h)
136
+ p = @h[:m]
137
+ a = @h[:a].map! { | e | 1; e }
138
+ a.should == [ 0, 1, p, 3, 4, p ]
139
+ end
140
+
141
+ it "should handle encode/decode through Array#select" do
142
+ @s.encode!(@h)
143
+ @s.decode!(@h)
144
+ p = @h[:m]
145
+ a = @h[:a].select { | e | @m.class == e.class }
146
+ a.should == [ p, p ]
147
+ end
148
+
149
+ it "should handle encode/decode through Array#find" do
150
+ @s.encode!(@h)
151
+ @s.decode!(@h)
152
+ p = @h[:m]
153
+ a = @h[:a].find { | e | @m.class == e.class }
154
+ a.should == p
155
+ end
156
+
157
+ it "should lazily traverse proxies" do
158
+ fm = TrickSerial::Serializer::Test::PhonyActiveRecord.find_map
159
+
160
+ fm[@m.id].should == nil
161
+
162
+ @s.encode!(@h)
163
+ @h = Marshal.load(Marshal.dump(@h))
164
+
165
+ fm[@m.id].should == nil
166
+
167
+ @s.decode!(@h)
168
+ fm[@m.id].should == 1
169
+
170
+ p = @h[:m]
171
+
172
+ fm[@m.id].should == 1
173
+
174
+ @h[:m].object_id.should == p.object_id
175
+ @h[:a][2].object_id.should == p.object_id
176
+ @h[:a][5].object_id.should == p.object_id
177
+
178
+ fm[@m.id].should == 1
179
+ fm.keys.size.should == 1
180
+ end
181
+
182
+ it "should preserve object identity" do
183
+ @s.encode!(@h)
184
+ @s.decode!(@h)
185
+
186
+ p = @h[:m]
187
+
188
+ @h[:m].object_id.should == p.object_id
189
+ @h[:a2].object_id.should == @h[:a].object_id
190
+ @h[:a][2].object_id.should == p.object_id
191
+ @h[:a][5].object_id.should == p.object_id
192
+ end
193
+
194
+ it "should produce a serializable result" do
195
+ @s.encode!(@h)
196
+
197
+ @o = Marshal.load(Marshal.dump(@h))
198
+ @o = @s.decode!(@o)
199
+
200
+ p = @o[:m]
201
+ p.class.should == @m.class
202
+
203
+ @o[:m].object_id.should == p.object_id
204
+ @o[:a][2].object_id.should == p.object_id
205
+ @o[:a][5].object_id.should == p.object_id
206
+ @o[:h2].object_id.should == @o.object_id
207
+ end
208
+
209
+ it "should copy core collections" do
210
+ @o = @s.encode(@h)
211
+ @o = @s.decode(@o)
212
+
213
+ @o.object_id.should_not == @h.object_id
214
+ @o[:a].object_id.should_not == @h[:a].object_id
215
+ @o[:a2].object_id.should == @o[:a].object_id
216
+
217
+ @o[:m].object_id.should_not == @h[:m].object_id
218
+ @o[:h2].object_id.should == @o.object_id
219
+ end
220
+
221
+ it "should honor :instance_vars option" do
222
+ obj = t::A.new
223
+ obj.x = @m
224
+ obj.y = @m
225
+ obj = @s.encode!(obj)
226
+ e = Marshal.load(str = Marshal.dump(obj))
227
+
228
+ e.class.should == t::A
229
+ e.instance_variable_get("@x").class.should == TrickSerial::Serializer::ActiveRecordProxy
230
+ e.instance_variable_get("@y").class.should == TrickSerial::Serializer::ActiveRecordProxy
231
+
232
+ @s.verbose = @s.debug = true
233
+ obj = @s.decode!(e)
234
+ # $stderr.puts "marshal = #{str.inspect}"
235
+
236
+ e.class.should == t::A
237
+ e.instance_variable_get("@x").class.should == TrickSerial::Serializer::Test::Model
238
+ e.instance_variable_get("@y").class.should == TrickSerial::Serializer::Test::Model
239
+ e.x.object_id.should == e.y.object_id
240
+
241
+ obj = t::B.new
242
+ obj.x = @m # should be encoded
243
+ obj.y = @m # should not be encoded
244
+ @s.verbose = @s.debug = false
245
+ obj = @s.encode!(obj)
246
+ e = Marshal.load(str = Marshal.dump(obj))
247
+
248
+ e.class.should == t::B
249
+ e.instance_variable_get("@x").class.should == TrickSerial::Serializer::ActiveRecordProxy
250
+ e.instance_variable_get("@y").class.should == TrickSerial::Serializer::Test::Model
251
+
252
+ @s.verbose = @s.debug = true
253
+ obj = @s.decode!(e)
254
+ # $stderr.puts "marshal = #{str.inspect}"
255
+
256
+ e.class.should == t::B
257
+ e.instance_variable_get("@x").class.should == TrickSerial::Serializer::Test::Model
258
+ e.x.class.should == @m.class
259
+ e.instance_variable_get("@y").class.should == TrickSerial::Serializer::Test::Model
260
+ e.y.class.should == @m.class
261
+ e.x.id.should == @m.id
262
+ e.y.id.should == @m.id
263
+ e.x.object_id.should_not == @m.object_id
264
+ e.x.object_id.should_not == e.y.object_id
265
+ e.y.object_id.should_not == @m.object_id
266
+ end
267
+
268
+ end