sass 3.3.14 → 3.4.0.rc.1

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +5 -5
  4. data/VERSION +1 -1
  5. data/VERSION_DATE +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +0 -5
  10. data/lib/sass/css.rb +1 -3
  11. data/lib/sass/engine.rb +28 -39
  12. data/lib/sass/environment.rb +13 -17
  13. data/lib/sass/error.rb +6 -9
  14. data/lib/sass/exec.rb +5 -771
  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 +419 -0
  18. data/lib/sass/features.rb +6 -0
  19. data/lib/sass/importers.rb +0 -1
  20. data/lib/sass/importers/base.rb +5 -1
  21. data/lib/sass/importers/filesystem.rb +4 -21
  22. data/lib/sass/media.rb +1 -4
  23. data/lib/sass/plugin/compiler.rb +32 -136
  24. data/lib/sass/script/css_lexer.rb +1 -1
  25. data/lib/sass/script/functions.rb +363 -39
  26. data/lib/sass/script/lexer.rb +68 -50
  27. data/lib/sass/script/parser.rb +29 -14
  28. data/lib/sass/script/tree.rb +1 -0
  29. data/lib/sass/script/tree/funcall.rb +1 -1
  30. data/lib/sass/script/tree/interpolation.rb +19 -1
  31. data/lib/sass/script/tree/selector.rb +26 -0
  32. data/lib/sass/script/value.rb +0 -1
  33. data/lib/sass/script/value/bool.rb +0 -5
  34. data/lib/sass/script/value/color.rb +32 -12
  35. data/lib/sass/script/value/helpers.rb +107 -0
  36. data/lib/sass/script/value/list.rb +0 -15
  37. data/lib/sass/script/value/null.rb +0 -5
  38. data/lib/sass/script/value/number.rb +60 -14
  39. data/lib/sass/script/value/string.rb +53 -9
  40. data/lib/sass/scss/css_parser.rb +8 -2
  41. data/lib/sass/scss/parser.rb +175 -319
  42. data/lib/sass/scss/rx.rb +14 -5
  43. data/lib/sass/scss/static_parser.rb +298 -1
  44. data/lib/sass/selector.rb +56 -193
  45. data/lib/sass/selector/abstract_sequence.rb +28 -13
  46. data/lib/sass/selector/comma_sequence.rb +91 -12
  47. data/lib/sass/selector/pseudo.rb +256 -0
  48. data/lib/sass/selector/sequence.rb +99 -31
  49. data/lib/sass/selector/simple.rb +14 -25
  50. data/lib/sass/selector/simple_sequence.rb +101 -37
  51. data/lib/sass/shared.rb +1 -1
  52. data/lib/sass/source/map.rb +23 -9
  53. data/lib/sass/stack.rb +0 -6
  54. data/lib/sass/supports.rb +1 -1
  55. data/lib/sass/tree/at_root_node.rb +1 -0
  56. data/lib/sass/tree/directive_node.rb +7 -1
  57. data/lib/sass/tree/error_node.rb +18 -0
  58. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  59. data/lib/sass/tree/prop_node.rb +1 -1
  60. data/lib/sass/tree/rule_node.rb +11 -6
  61. data/lib/sass/tree/visitors/check_nesting.rb +3 -4
  62. data/lib/sass/tree/visitors/convert.rb +8 -17
  63. data/lib/sass/tree/visitors/cssize.rb +12 -24
  64. data/lib/sass/tree/visitors/deep_copy.rb +5 -0
  65. data/lib/sass/tree/visitors/perform.rb +43 -28
  66. data/lib/sass/tree/visitors/set_options.rb +5 -0
  67. data/lib/sass/tree/visitors/to_css.rb +14 -13
  68. data/lib/sass/util.rb +94 -90
  69. data/test/sass/cache_test.rb +1 -1
  70. data/test/sass/callbacks_test.rb +1 -1
  71. data/test/sass/compiler_test.rb +5 -14
  72. data/test/sass/conversion_test.rb +47 -1
  73. data/test/sass/css2sass_test.rb +3 -3
  74. data/test/sass/encoding_test.rb +219 -0
  75. data/test/sass/engine_test.rb +128 -191
  76. data/test/sass/exec_test.rb +2 -2
  77. data/test/sass/extend_test.rb +234 -17
  78. data/test/sass/functions_test.rb +268 -213
  79. data/test/sass/importer_test.rb +31 -21
  80. data/test/sass/logger_test.rb +1 -1
  81. data/test/sass/more_results/more_import.css +1 -1
  82. data/test/sass/plugin_test.rb +12 -11
  83. data/test/sass/results/compact.css +1 -1
  84. data/test/sass/results/complex.css +4 -4
  85. data/test/sass/results/expanded.css +1 -1
  86. data/test/sass/results/import.css +1 -1
  87. data/test/sass/results/import_charset_ibm866.css +2 -2
  88. data/test/sass/results/mixins.css +17 -17
  89. data/test/sass/results/nested.css +1 -1
  90. data/test/sass/results/parent_ref.css +2 -2
  91. data/test/sass/results/script.css +3 -3
  92. data/test/sass/results/scss_import.css +1 -1
  93. data/test/sass/script_conversion_test.rb +7 -4
  94. data/test/sass/script_test.rb +202 -79
  95. data/test/sass/scss/css_test.rb +95 -25
  96. data/test/sass/scss/rx_test.rb +4 -4
  97. data/test/sass/scss/scss_test.rb +363 -19
  98. data/test/sass/source_map_test.rb +48 -41
  99. data/test/sass/superselector_test.rb +191 -0
  100. data/test/sass/templates/scss_import.scss +2 -1
  101. data/test/sass/test_helper.rb +1 -1
  102. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  103. data/test/sass/util/normalized_map_test.rb +1 -1
  104. data/test/sass/util/subset_map_test.rb +2 -2
  105. data/test/sass/util_test.rb +1 -1
  106. data/test/sass/value_helpers_test.rb +3 -3
  107. data/test/test_helper.rb +2 -2
  108. metadata +30 -7
  109. data/lib/sass/importers/deprecated_path.rb +0 -51
  110. data/lib/sass/script/value/deprecated_false.rb +0 -55
@@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/test_helper'
4
4
  require 'mock_importer'
5
5
  require 'sass/plugin'
6
6
 
7
- class ImporterTest < Test::Unit::TestCase
7
+ class ImporterTest < MiniTest::Test
8
8
 
9
9
  class FruitImporter < Sass::Importers::Base
10
10
  def find(name, context = nil)
@@ -225,11 +225,11 @@ SCSS
225
225
  JSON
226
226
  end
227
227
 
228
- def test_source_map_with_only_css_uri_can_have_no_public_url_without_warning
228
+ def test_source_map_with_only_css_uri_can_have_no_public_url
229
229
  ephemeral_importer = NoPublicUrlImporter.new
230
230
  mock_importer = MockImporter.new
231
231
  def mock_importer.public_url(name, sourcemap_directory = nil)
232
- "css_uri"
232
+ "source_uri"
233
233
  end
234
234
 
235
235
  options = {
@@ -248,28 +248,26 @@ JSON
248
248
  }
249
249
  SCSS
250
250
 
251
- assert_warning("") do
252
- css_output, sourcemap = engine.render_with_sourcemap('sourcemap_uri')
253
- assert_equal <<CSS.strip, css_output.strip
251
+ css_output, sourcemap = engine.render_with_sourcemap('sourcemap_uri')
252
+ assert_equal <<CSS.strip, css_output.strip
254
253
  .orange {
255
254
  color: orange; }
256
255
 
257
256
  /*# sourceMappingURL=sourcemap_uri */
258
257
  CSS
259
- map = sourcemap.to_json(:css_uri => 'css_uri')
260
- assert_equal <<JSON.strip, map
258
+ map = sourcemap.to_json(:css_uri => 'css_uri')
259
+ assert_equal <<JSON.strip, map
261
260
  {
262
261
  "version": 3,
263
262
  "mappings": "AACA,OAAQ",
264
- "sources": ["css_uri"],
263
+ "sources": ["source_uri"],
265
264
  "names": [],
266
265
  "file": "css_uri"
267
266
  }
268
267
  JSON
269
- end
270
268
  end
271
269
 
272
- def test_source_map_with_only_css_uri_doesnt_support_filesystem_importer
270
+ def test_source_map_with_only_css_uri_falls_back_to_file_uris
273
271
  file_system_importer = Sass::Importers::Filesystem.new('.')
274
272
  options = {
275
273
  :filename => filename_for_test(:scss),
@@ -284,13 +282,19 @@ SCSS
284
282
 
285
283
  _, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
286
284
 
287
- assert_warning(<<WARNING) {sourcemap.to_json(:css_uri => 'css_uri')}
288
- WARNING: Couldn't determine public URL for "#{filename_for_test(:scss)}" while generating sourcemap.
289
- Without a public URL, there's nothing for the source map to link to.
290
- WARNING
285
+ uri = Sass::Util.file_uri_from_path(Sass::Util.absolute_path(filename_for_test(:scss)))
286
+ assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => 'css_uri')
287
+ {
288
+ "version": 3,
289
+ "mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
290
+ "sources": ["#{uri}"],
291
+ "names": [],
292
+ "file": "css_uri"
293
+ }
294
+ JSON
291
295
  end
292
296
 
293
- def test_source_map_with_css_uri_and_css_path_doesnt_support_filesystem_importer
297
+ def test_source_map_with_css_uri_and_css_path_falls_back_to_file_uris
294
298
  file_system_importer = Sass::Importers::Filesystem.new('.')
295
299
  options = {
296
300
  :filename => filename_for_test(:scss),
@@ -305,10 +309,16 @@ SCSS
305
309
 
306
310
  _, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
307
311
 
308
- assert_warning(<<WARNING) {sourcemap.to_json(:css_uri => 'css_uri', :css_path => 'css_path')}
309
- WARNING: Couldn't determine public URL for "#{filename_for_test(:scss)}" while generating sourcemap.
310
- Without a public URL, there's nothing for the source map to link to.
311
- WARNING
312
+ uri = Sass::Util.file_uri_from_path(Sass::Util.absolute_path(filename_for_test(:scss)))
313
+ assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => 'css_uri', :css_path => 'css_path')
314
+ {
315
+ "version": 3,
316
+ "mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
317
+ "sources": ["#{uri}"],
318
+ "names": [],
319
+ "file": "css_uri"
320
+ }
321
+ JSON
312
322
  end
313
323
 
314
324
  def test_source_map_with_css_uri_and_sourcemap_path_supports_filesystem_importer
@@ -397,6 +407,6 @@ MESSAGE
397
407
 
398
408
  def test_absolute_files_across_template_locations
399
409
  importer = Sass::Importers::Filesystem.new(absolutize 'templates')
400
- assert_not_nil importer.mtime(absolutize('more_templates/more1.sass'), {})
410
+ refute_nil importer.mtime(absolutize('more_templates/more1.sass'), {})
401
411
  end
402
412
  end
@@ -2,7 +2,7 @@
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
3
  require 'pathname'
4
4
 
5
- class LoggerTest < Test::Unit::TestCase
5
+ class LoggerTest < MiniTest::Test
6
6
 
7
7
  class InterceptedLogger < Sass::Logger::Base
8
8
 
@@ -24,6 +24,6 @@ body { font: Arial; background: blue; }
24
24
  #content.user.show #container.top #column.right { width: 600px; }
25
25
  #content.user.show #container.bottom { background: brown; }
26
26
 
27
- #foo { background-color: #bbaaff; }
27
+ #foo { background-color: #baf; }
28
28
 
29
29
  nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }
@@ -17,7 +17,7 @@ module Sass::Script::Functions
17
17
  end
18
18
  end
19
19
 
20
- class SassPluginTest < Test::Unit::TestCase
20
+ class SassPluginTest < MiniTest::Test
21
21
  @@templates = %w{
22
22
  complex script parent_ref import scss_import alt
23
23
  subdir/subdir subdir/nested_subdir/nested_subdir
@@ -113,7 +113,7 @@ class SassPluginTest < Test::Unit::TestCase
113
113
  File.open(tempfile_loc('bork1')) do |file|
114
114
  assert_equal(<<CSS.strip, file.read.split("\n")[0...6].join("\n"))
115
115
  /*
116
- Syntax error: Undefined variable: "$bork".
116
+ Error: Undefined variable: "$bork".
117
117
  on line 2 of #{template_loc('bork1')}
118
118
 
119
119
  1: bork
@@ -129,7 +129,7 @@ CSS
129
129
  File.open(tempfile_loc('bork5')) do |file|
130
130
  assert_equal(<<CSS.strip, file.read.split("\n")[0...7].join("\n"))
131
131
  /*
132
- Syntax error: Undefined variable: "$bork".
132
+ Error: Undefined variable: "$bork".
133
133
  on line 3 of #{template_loc('bork5')}
134
134
 
135
135
  1: bork
@@ -146,7 +146,7 @@ CSS
146
146
  File.open(tempfile_loc('single_import_loop')) do |file|
147
147
  assert_equal(<<CSS.strip, file.read.split("\n")[0...2].join("\n"))
148
148
  /*
149
- Syntax error: An @import loop has been found: #{template_loc('single_import_loop')} imports itself
149
+ Error: An @import loop has been found: #{template_loc('single_import_loop')} imports itself
150
150
  CSS
151
151
  end
152
152
  end
@@ -157,9 +157,9 @@ CSS
157
157
  File.open(tempfile_loc('double_import_loop1')) do |file|
158
158
  assert_equal(<<CSS.strip, file.read.split("\n")[0...4].join("\n"))
159
159
  /*
160
- Syntax error: An @import loop has been found:
161
- #{template_loc('double_import_loop1')} imports #{template_loc('_double_import_loop2')}
162
- #{template_loc('_double_import_loop2')} imports #{template_loc('double_import_loop1')}
160
+ Error: An @import loop has been found:
161
+ #{template_loc('double_import_loop1')} imports #{template_loc('_double_import_loop2')}
162
+ #{template_loc('_double_import_loop2')} imports #{template_loc('double_import_loop1')}
163
163
  CSS
164
164
  end
165
165
  end
@@ -170,8 +170,8 @@ CSS
170
170
  File.open(tempfile_loc('subdir/import_up1')) do |file|
171
171
  assert_equal(<<CSS.strip, file.read.split("\n")[0...5].join("\n"))
172
172
  /*
173
- Syntax error: File to import not found or unreadable: ../subdir/import_up3.scss.
174
- Load path: #{template_loc}
173
+ Error: File to import not found or unreadable: ../subdir/import_up3.scss.
174
+ Load path: #{template_loc}
175
175
  on line 1 of #{template_loc 'subdir/import_up2'}
176
176
  from line 1 of #{template_loc 'subdir/import_up1'}
177
177
  CSS
@@ -183,7 +183,7 @@ CSS
183
183
  Sass::Plugin.options[:full_exception] = false
184
184
 
185
185
  File.delete(tempfile_loc('bork1'))
186
- assert_raise(Sass::SyntaxError) {check_for_updates!}
186
+ assert_raises(Sass::SyntaxError) {check_for_updates!}
187
187
  ensure
188
188
  Sass::Plugin.options[:full_exception] = old_full_exception
189
189
  end
@@ -537,7 +537,8 @@ WARNING
537
537
  :always_update => true,
538
538
  :never_update => false,
539
539
  :full_exception => true,
540
- :cache_store => @@cache_store
540
+ :cache_store => @@cache_store,
541
+ :sourcemap => :none
541
542
  )
542
543
  Sass::Plugin.options.merge!(overrides)
543
544
  end
@@ -1,4 +1,4 @@
1
- #main { width: 15em; color: blue; }
1
+ #main { width: 15em; color: #0000ff; }
2
2
  #main p { border-style: dotted; /* Nested comment More nested stuff */ border-width: 2px; }
3
3
  #main .cool { width: 100px; }
4
4
 
@@ -1,4 +1,4 @@
1
- body { margin: 0; font: 0.85em "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; color: white; background: url(/images/global_bg.gif); }
1
+ body { margin: 0; font: 0.85em "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; color: #fff; background: url(/images/global_bg.gif); }
2
2
 
3
3
  #page { width: 900px; margin: 0 auto; background: #440008; border-top-width: 5px; border-top-style: solid; border-top-color: #ff8500; }
4
4
 
@@ -16,8 +16,8 @@ body { margin: 0; font: 0.85em "Lucida Grande", "Trebuchet MS", Verdana, sans-se
16
16
 
17
17
  #menu { clear: both; text-align: right; height: 20px; border-bottom: 5px solid #006b95; background: #00a4e4; }
18
18
  #menu .contests ul { margin: 0 5px 0 0; padding: 0; }
19
- #menu .contests ul li { list-style-type: none; margin: 0 5px; padding: 5px 5px 0 5px; display: inline; font-size: 1.1em; color: white; background: #00a4e4; }
20
- #menu .contests a:link, #menu .contests a:visited { color: white; text-decoration: none; font-weight: bold; }
19
+ #menu .contests ul li { list-style-type: none; margin: 0 5px; padding: 5px 5px 0 5px; display: inline; font-size: 1.1em; color: #fff; background: #00a4e4; }
20
+ #menu .contests a:link, #menu .contests a:visited { color: #fff; text-decoration: none; font-weight: bold; }
21
21
  #menu .contests a:hover { text-decoration: underline; }
22
22
 
23
23
  #content { clear: both; }
@@ -81,6 +81,6 @@ body { margin: 0; font: 0.85em "Lucida Grande", "Trebuchet MS", Verdana, sans-se
81
81
 
82
82
  img { border: none; }
83
83
 
84
- button.short { width: 60px; height: 22px; padding: 0 0 2px 0; color: white; border: none; background: url(/images/btn_short.gif) no-repeat; }
84
+ button.short { width: 60px; height: 22px; padding: 0 0 2px 0; color: #fff; border: none; background: url(/images/btn_short.gif) no-repeat; }
85
85
 
86
86
  table { border-collapse: collapse; }
@@ -1,6 +1,6 @@
1
1
  #main {
2
2
  width: 15em;
3
- color: blue;
3
+ color: #0000ff;
4
4
  }
5
5
  #main p {
6
6
  border-style: dotted;
@@ -26,6 +26,6 @@ body { font: Arial; background: blue; }
26
26
  #content.user.show #container.top #column.right { width: 600px; }
27
27
  #content.user.show #container.bottom { background: brown; }
28
28
 
29
- #foo { background-color: #bbaaff; }
29
+ #foo { background-color: #baf; }
30
30
 
31
31
  nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }
@@ -1,5 +1,5 @@
1
- @charset "IBM866";
1
+ @charset "UTF-8";
2
2
  @import url(foo.css);
3
3
  .foo { a: b; }
4
4
 
5
- .bar { a: �; }
5
+ .bar { a: щ; }
@@ -1,12 +1,12 @@
1
1
  #main {
2
2
  width: 15em;
3
- color: blue;
3
+ color: #0000ff;
4
4
  }
5
5
  #main p {
6
6
  border-top-width: 2px;
7
- border-top-color: #ffcc00;
7
+ border-top-color: #fc0;
8
8
  border-left-width: 1px;
9
- border-left-color: black;
9
+ border-left-color: #000;
10
10
  -moz-border-radius: 10px;
11
11
  border-style: dotted;
12
12
  border-width: 2px;
@@ -17,9 +17,9 @@
17
17
 
18
18
  #left {
19
19
  border-top-width: 2px;
20
- border-top-color: #ffcc00;
20
+ border-top-color: #fc0;
21
21
  border-left-width: 1px;
22
- border-left-color: black;
22
+ border-left-color: #000;
23
23
  -moz-border-radius: 10px;
24
24
  font-size: 2em;
25
25
  font-weight: bold;
@@ -28,25 +28,25 @@
28
28
 
29
29
  #right {
30
30
  border-top-width: 2px;
31
- border-top-color: #ffcc00;
31
+ border-top-color: #fc0;
32
32
  border-left-width: 1px;
33
- border-left-color: black;
33
+ border-left-color: #000;
34
34
  -moz-border-radius: 10px;
35
- color: red;
35
+ color: #f00;
36
36
  font-size: 20px;
37
37
  float: right;
38
38
  }
39
39
 
40
40
  .bordered {
41
41
  border-top-width: 2px;
42
- border-top-color: #ffcc00;
42
+ border-top-color: #fc0;
43
43
  border-left-width: 1px;
44
- border-left-color: black;
44
+ border-left-color: #000;
45
45
  -moz-border-radius: 10px;
46
46
  }
47
47
 
48
48
  .complex {
49
- color: red;
49
+ color: #f00;
50
50
  font-size: 20px;
51
51
  text-decoration: none;
52
52
  }
@@ -59,12 +59,12 @@
59
59
  }
60
60
  * html .complex {
61
61
  height: 1px;
62
- color: red;
62
+ color: #f00;
63
63
  font-size: 20px;
64
64
  }
65
65
 
66
66
  .more-complex {
67
- color: red;
67
+ color: #f00;
68
68
  font-size: 20px;
69
69
  text-decoration: none;
70
70
  display: inline;
@@ -80,16 +80,16 @@
80
80
  }
81
81
  * html .more-complex {
82
82
  height: 1px;
83
- color: red;
83
+ color: #f00;
84
84
  font-size: 20px;
85
85
  }
86
86
  .more-complex a:hover {
87
87
  text-decoration: underline;
88
- color: red;
88
+ color: #f00;
89
89
  font-size: 20px;
90
90
  border-top-width: 2px;
91
- border-top-color: #ffcc00;
91
+ border-top-color: #fc0;
92
92
  border-left-width: 1px;
93
- border-left-color: black;
93
+ border-left-color: #000;
94
94
  -moz-border-radius: 10px;
95
95
  }
@@ -1,6 +1,6 @@
1
1
  #main {
2
2
  width: 15em;
3
- color: blue; }
3
+ color: #0000ff; }
4
4
  #main p {
5
5
  border-style: dotted;
6
6
  /* Nested comment
@@ -1,5 +1,5 @@
1
- a { color: black; }
2
- a:hover { color: red; }
1
+ a { color: #000; }
2
+ a:hover { color: #f00; }
3
3
 
4
4
  p, div { width: 100em; }
5
5
  p foo, div foo { width: 10em; }
@@ -1,7 +1,7 @@
1
- #main { content: Hello\!; qstr: 'Quo"ted"!'; hstr: Hyph-en\!; width: 30em; background-color: black; color: #ffffaa; short-color: #112233; named-color: olive; con: "foo" bar 9 hi there "boom"; con2: "noquo" quo; }
2
- #main #sidebar { background-color: #00ff98; num-normal: 10; num-dec: 10.2; num-dec0: 99; num-neg: -10; esc: 10 \+12; many: 6; order: 7; complex: #4c9db1hi16; }
1
+ #main { content: Hello\!; qstr: 'Quo"ted"!'; hstr: Hyph-en\!; width: 30em; background-color: #000; color: #ffa; short-color: #123; named-color: olive; con: "foo" bar 9 hi there "boom"; con2: "noquo" quo; }
2
+ #main #sidebar { background-color: #00ff98; num-normal: 10; num-dec: 10.2; num-dec0: 99; num-neg: -10; esc: 10\+12; many: 6; order: 7; complex: #4c9db1hi16; }
3
3
 
4
- #plus { num-num: 7; num-num-un: 25em; num-num-un2: 23em; num-num-neg: 9.87; num-str: 100px; num-col: #b7b7b7; num-perc: 31%; str-str: "hi\ there"; str-str2: "hi there"; str-col: "14em solid #112233"; str-num: "times: 13"; col-num: #ff7b9d; col-col: #5173ff; }
4
+ #plus { num-num: 7; num-num-un: 25em; num-num-un2: 23em; num-num-neg: 9.87; num-str: 100px; num-col: #b7b7b7; num-perc: 31%; str-str: "hi there"; str-str2: "hi there"; str-col: "14em solid #123"; str-num: "times: 13"; col-num: #ff7b9d; col-col: #5173ff; }
5
5
 
6
6
  #minus { num-num: 900; col-num: #f9f9f4; col-col: #000035; unary-num: -1; unary-const: 10; unary-paren: -11; unary-two: 12; unary-many: 12; unary-crazy: -15; }
7
7
 
@@ -26,6 +26,6 @@ body { font: Arial; background: blue; }
26
26
  #content.user.show #container.top #column.right { width: 600px; }
27
27
  #content.user.show #container.bottom { background: brown; }
28
28
 
29
- #foo { background-color: #bbaaff; }
29
+ #foo { background-color: #baf; }
30
30
 
31
31
  nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }
@@ -3,7 +3,7 @@
3
3
  require File.dirname(__FILE__) + '/../test_helper'
4
4
  require 'sass/engine'
5
5
 
6
- class SassScriptConversionTest < Test::Unit::TestCase
6
+ class SassScriptConversionTest < MiniTest::Test
7
7
  def test_bool
8
8
  assert_renders "true"
9
9
  assert_renders "false"
@@ -13,9 +13,8 @@ class SassScriptConversionTest < Test::Unit::TestCase
13
13
  assert_renders "#abcdef"
14
14
  assert_renders "blue"
15
15
  assert_renders "rgba(0, 1, 2, 0.2)"
16
-
17
- assert_equal "#aabbcc", render("#abc")
18
- assert_equal "blue", render("#0000ff")
16
+ assert_renders "#abc"
17
+ assert_renders "#0000ff"
19
18
  end
20
19
 
21
20
  def test_number
@@ -109,6 +108,10 @@ class SassScriptConversionTest < Test::Unit::TestCase
109
108
  assert_renders "(foo: (bar, baz), bip: bop)"
110
109
  end
111
110
 
111
+ def test_selector
112
+ assert_renders "&"
113
+ end
114
+
112
115
  def self.test_precedence(outer, inner)
113
116
  op_outer = Sass::Script::Lexer::OPERATORS_REVERSE[outer]
114
117
  op_inner = Sass::Script::Lexer::OPERATORS_REVERSE[inner]
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
2
3
  require File.dirname(__FILE__) + '/../test_helper'
3
4
  require 'sass/engine'
4
5
 
@@ -17,7 +18,7 @@ module Sass::Script::Functions
17
18
  include Sass::Script::Functions::UserFunctions
18
19
  end
19
20
 
20
- class SassScriptTest < Test::Unit::TestCase
21
+ class SassScriptTest < MiniTest::Test
21
22
  include Sass::Script
22
23
 
23
24
  def test_color_checks_input
@@ -33,18 +34,43 @@ class SassScriptTest < Test::Unit::TestCase
33
34
  def test_string_escapes
34
35
  assert_equal "'", resolve("\"'\"")
35
36
  assert_equal '"', resolve("\"\\\"\"")
36
- assert_equal "\\\\", resolve("\"\\\\\"")
37
- assert_equal "\\02fa", resolve("\"\\02fa\"")
38
-
39
- assert_equal "'", resolve("'\\''")
40
- assert_equal '"', resolve("'\"'")
41
- assert_equal "\\\\", resolve("'\\\\'")
42
- assert_equal "\\02fa", resolve("'\\02fa'")
37
+ assert_equal "\\", resolve("\"\\\\\"")
38
+ assert_equal "", resolve("\"\\2603\"")
39
+ assert_equal "☃f", resolve("\"\\2603 f\"")
40
+ assert_equal "☃x", resolve("\"\\2603x\"")
41
+ assert_equal "\\2603", resolve("\"\\\\2603\"")
42
+
43
+ # U+FFFD is the replacement character, "".
44
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\0\"")
45
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\FFFFFF\"")
46
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\D800\"")
47
+ assert_equal [0xD7FF].pack("U"), resolve("\"\\D7FF\"")
48
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\DFFF\"")
49
+ assert_equal [0xE000].pack("U"), resolve("\"\\E000\"")
50
+ end
51
+
52
+ def test_string_escapes_are_resolved_before_operators
53
+ assert_equal "true", resolve('"abc" == "\61\62\63"')
54
+ end
55
+
56
+ def test_string_quote
57
+ assert_equal '"foo"', resolve_quoted('"foo"')
58
+ assert_equal "'f\"oo'", resolve_quoted('"f\"oo"')
59
+ assert_equal "\"f'oo\"", resolve_quoted("'f\\'oo'")
60
+ assert_equal "\"f'o\\\"o\"", resolve_quoted("'f\\'o\"o'")
61
+ assert_equal '"foo bar"', resolve_quoted('"foo\20 bar"')
62
+ assert_equal '"foo\a bar"', resolve_quoted('"foo\a bar"')
63
+ assert_equal '"x\ay"', resolve_quoted('"x\a y"')
64
+ assert_equal '"\a "', resolve_quoted('"\a\20"')
65
+ assert_equal '"\a abcdef"', resolve_quoted('"\a abcdef"')
66
+ assert_equal '"☃abcdef"', resolve_quoted('"\2603 abcdef"')
67
+ assert_equal '"\\\\"', resolve_quoted('"\\\\"')
68
+ assert_equal '"foobar"', resolve_quoted("\"foo\\\nbar\"")
43
69
  end
44
70
 
45
71
  def test_color_names
46
72
  assert_equal "white", resolve("white")
47
- assert_equal "white", resolve("#ffffff")
73
+ assert_equal "#ffffff", resolve("#ffffff")
48
74
  assert_equal "#fffffe", resolve("white - #000001")
49
75
  assert_equal "transparent", resolve("transparent")
50
76
  assert_equal "transparent", resolve("rgba(0, 0, 0, 0)")
@@ -93,7 +119,7 @@ class SassScriptTest < Test::Unit::TestCase
93
119
  assert_equal "#123", resolve("#112233", :style => :compressed)
94
120
  assert_equal "#000", resolve("black", :style => :compressed)
95
121
  assert_equal "red", resolve("#f00", :style => :compressed)
96
- assert_equal "blue", resolve("#00f", :style => :compressed)
122
+ assert_equal "blue", resolve("blue", :style => :compressed)
97
123
  assert_equal "navy", resolve("#000080", :style => :compressed)
98
124
  assert_equal "navy #fff", resolve("#000080 white", :style => :compressed)
99
125
  assert_equal "This color is #fff", resolve('"This color is #{ white }"', :style => :compressed)
@@ -255,8 +281,8 @@ SASS
255
281
  assert_equal eval('1 2 3.0'), eval('1 2 3')
256
282
  assert_equal eval('1, 2, 3.0'), eval('1, 2, 3')
257
283
  assert_equal eval('(1 2), (3, 4), (5 6)'), eval('(1 2), (3, 4), (5 6)')
258
- assert_not_equal eval('1, 2, 3'), eval('1 2 3')
259
- assert_not_equal eval('1'), eval('"1"')
284
+ refute_equal eval('1, 2, 3'), eval('1 2 3')
285
+ refute_equal eval('1'), eval('"1"')
260
286
  end
261
287
 
262
288
  def test_booleans
@@ -430,6 +456,36 @@ SASS
430
456
  assert_equal "true", resolve("1.1cm == 11mm")
431
457
  end
432
458
 
459
+ def test_length_units
460
+ assert_equal "2.54", resolve("(1in/1cm)")
461
+ assert_equal "2.3622", resolve("(1cm/1pc)")
462
+ assert_equal "4.23333", resolve("(1pc/1mm)")
463
+ assert_equal "2.83465", resolve("(1mm/1pt)")
464
+ assert_equal "1.33333", resolve("(1pt/1px)")
465
+ assert_equal "0.01042", resolve("(1px/1in)")
466
+ end
467
+
468
+ def test_angle_units
469
+ assert_equal "1.11111", resolve("(1deg/1grad)")
470
+ assert_equal "0.01571", resolve("(1grad/1rad)")
471
+ assert_equal "0.15915", resolve("(1rad/1turn)")
472
+ assert_equal "360", resolve("(1turn/1deg)")
473
+ end
474
+
475
+ def test_time_units
476
+ assert_equal "1000", resolve("(1s/1ms)")
477
+ end
478
+
479
+ def test_frequency_units
480
+ assert_equal "0.001", resolve("(1Hz/1kHz)")
481
+ end
482
+
483
+ def test_resolution_units
484
+ assert_equal "2.54", resolve("(1dpi/1dpcm)")
485
+ assert_equal "37.79528", resolve("(1dpcm/1dppx)")
486
+ assert_equal "0.01042", resolve("(1dppx/1dpi)")
487
+ end
488
+
433
489
  def test_operations_have_options
434
490
  assert_equal "Options defined!", resolve("assert_options(1 + 1)")
435
491
  assert_equal "Options defined!", resolve("assert_options('bar' + 'baz')")
@@ -462,22 +518,22 @@ SASS
462
518
  assert_equal "0.5", resolve("$var", {}, env("var" => eval("1px/2px")))
463
519
  end
464
520
 
465
- def test_colors_with_wrong_number_of_digits
466
- assert_raise_message(Sass::SyntaxError,
467
- "Colors must have either three or six digits: '#0'") {eval("#0")}
521
+ def test_non_ident_colors_with_wrong_number_of_digits
468
522
  assert_raise_message(Sass::SyntaxError,
469
- "Colors must have either three or six digits: '#12'") {eval("#12")}
523
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#1"') {eval("#1")}
470
524
  assert_raise_message(Sass::SyntaxError,
471
- "Colors must have either three or six digits: '#abcd'") {eval("#abcd")}
525
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#12"') {eval("#12")}
472
526
  assert_raise_message(Sass::SyntaxError,
473
- "Colors must have either three or six digits: '#abcdE'") {eval("#abcdE")}
527
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#1234"') {eval("#1234")}
474
528
  assert_raise_message(Sass::SyntaxError,
475
- "Colors must have either three or six digits: '#abcdEFA'") {eval("#abcdEFA")}
529
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#12345"') {eval("#12345")}
530
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "": expected expression (e.g. ' \
531
+ '1px, bold), was "#1234567"') {eval("#1234567")}
476
532
  end
477
533
 
478
534
  def test_case_insensitive_color_names
479
- assert_equal "blue", resolve("BLUE")
480
- assert_equal "red", resolve("rEd")
535
+ assert_equal "BLUE", resolve("BLUE")
536
+ assert_equal "rEd", resolve("rEd")
481
537
  assert_equal "#7f4000", resolve("mix(GrEeN, ReD)")
482
538
  end
483
539
 
@@ -523,7 +579,7 @@ SASS
523
579
  assert_raise_message(Sass::SyntaxError, 'Duplicate key 2px in map (2px: bar, 1px + 1px: baz).') do
524
580
  eval("(2px: bar, 1px + 1px: baz)")
525
581
  end
526
- assert_raise_message(Sass::SyntaxError, 'Duplicate key #0000ff in map (blue: bar, blue: baz).') do
582
+ assert_raise_message(Sass::SyntaxError, 'Duplicate key #0000ff in map (blue: bar, #00f: baz).') do
527
583
  eval("(blue: bar, #00f: baz)")
528
584
  end
529
585
  end
@@ -558,7 +614,7 @@ SASS
558
614
  return if RUBY_PLATFORM =~ /java/
559
615
 
560
616
  # Don't validate the message; it's different on Rubinius.
561
- assert_raise(ArgumentError) {resolve("arg-error()")}
617
+ assert_raises(ArgumentError) {resolve("arg-error()")}
562
618
  end
563
619
 
564
620
  def test_shallow_argument_error_unwrapped
@@ -570,49 +626,25 @@ SASS
570
626
  assert_equal "true", resolve("$ie or $undef", {}, env('ie' => Sass::Script::Value::Bool.new(true)))
571
627
  end
572
628
 
573
- def test_setting_global_variable_locally_warns
574
- assert_warning(<<WARNING) {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
575
- DEPRECATION WARNING on line 4 of test_setting_global_variable_locally_warns_inline.scss:
576
- Assigning to global variable "$var" by default is deprecated.
577
- In future versions of Sass, this will create a new local variable.
578
- If you want to assign to the global variable, use "$var: x !global" instead.
579
- Note that this will be incompatible with Sass 3.2.
580
- WARNING
581
- .foo {
582
- a: x; }
583
-
584
- .bar {
585
- b: x; }
586
- CSS
587
- $var: 1;
588
-
589
- .foo {
590
- $var: x;
591
- a: $var;
592
- }
593
-
594
- .bar {
595
- b: $var;
596
- }
597
- SCSS
598
- end
629
+ def test_selector
630
+ env = Sass::Environment.new
631
+ assert_equal "true", resolve("& == null", {}, env)
599
632
 
600
- def test_setting_global_variable_locally_warns_only_once
601
- assert_warning(<<WARNING) {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
602
- DEPRECATION WARNING on line 3 of test_setting_global_variable_locally_warns_only_once_inline.scss:
603
- Assigning to global variable "$var" by default is deprecated.
604
- In future versions of Sass, this will create a new local variable.
605
- If you want to assign to the global variable, use "$var: x !global" instead.
606
- Note that this will be incompatible with Sass 3.2.
607
- WARNING
608
- CSS
609
- $var: 1;
633
+ env.selector = selector('.foo.bar .baz.bang, .bip.bop')
634
+ assert_equal ".foo.bar .baz.bang, .bip.bop", resolve("&", {}, env)
635
+ assert_equal ".foo.bar .baz.bang", resolve("nth(&, 1)", {}, env)
636
+ assert_equal ".bip.bop", resolve("nth(&, 2)", {}, env)
637
+ assert_equal ".foo.bar", resolve("nth(nth(&, 1), 1)", {}, env)
638
+ assert_equal ".baz.bang", resolve("nth(nth(&, 1), 2)", {}, env)
639
+ assert_equal ".bip.bop", resolve("nth(nth(&, 2), 1)", {}, env)
640
+ assert_equal "string", resolve("type-of(nth(nth(&, 1), 1))", {}, env)
610
641
 
611
- @mixin foo {$var: x}
612
- @include foo;
613
- @include foo;
614
- @include foo;
615
- SCSS
642
+ env.selector = selector('.foo > .bar')
643
+ assert_equal ".foo > .bar", resolve("&", {}, env)
644
+ assert_equal ".foo > .bar", resolve("nth(&, 1)", {}, env)
645
+ assert_equal ".foo", resolve("nth(nth(&, 1), 1)", {}, env)
646
+ assert_equal ">", resolve("nth(nth(&, 1), 2)", {}, env)
647
+ assert_equal ".bar", resolve("nth(nth(&, 1), 3)", {}, env)
616
648
  end
617
649
 
618
650
  def test_setting_global_variable_globally
@@ -637,7 +669,7 @@ $var: 2;
637
669
  SCSS
638
670
  end
639
671
 
640
- def test_setting_global_variable_with_flag
672
+ def test_setting_global_variable_locally
641
673
  assert_no_warning {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
642
674
  .bar {
643
675
  a: x;
@@ -663,7 +695,7 @@ $var3: 3;
663
695
  SCSS
664
696
  end
665
697
 
666
- def test_setting_global_variable_with_flag_and_default
698
+ def test_setting_global_variable_locally_with_default
667
699
  assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
668
700
  .bar {
669
701
  a: 1;
@@ -688,21 +720,104 @@ $var1: 1;
688
720
  SCSS
689
721
  end
690
722
 
691
- def test_unclosed_special_fun
692
- assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(foo()": expected ")", was ""') do
693
- resolve("calc(foo()")
694
- end
695
- assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(#{\')\'}": expected ")", was ""') do
696
- resolve("calc(\#{')'}")
697
- end
698
- assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(#{foo": expected "}", was ""') do
699
- resolve("calc(\#{foo")
700
- end
723
+ def test_setting_local_variable
724
+ assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
725
+ .a {
726
+ value: inside; }
727
+
728
+ .b {
729
+ value: outside; }
730
+ CSS
731
+ $var: outside;
732
+
733
+ .a {
734
+ $var: inside;
735
+ value: $var;
736
+ }
737
+
738
+ .b {
739
+ value: $var;
740
+ }
741
+ SCSS
742
+ end
743
+
744
+ def test_setting_local_variable_from_inner_scope
745
+ assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
746
+ .a .b {
747
+ value: inside; }
748
+ .a .c {
749
+ value: inside; }
750
+ CSS
751
+ .a {
752
+ $var: outside;
753
+
754
+ .b {
755
+ $var: inside;
756
+ value: $var;
757
+ }
758
+
759
+ .c {
760
+ value: $var;
761
+ }
762
+ }
763
+ SCSS
764
+ end
765
+
766
+ def test_color_format_is_preserved_by_default
767
+ assert_equal "blue", resolve("blue")
768
+ assert_equal "bLuE", resolve("bLuE")
769
+ assert_equal "#00f", resolve("#00f")
770
+ assert_equal "blue #00F", resolve("blue #00F")
771
+ assert_equal "blue", resolve("nth(blue #00F, 1)")
772
+ assert_equal "#00F", resolve("nth(blue #00F, 2)")
701
773
  end
702
774
 
703
- def test_special_fun_with_interpolation
704
- assert_equal "calc())", resolve("calc(\#{')'})")
705
- assert_equal "calc(# {foo})", resolve("calc(# {foo})")
775
+ def test_color_format_isnt_always_preserved_in_compressed_style
776
+ assert_equal "red", resolve("red", :style => :compressed)
777
+ assert_equal "red", resolve("#f00", :style => :compressed)
778
+ assert_equal "red red", resolve("red #f00", :style => :compressed)
779
+ assert_equal "red", resolve("nth(red #f00, 2)", :style => :compressed)
780
+ end
781
+
782
+ def test_color_format_is_sometimes_preserved_in_compressed_style
783
+ assert_equal "ReD", resolve("ReD", :style => :compressed)
784
+ assert_equal "blue", resolve("blue", :style => :compressed)
785
+ assert_equal "#00f", resolve("#00f", :style => :compressed)
786
+ end
787
+
788
+ def test_color_format_isnt_preserved_when_modified
789
+ assert_equal "magenta", resolve("#f00 + #00f")
790
+ end
791
+
792
+ def test_ids
793
+ assert_equal "#foo", resolve("#foo")
794
+ assert_equal "#abcd", resolve("#abcd")
795
+ assert_equal "#abc-def", resolve("#abc-def")
796
+ assert_equal "#abc_def", resolve("#abc_def")
797
+ assert_equal "#uvw-xyz", resolve("#uvw-xyz")
798
+ assert_equal "#uvw_xyz", resolve("#uvw_xyz")
799
+ assert_equal "#uvwxyz", resolve("#uvw + xyz")
800
+ end
801
+
802
+ def test_scientific_notation
803
+ assert_equal "2000", resolve("2e3")
804
+ assert_equal "2000", resolve("2E3")
805
+ assert_equal "2000", resolve("2e+3")
806
+ assert_equal "2000em", resolve("2e3em")
807
+ assert_equal "25000000000", resolve("2.5e10")
808
+ assert_equal "0.1234", resolve("1234e-4")
809
+ assert_equal "12.34", resolve("1.234e1")
810
+ end
811
+
812
+ def test_identifier_units
813
+ assert_equal "5-foo", resolve("2-foo + 3-foo")
814
+ assert_equal "5-foo-", resolve("2-foo- + 3-foo-")
815
+ assert_equal "5-\\u2603", resolve("2-\\u2603 + 3-\\u2603")
816
+ end
817
+
818
+ def test_backslash_newline_in_string
819
+ assert_equal 'foobar', resolve("\"foo\\\nbar\"")
820
+ assert_equal 'foobar', resolve("'foo\\\nbar'")
706
821
  end
707
822
 
708
823
  # Regression Tests
@@ -714,6 +829,7 @@ SCSS
714
829
 
715
830
  def test_minus_without_whitespace
716
831
  assert_equal "5px", resolve("15px-10px")
832
+ assert_equal "5px-", resolve("15px--10px-")
717
833
  end
718
834
 
719
835
  def test_minus_preceded_by_comment
@@ -833,6 +949,13 @@ SASS
833
949
  val.is_a?(Sass::Script::Value::String) ? val.value : val.to_s
834
950
  end
835
951
 
952
+ def resolve_quoted(str, opts = {}, environment = env)
953
+ munge_filename opts
954
+ val = eval(str, opts, environment)
955
+ assert_kind_of Sass::Script::Value::Base, val
956
+ val.to_s
957
+ end
958
+
836
959
  def assert_unquoted(str, opts = {}, environment = env)
837
960
  munge_filename opts
838
961
  val = eval(str, opts, environment)