aldebaran 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/.gitignore +13 -0
  2. data/.travis.yml +16 -0
  3. data/.yardopts +4 -0
  4. data/AUTHORS +4 -0
  5. data/Gemfile +77 -0
  6. data/KNOWN_ISSUES +5 -0
  7. data/LICENSE +22 -0
  8. data/README.rdoc +1900 -0
  9. data/Rakefile +175 -0
  10. data/aldebaran.gemspec +19 -0
  11. data/lib/aldebaran.rb +7 -0
  12. data/lib/aldebaran/base.rb +1600 -0
  13. data/lib/aldebaran/images/404.png +0 -0
  14. data/lib/aldebaran/images/500.png +0 -0
  15. data/lib/aldebaran/main.rb +28 -0
  16. data/lib/aldebaran/showexceptions.rb +340 -0
  17. data/lib/aldebaran/version.rb +3 -0
  18. data/test/aldebaran_test.rb +17 -0
  19. data/test/base_test.rb +160 -0
  20. data/test/builder_test.rb +95 -0
  21. data/test/coffee_test.rb +92 -0
  22. data/test/contest.rb +98 -0
  23. data/test/creole_test.rb +65 -0
  24. data/test/delegator_test.rb +162 -0
  25. data/test/encoding_test.rb +20 -0
  26. data/test/erb_test.rb +104 -0
  27. data/test/extensions_test.rb +100 -0
  28. data/test/filter_test.rb +397 -0
  29. data/test/haml_test.rb +101 -0
  30. data/test/helper.rb +115 -0
  31. data/test/helpers_test.rb +1192 -0
  32. data/test/less_test.rb +67 -0
  33. data/test/liquid_test.rb +59 -0
  34. data/test/mapped_error_test.rb +259 -0
  35. data/test/markaby_test.rb +80 -0
  36. data/test/markdown_test.rb +81 -0
  37. data/test/middleware_test.rb +68 -0
  38. data/test/nokogiri_test.rb +69 -0
  39. data/test/public/favicon.ico +0 -0
  40. data/test/radius_test.rb +59 -0
  41. data/test/rdoc_test.rb +65 -0
  42. data/test/readme_test.rb +136 -0
  43. data/test/request_test.rb +45 -0
  44. data/test/response_test.rb +61 -0
  45. data/test/result_test.rb +98 -0
  46. data/test/route_added_hook_test.rb +59 -0
  47. data/test/routing_test.rb +1096 -0
  48. data/test/sass_test.rb +115 -0
  49. data/test/scss_test.rb +88 -0
  50. data/test/server_test.rb +48 -0
  51. data/test/settings_test.rb +493 -0
  52. data/test/slim_test.rb +98 -0
  53. data/test/static_test.rb +178 -0
  54. data/test/streaming_test.rb +100 -0
  55. data/test/templates_test.rb +298 -0
  56. data/test/textile_test.rb +65 -0
  57. data/test/views/a/in_a.str +1 -0
  58. data/test/views/ascii.erb +2 -0
  59. data/test/views/b/in_b.str +1 -0
  60. data/test/views/calc.html.erb +1 -0
  61. data/test/views/error.builder +3 -0
  62. data/test/views/error.erb +3 -0
  63. data/test/views/error.haml +3 -0
  64. data/test/views/error.sass +2 -0
  65. data/test/views/explicitly_nested.str +1 -0
  66. data/test/views/foo/hello.test +1 -0
  67. data/test/views/hello.builder +1 -0
  68. data/test/views/hello.coffee +1 -0
  69. data/test/views/hello.creole +1 -0
  70. data/test/views/hello.erb +1 -0
  71. data/test/views/hello.haml +1 -0
  72. data/test/views/hello.less +5 -0
  73. data/test/views/hello.liquid +1 -0
  74. data/test/views/hello.mab +1 -0
  75. data/test/views/hello.md +1 -0
  76. data/test/views/hello.nokogiri +1 -0
  77. data/test/views/hello.radius +1 -0
  78. data/test/views/hello.rdoc +1 -0
  79. data/test/views/hello.sass +2 -0
  80. data/test/views/hello.scss +3 -0
  81. data/test/views/hello.slim +1 -0
  82. data/test/views/hello.str +1 -0
  83. data/test/views/hello.test +1 -0
  84. data/test/views/hello.textile +1 -0
  85. data/test/views/layout2.builder +3 -0
  86. data/test/views/layout2.erb +2 -0
  87. data/test/views/layout2.haml +2 -0
  88. data/test/views/layout2.liquid +2 -0
  89. data/test/views/layout2.mab +2 -0
  90. data/test/views/layout2.nokogiri +3 -0
  91. data/test/views/layout2.radius +2 -0
  92. data/test/views/layout2.slim +3 -0
  93. data/test/views/layout2.str +2 -0
  94. data/test/views/layout2.test +1 -0
  95. data/test/views/nested.str +1 -0
  96. data/test/views/utf8.erb +2 -0
  97. metadata +231 -0
@@ -0,0 +1,98 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'slim'
5
+
6
+ class SlimTest < Test::Unit::TestCase
7
+ def slim_app(&block)
8
+ mock_app {
9
+ set :views, File.dirname(__FILE__) + '/views'
10
+ get '/', &block
11
+ }
12
+ get '/'
13
+ end
14
+
15
+ it 'renders inline slim strings' do
16
+ slim_app { slim "h1 Hiya\n" }
17
+ assert ok?
18
+ assert_equal "<h1>Hiya</h1>", body
19
+ end
20
+
21
+ it 'renders .slim files in views path' do
22
+ slim_app { slim :hello }
23
+ assert ok?
24
+ assert_equal "<h1>Hello From Slim</h1>", body
25
+ end
26
+
27
+ it "renders with inline layouts" do
28
+ mock_app {
29
+ layout { %(h1\n | THIS. IS. \n == yield.upcase ) }
30
+ get('/') { slim 'em Sparta' }
31
+ }
32
+ get '/'
33
+ assert ok?
34
+ assert_equal "<h1>THIS. IS. <EM>SPARTA</EM></h1>", body
35
+ end
36
+
37
+ it "renders with file layouts" do
38
+ slim_app {
39
+ slim '| Hello World', :layout => :layout2
40
+ }
41
+ assert ok?
42
+ assert_equal "<h1>Slim Layout!</h1><p>Hello World</p>", body
43
+ end
44
+
45
+ it "raises error if template not found" do
46
+ mock_app {
47
+ get('/') { slim :no_such_template }
48
+ }
49
+ assert_raise(Errno::ENOENT) { get('/') }
50
+ end
51
+
52
+ HTML4_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"
53
+
54
+ it "passes slim options to the slim engine" do
55
+ mock_app {
56
+ get '/' do
57
+ slim "doctype html\nh1 Hello World", :format => :html4
58
+ end
59
+ }
60
+ get '/'
61
+ assert ok?
62
+ assert_equal "#{HTML4_DOCTYPE}<h1>Hello World</h1>", body
63
+ end
64
+
65
+ it "passes default slim options to the slim engine" do
66
+ mock_app {
67
+ set :slim, {:format => :html4}
68
+ get '/' do
69
+ slim "doctype html\nh1 Hello World"
70
+ end
71
+ }
72
+ get '/'
73
+ assert ok?
74
+ assert_equal "#{HTML4_DOCTYPE}<h1>Hello World</h1>", body
75
+ end
76
+
77
+ it "merges the default slim options with the overrides and passes them to the slim engine" do
78
+ mock_app {
79
+ set :slim, {:format => :html4}
80
+ get '/' do
81
+ slim "doctype html\nh1.header Hello World"
82
+ end
83
+ get '/html5' do
84
+ slim "doctype html\nh1.header Hello World", :format => :html5
85
+ end
86
+ }
87
+ get '/'
88
+ assert ok?
89
+ assert_match(/^#{HTML4_DOCTYPE}/, body)
90
+ get '/html5'
91
+ assert ok?
92
+ assert_equal "<!DOCTYPE html><h1 class=\"header\">Hello World</h1>", body
93
+ end
94
+ end
95
+
96
+ rescue LoadError
97
+ warn "#{$!.to_s}: skipping slim tests"
98
+ end
@@ -0,0 +1,178 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class StaticTest < Test::Unit::TestCase
4
+ setup do
5
+ mock_app {
6
+ set :static, true
7
+ set :public_folder, File.dirname(__FILE__)
8
+ }
9
+ end
10
+
11
+ it 'serves GET requests for files in the public directory' do
12
+ get "/#{File.basename(__FILE__)}"
13
+ assert ok?
14
+ assert_equal File.read(__FILE__), body
15
+ assert_equal File.size(__FILE__).to_s, response['Content-Length']
16
+ assert response.headers.include?('Last-Modified')
17
+ end
18
+
19
+ it 'produces a body that can be iterated over multiple times' do
20
+ env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
21
+ status, headers, body = @app.call(env)
22
+ buf1, buf2 = [], []
23
+ body.each { |part| buf1 << part }
24
+ body.each { |part| buf2 << part }
25
+ assert_equal buf1.join, buf2.join
26
+ assert_equal File.read(__FILE__), buf1.join
27
+ end
28
+
29
+ it 'sets the aldebaran.static_file env variable if served' do
30
+ env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
31
+ status, headers, body = @app.call(env)
32
+ assert_equal File.expand_path(__FILE__), env['aldebaran.static_file']
33
+ end
34
+
35
+ it 'serves HEAD requests for files in the public directory' do
36
+ head "/#{File.basename(__FILE__)}"
37
+ assert ok?
38
+ assert_equal '', body
39
+ assert_equal File.size(__FILE__).to_s, response['Content-Length']
40
+ assert response.headers.include?('Last-Modified')
41
+ end
42
+
43
+ %w[POST PUT DELETE].each do |verb|
44
+ it "does not serve #{verb} requests" do
45
+ send verb.downcase, "/#{File.basename(__FILE__)}"
46
+ assert_equal 404, status
47
+ end
48
+ end
49
+
50
+ it 'serves files in preference to custom routes' do
51
+ @app.get("/#{File.basename(__FILE__)}") { 'Hello World' }
52
+ get "/#{File.basename(__FILE__)}"
53
+ assert ok?
54
+ assert body != 'Hello World'
55
+ end
56
+
57
+ it 'does not serve directories' do
58
+ get "/"
59
+ assert not_found?
60
+ end
61
+
62
+ it 'passes to the next handler when the static option is disabled' do
63
+ @app.set :static, false
64
+ get "/#{File.basename(__FILE__)}"
65
+ assert not_found?
66
+ end
67
+
68
+ it 'passes to the next handler when the public option is nil' do
69
+ @app.set :public_folder, nil
70
+ get "/#{File.basename(__FILE__)}"
71
+ assert not_found?
72
+ end
73
+
74
+ it '404s when a file is not found' do
75
+ get "/foobarbaz.txt"
76
+ assert not_found?
77
+ end
78
+
79
+ it 'serves files when .. path traverses within public directory' do
80
+ get "/data/../#{File.basename(__FILE__)}"
81
+ assert ok?
82
+ assert_equal File.read(__FILE__), body
83
+ end
84
+
85
+ it '404s when .. path traverses outside of public directory' do
86
+ mock_app {
87
+ set :static, true
88
+ set :public_folder, File.dirname(__FILE__) + '/data'
89
+ }
90
+ get "/../#{File.basename(__FILE__)}"
91
+ assert not_found?
92
+ end
93
+
94
+ def assert_valid_range(http_range, range, path, file)
95
+ request = Rack::MockRequest.new(@app)
96
+ response = request.get("/#{File.basename(path)}", 'HTTP_RANGE' => http_range)
97
+
98
+ should_be = file[range]
99
+ expected_range = "bytes #{range.begin}-#{range.end}/#{file.length}"
100
+
101
+ assert_equal 206,response.status, "Should be HTTP/1.1 206 Partial content"
102
+ assert_equal should_be.length, response.body.length, "Unexpected response length for #{http_range}"
103
+ assert_equal should_be, response.body, "Unexpected response data for #{http_range}"
104
+ assert_equal should_be.length.to_s, response['Content-Length'], "Incorrect Content-Length for #{http_range}"
105
+ assert_equal expected_range, response['Content-Range'], "Incorrect Content-Range for #{http_range}"
106
+ end
107
+
108
+ it 'handles valid byte ranges correctly' do
109
+ # Use the biggest file in this dir so we can test ranges > 8k bytes. (StaticFile sends in 8k chunks.)
110
+ path = File.dirname(__FILE__) + '/helpers_test.rb' # currently 16k bytes
111
+ file = File.read(path)
112
+ length = file.length
113
+ assert length > 9000, "The test file #{path} is too short (#{length} bytes) to run these tests"
114
+
115
+ [0..0, 42..88, 1234..1234, 100..9000, 0..(length-1), (length-1)..(length-1)].each do |range|
116
+ assert_valid_range("bytes=#{range.begin}-#{range.end}", range, path, file)
117
+ end
118
+
119
+ [0, 100, length-100, length-1].each do |start|
120
+ assert_valid_range("bytes=#{start}-", (start..length-1), path, file)
121
+ end
122
+
123
+ [1, 100, length-100, length-1, length].each do |range_length|
124
+ assert_valid_range("bytes=-#{range_length}", (length-range_length..length-1), path, file)
125
+ end
126
+
127
+ # Some valid ranges that exceed the length of the file:
128
+ assert_valid_range("bytes=100-999999", (100..length-1), path, file)
129
+ assert_valid_range("bytes=100-#{length}", (100..length-1), path, file)
130
+ assert_valid_range("bytes=-#{length}", (0..length-1), path, file)
131
+ assert_valid_range("bytes=-#{length+1}", (0..length-1), path, file)
132
+ assert_valid_range("bytes=-999999", (0..length-1), path, file)
133
+ end
134
+
135
+ it 'correctly ignores syntactically invalid range requests' do
136
+ # ...and also ignores multi-range requests, which aren't supported yet
137
+ ["bytes=45-40", "bytes=IV-LXVI", "octets=10-20", "bytes=-", "bytes=1-2,3-4"].each do |http_range|
138
+ request = Rack::MockRequest.new(@app)
139
+ response = request.get("/#{File.basename(__FILE__)}", 'HTTP_RANGE' => http_range)
140
+
141
+ assert_equal 200,response.status, "Invalid range '#{http_range}' should be ignored"
142
+ assert_equal nil,response['Content-Range'], "Invalid range '#{http_range}' should be ignored"
143
+ end
144
+ end
145
+
146
+ it 'returns error 416 for unsatisfiable range requests' do
147
+ # An unsatisfiable request is one that specifies a start that's at or past the end of the file.
148
+ length = File.read(__FILE__).length
149
+ ["bytes=888888-", "bytes=888888-999999", "bytes=#{length}-#{length}"].each do |http_range|
150
+ request = Rack::MockRequest.new(@app)
151
+ response = request.get("/#{File.basename(__FILE__)}", 'HTTP_RANGE' => http_range)
152
+
153
+ assert_equal 416,response.status, "Unsatisfiable range '#{http_range}' should return 416"
154
+ assert_equal "bytes */#{length}",response['Content-Range'], "416 response should include actual length"
155
+ end
156
+ end
157
+
158
+ it 'does not include static cache control headers by default' do
159
+ env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
160
+ status, headers, body = @app.call(env)
161
+ assert !headers.has_key?('Cache-Control')
162
+ end
163
+
164
+ it 'sets cache control headers on static files if set' do
165
+ @app.set :static_cache_control, :public
166
+ env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
167
+ status, headers, body = @app.call(env)
168
+ assert headers.has_key?('Cache-Control')
169
+ assert_equal headers['Cache-Control'], 'public'
170
+
171
+ @app.set :static_cache_control, [:public, :must_revalidate, {:max_age => 300}]
172
+ env = Rack::MockRequest.env_for("/#{File.basename(__FILE__)}")
173
+ status, headers, body = @app.call(env)
174
+ assert headers.has_key?('Cache-Control')
175
+ assert_equal headers['Cache-Control'], 'public, must-revalidate, max-age=300'
176
+ end
177
+
178
+ end
@@ -0,0 +1,100 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class StreamingTest < Test::Unit::TestCase
4
+ Stream = aldebaran::Helpers::Stream
5
+
6
+ it 'returns the concatinated body' do
7
+ mock_app do
8
+ get '/' do
9
+ stream do |out|
10
+ out << "Hello" << " "
11
+ out << "World!"
12
+ end
13
+ end
14
+ end
15
+
16
+ get('/')
17
+ assert_body "Hello World!"
18
+ end
19
+
20
+ it 'always yields strings' do
21
+ stream = Stream.new { |out| out << :foo }
22
+ stream.each { |str| assert_equal 'foo', str }
23
+ end
24
+
25
+ it 'postpones body generation' do
26
+ step = 0
27
+
28
+ stream = Stream.new do |out|
29
+ 10.times do
30
+ out << step
31
+ step += 1
32
+ end
33
+ end
34
+
35
+ stream.each do |s|
36
+ assert_equal s, step.to_s
37
+ step += 1
38
+ end
39
+ end
40
+
41
+ it 'calls the callback after it is done' do
42
+ step = 0
43
+ final = 0
44
+ stream = Stream.new { |o| 10.times { step += 1 }}
45
+ stream.callback { final = step }
46
+ stream.each { |str| }
47
+ assert_equal 10, final
48
+ end
49
+
50
+ it 'does not trigger the callback if close is set to false' do
51
+ step = 0
52
+ final = 0
53
+ stream = Stream.new(Stream, false) { |o| 10.times { step += 1 } }
54
+ stream.callback { final = step }
55
+ stream.each { |str| }
56
+ assert_equal 0, final
57
+ end
58
+
59
+ class MockScheduler
60
+ def initialize(*) @schedule, @defer = [], [] end
61
+ def schedule(&block) @schedule << block end
62
+ def defer(&block) @defer << block end
63
+ def schedule!(*) @schedule.pop.call until @schedule.empty? end
64
+ def defer!(*) @defer.pop.call until @defer.empty? end
65
+ end
66
+
67
+ it 'allows dropping in another scheduler' do
68
+ scheduler = MockScheduler.new
69
+ processing = sending = done = false
70
+
71
+ stream = Stream.new(scheduler) do |out|
72
+ processing = true
73
+ out << :foo
74
+ end
75
+
76
+ stream.each { sending = true}
77
+ stream.callback { done = true }
78
+
79
+ scheduler.schedule!
80
+ assert !processing
81
+ assert !sending
82
+ assert !done
83
+
84
+ scheduler.defer!
85
+ assert processing
86
+ assert !sending
87
+ assert !done
88
+
89
+ scheduler.schedule!
90
+ assert sending
91
+ assert done
92
+ end
93
+
94
+ it 'schedules exceptions to be raised on the main thread/event loop/...' do
95
+ scheduler = MockScheduler.new
96
+ Stream.new(scheduler) { fail 'should be caught' }.each { }
97
+ scheduler.defer!
98
+ assert_raise(RuntimeError) { scheduler.schedule! }
99
+ end
100
+ end
@@ -0,0 +1,298 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path('../helper', __FILE__)
3
+ File.delete(File.dirname(__FILE__) + '/views/layout.test') rescue nil
4
+
5
+ class TestTemplate < Tilt::Template
6
+ def prepare
7
+ end
8
+
9
+ def evaluate(scope, locals={}, &block)
10
+ inner = block ? block.call : ''
11
+ data + inner
12
+ end
13
+
14
+ Tilt.register 'test', self
15
+ end
16
+
17
+ class TemplatesTest < Test::Unit::TestCase
18
+ def render_app(base=aldebaran::Base, options = {}, &block)
19
+ base, options = aldebaran::Base, base if base.is_a? Hash
20
+ mock_app(base) {
21
+ set :views, File.dirname(__FILE__) + '/views'
22
+ set options
23
+ get '/', &block
24
+ template(:layout3) { "Layout 3!\n" }
25
+ }
26
+ get '/'
27
+ end
28
+
29
+ def with_default_layout
30
+ layout = File.dirname(__FILE__) + '/views/layout.test'
31
+ File.open(layout, 'wb') { |io| io.write "Layout!\n" }
32
+ yield
33
+ ensure
34
+ File.unlink(layout) rescue nil
35
+ end
36
+
37
+ it 'renders String templates directly' do
38
+ render_app { render :test, 'Hello World' }
39
+ assert ok?
40
+ assert_equal 'Hello World', body
41
+ end
42
+
43
+ it 'renders Proc templates using the call result' do
44
+ render_app { render :test, Proc.new {'Hello World'} }
45
+ assert ok?
46
+ assert_equal 'Hello World', body
47
+ end
48
+
49
+ it 'looks up Symbol templates in views directory' do
50
+ render_app { render :test, :hello }
51
+ assert ok?
52
+ assert_equal "Hello World!\n", body
53
+ end
54
+
55
+ it 'uses the default layout template if not explicitly overridden' do
56
+ with_default_layout do
57
+ render_app { render :test, :hello }
58
+ assert ok?
59
+ assert_equal "Layout!\nHello World!\n", body
60
+ end
61
+ end
62
+
63
+ it 'uses the default layout template if not really overriden' do
64
+ with_default_layout do
65
+ render_app { render :test, :hello, :layout => true }
66
+ assert ok?
67
+ assert_equal "Layout!\nHello World!\n", body
68
+ end
69
+ end
70
+
71
+ it 'uses the layout template specified' do
72
+ render_app { render :test, :hello, :layout => :layout2 }
73
+ assert ok?
74
+ assert_equal "Layout 2!\nHello World!\n", body
75
+ end
76
+
77
+ it 'uses layout templates defined with the #template method' do
78
+ render_app { render :test, :hello, :layout => :layout3 }
79
+ assert ok?
80
+ assert_equal "Layout 3!\nHello World!\n", body
81
+ end
82
+
83
+ it 'avoids wrapping layouts around nested templates' do
84
+ render_app { render :str, :nested, :layout => :layout2 }
85
+ assert ok?
86
+ assert_equal "<h1>String Layout!</h1>\n<content><h1>Hello From String</h1></content>", body
87
+ end
88
+
89
+ it 'allows explicitly wrapping layouts around nested templates' do
90
+ render_app { render :str, :explicitly_nested, :layout => :layout2 }
91
+ assert ok?
92
+ assert_equal "<h1>String Layout!</h1>\n<content><h1>String Layout!</h1>\n<h1>Hello From String</h1></content>", body
93
+ end
94
+
95
+ it 'two independent render calls do not disable layouts' do
96
+ render_app do
97
+ render :str, :explicitly_nested, :layout => :layout2
98
+ render :str, :nested, :layout => :layout2
99
+ end
100
+ assert ok?
101
+ assert_equal "<h1>String Layout!</h1>\n<content><h1>Hello From String</h1></content>", body
102
+ end
103
+
104
+ it 'is possible to use partials in layouts' do
105
+ render_app do
106
+ settings.layout { "<%= erb 'foo' %><%= yield %>" }
107
+ erb 'bar'
108
+ end
109
+ assert ok?
110
+ assert_equal "foobar", body
111
+ end
112
+
113
+ it 'loads templates from source file' do
114
+ mock_app { enable :inline_templates }
115
+ assert_equal "this is foo\n\n", @app.templates[:foo][0]
116
+ assert_equal "X\n= yield\nX\n", @app.templates[:layout][0]
117
+ end
118
+
119
+ it 'ignores spaces after names of inline templates' do
120
+ mock_app { enable :inline_templates }
121
+ assert_equal "There's a space after 'bar'!\n\n", @app.templates[:bar][0]
122
+ assert_equal "this is not foo\n\n", @app.templates[:"foo bar"][0]
123
+ end
124
+
125
+ it 'loads templates from given source file' do
126
+ mock_app { set :inline_templates, __FILE__ }
127
+ assert_equal "this is foo\n\n", @app.templates[:foo][0]
128
+ end
129
+
130
+ test 'inline_templates ignores IO errors' do
131
+ assert_nothing_raised {
132
+ mock_app {
133
+ set :inline_templates, '/foo/bar'
134
+ }
135
+ }
136
+
137
+ assert @app.templates.empty?
138
+ end
139
+
140
+ it 'allows unicode in inline templates' do
141
+ mock_app { set :inline_templates, __FILE__ }
142
+ assert_equal "Den som tror at hemma det är där man bor har aldrig vart hos mig.\n\n",
143
+ @app.templates[:umlaut][0]
144
+ end
145
+
146
+ it 'loads templates from specified views directory' do
147
+ render_app { render :test, :hello, :views => settings.views + '/foo' }
148
+
149
+ assert_equal "from another views directory\n", body
150
+ end
151
+
152
+ it 'passes locals to the layout' do
153
+ mock_app {
154
+ template :my_layout do
155
+ 'Hello <%= name %>!<%= yield %>'
156
+ end
157
+
158
+ get '/' do
159
+ erb '<p>content</p>', { :layout => :my_layout }, { :name => 'Mike'}
160
+ end
161
+ }
162
+
163
+ get '/'
164
+ assert ok?
165
+ assert_equal 'Hello Mike!<p>content</p>', body
166
+ end
167
+
168
+ it 'loads templates defined in subclasses' do
169
+ base = Class.new(aldebaran::Base)
170
+ base.template(:foo) { 'bar' }
171
+ render_app(base) { render :test, :foo }
172
+ assert ok?
173
+ assert_equal 'bar', body
174
+ end
175
+
176
+ it 'allows setting default content type per template engine' do
177
+ render_app(:str => { :content_type => :txt }) { render :str, 'foo' }
178
+ assert_equal 'text/plain;charset=utf-8', response['Content-Type']
179
+ end
180
+
181
+ it 'setting default content type does not affect other template engines' do
182
+ render_app(:str => { :content_type => :txt }) { render :test, 'foo' }
183
+ assert_equal 'text/html;charset=utf-8', response['Content-Type']
184
+ end
185
+
186
+ it 'setting default content type per template engine does not override content_type' do
187
+ render_app :str => { :content_type => :txt } do
188
+ content_type :html
189
+ render :str, 'foo'
190
+ end
191
+ assert_equal 'text/html;charset=utf-8', response['Content-Type']
192
+ end
193
+
194
+ it 'uses templates in superclasses before subclasses' do
195
+ base = Class.new(aldebaran::Base)
196
+ base.template(:foo) { 'template in superclass' }
197
+ assert_equal 'template in superclass', base.templates[:foo].first.call
198
+
199
+ mock_app(base) {
200
+ set :views, File.dirname(__FILE__) + '/views'
201
+ template(:foo) { 'template in subclass' }
202
+ get('/') { render :test, :foo }
203
+ }
204
+ assert_equal 'template in subclass', @app.templates[:foo].first.call
205
+
206
+ get '/'
207
+ assert ok?
208
+ assert_equal 'template in subclass', body
209
+ end
210
+
211
+ it "is possible to use a different engine for the layout than for the template itself explicitely" do
212
+ render_app do
213
+ settings.template(:layout) { 'Hello <%= yield %>!' }
214
+ render :str, "<%= 'World' %>", :layout_engine => :erb
215
+ end
216
+ assert_equal "Hello <%= 'World' %>!", body
217
+ end
218
+
219
+ it "is possible to use a different engine for the layout than for the template itself globally" do
220
+ render_app :str => { :layout_engine => :erb } do
221
+ settings.template(:layout) { 'Hello <%= yield %>!' }
222
+ render :str, "<%= 'World' %>"
223
+ end
224
+ assert_equal "Hello <%= 'World' %>!", body
225
+ end
226
+
227
+ it "does not leak the content type to the template" do
228
+ render_app :str => { :layout_engine => :erb } do
229
+ settings.template(:layout) { 'Hello <%= yield %>!' }
230
+ render :str, "<%= 'World' %>", :content_type => :txt
231
+ end
232
+ assert_equal "text/html;charset=utf-8", headers['Content-Type']
233
+ end
234
+
235
+ it "is possible to register another template" do
236
+ Tilt.register "html.erb", Tilt[:erb]
237
+ render_app { render :erb, :calc }
238
+ assert_equal '2', body
239
+ end
240
+
241
+ it "passes scope to the template" do
242
+ mock_app do
243
+ template :scoped do
244
+ 'Hello <%= foo %>'
245
+ end
246
+
247
+ get '/' do
248
+ some_scope = Object.new
249
+ def some_scope.foo() 'World!' end
250
+ erb :scoped, :scope => some_scope
251
+ end
252
+ end
253
+
254
+ get '/'
255
+ assert ok?
256
+ assert_equal 'Hello World!', body
257
+ end
258
+
259
+ it "is possible to use custom logic for finding template files" do
260
+ mock_app do
261
+ set :views, ["a", "b"].map { |d| File.dirname(__FILE__) + '/views/' + d }
262
+ def find_template(views, name, engine, &block)
263
+ Array(views).each { |v| super(v, name, engine, &block) }
264
+ end
265
+
266
+ get('/:name') do
267
+ render :str, params[:name].to_sym
268
+ end
269
+ end
270
+
271
+ get '/in_a'
272
+ assert_body 'Gimme an A!'
273
+
274
+ get '/in_b'
275
+ assert_body 'Gimme a B!'
276
+ end
277
+ end
278
+
279
+ # __END__ : this is not the real end of the script.
280
+
281
+ __END__
282
+
283
+ @@ foo
284
+ this is foo
285
+
286
+ @@ bar
287
+ There's a space after 'bar'!
288
+
289
+ @@ foo bar
290
+ this is not foo
291
+
292
+ @@ umlaut
293
+ Den som tror at hemma det är där man bor har aldrig vart hos mig.
294
+
295
+ @@ layout
296
+ X
297
+ = yield
298
+ X