sass 3.3.0 → 3.4.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.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +58 -50
  4. data/Rakefile +1 -4
  5. data/VERSION +1 -1
  6. data/VERSION_DATE +1 -1
  7. data/VERSION_NAME +1 -1
  8. data/bin/sass +1 -1
  9. data/bin/scss +1 -1
  10. data/lib/sass/cache_stores/filesystem.rb +6 -2
  11. data/lib/sass/css.rb +1 -3
  12. data/lib/sass/engine.rb +37 -46
  13. data/lib/sass/environment.rb +13 -17
  14. data/lib/sass/error.rb +6 -9
  15. data/lib/sass/exec/base.rb +187 -0
  16. data/lib/sass/exec/sass_convert.rb +264 -0
  17. data/lib/sass/exec/sass_scss.rb +424 -0
  18. data/lib/sass/exec.rb +5 -771
  19. data/lib/sass/features.rb +7 -0
  20. data/lib/sass/importers/base.rb +7 -2
  21. data/lib/sass/importers/filesystem.rb +9 -25
  22. data/lib/sass/importers.rb +0 -1
  23. data/lib/sass/media.rb +1 -4
  24. data/lib/sass/plugin/compiler.rb +200 -83
  25. data/lib/sass/plugin/staleness_checker.rb +1 -1
  26. data/lib/sass/plugin.rb +3 -3
  27. data/lib/sass/script/css_lexer.rb +1 -1
  28. data/lib/sass/script/functions.rb +622 -268
  29. data/lib/sass/script/lexer.rb +99 -34
  30. data/lib/sass/script/parser.rb +24 -23
  31. data/lib/sass/script/tree/funcall.rb +1 -1
  32. data/lib/sass/script/tree/interpolation.rb +20 -2
  33. data/lib/sass/script/tree/selector.rb +26 -0
  34. data/lib/sass/script/tree/string_interpolation.rb +1 -1
  35. data/lib/sass/script/tree.rb +1 -0
  36. data/lib/sass/script/value/base.rb +7 -5
  37. data/lib/sass/script/value/bool.rb +0 -5
  38. data/lib/sass/script/value/color.rb +39 -21
  39. data/lib/sass/script/value/helpers.rb +107 -0
  40. data/lib/sass/script/value/list.rb +0 -15
  41. data/lib/sass/script/value/null.rb +0 -5
  42. data/lib/sass/script/value/number.rb +62 -14
  43. data/lib/sass/script/value/string.rb +59 -11
  44. data/lib/sass/script/value.rb +0 -1
  45. data/lib/sass/scss/css_parser.rb +8 -2
  46. data/lib/sass/scss/parser.rb +190 -328
  47. data/lib/sass/scss/rx.rb +15 -6
  48. data/lib/sass/scss/static_parser.rb +298 -1
  49. data/lib/sass/selector/abstract_sequence.rb +28 -13
  50. data/lib/sass/selector/comma_sequence.rb +92 -13
  51. data/lib/sass/selector/pseudo.rb +256 -0
  52. data/lib/sass/selector/sequence.rb +94 -24
  53. data/lib/sass/selector/simple.rb +14 -25
  54. data/lib/sass/selector/simple_sequence.rb +97 -33
  55. data/lib/sass/selector.rb +57 -194
  56. data/lib/sass/shared.rb +1 -1
  57. data/lib/sass/source/map.rb +26 -12
  58. data/lib/sass/stack.rb +0 -6
  59. data/lib/sass/supports.rb +2 -3
  60. data/lib/sass/tree/at_root_node.rb +1 -0
  61. data/lib/sass/tree/charset_node.rb +1 -1
  62. data/lib/sass/tree/directive_node.rb +8 -2
  63. data/lib/sass/tree/error_node.rb +18 -0
  64. data/lib/sass/tree/extend_node.rb +1 -1
  65. data/lib/sass/tree/function_node.rb +4 -0
  66. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  67. data/lib/sass/tree/prop_node.rb +1 -1
  68. data/lib/sass/tree/rule_node.rb +12 -7
  69. data/lib/sass/tree/visitors/check_nesting.rb +38 -10
  70. data/lib/sass/tree/visitors/convert.rb +16 -18
  71. data/lib/sass/tree/visitors/cssize.rb +29 -29
  72. data/lib/sass/tree/visitors/deep_copy.rb +5 -0
  73. data/lib/sass/tree/visitors/perform.rb +45 -33
  74. data/lib/sass/tree/visitors/set_options.rb +14 -0
  75. data/lib/sass/tree/visitors/to_css.rb +15 -14
  76. data/lib/sass/util/subset_map.rb +1 -1
  77. data/lib/sass/util.rb +222 -99
  78. data/lib/sass/version.rb +5 -5
  79. data/lib/sass.rb +0 -5
  80. data/test/sass/cache_test.rb +62 -20
  81. data/test/sass/callbacks_test.rb +1 -1
  82. data/test/sass/compiler_test.rb +19 -10
  83. data/test/sass/conversion_test.rb +58 -1
  84. data/test/sass/css2sass_test.rb +23 -4
  85. data/test/sass/encoding_test.rb +219 -0
  86. data/test/sass/engine_test.rb +136 -199
  87. data/test/sass/exec_test.rb +2 -2
  88. data/test/sass/extend_test.rb +236 -19
  89. data/test/sass/functions_test.rb +295 -253
  90. data/test/sass/importer_test.rb +31 -21
  91. data/test/sass/logger_test.rb +1 -1
  92. data/test/sass/more_results/more_import.css +1 -1
  93. data/test/sass/plugin_test.rb +14 -13
  94. data/test/sass/results/compact.css +1 -1
  95. data/test/sass/results/complex.css +4 -4
  96. data/test/sass/results/expanded.css +1 -1
  97. data/test/sass/results/import.css +1 -1
  98. data/test/sass/results/import_charset_ibm866.css +2 -2
  99. data/test/sass/results/mixins.css +17 -17
  100. data/test/sass/results/nested.css +1 -1
  101. data/test/sass/results/parent_ref.css +2 -2
  102. data/test/sass/results/script.css +3 -3
  103. data/test/sass/results/scss_import.css +1 -1
  104. data/test/sass/script_conversion_test.rb +10 -7
  105. data/test/sass/script_test.rb +288 -74
  106. data/test/sass/scss/css_test.rb +141 -24
  107. data/test/sass/scss/rx_test.rb +4 -4
  108. data/test/sass/scss/scss_test.rb +457 -18
  109. data/test/sass/source_map_test.rb +115 -25
  110. data/test/sass/superselector_test.rb +191 -0
  111. data/test/sass/templates/scss_import.scss +2 -1
  112. data/test/sass/test_helper.rb +1 -1
  113. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  114. data/test/sass/util/normalized_map_test.rb +1 -1
  115. data/test/sass/util/subset_map_test.rb +2 -2
  116. data/test/sass/util_test.rb +31 -1
  117. data/test/sass/value_helpers_test.rb +5 -7
  118. data/test/test_helper.rb +2 -2
  119. data/vendor/listen/CHANGELOG.md +1 -228
  120. data/vendor/listen/Gemfile +5 -15
  121. data/vendor/listen/README.md +111 -77
  122. data/vendor/listen/Rakefile +0 -42
  123. data/vendor/listen/lib/listen/adapter.rb +195 -82
  124. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  125. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  126. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  127. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  128. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  129. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  130. data/vendor/listen/lib/listen/listener.rb +135 -37
  131. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  132. data/vendor/listen/lib/listen/version.rb +1 -1
  133. data/vendor/listen/lib/listen.rb +33 -19
  134. data/vendor/listen/listen.gemspec +6 -0
  135. data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
  136. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  137. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  138. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  139. data/vendor/listen/spec/listen_spec.rb +15 -21
  140. data/vendor/listen/spec/spec_helper.rb +4 -0
  141. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  142. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  143. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  144. metadata +25 -22
  145. data/ext/mkrf_conf.rb +0 -27
  146. data/lib/sass/importers/deprecated_path.rb +0 -51
  147. data/lib/sass/script/value/deprecated_false.rb +0 -55
  148. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  149. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  150. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  151. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/../test_helper'
3
3
  require File.dirname(__FILE__) + '/test_helper'
4
4
  require 'sass/engine'
5
5
 
6
- class CacheTest < Test::Unit::TestCase
6
+ class CacheTest < MiniTest::Test
7
7
  @@cache_dir = "tmp/file_cache"
8
8
 
9
9
  def setup
@@ -18,42 +18,42 @@ class CacheTest < Test::Unit::TestCase
18
18
  def test_file_cache_writes_a_file
19
19
  file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
20
20
  file_store.store("asdf/foo.scssc", "fakesha1", root_node)
21
- assert File.exists?("#{@@cache_dir}/asdf/foo.scssc")
21
+ assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
22
22
  end
23
23
 
24
24
  def test_file_cache_reads_a_file
25
25
  file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
26
- assert !File.exists?("#{@@cache_dir}/asdf/foo.scssc")
26
+ assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
27
27
  file_store.store("asdf/foo.scssc", "fakesha1", root_node)
28
- assert File.exists?("#{@@cache_dir}/asdf/foo.scssc")
28
+ assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
29
29
  assert_kind_of Sass::Tree::RootNode, file_store.retrieve("asdf/foo.scssc", "fakesha1")
30
30
  end
31
31
 
32
32
  def test_file_cache_miss_returns_nil
33
33
  file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
34
- assert !File.exists?("#{@@cache_dir}/asdf/foo.scssc")
34
+ assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
35
35
  assert_nil file_store.retrieve("asdf/foo.scssc", "fakesha1")
36
36
  end
37
37
 
38
38
  def test_sha_change_invalidates_cache_and_cleans_up
39
39
  file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
40
- assert !File.exists?("#{@@cache_dir}/asdf/foo.scssc")
40
+ assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
41
41
  file_store.store("asdf/foo.scssc", "fakesha1", root_node)
42
- assert File.exists?("#{@@cache_dir}/asdf/foo.scssc")
42
+ assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
43
43
  assert_nil file_store.retrieve("asdf/foo.scssc", "differentsha1")
44
- assert !File.exists?("#{@@cache_dir}/asdf/foo.scssc")
44
+ assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
45
45
  end
46
46
 
47
47
  def test_version_change_invalidates_cache_and_cleans_up
48
48
  file_store = Sass::CacheStores::Filesystem.new(@@cache_dir)
49
- assert !File.exists?("#{@@cache_dir}/asdf/foo.scssc")
49
+ assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
50
50
  file_store.store("asdf/foo.scssc", "fakesha1", root_node)
51
- assert File.exists?("#{@@cache_dir}/asdf/foo.scssc")
51
+ assert File.exist?("#{@@cache_dir}/asdf/foo.scssc")
52
52
  real_version = Sass::VERSION
53
53
  begin
54
54
  Sass::VERSION.replace("a different version")
55
55
  assert_nil file_store.retrieve("asdf/foo.scssc", "fakesha1")
56
- assert !File.exists?("#{@@cache_dir}/asdf/foo.scssc")
56
+ assert !File.exist?("#{@@cache_dir}/asdf/foo.scssc")
57
57
  ensure
58
58
  Sass::VERSION.replace(real_version)
59
59
  end
@@ -66,17 +66,52 @@ class CacheTest < Test::Unit::TestCase
66
66
  assert_equal an_object, cache.retrieve("an_object", "")
67
67
  end
68
68
 
69
- class Unmarshalable
70
- def _dump(_)
71
- raise 'Unmarshalable'
72
- end
69
+ def test_cache_node_with_unmarshalable_option
70
+ engine_with_unmarshalable_options("foo {a: b + c}").to_tree
73
71
  end
74
72
 
75
- def test_cache_node_with_unmarshalable_option
76
- engine = Sass::Engine.new("foo {a: b + c}",
77
- :syntax => :scss, :object => Unmarshalable.new, :filename => 'file.scss',
78
- :importer => Sass::Importers::Filesystem.new(absolutize('templates')))
79
- engine.to_tree
73
+ # Regression tests
74
+
75
+ def test_cache_mixin_def_splat_sass_node_with_unmarshalable_option
76
+ engine_with_unmarshalable_options(<<SASS, :syntax => :sass).to_tree
77
+ =color($args...)
78
+ color: red
79
+ SASS
80
+ end
81
+
82
+ def test_cache_mixin_def_splat_scss_node_with_unmarshalable_option
83
+ engine_with_unmarshalable_options(<<SCSS, :syntax => :scss).to_tree
84
+ @mixin color($args...) {
85
+ color: red;
86
+ }
87
+ SCSS
88
+ end
89
+
90
+ def test_cache_function_splat_sass_node_with_unmarshalable_option
91
+ engine_with_unmarshalable_options(<<SASS, :syntax => :sass).to_tree
92
+ @function color($args...)
93
+ @return red
94
+ SASS
95
+ end
96
+
97
+ def test_cache_function_splat_scss_node_with_unmarshalable_option
98
+ engine_with_unmarshalable_options(<<SCSS, :syntax => :scss).to_tree
99
+ @function color($args...) {
100
+ @return red;
101
+ }
102
+ SCSS
103
+ end
104
+
105
+ def test_cache_include_splat_sass_node_with_unmarshalable_option
106
+ engine_with_unmarshalable_options(<<SASS, :syntax => :sass).to_tree
107
+ @include color($args..., $kwargs...)
108
+ SASS
109
+ end
110
+
111
+ def test_cache_include_splat_scss_node_with_unmarshalable_option
112
+ engine_with_unmarshalable_options(<<SCSS, :syntax => :scss).to_tree
113
+ @include color($args..., $kwargs...);
114
+ SCSS
80
115
  end
81
116
 
82
117
  private
@@ -86,4 +121,11 @@ class CacheTest < Test::Unit::TestCase
86
121
  div { @include color(red); }
87
122
  SCSS
88
123
  end
124
+
125
+ def engine_with_unmarshalable_options(src, options={})
126
+ Sass::Engine.new(src, {
127
+ :syntax => :scss, :object => Class.new.new, :filename => 'file.scss',
128
+ :importer => Sass::Importers::Filesystem.new(absolutize('templates'))
129
+ }.merge(options))
130
+ end
89
131
  end
@@ -26,7 +26,7 @@ module ClassLevelCallerBack
26
26
  end
27
27
  end
28
28
 
29
- class SassCallbacksTest < Test::Unit::TestCase
29
+ class SassCallbacksTest < MiniTest::Test
30
30
  def test_simple_callback
31
31
  cb = CallerBack.new
32
32
  there = false
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
- require 'test/unit'
2
+ require 'minitest/autorun'
3
3
  require File.dirname(__FILE__) + '/../test_helper'
4
4
  require 'sass/plugin'
5
5
  require 'sass/plugin/compiler'
6
6
 
7
- class CompilerTest < Test::Unit::TestCase
7
+ class CompilerTest < MiniTest::Test
8
8
  class FakeListener
9
9
  attr_accessor :options
10
10
  attr_accessor :directories
@@ -18,7 +18,7 @@ class CompilerTest < Test::Unit::TestCase
18
18
  @start_called = false
19
19
  reset_events!
20
20
  end
21
-
21
+
22
22
  def fire_events!(*args)
23
23
  @on_filesystem_event.call(@modified, @added, @removed)
24
24
  reset_events!
@@ -82,9 +82,18 @@ class CompilerTest < Test::Unit::TestCase
82
82
 
83
83
  private
84
84
  def create_listener(*args, &on_filesystem_event)
85
- @fake_listener = FakeListener.new(*args, &on_filesystem_event)
86
- @fake_listener.on_start!(&run_during_start)
87
- @fake_listener
85
+ if Sass::Util.listen_geq_2?
86
+ options = args.pop if args.last.is_a?(Hash)
87
+ args.map do |dir|
88
+ @fake_listener = FakeListener.new(*args, &on_filesystem_event)
89
+ @fake_listener.on_start!(&run_during_start)
90
+ @fake_listener
91
+ end
92
+ else
93
+ @fake_listener = FakeListener.new(*args, &on_filesystem_event)
94
+ @fake_listener.on_start!(&run_during_start)
95
+ @fake_listener
96
+ end
88
97
  end
89
98
  end
90
99
 
@@ -174,12 +183,12 @@ class CompilerTest < Test::Unit::TestCase
174
183
  directories = nil
175
184
  c = watcher do |listener|
176
185
  directories = listener.directories
177
- listener.removed "/asdf/foobar/sass/foo.scss"
186
+ listener.removed File.expand_path("./foo.scss")
178
187
  listener.fire_events!
179
188
  end
180
- c.watch([["/asdf/foobar/sass/foo.scss", "/asdf/foobar/css/foo.css", nil]])
181
- assert directories.include?("/asdf/foobar/sass"), directories.inspect
182
- assert_equal "/asdf/foobar/css/foo.css", c.deleted_css_files.first, "the corresponding css file was not deleted"
189
+ c.watch([[File.expand_path("./foo.scss"), File.expand_path("./foo.css"), nil]])
190
+ assert directories.include?(File.expand_path(".")), directories.inspect
191
+ assert_equal File.expand_path("./foo.css"), c.deleted_css_files.first, "the corresponding css file was not deleted"
183
192
  assert_equal [], c.update_stylesheets_called_with[1], "the sass file should not have been compiled"
184
193
  end
185
194
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
3
 
4
- class ConversionTest < Test::Unit::TestCase
4
+ class ConversionTest < MiniTest::Test
5
5
  def test_basic
6
6
  assert_renders <<SASS, <<SCSS
7
7
  foo bar
@@ -589,6 +589,19 @@ foo {
589
589
  SCSS
590
590
  end
591
591
 
592
+ def test_error
593
+ assert_renders <<SASS, <<SCSS
594
+ foo
595
+ @error "oh no!"
596
+ bar: baz
597
+ SASS
598
+ foo {
599
+ @error "oh no!";
600
+ bar: baz;
601
+ }
602
+ SCSS
603
+ end
604
+
592
605
  def test_directive_without_children
593
606
  assert_renders <<SASS, <<SCSS
594
607
  foo
@@ -1267,6 +1280,17 @@ $val: 20;
1267
1280
  SCSS
1268
1281
  end
1269
1282
 
1283
+ def test_media_with_feature
1284
+ assert_sass_to_scss <<SCSS, <<SASS
1285
+ @media screen and (-webkit-transform-3d) {
1286
+ a: b;
1287
+ }
1288
+ SCSS
1289
+ @media screen and (-webkit-transform-3d)
1290
+ a: b
1291
+ SASS
1292
+ end
1293
+
1270
1294
  def test_supports_with_expressions
1271
1295
  assert_renders <<SASS, <<SCSS
1272
1296
  $query: "(feature1: val)"
@@ -1808,6 +1832,39 @@ SASS
1808
1832
  SCSS
1809
1833
  end
1810
1834
 
1835
+ def test_keyframes
1836
+ assert_renders(<<SASS, <<SCSS)
1837
+ @keyframes identifier
1838
+ 0%
1839
+ top: 0
1840
+ left: 0
1841
+ 30%
1842
+ top: 50px
1843
+ 68%, 72%
1844
+ left: 50px
1845
+ 100%
1846
+ top: 100px
1847
+ left: 100%
1848
+ SASS
1849
+ @keyframes identifier {
1850
+ 0% {
1851
+ top: 0;
1852
+ left: 0;
1853
+ }
1854
+ 30% {
1855
+ top: 50px;
1856
+ }
1857
+ 68%, 72% {
1858
+ left: 50px;
1859
+ }
1860
+ 100% {
1861
+ top: 100px;
1862
+ left: 100%;
1863
+ }
1864
+ }
1865
+ SCSS
1866
+ end
1867
+
1811
1868
  ## Regression Tests
1812
1869
 
1813
1870
  def test_list_in_args
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
- require 'test/unit'
2
+ require 'minitest/autorun'
3
3
  require File.dirname(__FILE__) + '/../test_helper'
4
4
  require 'sass/css'
5
5
 
6
- class CSS2SassTest < Test::Unit::TestCase
6
+ class CSS2SassTest < MiniTest::Test
7
7
  def test_basic
8
8
  css = <<CSS
9
9
  h1 {
@@ -62,7 +62,7 @@ div .debug
62
62
  SASS
63
63
  div .warning {
64
64
  color: #d21a19; }
65
- span .debug {
65
+ span .debug {
66
66
  cursor: crosshair;}
67
67
  div .debug {
68
68
  cursor: default; }
@@ -238,7 +238,7 @@ CSS
238
238
  end
239
239
 
240
240
  def test_subject
241
- assert_equal(<<SASS, css2sass(<<CSS))
241
+ silence_warnings {assert_equal(<<SASS, css2sass(<<CSS))}
242
242
  .foo
243
243
  .bar!
244
244
  .baz
@@ -265,6 +265,25 @@ CSS
265
265
 
266
266
  # Regressions
267
267
 
268
+ def test_nesting_with_matching_property
269
+ assert_equal(<<SASS, css2sass(<<CSS))
270
+ ul
271
+ width: 10px
272
+ div
273
+ width: 20px
274
+
275
+ article
276
+ width: 10px
277
+ p
278
+ width: 20px
279
+ SASS
280
+ ul {width: 10px}
281
+ ul div {width: 20px}
282
+ article {width: 10px}
283
+ article p {width: 20px}
284
+ CSS
285
+ end
286
+
268
287
  def test_empty_rule
269
288
  assert_equal(<<SASS, css2sass(<<CSS))
270
289
  a
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/../test_helper'
4
+ require File.dirname(__FILE__) + '/test_helper'
5
+ require 'sass/util/test'
6
+
7
+ class EncodingTest < MiniTest::Test
8
+ include Sass::Util::Test
9
+
10
+ def test_encoding_error
11
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
12
+
13
+ render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
14
+ assert(false, "Expected exception")
15
+ rescue Sass::SyntaxError => e
16
+ assert_equal(3, e.sass_line)
17
+ assert_equal('Invalid UTF-8 character "\xFE"', e.message)
18
+ end
19
+
20
+ def test_ascii_incompatible_encoding_error
21
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
22
+
23
+ template = "foo\nbar\nb_z".encode("utf-16le")
24
+ template[9] = "\xFE".force_encoding("utf-16le")
25
+ render(template)
26
+ assert(false, "Expected exception")
27
+ rescue Sass::SyntaxError => e
28
+ assert_equal(3, e.sass_line)
29
+ assert_equal('Invalid UTF-16LE character "\xFE"', e.message)
30
+ end
31
+
32
+ def test_prefers_charset_to_ruby_encoding
33
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
34
+
35
+ assert_renders_encoded(<<CSS, <<SASS.encode("IBM866").force_encoding("UTF-8"))
36
+ @charset "UTF-8";
37
+ fЖЖ {
38
+ a: b; }
39
+ CSS
40
+ @charset "ibm866"
41
+ fЖЖ
42
+ a: b
43
+ SASS
44
+ end
45
+
46
+ def test_uses_ruby_encoding_without_charset
47
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
48
+
49
+ assert_renders_encoded(<<CSS, <<SASS.encode("IBM866"))
50
+ @charset "UTF-8";
51
+ тАЬ {
52
+ a: b; }
53
+ CSS
54
+ тАЬ
55
+ a: b
56
+ SASS
57
+ end
58
+
59
+ def test_multibyte_charset_without_bom_declared_as_binary
60
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
61
+
62
+ engine = Sass::Engine.new(<<SASS.encode("UTF-16LE").force_encoding("BINARY"))
63
+ @charset "utf-16le"
64
+ fóó
65
+ a: b
66
+ SASS
67
+ # Since multibyte encodings' @charset declarations aren't
68
+ # ASCII-compatible, we have to interpret the files as UTF-8 which will
69
+ # inevitably fail.
70
+ assert_raise_message(Sass::SyntaxError, "Invalid UTF-8 character \"\\xF3\"") {engine.render}
71
+ end
72
+
73
+ def test_multibyte_charset_without_bom_declared_as_utf_8
74
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
75
+
76
+ engine = Sass::Engine.new(<<SASS.encode("UTF-16LE").force_encoding("UTF-8"))
77
+ @charset "utf-16le"
78
+ fóó
79
+ a: b
80
+ SASS
81
+ # Since multibyte encodings' @charset declarations aren't
82
+ # ASCII-compatible, we have to interpret the files as UTF-8 which will
83
+ # inevitably fail.
84
+ assert_raise_message(Sass::SyntaxError, "Invalid UTF-8 character \"\\xF3\"") {engine.render}
85
+ end
86
+
87
+ def test_utf_16le_with_bom
88
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
89
+
90
+ assert_renders_encoded(<<CSS, <<SASS.encode("UTF-16LE").force_encoding("BINARY"))
91
+ @charset "UTF-8";
92
+ fóó {
93
+ a: b; }
94
+ CSS
95
+ \uFEFFfóó
96
+ a: b
97
+ SASS
98
+ end
99
+
100
+ def test_utf_16be_with_bom
101
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
102
+
103
+ assert_renders_encoded(<<CSS, <<SASS.encode("UTF-16BE").force_encoding("BINARY"))
104
+ @charset "UTF-8";
105
+ fóó {
106
+ a: b; }
107
+ CSS
108
+ \uFEFFfóó
109
+ a: b
110
+ SASS
111
+ end
112
+
113
+ def test_utf_8_with_bom
114
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
115
+
116
+ assert_renders_encoded(<<CSS, <<SASS.force_encoding("BINARY"))
117
+ @charset "UTF-8";
118
+ fóó {
119
+ a: b; }
120
+ CSS
121
+ \uFEFFfóó
122
+ a: b
123
+ SASS
124
+ end
125
+
126
+ def test_charset_with_multibyte_encoding
127
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
128
+
129
+ engine = Sass::Engine.new(<<SASS)
130
+ @charset "utf-32be"
131
+ fóó
132
+ a: b
133
+ SASS
134
+ # The charset declaration is just false here, so we should get an
135
+ # encoding error.
136
+ assert_raise_message(Sass::SyntaxError, "Invalid UTF-32BE character \"\\xC3\"") {engine.render}
137
+ end
138
+
139
+ def test_charset_with_special_case_encoding
140
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
141
+
142
+ # For some reason, a file with an ASCII-compatible UTF-16 charset
143
+ # declaration is specced to be parsed as UTF-8.
144
+ assert_renders_encoded(<<CSS, <<SASS.force_encoding("BINARY"))
145
+ @charset "UTF-8";
146
+ fóó {
147
+ a: b; }
148
+ CSS
149
+ @charset "utf-16"
150
+ fóó
151
+ a: b
152
+ SASS
153
+ end
154
+
155
+ def test_compressed_output_uses_bom
156
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
157
+
158
+ assert_equal("\uFEFFfóó{a:b}\n", render(<<SASS, :style => :compressed))
159
+ fóó
160
+ a: b
161
+ SASS
162
+ end
163
+
164
+ def test_newline_normalization
165
+ assert_equal("/* foo\nbar\nbaz\nbang\nqux */\n",
166
+ render("/* foo\nbar\r\nbaz\fbang\rqux */", :syntax => :scss))
167
+ end
168
+
169
+ def test_null_normalization
170
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
171
+
172
+ assert_equal(<<CSS, render("/* foo\x00bar\x00baz */", :syntax => :scss))
173
+ #{"@charset \"UTF-8\";\n" unless Sass::Util.ruby1_8?
174
+ }/* foo�bar�baz */
175
+ CSS
176
+ end
177
+
178
+ # Regression
179
+
180
+ def test_multibyte_prop_name
181
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
182
+
183
+ assert_equal(<<CSS, render(<<SASS))
184
+ @charset "UTF-8";
185
+ #bar {
186
+ cölor: blue; }
187
+ CSS
188
+ #bar
189
+ cölor: blue
190
+ SASS
191
+ end
192
+
193
+ def test_multibyte_and_interpolation
194
+ return skip "Can't be run on Ruby 1.8." if Sass::Util.ruby1_8?
195
+
196
+ assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
197
+ #bar {
198
+ background: a 0%; }
199
+ CSS
200
+ #bar {
201
+ // 
202
+ background: \#{a} 0%;
203
+ }
204
+ SCSS
205
+ end
206
+
207
+ private
208
+
209
+ def assert_renders_encoded(css, sass)
210
+ result = render(sass)
211
+ assert_equal css.encoding, result.encoding
212
+ assert_equal css, result
213
+ end
214
+
215
+ def render(sass, options = {})
216
+ munge_filename options
217
+ Sass::Engine.new(sass, options).render
218
+ end
219
+ end