sass 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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