sass 3.1.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -118,11 +118,11 @@ SCSS
118
118
  def test_warn_directive
119
119
  expected_warning = <<EXPECTATION
120
120
  WARNING: this is a warning
121
- on line 2 of test_warn_directive_inline.scss
121
+ on line 2 of test_warn_directive_inline.scss
122
122
 
123
123
  WARNING: this is a mixin
124
- on line 1 of test_warn_directive_inline.scss, in `foo'
125
- from line 3 of test_warn_directive_inline.scss
124
+ on line 1 of test_warn_directive_inline.scss, in `foo'
125
+ from line 3 of test_warn_directive_inline.scss
126
126
  EXPECTATION
127
127
  assert_warning expected_warning do
128
128
  assert_equal <<CSS, render(<<SCSS)
@@ -163,6 +163,51 @@ CSS
163
163
  SCSS
164
164
  end
165
165
 
166
+ def test_for_directive_with_same_start_and_end
167
+ assert_equal <<CSS, render(<<SCSS)
168
+ CSS
169
+ .foo {
170
+ @for $var from 1 to 1 {a: $var;}
171
+ }
172
+ SCSS
173
+
174
+ assert_equal <<CSS, render(<<SCSS)
175
+ .foo {
176
+ a: 1; }
177
+ CSS
178
+ .foo {
179
+ @for $var from 1 through 1 {a: $var;}
180
+ }
181
+ SCSS
182
+ end
183
+
184
+ def test_decrementing_estfor_directive
185
+ assert_equal <<CSS, render(<<SCSS)
186
+ .foo {
187
+ a: 5;
188
+ a: 4;
189
+ a: 3;
190
+ a: 2;
191
+ a: 1; }
192
+ CSS
193
+ .foo {
194
+ @for $var from 5 through 1 {a: $var;}
195
+ }
196
+ SCSS
197
+
198
+ assert_equal <<CSS, render(<<SCSS)
199
+ .foo {
200
+ a: 5;
201
+ a: 4;
202
+ a: 3;
203
+ a: 2; }
204
+ CSS
205
+ .foo {
206
+ @for $var from 5 to 1 {a: $var;}
207
+ }
208
+ SCSS
209
+ end
210
+
166
211
  def test_if_directive
167
212
  assert_equal <<CSS, render(<<SCSS)
168
213
  foo {
@@ -229,7 +274,7 @@ $i: 1;
229
274
  .foo {
230
275
  @while $i != 5 {
231
276
  a: $i;
232
- $i: $i + 1;
277
+ $i: $i + 1 !global;
233
278
  }
234
279
  }
235
280
  SCSS
@@ -262,27 +307,129 @@ c {
262
307
  SCSS
263
308
  end
264
309
 
310
+ def test_destructuring_each_directive
311
+ assert_equal <<CSS, render(<<SCSS)
312
+ a {
313
+ foo: 1px;
314
+ bar: 2px;
315
+ baz: 3px; }
316
+
317
+ c {
318
+ foo: "Value is bar";
319
+ bar: "Value is baz";
320
+ bang: "Value is "; }
321
+ CSS
322
+ a {
323
+ @each $name, $number in (foo: 1px, bar: 2px, baz: 3px) {
324
+ \#{$name}: $number;
325
+ }
326
+ }
327
+ c {
328
+ @each $key, $value in (foo bar) (bar, baz) bang {
329
+ \#{$key}: "Value is \#{$value}";
330
+ }
331
+ }
332
+ SCSS
333
+ end
334
+
265
335
  def test_css_import_directive
266
336
  assert_equal "@import url(foo.css);\n", render('@import "foo.css";')
267
337
  assert_equal "@import url(foo.css);\n", render("@import 'foo.css';")
268
338
  assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
269
- assert_equal "@import url('foo.css');\n", render("@import url('foo.css');")
339
+ assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
270
340
  assert_equal "@import url(foo.css);\n", render('@import url(foo.css);')
271
341
  end
272
342
 
343
+ def test_css_string_import_directive_with_media
344
+ assert_parses '@import "foo.css" screen;'
345
+ assert_parses '@import "foo.css" screen, print;'
346
+ assert_parses '@import "foo.css" screen, print and (foo: 0);'
347
+ assert_parses '@import "foo.css" screen, only print, screen and (foo: 0);'
348
+ end
349
+
350
+ def test_css_url_import_directive_with_media
351
+ assert_parses '@import url("foo.css") screen;'
352
+ assert_parses '@import url("foo.css") screen, print;'
353
+ assert_parses '@import url("foo.css") screen, print and (foo: 0);'
354
+ assert_parses '@import url("foo.css") screen, only print, screen and (foo: 0);'
355
+ end
356
+
273
357
  def test_media_import
274
358
  assert_equal("@import \"./fonts.sass\" all;\n", render("@import \"./fonts.sass\" all;"))
275
359
  end
276
360
 
361
+ def test_dynamic_media_import
362
+ assert_equal(<<CSS, render(<<SCSS))
363
+ @import "foo" print and (-webkit-min-device-pixel-ratio-foo: 25);
364
+ CSS
365
+ $media: print;
366
+ $key: -webkit-min-device-pixel-ratio;
367
+ $value: 20;
368
+ @import "foo" \#{$media} and ($key + "-foo": $value + 5);
369
+ SCSS
370
+ end
371
+
277
372
  def test_http_import
278
373
  assert_equal("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";\n",
279
374
  render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";"))
280
375
  end
281
376
 
377
+ def test_protocol_relative_import
378
+ assert_equal("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";\n",
379
+ render("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";"))
380
+ end
381
+
382
+ def test_import_with_interpolation
383
+ assert_equal <<CSS, render(<<SCSS)
384
+ @import url("http://fonts.googleapis.com/css?family=Droid+Sans");
385
+ CSS
386
+ $family: unquote("Droid+Sans");
387
+ @import url("http://fonts.googleapis.com/css?family=\#{$family}");
388
+ SCSS
389
+ end
390
+
282
391
  def test_url_import
283
392
  assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass);"))
284
393
  end
285
394
 
395
+ def test_css_import_doesnt_move_through_comments
396
+ assert_equal <<CSS, render(<<SCSS)
397
+ /* Comment 1 */
398
+ @import url("foo.css");
399
+ /* Comment 2 */
400
+ @import url("bar.css");
401
+ CSS
402
+ /* Comment 1 */
403
+ @import url("foo.css");
404
+
405
+ /* Comment 2 */
406
+ @import url("bar.css");
407
+ SCSS
408
+ end
409
+
410
+ def test_css_import_movement_stops_at_comments
411
+ assert_equal <<CSS, render(<<SCSS)
412
+ /* Comment 1 */
413
+ @import url("foo.css");
414
+ /* Comment 2 */
415
+ @import url("bar.css");
416
+ .foo {
417
+ a: b; }
418
+
419
+ /* Comment 3 */
420
+ CSS
421
+ /* Comment 1 */
422
+ @import url("foo.css");
423
+
424
+ /* Comment 2 */
425
+
426
+ .foo {a: b}
427
+
428
+ /* Comment 3 */
429
+ @import url("bar.css");
430
+ SCSS
431
+ end
432
+
286
433
  def test_block_comment_in_script
287
434
  assert_equal <<CSS, render(<<SCSS)
288
435
  foo {
@@ -497,6 +644,63 @@ foo {
497
644
  SCSS
498
645
  end
499
646
 
647
+ def test_parent_selector_with_subject
648
+ assert_equal <<CSS, render(<<SCSS)
649
+ bar foo.baz! .bip {
650
+ a: b; }
651
+
652
+ bar foo bar.baz! .bip {
653
+ c: d; }
654
+ CSS
655
+ foo {
656
+ bar &.baz! .bip {a: b}}
657
+
658
+ foo bar {
659
+ bar &.baz! .bip {c: d}}
660
+ SCSS
661
+ end
662
+
663
+ def test_parent_selector_with_suffix
664
+ assert_equal <<CSS, render(<<SCSS)
665
+ .foo-bar {
666
+ a: b; }
667
+ .foo_bar {
668
+ c: d; }
669
+ .foobar {
670
+ e: f; }
671
+ .foo123 {
672
+ e: f; }
673
+
674
+ :hover-suffix {
675
+ g: h; }
676
+ CSS
677
+ .foo {
678
+ &-bar {a: b}
679
+ &_bar {c: d}
680
+ &bar {e: f}
681
+ &123 {e: f}
682
+ }
683
+
684
+ :hover {
685
+ &-suffix {g: h}
686
+ }
687
+ SCSS
688
+ end
689
+
690
+ def test_unknown_directive_bubbling
691
+ assert_equal(<<CSS, render(<<SCSS, :style => :nested))
692
+ @fblthp {
693
+ .foo .bar {
694
+ a: b; } }
695
+ CSS
696
+ .foo {
697
+ @fblthp {
698
+ .bar {a: b}
699
+ }
700
+ }
701
+ SCSS
702
+ end
703
+
500
704
  ## Namespace Properties
501
705
 
502
706
  def test_namespace_properties
@@ -731,151 +935,1931 @@ bar {
731
935
  SASS
732
936
  end
733
937
 
734
- ## Interpolation
938
+ ## Var Args
735
939
 
736
- def test_basic_selector_interpolation
737
- assert_equal <<CSS, render(<<SCSS)
738
- foo 3 baz {
739
- a: b; }
740
- CSS
741
- foo \#{1 + 2} baz {a: b}
742
- SCSS
743
- assert_equal <<CSS, render(<<SCSS)
744
- foo.bar baz {
745
- a: b; }
746
- CSS
747
- foo\#{".bar"} baz {a: b}
748
- SCSS
940
+ def test_mixin_var_args
749
941
  assert_equal <<CSS, render(<<SCSS)
750
- foo.bar baz {
751
- a: b; }
942
+ .foo {
943
+ a: 1;
944
+ b: 2, 3, 4; }
752
945
  CSS
753
- \#{"foo"}.bar baz {a: b}
946
+ @mixin foo($a, $b...) {
947
+ a: $a;
948
+ b: $b;
949
+ }
950
+
951
+ .foo {@include foo(1, 2, 3, 4)}
754
952
  SCSS
755
953
  end
756
954
 
757
- def test_selector_only_interpolation
955
+ def test_mixin_empty_var_args
758
956
  assert_equal <<CSS, render(<<SCSS)
759
- foo bar {
760
- a: b; }
957
+ .foo {
958
+ a: 1;
959
+ b: 0; }
761
960
  CSS
762
- \#{"foo" + " bar"} {a: b}
961
+ @mixin foo($a, $b...) {
962
+ a: $a;
963
+ b: length($b);
964
+ }
965
+
966
+ .foo {@include foo(1)}
763
967
  SCSS
764
968
  end
765
969
 
766
- def test_selector_interpolation_before_element_name
970
+ def test_mixin_var_args_act_like_list
767
971
  assert_equal <<CSS, render(<<SCSS)
768
- foo barbaz {
769
- a: b; }
972
+ .foo {
973
+ a: 3;
974
+ b: 3; }
770
975
  CSS
771
- \#{"foo" + " bar"}baz {a: b}
976
+ @mixin foo($a, $b...) {
977
+ a: length($b);
978
+ b: nth($b, 2);
979
+ }
980
+
981
+ .foo {@include foo(1, 2, 3, 4)}
772
982
  SCSS
773
983
  end
774
984
 
775
- def test_selector_interpolation_in_string
985
+ def test_mixin_splat_args
776
986
  assert_equal <<CSS, render(<<SCSS)
777
- foo[val="bar foo bar baz"] {
778
- a: b; }
987
+ .foo {
988
+ a: 1;
989
+ b: 2;
990
+ c: 3;
991
+ d: 4; }
779
992
  CSS
780
- foo[val="bar \#{"foo" + " bar"} baz"] {a: b}
993
+ @mixin foo($a, $b, $c, $d) {
994
+ a: $a;
995
+ b: $b;
996
+ c: $c;
997
+ d: $d;
998
+ }
999
+
1000
+ $list: 2, 3, 4;
1001
+ .foo {@include foo(1, $list...)}
781
1002
  SCSS
782
1003
  end
783
1004
 
784
- def test_selector_interpolation_in_pseudoclass
1005
+ def test_mixin_splat_expression
785
1006
  assert_equal <<CSS, render(<<SCSS)
786
- foo:nth-child(5n) {
787
- a: b; }
1007
+ .foo {
1008
+ a: 1;
1009
+ b: 2;
1010
+ c: 3;
1011
+ d: 4; }
788
1012
  CSS
789
- foo:nth-child(\#{5 + "n"}) {a: b}
1013
+ @mixin foo($a, $b, $c, $d) {
1014
+ a: $a;
1015
+ b: $b;
1016
+ c: $c;
1017
+ d: $d;
1018
+ }
1019
+
1020
+ .foo {@include foo(1, (2, 3, 4)...)}
790
1021
  SCSS
791
1022
  end
792
1023
 
793
- def test_selector_interpolation_at_class_begininng
1024
+ def test_mixin_splat_args_with_var_args
794
1025
  assert_equal <<CSS, render(<<SCSS)
795
- .zzz {
796
- a: b; }
1026
+ .foo {
1027
+ a: 1;
1028
+ b: 2, 3, 4; }
797
1029
  CSS
798
- $zzz: zzz;
799
- .\#{$zzz} { a: b; }
1030
+ @mixin foo($a, $b...) {
1031
+ a: $a;
1032
+ b: $b;
1033
+ }
1034
+
1035
+ $list: 2, 3, 4;
1036
+ .foo {@include foo(1, $list...)}
800
1037
  SCSS
801
1038
  end
802
1039
 
803
- def test_selector_interpolation_at_id_begininng
1040
+ def test_mixin_splat_args_with_var_args_and_normal_args
804
1041
  assert_equal <<CSS, render(<<SCSS)
805
- #zzz {
806
- a: b; }
1042
+ .foo {
1043
+ a: 1;
1044
+ b: 2;
1045
+ c: 3, 4; }
807
1046
  CSS
808
- $zzz: zzz;
809
- #\#{$zzz} { a: b; }
1047
+ @mixin foo($a, $b, $c...) {
1048
+ a: $a;
1049
+ b: $b;
1050
+ c: $c;
1051
+ }
1052
+
1053
+ $list: 2, 3, 4;
1054
+ .foo {@include foo(1, $list...)}
810
1055
  SCSS
811
1056
  end
812
1057
 
813
- def test_selector_interpolation_at_pseudo_begininng
1058
+ def test_mixin_splat_args_with_var_args_preserves_separator
814
1059
  assert_equal <<CSS, render(<<SCSS)
815
- :zzz::zzz {
816
- a: b; }
1060
+ .foo {
1061
+ a: 1;
1062
+ b: 2 3 4 5; }
817
1063
  CSS
818
- $zzz: zzz;
819
- :\#{$zzz}::\#{$zzz} { a: b; }
1064
+ @mixin foo($a, $b...) {
1065
+ a: $a;
1066
+ b: $b;
1067
+ }
1068
+
1069
+ $list: 3 4 5;
1070
+ .foo {@include foo(1, 2, $list...)}
820
1071
  SCSS
821
1072
  end
822
1073
 
823
- def test_selector_interpolation_at_attr_beginning
1074
+ def test_mixin_var_and_splat_args_pass_through_keywords
824
1075
  assert_equal <<CSS, render(<<SCSS)
825
- [zzz=foo] {
826
- a: b; }
1076
+ .foo {
1077
+ a: 3;
1078
+ b: 1;
1079
+ c: 2; }
827
1080
  CSS
828
- $zzz: zzz;
829
- [\#{$zzz}=foo] { a: b; }
1081
+ @mixin foo($a...) {
1082
+ @include bar($a...);
1083
+ }
1084
+
1085
+ @mixin bar($b, $c, $a) {
1086
+ a: $a;
1087
+ b: $b;
1088
+ c: $c;
1089
+ }
1090
+
1091
+ .foo {@include foo(1, $c: 2, $a: 3)}
830
1092
  SCSS
831
1093
  end
832
1094
 
833
- def test_selector_interpolation_at_dashes
1095
+ def test_mixin_var_keyword_args
834
1096
  assert_equal <<CSS, render(<<SCSS)
835
- div {
836
- -foo-a-b-foo: foo; }
1097
+ .foo {
1098
+ a: 1;
1099
+ b: 2;
1100
+ c: 3; }
837
1101
  CSS
838
- $a : a;
839
- $b : b;
840
- div { -foo-\#{$a}-\#{$b}-foo: foo }
1102
+ @mixin foo($args...) {
1103
+ a: map-get(keywords($args), a);
1104
+ b: map-get(keywords($args), b);
1105
+ c: map-get(keywords($args), c);
1106
+ }
1107
+
1108
+ .foo {@include foo($a: 1, $b: 2, $c: 3)}
841
1109
  SCSS
842
1110
  end
843
1111
 
844
- def test_basic_prop_name_interpolation
1112
+ def test_mixin_empty_var_keyword_args
845
1113
  assert_equal <<CSS, render(<<SCSS)
846
- foo {
847
- barbazbang: blip; }
1114
+ .foo {
1115
+ length: 0; }
848
1116
  CSS
849
- foo {bar\#{"baz" + "bang"}: blip}
1117
+ @mixin foo($args...) {
1118
+ length: length(keywords($args));
1119
+ }
1120
+
1121
+ .foo {@include foo}
850
1122
  SCSS
1123
+ end
1124
+
1125
+ def test_mixin_map_splat
851
1126
  assert_equal <<CSS, render(<<SCSS)
852
- foo {
853
- bar3: blip; }
1127
+ .foo {
1128
+ a: 1;
1129
+ b: 2;
1130
+ c: 3; }
854
1131
  CSS
855
- foo {bar\#{1 + 2}: blip}
1132
+ @mixin foo($a, $b, $c) {
1133
+ a: $a;
1134
+ b: $b;
1135
+ c: $c;
1136
+ }
1137
+
1138
+ .foo {
1139
+ $map: (a: 1, b: 2, c: 3);
1140
+ @include foo($map...);
1141
+ }
856
1142
  SCSS
857
1143
  end
858
1144
 
859
- def test_prop_name_only_interpolation
1145
+ def test_mixin_map_and_list_splat
860
1146
  assert_equal <<CSS, render(<<SCSS)
861
- foo {
862
- bazbang: blip; }
863
- CSS
864
- foo {\#{"baz" + "bang"}: blip}
1147
+ .foo {
1148
+ a: x;
1149
+ b: y;
1150
+ c: z;
1151
+ d: 1;
1152
+ e: 2;
1153
+ f: 3; }
1154
+ CSS
1155
+ @mixin foo($a, $b, $c, $d, $e, $f) {
1156
+ a: $a;
1157
+ b: $b;
1158
+ c: $c;
1159
+ d: $d;
1160
+ e: $e;
1161
+ f: $f;
1162
+ }
1163
+
1164
+ .foo {
1165
+ $list: x y z;
1166
+ $map: (d: 1, e: 2, f: 3);
1167
+ @include foo($list..., $map...);
1168
+ }
865
1169
  SCSS
866
1170
  end
867
1171
 
868
- ## Errors
1172
+ def test_mixin_map_splat_takes_precedence_over_pass_through
1173
+ assert_equal <<CSS, render(<<SCSS)
1174
+ .foo {
1175
+ a: 1;
1176
+ b: 2;
1177
+ c: z; }
1178
+ CSS
1179
+ @mixin foo($args...) {
1180
+ $map: (c: z);
1181
+ @include bar($args..., $map...);
1182
+ }
1183
+
1184
+ @mixin bar($a, $b, $c) {
1185
+ a: $a;
1186
+ b: $b;
1187
+ c: $c;
1188
+ }
1189
+
1190
+ .foo {
1191
+ @include foo(1, $b: 2, $c: 3);
1192
+ }
1193
+ SCSS
1194
+ end
1195
+
1196
+ def test_mixin_list_of_pairs_splat_treated_as_list
1197
+ assert_equal <<CSS, render(<<SCSS)
1198
+ .foo {
1199
+ a: a 1;
1200
+ b: b 2;
1201
+ c: c 3; }
1202
+ CSS
1203
+ @mixin foo($a, $b, $c) {
1204
+ a: $a;
1205
+ b: $b;
1206
+ c: $c;
1207
+ }
1208
+
1209
+ .foo {
1210
+ @include foo((a 1, b 2, c 3)...);
1211
+ }
1212
+ SCSS
1213
+ end
1214
+
1215
+ def test_mixin_splat_after_keyword_args
1216
+ assert_equal <<CSS, render(<<SCSS)
1217
+ .foo {
1218
+ a: 1;
1219
+ b: 2;
1220
+ c: 3; }
1221
+ CSS
1222
+ @mixin foo($a, $b, $c) {
1223
+ a: 1;
1224
+ b: 2;
1225
+ c: 3;
1226
+ }
1227
+
1228
+ .foo {
1229
+ @include foo(1, $c: 3, 2...);
1230
+ }
1231
+ SCSS
1232
+ end
1233
+
1234
+ def test_mixin_keyword_args_after_splat
1235
+ assert_equal <<CSS, render(<<SCSS)
1236
+ .foo {
1237
+ a: 1;
1238
+ b: 2;
1239
+ c: 3; }
1240
+ CSS
1241
+ @mixin foo($a, $b, $c) {
1242
+ a: 1;
1243
+ b: 2;
1244
+ c: 3;
1245
+ }
1246
+
1247
+ .foo {
1248
+ @include foo(1, 2..., $c: 3);
1249
+ }
1250
+ SCSS
1251
+ end
1252
+
1253
+ def test_mixin_keyword_splat_after_keyword_args
1254
+ assert_equal <<CSS, render(<<SCSS)
1255
+ .foo {
1256
+ a: 1;
1257
+ b: 2;
1258
+ c: 3; }
1259
+ CSS
1260
+ @mixin foo($a, $b, $c) {
1261
+ a: 1;
1262
+ b: 2;
1263
+ c: 3;
1264
+ }
1265
+
1266
+ .foo {
1267
+ @include foo(1, $b: 2, (c: 3)...);
1268
+ }
1269
+ SCSS
1270
+ end
1271
+
1272
+ def test_mixin_triple_keyword_splat_merge
1273
+ assert_equal <<CSS, render(<<SCSS)
1274
+ .foo {
1275
+ foo: 1;
1276
+ bar: 2;
1277
+ kwarg: 3;
1278
+ a: 3;
1279
+ b: 2;
1280
+ c: 3; }
1281
+ CSS
1282
+ @mixin foo($foo, $bar, $kwarg, $a, $b, $c) {
1283
+ foo: $foo;
1284
+ bar: $bar;
1285
+ kwarg: $kwarg;
1286
+ a: $a;
1287
+ b: $b;
1288
+ c: $c;
1289
+ }
1290
+
1291
+ @mixin bar($args...) {
1292
+ @include foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1293
+ }
1294
+
1295
+ .foo {
1296
+ @include bar($foo: 1, $a: 1, $b: 1, $c: 1);
1297
+ }
1298
+ SCSS
1299
+ end
1300
+
1301
+ def test_mixin_map_splat_converts_hyphens_and_underscores_for_real_args
1302
+ assert_equal <<CSS, render(<<SCSS)
1303
+ .foo {
1304
+ a: 1;
1305
+ b: 2;
1306
+ c: 3;
1307
+ d: 4; }
1308
+ CSS
1309
+ @mixin foo($a-1, $b-2, $c_3, $d_4) {
1310
+ a: $a-1;
1311
+ b: $b-2;
1312
+ c: $c_3;
1313
+ d: $d_4;
1314
+ }
1315
+
1316
+ .foo {
1317
+ $map: (a-1: 1, b_2: 2, c-3: 3, d_4: 4);
1318
+ @include foo($map...);
1319
+ }
1320
+ SCSS
1321
+ end
1322
+
1323
+ def test_mixin_map_splat_doesnt_convert_hyphens_and_underscores_for_var_args
1324
+ assert_equal <<CSS, render(<<SCSS)
1325
+ .foo {
1326
+ a-1: 1;
1327
+ b_2: 2;
1328
+ c-3: 3;
1329
+ d_4: 4; }
1330
+ CSS
1331
+ @mixin foo($args...) {
1332
+ @each $key, $value in keywords($args) {
1333
+ \#{$key}: $value;
1334
+ }
1335
+ }
1336
+
1337
+ .foo {
1338
+ $map: (a-1: 1, b_2: 2, c-3: 3, d_4: 4);
1339
+ @include foo($map...);
1340
+ }
1341
+ SCSS
1342
+ end
1343
+
1344
+ def test_mixin_conflicting_splat_after_keyword_args
1345
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1346
+ Mixin foo was passed argument $b both by position and by name.
1347
+ MESSAGE
1348
+ @mixin foo($a, $b, $c) {
1349
+ a: 1;
1350
+ b: 2;
1351
+ c: 3;
1352
+ }
1353
+
1354
+ .foo {
1355
+ @include foo(1, $b: 2, 3...);
1356
+ }
1357
+ SCSS
1358
+ end
1359
+
1360
+ def test_mixin_keyword_splat_must_have_string_keys
1361
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1362
+ Variable keyword argument map must have string keys.
1363
+ 12 is not a string in (12: 1).
1364
+ MESSAGE
1365
+ @mixin foo($a) {
1366
+ a: $a;
1367
+ }
1368
+
1369
+ .foo {@include foo((12: 1)...)}
1370
+ SCSS
1371
+ end
1372
+
1373
+ def test_mixin_positional_arg_after_splat
1374
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1375
+ Only keyword arguments may follow variable arguments (...).
1376
+ MESSAGE
1377
+ @mixin foo($a, $b, $c) {
1378
+ a: 1;
1379
+ b: 2;
1380
+ c: 3;
1381
+ }
1382
+
1383
+ .foo {
1384
+ @include foo(1, 2..., 3);
1385
+ }
1386
+ SCSS
1387
+ end
1388
+
1389
+ def test_mixin_var_args_with_keyword
1390
+ assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1391
+ @mixin foo($a, $b...) {
1392
+ a: $a;
1393
+ b: $b;
1394
+ }
1395
+
1396
+ .foo {@include foo($a: 1, 2, 3, 4)}
1397
+ SCSS
1398
+ end
1399
+
1400
+ def test_mixin_keyword_for_var_arg
1401
+ assert_raise_message(Sass::SyntaxError, "Argument $b of mixin foo cannot be used as a named argument.") {render <<SCSS}
1402
+ @mixin foo($a, $b...) {
1403
+ a: $a;
1404
+ b: $b;
1405
+ }
1406
+
1407
+ .foo {@include foo(1, $b: 2 3 4)}
1408
+ SCSS
1409
+ end
1410
+
1411
+ def test_mixin_keyword_for_unknown_arg_with_var_args
1412
+ assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
1413
+ @mixin foo($a, $b...) {
1414
+ a: $a;
1415
+ b: $b;
1416
+ }
1417
+
1418
+ .foo {@include foo(1, $c: 2 3 4)}
1419
+ SCSS
1420
+ end
1421
+
1422
+ def test_mixin_map_splat_before_list_splat
1423
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render <<SCSS}
1424
+ @mixin foo($a, $b, $c) {
1425
+ a: $a;
1426
+ b: $b;
1427
+ c: $c;
1428
+ }
1429
+
1430
+ .foo {
1431
+ @include foo((a: 1)..., (2 3)...);
1432
+ }
1433
+ SCSS
1434
+ end
1435
+
1436
+ def test_mixin_map_splat_with_unknown_keyword
1437
+ assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
1438
+ @mixin foo($a, $b) {
1439
+ a: $a;
1440
+ b: $b;
1441
+ }
1442
+
1443
+ .foo {
1444
+ @include foo(1, 2, (c: 1)...);
1445
+ }
1446
+ SCSS
1447
+ end
1448
+
1449
+ def test_mixin_map_splat_with_wrong_type
1450
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render <<SCSS}
1451
+ @mixin foo($a, $b) {
1452
+ a: $a;
1453
+ b: $b;
1454
+ }
1455
+
1456
+ .foo {
1457
+ @include foo((1, 2)..., 12...);
1458
+ }
1459
+ SCSS
1460
+ end
1461
+
1462
+ def test_function_var_args
1463
+ assert_equal <<CSS, render(<<SCSS)
1464
+ .foo {
1465
+ val: "a: 1, b: 2, 3, 4"; }
1466
+ CSS
1467
+ @function foo($a, $b...) {
1468
+ @return "a: \#{$a}, b: \#{$b}";
1469
+ }
1470
+
1471
+ .foo {val: foo(1, 2, 3, 4)}
1472
+ SCSS
1473
+ end
1474
+
1475
+ def test_function_empty_var_args
1476
+ assert_equal <<CSS, render(<<SCSS)
1477
+ .foo {
1478
+ val: "a: 1, b: 0"; }
1479
+ CSS
1480
+ @function foo($a, $b...) {
1481
+ @return "a: \#{$a}, b: \#{length($b)}";
1482
+ }
1483
+
1484
+ .foo {val: foo(1)}
1485
+ SCSS
1486
+ end
1487
+
1488
+ def test_function_var_args_act_like_list
1489
+ assert_equal <<CSS, render(<<SCSS)
1490
+ .foo {
1491
+ val: "a: 3, b: 3"; }
1492
+ CSS
1493
+ @function foo($a, $b...) {
1494
+ @return "a: \#{length($b)}, b: \#{nth($b, 2)}";
1495
+ }
1496
+
1497
+ .foo {val: foo(1, 2, 3, 4)}
1498
+ SCSS
1499
+ end
1500
+
1501
+ def test_function_splat_args
1502
+ assert_equal <<CSS, render(<<SCSS)
1503
+ .foo {
1504
+ val: "a: 1, b: 2, c: 3, d: 4"; }
1505
+ CSS
1506
+ @function foo($a, $b, $c, $d) {
1507
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
1508
+ }
1509
+
1510
+ $list: 2, 3, 4;
1511
+ .foo {val: foo(1, $list...)}
1512
+ SCSS
1513
+ end
1514
+
1515
+ def test_function_splat_expression
1516
+ assert_equal <<CSS, render(<<SCSS)
1517
+ .foo {
1518
+ val: "a: 1, b: 2, c: 3, d: 4"; }
1519
+ CSS
1520
+ @function foo($a, $b, $c, $d) {
1521
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
1522
+ }
1523
+
1524
+ .foo {val: foo(1, (2, 3, 4)...)}
1525
+ SCSS
1526
+ end
1527
+
1528
+ def test_function_splat_args_with_var_args
1529
+ assert_equal <<CSS, render(<<SCSS)
1530
+ .foo {
1531
+ val: "a: 1, b: 2, 3, 4"; }
1532
+ CSS
1533
+ @function foo($a, $b...) {
1534
+ @return "a: \#{$a}, b: \#{$b}";
1535
+ }
1536
+
1537
+ $list: 2, 3, 4;
1538
+ .foo {val: foo(1, $list...)}
1539
+ SCSS
1540
+ end
1541
+
1542
+ def test_function_splat_args_with_var_args_and_normal_args
1543
+ assert_equal <<CSS, render(<<SCSS)
1544
+ .foo {
1545
+ val: "a: 1, b: 2, c: 3, 4"; }
1546
+ CSS
1547
+ @function foo($a, $b, $c...) {
1548
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1549
+ }
1550
+
1551
+ $list: 2, 3, 4;
1552
+ .foo {val: foo(1, $list...)}
1553
+ SCSS
1554
+ end
1555
+
1556
+ def test_function_splat_args_with_var_args_preserves_separator
1557
+ assert_equal <<CSS, render(<<SCSS)
1558
+ .foo {
1559
+ val: "a: 1, b: 2 3 4 5"; }
1560
+ CSS
1561
+ @function foo($a, $b...) {
1562
+ @return "a: \#{$a}, b: \#{$b}";
1563
+ }
1564
+
1565
+ $list: 3 4 5;
1566
+ .foo {val: foo(1, 2, $list...)}
1567
+ SCSS
1568
+ end
1569
+
1570
+ def test_function_var_and_splat_args_pass_through_keywords
1571
+ assert_equal <<CSS, render(<<SCSS)
1572
+ .foo {
1573
+ val: "a: 3, b: 1, c: 2"; }
1574
+ CSS
1575
+ @function foo($a...) {
1576
+ @return bar($a...);
1577
+ }
1578
+
1579
+ @function bar($b, $c, $a) {
1580
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1581
+ }
1582
+
1583
+ .foo {val: foo(1, $c: 2, $a: 3)}
1584
+ SCSS
1585
+ end
1586
+
1587
+ def test_function_var_keyword_args
1588
+ assert_equal <<CSS, render(<<SCSS)
1589
+ .foo {
1590
+ val: "a: 1, b: 2, c: 3"; }
1591
+ CSS
1592
+ @function foo($args...) {
1593
+ @return "a: \#{map-get(keywords($args), a)}, " +
1594
+ "b: \#{map-get(keywords($args), b)}, " +
1595
+ "c: \#{map-get(keywords($args), c)}";
1596
+ }
1597
+
1598
+ .foo {val: foo($a: 1, $b: 2, $c: 3)}
1599
+ SCSS
1600
+ end
1601
+
1602
+ def test_function_empty_var_keyword_args
1603
+ assert_equal <<CSS, render(<<SCSS)
1604
+ .foo {
1605
+ length: 0; }
1606
+ CSS
1607
+ @function foo($args...) {
1608
+ @return length(keywords($args));
1609
+ }
1610
+
1611
+ .foo {length: foo()}
1612
+ SCSS
1613
+ end
1614
+
1615
+ def test_function_map_splat
1616
+ assert_equal <<CSS, render(<<SCSS)
1617
+ .foo {
1618
+ val: "a: 1, b: 2, c: 3"; }
1619
+ CSS
1620
+ @function foo($a, $b, $c) {
1621
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1622
+ }
1623
+
1624
+ .foo {
1625
+ $map: (a: 1, b: 2, c: 3);
1626
+ val: foo($map...);
1627
+ }
1628
+ SCSS
1629
+ end
1630
+
1631
+ def test_function_map_and_list_splat
1632
+ assert_equal <<CSS, render(<<SCSS)
1633
+ .foo {
1634
+ val: "a: x, b: y, c: z, d: 1, e: 2, f: 3"; }
1635
+ CSS
1636
+ @function foo($a, $b, $c, $d, $e, $f) {
1637
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}, e: \#{$e}, f: \#{$f}";
1638
+ }
1639
+
1640
+ .foo {
1641
+ $list: x y z;
1642
+ $map: (d: 1, e: 2, f: 3);
1643
+ val: foo($list..., $map...);
1644
+ }
1645
+ SCSS
1646
+ end
1647
+
1648
+ def test_function_map_splat_takes_precedence_over_pass_through
1649
+ assert_equal <<CSS, render(<<SCSS)
1650
+ .foo {
1651
+ val: "a: 1, b: 2, c: z"; }
1652
+ CSS
1653
+ @function foo($args...) {
1654
+ $map: (c: z);
1655
+ @return bar($args..., $map...);
1656
+ }
1657
+
1658
+ @function bar($a, $b, $c) {
1659
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1660
+ }
1661
+
1662
+ .foo {
1663
+ val: foo(1, $b: 2, $c: 3);
1664
+ }
1665
+ SCSS
1666
+ end
1667
+
1668
+ def test_ruby_function_map_splat_takes_precedence_over_pass_through
1669
+ assert_equal <<CSS, render(<<SCSS)
1670
+ .foo {
1671
+ val: 1 2 3 z; }
1672
+ CSS
1673
+ @function foo($args...) {
1674
+ $map: (val: z);
1675
+ @return append($args..., $map...);
1676
+ }
1677
+
1678
+ .foo {
1679
+ val: foo(1 2 3, $val: 4)
1680
+ }
1681
+ SCSS
1682
+ end
1683
+
1684
+ def test_function_list_of_pairs_splat_treated_as_list
1685
+ assert_equal <<CSS, render(<<SCSS)
1686
+ .foo {
1687
+ val: "a: a 1, b: b 2, c: c 3"; }
1688
+ CSS
1689
+ @function foo($a, $b, $c) {
1690
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1691
+ }
1692
+
1693
+ .foo {
1694
+ val: foo((a 1, b 2, c 3)...);
1695
+ }
1696
+ SCSS
1697
+ end
1698
+
1699
+ def test_function_splat_after_keyword_args
1700
+ assert_equal <<CSS, render(<<SCSS)
1701
+ .foo {
1702
+ val: "a: 1, b: 2, c: 3"; }
1703
+ CSS
1704
+ @function foo($a, $b, $c) {
1705
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1706
+ }
1707
+
1708
+ .foo {
1709
+ val: foo(1, $c: 3, 2...);
1710
+ }
1711
+ SCSS
1712
+ end
1713
+
1714
+ def test_function_keyword_args_after_splat
1715
+ assert_equal <<CSS, render(<<SCSS)
1716
+ .foo {
1717
+ val: "a: 1, b: 2, c: 3"; }
1718
+ CSS
1719
+ @function foo($a, $b, $c) {
1720
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1721
+ }
1722
+
1723
+ .foo {
1724
+ val: foo(1, 2..., $c: 3);
1725
+ }
1726
+ SCSS
1727
+ end
1728
+
1729
+ def test_function_keyword_splat_after_keyword_args
1730
+ assert_equal <<CSS, render(<<SCSS)
1731
+ .foo {
1732
+ val: "a: 1, b: 2, c: 3"; }
1733
+ CSS
1734
+ @function foo($a, $b, $c) {
1735
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1736
+ }
1737
+
1738
+ .foo {
1739
+ val: foo(1, $b: 2, (c: 3)...);
1740
+ }
1741
+ SCSS
1742
+ end
1743
+
1744
+ def test_function_triple_keyword_splat_merge
1745
+ assert_equal <<CSS, render(<<SCSS)
1746
+ .foo {
1747
+ val: "foo: 1, bar: 2, kwarg: 3, a: 3, b: 2, c: 3"; }
1748
+ CSS
1749
+ @function foo($foo, $bar, $kwarg, $a, $b, $c) {
1750
+ @return "foo: \#{$foo}, bar: \#{$bar}, kwarg: \#{$kwarg}, a: \#{$a}, b: \#{$b}, c: \#{$c}";
1751
+ }
1752
+
1753
+ @function bar($args...) {
1754
+ @return foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1755
+ }
1756
+
1757
+ .foo {
1758
+ val: bar($foo: 1, $a: 1, $b: 1, $c: 1);
1759
+ }
1760
+ SCSS
1761
+ end
1762
+
1763
+ def test_function_conflicting_splat_after_keyword_args
1764
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1765
+ Function foo was passed argument $b both by position and by name.
1766
+ MESSAGE
1767
+ @function foo($a, $b, $c) {
1768
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1769
+ }
1770
+
1771
+ .foo {
1772
+ val: foo(1, $b: 2, 3...);
1773
+ }
1774
+ SCSS
1775
+ end
1776
+
1777
+ def test_function_positional_arg_after_splat
1778
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1779
+ Only keyword arguments may follow variable arguments (...).
1780
+ MESSAGE
1781
+ @function foo($a, $b, $c) {
1782
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1783
+ }
1784
+
1785
+ .foo {
1786
+ val: foo(1, 2..., 3);
1787
+ }
1788
+ SCSS
1789
+ end
1790
+
1791
+ def test_function_var_args_with_keyword
1792
+ assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1793
+ @function foo($a, $b...) {
1794
+ @return "a: \#{$a}, b: \#{$b}";
1795
+ }
1796
+
1797
+ .foo {val: foo($a: 1, 2, 3, 4)}
1798
+ SCSS
1799
+ end
1800
+
1801
+ def test_function_keyword_for_var_arg
1802
+ assert_raise_message(Sass::SyntaxError, "Argument $b of function foo cannot be used as a named argument.") {render <<SCSS}
1803
+ @function foo($a, $b...) {
1804
+ @return "a: \#{$a}, b: \#{$b}";
1805
+ }
1806
+
1807
+ .foo {val: foo(1, $b: 2 3 4)}
1808
+ SCSS
1809
+ end
1810
+
1811
+ def test_function_keyword_for_unknown_arg_with_var_args
1812
+ assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1813
+ @function foo($a, $b...) {
1814
+ @return "a: \#{$a}, b: \#{length($b)}";
1815
+ }
1816
+
1817
+ .foo {val: foo(1, $c: 2 3 4)}
1818
+ SCSS
1819
+ end
1820
+
1821
+ def test_function_var_args_passed_to_native
1822
+ assert_equal <<CSS, render(<<SCSS)
1823
+ .foo {
1824
+ val: #102035; }
1825
+ CSS
1826
+ @function foo($args...) {
1827
+ @return adjust-color($args...);
1828
+ }
1829
+
1830
+ .foo {val: foo(#102030, $blue: 5)}
1831
+ SCSS
1832
+ end
1833
+
1834
+ def test_function_map_splat_before_list_splat
1835
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render <<SCSS}
1836
+ @function foo($a, $b, $c) {
1837
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1838
+ }
1839
+
1840
+ .foo {
1841
+ val: foo((a: 1)..., (2 3)...);
1842
+ }
1843
+ SCSS
1844
+ end
1845
+
1846
+ def test_function_map_splat_with_unknown_keyword
1847
+ assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1848
+ @function foo($a, $b) {
1849
+ @return "a: \#{$a}, b: \#{$b}";
1850
+ }
1851
+
1852
+ .foo {
1853
+ val: foo(1, 2, (c: 1)...);
1854
+ }
1855
+ SCSS
1856
+ end
1857
+
1858
+ def test_function_map_splat_with_wrong_type
1859
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render <<SCSS}
1860
+ @function foo($a, $b) {
1861
+ @return "a: \#{$a}, b: \#{$b}";
1862
+ }
1863
+
1864
+ .foo {
1865
+ val: foo((1, 2)..., 12...);
1866
+ }
1867
+ SCSS
1868
+ end
1869
+
1870
+ def test_function_keyword_splat_must_have_string_keys
1871
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1872
+ Variable keyword argument map must have string keys.
1873
+ 12 is not a string in (12: 1).
1874
+ MESSAGE
1875
+ @function foo($a) {
1876
+ @return $a;
1877
+ }
1878
+
1879
+ .foo {val: foo((12: 1)...)}
1880
+ SCSS
1881
+ end
1882
+
1883
+ ## Interpolation
1884
+
1885
+ def test_basic_selector_interpolation
1886
+ assert_equal <<CSS, render(<<SCSS)
1887
+ foo 3 baz {
1888
+ a: b; }
1889
+ CSS
1890
+ foo \#{1 + 2} baz {a: b}
1891
+ SCSS
1892
+ assert_equal <<CSS, render(<<SCSS)
1893
+ foo.bar baz {
1894
+ a: b; }
1895
+ CSS
1896
+ foo\#{".bar"} baz {a: b}
1897
+ SCSS
1898
+ assert_equal <<CSS, render(<<SCSS)
1899
+ foo.bar baz {
1900
+ a: b; }
1901
+ CSS
1902
+ \#{"foo"}.bar baz {a: b}
1903
+ SCSS
1904
+ end
1905
+
1906
+ def test_selector_only_interpolation
1907
+ assert_equal <<CSS, render(<<SCSS)
1908
+ foo bar {
1909
+ a: b; }
1910
+ CSS
1911
+ \#{"foo" + " bar"} {a: b}
1912
+ SCSS
1913
+ end
1914
+
1915
+ def test_selector_interpolation_before_element_name
1916
+ assert_equal <<CSS, render(<<SCSS)
1917
+ foo barbaz {
1918
+ a: b; }
1919
+ CSS
1920
+ \#{"foo" + " bar"}baz {a: b}
1921
+ SCSS
1922
+ end
1923
+
1924
+ def test_selector_interpolation_in_string
1925
+ assert_equal <<CSS, render(<<SCSS)
1926
+ foo[val="bar foo bar baz"] {
1927
+ a: b; }
1928
+ CSS
1929
+ foo[val="bar \#{"foo" + " bar"} baz"] {a: b}
1930
+ SCSS
1931
+ end
1932
+
1933
+ def test_selector_interpolation_in_pseudoclass
1934
+ assert_equal <<CSS, render(<<SCSS)
1935
+ foo:nth-child(5n) {
1936
+ a: b; }
1937
+ CSS
1938
+ foo:nth-child(\#{5 + "n"}) {a: b}
1939
+ SCSS
1940
+ end
1941
+
1942
+ def test_selector_interpolation_at_class_begininng
1943
+ assert_equal <<CSS, render(<<SCSS)
1944
+ .zzz {
1945
+ a: b; }
1946
+ CSS
1947
+ $zzz: zzz;
1948
+ .\#{$zzz} { a: b; }
1949
+ SCSS
1950
+ end
1951
+
1952
+ def test_selector_interpolation_at_id_begininng
1953
+ assert_equal <<CSS, render(<<SCSS)
1954
+ #zzz {
1955
+ a: b; }
1956
+ CSS
1957
+ $zzz: zzz;
1958
+ #\#{$zzz} { a: b; }
1959
+ SCSS
1960
+ end
1961
+
1962
+ def test_selector_interpolation_at_pseudo_begininng
1963
+ assert_equal <<CSS, render(<<SCSS)
1964
+ :zzz::zzz {
1965
+ a: b; }
1966
+ CSS
1967
+ $zzz: zzz;
1968
+ :\#{$zzz}::\#{$zzz} { a: b; }
1969
+ SCSS
1970
+ end
1971
+
1972
+ def test_selector_interpolation_at_attr_beginning
1973
+ assert_equal <<CSS, render(<<SCSS)
1974
+ [zzz=foo] {
1975
+ a: b; }
1976
+ CSS
1977
+ $zzz: zzz;
1978
+ [\#{$zzz}=foo] { a: b; }
1979
+ SCSS
1980
+ end
1981
+
1982
+ def test_selector_interpolation_at_attr_end
1983
+ assert_equal <<CSS, render(<<SCSS)
1984
+ [foo=zzz] {
1985
+ a: b; }
1986
+ CSS
1987
+ $zzz: zzz;
1988
+ [foo=\#{$zzz}] { a: b; }
1989
+ SCSS
1990
+ end
1991
+
1992
+ def test_selector_interpolation_at_dashes
1993
+ assert_equal <<CSS, render(<<SCSS)
1994
+ div {
1995
+ -foo-a-b-foo: foo; }
1996
+ CSS
1997
+ $a : a;
1998
+ $b : b;
1999
+ div { -foo-\#{$a}-\#{$b}-foo: foo }
2000
+ SCSS
2001
+ end
2002
+
2003
+ def test_selector_interpolation_in_reference_combinator
2004
+ assert_equal <<CSS, render(<<SCSS)
2005
+ .foo /a/ .bar /b|c/ .baz {
2006
+ a: b; }
2007
+ CSS
2008
+ $a: a;
2009
+ $b: b;
2010
+ $c: c;
2011
+ .foo /\#{$a}/ .bar /\#{$b}|\#{$c}/ .baz {a: b}
2012
+ SCSS
2013
+ end
2014
+
2015
+ def test_parent_selector_with_parent_and_subject
2016
+ assert_equal <<CSS, render(<<SCSS)
2017
+ bar foo.baz! .bip {
2018
+ c: d; }
2019
+ CSS
2020
+ $subject: "!";
2021
+ foo {
2022
+ bar &.baz\#{$subject} .bip {c: d}}
2023
+ SCSS
2024
+ end
2025
+
2026
+ def test_basic_prop_name_interpolation
2027
+ assert_equal <<CSS, render(<<SCSS)
2028
+ foo {
2029
+ barbazbang: blip; }
2030
+ CSS
2031
+ foo {bar\#{"baz" + "bang"}: blip}
2032
+ SCSS
2033
+ assert_equal <<CSS, render(<<SCSS)
2034
+ foo {
2035
+ bar3: blip; }
2036
+ CSS
2037
+ foo {bar\#{1 + 2}: blip}
2038
+ SCSS
2039
+ end
2040
+
2041
+ def test_prop_name_only_interpolation
2042
+ assert_equal <<CSS, render(<<SCSS)
2043
+ foo {
2044
+ bazbang: blip; }
2045
+ CSS
2046
+ foo {\#{"baz" + "bang"}: blip}
2047
+ SCSS
2048
+ end
2049
+
2050
+ def test_directive_interpolation
2051
+ assert_equal <<CSS, render(<<SCSS)
2052
+ @foo bar12 qux {
2053
+ a: b; }
2054
+ CSS
2055
+ $baz: 12;
2056
+ @foo bar\#{$baz} qux {a: b}
2057
+ SCSS
2058
+ end
2059
+
2060
+ def test_media_interpolation
2061
+ assert_equal <<CSS, render(<<SCSS)
2062
+ @media bar12 {
2063
+ a: b; }
2064
+ CSS
2065
+ $baz: 12;
2066
+ @media bar\#{$baz} {a: b}
2067
+ SCSS
2068
+ end
2069
+
2070
+ def test_script_in_media
2071
+ assert_equal <<CSS, render(<<SCSS)
2072
+ @media screen and (-webkit-min-device-pixel-ratio: 20), only print {
2073
+ a: b; }
2074
+ CSS
2075
+ $media1: screen;
2076
+ $media2: print;
2077
+ $var: -webkit-min-device-pixel-ratio;
2078
+ $val: 20;
2079
+ @media \#{$media1} and ($var: $val), only \#{$media2} {a: b}
2080
+ SCSS
2081
+
2082
+ assert_equal <<CSS, render(<<SCSS)
2083
+ @media screen and (-webkit-min-device-pixel-ratio: 13) {
2084
+ a: b; }
2085
+ CSS
2086
+ $vals: 1 2 3;
2087
+ @media screen and (-webkit-min-device-pixel-ratio: 5 + 6 + nth($vals, 2)) {a: b}
2088
+ SCSS
2089
+ end
2090
+
2091
+ def test_media_interpolation_with_reparse
2092
+ assert_equal <<CSS, render(<<SCSS)
2093
+ @media screen and (max-width: 300px) {
2094
+ a: b; }
2095
+ @media screen and (max-width: 300px) {
2096
+ a: b; }
2097
+ @media screen and (max-width: 300px) {
2098
+ a: b; }
2099
+ @media screen and (max-width: 300px), print and (max-width: 300px) {
2100
+ a: b; }
2101
+ CSS
2102
+ $constraint: "(max-width: 300px)";
2103
+ $fragment: "nd \#{$constraint}";
2104
+ $comma: "een, pri";
2105
+ @media screen and \#{$constraint} {a: b}
2106
+ @media screen {
2107
+ @media \#{$constraint} {a: b}
2108
+ }
2109
+ @media screen a\#{$fragment} {a: b}
2110
+ @media scr\#{$comma}nt {
2111
+ @media \#{$constraint} {a: b}
2112
+ }
2113
+ SCSS
2114
+ end
2115
+
2116
+ def test_moz_document_interpolation
2117
+ assert_equal <<CSS, render(<<SCSS)
2118
+ @-moz-document url(http://sass-lang.com/),
2119
+ url-prefix(http://sass-lang.com/docs),
2120
+ domain(sass-lang.com),
2121
+ domain("sass-lang.com") {
2122
+ .foo {
2123
+ a: b; } }
2124
+ CSS
2125
+ $domain: "sass-lang.com";
2126
+ @-moz-document url(http://\#{$domain}/),
2127
+ url-prefix(http://\#{$domain}/docs),
2128
+ domain(\#{$domain}),
2129
+ \#{domain($domain)} {
2130
+ .foo {a: b}
2131
+ }
2132
+ SCSS
2133
+ end
2134
+
2135
+ def test_supports_with_expressions
2136
+ assert_equal <<CSS, render(<<SCSS)
2137
+ @supports (feature1: val) and (feature2: val) or (not (feature23: val4)) {
2138
+ foo {
2139
+ a: b; } }
2140
+ CSS
2141
+ $query: "(feature1: val)";
2142
+ $feature: feature2;
2143
+ $val: val;
2144
+ @supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4)) {
2145
+ foo {a: b}
2146
+ }
2147
+ SCSS
2148
+ end
2149
+
2150
+ def test_supports_bubbling
2151
+ assert_equal <<CSS, render(<<SCSS)
2152
+ @supports (foo: bar) {
2153
+ a {
2154
+ b: c; }
2155
+ @supports (baz: bang) {
2156
+ a {
2157
+ d: e; } } }
2158
+ CSS
2159
+ a {
2160
+ @supports (foo: bar) {
2161
+ b: c;
2162
+ @supports (baz: bang) {
2163
+ d: e;
2164
+ }
2165
+ }
2166
+ }
2167
+ SCSS
2168
+ end
2169
+
2170
+ def test_random_directive_interpolation
2171
+ assert_equal <<CSS, render(<<SCSS)
2172
+ @foo url(http://sass-lang.com/),
2173
+ domain("sass-lang.com"),
2174
+ "foobarbaz",
2175
+ foobarbaz {
2176
+ .foo {
2177
+ a: b; } }
2178
+ CSS
2179
+ $domain: "sass-lang.com";
2180
+ @foo url(http://\#{$domain}/),
2181
+ \#{domain($domain)},
2182
+ "foo\#{'ba' + 'r'}baz",
2183
+ foo\#{'ba' + 'r'}baz {
2184
+ .foo {a: b}
2185
+ }
2186
+ SCSS
2187
+ end
2188
+
2189
+ def test_nested_mixin_def
2190
+ assert_equal <<CSS, render(<<SCSS)
2191
+ foo {
2192
+ a: b; }
2193
+ CSS
2194
+ foo {
2195
+ @mixin bar {a: b}
2196
+ @include bar; }
2197
+ SCSS
2198
+ end
2199
+
2200
+ def test_nested_mixin_shadow
2201
+ assert_equal <<CSS, render(<<SCSS)
2202
+ foo {
2203
+ c: d; }
2204
+
2205
+ baz {
2206
+ a: b; }
2207
+ CSS
2208
+ @mixin bar {a: b}
2209
+
2210
+ foo {
2211
+ @mixin bar {c: d}
2212
+ @include bar;
2213
+ }
2214
+
2215
+ baz {@include bar}
2216
+ SCSS
2217
+ end
2218
+
2219
+ def test_nested_function_def
2220
+ assert_equal <<CSS, render(<<SCSS)
2221
+ foo {
2222
+ a: 1; }
2223
+
2224
+ bar {
2225
+ b: foo(); }
2226
+ CSS
2227
+ foo {
2228
+ @function foo() {@return 1}
2229
+ a: foo(); }
2230
+
2231
+ bar {b: foo()}
2232
+ SCSS
2233
+ end
2234
+
2235
+ def test_nested_function_shadow
2236
+ assert_equal <<CSS, render(<<SCSS)
2237
+ foo {
2238
+ a: 2; }
2239
+
2240
+ baz {
2241
+ b: 1; }
2242
+ CSS
2243
+ @function foo() {@return 1}
2244
+
2245
+ foo {
2246
+ @function foo() {@return 2}
2247
+ a: foo();
2248
+ }
2249
+
2250
+ baz {b: foo()}
2251
+ SCSS
2252
+ end
2253
+
2254
+ ## @at-root
2255
+
2256
+ def test_simple_at_root
2257
+ assert_equal <<CSS, render(<<SCSS)
2258
+ .bar {
2259
+ a: b; }
2260
+ CSS
2261
+ .foo {
2262
+ @at-root {
2263
+ .bar {a: b}
2264
+ }
2265
+ }
2266
+ SCSS
2267
+ end
2268
+
2269
+ def test_at_root_with_selector
2270
+ assert_equal <<CSS, render(<<SCSS)
2271
+ .bar {
2272
+ a: b; }
2273
+ CSS
2274
+ .foo {
2275
+ @at-root .bar {a: b}
2276
+ }
2277
+ SCSS
2278
+ end
2279
+
2280
+ def test_at_root_in_mixin
2281
+ assert_equal <<CSS, render(<<SCSS)
2282
+ .bar {
2283
+ a: b; }
2284
+ CSS
2285
+ @mixin bar {
2286
+ @at-root .bar {a: b}
2287
+ }
2288
+
2289
+ .foo {
2290
+ @include bar;
2291
+ }
2292
+ SCSS
2293
+ end
2294
+
2295
+ def test_at_root_in_media
2296
+ assert_equal <<CSS, render(<<SCSS)
2297
+ @media screen {
2298
+ .bar {
2299
+ a: b; } }
2300
+ CSS
2301
+ @media screen {
2302
+ .foo {
2303
+ @at-root .bar {a: b}
2304
+ }
2305
+ }
2306
+ SCSS
2307
+ end
2308
+
2309
+ def test_at_root_in_bubbled_media
2310
+ assert_equal <<CSS, render(<<SCSS)
2311
+ @media screen {
2312
+ .bar {
2313
+ a: b; } }
2314
+ CSS
2315
+ .foo {
2316
+ @media screen {
2317
+ @at-root .bar {a: b}
2318
+ }
2319
+ }
2320
+ SCSS
2321
+ end
2322
+
2323
+ def test_at_root_in_unknown_directive
2324
+ assert_equal <<CSS, render(<<SCSS)
2325
+ @fblthp {
2326
+ .bar {
2327
+ a: b; } }
2328
+ CSS
2329
+ @fblthp {
2330
+ .foo {
2331
+ @at-root .bar {a: b}
2332
+ }
2333
+ }
2334
+ SCSS
2335
+ end
2336
+
2337
+ def test_comments_in_at_root
2338
+ assert_equal <<CSS, render(<<SCSS)
2339
+ /* foo */
2340
+ .bar {
2341
+ a: b; }
2342
+
2343
+ /* baz */
2344
+ CSS
2345
+ .foo {
2346
+ @at-root {
2347
+ /* foo */
2348
+ .bar {a: b}
2349
+ /* baz */
2350
+ }
2351
+ }
2352
+ SCSS
2353
+ end
2354
+
2355
+ def test_comments_in_at_root_in_media
2356
+ assert_equal <<CSS, render(<<SCSS)
2357
+ @media screen {
2358
+ /* foo */
2359
+ .bar {
2360
+ a: b; }
2361
+
2362
+ /* baz */ }
2363
+ CSS
2364
+ @media screen {
2365
+ .foo {
2366
+ @at-root {
2367
+ /* foo */
2368
+ .bar {a: b}
2369
+ /* baz */
2370
+ }
2371
+ }
2372
+ }
2373
+ SCSS
2374
+ end
2375
+
2376
+ def test_comments_in_at_root_in_unknown_directive
2377
+ assert_equal <<CSS, render(<<SCSS)
2378
+ @fblthp {
2379
+ /* foo */
2380
+ .bar {
2381
+ a: b; }
2382
+
2383
+ /* baz */ }
2384
+ CSS
2385
+ @fblthp {
2386
+ .foo {
2387
+ @at-root {
2388
+ /* foo */
2389
+ .bar {a: b}
2390
+ /* baz */
2391
+ }
2392
+ }
2393
+ }
2394
+ SCSS
2395
+ end
2396
+
2397
+ def test_media_directive_in_at_root
2398
+ assert_equal <<CSS, render(<<SCSS)
2399
+ @media screen {
2400
+ .bar {
2401
+ a: b; } }
2402
+ CSS
2403
+ .foo {
2404
+ @at-root {
2405
+ @media screen {.bar {a: b}}
2406
+ }
2407
+ }
2408
+ SCSS
2409
+ end
2410
+
2411
+ def test_bubbled_media_directive_in_at_root
2412
+ assert_equal <<CSS, render(<<SCSS)
2413
+ @media screen {
2414
+ .bar .baz {
2415
+ a: b; } }
2416
+ CSS
2417
+ .foo {
2418
+ @at-root {
2419
+ .bar {
2420
+ @media screen {.baz {a: b}}
2421
+ }
2422
+ }
2423
+ }
2424
+ SCSS
2425
+ end
2426
+
2427
+ def test_unknown_directive_in_at_root
2428
+ assert_equal <<CSS, render(<<SCSS)
2429
+ @fblthp {
2430
+ .bar {
2431
+ a: b; } }
2432
+ CSS
2433
+ .foo {
2434
+ @at-root {
2435
+ @fblthp {.bar {a: b}}
2436
+ }
2437
+ }
2438
+ SCSS
2439
+ end
2440
+
2441
+ def test_at_root_in_at_root
2442
+ assert_equal <<CSS, render(<<SCSS)
2443
+ .bar {
2444
+ a: b; }
2445
+ CSS
2446
+ .foo {
2447
+ @at-root {
2448
+ @at-root .bar {a: b}
2449
+ }
2450
+ }
2451
+ SCSS
2452
+ end
2453
+
2454
+ def test_at_root_with_parent_ref
2455
+ assert_equal <<CSS, render(<<SCSS)
2456
+ .foo {
2457
+ a: b; }
2458
+ CSS
2459
+ .foo {
2460
+ @at-root & {
2461
+ a: b;
2462
+ }
2463
+ }
2464
+ SCSS
2465
+ end
2466
+
2467
+ def test_multi_level_at_root_with_parent_ref
2468
+ assert_equal <<CSS, render(<<SCSS)
2469
+ .foo .bar {
2470
+ a: b; }
2471
+ CSS
2472
+ .foo {
2473
+ @at-root & {
2474
+ .bar {
2475
+ @at-root & {
2476
+ a: b;
2477
+ }
2478
+ }
2479
+ }
2480
+ }
2481
+ SCSS
2482
+ end
2483
+
2484
+ def test_multi_level_at_root_with_inner_parent_ref
2485
+ assert_equal <<CSS, render(<<SCSS)
2486
+ .bar {
2487
+ a: b; }
2488
+ CSS
2489
+ .foo {
2490
+ @at-root .bar {
2491
+ @at-root & {
2492
+ a: b;
2493
+ }
2494
+ }
2495
+ }
2496
+ SCSS
2497
+ end
2498
+
2499
+ def test_at_root_beneath_comma_selector
2500
+ assert_equal(<<CSS, render(<<SCSS))
2501
+ .baz {
2502
+ a: b; }
2503
+ CSS
2504
+ .foo, .bar {
2505
+ @at-root .baz {
2506
+ a: b;
2507
+ }
2508
+ }
2509
+ SCSS
2510
+ end
2511
+
2512
+ def test_at_root_with_parent_ref_and_class
2513
+ assert_equal(<<CSS, render(<<SCSS))
2514
+ .foo.bar {
2515
+ a: b; }
2516
+ CSS
2517
+ .foo {
2518
+ @at-root &.bar {
2519
+ a: b;
2520
+ }
2521
+ }
2522
+ SCSS
2523
+ end
2524
+
2525
+ def test_at_root_beneath_comma_selector_with_parent_ref
2526
+ assert_equal(<<CSS, render(<<SCSS))
2527
+ .foo.baz, .bar.baz {
2528
+ a: b; }
2529
+ CSS
2530
+ .foo, .bar {
2531
+ @at-root &.baz {
2532
+ a: b;
2533
+ }
2534
+ }
2535
+ SCSS
2536
+ end
2537
+
2538
+ ## @at-root (...)
869
2539
 
870
- def test_mixin_defs_only_at_toplevel
2540
+ def test_at_root_without_media
2541
+ assert_equal <<CSS, render(<<SCSS)
2542
+ .foo .bar {
2543
+ a: b; }
2544
+ CSS
2545
+ .foo {
2546
+ @media screen {
2547
+ @at-root (without: media) {
2548
+ .bar {
2549
+ a: b;
2550
+ }
2551
+ }
2552
+ }
2553
+ }
2554
+ SCSS
2555
+ end
2556
+
2557
+ def test_at_root_without_supports
2558
+ assert_equal <<CSS, render(<<SCSS)
2559
+ .foo .bar {
2560
+ a: b; }
2561
+ CSS
2562
+ .foo {
2563
+ @supports (foo: bar) {
2564
+ @at-root (without: supports) {
2565
+ .bar {
2566
+ a: b;
2567
+ }
2568
+ }
2569
+ }
2570
+ }
2571
+ SCSS
2572
+ end
2573
+
2574
+ def test_at_root_without_rule
2575
+ assert_equal <<CSS, render(<<SCSS)
2576
+ @media screen {
2577
+ .bar {
2578
+ a: b; } }
2579
+ CSS
2580
+ .foo {
2581
+ @media screen {
2582
+ @at-root (without: rule) {
2583
+ .bar {
2584
+ a: b;
2585
+ }
2586
+ }
2587
+ }
2588
+ }
2589
+ SCSS
2590
+ end
2591
+
2592
+ def test_at_root_without_unknown_directive
2593
+ assert_equal <<CSS, render(<<SCSS)
2594
+ @fblthp {}
2595
+ .foo .bar {
2596
+ a: b; }
2597
+ CSS
2598
+ .foo {
2599
+ @fblthp {
2600
+ @at-root (without: fblthp) {
2601
+ .bar {
2602
+ a: b;
2603
+ }
2604
+ }
2605
+ }
2606
+ }
2607
+ SCSS
2608
+ end
2609
+
2610
+ def test_at_root_without_multiple
2611
+ assert_equal <<CSS, render(<<SCSS)
2612
+ @supports (foo: bar) {
2613
+ .bar {
2614
+ a: b; } }
2615
+ CSS
2616
+ .foo {
2617
+ @media screen {
2618
+ @supports (foo: bar) {
2619
+ @at-root (without: media rule) {
2620
+ .bar {
2621
+ a: b;
2622
+ }
2623
+ }
2624
+ }
2625
+ }
2626
+ }
2627
+ SCSS
2628
+ end
2629
+
2630
+ def test_at_root_without_all
2631
+ assert_equal <<CSS, render(<<SCSS)
2632
+ @supports (foo: bar) {
2633
+ @fblthp {} }
2634
+ .bar {
2635
+ a: b; }
2636
+ CSS
2637
+ .foo {
2638
+ @supports (foo: bar) {
2639
+ @fblthp {
2640
+ @at-root (without: all) {
2641
+ .bar {
2642
+ a: b;
2643
+ }
2644
+ }
2645
+ }
2646
+ }
2647
+ }
2648
+ SCSS
2649
+ end
2650
+
2651
+ def test_at_root_with_media
2652
+ assert_equal <<CSS, render(<<SCSS)
2653
+ @media screen {
2654
+ @fblthp {}
2655
+ .bar {
2656
+ a: b; } }
2657
+ CSS
2658
+ .foo {
2659
+ @media screen {
2660
+ @fblthp {
2661
+ @supports (foo: bar) {
2662
+ @at-root (with: media) {
2663
+ .bar {
2664
+ a: b;
2665
+ }
2666
+ }
2667
+ }
2668
+ }
2669
+ }
2670
+ }
2671
+ SCSS
2672
+ end
2673
+
2674
+ def test_at_root_with_rule
2675
+ assert_equal <<CSS, render(<<SCSS)
2676
+ @media screen {
2677
+ @fblthp {} }
2678
+ .foo .bar {
2679
+ a: b; }
2680
+ CSS
2681
+ .foo {
2682
+ @media screen {
2683
+ @fblthp {
2684
+ @supports (foo: bar) {
2685
+ @at-root (with: rule) {
2686
+ .bar {
2687
+ a: b;
2688
+ }
2689
+ }
2690
+ }
2691
+ }
2692
+ }
2693
+ }
2694
+ SCSS
2695
+ end
2696
+
2697
+ def test_at_root_with_supports
2698
+ assert_equal <<CSS, render(<<SCSS)
2699
+ @media screen {
2700
+ @fblthp {} }
2701
+ @supports (foo: bar) {
2702
+ .bar {
2703
+ a: b; } }
2704
+ CSS
2705
+ .foo {
2706
+ @media screen {
2707
+ @fblthp {
2708
+ @supports (foo: bar) {
2709
+ @at-root (with: supports) {
2710
+ .bar {
2711
+ a: b;
2712
+ }
2713
+ }
2714
+ }
2715
+ }
2716
+ }
2717
+ }
2718
+ SCSS
2719
+ end
2720
+
2721
+ def test_at_root_with_unknown_directive
2722
+ assert_equal <<CSS, render(<<SCSS)
2723
+ @media screen {
2724
+ @fblthp {} }
2725
+ @fblthp {
2726
+ .bar {
2727
+ a: b; } }
2728
+ CSS
2729
+ .foo {
2730
+ @media screen {
2731
+ @fblthp {
2732
+ @supports (foo: bar) {
2733
+ @at-root (with: fblthp) {
2734
+ .bar {
2735
+ a: b;
2736
+ }
2737
+ }
2738
+ }
2739
+ }
2740
+ }
2741
+ }
2742
+ SCSS
2743
+ end
2744
+
2745
+ def test_at_root_with_multiple
2746
+ assert_equal <<CSS, render(<<SCSS)
2747
+ @media screen {
2748
+ @fblthp {}
2749
+ .foo .bar {
2750
+ a: b; } }
2751
+ CSS
2752
+ .foo {
2753
+ @media screen {
2754
+ @fblthp {
2755
+ @supports (foo: bar) {
2756
+ @at-root (with: media rule) {
2757
+ .bar {
2758
+ a: b;
2759
+ }
2760
+ }
2761
+ }
2762
+ }
2763
+ }
2764
+ }
2765
+ SCSS
2766
+ end
2767
+
2768
+ def test_at_root_with_all
2769
+ assert_equal <<CSS, render(<<SCSS)
2770
+ @media screen {
2771
+ @fblthp {
2772
+ @supports (foo: bar) {
2773
+ .foo .bar {
2774
+ a: b; } } } }
2775
+ CSS
2776
+ .foo {
2777
+ @media screen {
2778
+ @fblthp {
2779
+ @supports (foo: bar) {
2780
+ @at-root (with: all) {
2781
+ .bar {
2782
+ a: b;
2783
+ }
2784
+ }
2785
+ }
2786
+ }
2787
+ }
2788
+ }
2789
+ SCSS
2790
+ end
2791
+
2792
+ def test_at_root_dynamic_values
2793
+ assert_equal <<CSS, render(<<SCSS)
2794
+ @media screen {
2795
+ .bar {
2796
+ a: b; } }
2797
+ CSS
2798
+ $key: with;
2799
+ $value: media;
2800
+ .foo {
2801
+ @media screen {
2802
+ @at-root ($key: $value) {
2803
+ .bar {
2804
+ a: b;
2805
+ }
2806
+ }
2807
+ }
2808
+ }
2809
+ SCSS
2810
+ end
2811
+
2812
+ def test_at_root_interpolated_query
2813
+ assert_equal <<CSS, render(<<SCSS)
2814
+ @media screen {
2815
+ .bar {
2816
+ a: b; } }
2817
+ CSS
2818
+ .foo {
2819
+ @media screen {
2820
+ @at-root (\#{"with: media"}) {
2821
+ .bar {
2822
+ a: b;
2823
+ }
2824
+ }
2825
+ }
2826
+ }
2827
+ SCSS
2828
+ end
2829
+
2830
+ def test_at_root_plus_extend
2831
+ assert_equal <<CSS, render(<<SCSS)
2832
+ .foo .bar {
2833
+ a: b; }
2834
+ CSS
2835
+ %base {
2836
+ a: b;
2837
+ }
2838
+
2839
+ .foo {
2840
+ @media screen {
2841
+ @at-root (without: media) {
2842
+ .bar {
2843
+ @extend %base;
2844
+ }
2845
+ }
2846
+ }
2847
+ }
2848
+ SCSS
2849
+ end
2850
+
2851
+ ## Errors
2852
+
2853
+ def test_nested_mixin_def_is_scoped
871
2854
  render <<SCSS
872
2855
  foo {
873
2856
  @mixin bar {a: b}}
2857
+ bar {@include bar}
874
2858
  SCSS
875
2859
  assert(false, "Expected syntax error")
876
2860
  rescue Sass::SyntaxError => e
877
- assert_equal "Mixins may only be defined at the root of a document.", e.message
878
- assert_equal 2, e.sass_line
2861
+ assert_equal "Undefined mixin 'bar'.", e.message
2862
+ assert_equal 3, e.sass_line
879
2863
  end
880
2864
 
881
2865
  def test_rules_beneath_properties
@@ -1029,11 +3013,10 @@ SCSS
1029
3013
  end
1030
3014
 
1031
3015
  def test_parent_in_mid_selector_error
1032
- assert_raise_message(Sass::SyntaxError, <<MESSAGE) {render <<SCSS}
1033
- Invalid CSS after ".foo": expected "{", was "&.bar"
3016
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3017
+ Invalid CSS after " .foo": expected "{", was "&.bar {a: b}"
1034
3018
 
1035
- In Sass 3, the parent selector & can only be used where element names are valid,
1036
- since it could potentially be replaced by an element name.
3019
+ "&.bar" may only be used at the beginning of a compound selector.
1037
3020
  MESSAGE
1038
3021
  flim {
1039
3022
  .foo&.bar {a: b}
@@ -1041,12 +3024,11 @@ flim {
1041
3024
  SCSS
1042
3025
  end
1043
3026
 
1044
- def test_parent_in_mid_selector_error
1045
- assert_raise_message(Sass::SyntaxError, <<MESSAGE) {render <<SCSS}
3027
+ def test_parent_after_selector_error
3028
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1046
3029
  Invalid CSS after " .foo.bar": expected "{", was "& {a: b}"
1047
3030
 
1048
- In Sass 3, the parent selector & can only be used where element names are valid,
1049
- since it could potentially be replaced by an element name.
3031
+ "&" may only be used at the beginning of a compound selector.
1050
3032
  MESSAGE
1051
3033
  flim {
1052
3034
  .foo.bar& {a: b}
@@ -1055,11 +3037,10 @@ SCSS
1055
3037
  end
1056
3038
 
1057
3039
  def test_double_parent_selector_error
1058
- assert_raise_message(Sass::SyntaxError, <<MESSAGE) {render <<SCSS}
3040
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1059
3041
  Invalid CSS after " &": expected "{", was "& {a: b}"
1060
3042
 
1061
- In Sass 3, the parent selector & can only be used where element names are valid,
1062
- since it could potentially be replaced by an element name.
3043
+ "&" may only be used at the beginning of a compound selector.
1063
3044
  MESSAGE
1064
3045
  flim {
1065
3046
  && {a: b}
@@ -1067,35 +3048,177 @@ flim {
1067
3048
  SCSS
1068
3049
  end
1069
3050
 
1070
- def test_no_interpolation_in_media_queries
3051
+ def test_no_lonely_else
1071
3052
  assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1072
- Invalid CSS after "...nd (min-width: ": expected expression (e.g. 1px, bold), was "\#{100}px) {"
3053
+ Invalid CSS: @else must come after @if
1073
3054
  MESSAGE
1074
- @media screen and (min-width: \#{100}px) {
1075
- foo {bar: baz}
1076
- }
3055
+ @else {foo: bar}
1077
3056
  SCSS
1078
3057
  end
1079
3058
 
1080
- def test_no_interpolation_in_unrecognized_directives
1081
- assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1082
- Invalid CSS after "@foo ": expected selector or at-rule, was "\#{100} {"
3059
+ def test_failed_parent_selector_with_suffix
3060
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3061
+ Invalid parent selector for "&-bar": "*"
1083
3062
  MESSAGE
1084
- @foo \#{100} {
1085
- foo {bar: baz}
3063
+ * {
3064
+ &-bar {a: b}
1086
3065
  }
1087
3066
  SCSS
1088
- end
1089
3067
 
1090
- def test_no_lonely_else
1091
- assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1092
- Invalid CSS: @else must come after @if
3068
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3069
+ Invalid parent selector for "&-bar": "[foo=bar]"
1093
3070
  MESSAGE
1094
- @else {foo: bar}
3071
+ [foo=bar] {
3072
+ &-bar {a: b}
3073
+ }
3074
+ SCSS
3075
+
3076
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3077
+ Invalid parent selector for "&-bar": "::nth-child(2n+1)"
3078
+ MESSAGE
3079
+ ::nth-child(2n+1) {
3080
+ &-bar {a: b}
3081
+ }
3082
+ SCSS
3083
+
3084
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3085
+ Invalid parent selector for "&-bar": ":not(.foo)"
3086
+ MESSAGE
3087
+ :not(.foo) {
3088
+ &-bar {a: b}
3089
+ }
3090
+ SCSS
3091
+
3092
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3093
+ Invalid parent selector for "&-bar": ".foo +"
3094
+ MESSAGE
3095
+ .foo + {
3096
+ &-bar {a: b}
3097
+ }
1095
3098
  SCSS
1096
3099
  end
1097
3100
 
1098
3101
  # Regression
3102
+
3103
+ def test_parent_ref_with_newline
3104
+ assert_equal(<<CSS, render(<<SCSS))
3105
+ a.c
3106
+ , b.c {
3107
+ x: y; }
3108
+ CSS
3109
+ a
3110
+ , b {&.c {x: y}}
3111
+ SCSS
3112
+ end
3113
+
3114
+ def test_parent_ref_in_nested_at_root
3115
+ assert_equal(<<CSS, render(<<SCSS))
3116
+ #test {
3117
+ border: 0; }
3118
+ #test:hover {
3119
+ display: none; }
3120
+ CSS
3121
+ a {
3122
+ @at-root #test {
3123
+ border: 0;
3124
+ &:hover{
3125
+ display: none;
3126
+ }
3127
+ }
3128
+ }
3129
+ SCSS
3130
+ end
3131
+
3132
+ def test_loud_comment_in_compressed_mode
3133
+ assert_equal(<<CSS, render(<<SCSS))
3134
+ /*! foo */
3135
+ CSS
3136
+ /*! foo */
3137
+ SCSS
3138
+ end
3139
+
3140
+ def test_parsing_decimals_followed_by_comments_doesnt_take_forever
3141
+ assert_equal(<<CSS, render(<<SCSS))
3142
+ .foo {
3143
+ padding: 4.21053% 4.21053% 5.63158%; }
3144
+ CSS
3145
+ .foo {
3146
+ padding: 4.21052631578947% 4.21052631578947% 5.631578947368421% /**/
3147
+ }
3148
+ SCSS
3149
+ end
3150
+
3151
+ def test_parsing_many_numbers_doesnt_take_forever
3152
+ values = ["80% 90%"] * 1000
3153
+ assert_equal(<<CSS, render(<<SCSS))
3154
+ .foo {
3155
+ padding: #{values.join(', ')}; }
3156
+ CSS
3157
+ .foo {
3158
+ padding: #{values.join(', ')};
3159
+ }
3160
+ SCSS
3161
+ end
3162
+
3163
+ def test_import_comments_in_imports
3164
+ assert_equal(<<CSS, render(<<SCSS))
3165
+ @import url(foo.css);
3166
+ @import url(bar.css);
3167
+ @import url(baz.css);
3168
+ CSS
3169
+ @import "foo.css", // this is a comment
3170
+ "bar.css", /* this is another comment */
3171
+ "baz.css"; // this is a third comment
3172
+ SCSS
3173
+ end
3174
+
3175
+ def test_reference_combinator_with_parent_ref
3176
+ assert_equal <<CSS, render(<<SCSS)
3177
+ a /foo/ b {
3178
+ c: d; }
3179
+ CSS
3180
+ a {& /foo/ b {c: d}}
3181
+ SCSS
3182
+ end
3183
+
3184
+ def test_newline_selector_rendered_multiple_times
3185
+ assert_equal <<CSS, render(<<SCSS)
3186
+ form input,
3187
+ form select {
3188
+ color: white; }
3189
+
3190
+ form input,
3191
+ form select {
3192
+ color: white; }
3193
+ CSS
3194
+ @for $i from 1 through 2 {
3195
+ form {
3196
+ input,
3197
+ select {
3198
+ color: white;
3199
+ }
3200
+ }
3201
+ }
3202
+ SCSS
3203
+ end
3204
+
3205
+ def test_prop_name_interpolation_after_hyphen
3206
+ assert_equal <<CSS, render(<<SCSS)
3207
+ a {
3208
+ -foo-bar: b; }
3209
+ CSS
3210
+ a { -\#{"foo"}-bar: b; }
3211
+ SCSS
3212
+ end
3213
+
3214
+ def test_star_plus_and_parent
3215
+ assert_equal <<CSS, render(<<SCSS)
3216
+ * + html foo {
3217
+ a: b; }
3218
+ CSS
3219
+ foo {*+html & {a: b}}
3220
+ SCSS
3221
+ end
1099
3222
 
1100
3223
  def test_weird_added_space
1101
3224
  assert_equal <<CSS, render(<<SCSS)
@@ -1200,7 +3323,7 @@ SCSS
1200
3323
  end
1201
3324
 
1202
3325
  def test_unknown_keyword_arg_raises_error
1203
- assert_raise_message(Sass::SyntaxError, "Mixin a doesn't have an argument named $c") {render <<SCSS}
3326
+ assert_raise_message(Sass::SyntaxError, "Mixin a doesn't have an argument named $c.") {render <<SCSS}
1204
3327
  @mixin a($b: 1) { a: $b; }
1205
3328
  div { @include a(1, $c: 3); }
1206
3329
  SCSS
@@ -1208,11 +3331,11 @@ SCSS
1208
3331
 
1209
3332
 
1210
3333
  def test_newlines_removed_from_selectors_when_compressed
1211
- assert_equal <<CSS, render(<<SCSS, :style=>:compressed)
3334
+ assert_equal <<CSS, render(<<SCSS, :style => :compressed)
1212
3335
  z a,z b{display:block}
1213
3336
  CSS
1214
- a,
1215
- b {
3337
+ a
3338
+ , b {
1216
3339
  z & {
1217
3340
  display: block;
1218
3341
  }
@@ -1244,6 +3367,95 @@ foo {
1244
3367
  a: $var1;
1245
3368
  b: $var2;
1246
3369
  c: $var3; }
3370
+ SCSS
3371
+ end
3372
+
3373
+ def test_mixin_content
3374
+ assert_equal <<CSS, render(<<SASS)
3375
+ .parent {
3376
+ background-color: red;
3377
+ border-color: red; }
3378
+ .parent .child {
3379
+ background-color: yellow;
3380
+ color: blue;
3381
+ border-color: yellow; }
3382
+ CSS
3383
+ $color: blue;
3384
+ @mixin context($class, $color: red) {
3385
+ .\#{$class} {
3386
+ background-color: $color;
3387
+ @content;
3388
+ border-color: $color;
3389
+ }
3390
+ }
3391
+ @include context(parent) {
3392
+ @include context(child, $color: yellow) {
3393
+ color: $color;
3394
+ }
3395
+ }
3396
+ SASS
3397
+ end
3398
+
3399
+ def test_empty_content
3400
+ assert_equal <<CSS, render(<<SCSS)
3401
+ a {
3402
+ b: c; }
3403
+ CSS
3404
+ @mixin foo { @content }
3405
+ a { b: c; @include foo {} }
3406
+ SCSS
3407
+ end
3408
+
3409
+ def test_options_passed_to_script
3410
+ assert_equal <<CSS, render(<<SCSS, :style => :compressed)
3411
+ foo{color:#000}
3412
+ CSS
3413
+ foo {color: darken(black, 10%)}
3414
+ SCSS
3415
+ end
3416
+
3417
+ # ref: https://github.com/nex3/sass/issues/104
3418
+ def test_no_buffer_overflow
3419
+ template = render <<SCSS
3420
+ .aaa {
3421
+ background-color: white;
3422
+ }
3423
+ .aaa .aaa .aaa {
3424
+ background-color: black;
3425
+ }
3426
+ .bbb {
3427
+ @extend .aaa;
3428
+ }
3429
+ .xxx {
3430
+ @extend .bbb;
3431
+ }
3432
+ .yyy {
3433
+ @extend .bbb;
3434
+ }
3435
+ .zzz {
3436
+ @extend .bbb;
3437
+ }
3438
+ SCSS
3439
+ Sass::SCSS::Parser.new(template, "test.scss", nil).parse
3440
+ end
3441
+
3442
+ def test_extend_in_media_in_rule
3443
+ assert_equal(<<CSS, render(<<SCSS))
3444
+ @media screen {
3445
+ .foo {
3446
+ a: b; } }
3447
+ CSS
3448
+ .foo {
3449
+ @media screen {
3450
+ @extend %bar;
3451
+ }
3452
+ }
3453
+
3454
+ @media screen {
3455
+ %bar {
3456
+ a: b;
3457
+ }
3458
+ }
1247
3459
  SCSS
1248
3460
  end
1249
3461
  end