fewer 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Fewer
2
+ VERSION = '0.3.0'
3
+ end
@@ -1,76 +1,26 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class AppTest < Test::Unit::TestCase
4
- include TestHelper
5
-
6
- def setup
7
- @app = stub
8
- @engine = stub(
9
- :check_request_extension => true,
10
- :content_type => 'text/css',
11
- :mtime => Time.utc(2010, 8, 17, 21, 5, 24),
12
- :read => 'content'
13
- )
14
- @engine_klass = stub(:new => @engine)
15
- @fewer_app = Fewer::App.new(:name,
16
- :engine => @engine_klass,
17
- :root => 'root'
18
- )
19
- @browser = Rack::Test::Session.new(Rack::MockSession.new(@fewer_app))
20
- end
21
-
22
- def test_can_retrieve_app_by_name
23
- assert_nil Fewer::App[:not_name]
24
- assert_equal @fewer_app, Fewer::App[:name]
25
- end
26
-
27
- def test_initialises_a_new_engine_with_a_single_file
28
- file = 'file'
29
- @engine_klass.expects(:new).with('root', file, {}).returns(@engine)
30
- @browser.get "/path/#{encode(file)}.css"
31
- end
32
-
33
- def test_initialises_a_new_engine_with_multiple_files
34
- files = ['file1', 'file2']
35
- @engine_klass.expects(:new).with('root', files, {}).returns(@engine)
36
- @browser.get "/path/#{encode(files)}.css"
4
+ def test_engine_required
5
+ assert_raises ArgumentError do
6
+ Fewer::App.new(:name, :root => 'blah')
7
+ end
37
8
  end
38
9
 
39
- def test_responds_with_engine_content_type
40
- @browser.get "/path/#{encode('file')}.css"
41
- assert_equal 'text/css', @browser.last_response.content_type
10
+ def test_root_required
11
+ assert_raises ArgumentError do
12
+ Fewer::App.new(:name, :engine => 'blah')
13
+ end
42
14
  end
43
15
 
44
- def test_responds_with_cache_control
45
- @browser.get "/path/#{encode('file')}.css"
46
- assert_equal 'public, max-age=31536000', @browser.last_response.headers['Cache-Control']
47
- end
48
-
49
- def test_responds_with_last_modified
50
- @browser.get "/path/#{encode('file')}.css"
51
- assert_equal 'Tue, 17 Aug 2010 21:05:24 -0000', @browser.last_response.headers['Last-Modified']
52
- end
53
-
54
- def test_responds_with_bundled_content
55
- @engine.expects(:read).returns('content')
56
- @browser.get "/path/#{encode('file')}.css"
57
- assert_equal 'content', @browser.last_response.body
58
- end
16
+ def test_named_apps_added_to_registry
17
+ assert_nil Fewer::App[:name]
59
18
 
60
- def test_responds_with_200
61
- @browser.get "/path/#{encode('file')}.css"
62
- assert_equal 200, @browser.last_response.status
63
- end
64
-
65
- def test_responds_with_404_for_missing_source
66
- @engine.stubs(:read).raises(Fewer::MissingSourceFileError)
67
- @browser.get "/path/#{encode('file')}.css"
68
- assert_equal 404, @browser.last_response.status
69
- end
19
+ app = Fewer::App.new(:name,
20
+ :engine => stub(:new => stub),
21
+ :root => 'blah'
22
+ )
70
23
 
71
- def test_responds_with_500_for_other_errors
72
- @engine.stubs(:read).raises(RuntimeError)
73
- @browser.get "/path/#{encode('file')}.css"
74
- assert_equal 500, @browser.last_response.status
24
+ assert_equal app, Fewer::App[:name]
75
25
  end
76
26
  end
@@ -3,54 +3,84 @@ require 'test_helper'
3
3
  class EngineTest < Test::Unit::TestCase
4
4
  include TestHelper
5
5
 
6
+ def teardown
7
+ FakeFS::FileSystem.clear
8
+ end
9
+
10
+ def test_copes_with_pathnames
11
+ root = Pathname.new(fs)
12
+ path = Pathname.new(touch('a.css'))
13
+ engine = Fewer::Engines::Abstract.new(root, [path])
14
+ end
15
+
6
16
  def test_sanitise_paths
7
- files = [
8
- 'dir/ectory/file.js',
9
- 'sub/dir/ectory/file.js',
10
- './../private.txt',
17
+ paths = [
18
+ 'a.css',
19
+ '/root/file.css',
20
+ '/root/../passwd',
21
+ '/root/./passwd',
11
22
  '/etc/passwd',
12
23
  '/etc/../passwd'
13
24
  ]
14
- engine = engine_klass_no_checking.new('./happy-place', files)
25
+ engine = engine_klass_no_checking.new('/root', paths)
15
26
  assert_equal [
16
- './happy-place/dir/ectory/file.js',
17
- './happy-place/sub/dir/ectory/file.js',
18
- './happy-place/./private.txt',
19
- './happy-place/etc/passwd',
20
- './happy-place/etc/passwd'
27
+ '/root/a.css',
28
+ '/root/file.css',
29
+ '/root/passwd',
30
+ '/root/passwd',
31
+ '/root/etc/passwd',
32
+ '/root/etc/passwd'
21
33
  ], engine.paths
22
34
  end
23
35
 
24
- def test_stringify_paths
25
- engine = engine_klass_no_checking.new('.', [:symbol, { :a => :b }])
26
- assert_equal ['./symbol', './ab'], engine.paths
27
- end
28
-
29
- def test_converts_names_to_an_array
30
- engine = engine_klass_no_checking.new(template_root, 'style')
31
- assert_equal ['style'], engine.names
32
- end
33
-
34
36
  def test_raises_error_for_missing_file
35
37
  assert_raises Fewer::MissingSourceFileError do
36
- Fewer::Engines::Abstract.new(template_root, ['does-not-exist'])
38
+ Fewer::Engines::Abstract.new('root', ['does-not-exist'])
37
39
  end
38
40
  end
39
41
 
42
+ def test_mtime_is_not_nil
43
+ engine = Fewer::Engines::Abstract.new(fs, [])
44
+ assert !engine.mtime.nil?
45
+ end
46
+
40
47
  def test_can_deal_with_encoding_for_you
41
- names = ['a', 'b']
42
- engine = engine_klass_no_checking.new(template_root, names)
43
- Fewer::Serializer.expects(:encode).with(names)
48
+ paths = [touch('a.css'), touch('a.css')]
49
+ engine = Fewer::Engines::Abstract.new(fs, paths)
50
+ Fewer::Serializer.expects(:encode).with(fs, paths)
44
51
  engine.encoded
45
52
  end
46
53
 
47
54
  def test_less_import_command
48
- engine = Fewer::Engines::Less.new(template_root, ['style'])
55
+ import = touch('import.less')
56
+ style = fs('style.less')
57
+
58
+ File.open(style, 'w') do |f|
59
+ f.write '@import "import";'
60
+ end
61
+
62
+ engine = Fewer::Engines::Less.new(fs, [style])
63
+
49
64
  assert_nothing_raised do
50
65
  engine.read
51
66
  end
52
67
  end
53
68
 
69
+ def test_read_source_files_once_when_generating_etag_and_content
70
+ file = touch('a.css')
71
+ engine = Fewer::Engines::Abstract.new(fs, [file])
72
+ File.expects(:read).once.returns('')
73
+ engine.etag
74
+ engine.read
75
+ end
76
+
77
+ def test_generating_etag_should_not_process_content
78
+ file = touch('a.less')
79
+ engine = Fewer::Engines::Less.new(fs, [file])
80
+ Less::Engine.expects(:new).never
81
+ engine.etag
82
+ end
83
+
54
84
  private
55
85
  def engine_klass(&block)
56
86
  Class.new(Fewer::Engines::Abstract, &block)
@@ -0,0 +1,103 @@
1
+ require 'test_helper'
2
+
3
+ class IntegrationTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def setup
7
+ @app = Fewer::App.new(:test, :engine => Fewer::Engines::Css, :root => fs)
8
+ @browser = Rack::Test::Session.new(Rack::MockSession.new(@app))
9
+ end
10
+
11
+ def teardown
12
+ FakeFS::FileSystem.clear
13
+ end
14
+
15
+ def test_initialises_a_new_engine_with_a_single_file
16
+ path = touch('a.css')
17
+ engine = Fewer::Engines::Css.new(fs, [path])
18
+ Fewer::Engines::Css.expects(:new).with(fs, [path], {}).returns(engine)
19
+ @browser.get "/#{encode([path])}"
20
+ end
21
+
22
+ def test_initialises_a_new_engine_with_multiple_files
23
+ paths = [touch('a.css'), touch('b.css')]
24
+ engine = Fewer::Engines::Css.new(fs, paths)
25
+ Fewer::Engines::Css.expects(:new).with(fs, paths, {}).returns(engine)
26
+ @browser.get "/#{encode(paths)}"
27
+ end
28
+
29
+ def test_strip_metadata_from_path
30
+ paths = [touch('a.css'), touch('b.css')]
31
+ engine = Fewer::Engines::Css.new(fs, paths)
32
+ Fewer::Engines::Css.expects(:new).with(fs, paths, {}).returns(engine)
33
+ @browser.get "/#{encode(paths)}-blah.css"
34
+ end
35
+
36
+ def test_responds_with_engine_content_type
37
+ path = touch('a.css')
38
+ @browser.get "/#{encode([path])}"
39
+ assert_equal 'text/css', @browser.last_response.content_type
40
+ end
41
+
42
+ def test_responds_with_cache_control
43
+ path = touch('a.css')
44
+ @browser.get "/#{encode([path])}"
45
+ assert_equal 'public, max-age=31536000', @browser.last_response.headers['Cache-Control']
46
+ end
47
+
48
+ def test_responds_with_last_modified
49
+ File.stubs(:mtime => Time.utc(2010, 8, 17, 21, 5, 24))
50
+ path = touch('a.css')
51
+ @browser.get "/#{encode([path])}"
52
+ assert_equal 'Tue, 17 Aug 2010 21:05:24 -0000', @browser.last_response.headers['Last-Modified']
53
+ end
54
+
55
+ def test_responds_with_bundled_content
56
+ path = fs('a.css')
57
+ File.open(path, 'w') do |f|
58
+ f.write 'content'
59
+ end
60
+
61
+ @browser.get "/#{encode([path])}"
62
+ assert_equal 'content', @browser.last_response.body
63
+ end
64
+
65
+ def test_responds_with_200
66
+ path = touch('a.css')
67
+ @browser.get "/#{encode([path])}"
68
+ assert_equal 200, @browser.last_response.status
69
+ end
70
+
71
+ def test_responds_with_304_for_not_modified_requests
72
+ file = touch('a.css')
73
+ path = "/#{encode([path])}"
74
+ @browser.get path
75
+ etag = @browser.last_response.headers['ETag']
76
+ @browser.header 'IF_NONE_MATCH', etag
77
+ @browser.get path
78
+ assert_equal 304, @browser.last_response.status
79
+ end
80
+
81
+ def test_responds_with_200_for_modified_requests
82
+ file = touch('a.css')
83
+ path = "/#{encode([path])}"
84
+ @browser.get path
85
+ File.open(fs('a.css'), 'w') { |f| f.write('blah') }
86
+ etag = @browser.last_response.headers['ETag']
87
+ @browser.header 'IF_NONE_MATCH', etag
88
+ @browser.get path
89
+ assert_equal 200, @browser.last_response.status
90
+ end
91
+
92
+ def test_responds_with_404_for_missing_source
93
+ Fewer::Engines::Css.stubs(:new).raises(Fewer::MissingSourceFileError)
94
+ @browser.get '/blah.css'
95
+ assert_equal 404, @browser.last_response.status
96
+ end
97
+
98
+ def test_responds_with_500_for_other_errors
99
+ Fewer::Engines::Css.stubs(:new).raises(RuntimeError)
100
+ @browser.get '/blah.css'
101
+ assert_equal 500, @browser.last_response.status
102
+ end
103
+ end
@@ -6,8 +6,7 @@ class MiddlewareTest < Test::Unit::TestCase
6
6
  def setup
7
7
  @app = stub
8
8
  @engine = stub(
9
- :check_request_extension => true,
10
- :content_type => 'text/css',
9
+ :etag => '',
11
10
  :mtime => Time.utc(2010, 8, 17, 21, 5, 24),
12
11
  :read => 'content'
13
12
  )
@@ -19,7 +18,9 @@ class MiddlewareTest < Test::Unit::TestCase
19
18
  :root => '/some/root/path',
20
19
  :engine => Fewer::Engines::Css,
21
20
  :mount => '/css'
22
- run lambda{|env| [200, {'Content-Type'=>'text/html'},'Hello World']}
21
+ run lambda { |env|
22
+ [200, { 'Content-Type' => 'text/html' }, ['Hello World']]
23
+ }
23
24
  end
24
25
  end
25
26
 
@@ -27,7 +28,7 @@ class MiddlewareTest < Test::Unit::TestCase
27
28
  end
28
29
 
29
30
  def test_middleware_intercepts_path
30
- @browser.get "/css/#{encode('file')}.css"
31
+ @browser.get '/css/blah.css'
31
32
  assert_equal 'content', @browser.last_response.body
32
33
  assert_equal 'text/css', @browser.last_response.content_type
33
34
  end
@@ -0,0 +1,60 @@
1
+ require 'test_helper'
2
+
3
+ class RailsHelpersTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def setup
7
+ @engine_klass = stub('klass', :extension => '.fewer')
8
+ @engine = stub('engine',
9
+ :encoded => 'qwerty',
10
+ :mtime => Time.utc(2010, 8, 17, 21, 5, 24)
11
+ )
12
+ @app = stub('app', :engine_klass => @engine_klass, :engine => @engine)
13
+ Fewer::App.stubs(:[] => @app)
14
+
15
+ @helper = Class.new do
16
+ include Fewer::RailsHelpers
17
+ end.new
18
+ @helper.stubs(:config => @config = stub(:perform_caching => true))
19
+ @helper.stubs(:javascript_include_tag)
20
+ @helper.stubs(:stylesheet_link_tag)
21
+ end
22
+
23
+ def test_extension_added_if_not_present
24
+ @app.expects(:engine).with(['a.min.fewer', 'b.fewer.min.fewer']).returns(@engine)
25
+ @helper.fewer_encode_sources @app, ['a.min', 'b.fewer.min']
26
+ end
27
+
28
+ def test_single_stylesheet_with_caching
29
+ @helper.expects(:stylesheet_link_tag).with(['l7bel0/qwerty.css'], {})
30
+ @helper.fewer_stylesheets_tag 'a.fewer', 'b.fewer'
31
+ end
32
+
33
+ def test_multiple_stylesheet_with_no_caching
34
+ @config.stubs(:perform_caching => false)
35
+ @helper.expects(:stylesheet_link_tag).with(['l7bel0/qwerty-a.css', 'l7bel0/qwerty-b.css'], {})
36
+ @helper.fewer_stylesheets_tag 'a.fewer', 'b.fewer'
37
+ end
38
+
39
+ def test_stylesheet_options_forwarded
40
+ options = { :a => :b }
41
+ @helper.expects(:stylesheet_link_tag).with(['l7bel0/qwerty.css'], options)
42
+ @helper.fewer_stylesheets_tag 'a.fewer', 'b.fewer', options
43
+ end
44
+
45
+ def test_stylesheet_cache_option_removed
46
+ @helper.expects(:stylesheet_link_tag).with(['l7bel0/qwerty.css'], {})
47
+ @helper.fewer_stylesheets_tag 'a.fewer', 'b.fewer', { :cache => true }
48
+ end
49
+
50
+ def test_single_javascript_with_caching
51
+ @helper.expects(:javascript_include_tag).with(['l7bel0/qwerty.js'], {})
52
+ @helper.fewer_javascripts_tag 'a.fewer', 'b.fewer'
53
+ end
54
+
55
+ def test_multiple_javascript_with_no_caching
56
+ @config.stubs(:perform_caching => false)
57
+ @helper.expects(:javascript_include_tag).with(['l7bel0/qwerty-a.js', 'l7bel0/qwerty-b.js'], {})
58
+ @helper.fewer_javascripts_tag 'a.fewer', 'b.fewer'
59
+ end
60
+ end
@@ -0,0 +1,159 @@
1
+ require 'test_helper'
2
+
3
+ class SerializerTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def setup
7
+ FakeFS.activate!
8
+ FileUtils.mkdir_p(fs('nested'))
9
+ touch('a.css')
10
+ touch('list.css')
11
+ touch('nested/files.css')
12
+ touch('of.css')
13
+ end
14
+
15
+ def teardown
16
+ FakeFS::FileSystem.clear
17
+ FakeFS.deactivate!
18
+ end
19
+
20
+ def test_encode_first_file
21
+ encoded = Fewer::Serializer.encode(fs, [
22
+ fs('a.css')
23
+ ])
24
+ assert_equal '0', encoded
25
+ end
26
+
27
+ def test_encode_last_file
28
+ encoded = Fewer::Serializer.encode(fs, [
29
+ fs('of.css')
30
+ ])
31
+ assert_equal '3', encoded
32
+ end
33
+
34
+ def test_encode_some_files
35
+ encoded = Fewer::Serializer.encode(fs, [
36
+ fs('a.css'),
37
+ fs('nested/files.css'),
38
+ fs('of.css')
39
+ ])
40
+ assert_equal '023', encoded
41
+ end
42
+
43
+ def test_encode_some_files_in_a_different_order
44
+ encoded = Fewer::Serializer.encode(fs, [
45
+ fs('of.css'),
46
+ fs('a.css'),
47
+ fs('nested/files.css')
48
+ ])
49
+ assert_equal '302', encoded
50
+ end
51
+
52
+ def test_encode_invalid_files
53
+ encoded = Fewer::Serializer.encode(fs, %w(0 1 2 3 4 5 6 7 8 9 a b c d e f
54
+ g h i j k l m n o p q r s t u v w x y z 10))
55
+ assert_equal '', encoded
56
+ end
57
+
58
+ def test_encode_35_files
59
+ FakeFS::FileSystem.clear
60
+ files = (0...36).map { |i| touch('%02d' % i + '.css') }
61
+
62
+ encoded = Fewer::Serializer.encode(fs, files)
63
+ assert_equal '0123456789abcdefghijklmnopqrstuvwxyz', encoded
64
+ end
65
+
66
+ def test_encode_99_files
67
+ FakeFS::FileSystem.clear
68
+ files = (0...99).map { |i| touch('%02d' % i + '.css') }
69
+
70
+ expected = '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t' +
71
+ ',u,v,w,x,y,z,10,11,12,13,14,15,16,17,18,19,1a,1b,1c,1d,1e,1f,1g,1h,' +
72
+ '1i,1j,1k,1l,1m,1n,1o,1p,1q,1r,1s,1t,1u,1v,1w,1x,1y,1z,20,21,22,23,24' +
73
+ ',25,26,27,28,29,2a,2b,2c,2d,2e,2f,2g,2h,2i,2j,2k,2l,2m,2n,2o,2p,2q'
74
+ assert_equal expected, Fewer::Serializer.encode(fs, files)
75
+ end
76
+
77
+ def test_encode_1_of_99_files
78
+ FakeFS::FileSystem.clear
79
+ files = (0...99).map { |i| touch('%02d' % i + '.css') }
80
+ assert_equal '2q', Fewer::Serializer.encode(fs, [fs('98.css')])
81
+ end
82
+
83
+ def test_files_encoded_in_the_same_order_each_time
84
+ FakeFS::FileSystem.clear
85
+ files = (0...36).map { |i| touch('%02d' % i + '.css') }
86
+ Dir.stubs(:glob).returns(files)
87
+ encoded1 = Fewer::Serializer.encode(fs, files)
88
+ Dir.stubs(:glob).returns(files.reverse)
89
+ encoded2 = Fewer::Serializer.encode(fs, files)
90
+ assert_equal encoded1, encoded2
91
+ end
92
+
93
+ def test_decode_first_file
94
+ decoded = Fewer::Serializer.decode(fs, '0')
95
+ assert_equal [
96
+ fs('a.css')
97
+ ], decoded
98
+ end
99
+
100
+ def test_decode_last_file
101
+ decoded = Fewer::Serializer.decode(fs, '3')
102
+ assert_equal [
103
+ fs('of.css')
104
+ ], decoded
105
+ end
106
+
107
+ def test_decode_some_files
108
+ decoded = Fewer::Serializer.decode(fs, '023')
109
+ assert_equal [
110
+ fs('a.css'),
111
+ fs('nested/files.css'),
112
+ fs('of.css')
113
+ ], decoded
114
+ end
115
+
116
+ def test_decode_some_files_in_a_different_order
117
+ decoded = Fewer::Serializer.decode(fs, '302')
118
+ assert_equal [
119
+ fs('of.css'),
120
+ fs('a.css'),
121
+ fs('nested/files.css')
122
+ ], decoded
123
+ end
124
+
125
+ def test_decode_invalid_file
126
+ decoded = Fewer::Serializer.decode(fs, '')
127
+ assert_equal [], decoded
128
+ end
129
+
130
+ def test_decode_another_invalid_file
131
+ decoded = Fewer::Serializer.decode(fs, 'z')
132
+ assert_equal [], decoded
133
+ end
134
+
135
+ def test_decode_35_files
136
+ FakeFS::FileSystem.clear
137
+ files = (0...36).map { |i| touch('%02d' % i + '.css') }
138
+
139
+ decoded = Fewer::Serializer.decode(fs, '0123456789abcdefghijklmnopqrstuvwxyz')
140
+ assert_equal files, decoded
141
+ end
142
+
143
+ def test_decode_99_files
144
+ FakeFS::FileSystem.clear
145
+ files = (0...99).map { |i| touch('%02d' % i + '.css') }
146
+
147
+ encoded = '0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t' +
148
+ ',u,v,w,x,y,z,10,11,12,13,14,15,16,17,18,19,1a,1b,1c,1d,1e,1f,1g,1h,' +
149
+ '1i,1j,1k,1l,1m,1n,1o,1p,1q,1r,1s,1t,1u,1v,1w,1x,1y,1z,20,21,22,23,24' +
150
+ ',25,26,27,28,29,2a,2b,2c,2d,2e,2f,2g,2h,2i,2j,2k,2l,2m,2n,2o,2p,2q'
151
+ assert_equal files, Fewer::Serializer.decode(fs, encoded)
152
+ end
153
+
154
+ def test_decode_1_of_99_files
155
+ FakeFS::FileSystem.clear
156
+ files = (0...99).map { |i| touch('%02d' % i + '.css') }
157
+ assert_equal [fs('98.css')], Fewer::Serializer.decode(fs, '2q')
158
+ end
159
+ end