lanyon 0.2.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.
- checksums.yaml +7 -0
- data/.yardopts +1 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.md +106 -0
- data/Rakefile +37 -0
- data/demo/404.md +11 -0
- data/demo/_config.yml +5 -0
- data/demo/_layouts/default.html +15 -0
- data/demo/_layouts/post.html +7 -0
- data/demo/_posts/2015-11-05-hello-world.md +8 -0
- data/demo/about/index.md +10 -0
- data/demo/config.ru +6 -0
- data/demo/css/site.css +6 -0
- data/demo/index.md +18 -0
- data/lanyon.gemspec +46 -0
- data/lib/lanyon/application.rb +124 -0
- data/lib/lanyon/router.rb +52 -0
- data/lib/lanyon/version.rb +4 -0
- data/lib/lanyon.rb +79 -0
- data/test/helper.rb +51 -0
- data/test/source/_posts/2015-11-05-hello-world.md +4 -0
- data/test/source/buenos_dias.md +4 -0
- data/test/source/css/test.css +1 -0
- data/test/source/dir-with-index/index.md +4 -0
- data/test/source/dir-without-index/page.md +4 -0
- data/test/source/index.md +4 -0
- data/test/source/js/test.min.js +1 -0
- data/test/source/no-extension +1 -0
- data/test/test_build.rb +44 -0
- data/test/test_configuration.rb +115 -0
- data/test/test_integration.rb +324 -0
- data/test/test_router.rb +123 -0
- metadata +136 -0
data/test/test_build.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe "when creating a Lanyon application" do
|
5
|
+
|
6
|
+
before do
|
7
|
+
tempdir = setup_tempdir
|
8
|
+
chdir_tempdir
|
9
|
+
|
10
|
+
destdir = File.join(tempdir, "_site")
|
11
|
+
|
12
|
+
@dir_options = { :source => sourcedir, :destination => destdir }
|
13
|
+
@page = File.join(destdir, "index.html")
|
14
|
+
@no_page = File.join(destdir, "not_a_page.html")
|
15
|
+
|
16
|
+
FileUtils.mkdir_p(destdir)
|
17
|
+
FileUtils.touch(@no_page)
|
18
|
+
assert File.exist?(@no_page)
|
19
|
+
assert !File.exist?(@page)
|
20
|
+
end
|
21
|
+
|
22
|
+
after do
|
23
|
+
teardown_tempdir
|
24
|
+
end
|
25
|
+
|
26
|
+
it "builds the site by default, removing old content" do
|
27
|
+
silence_output do
|
28
|
+
Lanyon.application(@dir_options)
|
29
|
+
end
|
30
|
+
|
31
|
+
file_must_exist(@page)
|
32
|
+
file_wont_exist(@no_page)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "does not build the site when :skip_build option is set" do
|
36
|
+
options = {:skip_build => true}.merge(@dir_options)
|
37
|
+
silence_output do
|
38
|
+
Lanyon.application(options)
|
39
|
+
end
|
40
|
+
|
41
|
+
file_must_exist(@no_page)
|
42
|
+
file_wont_exist(@page)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
|
4
|
+
def get_jekyll_config(overrides = {})
|
5
|
+
silence_output do
|
6
|
+
Lanyon.jekyll_config(overrides)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
describe "when configuring site" do
|
12
|
+
|
13
|
+
before do
|
14
|
+
setup_tempdir
|
15
|
+
chdir_tempdir
|
16
|
+
end
|
17
|
+
|
18
|
+
after do
|
19
|
+
teardown_tempdir
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "when no options are given and no config file exists" do
|
23
|
+
|
24
|
+
it "loads the correct default destination" do
|
25
|
+
config = get_jekyll_config
|
26
|
+
config["destination"].must_equal File.join(Dir.pwd, "_site")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "when using default config file" do
|
31
|
+
|
32
|
+
before do
|
33
|
+
File.open("_config.yml", "w") do |f|
|
34
|
+
f.puts "config_file_opt: ok"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
after do
|
39
|
+
FileUtils.rm("_config.yml")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "loads the configuration from file" do
|
43
|
+
config = get_jekyll_config
|
44
|
+
config.must_include "config_file_opt"
|
45
|
+
config["config_file_opt"].must_equal "ok"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "when using custom config file" do
|
50
|
+
|
51
|
+
before do
|
52
|
+
File.open("_my_config.yml", "w") do |f|
|
53
|
+
f.puts "config_file_opt: ok"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
after do
|
58
|
+
FileUtils.rm("_my_config.yml")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "loads the configuration from file" do
|
62
|
+
config = get_jekyll_config(:config => "_my_config.yml")
|
63
|
+
config.must_include "config_file_opt"
|
64
|
+
config["config_file_opt"].must_equal "ok"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "when initialization options are given" do
|
69
|
+
|
70
|
+
it "has the initialization options" do
|
71
|
+
config = get_jekyll_config(:init_opt => "ok")
|
72
|
+
config.must_include "init_opt"
|
73
|
+
config["init_opt"].must_equal "ok"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "has the correct destination" do
|
77
|
+
config = get_jekyll_config(:destination => "/project/_site")
|
78
|
+
config["destination"].must_equal "/project/_site"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does not pass :skip_build on to Jekyll" do
|
82
|
+
config = get_jekyll_config(:skip_build => "ok")
|
83
|
+
config.wont_include "skip_build"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "when initialization options are given and a config file exists" do
|
88
|
+
|
89
|
+
before do
|
90
|
+
File.open("_config.yml", "w") do |f|
|
91
|
+
f.puts "config_file_opt: ok"
|
92
|
+
f.puts "common_opt: from config"
|
93
|
+
f.puts "destination: /project/_site_from_config"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
after do
|
98
|
+
FileUtils.rm("_config.yml")
|
99
|
+
end
|
100
|
+
|
101
|
+
it "has all options and initialization options override file options" do
|
102
|
+
config = get_jekyll_config(:init_opt => "ok",
|
103
|
+
:common_opt => "from init")
|
104
|
+
config.must_include "init_opt"
|
105
|
+
config.must_include "config_file_opt"
|
106
|
+
config.must_include "common_opt"
|
107
|
+
config["common_opt"].must_equal "from init"
|
108
|
+
end
|
109
|
+
|
110
|
+
it "has the correct destination" do
|
111
|
+
config = get_jekyll_config(:destination => "/project/_site_from_init")
|
112
|
+
config["destination"].must_equal "/project/_site_from_init"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require_relative "helper"
|
4
|
+
|
5
|
+
|
6
|
+
def get_app(overrides = {})
|
7
|
+
silence_output do
|
8
|
+
Lanyon.application(overrides)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe "when handling requests" do
|
14
|
+
|
15
|
+
before do
|
16
|
+
tempdir = setup_tempdir
|
17
|
+
chdir_tempdir
|
18
|
+
|
19
|
+
@destdir = File.join(tempdir, "_site")
|
20
|
+
|
21
|
+
app = get_app(:source => sourcedir, :destination => @destdir)
|
22
|
+
@request = Rack::MockRequest.new(app)
|
23
|
+
end
|
24
|
+
|
25
|
+
after do
|
26
|
+
teardown_tempdir
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
describe "when asked for '/'" do
|
31
|
+
|
32
|
+
before do
|
33
|
+
@response = @request.get("/")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "returns status 200" do
|
37
|
+
@response.status.must_equal 200
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns correct Content-Length header" do
|
41
|
+
@response.original_headers["Content-Length"].must_equal "17"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "returns correct Content-Type header" do
|
45
|
+
@response.headers["Content-Type"].must_equal "text/html"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "returns correct Last-Modified header" do
|
49
|
+
mtime = File.mtime(@destdir + "/index.html")
|
50
|
+
@response.headers["Last-Modified"].must_equal mtime.httpdate
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns correct body" do
|
54
|
+
@response.body.must_match %r{<p>Home Page</p>}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
describe "when asked for a nonexistent path" do
|
60
|
+
|
61
|
+
before do
|
62
|
+
@response = @request.get("/not/a/page")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns status 200" do
|
66
|
+
@response.status.must_equal 404
|
67
|
+
end
|
68
|
+
|
69
|
+
it "returns correct Content-Length header" do
|
70
|
+
@response.original_headers["Content-Length"].must_equal "142"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns correct Content-Type header" do
|
74
|
+
@response.headers["Content-Type"].must_equal "text/html"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "returns correct body" do
|
78
|
+
expected = %r{<!DOCTYPE html>.*<p>404: Not Found</p>}m
|
79
|
+
@response.body.must_match expected
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
describe "when asked for a nonexistent path and a custom 404 exists" do
|
85
|
+
|
86
|
+
before do
|
87
|
+
@custom_404 = File.join(sourcedir, "404.html")
|
88
|
+
File.open(@custom_404, "w") {|f| f.print "Custom 404" }
|
89
|
+
|
90
|
+
app = get_app(:source => sourcedir, :destination => @destdir)
|
91
|
+
request = Rack::MockRequest.new(app)
|
92
|
+
@response = request.get("/not/a/page")
|
93
|
+
end
|
94
|
+
|
95
|
+
after do
|
96
|
+
FileUtils.rm(@custom_404)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "returns correct Content-Length header" do
|
100
|
+
@response.original_headers["Content-Length"].must_equal "10"
|
101
|
+
end
|
102
|
+
|
103
|
+
it "returns correct Content-Type header" do
|
104
|
+
@response.headers["Content-Type"].must_equal "text/html"
|
105
|
+
end
|
106
|
+
|
107
|
+
it "returns correct body" do
|
108
|
+
@response.body.must_equal "Custom 404"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
describe "when asked for an existing path" do
|
114
|
+
|
115
|
+
before do
|
116
|
+
@response = @request.get("/2015/11/05/hello-world.html")
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns status 200" do
|
120
|
+
@response.status.must_equal 200
|
121
|
+
end
|
122
|
+
|
123
|
+
it "returns correct Content-Type header" do
|
124
|
+
@response.headers["Content-Type"].must_equal "text/html"
|
125
|
+
end
|
126
|
+
|
127
|
+
it "returns correct Content-Length header" do
|
128
|
+
@response.original_headers["Content-Length"].must_equal "19"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "returns correct body" do
|
132
|
+
@response.body.must_match %r{<p>A Blog Post</p>}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
describe "when asked for a resource without extension" do
|
138
|
+
|
139
|
+
before do
|
140
|
+
@response = @request.get("/no-extension")
|
141
|
+
end
|
142
|
+
|
143
|
+
it "returns status 200" do
|
144
|
+
@response.status.must_equal 200
|
145
|
+
end
|
146
|
+
|
147
|
+
it "returns Content-Type 'application/octet-stream'" do
|
148
|
+
type = @response.headers["Content-Type"]
|
149
|
+
type.must_equal "application/octet-stream"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
describe "when asked for resources with various media types" do
|
155
|
+
|
156
|
+
it "returns correct Content-Type for *.css" do
|
157
|
+
type = @request.get("/css/test.css").headers["Content-Type"]
|
158
|
+
type.must_equal "text/css"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "returns correct Content-Type for *.min.js" do
|
162
|
+
type = @request.get("/js/test.min.js").headers["Content-Type"]
|
163
|
+
type.must_equal "application/javascript"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
describe "when asked for partially matching paths" do
|
169
|
+
|
170
|
+
it "returns status 404 for path 1" do
|
171
|
+
@request.get("/2015/10/05/hello").status.must_equal 404
|
172
|
+
end
|
173
|
+
|
174
|
+
it "returns status 404 for path 2" do
|
175
|
+
@request.get("/10/05/hello-world.html").status.must_equal 404
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
describe "when a directory is requested" do
|
181
|
+
|
182
|
+
it "redirects to 'directory/' for 'directory' with index.html" do
|
183
|
+
@request.get("/dir-with-index").status.must_equal 301
|
184
|
+
end
|
185
|
+
|
186
|
+
it "returns status 200 for 'directory/' with index.html" do
|
187
|
+
@request.get("/dir-with-index/").status.must_equal 200
|
188
|
+
end
|
189
|
+
|
190
|
+
it "returns correct body for 'directory/' with index.html" do
|
191
|
+
@request.get("/dir-with-index/").body.must_match %r{<p>Index of dir-with-index/</p>}
|
192
|
+
end
|
193
|
+
|
194
|
+
it "returns status 404 for 'directory' without index.html" do
|
195
|
+
@request.get("/dir-without-index").status.must_equal 404
|
196
|
+
end
|
197
|
+
|
198
|
+
it "returns status 404 for 'directory/' without index.html" do
|
199
|
+
@request.get("/dir-without-index/").status.must_equal 404
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
describe "when redirecting to URL with trailing slash" do
|
205
|
+
|
206
|
+
before do
|
207
|
+
@response = @request.get("/dir-with-index")
|
208
|
+
end
|
209
|
+
|
210
|
+
it "returns status 301" do
|
211
|
+
@response.status.must_equal 301
|
212
|
+
end
|
213
|
+
|
214
|
+
it "returns correct Location header" do
|
215
|
+
@response.headers["Location"].must_equal "/dir-with-index/"
|
216
|
+
end
|
217
|
+
|
218
|
+
it "returns a Cache-Control header" do
|
219
|
+
@response.headers["Cache-Control"].wont_be_nil
|
220
|
+
end
|
221
|
+
|
222
|
+
it "returns correct body" do
|
223
|
+
expected = %r{<!DOCTYPE html>.*<a href="/dir-with-index/">}m
|
224
|
+
@request.get("/dir-with-index").body.must_match expected
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
describe "when page contains multibyte characters" do
|
230
|
+
|
231
|
+
before do
|
232
|
+
@response = @request.get("/buenos_dias.html")
|
233
|
+
end
|
234
|
+
|
235
|
+
it "returns correct body" do
|
236
|
+
@response.body.must_match %r{<p>¡Buenos días!</p>}
|
237
|
+
end
|
238
|
+
|
239
|
+
it "returns the bytesize as Content-Length header" do
|
240
|
+
@response.original_headers["Content-Length"].must_equal "23"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
|
245
|
+
describe "when handling If-Modified-Since requests" do
|
246
|
+
|
247
|
+
before do
|
248
|
+
modify_time = @request.get("/").headers["Last-Modified"]
|
249
|
+
earlier_time = (Time.parse(modify_time) - 3600).httpdate
|
250
|
+
@modify_time_header = { "HTTP_IF_MODIFIED_SINCE" => modify_time }
|
251
|
+
@earlier_time_header = { "HTTP_IF_MODIFIED_SINCE" => earlier_time }
|
252
|
+
end
|
253
|
+
|
254
|
+
it "returns correct status code for unchanged '/'" do
|
255
|
+
@request.get("/", @modify_time_header).status.must_equal 304
|
256
|
+
end
|
257
|
+
|
258
|
+
it "does not return a Content-Length header for unchanged '/'" do
|
259
|
+
response = @request.get("/", @modify_time_header)
|
260
|
+
response.original_headers["Content-Length"].must_be_nil
|
261
|
+
end
|
262
|
+
|
263
|
+
it "returns correct status code for updated '/'" do
|
264
|
+
@request.get("/", @earlier_time_header).status.must_equal 200
|
265
|
+
end
|
266
|
+
|
267
|
+
it "returns correct status code for 404" do
|
268
|
+
@request.get("/not/a/page", @earlier_time_header).status.must_equal 404
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
describe "when handling HEAD requests" do
|
274
|
+
|
275
|
+
it "returns status 200 for '/'" do
|
276
|
+
@request.head("/").status.must_equal 200
|
277
|
+
end
|
278
|
+
|
279
|
+
it "returns correct Content-Length header for '/'" do
|
280
|
+
@request.head("/").original_headers["Content-Length"].must_equal "17"
|
281
|
+
end
|
282
|
+
|
283
|
+
it "does not return a body" do
|
284
|
+
@request.head("/").body.must_equal ""
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
describe "when handling OPTIONS requests" do
|
290
|
+
|
291
|
+
it "returns status 200" do
|
292
|
+
@request.options("/").status.must_equal 200
|
293
|
+
end
|
294
|
+
|
295
|
+
it "returns correct Allow header" do
|
296
|
+
@request.options("/").original_headers["Allow"].must_equal "GET,HEAD,OPTIONS"
|
297
|
+
end
|
298
|
+
|
299
|
+
it "does not return a body" do
|
300
|
+
@request.options("/").body.must_equal ""
|
301
|
+
end
|
302
|
+
|
303
|
+
it "returns 404 for nonexistent resource" do
|
304
|
+
@request.options("/not/a/page").status.must_equal 404
|
305
|
+
@request.options("/not/a/page").body.must_match %r{<p>404: Not Found</p>}
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
describe "when handling POST, PUT, DELETE, and other requests" do
|
311
|
+
|
312
|
+
it "returns status 405" do
|
313
|
+
@request.post("/").status.must_equal 405
|
314
|
+
@request.put("/").status.must_equal 405
|
315
|
+
@request.delete("/").status.must_equal 405
|
316
|
+
@request.request("OTHER", "/").status.must_equal 405
|
317
|
+
end
|
318
|
+
|
319
|
+
it "returns correct body" do
|
320
|
+
expected = %r{<!DOCTYPE html>.*<p>405: Method Not Allowed</p>}m
|
321
|
+
@request.post("/").body.must_match expected
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
data/test/test_router.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
|
4
|
+
describe Lanyon::Router do
|
5
|
+
|
6
|
+
before do
|
7
|
+
tempdir = setup_tempdir
|
8
|
+
chdir_tempdir
|
9
|
+
|
10
|
+
@sitedir = File.join(tempdir, "_site")
|
11
|
+
FileUtils.mkdir_p(@sitedir)
|
12
|
+
|
13
|
+
files = %w[
|
14
|
+
index.html
|
15
|
+
page.html
|
16
|
+
README
|
17
|
+
dir-with-index/index.html
|
18
|
+
dir-without-index/page.html
|
19
|
+
dir1/dir2/dir3/index.html
|
20
|
+
]
|
21
|
+
|
22
|
+
files.each do |path|
|
23
|
+
dirname = File.dirname(path)
|
24
|
+
FileUtils.mkdir_p(File.join(@sitedir, dirname))
|
25
|
+
FileUtils.touch(File.join(@sitedir, path))
|
26
|
+
end
|
27
|
+
|
28
|
+
@router = Lanyon::Router.new(@sitedir)
|
29
|
+
end
|
30
|
+
|
31
|
+
after do
|
32
|
+
teardown_tempdir
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
describe "when asked for filenames with #endpoint" do
|
37
|
+
|
38
|
+
it "returns path for '/'" do
|
39
|
+
filename = File.join(@sitedir, "index.html")
|
40
|
+
@router.endpoint("/").must_equal filename
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns existing path" do
|
44
|
+
filename = File.join(@sitedir, "page.html")
|
45
|
+
@router.endpoint("/page.html").must_equal filename
|
46
|
+
end
|
47
|
+
|
48
|
+
it "returns existing path for resource without extension" do
|
49
|
+
filename = File.join(@sitedir, "README")
|
50
|
+
@router.endpoint("/README").must_equal filename
|
51
|
+
end
|
52
|
+
|
53
|
+
it "returns :not_found for non-existent path" do
|
54
|
+
@router.endpoint("/not-a-page.html").must_equal :not_found
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns :not_found for partially matching paths" do
|
58
|
+
@router.endpoint("/dir1/dir2/").must_equal :not_found
|
59
|
+
@router.endpoint("/dir2/dir3").must_equal :not_found
|
60
|
+
@router.endpoint("ir1/di").must_equal :not_found
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns path for '/path/to/dir/' with index" do
|
64
|
+
filename = File.join(@sitedir, "dir-with-index/index.html")
|
65
|
+
@router.endpoint("/dir-with-index/").must_equal filename
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns :must_redirect for '/path/to/dir' with index" do
|
69
|
+
@router.endpoint("/dir-with-index").must_equal :must_redirect
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns :not_found for '/path/to/dir/' without index" do
|
73
|
+
@router.endpoint("/dir-without-index/").must_equal :not_found
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns :not_found for '/path/to/dir' without index" do
|
77
|
+
@router.endpoint("/dir-without-index").must_equal :not_found
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
describe "when asked for #custom_404_body" do
|
83
|
+
|
84
|
+
describe "when 404.html does not exist" do
|
85
|
+
|
86
|
+
it "returns nil" do
|
87
|
+
@router.custom_404_body.must_be_nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "when 404.html does exist" do
|
92
|
+
|
93
|
+
before do
|
94
|
+
@custom_404 = File.join(@sitedir, "404.html")
|
95
|
+
File.open(@custom_404, "w") {|f| f.print "Custom 404" }
|
96
|
+
end
|
97
|
+
|
98
|
+
after do
|
99
|
+
FileUtils.rm(@custom_404)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "returns correct body" do
|
103
|
+
@router.custom_404_body.must_equal "Custom 404"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
describe "when initialized" do
|
110
|
+
|
111
|
+
it "strips trailing slash from root" do
|
112
|
+
router = Lanyon::Router.new(@sitedir + "/")
|
113
|
+
router.root.must_equal @sitedir
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does not append a trailing slash to root" do
|
117
|
+
assert !@sitedir.end_with?("/")
|
118
|
+
|
119
|
+
router = Lanyon::Router.new(@sitedir)
|
120
|
+
router.root.must_equal @sitedir
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|