nitro 0.31.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. data/bin/nitro +135 -37
  2. data/doc/CHANGELOG.1 +108 -108
  3. data/doc/CHANGELOG.2 +89 -89
  4. data/doc/CHANGELOG.3 +105 -105
  5. data/{CHANGELOG → doc/CHANGELOG.4} +509 -509
  6. data/doc/{AUTHORS → CONTRIBUTORS} +49 -37
  7. data/doc/LIBRARIES +13 -0
  8. data/doc/LICENSE +2 -3
  9. data/doc/MIGRATION +45 -0
  10. data/doc/RELEASES +131 -11
  11. data/doc/TODO +67 -0
  12. data/lib/glue/magick.rb +0 -3
  13. data/lib/glue/sweeper.rb +30 -15
  14. data/lib/glue/thumbnails.rb +0 -2
  15. data/lib/glue/webfile.rb +23 -11
  16. data/lib/nitro.rb +37 -44
  17. data/lib/nitro/adapter/cgi.rb +0 -3
  18. data/lib/nitro/adapter/console.rb +0 -2
  19. data/lib/nitro/adapter/fastcgi.rb +6 -3
  20. data/lib/nitro/adapter/mongrel.rb +97 -58
  21. data/lib/nitro/adapter/script.rb +4 -6
  22. data/lib/nitro/adapter/webrick.rb +33 -87
  23. data/lib/nitro/adapter/webrick/vcr.rb +85 -0
  24. data/lib/nitro/caching.rb +0 -2
  25. data/lib/nitro/caching/actions.rb +0 -2
  26. data/lib/nitro/caching/fragments.rb +0 -2
  27. data/lib/nitro/caching/output.rb +45 -16
  28. data/lib/nitro/caching/proxy.rb +49 -0
  29. data/lib/nitro/cgi.rb +3 -6
  30. data/lib/nitro/cgi/cookie.rb +0 -3
  31. data/lib/nitro/cgi/request.rb +67 -24
  32. data/lib/nitro/cgi/response.rb +0 -2
  33. data/lib/nitro/cgi/{sendfile.rb → send_file.rb} +7 -6
  34. data/lib/nitro/compiler.rb +62 -55
  35. data/lib/nitro/compiler/cleanup.rb +0 -3
  36. data/lib/nitro/compiler/elements.rb +31 -28
  37. data/lib/nitro/compiler/errors.rb +2 -5
  38. data/lib/nitro/compiler/include.rb +10 -8
  39. data/lib/nitro/compiler/layout.rb +0 -2
  40. data/lib/nitro/compiler/localization.rb +0 -2
  41. data/lib/nitro/compiler/markup.rb +14 -6
  42. data/lib/nitro/compiler/morphing.rb +1 -5
  43. data/lib/nitro/compiler/script.rb +2 -4
  44. data/lib/nitro/compiler/squeeze.rb +0 -2
  45. data/lib/nitro/compiler/xslt.rb +0 -2
  46. data/lib/nitro/context.rb +10 -5
  47. data/lib/nitro/control.rb +18 -0
  48. data/lib/nitro/control/attribute.rb +88 -0
  49. data/lib/nitro/control/attribute/checkbox.rb +19 -0
  50. data/lib/nitro/control/attribute/datetime.rb +21 -0
  51. data/lib/nitro/control/attribute/file.rb +20 -0
  52. data/lib/nitro/control/attribute/fixnum.rb +26 -0
  53. data/lib/nitro/control/attribute/float.rb +26 -0
  54. data/lib/nitro/control/attribute/options.rb +38 -0
  55. data/lib/nitro/control/attribute/password.rb +16 -0
  56. data/lib/nitro/control/attribute/text.rb +16 -0
  57. data/lib/nitro/control/attribute/textarea.rb +16 -0
  58. data/lib/nitro/control/none.rb +16 -0
  59. data/lib/nitro/control/relation.rb +53 -0
  60. data/lib/nitro/control/relation/belongs_to.rb +0 -0
  61. data/lib/nitro/control/relation/has_many.rb +97 -0
  62. data/lib/nitro/control/relation/joins_many.rb +0 -0
  63. data/lib/nitro/control/relation/many_to_many.rb +0 -0
  64. data/lib/nitro/control/relation/refers_to.rb +29 -0
  65. data/lib/nitro/controller.rb +7 -296
  66. data/lib/nitro/dispatcher.rb +72 -34
  67. data/lib/nitro/element.rb +36 -10
  68. data/lib/nitro/element/javascript.rb +0 -2
  69. data/lib/nitro/flash.rb +23 -10
  70. data/lib/nitro/global.rb +36 -11
  71. data/lib/nitro/helper.rb +22 -8
  72. data/lib/nitro/helper/benchmark.rb +0 -2
  73. data/lib/nitro/helper/buffer.rb +0 -3
  74. data/lib/nitro/helper/css.rb +12 -0
  75. data/lib/nitro/helper/debug.rb +1 -3
  76. data/lib/nitro/helper/default.rb +1 -0
  77. data/lib/nitro/helper/feed.rb +400 -386
  78. data/lib/nitro/helper/form.rb +246 -116
  79. data/lib/nitro/helper/javascript.rb +28 -2
  80. data/lib/nitro/helper/javascript/morphing.rb +0 -2
  81. data/lib/nitro/helper/javascript/prototype.rb +0 -2
  82. data/lib/nitro/helper/javascript/scriptaculous.rb +0 -1
  83. data/lib/nitro/helper/layout.rb +0 -2
  84. data/lib/nitro/helper/navigation.rb +87 -0
  85. data/lib/nitro/helper/pager.rb +11 -22
  86. data/lib/nitro/helper/table.rb +9 -32
  87. data/lib/nitro/helper/url.rb +104 -0
  88. data/lib/nitro/helper/xhtml.rb +20 -4
  89. data/lib/nitro/helper/xml.rb +0 -2
  90. data/lib/nitro/markup.rb +131 -0
  91. data/lib/nitro/part.rb +52 -7
  92. data/lib/nitro/publishable.rb +328 -0
  93. data/lib/nitro/render.rb +30 -61
  94. data/lib/nitro/router.rb +12 -4
  95. data/lib/nitro/sanitize.rb +48 -0
  96. data/lib/nitro/scaffold.rb +9 -11
  97. data/lib/nitro/scaffold/controller.rb +25 -0
  98. data/lib/nitro/scaffold/model.rb +150 -0
  99. data/lib/nitro/scaffolding.rb +1 -3
  100. data/lib/nitro/server.rb +57 -32
  101. data/lib/nitro/server/drb.rb +16 -2
  102. data/lib/nitro/server/runner.rb +80 -102
  103. data/lib/nitro/service.rb +0 -1
  104. data/lib/nitro/service/xmlrpc.rb +0 -2
  105. data/lib/nitro/session.rb +26 -18
  106. data/lib/nitro/session/drb.rb +2 -16
  107. data/lib/nitro/session/memory.rb +0 -2
  108. data/lib/nitro/template.rb +219 -0
  109. data/lib/nitro/test/assertions.rb +1 -3
  110. data/lib/nitro/test/context.rb +0 -1
  111. data/lib/nitro/test/testcase.rb +0 -1
  112. data/lib/nitro/version.rb +6 -0
  113. data/lib/part/admin.rb +16 -0
  114. data/lib/part/admin/controller.rb +19 -0
  115. data/lib/part/admin/helper.rb +30 -0
  116. data/lib/part/admin/og/controller.rb +114 -0
  117. data/lib/part/admin/og/customize.rb +4 -0
  118. data/lib/part/admin/og/template/index.xhtml +27 -0
  119. data/lib/part/admin/og/template/list.xhtml +38 -0
  120. data/lib/part/admin/og/template/search.xhtml +20 -0
  121. data/lib/part/admin/og/template/update.xhtml +25 -0
  122. data/lib/part/admin/skin.rb +207 -0
  123. data/lib/part/admin/template/denied.xhtml +13 -0
  124. data/lib/part/admin/template/index.xhtml +12 -0
  125. data/lib/part/admin/todo.txt +2 -0
  126. data/proto/public/error.xhtml +4 -2
  127. data/proto/run.rb +0 -2
  128. data/test/glue/tc_webfile.rb +1 -0
  129. data/test/nitro/cgi/tc_request.rb +23 -0
  130. data/test/nitro/helper/tc_feed.rb +0 -3
  131. data/test/nitro/helper/tc_navbar.rb +74 -0
  132. data/test/nitro/helper/tc_table.rb +2 -0
  133. data/test/nitro/tc_cgi.rb +72 -19
  134. data/test/nitro/tc_controller.rb +35 -26
  135. data/test/nitro/tc_controller_aspect.rb +1 -0
  136. data/test/nitro/tc_controller_params.rb +864 -0
  137. data/test/nitro/tc_dispatcher.rb +2 -2
  138. data/test/nitro/tc_element.rb +16 -16
  139. data/test/nitro/tc_flash.rb +3 -3
  140. data/test/nitro/tc_markup.rb +31 -0
  141. data/test/nitro/tc_render.rb +12 -14
  142. data/test/nitro/tc_session.rb +9 -7
  143. data/test/nitro/tc_template.rb +34 -0
  144. metadata +217 -198
  145. data/INSTALL +0 -121
  146. data/ProjectInfo +0 -74
  147. data/README +0 -555
  148. data/doc/apache.txt +0 -9
  149. data/doc/config.txt +0 -28
  150. data/doc/faq.txt +0 -7
  151. data/doc/lhttpd.txt +0 -7
  152. data/lib/nitro/adapter/scgi.rb +0 -239
  153. data/lib/nitro/helper/form/builder.rb +0 -144
  154. data/lib/nitro/helper/form/controls.rb +0 -389
  155. data/lib/nitro/helper/rss.rb +0 -72
  156. data/proto/conf/apache.conf +0 -51
  157. data/proto/public/scaffold/advanced_search.xhtml +0 -30
  158. data/proto/public/scaffold/edit.xhtml +0 -11
  159. data/proto/public/scaffold/form.xhtml +0 -1
  160. data/proto/public/scaffold/index.xhtml +0 -20
  161. data/proto/public/scaffold/list.xhtml +0 -32
  162. data/proto/public/scaffold/new.xhtml +0 -11
  163. data/proto/public/scaffold/search.xhtml +0 -29
  164. data/proto/public/scaffold/view.xhtml +0 -8
  165. data/proto/script/scgi_ctl +0 -221
  166. data/proto/script/scgi_service +0 -128
  167. data/setup.rb +0 -1585
  168. data/src/part/admin.rb +0 -16
  169. data/src/part/admin/controller.rb +0 -81
  170. data/src/part/admin/skin.rb +0 -21
  171. data/src/part/admin/system.css +0 -135
  172. data/src/part/admin/template/denied.xhtml +0 -1
  173. data/src/part/admin/template/index.xhtml +0 -43
  174. data/test/nitro/helper/tc_rss.rb +0 -24
@@ -64,3 +64,5 @@ class TC_TableHelper < Test::Unit::TestCase # :nodoc: all
64
64
  assert_equal res, table
65
65
  end
66
66
  end
67
+
68
+
@@ -12,44 +12,97 @@ require 'nitro/cgi'
12
12
  require 'nitro/cgi/cookie'
13
13
 
14
14
  class String
15
- class << self
16
- def random(size)
17
- s = String.new
18
- size.times {|i| s << (Kernel.rand(26)+25) } # ascii range
19
- s
15
+ class << self
16
+
17
+ begin
18
+ require 'inline'
19
+
20
+ inline do |builder|
21
+ builder.c_raw <<-EOS
22
+ static VALUE rnd(int argc, VALUE* args, VALUE self)
23
+ {
24
+ if (!argc)
25
+ rb_raise(rb_eArgError, "not enough arguments");
26
+ if (argc > 0)
27
+ Check_Type(args[0], T_FIXNUM);
28
+ if (argc > 1)
29
+ Check_Type(args[1], T_FIXNUM);
30
+
31
+ int size = FIX2INT(args[0]);
32
+ int seed = argc > 1 ? FIX2INT(args[1]) : 0;
33
+ int i = 0;
34
+ VALUE str = rb_str_new((char*)0, size);
35
+
36
+ srandom(seed);
37
+
38
+ for (; i < size; i++) {
39
+ RSTRING(str)->ptr[i] = (char)(((random() % ('z' - ' ')) + ' '));
40
+ }
41
+
42
+ return str;
43
+ }
44
+ EOS
45
+ end
46
+
47
+ def random(size, seed = 22)
48
+ return rnd(size.to_i, seed.to_i)
49
+ end
50
+
51
+ rescue Exception => e
52
+ puts "please install Ruby::Inline (gem install RubyInline) to speed up this test"
53
+
54
+ def random(size)
55
+ s = String.new
56
+ range = (' '..'z').to_a
57
+ r_size = range.size
58
+ for i in (0...size)
59
+ s << range[Kernel.rand(r_size)] # ascii range
60
+ end
61
+ s
62
+ end
63
+
20
64
  end
65
+
21
66
  end
22
67
  end
23
68
 
24
69
  class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
25
70
  include Nitro
26
71
 
72
+ def test_rnd
73
+ size = 500
74
+ d = String.random(size)
75
+
76
+ assert_equal size, d.size
77
+ assert d.all? {|x| (' '..'z').include?(x) }, 'has to have ascii, had: ' + d.inspect
78
+ end
79
+
27
80
  class User
28
81
  attr_accessor :name
29
82
  attr_accessor :password
30
83
  end
31
-
84
+
32
85
  def test_parse_query_parameters
33
86
  qs = 'name=tml;id=12354'
34
87
  params = Cgi.parse_query_string(qs)
35
88
  assert_equal 2, params.size
36
89
  assert_equal 'tml', params['name']
37
-
90
+
38
91
  qs = ''
39
92
  params = Cgi.parse_query_string(qs)
40
93
  assert_equal 0, params.size
41
-
94
+
42
95
  qs = nil
43
96
  params = Cgi.parse_query_string(qs)
44
97
  assert_equal 0, params.size
45
-
98
+
46
99
  qs = 'name=tml;arr[]=1;arr[]=2;arr[]=3'
47
100
  params = Cgi.parse_query_string(qs)
48
101
  assert_equal 2, params.size
49
102
  arr = params['arr']
50
103
  assert_equal Array, arr.class
51
104
  assert_equal 3, arr.size
52
-
105
+
53
106
  qs = 'other=1;user.name=gmosx;user.password=hello'
54
107
  params = Cgi.parse_query_string(qs)
55
108
  assert_equal 2, params.size
@@ -64,7 +117,7 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
64
117
  assert_equal 'hello', user.password
65
118
 
66
119
  # Ruby/Scriptaculous compatibility.
67
-
120
+
68
121
  qs = 'other=1;user[name]=gmosx;user[password]=hello'
69
122
  params = Cgi.parse_query_string(qs)
70
123
  assert_equal 2, params.size
@@ -81,7 +134,7 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
81
134
  Cgi.parse_cookies(context)
82
135
  assert_equal 2, context.cookies.size
83
136
  assert_equal '123', context.cookies['nsid']
84
-
137
+
85
138
  context.env = {}
86
139
  context.env['HTTP_COOKIE'] = 'nsid=123; nsid=23123'
87
140
  cookies = Cgi.parse_cookies(context)
@@ -99,7 +152,7 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
99
152
  ctx.response_headers = {
100
153
  'Content-Type' => 'text/html'
101
154
  }
102
-
155
+
103
156
  res = "Status: 200 OK\r\nContent-Type: text/html\r\nSet-Cookie: nauthnauth=gmosx; Path=/\r\nSet-Cookie: nsidnsid=1233; Path=/\r\n\r\n"
104
157
  assert_equal res, Cgi.response_headers(ctx)
105
158
  end
@@ -118,7 +171,7 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
118
171
  boundary = "---------------------------15773515131648678014689318540"
119
172
  closure = "#{Cgi::EOL}--#{boundary}--#{Cgi::EOL}"
120
173
  block_size = Cgi.buffer_size
121
-
174
+
122
175
  input = StringIO.new
123
176
  input << "--#{boundary}#{Cgi::EOL}"
124
177
  input << "Content-Disposition: form-data; name=\"test_file_a\"; filename=\"test_case.txt\"#{Cgi::EOL}Content-Type: application/octet-stream#{Cgi::EOL}#{Cgi::EOL}"
@@ -126,13 +179,13 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
126
179
  input << fake_file_a
127
180
  input_after_fake_file = input.size
128
181
  input << "#{Cgi::EOL}--#{boundary}#{Cgi::EOL}"
129
-
182
+
130
183
  #Boundary fell inbetween two reads?
131
184
  assert_equal((block_size > input_after_fake_file) && (block_size < input.size),true)
132
-
185
+
133
186
  input << "Content-Disposition: form-data; name=\"test_file_b\"; filename=\"test_case.txt\"#{Cgi::EOL}Content-Type: application/octet-stream#{Cgi::EOL}#{Cgi::EOL}"
134
187
  fake_file_b = Tempfile.new("TCCGI")
135
-
188
+
136
189
  i = 0
137
190
  file_size = 1024*1024*10 # 10MB
138
191
  i += fake_file_b.write String.random(1024*10) while i < file_size
@@ -148,12 +201,12 @@ class TestAdapterCgi < Test::Unit::TestCase # :nodoc: all
148
201
  start = Time.now
149
202
  params = Nitro::Cgi.parse_multipart(make_context(input), boundary)
150
203
  duration = Time.now - start
151
- # puts "\nparse_multipart took: #{duration} seconds\n"
204
+ # puts "\nparse_multipart took: #{duration} seconds\n"
152
205
  assert_equal(fake_file_a,params['test_file_a'].to_s)
153
206
  assert_equal(fake_file_b.read,params['test_file_b'].to_s)
154
207
  assert_equal(String.new,params['empty_field'].to_s)
155
208
  end
156
-
209
+
157
210
 
158
211
  def make_context(input)
159
212
  context = OpenStruct.new
@@ -9,13 +9,13 @@ require 'nitro'
9
9
 
10
10
  class TC_Controller < Test::Unit::TestCase # :nodoc: all
11
11
  include Nitro
12
-
13
- class Blog1Controller < Controller
12
+
13
+ class FirstController < Controller
14
14
  def list
15
15
  end
16
16
  end
17
17
 
18
- class Blog2Controller < Controller
18
+ class SecondController < Controller
19
19
  attr_reader :aqflag, :tflag
20
20
 
21
21
  def self.setup_template_root(path)
@@ -25,70 +25,79 @@ class TC_Controller < Test::Unit::TestCase # :nodoc: all
25
25
  def list
26
26
  @aqflag = true
27
27
  end
28
-
28
+
29
29
  def another(oid)
30
- # nop
30
+ # nop
31
31
  end
32
-
33
- private
32
+
33
+ private
34
34
 
35
35
  def encode_myself
36
36
  encode_url :list
37
37
  end
38
38
 
39
- def encode_blog1
40
- encode_url Blog1Controller, :list
39
+ def encode_first
40
+ encode_url FirstController, :list
41
41
  end
42
42
  end
43
-
43
+
44
44
  def setup
45
- @disp = Dispatcher.new({
46
- '/blog' => Blog2Controller,
47
- '/blog1' => Blog1Controller
48
- })
45
+ @disp = Dispatcher.new '/first' => FirstController,
46
+ '/second' => SecondController
49
47
  @conf = OpenStruct.new
50
48
  @conf.dispatcher = @disp
51
49
  end
52
-
50
+
53
51
  def test_render
54
52
  ctx = Context.new(@conf)
55
53
  ctx.headers = {}
56
54
  ctx.params = {}
57
- ctx.headers['REQUEST_URI'] = '/blog/list'
55
+ ctx.headers['REQUEST_URI'] = '/second/list'
58
56
  ctx.instance_eval '@session = {}'
59
57
  klass, action = ctx.dispatcher.dispatch(ctx.path, ctx)
60
58
  c = klass.new(ctx)
61
-
59
+
62
60
  begin
63
61
  c.send(action)
64
62
  rescue RenderExit
65
63
  # drink
66
64
  end
67
65
 
68
- assert_equal('/blog/list', c.send(:encode_myself))
69
- assert_equal('/blog1/list', c.send(:encode_blog1))
66
+ assert_equal('/second/list', c.send(:encode_myself))
67
+ assert_equal('/first/list', c.send(:encode_first))
70
68
 
71
69
  # handle action with arity.
72
- assert_equal('/blog/another/32', c.send(:encode_url, :another, :oid, 32))
70
+ assert_equal('/second/another/32', c.send(:encode_url, :another, :oid, 32))
73
71
 
74
72
  assert_equal true, c.aqflag
73
+ =begin
74
+ # if anybody has an idea what this is for, go, fix it :)
75
75
  assert_equal true, $include1
76
76
  assert_equal true, $include2
77
77
 
78
78
  # the template is compiled
79
79
  assert_equal true, c.tflag
80
+ =end
80
81
  end
81
82
 
82
83
  def test_action_methods
83
- # aflag/tflag are counted too!
84
- # p Blog2Controller.action_methods
85
- # FIXME: the next 5 should be 3!!
86
- # assert_equal 5, Blog2Controller.action_methods.size
87
- assert Blog2Controller.action_methods.include?('list')
84
+ assert_equal ['list'], FirstController.action_methods
85
+ assert_equal 1, FirstController.action_methods.size
86
+ assert_equal 4, SecondController.action_methods.size
87
+ assert FirstController.action_methods.include?('list')
88
+ assert SecondController.action_methods.include?('list')
88
89
  end
89
90
 
90
91
  def test_encode_decode_methods
91
-
92
+
93
+ end
94
+
95
+ def test_mount_path
96
+ assert_equal '/first', FirstController.mount_path
97
+ assert_equal '/second', SecondController.mount_path
98
+ # path is private
99
+ assert_equal '/first', FirstController.allocate.send(:mount_path)
100
+ assert_equal '/second', SecondController.allocate.send(:mount_path)
92
101
  end
93
102
 
94
103
  end
@@ -22,6 +22,7 @@ class TestControllerAspect < Test::Unit::TestCase # :nodoc: all
22
22
  def test_aspect
23
23
  ctx = Context.new(Server.new)
24
24
  ctx.instance_variable_set '@session', {}
25
+ ctx.instance_variable_set '@headers', {}
25
26
  c = TestController.new(ctx)
26
27
  c.list_action
27
28
 
@@ -0,0 +1,864 @@
1
+ require File.join(File.dirname(__FILE__), 'CONFIG.rb')
2
+
3
+ $DBG = true
4
+
5
+ require 'test/unit'
6
+ require 'ostruct'
7
+
8
+ require 'nitro'
9
+ require 'nitro/cgi'
10
+
11
+
12
+ class String
13
+ def clear
14
+ gsub!(/.*/m, '')
15
+ end
16
+ end
17
+
18
+ class TC_ControllerParams < Test::Unit::TestCase # :nodoc: all
19
+
20
+ module Common
21
+ def return_results *arguments
22
+ from = caller[0][/`.*?'/][1..-2].intern
23
+ hash = {}
24
+ request.params.each do |k,v|
25
+ hash[k] = if v.kind_of?(Tempfile) || v.kind_of?(StringIO) || v.kind_of?(IO)
26
+ { :filename => v.original_filename, :size => v.size }
27
+ else
28
+ v
29
+ end
30
+ request.params = hash
31
+ end
32
+
33
+ @out.clear
34
+ @out << {
35
+ :action => from,
36
+ :params => request.params,
37
+ :arguments => arguments,
38
+ :klass => self.class,
39
+ :method => request.method
40
+ }.inspect
41
+ end
42
+ private :return_results
43
+ end # end module Common
44
+
45
+ class TestController < Nitro::Controller
46
+ include Common
47
+
48
+ def index
49
+ return_results
50
+ end
51
+
52
+ # Arity 0
53
+
54
+ def none
55
+ return_results
56
+ end
57
+
58
+ # Arity 1 - 3
59
+
60
+ def single(arg)
61
+ return_results arg
62
+ end
63
+
64
+ def double(arg1, arg2)
65
+ return_results arg1, arg2
66
+ end
67
+
68
+ def triple(arg1, arg2, arg3)
69
+ return_results arg1, arg2, arg3
70
+ end
71
+
72
+ def double__foo(arg)
73
+ return_results arg
74
+ end
75
+
76
+ # Arity -1
77
+
78
+ def m1(*args)
79
+ return_results *args
80
+ end
81
+
82
+ def m1_2(arg1 = nil, arg2 = nil)
83
+ return_results arg1, arg2
84
+ end
85
+
86
+ # Arity -2
87
+
88
+ def m2(klass, parent_symbol = nil, parent_oid = nil, *args)
89
+ return_results klass, parent_symbol, parent_oid, args
90
+ end
91
+
92
+ def m2_2(klass, parent_symbol = nil, parent_oid = nil)
93
+ return_results klass, parent_symbol, parent_oid
94
+ end
95
+
96
+ # Overridden by C2?
97
+
98
+ def c2
99
+ return_results
100
+ end
101
+
102
+ # Error handler
103
+
104
+ def error
105
+ "(error)"
106
+ end
107
+
108
+ end # end class TestController
109
+
110
+ class TestController2 < Nitro::Controller
111
+ include Common
112
+
113
+ def index(arg1 = nil, arg2 = nil)
114
+ return_results arg1, arg2
115
+ end
116
+
117
+ end # end class TestController2
118
+
119
+ module TestTestController3Helper
120
+ def login
121
+ return_results
122
+ end
123
+ end
124
+
125
+ class TestController3 < Nitro::Controller
126
+ include Common
127
+ include TestTestController3Helper
128
+
129
+ def index(arg1)
130
+ return_results arg1
131
+ end
132
+
133
+ def document(oid=nil, del=nil, add=nil)
134
+ return_results oid, del, add
135
+ end
136
+
137
+ def post(one = nil)
138
+ return_results one
139
+ end
140
+
141
+ end # end class TestController2
142
+
143
+
144
+ class TestControllerRouter < Nitro::Controller
145
+ include Common
146
+
147
+ def routed_one(name)
148
+ return_results name
149
+ end
150
+ ::Nitro::Router.add_rule :match => /^\/routed_one\/(.*)/, :controller => TestControllerRouter, :action => :routed_one, :param => :name
151
+
152
+ end
153
+
154
+ #
155
+ # Defined assertions
156
+ #
157
+
158
+ # Check against reference hash, only compare available values
159
+
160
+ def cmp(reference, checked)
161
+ reference.each do |k,v|
162
+ return false if checked[k] != v
163
+ end
164
+
165
+ return true
166
+ end
167
+
168
+ def handle_request(url, value)
169
+ conf = OpenStruct.new
170
+ disp = Nitro::Dispatcher.new(
171
+ '/' => TestController,
172
+ '/c2' => TestController2,
173
+ '/c3' => TestController3,
174
+ '/c4' => TestControllerRouter)
175
+ conf.dispatcher = disp
176
+ @ctx = Nitro::Context.new(conf)
177
+ @ctx.headers = { 'REQUEST_METHOD' => 'GET' }
178
+ @ctx.params = {}
179
+ @ctx.instance_variable_set '@session', {}
180
+
181
+ if value[:in]
182
+ @ctx.in = value.delete(:in)
183
+ @ctx.headers['CONTENT_LENGTH'] = value.delete(:in_size) || @ctx.in.size
184
+ end
185
+
186
+ if value[:method]
187
+ @ctx.headers['REQUEST_METHOD'] = value[:method].to_s
188
+ end
189
+
190
+ if value['CONTENT_TYPE']
191
+ @ctx.headers['CONTENT_TYPE'] = value.delete('CONTENT_TYPE')
192
+ end
193
+
194
+ @ctx.headers['REQUEST_URI'] = url
195
+
196
+ if (!@ctx.query_string || @ctx.query_string.empty?) and @ctx.uri =~ /\?/
197
+ @ctx.headers['QUERY_STRING'] = @ctx.uri.split('?').last
198
+ end
199
+
200
+ Nitro::Cgi.parse_params(@ctx)
201
+ Nitro::Cgi.parse_cookies(@ctx)
202
+
203
+ @ctx.render url
204
+
205
+ #retrieve the stuff from @out again as a hash
206
+ result = @ctx.out
207
+
208
+ return result
209
+ end
210
+
211
+ def assert_request_good(url, value, message = nil)
212
+ result = handle_request(url, value)
213
+
214
+ message = build_message(message, "<?> returned error. \nResult: ?\nInstead of: ?", url, result, value)
215
+
216
+ assert_block message do
217
+ if result =~ /error/
218
+ false
219
+ else
220
+ cmp(value, eval(result))
221
+ end
222
+ end
223
+ end
224
+
225
+ def assert_request_bad(url, value, message = nil)
226
+ result = handle_request(url, value)
227
+
228
+ message = build_message(message, '<?> did not return error.', url)
229
+ assert_block message do
230
+ result = @ctx.out
231
+
232
+ result =~ /error/
233
+ end
234
+ end
235
+
236
+ ###################################################################
237
+ # Simple Testcases
238
+ ###################################################################
239
+
240
+ def test_simple
241
+ tests = {
242
+ '/none' => {
243
+ :action => :none,
244
+ :params => {},
245
+ :arguments => []
246
+ },
247
+ '/single/arg' => {
248
+ :action => :single,
249
+ :params => {},
250
+ :arguments => ['arg']
251
+ },
252
+ '/double/arg1/arg2' => {
253
+ :action => :double,
254
+ :params => {},
255
+ :arguments => ['arg1', 'arg2']
256
+ },
257
+ '/triple/arg1/arg2/arg3' => {
258
+ :action => :triple,
259
+ :params => {},
260
+ :arguments => ['arg1', 'arg2', 'arg3']
261
+ },
262
+ # George: none hase no arity, so the following *IS* valid!
263
+ '/none/one/two' => {
264
+ :action => :none,
265
+ :params => {},
266
+ :arguments => []
267
+ }
268
+ }
269
+
270
+ tests.each do |url, value|
271
+ assert_request_good url, value
272
+ end
273
+ end
274
+
275
+ def test_simple_params
276
+ tests = {
277
+ '/none/?first=one&second=two' => {
278
+ :action => :none,
279
+ :params => {'first' => 'one', 'second' => 'two'},
280
+ :arguments => []
281
+ },
282
+ '/none/?first=one&second=two' => {
283
+ :action => :none,
284
+ :params => {'first' => 'one', 'second' => 'two'},
285
+ :arguments => []
286
+ },
287
+ '/none/?first' => {
288
+ :action => :none,
289
+ :params => {'first' => nil},
290
+ :arguments => []
291
+ },
292
+ '/none/?first&second' => {
293
+ :action => :none,
294
+ :params => {'first' => nil, 'second' => nil},
295
+ :arguments => []
296
+ }
297
+ }
298
+
299
+ tests.each do |url, value|
300
+ assert_request_good url, value
301
+ end
302
+ end
303
+
304
+ def test_simple_bad
305
+ tests = {
306
+ '/single' => {
307
+ :action => :single,
308
+ :params => {},
309
+ :arguments => [],
310
+ :errmsg => 'Too few arguments. Should be one.'
311
+ },
312
+ '/double/arg1' => {
313
+ :action => :double,
314
+ :params => {},
315
+ :arguments => [],
316
+ :errmsg => 'Too few arguments. Should be two.'
317
+ },
318
+ '/triple/arg1/arg2' => {
319
+ :action => :triple,
320
+ :params => {},
321
+ :arguments => [],
322
+ :errmsg => 'Too few arguments. Should be 3.'
323
+ },
324
+ '/triple/arg1/arg2/arg3/arg4' => {
325
+ :action => :triple,
326
+ :params => {},
327
+ :arguments => [],
328
+ :errmsg => 'Too many arguments. Should be 3.'
329
+ }
330
+ }
331
+
332
+ tests.each do |url, value|
333
+ assert_request_bad url, value, value.delete(:errmsg)
334
+ end
335
+ end
336
+
337
+ def test_mixed
338
+ tests = {
339
+ '/single/foo?first=one&second=two' => {
340
+ :action => :single,
341
+ :params => {'first' => 'one', 'second' => 'two'},
342
+ :arguments => ['foo']
343
+ },
344
+ '/double/foo/bar?first=one&second=two' => {
345
+ :action => :double,
346
+ :params => {'first' => 'one', 'second' => 'two'},
347
+ :arguments => ['foo', 'bar']
348
+ }
349
+ }
350
+
351
+ tests.each do |url, value|
352
+ assert_request_good url, value
353
+ end
354
+ end
355
+
356
+ def test_slashes
357
+ tests = {
358
+ '/single/foo' => {
359
+ :action => :single,
360
+ :params => {},
361
+ :arguments => ['foo']
362
+ },
363
+ '/double/foo/bar' => {
364
+ :action => :double__foo,
365
+ :params => {},
366
+ :arguments => []
367
+ },
368
+ '/double/foo/bar/' => {
369
+ :action => :double,
370
+ :params => {},
371
+ :arguments => ['foo', 'bar']
372
+ },
373
+ '/double/foo/bar' => {
374
+ :action => :double,
375
+ :params => {},
376
+ :arguments => ['foo', 'bar']
377
+ },
378
+ '/double/foo/bar/' => {
379
+ :action => :double,
380
+ :params => {},
381
+ :arguments => ['foo', 'bar']
382
+ },
383
+ '/none' => {
384
+ :action => :none,
385
+ :params => {},
386
+ :arguments => []
387
+ },
388
+ '/none/' => {
389
+ :action => :none,
390
+ :params => {},
391
+ :arguments => []
392
+ }
393
+ }
394
+
395
+ tests.each do |url, value|
396
+ assert_request_good url, value
397
+ end
398
+ end
399
+
400
+ ###################################################################
401
+ # Arity -2 tests
402
+ ###################################################################
403
+
404
+ def test_m2
405
+ tests = {
406
+ '/m2/OgModule/user/5' => {
407
+ :action => :m2,
408
+ :params => {},
409
+ :arguments => ['OgModule', 'user', '5', []]
410
+ },
411
+ '/m2/OgModule' => {
412
+ :action => :m2,
413
+ :params => {},
414
+ :arguments => ['OgModule', nil, nil, []]
415
+ },
416
+ '/m2/OgModule/' => {
417
+ :action => :m2,
418
+ :params => {},
419
+ :arguments => ['OgModule', nil, nil, []]
420
+ },
421
+ '/m2/OgModule/user/5/more/garbage' => {
422
+ :action => :m2,
423
+ :params => {},
424
+ :arguments => ['OgModule', 'user', '5', ['more', 'garbage']]
425
+ },
426
+ '/m2_2/OgModule/user/5' => {
427
+ :action => :m2_2,
428
+ :params => {},
429
+ :arguments => ['OgModule', 'user', '5']
430
+ },
431
+ '/m2_2/OgModule' => {
432
+ :action => :m2_2,
433
+ :params => {},
434
+ :arguments => ['OgModule', nil, nil]
435
+ }
436
+ }
437
+
438
+ tests.each do |url, value|
439
+ assert_request_good url, value
440
+ end
441
+ end
442
+
443
+ def test_m2_bad
444
+ tests = {
445
+ '/m2_2/OgModule/user/5/foo/bar' => {
446
+ :action => :m2_2,
447
+ :params => {},
448
+ :arguments => [],
449
+ :errmsg => 'Too many arguments.'
450
+ },
451
+ '/m2_2/' => {
452
+ :action => :m2_2,
453
+ :params => {},
454
+ :arguments => [],
455
+ :errmsg => 'Not enough arguments.'
456
+ },
457
+ '/m2' => {
458
+ :action => :m2,
459
+ :params => {},
460
+ :arguments => [],
461
+ :errmsg => 'Not enough arguments.'
462
+ }
463
+ }
464
+
465
+ tests.each do |url, value|
466
+ assert_request_bad url, value, value.delete(:errmsg)
467
+ end
468
+ end
469
+
470
+ ###################################################################
471
+ # Arity -1 Tests
472
+ ###################################################################
473
+
474
+ def test_m1
475
+ tests = {
476
+ '/m1_2/' => {
477
+ :action => :m1_2,
478
+ :params => {},
479
+ :arguments => [nil, nil]
480
+ },
481
+ '/m1_2' => {
482
+ :action => :m1_2,
483
+ :params => {},
484
+ :arguments => [nil, nil]
485
+ },
486
+ '/m1_2/One' => {
487
+ :action => :m1_2,
488
+ :params => {},
489
+ :arguments => ['One', nil]
490
+ },
491
+ '/m1_2/One/Two' => {
492
+ :action => :m1_2,
493
+ :params => {},
494
+ :arguments => ['One', 'Two']
495
+ },
496
+ }
497
+
498
+ tests.each do |url, value|
499
+ assert_request_good url, value
500
+ end
501
+ end
502
+
503
+ def test_sub_zero_mixed
504
+ tests = {
505
+ '/m1/OgModule/user/5?more=garbage' => {
506
+ :action => :m1,
507
+ :params => {'more' => 'garbage'},
508
+ :arguments => ['OgModule', 'user', '5']
509
+ },
510
+ '/m2/OgModule/user/5?more=garbage' => {
511
+ :action => :m2,
512
+ :params => {'more' => 'garbage'},
513
+ :arguments => ['OgModule', 'user', '5', []]
514
+ },
515
+ '/m2/OgModule?more=garbage' => {
516
+ :action => :m2,
517
+ :params => {'more' => 'garbage'},
518
+ :arguments => ['OgModule', nil, nil, []]
519
+ }
520
+ }
521
+
522
+ tests.each do |url, value|
523
+ assert_request_good url, value
524
+ end
525
+ end
526
+
527
+ ###################################################################
528
+ # Used Controller Tests
529
+ ###################################################################
530
+
531
+ def test_controllers
532
+ tests = {
533
+ '/c2' => {
534
+ :action => :index,
535
+ :klass => TestController2,
536
+ :arguments => [nil, nil]
537
+ },
538
+ '/c2/' => {
539
+ :action => :index,
540
+ :klass => TestController2,
541
+ :arguments => [nil, nil]
542
+ },
543
+ '/' => {
544
+ :action => :index,
545
+ :klass => TestController
546
+ }
547
+ }
548
+
549
+ tests.each do |url, value|
550
+ assert_request_good url, value
551
+ end
552
+ end
553
+
554
+ def test_index_handling
555
+ tests = {
556
+ '/c2/One' => {
557
+ :action => :index,
558
+ :klass => TestController2,
559
+ :arguments => ['One', nil]
560
+ },
561
+ '/c2/One/Two' => {
562
+ :action => :index,
563
+ :klass => TestController2,
564
+ :arguments => ['One', 'Two']
565
+ },
566
+ '/c2/index/One' => {
567
+ :action => :index,
568
+ :klass => TestController2,
569
+ :arguments => ['One', nil]
570
+ },
571
+ '/c2/index/One/Two' => {
572
+ :action => :index,
573
+ :klass => TestController2,
574
+ :arguments => ['One', 'Two']
575
+ },
576
+ '/c3/index/One' => {
577
+ :action => :index,
578
+ :klass => TestController3,
579
+ :arguments => ['One']
580
+ },
581
+ '/c3/One' => {
582
+ :action => :index,
583
+ :klass => TestController3,
584
+ :arguments => ['One']
585
+ }
586
+ }
587
+
588
+ tests.each do |url, value|
589
+ assert_request_good url, value
590
+ end
591
+ end
592
+
593
+ def test_index_handling_bad
594
+ tests = {
595
+ '/c2/One/Two/Three' => {
596
+ :action => :index,
597
+ :klass => TestController2
598
+ },
599
+ '/c2/index/One/Two/Three' => {
600
+ :action => :index,
601
+ :klass => TestController2
602
+ },
603
+ '/c3/One/Two' => {
604
+ :action => :index,
605
+ :klass => TestController3
606
+ },
607
+ '/c3' => {
608
+ :action => :index,
609
+ :klass => TestController3
610
+ },
611
+ '/c3/index' => {
612
+ :action => :index,
613
+ :klass => TestController3
614
+ }
615
+ }
616
+
617
+ tests.each do |url, value|
618
+ assert_request_bad url, value
619
+ end
620
+ end
621
+
622
+ ###################################################################
623
+ # Test Bug Reports
624
+ ###################################################################
625
+
626
+ def test_bug_report_ray
627
+ tests = {
628
+ '/c3/document/new/1' => {
629
+ :action => :document,
630
+ :klass => TestController3,
631
+ :arguments => ['new', '1', nil]
632
+ }
633
+ }
634
+
635
+ tests.each do |url, value|
636
+ assert_request_good url, value
637
+ end
638
+ end
639
+
640
+ def test_bug_report_fabian
641
+ tests = {
642
+ '/c3/login' => {
643
+ :action => :login,
644
+ :klass => TestController3,
645
+ :arguments => []
646
+ }
647
+ }
648
+
649
+ assert TestController3.ancestors.include?(TestTestController3Helper)
650
+ assert TestController3.instance_methods.include?('login')
651
+ assert TestController3.action_methods.include?('login')
652
+
653
+ tests.each do |url, value|
654
+ assert_request_good url, value
655
+ end
656
+
657
+ end
658
+
659
+ ###################################################################
660
+ # Test Routed Parameters
661
+ ###################################################################
662
+
663
+ def test_routed_one
664
+ tests = {
665
+ '/routed_one/some/name/I/got/here...' => {
666
+ :action => :routed_one,
667
+ :klass => TestControllerRouter,
668
+ :arguments => ['some/name/I/got/here...'],
669
+ :params => {}
670
+ }
671
+ }
672
+
673
+ tests.each do |url, value|
674
+ assert_request_good url, value
675
+ end
676
+ end
677
+
678
+ ###################################################################
679
+ # Mix-in GET Parameter Tests
680
+ ###################################################################
681
+
682
+ def test_mixin_get_parameters
683
+ ::Nitro::Compiler.mixin_get_parameters = true
684
+
685
+ tests = {
686
+ '/double?arg1=bar;arg2=foo' => {
687
+ :action => :double,
688
+ :params => {'arg1' => 'bar', 'arg2' => 'foo'},
689
+ :arguments => ['bar', 'foo']
690
+ }
691
+ }
692
+
693
+ tests.each do |url, value|
694
+ assert_request_good url, value
695
+ end
696
+ ensure
697
+ ::Nitro::Compiler.mixin_get_parameters = false
698
+ end
699
+
700
+ ###################################################################
701
+ # Non-strict Action Calling Tests
702
+ ###################################################################
703
+
704
+ def test_non_strict_action_calling
705
+ ::Nitro::Compiler.non_strict_action_calling = true
706
+
707
+ tests = {
708
+ '/double' => {
709
+ :action => :double,
710
+ :params => {},
711
+ :arguments => [nil, nil]
712
+ }
713
+ }
714
+
715
+ tests.each do |url, value|
716
+ assert_request_good url, value
717
+ end
718
+ ensure
719
+ ::Nitro::Compiler.non_strict_action_calling = false
720
+ end
721
+
722
+ ###################################################################
723
+ # Test POST Multipart
724
+ ###################################################################
725
+
726
+ def test_multipart
727
+ tests = {
728
+ '/c3/post' => {
729
+ :action => :post,
730
+ :klass => TestController3,
731
+ :arguments => [nil],
732
+ :params => {"test_file_a" => {:size=>10028,
733
+ :filename=>"test_case.txt"},
734
+ "test_file_b" => {:size=>10240,
735
+ :filename=>"test_case.txt"},
736
+ "empty_field" => {:size=>0, :filename=>""}},
737
+ :method => :post
738
+ },
739
+ '/c3/post/1' => {
740
+ :action => :post,
741
+ :klass => TestController3,
742
+ :arguments => ['1'],
743
+ :params => {"test_file_a" => {:size=>10028,
744
+ :filename=>"test_case.txt"},
745
+ "test_file_b" => {:size=>10240,
746
+ :filename=>"test_case.txt"},
747
+ "empty_field" => {:size=>0, :filename=>""}},
748
+ :method => :post
749
+ },
750
+ '/c3/post/1?more=data' => {
751
+ :action => :post,
752
+ :klass => TestController3,
753
+ :arguments => ['1'],
754
+ :params => {"test_file_a" => {:size=>10028,
755
+ :filename=>"test_case.txt"},
756
+ "test_file_b" => {:size=>10240,
757
+ :filename=>"test_case.txt"},
758
+ "empty_field" => {:size=>0, :filename=>""},
759
+ "more" => "data"},
760
+ :method => :post
761
+ }
762
+ }
763
+
764
+ tests.each do |url, value|
765
+ create_multipart(value)
766
+ assert_request_good url, value
767
+ end
768
+ end
769
+
770
+ def create_multipart(options, boundary = "---------------------------15773515131648678014689318540")
771
+ # MIME block close falls on read boundary, also contains an empty field.
772
+ closure = "#{Nitro::Cgi::EOL}--#{boundary}--#{Nitro::Cgi::EOL}"
773
+ block_size = Nitro::Cgi.buffer_size
774
+
775
+ input = StringIO.new
776
+ input << "--#{boundary}#{Nitro::Cgi::EOL}"
777
+ input << "Content-Disposition: form-data; name=\"test_file_a\"; filename=\"test_case.txt\"#{Nitro::Cgi::EOL}Content-Type: application/octet-stream#{Nitro::Cgi::EOL}#{Nitro::Cgi::EOL}"
778
+ fake_file_a = String.random(block_size - input.size - (closure.size/2))
779
+ input << fake_file_a
780
+ input_after_fake_file = input.size
781
+ input << "#{Nitro::Cgi::EOL}--#{boundary}#{Nitro::Cgi::EOL}"
782
+
783
+ #Boundary fell inbetween two reads?
784
+ assert_equal((block_size > input_after_fake_file) && (block_size < input.size),true)
785
+
786
+ input << "Content-Disposition: form-data; name=\"test_file_b\"; filename=\"test_case.txt\"#{Nitro::Cgi::EOL}Content-Type: application/octet-stream#{Nitro::Cgi::EOL}#{Nitro::Cgi::EOL}"
787
+ fake_file_b = Tempfile.new("TCCGI")
788
+
789
+ i = 0
790
+ file_size = 1024*10 # 1MB
791
+ i += fake_file_b.write String.random(1024*10) while i < file_size
792
+
793
+ fake_file_b.rewind
794
+ input << fake_file_b.read
795
+ fake_file_b.rewind
796
+ input << "#{Nitro::Cgi::EOL}--#{boundary}#{Nitro::Cgi::EOL}"
797
+
798
+ input << "Content-Disposition: form-data; name=\"empty_field\"#{Nitro::Cgi::EOL}#{Nitro::Cgi::EOL}"
799
+ input << closure
800
+ input.rewind
801
+
802
+ options[:in] = input
803
+ options[:in_size] = input.size
804
+ options['CONTENT_TYPE'] = "multipart/form-data boundary=\"#{boundary}\""
805
+ end
806
+
807
+ end
808
+
809
+ # Random data for multipart param test
810
+
811
+ class String
812
+ class << self
813
+
814
+ begin
815
+ require 'inline'
816
+
817
+ inline do |builder|
818
+ builder.c_raw <<-EOS
819
+ static VALUE rnd(int argc, VALUE* args, VALUE self)
820
+ {
821
+ if (!argc)
822
+ rb_raise(rb_eArgError, "not enough arguments");
823
+ if (argc > 0)
824
+ Check_Type(args[0], T_FIXNUM);
825
+ if (argc > 1)
826
+ Check_Type(args[1], T_FIXNUM);
827
+
828
+ int size = FIX2INT(args[0]);
829
+ int seed = argc > 1 ? FIX2INT(args[1]) : 0;
830
+ int i = 0;
831
+ VALUE str = rb_str_new((char*)0, size);
832
+
833
+ srandom(seed);
834
+
835
+ for (; i < size; i++) {
836
+ RSTRING(str)->ptr[i] = (char)(((random() % ('z' - ' ')) + ' '));
837
+ }
838
+
839
+ return str;
840
+ }
841
+ EOS
842
+ end
843
+
844
+ def random(size, seed = 22)
845
+ return rnd(size.to_i, seed.to_i)
846
+ end
847
+
848
+ rescue Exception => e
849
+ puts "please install Ruby::Inline (gem install RubyInline) to speed up this test"
850
+
851
+ def random(size)
852
+ s = String.new
853
+ range = (' '..'z').to_a
854
+ r_size = range.size
855
+ for i in (0...size)
856
+ s << range[Kernel.rand(r_size)] # ascii range
857
+ end
858
+ s
859
+ end
860
+
861
+ end
862
+
863
+ end
864
+ end