fewer 0.2.0 → 0.3.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,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