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.
@@ -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