oreorenasass 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +11 -0
  3. data/CONTRIBUTING +3 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +221 -0
  6. data/Rakefile +370 -0
  7. data/VERSION +1 -0
  8. data/VERSION_NAME +1 -0
  9. data/bin/sass +13 -0
  10. data/bin/sass-convert +12 -0
  11. data/bin/scss +13 -0
  12. data/extra/update_watch.rb +13 -0
  13. data/init.rb +18 -0
  14. data/lib/sass/cache_stores/base.rb +88 -0
  15. data/lib/sass/cache_stores/chain.rb +34 -0
  16. data/lib/sass/cache_stores/filesystem.rb +60 -0
  17. data/lib/sass/cache_stores/memory.rb +47 -0
  18. data/lib/sass/cache_stores/null.rb +25 -0
  19. data/lib/sass/cache_stores.rb +15 -0
  20. data/lib/sass/callbacks.rb +67 -0
  21. data/lib/sass/css.rb +407 -0
  22. data/lib/sass/engine.rb +1181 -0
  23. data/lib/sass/environment.rb +191 -0
  24. data/lib/sass/error.rb +198 -0
  25. data/lib/sass/exec/base.rb +187 -0
  26. data/lib/sass/exec/sass_convert.rb +264 -0
  27. data/lib/sass/exec/sass_scss.rb +424 -0
  28. data/lib/sass/exec.rb +9 -0
  29. data/lib/sass/features.rb +47 -0
  30. data/lib/sass/importers/base.rb +182 -0
  31. data/lib/sass/importers/filesystem.rb +211 -0
  32. data/lib/sass/importers.rb +22 -0
  33. data/lib/sass/logger/base.rb +30 -0
  34. data/lib/sass/logger/log_level.rb +45 -0
  35. data/lib/sass/logger.rb +12 -0
  36. data/lib/sass/media.rb +210 -0
  37. data/lib/sass/plugin/compiler.rb +565 -0
  38. data/lib/sass/plugin/configuration.rb +118 -0
  39. data/lib/sass/plugin/generic.rb +15 -0
  40. data/lib/sass/plugin/merb.rb +48 -0
  41. data/lib/sass/plugin/rack.rb +60 -0
  42. data/lib/sass/plugin/rails.rb +47 -0
  43. data/lib/sass/plugin/staleness_checker.rb +199 -0
  44. data/lib/sass/plugin.rb +133 -0
  45. data/lib/sass/railtie.rb +10 -0
  46. data/lib/sass/repl.rb +57 -0
  47. data/lib/sass/root.rb +7 -0
  48. data/lib/sass/script/css_lexer.rb +33 -0
  49. data/lib/sass/script/css_parser.rb +34 -0
  50. data/lib/sass/script/functions.rb +2626 -0
  51. data/lib/sass/script/lexer.rb +449 -0
  52. data/lib/sass/script/parser.rb +637 -0
  53. data/lib/sass/script/tree/funcall.rb +306 -0
  54. data/lib/sass/script/tree/interpolation.rb +118 -0
  55. data/lib/sass/script/tree/list_literal.rb +77 -0
  56. data/lib/sass/script/tree/literal.rb +45 -0
  57. data/lib/sass/script/tree/map_literal.rb +64 -0
  58. data/lib/sass/script/tree/node.rb +109 -0
  59. data/lib/sass/script/tree/operation.rb +103 -0
  60. data/lib/sass/script/tree/selector.rb +26 -0
  61. data/lib/sass/script/tree/string_interpolation.rb +104 -0
  62. data/lib/sass/script/tree/unary_operation.rb +69 -0
  63. data/lib/sass/script/tree/variable.rb +57 -0
  64. data/lib/sass/script/tree.rb +16 -0
  65. data/lib/sass/script/value/arg_list.rb +36 -0
  66. data/lib/sass/script/value/base.rb +240 -0
  67. data/lib/sass/script/value/bool.rb +35 -0
  68. data/lib/sass/script/value/color.rb +680 -0
  69. data/lib/sass/script/value/helpers.rb +262 -0
  70. data/lib/sass/script/value/list.rb +113 -0
  71. data/lib/sass/script/value/map.rb +70 -0
  72. data/lib/sass/script/value/null.rb +44 -0
  73. data/lib/sass/script/value/number.rb +530 -0
  74. data/lib/sass/script/value/string.rb +97 -0
  75. data/lib/sass/script/value.rb +11 -0
  76. data/lib/sass/script.rb +66 -0
  77. data/lib/sass/scss/css_parser.rb +42 -0
  78. data/lib/sass/scss/parser.rb +1209 -0
  79. data/lib/sass/scss/rx.rb +141 -0
  80. data/lib/sass/scss/script_lexer.rb +15 -0
  81. data/lib/sass/scss/script_parser.rb +25 -0
  82. data/lib/sass/scss/static_parser.rb +368 -0
  83. data/lib/sass/scss.rb +16 -0
  84. data/lib/sass/selector/abstract_sequence.rb +109 -0
  85. data/lib/sass/selector/comma_sequence.rb +175 -0
  86. data/lib/sass/selector/pseudo.rb +256 -0
  87. data/lib/sass/selector/sequence.rb +600 -0
  88. data/lib/sass/selector/simple.rb +117 -0
  89. data/lib/sass/selector/simple_sequence.rb +325 -0
  90. data/lib/sass/selector.rb +326 -0
  91. data/lib/sass/shared.rb +76 -0
  92. data/lib/sass/source/map.rb +210 -0
  93. data/lib/sass/source/position.rb +39 -0
  94. data/lib/sass/source/range.rb +41 -0
  95. data/lib/sass/stack.rb +120 -0
  96. data/lib/sass/supports.rb +227 -0
  97. data/lib/sass/tree/at_root_node.rb +83 -0
  98. data/lib/sass/tree/charset_node.rb +22 -0
  99. data/lib/sass/tree/comment_node.rb +82 -0
  100. data/lib/sass/tree/content_node.rb +9 -0
  101. data/lib/sass/tree/css_import_node.rb +60 -0
  102. data/lib/sass/tree/debug_node.rb +18 -0
  103. data/lib/sass/tree/directive_node.rb +59 -0
  104. data/lib/sass/tree/each_node.rb +24 -0
  105. data/lib/sass/tree/error_node.rb +18 -0
  106. data/lib/sass/tree/extend_node.rb +43 -0
  107. data/lib/sass/tree/for_node.rb +36 -0
  108. data/lib/sass/tree/function_node.rb +39 -0
  109. data/lib/sass/tree/if_node.rb +52 -0
  110. data/lib/sass/tree/import_node.rb +74 -0
  111. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  112. data/lib/sass/tree/media_node.rb +48 -0
  113. data/lib/sass/tree/mixin_def_node.rb +38 -0
  114. data/lib/sass/tree/mixin_node.rb +52 -0
  115. data/lib/sass/tree/node.rb +238 -0
  116. data/lib/sass/tree/prop_node.rb +171 -0
  117. data/lib/sass/tree/return_node.rb +19 -0
  118. data/lib/sass/tree/root_node.rb +44 -0
  119. data/lib/sass/tree/rule_node.rb +145 -0
  120. data/lib/sass/tree/supports_node.rb +38 -0
  121. data/lib/sass/tree/trace_node.rb +33 -0
  122. data/lib/sass/tree/variable_node.rb +36 -0
  123. data/lib/sass/tree/visitors/base.rb +72 -0
  124. data/lib/sass/tree/visitors/check_nesting.rb +177 -0
  125. data/lib/sass/tree/visitors/convert.rb +334 -0
  126. data/lib/sass/tree/visitors/cssize.rb +369 -0
  127. data/lib/sass/tree/visitors/deep_copy.rb +107 -0
  128. data/lib/sass/tree/visitors/extend.rb +68 -0
  129. data/lib/sass/tree/visitors/perform.rb +539 -0
  130. data/lib/sass/tree/visitors/set_options.rb +139 -0
  131. data/lib/sass/tree/visitors/to_css.rb +381 -0
  132. data/lib/sass/tree/warn_node.rb +18 -0
  133. data/lib/sass/tree/while_node.rb +18 -0
  134. data/lib/sass/util/cross_platform_random.rb +19 -0
  135. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  136. data/lib/sass/util/normalized_map.rb +130 -0
  137. data/lib/sass/util/ordered_hash.rb +192 -0
  138. data/lib/sass/util/subset_map.rb +110 -0
  139. data/lib/sass/util/test.rb +9 -0
  140. data/lib/sass/util.rb +1318 -0
  141. data/lib/sass/version.rb +124 -0
  142. data/lib/sass.rb +102 -0
  143. data/rails/init.rb +1 -0
  144. data/test/sass/cache_test.rb +131 -0
  145. data/test/sass/callbacks_test.rb +61 -0
  146. data/test/sass/compiler_test.rb +232 -0
  147. data/test/sass/conversion_test.rb +2054 -0
  148. data/test/sass/css2sass_test.rb +477 -0
  149. data/test/sass/data/hsl-rgb.txt +319 -0
  150. data/test/sass/encoding_test.rb +219 -0
  151. data/test/sass/engine_test.rb +3301 -0
  152. data/test/sass/exec_test.rb +86 -0
  153. data/test/sass/extend_test.rb +1661 -0
  154. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  155. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  156. data/test/sass/functions_test.rb +1926 -0
  157. data/test/sass/importer_test.rb +412 -0
  158. data/test/sass/logger_test.rb +58 -0
  159. data/test/sass/mock_importer.rb +49 -0
  160. data/test/sass/more_results/more1.css +9 -0
  161. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  162. data/test/sass/more_results/more_import.css +29 -0
  163. data/test/sass/more_templates/_more_partial.sass +2 -0
  164. data/test/sass/more_templates/more1.sass +23 -0
  165. data/test/sass/more_templates/more_import.sass +11 -0
  166. data/test/sass/plugin_test.rb +554 -0
  167. data/test/sass/results/alt.css +4 -0
  168. data/test/sass/results/basic.css +9 -0
  169. data/test/sass/results/cached_import_option.css +3 -0
  170. data/test/sass/results/compact.css +5 -0
  171. data/test/sass/results/complex.css +86 -0
  172. data/test/sass/results/compressed.css +1 -0
  173. data/test/sass/results/expanded.css +19 -0
  174. data/test/sass/results/filename_fn.css +3 -0
  175. data/test/sass/results/if.css +3 -0
  176. data/test/sass/results/import.css +31 -0
  177. data/test/sass/results/import_charset.css +5 -0
  178. data/test/sass/results/import_charset_1_8.css +5 -0
  179. data/test/sass/results/import_charset_ibm866.css +5 -0
  180. data/test/sass/results/import_content.css +1 -0
  181. data/test/sass/results/line_numbers.css +49 -0
  182. data/test/sass/results/mixins.css +95 -0
  183. data/test/sass/results/multiline.css +24 -0
  184. data/test/sass/results/nested.css +22 -0
  185. data/test/sass/results/options.css +1 -0
  186. data/test/sass/results/parent_ref.css +13 -0
  187. data/test/sass/results/script.css +16 -0
  188. data/test/sass/results/scss_import.css +31 -0
  189. data/test/sass/results/scss_importee.css +2 -0
  190. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  191. data/test/sass/results/subdir/subdir.css +3 -0
  192. data/test/sass/results/units.css +11 -0
  193. data/test/sass/results/warn.css +0 -0
  194. data/test/sass/results/warn_imported.css +0 -0
  195. data/test/sass/script_conversion_test.rb +328 -0
  196. data/test/sass/script_test.rb +1054 -0
  197. data/test/sass/scss/css_test.rb +1215 -0
  198. data/test/sass/scss/rx_test.rb +156 -0
  199. data/test/sass/scss/scss_test.rb +3900 -0
  200. data/test/sass/scss/test_helper.rb +37 -0
  201. data/test/sass/source_map_test.rb +977 -0
  202. data/test/sass/superselector_test.rb +191 -0
  203. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  204. data/test/sass/templates/_double_import_loop2.sass +1 -0
  205. data/test/sass/templates/_filename_fn_import.scss +11 -0
  206. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  207. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  208. data/test/sass/templates/_imported_content.sass +3 -0
  209. data/test/sass/templates/_partial.sass +2 -0
  210. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  211. data/test/sass/templates/alt.sass +16 -0
  212. data/test/sass/templates/basic.sass +23 -0
  213. data/test/sass/templates/bork1.sass +2 -0
  214. data/test/sass/templates/bork2.sass +2 -0
  215. data/test/sass/templates/bork3.sass +2 -0
  216. data/test/sass/templates/bork4.sass +2 -0
  217. data/test/sass/templates/bork5.sass +3 -0
  218. data/test/sass/templates/cached_import_option.scss +3 -0
  219. data/test/sass/templates/compact.sass +17 -0
  220. data/test/sass/templates/complex.sass +305 -0
  221. data/test/sass/templates/compressed.sass +15 -0
  222. data/test/sass/templates/double_import_loop1.sass +1 -0
  223. data/test/sass/templates/expanded.sass +17 -0
  224. data/test/sass/templates/filename_fn.scss +18 -0
  225. data/test/sass/templates/if.sass +11 -0
  226. data/test/sass/templates/import.sass +12 -0
  227. data/test/sass/templates/import_charset.sass +9 -0
  228. data/test/sass/templates/import_charset_1_8.sass +6 -0
  229. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  230. data/test/sass/templates/import_content.sass +4 -0
  231. data/test/sass/templates/importee.less +2 -0
  232. data/test/sass/templates/importee.sass +19 -0
  233. data/test/sass/templates/line_numbers.sass +13 -0
  234. data/test/sass/templates/mixin_bork.sass +5 -0
  235. data/test/sass/templates/mixins.sass +76 -0
  236. data/test/sass/templates/multiline.sass +20 -0
  237. data/test/sass/templates/nested.sass +25 -0
  238. data/test/sass/templates/nested_bork1.sass +2 -0
  239. data/test/sass/templates/nested_bork2.sass +2 -0
  240. data/test/sass/templates/nested_bork3.sass +2 -0
  241. data/test/sass/templates/nested_bork4.sass +2 -0
  242. data/test/sass/templates/nested_import.sass +2 -0
  243. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  244. data/test/sass/templates/options.sass +2 -0
  245. data/test/sass/templates/parent_ref.sass +25 -0
  246. data/test/sass/templates/same_name_different_ext.sass +2 -0
  247. data/test/sass/templates/same_name_different_ext.scss +1 -0
  248. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  249. data/test/sass/templates/script.sass +101 -0
  250. data/test/sass/templates/scss_import.scss +12 -0
  251. data/test/sass/templates/scss_importee.scss +1 -0
  252. data/test/sass/templates/single_import_loop.sass +1 -0
  253. data/test/sass/templates/subdir/import_up1.scss +1 -0
  254. data/test/sass/templates/subdir/import_up2.scss +1 -0
  255. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  256. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  257. data/test/sass/templates/subdir/subdir.sass +6 -0
  258. data/test/sass/templates/units.sass +11 -0
  259. data/test/sass/templates/warn.sass +3 -0
  260. data/test/sass/templates/warn_imported.sass +4 -0
  261. data/test/sass/test_helper.rb +8 -0
  262. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  263. data/test/sass/util/normalized_map_test.rb +51 -0
  264. data/test/sass/util/subset_map_test.rb +91 -0
  265. data/test/sass/util_test.rb +467 -0
  266. data/test/sass/value_helpers_test.rb +179 -0
  267. data/test/test_helper.rb +109 -0
  268. metadata +386 -0
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/../../test_helper'
4
+ require 'sass/engine'
5
+
6
+ class ScssRxTest < MiniTest::Test
7
+ include Sass::SCSS::RX
8
+
9
+ def test_identifiers
10
+ assert_match IDENT, "foo"
11
+ assert_match IDENT, "\xC3\xBFoo" # Initial char can be nonascii
12
+ assert_match IDENT, "\\123abcoo" # Initial char can be unicode escape
13
+ assert_match IDENT, "\\f oo" # Unicode escapes can be followed by whitespace
14
+ assert_match IDENT, "\\fa\too"
15
+ assert_match IDENT, "\\ff2\roo"
16
+ assert_match IDENT, "\\f13a\foo"
17
+ assert_match IDENT, "\\f13abcoo"
18
+ assert_match IDENT, "\\ oo" # Initial char can be a plain escape as well
19
+ assert_match IDENT, "\\~oo"
20
+ assert_match IDENT, "\\\\oo"
21
+ assert_match IDENT, "\\{oo"
22
+ assert_match IDENT, "\\\xC3\xBFoo"
23
+ assert_match IDENT, "-foo" # Can put a - before anything
24
+ assert_match IDENT, "-\xC3\xBFoo"
25
+ assert_match IDENT, "-\\f oo"
26
+ assert_match IDENT, "_foo" # Can put a _ before anything
27
+ assert_match IDENT, "_\xC3\xBFoo"
28
+ assert_match IDENT, "_\\f oo"
29
+ assert_match IDENT, "--foo" # "Custom" identifier
30
+
31
+ assert_match IDENT, "foo-bar"
32
+ assert_match IDENT, "f012-23"
33
+ assert_match IDENT, "foo_-_bar"
34
+ assert_match IDENT, "f012_23"
35
+
36
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-003.xht
37
+ assert_match IDENT, "c\\lass"
38
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-004.xht
39
+ assert_match IDENT, "c\\00006Cas\\000073"
40
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-001.xht
41
+ assert_match IDENT, "IdE6n-3t0_6"
42
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-006.xht
43
+ assert_match IDENT, "\\6000ident"
44
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-007.xht
45
+ assert_match IDENT, "iden\\6000t\\6000"
46
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-013.xht
47
+ assert_match IDENT, "\\-ident"
48
+ end
49
+
50
+ def test_underscores_in_identifiers
51
+ assert_match IDENT, "foo_bar"
52
+ assert_match IDENT, "_\xC3\xBFfoo"
53
+ assert_match IDENT, "__foo"
54
+ assert_match IDENT, "_1foo"
55
+ assert_match IDENT, "-_foo"
56
+ assert_match IDENT, "_-foo"
57
+ end
58
+
59
+ def test_invalid_identifiers
60
+ assert_no_match IDENT, ""
61
+ assert_no_match IDENT, "1foo"
62
+ assert_no_match IDENT, "-1foo"
63
+ assert_no_match IDENT, "foo bar"
64
+ assert_no_match IDENT, "foo~bar"
65
+
66
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-008.xht
67
+ assert_no_match IDENT, "c\\06C ass"
68
+ assert_no_match IDENT, "back\\67\n round"
69
+ end
70
+
71
+ def test_double_quote_strings
72
+ assert_match STRING, '"foo bar"'
73
+ assert_match STRING, '"foo\\\nbar"'
74
+ assert_match STRING, "\"\\\"\""
75
+ assert_match STRING, '"\t !#$%&(-~()*+,-./0123456789~"'
76
+ end
77
+
78
+ def test_single_quote_strings
79
+ assert_match STRING, "'foo bar'"
80
+ assert_match STRING, "'foo\\\nbar'"
81
+ assert_match STRING, "'\\''"
82
+ assert_match STRING, "'\t !#\$%&(-~()*+,-./0123456789~'"
83
+ end
84
+
85
+ def test_invalid_strings
86
+ assert_no_match STRING, "\"foo\nbar\""
87
+ assert_no_match STRING, "\"foo\"bar\""
88
+ assert_no_match STRING, "'foo\nbar'"
89
+ assert_no_match STRING, "'foo'bar'"
90
+ end
91
+
92
+ def test_uri
93
+ assert_match URI, 'url("foo bar)")'
94
+ assert_match URI, "url('foo bar)')"
95
+ assert_match URI, 'url( "foo bar)" )'
96
+ assert_match URI, "url(#\\%&**+,-./0123456789~)"
97
+ end
98
+
99
+ def test_invalid_uri
100
+ assert_no_match URI, 'url(foo)bar)'
101
+ end
102
+
103
+ def test_unicode_range
104
+ assert_match UNICODERANGE, 'U+00-Ff'
105
+ assert_match UNICODERANGE, 'u+980-9FF'
106
+ assert_match UNICODERANGE, 'U+9aF??'
107
+ assert_match UNICODERANGE, 'U+??'
108
+ end
109
+
110
+ def test_escape_empty_ident
111
+ assert_equal "", Sass::SCSS::RX.escape_ident("")
112
+ end
113
+
114
+ def test_escape_just_prefix_ident
115
+ assert_equal "\\-", Sass::SCSS::RX.escape_ident("-")
116
+ assert_equal "\\_", Sass::SCSS::RX.escape_ident("_")
117
+ end
118
+
119
+ def test_escape_plain_ident
120
+ assert_equal "foo", Sass::SCSS::RX.escape_ident("foo")
121
+ assert_equal "foo-1bar", Sass::SCSS::RX.escape_ident("foo-1bar")
122
+ assert_equal "-foo-bar", Sass::SCSS::RX.escape_ident("-foo-bar")
123
+ assert_equal "f2oo_bar", Sass::SCSS::RX.escape_ident("f2oo_bar")
124
+ assert_equal "_foo_bar", Sass::SCSS::RX.escape_ident("_foo_bar")
125
+ end
126
+
127
+ def test_escape_initial_funky_ident
128
+ assert_equal "\\000035foo", Sass::SCSS::RX.escape_ident("5foo")
129
+ assert_equal "-\\000035foo", Sass::SCSS::RX.escape_ident("-5foo")
130
+ assert_equal "_\\000035foo", Sass::SCSS::RX.escape_ident("_5foo")
131
+
132
+ assert_equal "\\&foo", Sass::SCSS::RX.escape_ident("&foo")
133
+ assert_equal "-\\&foo", Sass::SCSS::RX.escape_ident("-&foo")
134
+
135
+ assert_equal "-\\ foo", Sass::SCSS::RX.escape_ident("- foo")
136
+ end
137
+
138
+ def test_escape_mid_funky_ident
139
+ assert_equal "foo\\&bar", Sass::SCSS::RX.escape_ident("foo&bar")
140
+ assert_equal "foo\\ \\ bar", Sass::SCSS::RX.escape_ident("foo bar")
141
+ assert_equal "foo\\00007fbar", Sass::SCSS::RX.escape_ident("foo\177bar")
142
+ end
143
+
144
+ private
145
+
146
+ def assert_match(rx, str)
147
+ refute_nil(match = rx.match(str))
148
+ assert_equal str.size, match[0].size
149
+ end
150
+
151
+ def assert_no_match(rx, str)
152
+ match = rx.match(str)
153
+ refute_equal str.size, match && match[0].size
154
+ end
155
+
156
+ end
@@ -0,0 +1,3900 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/test_helper'
4
+
5
+ class ScssTest < MiniTest::Test
6
+ include ScssTestHelper
7
+
8
+ ## One-Line Comments
9
+
10
+ def test_one_line_comments
11
+ assert_equal <<CSS, render(<<SCSS)
12
+ .foo {
13
+ baz: bang; }
14
+ CSS
15
+ .foo {// bar: baz;}
16
+ baz: bang; //}
17
+ }
18
+ SCSS
19
+ assert_equal <<CSS, render(<<SCSS)
20
+ .foo bar[val="//"] {
21
+ baz: bang; }
22
+ CSS
23
+ .foo bar[val="//"] {
24
+ baz: bang; //}
25
+ }
26
+ SCSS
27
+ end
28
+
29
+ ## Script
30
+
31
+ def test_variables
32
+ assert_equal <<CSS, render(<<SCSS)
33
+ blat {
34
+ a: foo; }
35
+ CSS
36
+ $var: foo;
37
+
38
+ blat {a: $var}
39
+ SCSS
40
+
41
+ assert_equal <<CSS, render(<<SCSS)
42
+ foo {
43
+ a: 2;
44
+ b: 6; }
45
+ CSS
46
+ foo {
47
+ $var: 2;
48
+ $another-var: 4;
49
+ a: $var;
50
+ b: $var + $another-var;}
51
+ SCSS
52
+ end
53
+
54
+ def test_unicode_variables
55
+ assert_equal <<CSS, render(<<SCSS)
56
+ blat {
57
+ a: foo; }
58
+ CSS
59
+ $vär: foo;
60
+
61
+ blat {a: $vär}
62
+ SCSS
63
+ end
64
+
65
+ def test_guard_assign
66
+ assert_equal <<CSS, render(<<SCSS)
67
+ foo {
68
+ a: 1; }
69
+ CSS
70
+ $var: 1;
71
+ $var: 2 !default;
72
+
73
+ foo {a: $var}
74
+ SCSS
75
+
76
+ assert_equal <<CSS, render(<<SCSS)
77
+ foo {
78
+ a: 2; }
79
+ CSS
80
+ $var: 2 !default;
81
+
82
+ foo {a: $var}
83
+ SCSS
84
+ end
85
+
86
+ def test_sass_script
87
+ assert_equal <<CSS, render(<<SCSS)
88
+ foo {
89
+ a: 3;
90
+ b: -1;
91
+ c: foobar;
92
+ d: 12px; }
93
+ CSS
94
+ foo {
95
+ a: 1 + 2;
96
+ b: 1 - 2;
97
+ c: foo + bar;
98
+ d: floor(12.3px); }
99
+ SCSS
100
+ end
101
+
102
+ def test_debug_directive
103
+ assert_warning "test_debug_directive_inline.scss:2 DEBUG: hello world!" do
104
+ assert_equal <<CSS, render(<<SCSS)
105
+ foo {
106
+ a: b; }
107
+
108
+ bar {
109
+ c: d; }
110
+ CSS
111
+ foo {a: b}
112
+ @debug "hello world!";
113
+ bar {c: d}
114
+ SCSS
115
+ end
116
+ end
117
+
118
+ def test_error_directive
119
+ assert_raise_message(Sass::SyntaxError, "hello world!") {render(<<SCSS)}
120
+ foo {a: b}
121
+ @error "hello world!";
122
+ bar {c: d}
123
+ SCSS
124
+ end
125
+
126
+ def test_warn_directive
127
+ expected_warning = <<EXPECTATION
128
+ WARNING: this is a warning
129
+ on line 2 of test_warn_directive_inline.scss
130
+
131
+ WARNING: this is a mixin
132
+ on line 1 of test_warn_directive_inline.scss, in `foo'
133
+ from line 3 of test_warn_directive_inline.scss
134
+ EXPECTATION
135
+ assert_warning expected_warning do
136
+ assert_equal <<CSS, render(<<SCSS)
137
+ bar {
138
+ c: d; }
139
+ CSS
140
+ @mixin foo { @warn "this is a mixin";}
141
+ @warn "this is a warning";
142
+ bar {c: d; @include foo;}
143
+ SCSS
144
+ end
145
+ end
146
+
147
+ def test_for_directive
148
+ assert_equal <<CSS, render(<<SCSS)
149
+ .foo {
150
+ a: 1;
151
+ a: 2;
152
+ a: 3;
153
+ a: 4; }
154
+ CSS
155
+ .foo {
156
+ @for $var from 1 to 5 {a: $var;}
157
+ }
158
+ SCSS
159
+
160
+ assert_equal <<CSS, render(<<SCSS)
161
+ .foo {
162
+ a: 1;
163
+ a: 2;
164
+ a: 3;
165
+ a: 4;
166
+ a: 5; }
167
+ CSS
168
+ .foo {
169
+ @for $var from 1 through 5 {a: $var;}
170
+ }
171
+ SCSS
172
+ end
173
+
174
+ def test_for_directive_with_same_start_and_end
175
+ assert_equal <<CSS, render(<<SCSS)
176
+ CSS
177
+ .foo {
178
+ @for $var from 1 to 1 {a: $var;}
179
+ }
180
+ SCSS
181
+
182
+ assert_equal <<CSS, render(<<SCSS)
183
+ .foo {
184
+ a: 1; }
185
+ CSS
186
+ .foo {
187
+ @for $var from 1 through 1 {a: $var;}
188
+ }
189
+ SCSS
190
+ end
191
+
192
+ def test_decrementing_estfor_directive
193
+ assert_equal <<CSS, render(<<SCSS)
194
+ .foo {
195
+ a: 5;
196
+ a: 4;
197
+ a: 3;
198
+ a: 2;
199
+ a: 1; }
200
+ CSS
201
+ .foo {
202
+ @for $var from 5 through 1 {a: $var;}
203
+ }
204
+ SCSS
205
+
206
+ assert_equal <<CSS, render(<<SCSS)
207
+ .foo {
208
+ a: 5;
209
+ a: 4;
210
+ a: 3;
211
+ a: 2; }
212
+ CSS
213
+ .foo {
214
+ @for $var from 5 to 1 {a: $var;}
215
+ }
216
+ SCSS
217
+ end
218
+
219
+ def test_if_directive
220
+ assert_equal <<CSS, render(<<SCSS)
221
+ foo {
222
+ a: b; }
223
+ CSS
224
+ @if "foo" == "foo" {foo {a: b}}
225
+ @if "foo" != "foo" {bar {a: b}}
226
+ SCSS
227
+
228
+ assert_equal <<CSS, render(<<SCSS)
229
+ bar {
230
+ a: b; }
231
+ CSS
232
+ @if "foo" != "foo" {foo {a: b}}
233
+ @else if "foo" == "foo" {bar {a: b}}
234
+ @else if true {baz {a: b}}
235
+ SCSS
236
+
237
+ assert_equal <<CSS, render(<<SCSS)
238
+ bar {
239
+ a: b; }
240
+ CSS
241
+ @if "foo" != "foo" {foo {a: b}}
242
+ @else {bar {a: b}}
243
+ SCSS
244
+ end
245
+
246
+ def test_comment_after_if_directive
247
+ assert_equal <<CSS, render(<<SCSS)
248
+ foo {
249
+ a: b;
250
+ /* This is a comment */
251
+ c: d; }
252
+ CSS
253
+ foo {
254
+ @if true {a: b}
255
+ /* This is a comment */
256
+ c: d }
257
+ SCSS
258
+ assert_equal <<CSS, render(<<SCSS)
259
+ foo {
260
+ a: b;
261
+ /* This is a comment */
262
+ c: d; }
263
+ CSS
264
+ foo {
265
+ @if true {a: b}
266
+ @else {x: y}
267
+ /* This is a comment */
268
+ c: d }
269
+ SCSS
270
+ end
271
+
272
+ def test_while_directive
273
+ assert_equal <<CSS, render(<<SCSS)
274
+ .foo {
275
+ a: 1;
276
+ a: 2;
277
+ a: 3;
278
+ a: 4; }
279
+ CSS
280
+ $i: 1;
281
+
282
+ .foo {
283
+ @while $i != 5 {
284
+ a: $i;
285
+ $i: $i + 1 !global;
286
+ }
287
+ }
288
+ SCSS
289
+ end
290
+
291
+ def test_each_directive
292
+ assert_equal <<CSS, render(<<SCSS)
293
+ a {
294
+ b: 1px;
295
+ b: 2px;
296
+ b: 3px;
297
+ b: 4px; }
298
+
299
+ c {
300
+ d: foo;
301
+ d: bar;
302
+ d: baz;
303
+ d: bang; }
304
+ CSS
305
+ a {
306
+ @each $number in 1px 2px 3px 4px {
307
+ b: $number;
308
+ }
309
+ }
310
+ c {
311
+ @each $str in foo, bar, baz, bang {
312
+ d: $str;
313
+ }
314
+ }
315
+ SCSS
316
+ end
317
+
318
+ def test_destructuring_each_directive
319
+ assert_equal <<CSS, render(<<SCSS)
320
+ a {
321
+ foo: 1px;
322
+ bar: 2px;
323
+ baz: 3px; }
324
+
325
+ c {
326
+ foo: "Value is bar";
327
+ bar: "Value is baz";
328
+ bang: "Value is "; }
329
+ CSS
330
+ a {
331
+ @each $name, $number in (foo: 1px, bar: 2px, baz: 3px) {
332
+ \#{$name}: $number;
333
+ }
334
+ }
335
+ c {
336
+ @each $key, $value in (foo bar) (bar, baz) bang {
337
+ \#{$key}: "Value is \#{$value}";
338
+ }
339
+ }
340
+ SCSS
341
+ end
342
+
343
+ def test_css_import_directive
344
+ assert_equal "@import url(foo.css);\n", render('@import "foo.css";')
345
+ assert_equal "@import url(foo.css);\n", render("@import 'foo.css';")
346
+ assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
347
+ assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
348
+ assert_equal "@import url(foo.css);\n", render('@import url(foo.css);')
349
+ end
350
+
351
+ def test_css_string_import_directive_with_media
352
+ assert_parses '@import "foo.css" screen;'
353
+ assert_parses '@import "foo.css" screen, print;'
354
+ assert_parses '@import "foo.css" screen, print and (foo: 0);'
355
+ assert_parses '@import "foo.css" screen, only print, screen and (foo: 0);'
356
+ end
357
+
358
+ def test_css_url_import_directive_with_media
359
+ assert_parses '@import url("foo.css") screen;'
360
+ assert_parses '@import url("foo.css") screen, print;'
361
+ assert_parses '@import url("foo.css") screen, print and (foo: 0);'
362
+ assert_parses '@import url("foo.css") screen, only print, screen and (foo: 0);'
363
+ end
364
+
365
+ def test_media_import
366
+ assert_equal("@import \"./fonts.sass\" all;\n", render("@import \"./fonts.sass\" all;"))
367
+ end
368
+
369
+ def test_dynamic_media_import
370
+ assert_equal(<<CSS, render(<<SCSS))
371
+ @import "foo" print and (-webkit-min-device-pixel-ratio-foo: 25);
372
+ CSS
373
+ $media: print;
374
+ $key: -webkit-min-device-pixel-ratio;
375
+ $value: 20;
376
+ @import "foo" \#{$media} and ($key + "-foo": $value + 5);
377
+ SCSS
378
+ end
379
+
380
+ def test_http_import
381
+ assert_equal("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";\n",
382
+ render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";"))
383
+ end
384
+
385
+ def test_protocol_relative_import
386
+ assert_equal("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";\n",
387
+ render("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";"))
388
+ end
389
+
390
+ def test_import_with_interpolation
391
+ assert_equal <<CSS, render(<<SCSS)
392
+ @import url("http://fonts.googleapis.com/css?family=Droid+Sans");
393
+ CSS
394
+ $family: unquote("Droid+Sans");
395
+ @import url("http://fonts.googleapis.com/css?family=\#{$family}");
396
+ SCSS
397
+ end
398
+
399
+ def test_url_import
400
+ assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass);"))
401
+ end
402
+
403
+ def test_css_import_doesnt_move_through_comments
404
+ assert_equal <<CSS, render(<<SCSS)
405
+ /* Comment 1 */
406
+ @import url("foo.css");
407
+ /* Comment 2 */
408
+ @import url("bar.css");
409
+ CSS
410
+ /* Comment 1 */
411
+ @import url("foo.css");
412
+
413
+ /* Comment 2 */
414
+ @import url("bar.css");
415
+ SCSS
416
+ end
417
+
418
+ def test_css_import_movement_stops_at_comments
419
+ assert_equal <<CSS, render(<<SCSS)
420
+ /* Comment 1 */
421
+ @import url("foo.css");
422
+ /* Comment 2 */
423
+ @import url("bar.css");
424
+ .foo {
425
+ a: b; }
426
+
427
+ /* Comment 3 */
428
+ CSS
429
+ /* Comment 1 */
430
+ @import url("foo.css");
431
+
432
+ /* Comment 2 */
433
+
434
+ .foo {a: b}
435
+
436
+ /* Comment 3 */
437
+ @import url("bar.css");
438
+ SCSS
439
+ end
440
+
441
+ def test_block_comment_in_script
442
+ assert_equal <<CSS, render(<<SCSS)
443
+ foo {
444
+ a: 1bar; }
445
+ CSS
446
+ foo {a: 1 + /* flang */ bar}
447
+ SCSS
448
+ end
449
+
450
+ def test_line_comment_in_script
451
+ assert_equal <<CSS, render(<<SCSS)
452
+ foo {
453
+ a: 1blang; }
454
+ CSS
455
+ foo {a: 1 + // flang }
456
+ blang }
457
+ SCSS
458
+ end
459
+
460
+ ## Nested Rules
461
+
462
+ def test_nested_rules
463
+ assert_equal <<CSS, render(<<SCSS)
464
+ foo bar {
465
+ a: b; }
466
+ CSS
467
+ foo {bar {a: b}}
468
+ SCSS
469
+ assert_equal <<CSS, render(<<SCSS)
470
+ foo bar {
471
+ a: b; }
472
+ foo baz {
473
+ b: c; }
474
+ CSS
475
+ foo {
476
+ bar {a: b}
477
+ baz {b: c}}
478
+ SCSS
479
+ assert_equal <<CSS, render(<<SCSS)
480
+ foo bar baz {
481
+ a: b; }
482
+ foo bang bip {
483
+ a: b; }
484
+ CSS
485
+ foo {
486
+ bar {baz {a: b}}
487
+ bang {bip {a: b}}}
488
+ SCSS
489
+ end
490
+
491
+ def test_nested_rules_with_declarations
492
+ assert_equal <<CSS, render(<<SCSS)
493
+ foo {
494
+ a: b; }
495
+ foo bar {
496
+ c: d; }
497
+ CSS
498
+ foo {
499
+ a: b;
500
+ bar {c: d}}
501
+ SCSS
502
+ assert_equal <<CSS, render(<<SCSS)
503
+ foo {
504
+ a: b; }
505
+ foo bar {
506
+ c: d; }
507
+ CSS
508
+ foo {
509
+ bar {c: d}
510
+ a: b}
511
+ SCSS
512
+ assert_equal <<CSS, render(<<SCSS)
513
+ foo {
514
+ ump: nump;
515
+ grump: clump; }
516
+ foo bar {
517
+ blat: bang;
518
+ habit: rabbit; }
519
+ foo bar baz {
520
+ a: b; }
521
+ foo bar bip {
522
+ c: d; }
523
+ foo bibble bap {
524
+ e: f; }
525
+ CSS
526
+ foo {
527
+ ump: nump;
528
+ grump: clump;
529
+ bar {
530
+ blat: bang;
531
+ habit: rabbit;
532
+ baz {a: b}
533
+ bip {c: d}}
534
+ bibble {
535
+ bap {e: f}}}
536
+ SCSS
537
+ end
538
+
539
+ def test_nested_rules_with_fancy_selectors
540
+ assert_equal <<CSS, render(<<SCSS)
541
+ foo .bar {
542
+ a: b; }
543
+ foo :baz {
544
+ c: d; }
545
+ foo bang:bop {
546
+ e: f; }
547
+ foo ::qux {
548
+ g: h; }
549
+ foo zap::fblthp {
550
+ i: j; }
551
+ CSS
552
+ foo {
553
+ .bar {a: b}
554
+ :baz {c: d}
555
+ bang:bop {e: f}
556
+ ::qux {g: h}
557
+ zap::fblthp {i: j}}
558
+ SCSS
559
+ end
560
+
561
+ def test_almost_ambiguous_nested_rules_and_declarations
562
+ assert_equal <<CSS, render(<<SCSS)
563
+ foo {
564
+ bar: baz bang bop biddle woo look at all these elems; }
565
+ foo bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {
566
+ a: b; }
567
+ foo bar:baz bang bop biddle woo look at all these elems {
568
+ a: b; }
569
+ CSS
570
+ foo {
571
+ bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {a: b};
572
+ bar:baz bang bop biddle woo look at all these elems {a: b};
573
+ bar:baz bang bop biddle woo look at all these elems; }
574
+ SCSS
575
+ end
576
+
577
+ def test_newlines_in_selectors
578
+ assert_equal <<CSS, render(<<SCSS)
579
+ foo
580
+ bar {
581
+ a: b; }
582
+ CSS
583
+ foo
584
+ bar {a: b}
585
+ SCSS
586
+
587
+ assert_equal <<CSS, render(<<SCSS)
588
+ foo baz,
589
+ foo bang,
590
+ bar baz,
591
+ bar bang {
592
+ a: b; }
593
+ CSS
594
+ foo,
595
+ bar {
596
+ baz,
597
+ bang {a: b}}
598
+ SCSS
599
+
600
+ assert_equal <<CSS, render(<<SCSS)
601
+ foo
602
+ bar baz
603
+ bang {
604
+ a: b; }
605
+ foo
606
+ bar bip bop {
607
+ c: d; }
608
+ CSS
609
+ foo
610
+ bar {
611
+ baz
612
+ bang {a: b}
613
+
614
+ bip bop {c: d}}
615
+ SCSS
616
+
617
+ assert_equal <<CSS, render(<<SCSS)
618
+ foo bang, foo bip
619
+ bop, bar
620
+ baz bang, bar
621
+ baz bip
622
+ bop {
623
+ a: b; }
624
+ CSS
625
+ foo, bar
626
+ baz {
627
+ bang, bip
628
+ bop {a: b}}
629
+ SCSS
630
+ end
631
+
632
+ def test_trailing_comma_in_selector
633
+ assert_equal <<CSS, render(<<SCSS)
634
+ #foo #bar,
635
+ #baz #boom {
636
+ a: b; }
637
+
638
+ #bip #bop {
639
+ c: d; }
640
+ CSS
641
+ #foo #bar,,
642
+ ,#baz #boom, {a: b}
643
+
644
+ #bip #bop, ,, {c: d}
645
+ SCSS
646
+ end
647
+
648
+ def test_parent_selectors
649
+ assert_equal <<CSS, render(<<SCSS)
650
+ foo:hover {
651
+ a: b; }
652
+ bar foo.baz {
653
+ c: d; }
654
+ CSS
655
+ foo {
656
+ &:hover {a: b}
657
+ bar &.baz {c: d}}
658
+ SCSS
659
+ end
660
+
661
+ def test_parent_selector_with_subject
662
+ silence_warnings {assert_equal <<CSS, render(<<SCSS)}
663
+ bar foo.baz! .bip {
664
+ a: b; }
665
+
666
+ bar foo bar.baz! .bip {
667
+ c: d; }
668
+ CSS
669
+ foo {
670
+ bar &.baz! .bip {a: b}}
671
+
672
+ foo bar {
673
+ bar &.baz! .bip {c: d}}
674
+ SCSS
675
+ end
676
+
677
+ def test_parent_selector_with_suffix
678
+ assert_equal <<CSS, render(<<SCSS)
679
+ .foo-bar {
680
+ a: b; }
681
+ .foo_bar {
682
+ c: d; }
683
+ .foobar {
684
+ e: f; }
685
+ .foo123 {
686
+ e: f; }
687
+
688
+ :hover-suffix {
689
+ g: h; }
690
+ CSS
691
+ .foo {
692
+ &-bar {a: b}
693
+ &_bar {c: d}
694
+ &bar {e: f}
695
+ &123 {e: f}
696
+ }
697
+
698
+ :hover {
699
+ &-suffix {g: h}
700
+ }
701
+ SCSS
702
+ end
703
+
704
+ def test_unknown_directive_bubbling
705
+ assert_equal(<<CSS, render(<<SCSS, :style => :nested))
706
+ @fblthp {
707
+ .foo .bar {
708
+ a: b; } }
709
+ CSS
710
+ .foo {
711
+ @fblthp {
712
+ .bar {a: b}
713
+ }
714
+ }
715
+ SCSS
716
+ end
717
+
718
+ ## Namespace Properties
719
+
720
+ def test_namespace_properties
721
+ assert_equal <<CSS, render(<<SCSS)
722
+ foo {
723
+ bar: baz;
724
+ bang-bip: 1px;
725
+ bang-bop: bar; }
726
+ CSS
727
+ foo {
728
+ bar: baz;
729
+ bang: {
730
+ bip: 1px;
731
+ bop: bar;}}
732
+ SCSS
733
+ end
734
+
735
+ def test_several_namespace_properties
736
+ assert_equal <<CSS, render(<<SCSS)
737
+ foo {
738
+ bar: baz;
739
+ bang-bip: 1px;
740
+ bang-bop: bar;
741
+ buzz-fram: "foo";
742
+ buzz-frum: moo; }
743
+ CSS
744
+ foo {
745
+ bar: baz;
746
+ bang: {
747
+ bip: 1px;
748
+ bop: bar;}
749
+ buzz: {
750
+ fram: "foo";
751
+ frum: moo;
752
+ }
753
+ }
754
+ SCSS
755
+ end
756
+
757
+ def test_nested_namespace_properties
758
+ assert_equal <<CSS, render(<<SCSS)
759
+ foo {
760
+ bar: baz;
761
+ bang-bip: 1px;
762
+ bang-bop: bar;
763
+ bang-blat-baf: bort; }
764
+ CSS
765
+ foo {
766
+ bar: baz;
767
+ bang: {
768
+ bip: 1px;
769
+ bop: bar;
770
+ blat:{baf:bort}}}
771
+ SCSS
772
+ end
773
+
774
+ def test_namespace_properties_with_value
775
+ assert_equal <<CSS, render(<<SCSS)
776
+ foo {
777
+ bar: baz;
778
+ bar-bip: bop;
779
+ bar-bing: bop; }
780
+ CSS
781
+ foo {
782
+ bar: baz {
783
+ bip: bop;
784
+ bing: bop; }}
785
+ SCSS
786
+ end
787
+
788
+ def test_namespace_properties_with_script_value
789
+ assert_equal <<CSS, render(<<SCSS)
790
+ foo {
791
+ bar: bazbang;
792
+ bar-bip: bop;
793
+ bar-bing: bop; }
794
+ CSS
795
+ foo {
796
+ bar: baz + bang {
797
+ bip: bop;
798
+ bing: bop; }}
799
+ SCSS
800
+ end
801
+
802
+ def test_no_namespace_properties_without_space
803
+ assert_equal <<CSS, render(<<SCSS)
804
+ foo bar:baz {
805
+ bip: bop; }
806
+ CSS
807
+ foo {
808
+ bar:baz {
809
+ bip: bop }}
810
+ SCSS
811
+ end
812
+
813
+ def test_no_namespace_properties_without_space_even_when_its_unambiguous
814
+ render(<<SCSS)
815
+ foo {
816
+ bar:baz calc(1 + 2) {
817
+ bip: bop }}
818
+ SCSS
819
+ assert(false, "Expected syntax error")
820
+ rescue Sass::SyntaxError => e
821
+ assert_equal 'Invalid CSS after "bar:baz calc": expected selector, was "(1 + 2)"', e.message
822
+ assert_equal 2, e.sass_line
823
+ end
824
+
825
+ def test_namespace_properties_without_space_allowed_for_non_identifier
826
+ assert_equal <<CSS, render(<<SCSS)
827
+ foo {
828
+ bar: 1px;
829
+ bar-bip: bop; }
830
+ CSS
831
+ foo {
832
+ bar:1px {
833
+ bip: bop }}
834
+ SCSS
835
+ end
836
+
837
+ ## Mixins
838
+
839
+ def test_basic_mixins
840
+ assert_equal <<CSS, render(<<SCSS)
841
+ .foo {
842
+ a: b; }
843
+ CSS
844
+ @mixin foo {
845
+ .foo {a: b}}
846
+
847
+ @include foo;
848
+ SCSS
849
+
850
+ assert_equal <<CSS, render(<<SCSS)
851
+ bar {
852
+ c: d; }
853
+ bar .foo {
854
+ a: b; }
855
+ CSS
856
+ @mixin foo {
857
+ .foo {a: b}}
858
+
859
+ bar {
860
+ @include foo;
861
+ c: d; }
862
+ SCSS
863
+
864
+ assert_equal <<CSS, render(<<SCSS)
865
+ bar {
866
+ a: b;
867
+ c: d; }
868
+ CSS
869
+ @mixin foo {a: b}
870
+
871
+ bar {
872
+ @include foo;
873
+ c: d; }
874
+ SCSS
875
+ end
876
+
877
+ def test_mixins_with_empty_args
878
+ assert_equal <<CSS, render(<<SCSS)
879
+ .foo {
880
+ a: b; }
881
+ CSS
882
+ @mixin foo() {a: b}
883
+
884
+ .foo {@include foo();}
885
+ SCSS
886
+
887
+ assert_equal <<CSS, render(<<SCSS)
888
+ .foo {
889
+ a: b; }
890
+ CSS
891
+ @mixin foo() {a: b}
892
+
893
+ .foo {@include foo;}
894
+ SCSS
895
+
896
+ assert_equal <<CSS, render(<<SCSS)
897
+ .foo {
898
+ a: b; }
899
+ CSS
900
+ @mixin foo {a: b}
901
+
902
+ .foo {@include foo();}
903
+ SCSS
904
+ end
905
+
906
+ def test_mixins_with_args
907
+ assert_equal <<CSS, render(<<SCSS)
908
+ .foo {
909
+ a: bar; }
910
+ CSS
911
+ @mixin foo($a) {a: $a}
912
+
913
+ .foo {@include foo(bar)}
914
+ SCSS
915
+
916
+ assert_equal <<CSS, render(<<SCSS)
917
+ .foo {
918
+ a: bar;
919
+ b: 12px; }
920
+ CSS
921
+ @mixin foo($a, $b) {
922
+ a: $a;
923
+ b: $b; }
924
+
925
+ .foo {@include foo(bar, 12px)}
926
+ SCSS
927
+ end
928
+
929
+ def test_keyframes_rules_in_content
930
+ assert_equal <<CSS, render(<<SCSS)
931
+ @keyframes identifier {
932
+ 0% {
933
+ top: 0;
934
+ left: 0; }
935
+ 30% {
936
+ top: 50px; }
937
+ 68%, 72% {
938
+ left: 50px; }
939
+ 100% {
940
+ top: 100px;
941
+ left: 100%; } }
942
+ CSS
943
+ @mixin keyframes {
944
+ @keyframes identifier { @content }
945
+ }
946
+
947
+ @include keyframes {
948
+ 0% {top: 0; left: 0}
949
+ \#{"30%"} {top: 50px}
950
+ 68%, 72% {left: 50px}
951
+ 100% {top: 100px; left: 100%}
952
+ }
953
+ SCSS
954
+ end
955
+
956
+ ## Functions
957
+
958
+ def test_basic_function
959
+ assert_equal(<<CSS, render(<<SASS))
960
+ bar {
961
+ a: 3; }
962
+ CSS
963
+ @function foo() {
964
+ @return 1 + 2;
965
+ }
966
+
967
+ bar {
968
+ a: foo();
969
+ }
970
+ SASS
971
+ end
972
+
973
+ def test_function_args
974
+ assert_equal(<<CSS, render(<<SASS))
975
+ bar {
976
+ a: 3; }
977
+ CSS
978
+ @function plus($var1, $var2) {
979
+ @return $var1 + $var2;
980
+ }
981
+
982
+ bar {
983
+ a: plus(1, 2);
984
+ }
985
+ SASS
986
+ end
987
+
988
+ ## Var Args
989
+
990
+ def test_mixin_var_args
991
+ assert_equal <<CSS, render(<<SCSS)
992
+ .foo {
993
+ a: 1;
994
+ b: 2, 3, 4; }
995
+ CSS
996
+ @mixin foo($a, $b...) {
997
+ a: $a;
998
+ b: $b;
999
+ }
1000
+
1001
+ .foo {@include foo(1, 2, 3, 4)}
1002
+ SCSS
1003
+ end
1004
+
1005
+ def test_mixin_empty_var_args
1006
+ assert_equal <<CSS, render(<<SCSS)
1007
+ .foo {
1008
+ a: 1;
1009
+ b: 0; }
1010
+ CSS
1011
+ @mixin foo($a, $b...) {
1012
+ a: $a;
1013
+ b: length($b);
1014
+ }
1015
+
1016
+ .foo {@include foo(1)}
1017
+ SCSS
1018
+ end
1019
+
1020
+ def test_mixin_var_args_act_like_list
1021
+ assert_equal <<CSS, render(<<SCSS)
1022
+ .foo {
1023
+ a: 3;
1024
+ b: 3; }
1025
+ CSS
1026
+ @mixin foo($a, $b...) {
1027
+ a: length($b);
1028
+ b: nth($b, 2);
1029
+ }
1030
+
1031
+ .foo {@include foo(1, 2, 3, 4)}
1032
+ SCSS
1033
+ end
1034
+
1035
+ def test_mixin_splat_args
1036
+ assert_equal <<CSS, render(<<SCSS)
1037
+ .foo {
1038
+ a: 1;
1039
+ b: 2;
1040
+ c: 3;
1041
+ d: 4; }
1042
+ CSS
1043
+ @mixin foo($a, $b, $c, $d) {
1044
+ a: $a;
1045
+ b: $b;
1046
+ c: $c;
1047
+ d: $d;
1048
+ }
1049
+
1050
+ $list: 2, 3, 4;
1051
+ .foo {@include foo(1, $list...)}
1052
+ SCSS
1053
+ end
1054
+
1055
+ def test_mixin_splat_expression
1056
+ assert_equal <<CSS, render(<<SCSS)
1057
+ .foo {
1058
+ a: 1;
1059
+ b: 2;
1060
+ c: 3;
1061
+ d: 4; }
1062
+ CSS
1063
+ @mixin foo($a, $b, $c, $d) {
1064
+ a: $a;
1065
+ b: $b;
1066
+ c: $c;
1067
+ d: $d;
1068
+ }
1069
+
1070
+ .foo {@include foo(1, (2, 3, 4)...)}
1071
+ SCSS
1072
+ end
1073
+
1074
+ def test_mixin_splat_args_with_var_args
1075
+ assert_equal <<CSS, render(<<SCSS)
1076
+ .foo {
1077
+ a: 1;
1078
+ b: 2, 3, 4; }
1079
+ CSS
1080
+ @mixin foo($a, $b...) {
1081
+ a: $a;
1082
+ b: $b;
1083
+ }
1084
+
1085
+ $list: 2, 3, 4;
1086
+ .foo {@include foo(1, $list...)}
1087
+ SCSS
1088
+ end
1089
+
1090
+ def test_mixin_splat_args_with_var_args_and_normal_args
1091
+ assert_equal <<CSS, render(<<SCSS)
1092
+ .foo {
1093
+ a: 1;
1094
+ b: 2;
1095
+ c: 3, 4; }
1096
+ CSS
1097
+ @mixin foo($a, $b, $c...) {
1098
+ a: $a;
1099
+ b: $b;
1100
+ c: $c;
1101
+ }
1102
+
1103
+ $list: 2, 3, 4;
1104
+ .foo {@include foo(1, $list...)}
1105
+ SCSS
1106
+ end
1107
+
1108
+ def test_mixin_splat_args_with_var_args_preserves_separator
1109
+ assert_equal <<CSS, render(<<SCSS)
1110
+ .foo {
1111
+ a: 1;
1112
+ b: 2 3 4 5; }
1113
+ CSS
1114
+ @mixin foo($a, $b...) {
1115
+ a: $a;
1116
+ b: $b;
1117
+ }
1118
+
1119
+ $list: 3 4 5;
1120
+ .foo {@include foo(1, 2, $list...)}
1121
+ SCSS
1122
+ end
1123
+
1124
+ def test_mixin_var_and_splat_args_pass_through_keywords
1125
+ assert_equal <<CSS, render(<<SCSS)
1126
+ .foo {
1127
+ a: 3;
1128
+ b: 1;
1129
+ c: 2; }
1130
+ CSS
1131
+ @mixin foo($a...) {
1132
+ @include bar($a...);
1133
+ }
1134
+
1135
+ @mixin bar($b, $c, $a) {
1136
+ a: $a;
1137
+ b: $b;
1138
+ c: $c;
1139
+ }
1140
+
1141
+ .foo {@include foo(1, $c: 2, $a: 3)}
1142
+ SCSS
1143
+ end
1144
+
1145
+ def test_mixin_var_keyword_args
1146
+ assert_equal <<CSS, render(<<SCSS)
1147
+ .foo {
1148
+ a: 1;
1149
+ b: 2;
1150
+ c: 3; }
1151
+ CSS
1152
+ @mixin foo($args...) {
1153
+ a: map-get(keywords($args), a);
1154
+ b: map-get(keywords($args), b);
1155
+ c: map-get(keywords($args), c);
1156
+ }
1157
+
1158
+ .foo {@include foo($a: 1, $b: 2, $c: 3)}
1159
+ SCSS
1160
+ end
1161
+
1162
+ def test_mixin_empty_var_keyword_args
1163
+ assert_equal <<CSS, render(<<SCSS)
1164
+ .foo {
1165
+ length: 0; }
1166
+ CSS
1167
+ @mixin foo($args...) {
1168
+ length: length(keywords($args));
1169
+ }
1170
+
1171
+ .foo {@include foo}
1172
+ SCSS
1173
+ end
1174
+
1175
+ def test_mixin_map_splat
1176
+ assert_equal <<CSS, render(<<SCSS)
1177
+ .foo {
1178
+ a: 1;
1179
+ b: 2;
1180
+ c: 3; }
1181
+ CSS
1182
+ @mixin foo($a, $b, $c) {
1183
+ a: $a;
1184
+ b: $b;
1185
+ c: $c;
1186
+ }
1187
+
1188
+ .foo {
1189
+ $map: (a: 1, b: 2, c: 3);
1190
+ @include foo($map...);
1191
+ }
1192
+ SCSS
1193
+ end
1194
+
1195
+ def test_mixin_map_and_list_splat
1196
+ assert_equal <<CSS, render(<<SCSS)
1197
+ .foo {
1198
+ a: x;
1199
+ b: y;
1200
+ c: z;
1201
+ d: 1;
1202
+ e: 2;
1203
+ f: 3; }
1204
+ CSS
1205
+ @mixin foo($a, $b, $c, $d, $e, $f) {
1206
+ a: $a;
1207
+ b: $b;
1208
+ c: $c;
1209
+ d: $d;
1210
+ e: $e;
1211
+ f: $f;
1212
+ }
1213
+
1214
+ .foo {
1215
+ $list: x y z;
1216
+ $map: (d: 1, e: 2, f: 3);
1217
+ @include foo($list..., $map...);
1218
+ }
1219
+ SCSS
1220
+ end
1221
+
1222
+ def test_mixin_map_splat_takes_precedence_over_pass_through
1223
+ assert_equal <<CSS, render(<<SCSS)
1224
+ .foo {
1225
+ a: 1;
1226
+ b: 2;
1227
+ c: z; }
1228
+ CSS
1229
+ @mixin foo($args...) {
1230
+ $map: (c: z);
1231
+ @include bar($args..., $map...);
1232
+ }
1233
+
1234
+ @mixin bar($a, $b, $c) {
1235
+ a: $a;
1236
+ b: $b;
1237
+ c: $c;
1238
+ }
1239
+
1240
+ .foo {
1241
+ @include foo(1, $b: 2, $c: 3);
1242
+ }
1243
+ SCSS
1244
+ end
1245
+
1246
+ def test_mixin_list_of_pairs_splat_treated_as_list
1247
+ assert_equal <<CSS, render(<<SCSS)
1248
+ .foo {
1249
+ a: a 1;
1250
+ b: b 2;
1251
+ c: c 3; }
1252
+ CSS
1253
+ @mixin foo($a, $b, $c) {
1254
+ a: $a;
1255
+ b: $b;
1256
+ c: $c;
1257
+ }
1258
+
1259
+ .foo {
1260
+ @include foo((a 1, b 2, c 3)...);
1261
+ }
1262
+ SCSS
1263
+ end
1264
+
1265
+ def test_mixin_splat_after_keyword_args
1266
+ assert_equal <<CSS, render(<<SCSS)
1267
+ .foo {
1268
+ a: 1;
1269
+ b: 2;
1270
+ c: 3; }
1271
+ CSS
1272
+ @mixin foo($a, $b, $c) {
1273
+ a: 1;
1274
+ b: 2;
1275
+ c: 3;
1276
+ }
1277
+
1278
+ .foo {
1279
+ @include foo(1, $c: 3, 2...);
1280
+ }
1281
+ SCSS
1282
+ end
1283
+
1284
+ def test_mixin_keyword_args_after_splat
1285
+ assert_equal <<CSS, render(<<SCSS)
1286
+ .foo {
1287
+ a: 1;
1288
+ b: 2;
1289
+ c: 3; }
1290
+ CSS
1291
+ @mixin foo($a, $b, $c) {
1292
+ a: 1;
1293
+ b: 2;
1294
+ c: 3;
1295
+ }
1296
+
1297
+ .foo {
1298
+ @include foo(1, 2..., $c: 3);
1299
+ }
1300
+ SCSS
1301
+ end
1302
+
1303
+ def test_mixin_keyword_splat_after_keyword_args
1304
+ assert_equal <<CSS, render(<<SCSS)
1305
+ .foo {
1306
+ a: 1;
1307
+ b: 2;
1308
+ c: 3; }
1309
+ CSS
1310
+ @mixin foo($a, $b, $c) {
1311
+ a: 1;
1312
+ b: 2;
1313
+ c: 3;
1314
+ }
1315
+
1316
+ .foo {
1317
+ @include foo(1, $b: 2, (c: 3)...);
1318
+ }
1319
+ SCSS
1320
+ end
1321
+
1322
+ def test_mixin_triple_keyword_splat_merge
1323
+ assert_equal <<CSS, render(<<SCSS)
1324
+ .foo {
1325
+ foo: 1;
1326
+ bar: 2;
1327
+ kwarg: 3;
1328
+ a: 3;
1329
+ b: 2;
1330
+ c: 3; }
1331
+ CSS
1332
+ @mixin foo($foo, $bar, $kwarg, $a, $b, $c) {
1333
+ foo: $foo;
1334
+ bar: $bar;
1335
+ kwarg: $kwarg;
1336
+ a: $a;
1337
+ b: $b;
1338
+ c: $c;
1339
+ }
1340
+
1341
+ @mixin bar($args...) {
1342
+ @include foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1343
+ }
1344
+
1345
+ .foo {
1346
+ @include bar($foo: 1, $a: 1, $b: 1, $c: 1);
1347
+ }
1348
+ SCSS
1349
+ end
1350
+
1351
+ def test_mixin_map_splat_converts_hyphens_and_underscores_for_real_args
1352
+ assert_equal <<CSS, render(<<SCSS)
1353
+ .foo {
1354
+ a: 1;
1355
+ b: 2;
1356
+ c: 3;
1357
+ d: 4; }
1358
+ CSS
1359
+ @mixin foo($a-1, $b-2, $c_3, $d_4) {
1360
+ a: $a-1;
1361
+ b: $b-2;
1362
+ c: $c_3;
1363
+ d: $d_4;
1364
+ }
1365
+
1366
+ .foo {
1367
+ $map: (a-1: 1, b_2: 2, c-3: 3, d_4: 4);
1368
+ @include foo($map...);
1369
+ }
1370
+ SCSS
1371
+ end
1372
+
1373
+ def test_mixin_map_splat_doesnt_convert_hyphens_and_underscores_for_var_args
1374
+ assert_equal <<CSS, render(<<SCSS)
1375
+ .foo {
1376
+ a-1: 1;
1377
+ b_2: 2;
1378
+ c-3: 3;
1379
+ d_4: 4; }
1380
+ CSS
1381
+ @mixin foo($args...) {
1382
+ @each $key, $value in keywords($args) {
1383
+ \#{$key}: $value;
1384
+ }
1385
+ }
1386
+
1387
+ .foo {
1388
+ $map: (a-1: 1, b_2: 2, c-3: 3, d_4: 4);
1389
+ @include foo($map...);
1390
+ }
1391
+ SCSS
1392
+ end
1393
+
1394
+ def test_mixin_conflicting_splat_after_keyword_args
1395
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1396
+ Mixin foo was passed argument $b both by position and by name.
1397
+ MESSAGE
1398
+ @mixin foo($a, $b, $c) {
1399
+ a: 1;
1400
+ b: 2;
1401
+ c: 3;
1402
+ }
1403
+
1404
+ .foo {
1405
+ @include foo(1, $b: 2, 3...);
1406
+ }
1407
+ SCSS
1408
+ end
1409
+
1410
+ def test_mixin_keyword_splat_must_have_string_keys
1411
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1412
+ Variable keyword argument map must have string keys.
1413
+ 12 is not a string in (12: 1).
1414
+ MESSAGE
1415
+ @mixin foo($a) {
1416
+ a: $a;
1417
+ }
1418
+
1419
+ .foo {@include foo((12: 1)...)}
1420
+ SCSS
1421
+ end
1422
+
1423
+ def test_mixin_positional_arg_after_splat
1424
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1425
+ Only keyword arguments may follow variable arguments (...).
1426
+ MESSAGE
1427
+ @mixin foo($a, $b, $c) {
1428
+ a: 1;
1429
+ b: 2;
1430
+ c: 3;
1431
+ }
1432
+
1433
+ .foo {
1434
+ @include foo(1, 2..., 3);
1435
+ }
1436
+ SCSS
1437
+ end
1438
+
1439
+ def test_mixin_var_args_with_keyword
1440
+ assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1441
+ @mixin foo($a, $b...) {
1442
+ a: $a;
1443
+ b: $b;
1444
+ }
1445
+
1446
+ .foo {@include foo($a: 1, 2, 3, 4)}
1447
+ SCSS
1448
+ end
1449
+
1450
+ def test_mixin_keyword_for_var_arg
1451
+ assert_raise_message(Sass::SyntaxError, "Argument $b of mixin foo cannot be used as a named argument.") {render <<SCSS}
1452
+ @mixin foo($a, $b...) {
1453
+ a: $a;
1454
+ b: $b;
1455
+ }
1456
+
1457
+ .foo {@include foo(1, $b: 2 3 4)}
1458
+ SCSS
1459
+ end
1460
+
1461
+ def test_mixin_keyword_for_unknown_arg_with_var_args
1462
+ assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
1463
+ @mixin foo($a, $b...) {
1464
+ a: $a;
1465
+ b: $b;
1466
+ }
1467
+
1468
+ .foo {@include foo(1, $c: 2 3 4)}
1469
+ SCSS
1470
+ end
1471
+
1472
+ def test_mixin_map_splat_before_list_splat
1473
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render <<SCSS}
1474
+ @mixin foo($a, $b, $c) {
1475
+ a: $a;
1476
+ b: $b;
1477
+ c: $c;
1478
+ }
1479
+
1480
+ .foo {
1481
+ @include foo((a: 1)..., (2 3)...);
1482
+ }
1483
+ SCSS
1484
+ end
1485
+
1486
+ def test_mixin_map_splat_with_unknown_keyword
1487
+ assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
1488
+ @mixin foo($a, $b) {
1489
+ a: $a;
1490
+ b: $b;
1491
+ }
1492
+
1493
+ .foo {
1494
+ @include foo(1, 2, (c: 1)...);
1495
+ }
1496
+ SCSS
1497
+ end
1498
+
1499
+ def test_mixin_map_splat_with_wrong_type
1500
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render <<SCSS}
1501
+ @mixin foo($a, $b) {
1502
+ a: $a;
1503
+ b: $b;
1504
+ }
1505
+
1506
+ .foo {
1507
+ @include foo((1, 2)..., 12...);
1508
+ }
1509
+ SCSS
1510
+ end
1511
+
1512
+ def test_function_var_args
1513
+ assert_equal <<CSS, render(<<SCSS)
1514
+ .foo {
1515
+ val: "a: 1, b: 2, 3, 4"; }
1516
+ CSS
1517
+ @function foo($a, $b...) {
1518
+ @return "a: \#{$a}, b: \#{$b}";
1519
+ }
1520
+
1521
+ .foo {val: foo(1, 2, 3, 4)}
1522
+ SCSS
1523
+ end
1524
+
1525
+ def test_function_empty_var_args
1526
+ assert_equal <<CSS, render(<<SCSS)
1527
+ .foo {
1528
+ val: "a: 1, b: 0"; }
1529
+ CSS
1530
+ @function foo($a, $b...) {
1531
+ @return "a: \#{$a}, b: \#{length($b)}";
1532
+ }
1533
+
1534
+ .foo {val: foo(1)}
1535
+ SCSS
1536
+ end
1537
+
1538
+ def test_function_var_args_act_like_list
1539
+ assert_equal <<CSS, render(<<SCSS)
1540
+ .foo {
1541
+ val: "a: 3, b: 3"; }
1542
+ CSS
1543
+ @function foo($a, $b...) {
1544
+ @return "a: \#{length($b)}, b: \#{nth($b, 2)}";
1545
+ }
1546
+
1547
+ .foo {val: foo(1, 2, 3, 4)}
1548
+ SCSS
1549
+ end
1550
+
1551
+ def test_function_splat_args
1552
+ assert_equal <<CSS, render(<<SCSS)
1553
+ .foo {
1554
+ val: "a: 1, b: 2, c: 3, d: 4"; }
1555
+ CSS
1556
+ @function foo($a, $b, $c, $d) {
1557
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
1558
+ }
1559
+
1560
+ $list: 2, 3, 4;
1561
+ .foo {val: foo(1, $list...)}
1562
+ SCSS
1563
+ end
1564
+
1565
+ def test_function_splat_expression
1566
+ assert_equal <<CSS, render(<<SCSS)
1567
+ .foo {
1568
+ val: "a: 1, b: 2, c: 3, d: 4"; }
1569
+ CSS
1570
+ @function foo($a, $b, $c, $d) {
1571
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
1572
+ }
1573
+
1574
+ .foo {val: foo(1, (2, 3, 4)...)}
1575
+ SCSS
1576
+ end
1577
+
1578
+ def test_function_splat_args_with_var_args
1579
+ assert_equal <<CSS, render(<<SCSS)
1580
+ .foo {
1581
+ val: "a: 1, b: 2, 3, 4"; }
1582
+ CSS
1583
+ @function foo($a, $b...) {
1584
+ @return "a: \#{$a}, b: \#{$b}";
1585
+ }
1586
+
1587
+ $list: 2, 3, 4;
1588
+ .foo {val: foo(1, $list...)}
1589
+ SCSS
1590
+ end
1591
+
1592
+ def test_function_splat_args_with_var_args_and_normal_args
1593
+ assert_equal <<CSS, render(<<SCSS)
1594
+ .foo {
1595
+ val: "a: 1, b: 2, c: 3, 4"; }
1596
+ CSS
1597
+ @function foo($a, $b, $c...) {
1598
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1599
+ }
1600
+
1601
+ $list: 2, 3, 4;
1602
+ .foo {val: foo(1, $list...)}
1603
+ SCSS
1604
+ end
1605
+
1606
+ def test_function_splat_args_with_var_args_preserves_separator
1607
+ assert_equal <<CSS, render(<<SCSS)
1608
+ .foo {
1609
+ val: "a: 1, b: 2 3 4 5"; }
1610
+ CSS
1611
+ @function foo($a, $b...) {
1612
+ @return "a: \#{$a}, b: \#{$b}";
1613
+ }
1614
+
1615
+ $list: 3 4 5;
1616
+ .foo {val: foo(1, 2, $list...)}
1617
+ SCSS
1618
+ end
1619
+
1620
+ def test_function_var_and_splat_args_pass_through_keywords
1621
+ assert_equal <<CSS, render(<<SCSS)
1622
+ .foo {
1623
+ val: "a: 3, b: 1, c: 2"; }
1624
+ CSS
1625
+ @function foo($a...) {
1626
+ @return bar($a...);
1627
+ }
1628
+
1629
+ @function bar($b, $c, $a) {
1630
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1631
+ }
1632
+
1633
+ .foo {val: foo(1, $c: 2, $a: 3)}
1634
+ SCSS
1635
+ end
1636
+
1637
+ def test_function_var_keyword_args
1638
+ assert_equal <<CSS, render(<<SCSS)
1639
+ .foo {
1640
+ val: "a: 1, b: 2, c: 3"; }
1641
+ CSS
1642
+ @function foo($args...) {
1643
+ @return "a: \#{map-get(keywords($args), a)}, " +
1644
+ "b: \#{map-get(keywords($args), b)}, " +
1645
+ "c: \#{map-get(keywords($args), c)}";
1646
+ }
1647
+
1648
+ .foo {val: foo($a: 1, $b: 2, $c: 3)}
1649
+ SCSS
1650
+ end
1651
+
1652
+ def test_function_empty_var_keyword_args
1653
+ assert_equal <<CSS, render(<<SCSS)
1654
+ .foo {
1655
+ length: 0; }
1656
+ CSS
1657
+ @function foo($args...) {
1658
+ @return length(keywords($args));
1659
+ }
1660
+
1661
+ .foo {length: foo()}
1662
+ SCSS
1663
+ end
1664
+
1665
+ def test_function_map_splat
1666
+ assert_equal <<CSS, render(<<SCSS)
1667
+ .foo {
1668
+ val: "a: 1, b: 2, c: 3"; }
1669
+ CSS
1670
+ @function foo($a, $b, $c) {
1671
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1672
+ }
1673
+
1674
+ .foo {
1675
+ $map: (a: 1, b: 2, c: 3);
1676
+ val: foo($map...);
1677
+ }
1678
+ SCSS
1679
+ end
1680
+
1681
+ def test_function_map_and_list_splat
1682
+ assert_equal <<CSS, render(<<SCSS)
1683
+ .foo {
1684
+ val: "a: x, b: y, c: z, d: 1, e: 2, f: 3"; }
1685
+ CSS
1686
+ @function foo($a, $b, $c, $d, $e, $f) {
1687
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}, e: \#{$e}, f: \#{$f}";
1688
+ }
1689
+
1690
+ .foo {
1691
+ $list: x y z;
1692
+ $map: (d: 1, e: 2, f: 3);
1693
+ val: foo($list..., $map...);
1694
+ }
1695
+ SCSS
1696
+ end
1697
+
1698
+ def test_function_map_splat_takes_precedence_over_pass_through
1699
+ assert_equal <<CSS, render(<<SCSS)
1700
+ .foo {
1701
+ val: "a: 1, b: 2, c: z"; }
1702
+ CSS
1703
+ @function foo($args...) {
1704
+ $map: (c: z);
1705
+ @return bar($args..., $map...);
1706
+ }
1707
+
1708
+ @function bar($a, $b, $c) {
1709
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1710
+ }
1711
+
1712
+ .foo {
1713
+ val: foo(1, $b: 2, $c: 3);
1714
+ }
1715
+ SCSS
1716
+ end
1717
+
1718
+ def test_ruby_function_map_splat_takes_precedence_over_pass_through
1719
+ assert_equal <<CSS, render(<<SCSS)
1720
+ .foo {
1721
+ val: 1 2 3 z; }
1722
+ CSS
1723
+ @function foo($args...) {
1724
+ $map: (val: z);
1725
+ @return append($args..., $map...);
1726
+ }
1727
+
1728
+ .foo {
1729
+ val: foo(1 2 3, $val: 4)
1730
+ }
1731
+ SCSS
1732
+ end
1733
+
1734
+ def test_function_list_of_pairs_splat_treated_as_list
1735
+ assert_equal <<CSS, render(<<SCSS)
1736
+ .foo {
1737
+ val: "a: a 1, b: b 2, c: c 3"; }
1738
+ CSS
1739
+ @function foo($a, $b, $c) {
1740
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1741
+ }
1742
+
1743
+ .foo {
1744
+ val: foo((a 1, b 2, c 3)...);
1745
+ }
1746
+ SCSS
1747
+ end
1748
+
1749
+ def test_function_splat_after_keyword_args
1750
+ assert_equal <<CSS, render(<<SCSS)
1751
+ .foo {
1752
+ val: "a: 1, b: 2, c: 3"; }
1753
+ CSS
1754
+ @function foo($a, $b, $c) {
1755
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1756
+ }
1757
+
1758
+ .foo {
1759
+ val: foo(1, $c: 3, 2...);
1760
+ }
1761
+ SCSS
1762
+ end
1763
+
1764
+ def test_function_keyword_args_after_splat
1765
+ assert_equal <<CSS, render(<<SCSS)
1766
+ .foo {
1767
+ val: "a: 1, b: 2, c: 3"; }
1768
+ CSS
1769
+ @function foo($a, $b, $c) {
1770
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1771
+ }
1772
+
1773
+ .foo {
1774
+ val: foo(1, 2..., $c: 3);
1775
+ }
1776
+ SCSS
1777
+ end
1778
+
1779
+ def test_function_keyword_splat_after_keyword_args
1780
+ assert_equal <<CSS, render(<<SCSS)
1781
+ .foo {
1782
+ val: "a: 1, b: 2, c: 3"; }
1783
+ CSS
1784
+ @function foo($a, $b, $c) {
1785
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1786
+ }
1787
+
1788
+ .foo {
1789
+ val: foo(1, $b: 2, (c: 3)...);
1790
+ }
1791
+ SCSS
1792
+ end
1793
+
1794
+ def test_function_triple_keyword_splat_merge
1795
+ assert_equal <<CSS, render(<<SCSS)
1796
+ .foo {
1797
+ val: "foo: 1, bar: 2, kwarg: 3, a: 3, b: 2, c: 3"; }
1798
+ CSS
1799
+ @function foo($foo, $bar, $kwarg, $a, $b, $c) {
1800
+ @return "foo: \#{$foo}, bar: \#{$bar}, kwarg: \#{$kwarg}, a: \#{$a}, b: \#{$b}, c: \#{$c}";
1801
+ }
1802
+
1803
+ @function bar($args...) {
1804
+ @return foo($args..., $bar: 2, $a: 2, $b: 2, (kwarg: 3, a: 3, c: 3)...);
1805
+ }
1806
+
1807
+ .foo {
1808
+ val: bar($foo: 1, $a: 1, $b: 1, $c: 1);
1809
+ }
1810
+ SCSS
1811
+ end
1812
+
1813
+ def test_function_conflicting_splat_after_keyword_args
1814
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1815
+ Function foo was passed argument $b both by position and by name.
1816
+ MESSAGE
1817
+ @function foo($a, $b, $c) {
1818
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1819
+ }
1820
+
1821
+ .foo {
1822
+ val: foo(1, $b: 2, 3...);
1823
+ }
1824
+ SCSS
1825
+ end
1826
+
1827
+ def test_function_positional_arg_after_splat
1828
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
1829
+ Only keyword arguments may follow variable arguments (...).
1830
+ MESSAGE
1831
+ @function foo($a, $b, $c) {
1832
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1833
+ }
1834
+
1835
+ .foo {
1836
+ val: foo(1, 2..., 3);
1837
+ }
1838
+ SCSS
1839
+ end
1840
+
1841
+ def test_function_var_args_with_keyword
1842
+ assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1843
+ @function foo($a, $b...) {
1844
+ @return "a: \#{$a}, b: \#{$b}";
1845
+ }
1846
+
1847
+ .foo {val: foo($a: 1, 2, 3, 4)}
1848
+ SCSS
1849
+ end
1850
+
1851
+ def test_function_keyword_for_var_arg
1852
+ assert_raise_message(Sass::SyntaxError, "Argument $b of function foo cannot be used as a named argument.") {render <<SCSS}
1853
+ @function foo($a, $b...) {
1854
+ @return "a: \#{$a}, b: \#{$b}";
1855
+ }
1856
+
1857
+ .foo {val: foo(1, $b: 2 3 4)}
1858
+ SCSS
1859
+ end
1860
+
1861
+ def test_function_keyword_for_unknown_arg_with_var_args
1862
+ assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1863
+ @function foo($a, $b...) {
1864
+ @return "a: \#{$a}, b: \#{length($b)}";
1865
+ }
1866
+
1867
+ .foo {val: foo(1, $c: 2 3 4)}
1868
+ SCSS
1869
+ end
1870
+
1871
+ def test_function_var_args_passed_to_native
1872
+ assert_equal <<CSS, render(<<SCSS)
1873
+ .foo {
1874
+ val: #102035; }
1875
+ CSS
1876
+ @function foo($args...) {
1877
+ @return adjust-color($args...);
1878
+ }
1879
+
1880
+ .foo {val: foo(#102030, $blue: 5)}
1881
+ SCSS
1882
+ end
1883
+
1884
+ def test_function_map_splat_before_list_splat
1885
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was (2 3)).") {render <<SCSS}
1886
+ @function foo($a, $b, $c) {
1887
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1888
+ }
1889
+
1890
+ .foo {
1891
+ val: foo((a: 1)..., (2 3)...);
1892
+ }
1893
+ SCSS
1894
+ end
1895
+
1896
+ def test_function_map_splat_with_unknown_keyword
1897
+ assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1898
+ @function foo($a, $b) {
1899
+ @return "a: \#{$a}, b: \#{$b}";
1900
+ }
1901
+
1902
+ .foo {
1903
+ val: foo(1, 2, (c: 1)...);
1904
+ }
1905
+ SCSS
1906
+ end
1907
+
1908
+ def test_function_map_splat_with_wrong_type
1909
+ assert_raise_message(Sass::SyntaxError, "Variable keyword arguments must be a map (was 12).") {render <<SCSS}
1910
+ @function foo($a, $b) {
1911
+ @return "a: \#{$a}, b: \#{$b}";
1912
+ }
1913
+
1914
+ .foo {
1915
+ val: foo((1, 2)..., 12...);
1916
+ }
1917
+ SCSS
1918
+ end
1919
+
1920
+ def test_function_keyword_splat_must_have_string_keys
1921
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1922
+ Variable keyword argument map must have string keys.
1923
+ 12 is not a string in (12: 1).
1924
+ MESSAGE
1925
+ @function foo($a) {
1926
+ @return $a;
1927
+ }
1928
+
1929
+ .foo {val: foo((12: 1)...)}
1930
+ SCSS
1931
+ end
1932
+
1933
+ ## Interpolation
1934
+
1935
+ def test_basic_selector_interpolation
1936
+ assert_equal <<CSS, render(<<SCSS)
1937
+ foo ab baz {
1938
+ a: b; }
1939
+ CSS
1940
+ foo \#{'a' + 'b'} baz {a: b}
1941
+ SCSS
1942
+ assert_equal <<CSS, render(<<SCSS)
1943
+ foo.bar baz {
1944
+ a: b; }
1945
+ CSS
1946
+ foo\#{".bar"} baz {a: b}
1947
+ SCSS
1948
+ assert_equal <<CSS, render(<<SCSS)
1949
+ foo.bar baz {
1950
+ a: b; }
1951
+ CSS
1952
+ \#{"foo"}.bar baz {a: b}
1953
+ SCSS
1954
+ end
1955
+
1956
+ def test_selector_only_interpolation
1957
+ assert_equal <<CSS, render(<<SCSS)
1958
+ foo bar {
1959
+ a: b; }
1960
+ CSS
1961
+ \#{"foo" + " bar"} {a: b}
1962
+ SCSS
1963
+ end
1964
+
1965
+ def test_selector_interpolation_before_element_name
1966
+ assert_equal <<CSS, render(<<SCSS)
1967
+ foo barbaz {
1968
+ a: b; }
1969
+ CSS
1970
+ \#{"foo" + " bar"}baz {a: b}
1971
+ SCSS
1972
+ end
1973
+
1974
+ def test_selector_interpolation_in_string
1975
+ assert_equal <<CSS, render(<<SCSS)
1976
+ foo[val="bar foo bar baz"] {
1977
+ a: b; }
1978
+ CSS
1979
+ foo[val="bar \#{"foo" + " bar"} baz"] {a: b}
1980
+ SCSS
1981
+ end
1982
+
1983
+ def test_selector_interpolation_in_pseudoclass
1984
+ assert_equal <<CSS, render(<<SCSS)
1985
+ foo:nth-child(5n) {
1986
+ a: b; }
1987
+ CSS
1988
+ foo:nth-child(\#{5 + "n"}) {a: b}
1989
+ SCSS
1990
+ end
1991
+
1992
+ def test_selector_interpolation_at_class_begininng
1993
+ assert_equal <<CSS, render(<<SCSS)
1994
+ .zzz {
1995
+ a: b; }
1996
+ CSS
1997
+ $zzz: zzz;
1998
+ .\#{$zzz} { a: b; }
1999
+ SCSS
2000
+ end
2001
+
2002
+ def test_selector_interpolation_at_id_begininng
2003
+ assert_equal <<CSS, render(<<SCSS)
2004
+ #zzz {
2005
+ a: b; }
2006
+ CSS
2007
+ $zzz: zzz;
2008
+ #\#{$zzz} { a: b; }
2009
+ SCSS
2010
+ end
2011
+
2012
+ def test_selector_interpolation_at_pseudo_begininng
2013
+ assert_equal <<CSS, render(<<SCSS)
2014
+ :zzz::zzz {
2015
+ a: b; }
2016
+ CSS
2017
+ $zzz: zzz;
2018
+ :\#{$zzz}::\#{$zzz} { a: b; }
2019
+ SCSS
2020
+ end
2021
+
2022
+ def test_selector_interpolation_at_attr_beginning
2023
+ assert_equal <<CSS, render(<<SCSS)
2024
+ [zzz=foo] {
2025
+ a: b; }
2026
+ CSS
2027
+ $zzz: zzz;
2028
+ [\#{$zzz}=foo] { a: b; }
2029
+ SCSS
2030
+ end
2031
+
2032
+ def test_selector_interpolation_at_attr_end
2033
+ assert_equal <<CSS, render(<<SCSS)
2034
+ [foo=zzz] {
2035
+ a: b; }
2036
+ CSS
2037
+ $zzz: zzz;
2038
+ [foo=\#{$zzz}] { a: b; }
2039
+ SCSS
2040
+ end
2041
+
2042
+ def test_selector_interpolation_at_dashes
2043
+ assert_equal <<CSS, render(<<SCSS)
2044
+ div {
2045
+ -foo-a-b-foo: foo; }
2046
+ CSS
2047
+ $a : a;
2048
+ $b : b;
2049
+ div { -foo-\#{$a}-\#{$b}-foo: foo }
2050
+ SCSS
2051
+ end
2052
+
2053
+ def test_selector_interpolation_in_reference_combinator
2054
+ assert_equal <<CSS, render(<<SCSS)
2055
+ .foo /a/ .bar /b|c/ .baz {
2056
+ a: b; }
2057
+ CSS
2058
+ $a: a;
2059
+ $b: b;
2060
+ $c: c;
2061
+ .foo /\#{$a}/ .bar /\#{$b}|\#{$c}/ .baz {a: b}
2062
+ SCSS
2063
+ end
2064
+
2065
+ def test_parent_selector_with_parent_and_subject
2066
+ silence_warnings {assert_equal <<CSS, render(<<SCSS)}
2067
+ bar foo.baz! .bip {
2068
+ c: d; }
2069
+ CSS
2070
+ $subject: "!";
2071
+ foo {
2072
+ bar &.baz\#{$subject} .bip {c: d}}
2073
+ SCSS
2074
+ end
2075
+
2076
+ def test_basic_prop_name_interpolation
2077
+ assert_equal <<CSS, render(<<SCSS)
2078
+ foo {
2079
+ barbazbang: blip; }
2080
+ CSS
2081
+ foo {bar\#{"baz" + "bang"}: blip}
2082
+ SCSS
2083
+ assert_equal <<CSS, render(<<SCSS)
2084
+ foo {
2085
+ bar3: blip; }
2086
+ CSS
2087
+ foo {bar\#{1 + 2}: blip}
2088
+ SCSS
2089
+ end
2090
+
2091
+ def test_prop_name_only_interpolation
2092
+ assert_equal <<CSS, render(<<SCSS)
2093
+ foo {
2094
+ bazbang: blip; }
2095
+ CSS
2096
+ foo {\#{"baz" + "bang"}: blip}
2097
+ SCSS
2098
+ end
2099
+
2100
+ def test_directive_interpolation
2101
+ assert_equal <<CSS, render(<<SCSS)
2102
+ @foo bar12 qux {
2103
+ a: b; }
2104
+ CSS
2105
+ $baz: 12;
2106
+ @foo bar\#{$baz} qux {a: b}
2107
+ SCSS
2108
+ end
2109
+
2110
+ def test_media_interpolation
2111
+ assert_equal <<CSS, render(<<SCSS)
2112
+ @media bar12 {
2113
+ a: b; }
2114
+ CSS
2115
+ $baz: 12;
2116
+ @media bar\#{$baz} {a: b}
2117
+ SCSS
2118
+ end
2119
+
2120
+ def test_script_in_media
2121
+ assert_equal <<CSS, render(<<SCSS)
2122
+ @media screen and (-webkit-min-device-pixel-ratio: 20), only print {
2123
+ a: b; }
2124
+ CSS
2125
+ $media1: screen;
2126
+ $media2: print;
2127
+ $var: -webkit-min-device-pixel-ratio;
2128
+ $val: 20;
2129
+ @media \#{$media1} and ($var: $val), only \#{$media2} {a: b}
2130
+ SCSS
2131
+
2132
+ assert_equal <<CSS, render(<<SCSS)
2133
+ @media screen and (-webkit-min-device-pixel-ratio: 13) {
2134
+ a: b; }
2135
+ CSS
2136
+ $vals: 1 2 3;
2137
+ @media screen and (-webkit-min-device-pixel-ratio: 5 + 6 + nth($vals, 2)) {a: b}
2138
+ SCSS
2139
+ end
2140
+
2141
+ def test_media_interpolation_with_reparse
2142
+ assert_equal <<CSS, render(<<SCSS)
2143
+ @media screen and (max-width: 300px) {
2144
+ a: b; }
2145
+ @media screen and (max-width: 300px) {
2146
+ a: b; }
2147
+ @media screen and (max-width: 300px) {
2148
+ a: b; }
2149
+ @media screen and (max-width: 300px), print and (max-width: 300px) {
2150
+ a: b; }
2151
+ CSS
2152
+ $constraint: "(max-width: 300px)";
2153
+ $fragment: "nd \#{$constraint}";
2154
+ $comma: "een, pri";
2155
+ @media screen and \#{$constraint} {a: b}
2156
+ @media screen {
2157
+ @media \#{$constraint} {a: b}
2158
+ }
2159
+ @media screen a\#{$fragment} {a: b}
2160
+ @media scr\#{$comma}nt {
2161
+ @media \#{$constraint} {a: b}
2162
+ }
2163
+ SCSS
2164
+ end
2165
+
2166
+ def test_moz_document_interpolation
2167
+ assert_equal <<CSS, render(<<SCSS)
2168
+ @-moz-document url(http://sass-lang.com/),
2169
+ url-prefix(http://sass-lang.com/docs),
2170
+ domain(sass-lang.com),
2171
+ domain("sass-lang.com") {
2172
+ .foo {
2173
+ a: b; } }
2174
+ CSS
2175
+ $domain: "sass-lang.com";
2176
+ @-moz-document url(http://\#{$domain}/),
2177
+ url-prefix(http://\#{$domain}/docs),
2178
+ domain(\#{$domain}),
2179
+ \#{domain($domain)} {
2180
+ .foo {a: b}
2181
+ }
2182
+ SCSS
2183
+ end
2184
+
2185
+ def test_supports_with_expressions
2186
+ assert_equal <<CSS, render(<<SCSS)
2187
+ @supports (feature1: val) and (feature2: val) or (not (feature23: val4)) {
2188
+ foo {
2189
+ a: b; } }
2190
+ CSS
2191
+ $query: "(feature1: val)";
2192
+ $feature: feature2;
2193
+ $val: val;
2194
+ @supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4)) {
2195
+ foo {a: b}
2196
+ }
2197
+ SCSS
2198
+ end
2199
+
2200
+ def test_supports_bubbling
2201
+ assert_equal <<CSS, render(<<SCSS)
2202
+ @supports (foo: bar) {
2203
+ a {
2204
+ b: c; }
2205
+ @supports (baz: bang) {
2206
+ a {
2207
+ d: e; } } }
2208
+ CSS
2209
+ a {
2210
+ @supports (foo: bar) {
2211
+ b: c;
2212
+ @supports (baz: bang) {
2213
+ d: e;
2214
+ }
2215
+ }
2216
+ }
2217
+ SCSS
2218
+ end
2219
+
2220
+ def test_random_directive_interpolation
2221
+ assert_equal <<CSS, render(<<SCSS)
2222
+ @foo url(http://sass-lang.com/),
2223
+ domain("sass-lang.com"),
2224
+ "foobarbaz",
2225
+ foobarbaz {
2226
+ .foo {
2227
+ a: b; } }
2228
+ CSS
2229
+ $domain: "sass-lang.com";
2230
+ @foo url(http://\#{$domain}/),
2231
+ \#{domain($domain)},
2232
+ "foo\#{'ba' + 'r'}baz",
2233
+ foo\#{'ba' + 'r'}baz {
2234
+ .foo {a: b}
2235
+ }
2236
+ SCSS
2237
+ end
2238
+
2239
+ def test_color_interpolation_warning_in_selector
2240
+ assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
2241
+ WARNING on line 1, column 4 of #{filename_for_test(:scss)}:
2242
+ You probably don't mean to use the color value `blue' in interpolation here.
2243
+ It may end up represented as #0000ff, which will likely produce invalid CSS.
2244
+ Always quote color names when using them as strings (for example, "blue").
2245
+ If you really want to use the color value here, use `"" + blue'.
2246
+ WARNING
2247
+ fooblue {
2248
+ a: b; }
2249
+ CSS
2250
+ foo\#{blue} {a: b}
2251
+ SCSS
2252
+ end
2253
+
2254
+ def test_color_interpolation_warning_in_directive
2255
+ assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
2256
+ WARNING on line 1, column 12 of #{filename_for_test(:scss)}:
2257
+ You probably don't mean to use the color value `blue' in interpolation here.
2258
+ It may end up represented as #0000ff, which will likely produce invalid CSS.
2259
+ Always quote color names when using them as strings (for example, "blue").
2260
+ If you really want to use the color value here, use `"" + blue'.
2261
+ WARNING
2262
+ @fblthp fooblue {
2263
+ a: b; }
2264
+ CSS
2265
+ @fblthp foo\#{blue} {a: b}
2266
+ SCSS
2267
+ end
2268
+
2269
+ def test_color_interpolation_warning_in_property_name
2270
+ assert_warning(<<WARNING) {assert_equal <<CSS, render(<<SCSS)}
2271
+ WARNING on line 1, column 8 of #{filename_for_test(:scss)}:
2272
+ You probably don't mean to use the color value `blue' in interpolation here.
2273
+ It may end up represented as #0000ff, which will likely produce invalid CSS.
2274
+ Always quote color names when using them as strings (for example, "blue").
2275
+ If you really want to use the color value here, use `"" + blue'.
2276
+ WARNING
2277
+ foo {
2278
+ a-blue: b; }
2279
+ CSS
2280
+ foo {a-\#{blue}: b}
2281
+ SCSS
2282
+ end
2283
+
2284
+ def test_no_color_interpolation_warning_in_property_value
2285
+ assert_no_warning {assert_equal <<CSS, render(<<SCSS)}
2286
+ foo {
2287
+ a: b-blue; }
2288
+ CSS
2289
+ foo {a: b-\#{blue}}
2290
+ SCSS
2291
+ end
2292
+
2293
+ def test_no_color_interpolation_warning_for_nameless_color
2294
+ assert_no_warning {assert_equal <<CSS, render(<<SCSS)}
2295
+ foo-#abcdef {
2296
+ a: b; }
2297
+ CSS
2298
+ foo-\#{#abcdef} {a: b}
2299
+ SCSS
2300
+ end
2301
+
2302
+ def test_nested_mixin_def
2303
+ assert_equal <<CSS, render(<<SCSS)
2304
+ foo {
2305
+ a: b; }
2306
+ CSS
2307
+ foo {
2308
+ @mixin bar {a: b}
2309
+ @include bar; }
2310
+ SCSS
2311
+ end
2312
+
2313
+ def test_nested_mixin_shadow
2314
+ assert_equal <<CSS, render(<<SCSS)
2315
+ foo {
2316
+ c: d; }
2317
+
2318
+ baz {
2319
+ a: b; }
2320
+ CSS
2321
+ @mixin bar {a: b}
2322
+
2323
+ foo {
2324
+ @mixin bar {c: d}
2325
+ @include bar;
2326
+ }
2327
+
2328
+ baz {@include bar}
2329
+ SCSS
2330
+ end
2331
+
2332
+ def test_nested_function_def
2333
+ assert_equal <<CSS, render(<<SCSS)
2334
+ foo {
2335
+ a: 1; }
2336
+
2337
+ bar {
2338
+ b: foo(); }
2339
+ CSS
2340
+ foo {
2341
+ @function foo() {@return 1}
2342
+ a: foo(); }
2343
+
2344
+ bar {b: foo()}
2345
+ SCSS
2346
+ end
2347
+
2348
+ def test_nested_function_shadow
2349
+ assert_equal <<CSS, render(<<SCSS)
2350
+ foo {
2351
+ a: 2; }
2352
+
2353
+ baz {
2354
+ b: 1; }
2355
+ CSS
2356
+ @function foo() {@return 1}
2357
+
2358
+ foo {
2359
+ @function foo() {@return 2}
2360
+ a: foo();
2361
+ }
2362
+
2363
+ baz {b: foo()}
2364
+ SCSS
2365
+ end
2366
+
2367
+ ## @at-root
2368
+
2369
+ def test_simple_at_root
2370
+ assert_equal <<CSS, render(<<SCSS)
2371
+ .bar {
2372
+ a: b; }
2373
+ CSS
2374
+ .foo {
2375
+ @at-root {
2376
+ .bar {a: b}
2377
+ }
2378
+ }
2379
+ SCSS
2380
+ end
2381
+
2382
+ def test_at_root_with_selector
2383
+ assert_equal <<CSS, render(<<SCSS)
2384
+ .bar {
2385
+ a: b; }
2386
+ CSS
2387
+ .foo {
2388
+ @at-root .bar {a: b}
2389
+ }
2390
+ SCSS
2391
+ end
2392
+
2393
+ def test_at_root_in_mixin
2394
+ assert_equal <<CSS, render(<<SCSS)
2395
+ .bar {
2396
+ a: b; }
2397
+ CSS
2398
+ @mixin bar {
2399
+ @at-root .bar {a: b}
2400
+ }
2401
+
2402
+ .foo {
2403
+ @include bar;
2404
+ }
2405
+ SCSS
2406
+ end
2407
+
2408
+ def test_at_root_in_media
2409
+ assert_equal <<CSS, render(<<SCSS)
2410
+ @media screen {
2411
+ .bar {
2412
+ a: b; } }
2413
+ CSS
2414
+ @media screen {
2415
+ .foo {
2416
+ @at-root .bar {a: b}
2417
+ }
2418
+ }
2419
+ SCSS
2420
+ end
2421
+
2422
+ def test_at_root_in_bubbled_media
2423
+ assert_equal <<CSS, render(<<SCSS)
2424
+ @media screen {
2425
+ .bar {
2426
+ a: b; } }
2427
+ CSS
2428
+ .foo {
2429
+ @media screen {
2430
+ @at-root .bar {a: b}
2431
+ }
2432
+ }
2433
+ SCSS
2434
+ end
2435
+
2436
+ def test_at_root_in_unknown_directive
2437
+ assert_equal <<CSS, render(<<SCSS)
2438
+ @fblthp {
2439
+ .bar {
2440
+ a: b; } }
2441
+ CSS
2442
+ @fblthp {
2443
+ .foo {
2444
+ @at-root .bar {a: b}
2445
+ }
2446
+ }
2447
+ SCSS
2448
+ end
2449
+
2450
+ def test_comments_in_at_root
2451
+ assert_equal <<CSS, render(<<SCSS)
2452
+ /* foo */
2453
+ .bar {
2454
+ a: b; }
2455
+
2456
+ /* baz */
2457
+ CSS
2458
+ .foo {
2459
+ @at-root {
2460
+ /* foo */
2461
+ .bar {a: b}
2462
+ /* baz */
2463
+ }
2464
+ }
2465
+ SCSS
2466
+ end
2467
+
2468
+ def test_comments_in_at_root_in_media
2469
+ assert_equal <<CSS, render(<<SCSS)
2470
+ @media screen {
2471
+ /* foo */
2472
+ .bar {
2473
+ a: b; }
2474
+
2475
+ /* baz */ }
2476
+ CSS
2477
+ @media screen {
2478
+ .foo {
2479
+ @at-root {
2480
+ /* foo */
2481
+ .bar {a: b}
2482
+ /* baz */
2483
+ }
2484
+ }
2485
+ }
2486
+ SCSS
2487
+ end
2488
+
2489
+ def test_comments_in_at_root_in_unknown_directive
2490
+ assert_equal <<CSS, render(<<SCSS)
2491
+ @fblthp {
2492
+ /* foo */
2493
+ .bar {
2494
+ a: b; }
2495
+
2496
+ /* baz */ }
2497
+ CSS
2498
+ @fblthp {
2499
+ .foo {
2500
+ @at-root {
2501
+ /* foo */
2502
+ .bar {a: b}
2503
+ /* baz */
2504
+ }
2505
+ }
2506
+ }
2507
+ SCSS
2508
+ end
2509
+
2510
+ def test_media_directive_in_at_root
2511
+ assert_equal <<CSS, render(<<SCSS)
2512
+ @media screen {
2513
+ .bar {
2514
+ a: b; } }
2515
+ CSS
2516
+ .foo {
2517
+ @at-root {
2518
+ @media screen {.bar {a: b}}
2519
+ }
2520
+ }
2521
+ SCSS
2522
+ end
2523
+
2524
+ def test_bubbled_media_directive_in_at_root
2525
+ assert_equal <<CSS, render(<<SCSS)
2526
+ @media screen {
2527
+ .bar .baz {
2528
+ a: b; } }
2529
+ CSS
2530
+ .foo {
2531
+ @at-root {
2532
+ .bar {
2533
+ @media screen {.baz {a: b}}
2534
+ }
2535
+ }
2536
+ }
2537
+ SCSS
2538
+ end
2539
+
2540
+ def test_unknown_directive_in_at_root
2541
+ assert_equal <<CSS, render(<<SCSS)
2542
+ @fblthp {
2543
+ .bar {
2544
+ a: b; } }
2545
+ CSS
2546
+ .foo {
2547
+ @at-root {
2548
+ @fblthp {.bar {a: b}}
2549
+ }
2550
+ }
2551
+ SCSS
2552
+ end
2553
+
2554
+ def test_at_root_in_at_root
2555
+ assert_equal <<CSS, render(<<SCSS)
2556
+ .bar {
2557
+ a: b; }
2558
+ CSS
2559
+ .foo {
2560
+ @at-root {
2561
+ @at-root .bar {a: b}
2562
+ }
2563
+ }
2564
+ SCSS
2565
+ end
2566
+
2567
+ def test_at_root_with_parent_ref
2568
+ assert_equal <<CSS, render(<<SCSS)
2569
+ .foo {
2570
+ a: b; }
2571
+ CSS
2572
+ .foo {
2573
+ @at-root & {
2574
+ a: b;
2575
+ }
2576
+ }
2577
+ SCSS
2578
+ end
2579
+
2580
+ def test_multi_level_at_root_with_parent_ref
2581
+ assert_equal <<CSS, render(<<SCSS)
2582
+ .foo .bar {
2583
+ a: b; }
2584
+ CSS
2585
+ .foo {
2586
+ @at-root & {
2587
+ .bar {
2588
+ @at-root & {
2589
+ a: b;
2590
+ }
2591
+ }
2592
+ }
2593
+ }
2594
+ SCSS
2595
+ end
2596
+
2597
+ def test_multi_level_at_root_with_inner_parent_ref
2598
+ assert_equal <<CSS, render(<<SCSS)
2599
+ .bar {
2600
+ a: b; }
2601
+ CSS
2602
+ .foo {
2603
+ @at-root .bar {
2604
+ @at-root & {
2605
+ a: b;
2606
+ }
2607
+ }
2608
+ }
2609
+ SCSS
2610
+ end
2611
+
2612
+ def test_at_root_beneath_comma_selector
2613
+ assert_equal(<<CSS, render(<<SCSS))
2614
+ .baz {
2615
+ a: b; }
2616
+ CSS
2617
+ .foo, .bar {
2618
+ @at-root .baz {
2619
+ a: b;
2620
+ }
2621
+ }
2622
+ SCSS
2623
+ end
2624
+
2625
+ def test_at_root_with_parent_ref_and_class
2626
+ assert_equal(<<CSS, render(<<SCSS))
2627
+ .foo.bar {
2628
+ a: b; }
2629
+ CSS
2630
+ .foo {
2631
+ @at-root &.bar {
2632
+ a: b;
2633
+ }
2634
+ }
2635
+ SCSS
2636
+ end
2637
+
2638
+ def test_at_root_beneath_comma_selector_with_parent_ref
2639
+ assert_equal(<<CSS, render(<<SCSS))
2640
+ .foo.baz, .bar.baz {
2641
+ a: b; }
2642
+ CSS
2643
+ .foo, .bar {
2644
+ @at-root &.baz {
2645
+ a: b;
2646
+ }
2647
+ }
2648
+ SCSS
2649
+ end
2650
+
2651
+ ## @at-root (...)
2652
+
2653
+ def test_at_root_without_media
2654
+ assert_equal <<CSS, render(<<SCSS)
2655
+ .foo .bar {
2656
+ a: b; }
2657
+ CSS
2658
+ .foo {
2659
+ @media screen {
2660
+ @at-root (without: media) {
2661
+ .bar {
2662
+ a: b;
2663
+ }
2664
+ }
2665
+ }
2666
+ }
2667
+ SCSS
2668
+ end
2669
+
2670
+ def test_at_root_without_supports
2671
+ assert_equal <<CSS, render(<<SCSS)
2672
+ .foo .bar {
2673
+ a: b; }
2674
+ CSS
2675
+ .foo {
2676
+ @supports (foo: bar) {
2677
+ @at-root (without: supports) {
2678
+ .bar {
2679
+ a: b;
2680
+ }
2681
+ }
2682
+ }
2683
+ }
2684
+ SCSS
2685
+ end
2686
+
2687
+ def test_at_root_without_rule
2688
+ assert_equal <<CSS, render(<<SCSS)
2689
+ @media screen {
2690
+ .bar {
2691
+ a: b; } }
2692
+ CSS
2693
+ .foo {
2694
+ @media screen {
2695
+ @at-root (without: rule) {
2696
+ .bar {
2697
+ a: b;
2698
+ }
2699
+ }
2700
+ }
2701
+ }
2702
+ SCSS
2703
+ end
2704
+
2705
+ def test_at_root_without_unknown_directive
2706
+ assert_equal <<CSS, render(<<SCSS)
2707
+ @fblthp {}
2708
+ .foo .bar {
2709
+ a: b; }
2710
+ CSS
2711
+ .foo {
2712
+ @fblthp {
2713
+ @at-root (without: fblthp) {
2714
+ .bar {
2715
+ a: b;
2716
+ }
2717
+ }
2718
+ }
2719
+ }
2720
+ SCSS
2721
+ end
2722
+
2723
+ def test_at_root_without_multiple
2724
+ assert_equal <<CSS, render(<<SCSS)
2725
+ @supports (foo: bar) {
2726
+ .bar {
2727
+ a: b; } }
2728
+ CSS
2729
+ .foo {
2730
+ @media screen {
2731
+ @supports (foo: bar) {
2732
+ @at-root (without: media rule) {
2733
+ .bar {
2734
+ a: b;
2735
+ }
2736
+ }
2737
+ }
2738
+ }
2739
+ }
2740
+ SCSS
2741
+ end
2742
+
2743
+ def test_at_root_without_all
2744
+ assert_equal <<CSS, render(<<SCSS)
2745
+ @supports (foo: bar) {
2746
+ @fblthp {} }
2747
+ .bar {
2748
+ a: b; }
2749
+ CSS
2750
+ .foo {
2751
+ @supports (foo: bar) {
2752
+ @fblthp {
2753
+ @at-root (without: all) {
2754
+ .bar {
2755
+ a: b;
2756
+ }
2757
+ }
2758
+ }
2759
+ }
2760
+ }
2761
+ SCSS
2762
+ end
2763
+
2764
+ def test_at_root_with_media
2765
+ assert_equal <<CSS, render(<<SCSS)
2766
+ @media screen {
2767
+ @fblthp {}
2768
+ .bar {
2769
+ a: b; } }
2770
+ CSS
2771
+ .foo {
2772
+ @media screen {
2773
+ @fblthp {
2774
+ @supports (foo: bar) {
2775
+ @at-root (with: media) {
2776
+ .bar {
2777
+ a: b;
2778
+ }
2779
+ }
2780
+ }
2781
+ }
2782
+ }
2783
+ }
2784
+ SCSS
2785
+ end
2786
+
2787
+ def test_at_root_with_rule
2788
+ assert_equal <<CSS, render(<<SCSS)
2789
+ @media screen {
2790
+ @fblthp {} }
2791
+ .foo .bar {
2792
+ a: b; }
2793
+ CSS
2794
+ .foo {
2795
+ @media screen {
2796
+ @fblthp {
2797
+ @supports (foo: bar) {
2798
+ @at-root (with: rule) {
2799
+ .bar {
2800
+ a: b;
2801
+ }
2802
+ }
2803
+ }
2804
+ }
2805
+ }
2806
+ }
2807
+ SCSS
2808
+ end
2809
+
2810
+ def test_at_root_with_supports
2811
+ assert_equal <<CSS, render(<<SCSS)
2812
+ @media screen {
2813
+ @fblthp {} }
2814
+ @supports (foo: bar) {
2815
+ .bar {
2816
+ a: b; } }
2817
+ CSS
2818
+ .foo {
2819
+ @media screen {
2820
+ @fblthp {
2821
+ @supports (foo: bar) {
2822
+ @at-root (with: supports) {
2823
+ .bar {
2824
+ a: b;
2825
+ }
2826
+ }
2827
+ }
2828
+ }
2829
+ }
2830
+ }
2831
+ SCSS
2832
+ end
2833
+
2834
+ def test_at_root_with_unknown_directive
2835
+ assert_equal <<CSS, render(<<SCSS)
2836
+ @media screen {
2837
+ @fblthp {} }
2838
+ @fblthp {
2839
+ .bar {
2840
+ a: b; } }
2841
+ CSS
2842
+ .foo {
2843
+ @media screen {
2844
+ @fblthp {
2845
+ @supports (foo: bar) {
2846
+ @at-root (with: fblthp) {
2847
+ .bar {
2848
+ a: b;
2849
+ }
2850
+ }
2851
+ }
2852
+ }
2853
+ }
2854
+ }
2855
+ SCSS
2856
+ end
2857
+
2858
+ def test_at_root_with_multiple
2859
+ assert_equal <<CSS, render(<<SCSS)
2860
+ @media screen {
2861
+ @fblthp {}
2862
+ .foo .bar {
2863
+ a: b; } }
2864
+ CSS
2865
+ .foo {
2866
+ @media screen {
2867
+ @fblthp {
2868
+ @supports (foo: bar) {
2869
+ @at-root (with: media rule) {
2870
+ .bar {
2871
+ a: b;
2872
+ }
2873
+ }
2874
+ }
2875
+ }
2876
+ }
2877
+ }
2878
+ SCSS
2879
+ end
2880
+
2881
+ def test_at_root_with_all
2882
+ assert_equal <<CSS, render(<<SCSS)
2883
+ @media screen {
2884
+ @fblthp {
2885
+ @supports (foo: bar) {
2886
+ .foo .bar {
2887
+ a: b; } } } }
2888
+ CSS
2889
+ .foo {
2890
+ @media screen {
2891
+ @fblthp {
2892
+ @supports (foo: bar) {
2893
+ @at-root (with: all) {
2894
+ .bar {
2895
+ a: b;
2896
+ }
2897
+ }
2898
+ }
2899
+ }
2900
+ }
2901
+ }
2902
+ SCSS
2903
+ end
2904
+
2905
+ def test_at_root_dynamic_values
2906
+ assert_equal <<CSS, render(<<SCSS)
2907
+ @media screen {
2908
+ .bar {
2909
+ a: b; } }
2910
+ CSS
2911
+ $key: with;
2912
+ $value: media;
2913
+ .foo {
2914
+ @media screen {
2915
+ @at-root ($key: $value) {
2916
+ .bar {
2917
+ a: b;
2918
+ }
2919
+ }
2920
+ }
2921
+ }
2922
+ SCSS
2923
+ end
2924
+
2925
+ def test_at_root_interpolated_query
2926
+ assert_equal <<CSS, render(<<SCSS)
2927
+ @media screen {
2928
+ .bar {
2929
+ a: b; } }
2930
+ CSS
2931
+ .foo {
2932
+ @media screen {
2933
+ @at-root (\#{"with: media"}) {
2934
+ .bar {
2935
+ a: b;
2936
+ }
2937
+ }
2938
+ }
2939
+ }
2940
+ SCSS
2941
+ end
2942
+
2943
+ def test_at_root_plus_extend
2944
+ assert_equal <<CSS, render(<<SCSS)
2945
+ .foo .bar {
2946
+ a: b; }
2947
+ CSS
2948
+ %base {
2949
+ a: b;
2950
+ }
2951
+
2952
+ .foo {
2953
+ @media screen {
2954
+ @at-root (without: media) {
2955
+ .bar {
2956
+ @extend %base;
2957
+ }
2958
+ }
2959
+ }
2960
+ }
2961
+ SCSS
2962
+ end
2963
+
2964
+ def test_at_root_without_keyframes_in_keyframe_rule
2965
+ assert_equal <<CSS, render(<<SCSS)
2966
+ .foo {
2967
+ a: b; }
2968
+ CSS
2969
+ @keyframes identifier {
2970
+ 0% {
2971
+ @at-root (without: keyframes) {
2972
+ .foo {a: b}
2973
+ }
2974
+ }
2975
+ }
2976
+ SCSS
2977
+ end
2978
+
2979
+ def test_at_root_without_rule_in_keyframe_rule
2980
+ assert_equal <<CSS, render(<<SCSS)
2981
+ @keyframes identifier {
2982
+ 0% {
2983
+ a: b; } }
2984
+ CSS
2985
+ @keyframes identifier {
2986
+ 0% {
2987
+ @at-root (without: rule) {a: b}
2988
+ }
2989
+ }
2990
+ SCSS
2991
+ end
2992
+
2993
+ ## Selector Script
2994
+
2995
+ def test_selector_script
2996
+ assert_equal(<<CSS, render(<<SCSS))
2997
+ .foo .bar {
2998
+ content: ".foo .bar"; }
2999
+ CSS
3000
+ .foo .bar {
3001
+ content: "\#{&}";
3002
+ }
3003
+ SCSS
3004
+ end
3005
+
3006
+ def test_nested_selector_script
3007
+ assert_equal(<<CSS, render(<<SCSS))
3008
+ .foo .bar {
3009
+ content: ".foo .bar"; }
3010
+ CSS
3011
+ .foo {
3012
+ .bar {
3013
+ content: "\#{&}";
3014
+ }
3015
+ }
3016
+ SCSS
3017
+ end
3018
+
3019
+ def test_nested_selector_script_with_outer_comma_selector
3020
+ assert_equal(<<CSS, render(<<SCSS))
3021
+ .foo .baz, .bar .baz {
3022
+ content: ".foo .baz, .bar .baz"; }
3023
+ CSS
3024
+ .foo, .bar {
3025
+ .baz {
3026
+ content: "\#{&}";
3027
+ }
3028
+ }
3029
+ SCSS
3030
+ end
3031
+
3032
+ def test_nested_selector_script_with_inner_comma_selector
3033
+ assert_equal(<<CSS, render(<<SCSS))
3034
+ .foo .bar, .foo .baz {
3035
+ content: ".foo .bar, .foo .baz"; }
3036
+ CSS
3037
+ .foo {
3038
+ .bar, .baz {
3039
+ content: "\#{&}";
3040
+ }
3041
+ }
3042
+ SCSS
3043
+ end
3044
+
3045
+ def test_selector_script_through_mixin
3046
+ assert_equal(<<CSS, render(<<SCSS))
3047
+ .foo {
3048
+ content: ".foo"; }
3049
+ CSS
3050
+ @mixin mixin {
3051
+ content: "\#{&}";
3052
+ }
3053
+
3054
+ .foo {
3055
+ @include mixin;
3056
+ }
3057
+ SCSS
3058
+ end
3059
+
3060
+ def test_selector_script_through_content
3061
+ assert_equal(<<CSS, render(<<SCSS))
3062
+ .foo {
3063
+ content: ".foo"; }
3064
+ CSS
3065
+ @mixin mixin {
3066
+ @content;
3067
+ }
3068
+
3069
+ .foo {
3070
+ @include mixin {
3071
+ content: "\#{&}";
3072
+ }
3073
+ }
3074
+ SCSS
3075
+ end
3076
+
3077
+ def test_selector_script_through_function
3078
+ assert_equal(<<CSS, render(<<SCSS))
3079
+ .foo {
3080
+ content: ".foo"; }
3081
+ CSS
3082
+ @function fn() {
3083
+ @return "\#{&}";
3084
+ }
3085
+
3086
+ .foo {
3087
+ content: fn();
3088
+ }
3089
+ SCSS
3090
+ end
3091
+
3092
+ def test_selector_script_through_media
3093
+ assert_equal(<<CSS, render(<<SCSS))
3094
+ .foo {
3095
+ content: "outer"; }
3096
+ @media screen {
3097
+ .foo .bar {
3098
+ content: ".foo .bar"; } }
3099
+ CSS
3100
+ .foo {
3101
+ content: "outer";
3102
+ @media screen {
3103
+ .bar {
3104
+ content: "\#{&}";
3105
+ }
3106
+ }
3107
+ }
3108
+ SCSS
3109
+ end
3110
+
3111
+ def test_selector_script_save_and_reuse
3112
+ assert_equal(<<CSS, render(<<SCSS))
3113
+ .bar {
3114
+ content: ".foo"; }
3115
+ CSS
3116
+ $var: null;
3117
+ .foo {
3118
+ $var: & !global;
3119
+ }
3120
+
3121
+ .bar {
3122
+ content: "\#{$var}";
3123
+ }
3124
+ SCSS
3125
+ end
3126
+
3127
+ def test_selector_script_with_at_root
3128
+ assert_equal(<<CSS, render(<<SCSS))
3129
+ .foo-bar {
3130
+ a: b; }
3131
+ CSS
3132
+ .foo {
3133
+ @at-root \#{&}-bar {
3134
+ a: b;
3135
+ }
3136
+ }
3137
+ SCSS
3138
+ end
3139
+
3140
+ def test_multi_level_at_root_with_inner_selector_script
3141
+ assert_equal <<CSS, render(<<SCSS)
3142
+ .bar {
3143
+ a: b; }
3144
+ CSS
3145
+ .foo {
3146
+ @at-root .bar {
3147
+ @at-root \#{&} {
3148
+ a: b;
3149
+ }
3150
+ }
3151
+ }
3152
+ SCSS
3153
+ end
3154
+
3155
+ def test_at_root_with_at_root_through_mixin
3156
+ assert_equal(<<CSS, render(<<SCSS))
3157
+ .bar-baz {
3158
+ a: b; }
3159
+ CSS
3160
+ @mixin foo {
3161
+ .bar {
3162
+ @at-root \#{&}-baz {
3163
+ a: b;
3164
+ }
3165
+ }
3166
+ }
3167
+
3168
+ @include foo;
3169
+ SCSS
3170
+ end
3171
+
3172
+ # See https://github.com/sass/sass/issues/1294
3173
+ def test_extend_top_leveled_by_at_root
3174
+ render(<<SCSS)
3175
+ .span-10 {
3176
+ @at-root (without: all) {
3177
+ @extend %column;
3178
+ }
3179
+ }
3180
+ SCSS
3181
+
3182
+ assert(false, "Expected syntax error")
3183
+ rescue Sass::SyntaxError => e
3184
+ assert_equal "Extend directives may only be used within rules.", e.message
3185
+ assert_equal 3, e.sass_line
3186
+ end
3187
+
3188
+ def test_at_root_doesnt_always_break_blocks
3189
+ assert_equal <<CSS, render(<<SCSS)
3190
+ .foo {
3191
+ a: b; }
3192
+
3193
+ @media screen {
3194
+ .foo {
3195
+ c: d; }
3196
+ .bar {
3197
+ e: f; } }
3198
+ CSS
3199
+ %base {
3200
+ a: b;
3201
+ }
3202
+
3203
+ @media screen {
3204
+ .foo {
3205
+ c: d;
3206
+ @at-root (without: media) {
3207
+ @extend %base;
3208
+ }
3209
+ }
3210
+
3211
+ .bar {e: f}
3212
+ }
3213
+ SCSS
3214
+ end
3215
+
3216
+ ## Errors
3217
+
3218
+ def test_keyframes_rule_outside_of_keyframes
3219
+ render <<SCSS
3220
+ 0% {
3221
+ top: 0; }
3222
+ SCSS
3223
+ assert(false, "Expected syntax error")
3224
+ rescue Sass::SyntaxError => e
3225
+ assert_equal 'Invalid CSS after "": expected selector, was "0%"', e.message
3226
+ assert_equal 1, e.sass_line
3227
+ end
3228
+
3229
+ def test_selector_rule_in_keyframes
3230
+ render <<SCSS
3231
+ @keyframes identifier {
3232
+ .foo {
3233
+ top: 0; } }
3234
+ SCSS
3235
+ assert(false, "Expected syntax error")
3236
+ rescue Sass::SyntaxError => e
3237
+ assert_equal 'Invalid CSS after "": expected keyframes selector (e.g. 10%), was ".foo"', e.message
3238
+ assert_equal 2, e.sass_line
3239
+ end
3240
+
3241
+ def test_nested_mixin_def_is_scoped
3242
+ render <<SCSS
3243
+ foo {
3244
+ @mixin bar {a: b}}
3245
+ bar {@include bar}
3246
+ SCSS
3247
+ assert(false, "Expected syntax error")
3248
+ rescue Sass::SyntaxError => e
3249
+ assert_equal "Undefined mixin 'bar'.", e.message
3250
+ assert_equal 3, e.sass_line
3251
+ end
3252
+
3253
+ def test_rules_beneath_properties
3254
+ render <<SCSS
3255
+ foo {
3256
+ bar: {
3257
+ baz {
3258
+ bang: bop }}}
3259
+ SCSS
3260
+ assert(false, "Expected syntax error")
3261
+ rescue Sass::SyntaxError => e
3262
+ assert_equal 'Illegal nesting: Only properties may be nested beneath properties.', e.message
3263
+ assert_equal 3, e.sass_line
3264
+ end
3265
+
3266
+ def test_uses_property_exception_with_star_hack
3267
+ render <<SCSS
3268
+ foo {
3269
+ *bar:baz [fail]; }
3270
+ SCSS
3271
+ assert(false, "Expected syntax error")
3272
+ rescue Sass::SyntaxError => e
3273
+ assert_equal 'Invalid CSS after " *bar:baz ": expected ";", was "[fail]; }"', e.message
3274
+ assert_equal 2, e.sass_line
3275
+ end
3276
+
3277
+ def test_uses_property_exception_with_colon_hack
3278
+ render <<SCSS
3279
+ foo {
3280
+ :bar:baz [fail]; }
3281
+ SCSS
3282
+ assert(false, "Expected syntax error")
3283
+ rescue Sass::SyntaxError => e
3284
+ assert_equal 'Invalid CSS after " :bar:baz ": expected ";", was "[fail]; }"', e.message
3285
+ assert_equal 2, e.sass_line
3286
+ end
3287
+
3288
+ def test_uses_rule_exception_with_dot_hack
3289
+ render <<SCSS
3290
+ foo {
3291
+ .bar:baz <fail>; }
3292
+ SCSS
3293
+ assert(false, "Expected syntax error")
3294
+ rescue Sass::SyntaxError => e
3295
+ assert_equal 'Invalid CSS after " .bar:baz <fail>": expected expression (e.g. 1px, bold), was "; }"', e.message
3296
+ assert_equal 2, e.sass_line
3297
+ end
3298
+
3299
+ def test_uses_property_exception_with_space_after_name
3300
+ render <<SCSS
3301
+ foo {
3302
+ bar: baz [fail]; }
3303
+ SCSS
3304
+ assert(false, "Expected syntax error")
3305
+ rescue Sass::SyntaxError => e
3306
+ assert_equal 'Invalid CSS after " bar: baz ": expected ";", was "[fail]; }"', e.message
3307
+ assert_equal 2, e.sass_line
3308
+ end
3309
+
3310
+ def test_uses_property_exception_with_non_identifier_after_name
3311
+ render <<SCSS
3312
+ foo {
3313
+ bar:1px [fail]; }
3314
+ SCSS
3315
+ assert(false, "Expected syntax error")
3316
+ rescue Sass::SyntaxError => e
3317
+ assert_equal 'Invalid CSS after " bar:1px ": expected ";", was "[fail]; }"', e.message
3318
+ assert_equal 2, e.sass_line
3319
+ end
3320
+
3321
+ def test_uses_property_exception_when_followed_by_open_bracket
3322
+ render <<SCSS
3323
+ foo {
3324
+ bar:{baz: .fail} }
3325
+ SCSS
3326
+ assert(false, "Expected syntax error")
3327
+ rescue Sass::SyntaxError => e
3328
+ assert_equal 'Invalid CSS after " bar:{baz: ": expected expression (e.g. 1px, bold), was ".fail} }"', e.message
3329
+ assert_equal 2, e.sass_line
3330
+ end
3331
+
3332
+ def test_script_error
3333
+ render <<SCSS
3334
+ foo {
3335
+ bar: "baz" * * }
3336
+ SCSS
3337
+ assert(false, "Expected syntax error")
3338
+ rescue Sass::SyntaxError => e
3339
+ assert_equal 'Invalid CSS after " bar: "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message
3340
+ assert_equal 2, e.sass_line
3341
+ end
3342
+
3343
+ def test_multiline_script_syntax_error
3344
+ render <<SCSS
3345
+ foo {
3346
+ bar:
3347
+ "baz" * * }
3348
+ SCSS
3349
+ assert(false, "Expected syntax error")
3350
+ rescue Sass::SyntaxError => e
3351
+ assert_equal 'Invalid CSS after " "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message
3352
+ assert_equal 3, e.sass_line
3353
+ end
3354
+
3355
+ def test_multiline_script_runtime_error
3356
+ render <<SCSS
3357
+ foo {
3358
+ bar: "baz" +
3359
+ "bar" +
3360
+ $bang }
3361
+ SCSS
3362
+ assert(false, "Expected syntax error")
3363
+ rescue Sass::SyntaxError => e
3364
+ assert_equal "Undefined variable: \"$bang\".", e.message
3365
+ assert_equal 4, e.sass_line
3366
+ end
3367
+
3368
+ def test_post_multiline_script_runtime_error
3369
+ render <<SCSS
3370
+ foo {
3371
+ bar: "baz" +
3372
+ "bar" +
3373
+ "baz";
3374
+ bip: $bop; }
3375
+ SCSS
3376
+ assert(false, "Expected syntax error")
3377
+ rescue Sass::SyntaxError => e
3378
+ assert_equal "Undefined variable: \"$bop\".", e.message
3379
+ assert_equal 5, e.sass_line
3380
+ end
3381
+
3382
+ def test_multiline_property_runtime_error
3383
+ render <<SCSS
3384
+ foo {
3385
+ bar: baz
3386
+ bar
3387
+ \#{$bang} }
3388
+ SCSS
3389
+ assert(false, "Expected syntax error")
3390
+ rescue Sass::SyntaxError => e
3391
+ assert_equal "Undefined variable: \"$bang\".", e.message
3392
+ assert_equal 4, e.sass_line
3393
+ end
3394
+
3395
+ def test_post_resolution_selector_error
3396
+ render "\n\nfoo \#{\") bar\"} {a: b}"
3397
+ assert(false, "Expected syntax error")
3398
+ rescue Sass::SyntaxError => e
3399
+ assert_equal 'Invalid CSS after "foo ": expected selector, was ") bar"', e.message
3400
+ assert_equal 3, e.sass_line
3401
+ end
3402
+
3403
+ def test_parent_in_mid_selector_error
3404
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3405
+ Invalid CSS after ".foo": expected "{", was "&.bar"
3406
+
3407
+ "&.bar" may only be used at the beginning of a compound selector.
3408
+ MESSAGE
3409
+ flim {
3410
+ .foo&.bar {a: b}
3411
+ }
3412
+ SCSS
3413
+ end
3414
+
3415
+ def test_parent_after_selector_error
3416
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3417
+ Invalid CSS after ".foo.bar": expected "{", was "&"
3418
+
3419
+ "&" may only be used at the beginning of a compound selector.
3420
+ MESSAGE
3421
+ flim {
3422
+ .foo.bar& {a: b}
3423
+ }
3424
+ SCSS
3425
+ end
3426
+
3427
+ def test_double_parent_selector_error
3428
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3429
+ Invalid CSS after "&": expected "{", was "&"
3430
+
3431
+ "&" may only be used at the beginning of a compound selector.
3432
+ MESSAGE
3433
+ flim {
3434
+ && {a: b}
3435
+ }
3436
+ SCSS
3437
+ end
3438
+
3439
+ def test_no_lonely_else
3440
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3441
+ Invalid CSS: @else must come after @if
3442
+ MESSAGE
3443
+ @else {foo: bar}
3444
+ SCSS
3445
+ end
3446
+
3447
+ def test_failed_parent_selector_with_suffix
3448
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3449
+ Invalid parent selector for "&-bar": "*"
3450
+ MESSAGE
3451
+ * {
3452
+ &-bar {a: b}
3453
+ }
3454
+ SCSS
3455
+
3456
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3457
+ Invalid parent selector for "&-bar": "[foo=bar]"
3458
+ MESSAGE
3459
+ [foo=bar] {
3460
+ &-bar {a: b}
3461
+ }
3462
+ SCSS
3463
+
3464
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3465
+ Invalid parent selector for "&-bar": "::nth-child(2n+1)"
3466
+ MESSAGE
3467
+ ::nth-child(2n+1) {
3468
+ &-bar {a: b}
3469
+ }
3470
+ SCSS
3471
+
3472
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3473
+ Invalid parent selector for "&-bar": ":not(.foo)"
3474
+ MESSAGE
3475
+ :not(.foo) {
3476
+ &-bar {a: b}
3477
+ }
3478
+ SCSS
3479
+
3480
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3481
+ Invalid parent selector for "&-bar": ".foo +"
3482
+ MESSAGE
3483
+ .foo + {
3484
+ &-bar {a: b}
3485
+ }
3486
+ SCSS
3487
+ end
3488
+
3489
+ def test_empty_media_query_error
3490
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render(<<SCSS)}
3491
+ Invalid CSS after "": expected media query list, was ""
3492
+ MESSAGE
3493
+ @media \#{""} {
3494
+ foo {a: b}
3495
+ }
3496
+ SCSS
3497
+ end
3498
+
3499
+ def test_newline_in_property_value
3500
+ assert_equal(<<CSS, render(<<SCSS))
3501
+ .foo {
3502
+ bar: "bazbang"; }
3503
+ CSS
3504
+ .foo {
3505
+ $var: "baz\\
3506
+ bang";
3507
+ bar: $var;
3508
+ }
3509
+ SCSS
3510
+ end
3511
+
3512
+ def test_raw_newline_warning
3513
+ assert_warning(<<MESSAGE.rstrip) {assert_equal(<<CSS, render(<<SCSS))}
3514
+ DEPRECATION WARNING on line 2, column 9 of #{filename_for_test :scss}:
3515
+ Unescaped multiline strings are deprecated and will be removed in a future version of Sass.
3516
+ To include a newline in a string, use "\\a" or "\\a " as in CSS.
3517
+ MESSAGE
3518
+ .foo {
3519
+ bar: "baz\\a bang"; }
3520
+ CSS
3521
+ .foo {
3522
+ $var: "baz
3523
+ bang";
3524
+ bar: $var;
3525
+ }
3526
+ SCSS
3527
+ end
3528
+
3529
+ # Regression
3530
+
3531
+ def test_top_level_unknown_directive_in_at_root
3532
+ assert_equal(<<CSS, render(<<SCSS))
3533
+ @fblthp {
3534
+ a: b; }
3535
+ CSS
3536
+ @at-root {
3537
+ @fblthp {a: b}
3538
+ }
3539
+ SCSS
3540
+ end
3541
+
3542
+ def test_parent_ref_with_newline
3543
+ assert_equal(<<CSS, render(<<SCSS))
3544
+ a.c
3545
+ , b.c {
3546
+ x: y; }
3547
+ CSS
3548
+ a
3549
+ , b {&.c {x: y}}
3550
+ SCSS
3551
+ end
3552
+
3553
+ def test_parent_ref_in_nested_at_root
3554
+ assert_equal(<<CSS, render(<<SCSS))
3555
+ #test {
3556
+ border: 0; }
3557
+ #test:hover {
3558
+ display: none; }
3559
+ CSS
3560
+ a {
3561
+ @at-root #test {
3562
+ border: 0;
3563
+ &:hover{
3564
+ display: none;
3565
+ }
3566
+ }
3567
+ }
3568
+ SCSS
3569
+ end
3570
+
3571
+ def test_loud_comment_in_compressed_mode
3572
+ assert_equal(<<CSS, render(<<SCSS))
3573
+ /*! foo */
3574
+ CSS
3575
+ /*! foo */
3576
+ SCSS
3577
+ end
3578
+
3579
+ def test_parsing_decimals_followed_by_comments_doesnt_take_forever
3580
+ assert_equal(<<CSS, render(<<SCSS))
3581
+ .foo {
3582
+ padding: 4.21053% 4.21053% 5.63158%; }
3583
+ CSS
3584
+ .foo {
3585
+ padding: 4.21052631578947% 4.21052631578947% 5.631578947368421% /**/
3586
+ }
3587
+ SCSS
3588
+ end
3589
+
3590
+ def test_parsing_many_numbers_doesnt_take_forever
3591
+ values = ["80% 90%"] * 1000
3592
+ assert_equal(<<CSS, render(<<SCSS))
3593
+ .foo {
3594
+ padding: #{values.join(', ')}; }
3595
+ CSS
3596
+ .foo {
3597
+ padding: #{values.join(', ')};
3598
+ }
3599
+ SCSS
3600
+ end
3601
+
3602
+ def test_import_comments_in_imports
3603
+ assert_equal(<<CSS, render(<<SCSS))
3604
+ @import url(foo.css);
3605
+ @import url(bar.css);
3606
+ @import url(baz.css);
3607
+ CSS
3608
+ @import "foo.css", // this is a comment
3609
+ "bar.css", /* this is another comment */
3610
+ "baz.css"; // this is a third comment
3611
+ SCSS
3612
+ end
3613
+
3614
+ def test_reference_combinator_with_parent_ref
3615
+ assert_equal <<CSS, render(<<SCSS)
3616
+ a /foo/ b {
3617
+ c: d; }
3618
+ CSS
3619
+ a {& /foo/ b {c: d}}
3620
+ SCSS
3621
+ end
3622
+
3623
+ def test_newline_selector_rendered_multiple_times
3624
+ assert_equal <<CSS, render(<<SCSS)
3625
+ form input,
3626
+ form select {
3627
+ color: white; }
3628
+
3629
+ form input,
3630
+ form select {
3631
+ color: white; }
3632
+ CSS
3633
+ @for $i from 1 through 2 {
3634
+ form {
3635
+ input,
3636
+ select {
3637
+ color: white;
3638
+ }
3639
+ }
3640
+ }
3641
+ SCSS
3642
+ end
3643
+
3644
+ def test_prop_name_interpolation_after_hyphen
3645
+ assert_equal <<CSS, render(<<SCSS)
3646
+ a {
3647
+ -foo-bar: b; }
3648
+ CSS
3649
+ a { -\#{"foo"}-bar: b; }
3650
+ SCSS
3651
+ end
3652
+
3653
+ def test_star_plus_and_parent
3654
+ assert_equal <<CSS, render(<<SCSS)
3655
+ * + html foo {
3656
+ a: b; }
3657
+ CSS
3658
+ foo {*+html & {a: b}}
3659
+ SCSS
3660
+ end
3661
+
3662
+ def test_weird_added_space
3663
+ assert_equal <<CSS, render(<<SCSS)
3664
+ foo {
3665
+ bar: -moz-bip; }
3666
+ CSS
3667
+ $value : bip;
3668
+
3669
+ foo {
3670
+ bar: -moz-\#{$value};
3671
+ }
3672
+ SCSS
3673
+ end
3674
+
3675
+ def test_interpolation_with_bracket_on_next_line
3676
+ assert_equal <<CSS, render(<<SCSS)
3677
+ a.foo b {
3678
+ color: red; }
3679
+ CSS
3680
+ a.\#{"foo"} b
3681
+ {color: red}
3682
+ SCSS
3683
+ end
3684
+
3685
+ def test_extra_comma_in_mixin_arglist_error
3686
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
3687
+ Invalid CSS after "...clude foo(bar, ": expected mixin argument, was ");"
3688
+ MESSAGE
3689
+ @mixin foo($a1, $a2) {
3690
+ baz: $a1 $a2;
3691
+ }
3692
+
3693
+ .bar {
3694
+ @include foo(bar, );
3695
+ }
3696
+ SCSS
3697
+ end
3698
+
3699
+ def test_interpolation
3700
+ assert_equal <<CSS, render(<<SCSS)
3701
+ ul li#foo a span.label {
3702
+ foo: bar; }
3703
+ CSS
3704
+ $bar : "#foo";
3705
+ ul li\#{$bar} a span.label { foo: bar; }
3706
+ SCSS
3707
+ end
3708
+
3709
+ def test_mixin_with_keyword_args
3710
+ assert_equal <<CSS, render(<<SCSS)
3711
+ .mixed {
3712
+ required: foo;
3713
+ arg1: default-val1;
3714
+ arg2: non-default-val2; }
3715
+ CSS
3716
+ @mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
3717
+ required: $required;
3718
+ arg1: $arg1;
3719
+ arg2: $arg2;
3720
+ }
3721
+ .mixed { @include a-mixin(foo, $arg2: non-default-val2); }
3722
+ SCSS
3723
+ end
3724
+
3725
+ def test_passing_required_args_as_a_keyword_arg
3726
+ assert_equal <<CSS, render(<<SCSS)
3727
+ .mixed {
3728
+ required: foo;
3729
+ arg1: default-val1;
3730
+ arg2: default-val2; }
3731
+ CSS
3732
+ @mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
3733
+ required: $required;
3734
+ arg1: $arg1;
3735
+ arg2: $arg2; }
3736
+ .mixed { @include a-mixin($required: foo); }
3737
+ SCSS
3738
+ end
3739
+
3740
+ def test_passing_all_as_keyword_args_in_opposite_order
3741
+ assert_equal <<CSS, render(<<SCSS)
3742
+ .mixed {
3743
+ required: foo;
3744
+ arg1: non-default-val1;
3745
+ arg2: non-default-val2; }
3746
+ CSS
3747
+ @mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
3748
+ required: $required;
3749
+ arg1: $arg1;
3750
+ arg2: $arg2; }
3751
+ .mixed { @include a-mixin($arg2: non-default-val2, $arg1: non-default-val1, $required: foo); }
3752
+ SCSS
3753
+ end
3754
+
3755
+ def test_keyword_args_in_functions
3756
+ assert_equal <<CSS, render(<<SCSS)
3757
+ .keyed {
3758
+ color: rgba(170, 119, 204, 0.4); }
3759
+ CSS
3760
+ .keyed { color: rgba($color: #a7c, $alpha: 0.4) }
3761
+ SCSS
3762
+ end
3763
+
3764
+ def test_unknown_keyword_arg_raises_error
3765
+ assert_raise_message(Sass::SyntaxError, "Mixin a doesn't have an argument named $c.") {render <<SCSS}
3766
+ @mixin a($b: 1) { a: $b; }
3767
+ div { @include a(1, $c: 3); }
3768
+ SCSS
3769
+ end
3770
+
3771
+
3772
+ def test_newlines_removed_from_selectors_when_compressed
3773
+ assert_equal <<CSS, render(<<SCSS, :style => :compressed)
3774
+ z a,z b{display:block}
3775
+ CSS
3776
+ a
3777
+ , b {
3778
+ z & {
3779
+ display: block;
3780
+ }
3781
+ }
3782
+ SCSS
3783
+ end
3784
+
3785
+ def test_if_error_line
3786
+ assert_raise_line(2) {render(<<SCSS)}
3787
+ @if true {foo: bar}
3788
+ }
3789
+ SCSS
3790
+ end
3791
+
3792
+ def test_multiline_var
3793
+ assert_equal <<CSS, render(<<SCSS)
3794
+ foo {
3795
+ a: 3;
3796
+ b: false;
3797
+ c: a b c; }
3798
+ CSS
3799
+ foo {
3800
+ $var1: 1 +
3801
+ 2;
3802
+ $var2: true and
3803
+ false;
3804
+ $var3: a b
3805
+ c;
3806
+ a: $var1;
3807
+ b: $var2;
3808
+ c: $var3; }
3809
+ SCSS
3810
+ end
3811
+
3812
+ def test_mixin_content
3813
+ assert_equal <<CSS, render(<<SASS)
3814
+ .parent {
3815
+ background-color: red;
3816
+ border-color: red; }
3817
+ .parent .child {
3818
+ background-color: yellow;
3819
+ color: blue;
3820
+ border-color: yellow; }
3821
+ CSS
3822
+ $color: blue;
3823
+ @mixin context($class, $color: red) {
3824
+ .\#{$class} {
3825
+ background-color: $color;
3826
+ @content;
3827
+ border-color: $color;
3828
+ }
3829
+ }
3830
+ @include context(parent) {
3831
+ @include context(child, $color: yellow) {
3832
+ color: $color;
3833
+ }
3834
+ }
3835
+ SASS
3836
+ end
3837
+
3838
+ def test_empty_content
3839
+ assert_equal <<CSS, render(<<SCSS)
3840
+ a {
3841
+ b: c; }
3842
+ CSS
3843
+ @mixin foo { @content }
3844
+ a { b: c; @include foo {} }
3845
+ SCSS
3846
+ end
3847
+
3848
+ def test_options_passed_to_script
3849
+ assert_equal <<CSS, render(<<SCSS, :style => :compressed)
3850
+ foo{color:#000}
3851
+ CSS
3852
+ foo {color: darken(black, 10%)}
3853
+ SCSS
3854
+ end
3855
+
3856
+ # ref: https://github.com/nex3/sass/issues/104
3857
+ def test_no_buffer_overflow
3858
+ template = render <<SCSS
3859
+ .aaa {
3860
+ background-color: white;
3861
+ }
3862
+ .aaa .aaa .aaa {
3863
+ background-color: black;
3864
+ }
3865
+ .bbb {
3866
+ @extend .aaa;
3867
+ }
3868
+ .xxx {
3869
+ @extend .bbb;
3870
+ }
3871
+ .yyy {
3872
+ @extend .bbb;
3873
+ }
3874
+ .zzz {
3875
+ @extend .bbb;
3876
+ }
3877
+ SCSS
3878
+ Sass::SCSS::Parser.new(template, "test.scss", nil).parse
3879
+ end
3880
+
3881
+ def test_extend_in_media_in_rule
3882
+ assert_equal(<<CSS, render(<<SCSS))
3883
+ @media screen {
3884
+ .foo {
3885
+ a: b; } }
3886
+ CSS
3887
+ .foo {
3888
+ @media screen {
3889
+ @extend %bar;
3890
+ }
3891
+ }
3892
+
3893
+ @media screen {
3894
+ %bar {
3895
+ a: b;
3896
+ }
3897
+ }
3898
+ SCSS
3899
+ end
3900
+ end