lanyon 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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