aliddle-sass 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (238) hide show
  1. data/.yardopts +11 -0
  2. data/CONTRIBUTING +3 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +201 -0
  5. data/Rakefile +347 -0
  6. data/VERSION +1 -0
  7. data/VERSION_NAME +1 -0
  8. data/bin/sass +9 -0
  9. data/bin/sass-convert +8 -0
  10. data/bin/scss +9 -0
  11. data/extra/update_watch.rb +13 -0
  12. data/init.rb +18 -0
  13. data/lib/sass.rb +95 -0
  14. data/lib/sass/cache_stores.rb +15 -0
  15. data/lib/sass/cache_stores/base.rb +88 -0
  16. data/lib/sass/cache_stores/chain.rb +33 -0
  17. data/lib/sass/cache_stores/filesystem.rb +60 -0
  18. data/lib/sass/cache_stores/memory.rb +47 -0
  19. data/lib/sass/cache_stores/null.rb +25 -0
  20. data/lib/sass/callbacks.rb +66 -0
  21. data/lib/sass/css.rb +409 -0
  22. data/lib/sass/engine.rb +928 -0
  23. data/lib/sass/environment.rb +101 -0
  24. data/lib/sass/error.rb +201 -0
  25. data/lib/sass/exec.rb +707 -0
  26. data/lib/sass/importers.rb +22 -0
  27. data/lib/sass/importers/base.rb +139 -0
  28. data/lib/sass/importers/filesystem.rb +190 -0
  29. data/lib/sass/logger.rb +15 -0
  30. data/lib/sass/logger/base.rb +32 -0
  31. data/lib/sass/logger/log_level.rb +49 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin.rb +132 -0
  34. data/lib/sass/plugin/compiler.rb +406 -0
  35. data/lib/sass/plugin/configuration.rb +123 -0
  36. data/lib/sass/plugin/generic.rb +15 -0
  37. data/lib/sass/plugin/merb.rb +48 -0
  38. data/lib/sass/plugin/rack.rb +60 -0
  39. data/lib/sass/plugin/rails.rb +47 -0
  40. data/lib/sass/plugin/staleness_checker.rb +183 -0
  41. data/lib/sass/railtie.rb +9 -0
  42. data/lib/sass/repl.rb +57 -0
  43. data/lib/sass/root.rb +7 -0
  44. data/lib/sass/script.rb +39 -0
  45. data/lib/sass/script/arg_list.rb +52 -0
  46. data/lib/sass/script/bool.rb +18 -0
  47. data/lib/sass/script/color.rb +606 -0
  48. data/lib/sass/script/css_lexer.rb +29 -0
  49. data/lib/sass/script/css_parser.rb +31 -0
  50. data/lib/sass/script/funcall.rb +237 -0
  51. data/lib/sass/script/functions.rb +1543 -0
  52. data/lib/sass/script/interpolation.rb +79 -0
  53. data/lib/sass/script/lexer.rb +348 -0
  54. data/lib/sass/script/list.rb +85 -0
  55. data/lib/sass/script/literal.rb +221 -0
  56. data/lib/sass/script/node.rb +99 -0
  57. data/lib/sass/script/null.rb +37 -0
  58. data/lib/sass/script/number.rb +453 -0
  59. data/lib/sass/script/operation.rb +110 -0
  60. data/lib/sass/script/parser.rb +495 -0
  61. data/lib/sass/script/string.rb +51 -0
  62. data/lib/sass/script/string_interpolation.rb +103 -0
  63. data/lib/sass/script/unary_operation.rb +69 -0
  64. data/lib/sass/script/variable.rb +58 -0
  65. data/lib/sass/scss.rb +16 -0
  66. data/lib/sass/scss/css_parser.rb +36 -0
  67. data/lib/sass/scss/parser.rb +1179 -0
  68. data/lib/sass/scss/rx.rb +133 -0
  69. data/lib/sass/scss/script_lexer.rb +15 -0
  70. data/lib/sass/scss/script_parser.rb +25 -0
  71. data/lib/sass/scss/static_parser.rb +54 -0
  72. data/lib/sass/selector.rb +452 -0
  73. data/lib/sass/selector/abstract_sequence.rb +94 -0
  74. data/lib/sass/selector/comma_sequence.rb +92 -0
  75. data/lib/sass/selector/sequence.rb +507 -0
  76. data/lib/sass/selector/simple.rb +119 -0
  77. data/lib/sass/selector/simple_sequence.rb +212 -0
  78. data/lib/sass/shared.rb +76 -0
  79. data/lib/sass/supports.rb +229 -0
  80. data/lib/sass/tree/charset_node.rb +22 -0
  81. data/lib/sass/tree/comment_node.rb +82 -0
  82. data/lib/sass/tree/content_node.rb +9 -0
  83. data/lib/sass/tree/css_import_node.rb +60 -0
  84. data/lib/sass/tree/debug_node.rb +18 -0
  85. data/lib/sass/tree/directive_node.rb +42 -0
  86. data/lib/sass/tree/each_node.rb +24 -0
  87. data/lib/sass/tree/extend_node.rb +36 -0
  88. data/lib/sass/tree/for_node.rb +36 -0
  89. data/lib/sass/tree/function_node.rb +34 -0
  90. data/lib/sass/tree/if_node.rb +52 -0
  91. data/lib/sass/tree/import_node.rb +75 -0
  92. data/lib/sass/tree/media_node.rb +58 -0
  93. data/lib/sass/tree/mixin_def_node.rb +38 -0
  94. data/lib/sass/tree/mixin_node.rb +39 -0
  95. data/lib/sass/tree/node.rb +196 -0
  96. data/lib/sass/tree/prop_node.rb +152 -0
  97. data/lib/sass/tree/return_node.rb +18 -0
  98. data/lib/sass/tree/root_node.rb +28 -0
  99. data/lib/sass/tree/rule_node.rb +132 -0
  100. data/lib/sass/tree/supports_node.rb +51 -0
  101. data/lib/sass/tree/trace_node.rb +32 -0
  102. data/lib/sass/tree/variable_node.rb +30 -0
  103. data/lib/sass/tree/visitors/base.rb +75 -0
  104. data/lib/sass/tree/visitors/check_nesting.rb +147 -0
  105. data/lib/sass/tree/visitors/convert.rb +316 -0
  106. data/lib/sass/tree/visitors/cssize.rb +229 -0
  107. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  108. data/lib/sass/tree/visitors/extend.rb +68 -0
  109. data/lib/sass/tree/visitors/perform.rb +446 -0
  110. data/lib/sass/tree/visitors/set_options.rb +125 -0
  111. data/lib/sass/tree/visitors/to_css.rb +230 -0
  112. data/lib/sass/tree/warn_node.rb +18 -0
  113. data/lib/sass/tree/while_node.rb +18 -0
  114. data/lib/sass/util.rb +906 -0
  115. data/lib/sass/util/multibyte_string_scanner.rb +155 -0
  116. data/lib/sass/util/subset_map.rb +109 -0
  117. data/lib/sass/util/test.rb +10 -0
  118. data/lib/sass/version.rb +126 -0
  119. data/rails/init.rb +1 -0
  120. data/test/Gemfile +3 -0
  121. data/test/Gemfile.lock +10 -0
  122. data/test/sass/cache_test.rb +89 -0
  123. data/test/sass/callbacks_test.rb +61 -0
  124. data/test/sass/conversion_test.rb +1760 -0
  125. data/test/sass/css2sass_test.rb +439 -0
  126. data/test/sass/data/hsl-rgb.txt +319 -0
  127. data/test/sass/engine_test.rb +3243 -0
  128. data/test/sass/exec_test.rb +86 -0
  129. data/test/sass/extend_test.rb +1461 -0
  130. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  131. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  132. data/test/sass/functions_test.rb +1139 -0
  133. data/test/sass/importer_test.rb +192 -0
  134. data/test/sass/logger_test.rb +58 -0
  135. data/test/sass/mock_importer.rb +49 -0
  136. data/test/sass/more_results/more1.css +9 -0
  137. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  138. data/test/sass/more_results/more_import.css +29 -0
  139. data/test/sass/more_templates/_more_partial.sass +2 -0
  140. data/test/sass/more_templates/more1.sass +23 -0
  141. data/test/sass/more_templates/more_import.sass +11 -0
  142. data/test/sass/plugin_test.rb +550 -0
  143. data/test/sass/results/alt.css +4 -0
  144. data/test/sass/results/basic.css +9 -0
  145. data/test/sass/results/cached_import_option.css +3 -0
  146. data/test/sass/results/compact.css +5 -0
  147. data/test/sass/results/complex.css +86 -0
  148. data/test/sass/results/compressed.css +1 -0
  149. data/test/sass/results/expanded.css +19 -0
  150. data/test/sass/results/filename_fn.css +3 -0
  151. data/test/sass/results/if.css +3 -0
  152. data/test/sass/results/import.css +31 -0
  153. data/test/sass/results/import_charset.css +5 -0
  154. data/test/sass/results/import_charset_1_8.css +5 -0
  155. data/test/sass/results/import_charset_ibm866.css +5 -0
  156. data/test/sass/results/import_content.css +1 -0
  157. data/test/sass/results/line_numbers.css +49 -0
  158. data/test/sass/results/mixins.css +95 -0
  159. data/test/sass/results/multiline.css +24 -0
  160. data/test/sass/results/nested.css +22 -0
  161. data/test/sass/results/options.css +1 -0
  162. data/test/sass/results/parent_ref.css +13 -0
  163. data/test/sass/results/script.css +16 -0
  164. data/test/sass/results/scss_import.css +31 -0
  165. data/test/sass/results/scss_importee.css +2 -0
  166. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  167. data/test/sass/results/subdir/subdir.css +3 -0
  168. data/test/sass/results/units.css +11 -0
  169. data/test/sass/results/warn.css +0 -0
  170. data/test/sass/results/warn_imported.css +0 -0
  171. data/test/sass/script_conversion_test.rb +299 -0
  172. data/test/sass/script_test.rb +591 -0
  173. data/test/sass/scss/css_test.rb +1093 -0
  174. data/test/sass/scss/rx_test.rb +156 -0
  175. data/test/sass/scss/scss_test.rb +2043 -0
  176. data/test/sass/scss/test_helper.rb +37 -0
  177. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  178. data/test/sass/templates/_double_import_loop2.sass +1 -0
  179. data/test/sass/templates/_filename_fn_import.scss +11 -0
  180. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  181. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  182. data/test/sass/templates/_imported_content.sass +3 -0
  183. data/test/sass/templates/_partial.sass +2 -0
  184. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  185. data/test/sass/templates/alt.sass +16 -0
  186. data/test/sass/templates/basic.sass +23 -0
  187. data/test/sass/templates/bork1.sass +2 -0
  188. data/test/sass/templates/bork2.sass +2 -0
  189. data/test/sass/templates/bork3.sass +2 -0
  190. data/test/sass/templates/bork4.sass +2 -0
  191. data/test/sass/templates/bork5.sass +3 -0
  192. data/test/sass/templates/cached_import_option.scss +3 -0
  193. data/test/sass/templates/compact.sass +17 -0
  194. data/test/sass/templates/complex.sass +305 -0
  195. data/test/sass/templates/compressed.sass +15 -0
  196. data/test/sass/templates/double_import_loop1.sass +1 -0
  197. data/test/sass/templates/expanded.sass +17 -0
  198. data/test/sass/templates/filename_fn.scss +18 -0
  199. data/test/sass/templates/if.sass +11 -0
  200. data/test/sass/templates/import.sass +12 -0
  201. data/test/sass/templates/import_charset.sass +9 -0
  202. data/test/sass/templates/import_charset_1_8.sass +6 -0
  203. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  204. data/test/sass/templates/import_content.sass +4 -0
  205. data/test/sass/templates/importee.less +2 -0
  206. data/test/sass/templates/importee.sass +19 -0
  207. data/test/sass/templates/line_numbers.sass +13 -0
  208. data/test/sass/templates/mixin_bork.sass +5 -0
  209. data/test/sass/templates/mixins.sass +76 -0
  210. data/test/sass/templates/multiline.sass +20 -0
  211. data/test/sass/templates/nested.sass +25 -0
  212. data/test/sass/templates/nested_bork1.sass +2 -0
  213. data/test/sass/templates/nested_bork2.sass +2 -0
  214. data/test/sass/templates/nested_bork3.sass +2 -0
  215. data/test/sass/templates/nested_bork4.sass +2 -0
  216. data/test/sass/templates/nested_import.sass +2 -0
  217. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  218. data/test/sass/templates/options.sass +2 -0
  219. data/test/sass/templates/parent_ref.sass +25 -0
  220. data/test/sass/templates/same_name_different_ext.sass +2 -0
  221. data/test/sass/templates/same_name_different_ext.scss +1 -0
  222. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  223. data/test/sass/templates/script.sass +101 -0
  224. data/test/sass/templates/scss_import.scss +11 -0
  225. data/test/sass/templates/scss_importee.scss +1 -0
  226. data/test/sass/templates/single_import_loop.sass +1 -0
  227. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  228. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  229. data/test/sass/templates/subdir/subdir.sass +6 -0
  230. data/test/sass/templates/units.sass +11 -0
  231. data/test/sass/templates/warn.sass +3 -0
  232. data/test/sass/templates/warn_imported.sass +4 -0
  233. data/test/sass/test_helper.rb +8 -0
  234. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  235. data/test/sass/util/subset_map_test.rb +91 -0
  236. data/test/sass/util_test.rb +313 -0
  237. data/test/test_helper.rb +80 -0
  238. metadata +348 -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 < Test::Unit::TestCase
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
+
30
+ assert_match IDENT, "foo-bar"
31
+ assert_match IDENT, "f012-23"
32
+ assert_match IDENT, "foo_-_bar"
33
+ assert_match IDENT, "f012_23"
34
+
35
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-003.xht
36
+ assert_match IDENT, "c\\lass"
37
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-004.xht
38
+ assert_match IDENT, "c\\00006Cas\\000073"
39
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-001.xht
40
+ assert_match IDENT, "IdE6n-3t0_6"
41
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-006.xht
42
+ assert_match IDENT, "\\6000ident"
43
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-007.xht
44
+ assert_match IDENT, "iden\\6000t\\6000"
45
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-013.xht
46
+ assert_match IDENT, "\\-ident"
47
+ end
48
+
49
+ def test_underscores_in_identifiers
50
+ assert_match IDENT, "foo_bar"
51
+ assert_match IDENT, "_\xC3\xBFfoo"
52
+ assert_match IDENT, "__foo"
53
+ assert_match IDENT, "_1foo"
54
+ assert_match IDENT, "-_foo"
55
+ assert_match IDENT, "_-foo"
56
+ end
57
+
58
+ def test_invalid_identifiers
59
+ assert_no_match IDENT, ""
60
+ assert_no_match IDENT, "1foo"
61
+ assert_no_match IDENT, "-1foo"
62
+ assert_no_match IDENT, "--foo"
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
+ assert_not_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
+ assert_not_equal str.size, match && match[0].size
154
+ end
155
+
156
+ end
@@ -0,0 +1,2043 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/test_helper'
4
+
5
+ class ScssTest < Test::Unit::TestCase
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_warn_directive
119
+ expected_warning = <<EXPECTATION
120
+ WARNING: this is a warning
121
+ on line 2 of test_warn_directive_inline.scss
122
+
123
+ WARNING: this is a mixin
124
+ on line 1 of test_warn_directive_inline.scss, in `foo'
125
+ from line 3 of test_warn_directive_inline.scss
126
+ EXPECTATION
127
+ assert_warning expected_warning do
128
+ assert_equal <<CSS, render(<<SCSS)
129
+ bar {
130
+ c: d; }
131
+ CSS
132
+ @mixin foo { @warn "this is a mixin";}
133
+ @warn "this is a warning";
134
+ bar {c: d; @include foo;}
135
+ SCSS
136
+ end
137
+ end
138
+
139
+ def test_for_directive
140
+ assert_equal <<CSS, render(<<SCSS)
141
+ .foo {
142
+ a: 1;
143
+ a: 2;
144
+ a: 3;
145
+ a: 4; }
146
+ CSS
147
+ .foo {
148
+ @for $var from 1 to 5 {a: $var;}
149
+ }
150
+ SCSS
151
+
152
+ assert_equal <<CSS, render(<<SCSS)
153
+ .foo {
154
+ a: 1;
155
+ a: 2;
156
+ a: 3;
157
+ a: 4;
158
+ a: 5; }
159
+ CSS
160
+ .foo {
161
+ @for $var from 1 through 5 {a: $var;}
162
+ }
163
+ SCSS
164
+ end
165
+
166
+ def test_if_directive
167
+ assert_equal <<CSS, render(<<SCSS)
168
+ foo {
169
+ a: b; }
170
+ CSS
171
+ @if "foo" == "foo" {foo {a: b}}
172
+ @if "foo" != "foo" {bar {a: b}}
173
+ SCSS
174
+
175
+ assert_equal <<CSS, render(<<SCSS)
176
+ bar {
177
+ a: b; }
178
+ CSS
179
+ @if "foo" != "foo" {foo {a: b}}
180
+ @else if "foo" == "foo" {bar {a: b}}
181
+ @else if true {baz {a: b}}
182
+ SCSS
183
+
184
+ assert_equal <<CSS, render(<<SCSS)
185
+ bar {
186
+ a: b; }
187
+ CSS
188
+ @if "foo" != "foo" {foo {a: b}}
189
+ @else {bar {a: b}}
190
+ SCSS
191
+ end
192
+
193
+ def test_comment_after_if_directive
194
+ assert_equal <<CSS, render(<<SCSS)
195
+ foo {
196
+ a: b;
197
+ /* This is a comment */
198
+ c: d; }
199
+ CSS
200
+ foo {
201
+ @if true {a: b}
202
+ /* This is a comment */
203
+ c: d }
204
+ SCSS
205
+ assert_equal <<CSS, render(<<SCSS)
206
+ foo {
207
+ a: b;
208
+ /* This is a comment */
209
+ c: d; }
210
+ CSS
211
+ foo {
212
+ @if true {a: b}
213
+ @else {x: y}
214
+ /* This is a comment */
215
+ c: d }
216
+ SCSS
217
+ end
218
+
219
+ def test_while_directive
220
+ assert_equal <<CSS, render(<<SCSS)
221
+ .foo {
222
+ a: 1;
223
+ a: 2;
224
+ a: 3;
225
+ a: 4; }
226
+ CSS
227
+ $i: 1;
228
+
229
+ .foo {
230
+ @while $i != 5 {
231
+ a: $i;
232
+ $i: $i + 1;
233
+ }
234
+ }
235
+ SCSS
236
+ end
237
+
238
+ def test_each_directive
239
+ assert_equal <<CSS, render(<<SCSS)
240
+ a {
241
+ b: 1px;
242
+ b: 2px;
243
+ b: 3px;
244
+ b: 4px; }
245
+
246
+ c {
247
+ d: foo;
248
+ d: bar;
249
+ d: baz;
250
+ d: bang; }
251
+ CSS
252
+ a {
253
+ @each $number in 1px 2px 3px 4px {
254
+ b: $number;
255
+ }
256
+ }
257
+ c {
258
+ @each $str in foo, bar, baz, bang {
259
+ d: $str;
260
+ }
261
+ }
262
+ SCSS
263
+ end
264
+
265
+ def test_css_import_directive
266
+ assert_equal "@import url(foo.css);\n", render('@import "foo.css";')
267
+ assert_equal "@import url(foo.css);\n", render("@import 'foo.css';")
268
+ assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
269
+ assert_equal "@import url(\"foo.css\");\n", render('@import url("foo.css");')
270
+ assert_equal "@import url(foo.css);\n", render('@import url(foo.css);')
271
+ end
272
+
273
+ def test_media_import
274
+ assert_equal("@import \"./fonts.sass\" all;\n", render("@import \"./fonts.sass\" all;"))
275
+ end
276
+
277
+ def test_dynamic_media_import
278
+ assert_equal(<<CSS, render(<<SCSS))
279
+ @import "foo" print and (-webkit-min-device-pixel-ratio-foo: 25);
280
+ CSS
281
+ $media: print;
282
+ $key: -webkit-min-device-pixel-ratio;
283
+ $value: 20;
284
+ @import "foo" \#{$media} and ($key + "-foo": $value + 5);
285
+ SCSS
286
+ end
287
+
288
+ def test_http_import
289
+ assert_equal("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";\n",
290
+ render("@import \"http://fonts.googleapis.com/css?family=Droid+Sans\";"))
291
+ end
292
+
293
+ def test_protocol_relative_import
294
+ assert_equal("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";\n",
295
+ render("@import \"//fonts.googleapis.com/css?family=Droid+Sans\";"))
296
+ end
297
+
298
+ def test_import_with_interpolation
299
+ assert_equal <<CSS, render(<<SCSS)
300
+ @import url("http://fonts.googleapis.com/css?family=Droid+Sans");
301
+ CSS
302
+ $family: unquote("Droid+Sans");
303
+ @import url("http://fonts.googleapis.com/css?family=\#{$family}");
304
+ SCSS
305
+ end
306
+
307
+ def test_url_import
308
+ assert_equal("@import url(fonts.sass);\n", render("@import url(fonts.sass);"))
309
+ end
310
+
311
+ def test_block_comment_in_script
312
+ assert_equal <<CSS, render(<<SCSS)
313
+ foo {
314
+ a: 1bar; }
315
+ CSS
316
+ foo {a: 1 + /* flang */ bar}
317
+ SCSS
318
+ end
319
+
320
+ def test_line_comment_in_script
321
+ assert_equal <<CSS, render(<<SCSS)
322
+ foo {
323
+ a: 1blang; }
324
+ CSS
325
+ foo {a: 1 + // flang }
326
+ blang }
327
+ SCSS
328
+ end
329
+
330
+ ## Nested Rules
331
+
332
+ def test_nested_rules
333
+ assert_equal <<CSS, render(<<SCSS)
334
+ foo bar {
335
+ a: b; }
336
+ CSS
337
+ foo {bar {a: b}}
338
+ SCSS
339
+ assert_equal <<CSS, render(<<SCSS)
340
+ foo bar {
341
+ a: b; }
342
+ foo baz {
343
+ b: c; }
344
+ CSS
345
+ foo {
346
+ bar {a: b}
347
+ baz {b: c}}
348
+ SCSS
349
+ assert_equal <<CSS, render(<<SCSS)
350
+ foo bar baz {
351
+ a: b; }
352
+ foo bang bip {
353
+ a: b; }
354
+ CSS
355
+ foo {
356
+ bar {baz {a: b}}
357
+ bang {bip {a: b}}}
358
+ SCSS
359
+ end
360
+
361
+ def test_nested_rules_with_declarations
362
+ assert_equal <<CSS, render(<<SCSS)
363
+ foo {
364
+ a: b; }
365
+ foo bar {
366
+ c: d; }
367
+ CSS
368
+ foo {
369
+ a: b;
370
+ bar {c: d}}
371
+ SCSS
372
+ assert_equal <<CSS, render(<<SCSS)
373
+ foo {
374
+ a: b; }
375
+ foo bar {
376
+ c: d; }
377
+ CSS
378
+ foo {
379
+ bar {c: d}
380
+ a: b}
381
+ SCSS
382
+ assert_equal <<CSS, render(<<SCSS)
383
+ foo {
384
+ ump: nump;
385
+ grump: clump; }
386
+ foo bar {
387
+ blat: bang;
388
+ habit: rabbit; }
389
+ foo bar baz {
390
+ a: b; }
391
+ foo bar bip {
392
+ c: d; }
393
+ foo bibble bap {
394
+ e: f; }
395
+ CSS
396
+ foo {
397
+ ump: nump;
398
+ grump: clump;
399
+ bar {
400
+ blat: bang;
401
+ habit: rabbit;
402
+ baz {a: b}
403
+ bip {c: d}}
404
+ bibble {
405
+ bap {e: f}}}
406
+ SCSS
407
+ end
408
+
409
+ def test_nested_rules_with_fancy_selectors
410
+ assert_equal <<CSS, render(<<SCSS)
411
+ foo .bar {
412
+ a: b; }
413
+ foo :baz {
414
+ c: d; }
415
+ foo bang:bop {
416
+ e: f; }
417
+ CSS
418
+ foo {
419
+ .bar {a: b}
420
+ :baz {c: d}
421
+ bang:bop {e: f}}
422
+ SCSS
423
+ end
424
+
425
+ def test_almost_ambiguous_nested_rules_and_declarations
426
+ assert_equal <<CSS, render(<<SCSS)
427
+ foo {
428
+ bar: baz bang bop biddle woo look at all these elems; }
429
+ foo bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {
430
+ a: b; }
431
+ foo bar:baz bang bop biddle woo look at all these elems {
432
+ a: b; }
433
+ CSS
434
+ foo {
435
+ bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {a: b};
436
+ bar:baz bang bop biddle woo look at all these elems {a: b};
437
+ bar:baz bang bop biddle woo look at all these elems; }
438
+ SCSS
439
+ end
440
+
441
+ def test_newlines_in_selectors
442
+ assert_equal <<CSS, render(<<SCSS)
443
+ foo
444
+ bar {
445
+ a: b; }
446
+ CSS
447
+ foo
448
+ bar {a: b}
449
+ SCSS
450
+
451
+ assert_equal <<CSS, render(<<SCSS)
452
+ foo baz,
453
+ foo bang,
454
+ bar baz,
455
+ bar bang {
456
+ a: b; }
457
+ CSS
458
+ foo,
459
+ bar {
460
+ baz,
461
+ bang {a: b}}
462
+ SCSS
463
+
464
+ assert_equal <<CSS, render(<<SCSS)
465
+ foo
466
+ bar baz
467
+ bang {
468
+ a: b; }
469
+ foo
470
+ bar bip bop {
471
+ c: d; }
472
+ CSS
473
+ foo
474
+ bar {
475
+ baz
476
+ bang {a: b}
477
+
478
+ bip bop {c: d}}
479
+ SCSS
480
+
481
+ assert_equal <<CSS, render(<<SCSS)
482
+ foo bang, foo bip
483
+ bop, bar
484
+ baz bang, bar
485
+ baz bip
486
+ bop {
487
+ a: b; }
488
+ CSS
489
+ foo, bar
490
+ baz {
491
+ bang, bip
492
+ bop {a: b}}
493
+ SCSS
494
+ end
495
+
496
+ def test_trailing_comma_in_selector
497
+ assert_equal <<CSS, render(<<SCSS)
498
+ #foo #bar,
499
+ #baz #boom {
500
+ a: b; }
501
+
502
+ #bip #bop {
503
+ c: d; }
504
+ CSS
505
+ #foo #bar,,
506
+ ,#baz #boom, {a: b}
507
+
508
+ #bip #bop, ,, {c: d}
509
+ SCSS
510
+ end
511
+
512
+ def test_parent_selectors
513
+ assert_equal <<CSS, render(<<SCSS)
514
+ foo:hover {
515
+ a: b; }
516
+ bar foo.baz {
517
+ c: d; }
518
+ CSS
519
+ foo {
520
+ &:hover {a: b}
521
+ bar &.baz {c: d}}
522
+ SCSS
523
+ end
524
+
525
+ def test_parent_selector_with_subject
526
+ assert_equal <<CSS, render(<<SCSS)
527
+ bar foo.baz! .bip {
528
+ a: b; }
529
+
530
+ bar foo bar.baz! .bip {
531
+ c: d; }
532
+ CSS
533
+ foo {
534
+ bar &.baz! .bip {a: b}}
535
+
536
+ foo bar {
537
+ bar &.baz! .bip {c: d}}
538
+ SCSS
539
+ end
540
+
541
+ ## Namespace Properties
542
+
543
+ def test_namespace_properties
544
+ assert_equal <<CSS, render(<<SCSS)
545
+ foo {
546
+ bar: baz;
547
+ bang-bip: 1px;
548
+ bang-bop: bar; }
549
+ CSS
550
+ foo {
551
+ bar: baz;
552
+ bang: {
553
+ bip: 1px;
554
+ bop: bar;}}
555
+ SCSS
556
+ end
557
+
558
+ def test_several_namespace_properties
559
+ assert_equal <<CSS, render(<<SCSS)
560
+ foo {
561
+ bar: baz;
562
+ bang-bip: 1px;
563
+ bang-bop: bar;
564
+ buzz-fram: "foo";
565
+ buzz-frum: moo; }
566
+ CSS
567
+ foo {
568
+ bar: baz;
569
+ bang: {
570
+ bip: 1px;
571
+ bop: bar;}
572
+ buzz: {
573
+ fram: "foo";
574
+ frum: moo;
575
+ }
576
+ }
577
+ SCSS
578
+ end
579
+
580
+ def test_nested_namespace_properties
581
+ assert_equal <<CSS, render(<<SCSS)
582
+ foo {
583
+ bar: baz;
584
+ bang-bip: 1px;
585
+ bang-bop: bar;
586
+ bang-blat-baf: bort; }
587
+ CSS
588
+ foo {
589
+ bar: baz;
590
+ bang: {
591
+ bip: 1px;
592
+ bop: bar;
593
+ blat:{baf:bort}}}
594
+ SCSS
595
+ end
596
+
597
+ def test_namespace_properties_with_value
598
+ assert_equal <<CSS, render(<<SCSS)
599
+ foo {
600
+ bar: baz;
601
+ bar-bip: bop;
602
+ bar-bing: bop; }
603
+ CSS
604
+ foo {
605
+ bar: baz {
606
+ bip: bop;
607
+ bing: bop; }}
608
+ SCSS
609
+ end
610
+
611
+ def test_namespace_properties_with_script_value
612
+ assert_equal <<CSS, render(<<SCSS)
613
+ foo {
614
+ bar: bazbang;
615
+ bar-bip: bop;
616
+ bar-bing: bop; }
617
+ CSS
618
+ foo {
619
+ bar: baz + bang {
620
+ bip: bop;
621
+ bing: bop; }}
622
+ SCSS
623
+ end
624
+
625
+ def test_no_namespace_properties_without_space
626
+ assert_equal <<CSS, render(<<SCSS)
627
+ foo bar:baz {
628
+ bip: bop; }
629
+ CSS
630
+ foo {
631
+ bar:baz {
632
+ bip: bop }}
633
+ SCSS
634
+ end
635
+
636
+ def test_no_namespace_properties_without_space_even_when_its_unambiguous
637
+ render(<<SCSS)
638
+ foo {
639
+ bar:1px {
640
+ bip: bop }}
641
+ SCSS
642
+ assert(false, "Expected syntax error")
643
+ rescue Sass::SyntaxError => e
644
+ assert_equal <<MESSAGE, e.message
645
+ Invalid CSS: a space is required between a property and its definition
646
+ when it has other properties nested beneath it.
647
+ MESSAGE
648
+ assert_equal 2, e.sass_line
649
+ end
650
+
651
+ ## Mixins
652
+
653
+ def test_basic_mixins
654
+ assert_equal <<CSS, render(<<SCSS)
655
+ .foo {
656
+ a: b; }
657
+ CSS
658
+ @mixin foo {
659
+ .foo {a: b}}
660
+
661
+ @include foo;
662
+ SCSS
663
+
664
+ assert_equal <<CSS, render(<<SCSS)
665
+ bar {
666
+ c: d; }
667
+ bar .foo {
668
+ a: b; }
669
+ CSS
670
+ @mixin foo {
671
+ .foo {a: b}}
672
+
673
+ bar {
674
+ @include foo;
675
+ c: d; }
676
+ SCSS
677
+
678
+ assert_equal <<CSS, render(<<SCSS)
679
+ bar {
680
+ a: b;
681
+ c: d; }
682
+ CSS
683
+ @mixin foo {a: b}
684
+
685
+ bar {
686
+ @include foo;
687
+ c: d; }
688
+ SCSS
689
+ end
690
+
691
+ def test_mixins_with_empty_args
692
+ assert_equal <<CSS, render(<<SCSS)
693
+ .foo {
694
+ a: b; }
695
+ CSS
696
+ @mixin foo() {a: b}
697
+
698
+ .foo {@include foo();}
699
+ SCSS
700
+
701
+ assert_equal <<CSS, render(<<SCSS)
702
+ .foo {
703
+ a: b; }
704
+ CSS
705
+ @mixin foo() {a: b}
706
+
707
+ .foo {@include foo;}
708
+ SCSS
709
+
710
+ assert_equal <<CSS, render(<<SCSS)
711
+ .foo {
712
+ a: b; }
713
+ CSS
714
+ @mixin foo {a: b}
715
+
716
+ .foo {@include foo();}
717
+ SCSS
718
+ end
719
+
720
+ def test_mixins_with_args
721
+ assert_equal <<CSS, render(<<SCSS)
722
+ .foo {
723
+ a: bar; }
724
+ CSS
725
+ @mixin foo($a) {a: $a}
726
+
727
+ .foo {@include foo(bar)}
728
+ SCSS
729
+
730
+ assert_equal <<CSS, render(<<SCSS)
731
+ .foo {
732
+ a: bar;
733
+ b: 12px; }
734
+ CSS
735
+ @mixin foo($a, $b) {
736
+ a: $a;
737
+ b: $b; }
738
+
739
+ .foo {@include foo(bar, 12px)}
740
+ SCSS
741
+ end
742
+
743
+ ## Functions
744
+
745
+ def test_basic_function
746
+ assert_equal(<<CSS, render(<<SASS))
747
+ bar {
748
+ a: 3; }
749
+ CSS
750
+ @function foo() {
751
+ @return 1 + 2;
752
+ }
753
+
754
+ bar {
755
+ a: foo();
756
+ }
757
+ SASS
758
+ end
759
+
760
+ def test_function_args
761
+ assert_equal(<<CSS, render(<<SASS))
762
+ bar {
763
+ a: 3; }
764
+ CSS
765
+ @function plus($var1, $var2) {
766
+ @return $var1 + $var2;
767
+ }
768
+
769
+ bar {
770
+ a: plus(1, 2);
771
+ }
772
+ SASS
773
+ end
774
+
775
+ ## Var Args
776
+
777
+ def test_mixin_var_args
778
+ assert_equal <<CSS, render(<<SCSS)
779
+ .foo {
780
+ a: 1;
781
+ b: 2, 3, 4; }
782
+ CSS
783
+ @mixin foo($a, $b...) {
784
+ a: $a;
785
+ b: $b;
786
+ }
787
+
788
+ .foo {@include foo(1, 2, 3, 4)}
789
+ SCSS
790
+ end
791
+
792
+ def test_mixin_empty_var_args
793
+ assert_equal <<CSS, render(<<SCSS)
794
+ .foo {
795
+ a: 1;
796
+ b: 0; }
797
+ CSS
798
+ @mixin foo($a, $b...) {
799
+ a: $a;
800
+ b: length($b);
801
+ }
802
+
803
+ .foo {@include foo(1)}
804
+ SCSS
805
+ end
806
+
807
+ def test_mixin_var_args_act_like_list
808
+ assert_equal <<CSS, render(<<SCSS)
809
+ .foo {
810
+ a: 3;
811
+ b: 3; }
812
+ CSS
813
+ @mixin foo($a, $b...) {
814
+ a: length($b);
815
+ b: nth($b, 2);
816
+ }
817
+
818
+ .foo {@include foo(1, 2, 3, 4)}
819
+ SCSS
820
+ end
821
+
822
+ def test_mixin_splat_args
823
+ assert_equal <<CSS, render(<<SCSS)
824
+ .foo {
825
+ a: 1;
826
+ b: 2;
827
+ c: 3;
828
+ d: 4; }
829
+ CSS
830
+ @mixin foo($a, $b, $c, $d) {
831
+ a: $a;
832
+ b: $b;
833
+ c: $c;
834
+ d: $d;
835
+ }
836
+
837
+ $list: 2, 3, 4;
838
+ .foo {@include foo(1, $list...)}
839
+ SCSS
840
+ end
841
+
842
+ def test_mixin_splat_expression
843
+ assert_equal <<CSS, render(<<SCSS)
844
+ .foo {
845
+ a: 1;
846
+ b: 2;
847
+ c: 3;
848
+ d: 4; }
849
+ CSS
850
+ @mixin foo($a, $b, $c, $d) {
851
+ a: $a;
852
+ b: $b;
853
+ c: $c;
854
+ d: $d;
855
+ }
856
+
857
+ .foo {@include foo(1, (2, 3, 4)...)}
858
+ SCSS
859
+ end
860
+
861
+ def test_mixin_splat_args_with_var_args
862
+ assert_equal <<CSS, render(<<SCSS)
863
+ .foo {
864
+ a: 1;
865
+ b: 2, 3, 4; }
866
+ CSS
867
+ @mixin foo($a, $b...) {
868
+ a: $a;
869
+ b: $b;
870
+ }
871
+
872
+ $list: 2, 3, 4;
873
+ .foo {@include foo(1, $list...)}
874
+ SCSS
875
+ end
876
+
877
+ def test_mixin_splat_args_with_var_args_and_normal_args
878
+ assert_equal <<CSS, render(<<SCSS)
879
+ .foo {
880
+ a: 1;
881
+ b: 2;
882
+ c: 3, 4; }
883
+ CSS
884
+ @mixin foo($a, $b, $c...) {
885
+ a: $a;
886
+ b: $b;
887
+ c: $c;
888
+ }
889
+
890
+ $list: 2, 3, 4;
891
+ .foo {@include foo(1, $list...)}
892
+ SCSS
893
+ end
894
+
895
+ def test_mixin_splat_args_with_var_args_preserves_separator
896
+ assert_equal <<CSS, render(<<SCSS)
897
+ .foo {
898
+ a: 1;
899
+ b: 2 3 4 5; }
900
+ CSS
901
+ @mixin foo($a, $b...) {
902
+ a: $a;
903
+ b: $b;
904
+ }
905
+
906
+ $list: 3 4 5;
907
+ .foo {@include foo(1, 2, $list...)}
908
+ SCSS
909
+ end
910
+
911
+ def test_mixin_var_and_splat_args_pass_through_keywords
912
+ assert_equal <<CSS, render(<<SCSS)
913
+ .foo {
914
+ a: 3;
915
+ b: 1;
916
+ c: 2; }
917
+ CSS
918
+ @mixin foo($a...) {
919
+ @include bar($a...);
920
+ }
921
+
922
+ @mixin bar($b, $c, $a) {
923
+ a: $a;
924
+ b: $b;
925
+ c: $c;
926
+ }
927
+
928
+ .foo {@include foo(1, $c: 2, $a: 3)}
929
+ SCSS
930
+ end
931
+
932
+ def test_mixin_var_args_with_keyword
933
+ assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
934
+ @mixin foo($a, $b...) {
935
+ a: $a;
936
+ b: $b;
937
+ }
938
+
939
+ .foo {@include foo($a: 1, 2, 3, 4)}
940
+ SCSS
941
+ end
942
+
943
+ def test_mixin_keyword_for_var_arg
944
+ assert_raise_message(Sass::SyntaxError, "Argument $b of mixin foo cannot be used as a named argument.") {render <<SCSS}
945
+ @mixin foo($a, $b...) {
946
+ a: $a;
947
+ b: $b;
948
+ }
949
+
950
+ .foo {@include foo(1, $b: 2 3 4)}
951
+ SCSS
952
+ end
953
+
954
+ def test_mixin_keyword_for_unknown_arg_with_var_args
955
+ assert_raise_message(Sass::SyntaxError, "Mixin foo doesn't have an argument named $c.") {render <<SCSS}
956
+ @mixin foo($a, $b...) {
957
+ a: $a;
958
+ b: $b;
959
+ }
960
+
961
+ .foo {@include foo(1, $c: 2 3 4)}
962
+ SCSS
963
+ end
964
+
965
+ def test_function_var_args
966
+ assert_equal <<CSS, render(<<SCSS)
967
+ .foo {
968
+ val: "a: 1, b: 2, 3, 4"; }
969
+ CSS
970
+ @function foo($a, $b...) {
971
+ @return "a: \#{$a}, b: \#{$b}";
972
+ }
973
+
974
+ .foo {val: foo(1, 2, 3, 4)}
975
+ SCSS
976
+ end
977
+
978
+ def test_function_empty_var_args
979
+ assert_equal <<CSS, render(<<SCSS)
980
+ .foo {
981
+ val: "a: 1, b: 0"; }
982
+ CSS
983
+ @function foo($a, $b...) {
984
+ @return "a: \#{$a}, b: \#{length($b)}";
985
+ }
986
+
987
+ .foo {val: foo(1)}
988
+ SCSS
989
+ end
990
+
991
+ def test_function_var_args_act_like_list
992
+ assert_equal <<CSS, render(<<SCSS)
993
+ .foo {
994
+ val: "a: 3, b: 3"; }
995
+ CSS
996
+ @function foo($a, $b...) {
997
+ @return "a: \#{length($b)}, b: \#{nth($b, 2)}";
998
+ }
999
+
1000
+ .foo {val: foo(1, 2, 3, 4)}
1001
+ SCSS
1002
+ end
1003
+
1004
+ def test_function_splat_args
1005
+ assert_equal <<CSS, render(<<SCSS)
1006
+ .foo {
1007
+ val: "a: 1, b: 2, c: 3, d: 4"; }
1008
+ CSS
1009
+ @function foo($a, $b, $c, $d) {
1010
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
1011
+ }
1012
+
1013
+ $list: 2, 3, 4;
1014
+ .foo {val: foo(1, $list...)}
1015
+ SCSS
1016
+ end
1017
+
1018
+ def test_function_splat_expression
1019
+ assert_equal <<CSS, render(<<SCSS)
1020
+ .foo {
1021
+ val: "a: 1, b: 2, c: 3, d: 4"; }
1022
+ CSS
1023
+ @function foo($a, $b, $c, $d) {
1024
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}, d: \#{$d}";
1025
+ }
1026
+
1027
+ .foo {val: foo(1, (2, 3, 4)...)}
1028
+ SCSS
1029
+ end
1030
+
1031
+ def test_function_splat_args_with_var_args
1032
+ assert_equal <<CSS, render(<<SCSS)
1033
+ .foo {
1034
+ val: "a: 1, b: 2, 3, 4"; }
1035
+ CSS
1036
+ @function foo($a, $b...) {
1037
+ @return "a: \#{$a}, b: \#{$b}";
1038
+ }
1039
+
1040
+ $list: 2, 3, 4;
1041
+ .foo {val: foo(1, $list...)}
1042
+ SCSS
1043
+ end
1044
+
1045
+ def test_function_splat_args_with_var_args_and_normal_args
1046
+ assert_equal <<CSS, render(<<SCSS)
1047
+ .foo {
1048
+ val: "a: 1, b: 2, c: 3, 4"; }
1049
+ CSS
1050
+ @function foo($a, $b, $c...) {
1051
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1052
+ }
1053
+
1054
+ $list: 2, 3, 4;
1055
+ .foo {val: foo(1, $list...)}
1056
+ SCSS
1057
+ end
1058
+
1059
+ def test_function_splat_args_with_var_args_preserves_separator
1060
+ assert_equal <<CSS, render(<<SCSS)
1061
+ .foo {
1062
+ val: "a: 1, b: 2 3 4 5"; }
1063
+ CSS
1064
+ @function foo($a, $b...) {
1065
+ @return "a: \#{$a}, b: \#{$b}";
1066
+ }
1067
+
1068
+ $list: 3 4 5;
1069
+ .foo {val: foo(1, 2, $list...)}
1070
+ SCSS
1071
+ end
1072
+
1073
+ def test_function_var_and_splat_args_pass_through_keywords
1074
+ assert_equal <<CSS, render(<<SCSS)
1075
+ .foo {
1076
+ val: "a: 3, b: 1, c: 2"; }
1077
+ CSS
1078
+ @function foo($a...) {
1079
+ @return bar($a...);
1080
+ }
1081
+
1082
+ @function bar($b, $c, $a) {
1083
+ @return "a: \#{$a}, b: \#{$b}, c: \#{$c}";
1084
+ }
1085
+
1086
+ .foo {val: foo(1, $c: 2, $a: 3)}
1087
+ SCSS
1088
+ end
1089
+
1090
+ def test_function_var_args_with_keyword
1091
+ assert_raise_message(Sass::SyntaxError, "Positional arguments must come before keyword arguments.") {render <<SCSS}
1092
+ @function foo($a, $b...) {
1093
+ @return "a: \#{$a}, b: $b";
1094
+ }
1095
+
1096
+ .foo {val: foo($a: 1, 2, 3, 4)}
1097
+ SCSS
1098
+ end
1099
+
1100
+ def test_function_keyword_for_var_arg
1101
+ assert_raise_message(Sass::SyntaxError, "Argument $b of function foo cannot be used as a named argument.") {render <<SCSS}
1102
+ @function foo($a, $b...) {
1103
+ @return "a: \#{$a}, b: \#{$b}";
1104
+ }
1105
+
1106
+ .foo {val: foo(1, $b: 2 3 4)}
1107
+ SCSS
1108
+ end
1109
+
1110
+ def test_function_keyword_for_unknown_arg_with_var_args
1111
+ assert_raise_message(Sass::SyntaxError, "Function foo doesn't have an argument named $c.") {render <<SCSS}
1112
+ @function foo($a, $b...) {
1113
+ @return "a: \#{$a}, b: \#{$b}";
1114
+ }
1115
+
1116
+ .foo {val: foo(1, $c: 2 3 4)}
1117
+ SCSS
1118
+ end
1119
+
1120
+ def test_function_var_args_passed_to_native
1121
+ assert_equal <<CSS, render(<<SCSS)
1122
+ .foo {
1123
+ val: #102035; }
1124
+ CSS
1125
+ @function foo($args...) {
1126
+ @return adjust-color($args...);
1127
+ }
1128
+
1129
+ .foo {val: foo(#102030, $blue: 5)}
1130
+ SCSS
1131
+ end
1132
+
1133
+ ## Interpolation
1134
+
1135
+ def test_basic_selector_interpolation
1136
+ assert_equal <<CSS, render(<<SCSS)
1137
+ foo 3 baz {
1138
+ a: b; }
1139
+ CSS
1140
+ foo \#{1 + 2} baz {a: b}
1141
+ SCSS
1142
+ assert_equal <<CSS, render(<<SCSS)
1143
+ foo.bar baz {
1144
+ a: b; }
1145
+ CSS
1146
+ foo\#{".bar"} baz {a: b}
1147
+ SCSS
1148
+ assert_equal <<CSS, render(<<SCSS)
1149
+ foo.bar baz {
1150
+ a: b; }
1151
+ CSS
1152
+ \#{"foo"}.bar baz {a: b}
1153
+ SCSS
1154
+ end
1155
+
1156
+ def test_selector_only_interpolation
1157
+ assert_equal <<CSS, render(<<SCSS)
1158
+ foo bar {
1159
+ a: b; }
1160
+ CSS
1161
+ \#{"foo" + " bar"} {a: b}
1162
+ SCSS
1163
+ end
1164
+
1165
+ def test_selector_interpolation_before_element_name
1166
+ assert_equal <<CSS, render(<<SCSS)
1167
+ foo barbaz {
1168
+ a: b; }
1169
+ CSS
1170
+ \#{"foo" + " bar"}baz {a: b}
1171
+ SCSS
1172
+ end
1173
+
1174
+ def test_selector_interpolation_in_string
1175
+ assert_equal <<CSS, render(<<SCSS)
1176
+ foo[val="bar foo bar baz"] {
1177
+ a: b; }
1178
+ CSS
1179
+ foo[val="bar \#{"foo" + " bar"} baz"] {a: b}
1180
+ SCSS
1181
+ end
1182
+
1183
+ def test_selector_interpolation_in_pseudoclass
1184
+ assert_equal <<CSS, render(<<SCSS)
1185
+ foo:nth-child(5n) {
1186
+ a: b; }
1187
+ CSS
1188
+ foo:nth-child(\#{5 + "n"}) {a: b}
1189
+ SCSS
1190
+ end
1191
+
1192
+ def test_selector_interpolation_at_class_begininng
1193
+ assert_equal <<CSS, render(<<SCSS)
1194
+ .zzz {
1195
+ a: b; }
1196
+ CSS
1197
+ $zzz: zzz;
1198
+ .\#{$zzz} { a: b; }
1199
+ SCSS
1200
+ end
1201
+
1202
+ def test_selector_interpolation_at_id_begininng
1203
+ assert_equal <<CSS, render(<<SCSS)
1204
+ #zzz {
1205
+ a: b; }
1206
+ CSS
1207
+ $zzz: zzz;
1208
+ #\#{$zzz} { a: b; }
1209
+ SCSS
1210
+ end
1211
+
1212
+ def test_selector_interpolation_at_pseudo_begininng
1213
+ assert_equal <<CSS, render(<<SCSS)
1214
+ :zzz::zzz {
1215
+ a: b; }
1216
+ CSS
1217
+ $zzz: zzz;
1218
+ :\#{$zzz}::\#{$zzz} { a: b; }
1219
+ SCSS
1220
+ end
1221
+
1222
+ def test_selector_interpolation_at_attr_beginning
1223
+ assert_equal <<CSS, render(<<SCSS)
1224
+ [zzz=foo] {
1225
+ a: b; }
1226
+ CSS
1227
+ $zzz: zzz;
1228
+ [\#{$zzz}=foo] { a: b; }
1229
+ SCSS
1230
+ end
1231
+
1232
+ def test_selector_interpolation_at_attr_end
1233
+ assert_equal <<CSS, render(<<SCSS)
1234
+ [foo=zzz] {
1235
+ a: b; }
1236
+ CSS
1237
+ $zzz: zzz;
1238
+ [foo=\#{$zzz}] { a: b; }
1239
+ SCSS
1240
+ end
1241
+
1242
+ def test_selector_interpolation_at_dashes
1243
+ assert_equal <<CSS, render(<<SCSS)
1244
+ div {
1245
+ -foo-a-b-foo: foo; }
1246
+ CSS
1247
+ $a : a;
1248
+ $b : b;
1249
+ div { -foo-\#{$a}-\#{$b}-foo: foo }
1250
+ SCSS
1251
+ end
1252
+
1253
+ def test_selector_interpolation_in_reference_combinator
1254
+ assert_equal <<CSS, render(<<SCSS)
1255
+ .foo /a/ .bar /b|c/ .baz {
1256
+ a: b; }
1257
+ CSS
1258
+ $a: a;
1259
+ $b: b;
1260
+ $c: c;
1261
+ .foo /\#{$a}/ .bar /\#{$b}|\#{$c}/ .baz {a: b}
1262
+ SCSS
1263
+ end
1264
+
1265
+ def test_parent_selector_with_parent_and_subject
1266
+ assert_equal <<CSS, render(<<SCSS)
1267
+ bar foo.baz! .bip {
1268
+ c: d; }
1269
+ CSS
1270
+ $subject: "!";
1271
+ foo {
1272
+ bar &.baz\#{$subject} .bip {c: d}}
1273
+ SCSS
1274
+ end
1275
+
1276
+ def test_basic_prop_name_interpolation
1277
+ assert_equal <<CSS, render(<<SCSS)
1278
+ foo {
1279
+ barbazbang: blip; }
1280
+ CSS
1281
+ foo {bar\#{"baz" + "bang"}: blip}
1282
+ SCSS
1283
+ assert_equal <<CSS, render(<<SCSS)
1284
+ foo {
1285
+ bar3: blip; }
1286
+ CSS
1287
+ foo {bar\#{1 + 2}: blip}
1288
+ SCSS
1289
+ end
1290
+
1291
+ def test_prop_name_only_interpolation
1292
+ assert_equal <<CSS, render(<<SCSS)
1293
+ foo {
1294
+ bazbang: blip; }
1295
+ CSS
1296
+ foo {\#{"baz" + "bang"}: blip}
1297
+ SCSS
1298
+ end
1299
+
1300
+ def test_directive_interpolation
1301
+ assert_equal <<CSS, render(<<SCSS)
1302
+ @foo bar12 qux {
1303
+ a: b; }
1304
+ CSS
1305
+ $baz: 12;
1306
+ @foo bar\#{$baz} qux {a: b}
1307
+ SCSS
1308
+ end
1309
+
1310
+ def test_media_interpolation
1311
+ assert_equal <<CSS, render(<<SCSS)
1312
+ @media bar12 {
1313
+ a: b; }
1314
+ CSS
1315
+ $baz: 12;
1316
+ @media bar\#{$baz} {a: b}
1317
+ SCSS
1318
+ end
1319
+
1320
+ def test_script_in_media
1321
+ assert_equal <<CSS, render(<<SCSS)
1322
+ @media screen and (-webkit-min-device-pixel-ratio: 20), only print {
1323
+ a: b; }
1324
+ CSS
1325
+ $media1: screen;
1326
+ $media2: print;
1327
+ $var: -webkit-min-device-pixel-ratio;
1328
+ $val: 20;
1329
+ @media \#{$media1} and ($var: $val), only \#{$media2} {a: b}
1330
+ SCSS
1331
+
1332
+ assert_equal <<CSS, render(<<SCSS)
1333
+ @media screen and (-webkit-min-device-pixel-ratio: 13) {
1334
+ a: b; }
1335
+ CSS
1336
+ $vals: 1 2 3;
1337
+ @media screen and (-webkit-min-device-pixel-ratio: 5 + 6 + nth($vals, 2)) {a: b}
1338
+ SCSS
1339
+ end
1340
+
1341
+ def test_media_interpolation_with_reparse
1342
+ assert_equal <<CSS, render(<<SCSS)
1343
+ @media screen and (max-width: 300px) {
1344
+ a: b; }
1345
+ @media screen and (max-width: 300px) {
1346
+ a: b; }
1347
+ @media screen and (max-width: 300px) {
1348
+ a: b; }
1349
+ @media screen and (max-width: 300px), print and (max-width: 300px) {
1350
+ a: b; }
1351
+ CSS
1352
+ $constraint: "(max-width: 300px)";
1353
+ $fragment: "nd \#{$constraint}";
1354
+ $comma: "een, pri";
1355
+ @media screen and \#{$constraint} {a: b}
1356
+ @media screen {
1357
+ @media \#{$constraint} {a: b}
1358
+ }
1359
+ @media screen a\#{$fragment} {a: b}
1360
+ @media scr\#{$comma}nt {
1361
+ @media \#{$constraint} {a: b}
1362
+ }
1363
+ SCSS
1364
+ end
1365
+
1366
+ def test_moz_document_interpolation
1367
+ assert_equal <<CSS, render(<<SCSS)
1368
+ @-moz-document url(http://sass-lang.com/),
1369
+ url-prefix(http://sass-lang.com/docs),
1370
+ domain(sass-lang.com),
1371
+ domain("sass-lang.com") {
1372
+ .foo {
1373
+ a: b; } }
1374
+ CSS
1375
+ $domain: "sass-lang.com";
1376
+ @-moz-document url(http://\#{$domain}/),
1377
+ url-prefix(http://\#{$domain}/docs),
1378
+ domain(\#{$domain}),
1379
+ \#{domain($domain)} {
1380
+ .foo {a: b}
1381
+ }
1382
+ SCSS
1383
+ end
1384
+
1385
+ def test_supports_with_expressions
1386
+ assert_equal <<CSS, render(<<SCSS)
1387
+ @supports (feature1: val) and (feature2: val) or (not (feature23: val4)) {
1388
+ foo {
1389
+ a: b; } }
1390
+ CSS
1391
+ $query: "(feature1: val)";
1392
+ $feature: feature2;
1393
+ $val: val;
1394
+ @supports \#{$query} and ($feature: $val) or (not ($feature + 3: $val + 4)) {
1395
+ foo {a: b}
1396
+ }
1397
+ SCSS
1398
+ end
1399
+
1400
+ def test_supports_bubbling
1401
+ assert_equal <<CSS, render(<<SCSS)
1402
+ @supports (foo: bar) {
1403
+ a {
1404
+ b: c; }
1405
+ @supports (baz: bang) {
1406
+ a {
1407
+ d: e; } } }
1408
+ CSS
1409
+ a {
1410
+ @supports (foo: bar) {
1411
+ b: c;
1412
+ @supports (baz: bang) {
1413
+ d: e;
1414
+ }
1415
+ }
1416
+ }
1417
+ SCSS
1418
+ end
1419
+
1420
+ def test_random_directive_interpolation
1421
+ assert_equal <<CSS, render(<<SCSS)
1422
+ @foo url(http://sass-lang.com/),
1423
+ domain("sass-lang.com"),
1424
+ "foobarbaz",
1425
+ foobarbaz {
1426
+ .foo {
1427
+ a: b; } }
1428
+ CSS
1429
+ $domain: "sass-lang.com";
1430
+ @foo url(http://\#{$domain}/),
1431
+ \#{domain($domain)},
1432
+ "foo\#{'ba' + 'r'}baz",
1433
+ foo\#{'ba' + 'r'}baz {
1434
+ .foo {a: b}
1435
+ }
1436
+ SCSS
1437
+ end
1438
+
1439
+ def test_nested_mixin_def
1440
+ assert_equal <<CSS, render(<<SCSS)
1441
+ foo {
1442
+ a: b; }
1443
+ CSS
1444
+ foo {
1445
+ @mixin bar {a: b}
1446
+ @include bar; }
1447
+ SCSS
1448
+ end
1449
+
1450
+ def test_nested_mixin_shadow
1451
+ assert_equal <<CSS, render(<<SCSS)
1452
+ foo {
1453
+ c: d; }
1454
+
1455
+ baz {
1456
+ a: b; }
1457
+ CSS
1458
+ @mixin bar {a: b}
1459
+
1460
+ foo {
1461
+ @mixin bar {c: d}
1462
+ @include bar;
1463
+ }
1464
+
1465
+ baz {@include bar}
1466
+ SCSS
1467
+ end
1468
+
1469
+ def test_nested_function_def
1470
+ assert_equal <<CSS, render(<<SCSS)
1471
+ foo {
1472
+ a: 1; }
1473
+
1474
+ bar {
1475
+ b: foo(); }
1476
+ CSS
1477
+ foo {
1478
+ @function foo() {@return 1}
1479
+ a: foo(); }
1480
+
1481
+ bar {b: foo()}
1482
+ SCSS
1483
+ end
1484
+
1485
+ def test_nested_function_shadow
1486
+ assert_equal <<CSS, render(<<SCSS)
1487
+ foo {
1488
+ a: 2; }
1489
+
1490
+ baz {
1491
+ b: 1; }
1492
+ CSS
1493
+ @function foo() {@return 1}
1494
+
1495
+ foo {
1496
+ @function foo() {@return 2}
1497
+ a: foo();
1498
+ }
1499
+
1500
+ baz {b: foo()}
1501
+ SCSS
1502
+ end
1503
+
1504
+ ## Errors
1505
+
1506
+ def test_nested_mixin_def_is_scoped
1507
+ render <<SCSS
1508
+ foo {
1509
+ @mixin bar {a: b}}
1510
+ bar {@include bar}
1511
+ SCSS
1512
+ assert(false, "Expected syntax error")
1513
+ rescue Sass::SyntaxError => e
1514
+ assert_equal "Undefined mixin 'bar'.", e.message
1515
+ assert_equal 3, e.sass_line
1516
+ end
1517
+
1518
+ def test_rules_beneath_properties
1519
+ render <<SCSS
1520
+ foo {
1521
+ bar: {
1522
+ baz {
1523
+ bang: bop }}}
1524
+ SCSS
1525
+ assert(false, "Expected syntax error")
1526
+ rescue Sass::SyntaxError => e
1527
+ assert_equal 'Illegal nesting: Only properties may be nested beneath properties.', e.message
1528
+ assert_equal 3, e.sass_line
1529
+ end
1530
+
1531
+ def test_uses_property_exception_with_star_hack
1532
+ render <<SCSS
1533
+ foo {
1534
+ *bar:baz [fail]; }
1535
+ SCSS
1536
+ assert(false, "Expected syntax error")
1537
+ rescue Sass::SyntaxError => e
1538
+ assert_equal 'Invalid CSS after " *bar:baz ": expected ";", was "[fail]; }"', e.message
1539
+ assert_equal 2, e.sass_line
1540
+ end
1541
+
1542
+ def test_uses_property_exception_with_colon_hack
1543
+ render <<SCSS
1544
+ foo {
1545
+ :bar:baz [fail]; }
1546
+ SCSS
1547
+ assert(false, "Expected syntax error")
1548
+ rescue Sass::SyntaxError => e
1549
+ assert_equal 'Invalid CSS after " :bar:baz ": expected ";", was "[fail]; }"', e.message
1550
+ assert_equal 2, e.sass_line
1551
+ end
1552
+
1553
+ def test_uses_rule_exception_with_dot_hack
1554
+ render <<SCSS
1555
+ foo {
1556
+ .bar:baz <fail>; }
1557
+ SCSS
1558
+ assert(false, "Expected syntax error")
1559
+ rescue Sass::SyntaxError => e
1560
+ assert_equal 'Invalid CSS after " .bar:baz ": expected "{", was "<fail>; }"', e.message
1561
+ assert_equal 2, e.sass_line
1562
+ end
1563
+
1564
+ def test_uses_property_exception_with_space_after_name
1565
+ render <<SCSS
1566
+ foo {
1567
+ bar: baz [fail]; }
1568
+ SCSS
1569
+ assert(false, "Expected syntax error")
1570
+ rescue Sass::SyntaxError => e
1571
+ assert_equal 'Invalid CSS after " bar: baz ": expected ";", was "[fail]; }"', e.message
1572
+ assert_equal 2, e.sass_line
1573
+ end
1574
+
1575
+ def test_uses_property_exception_with_non_identifier_after_name
1576
+ render <<SCSS
1577
+ foo {
1578
+ bar:1px [fail]; }
1579
+ SCSS
1580
+ assert(false, "Expected syntax error")
1581
+ rescue Sass::SyntaxError => e
1582
+ assert_equal 'Invalid CSS after " bar:1px ": expected ";", was "[fail]; }"', e.message
1583
+ assert_equal 2, e.sass_line
1584
+ end
1585
+
1586
+ def test_uses_property_exception_when_followed_by_open_bracket
1587
+ render <<SCSS
1588
+ foo {
1589
+ bar:{baz: .fail} }
1590
+ SCSS
1591
+ assert(false, "Expected syntax error")
1592
+ rescue Sass::SyntaxError => e
1593
+ assert_equal 'Invalid CSS after " bar:{baz: ": expected expression (e.g. 1px, bold), was ".fail} }"', e.message
1594
+ assert_equal 2, e.sass_line
1595
+ end
1596
+
1597
+ def test_script_error
1598
+ render <<SCSS
1599
+ foo {
1600
+ bar: "baz" * * }
1601
+ SCSS
1602
+ assert(false, "Expected syntax error")
1603
+ rescue Sass::SyntaxError => e
1604
+ assert_equal 'Invalid CSS after " bar: "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message
1605
+ assert_equal 2, e.sass_line
1606
+ end
1607
+
1608
+ def test_multiline_script_syntax_error
1609
+ render <<SCSS
1610
+ foo {
1611
+ bar:
1612
+ "baz" * * }
1613
+ SCSS
1614
+ assert(false, "Expected syntax error")
1615
+ rescue Sass::SyntaxError => e
1616
+ assert_equal 'Invalid CSS after " "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message
1617
+ assert_equal 3, e.sass_line
1618
+ end
1619
+
1620
+ def test_multiline_script_runtime_error
1621
+ render <<SCSS
1622
+ foo {
1623
+ bar: "baz" +
1624
+ "bar" +
1625
+ $bang }
1626
+ SCSS
1627
+ assert(false, "Expected syntax error")
1628
+ rescue Sass::SyntaxError => e
1629
+ assert_equal "Undefined variable: \"$bang\".", e.message
1630
+ assert_equal 4, e.sass_line
1631
+ end
1632
+
1633
+ def test_post_multiline_script_runtime_error
1634
+ render <<SCSS
1635
+ foo {
1636
+ bar: "baz" +
1637
+ "bar" +
1638
+ "baz";
1639
+ bip: $bop; }
1640
+ SCSS
1641
+ assert(false, "Expected syntax error")
1642
+ rescue Sass::SyntaxError => e
1643
+ assert_equal "Undefined variable: \"$bop\".", e.message
1644
+ assert_equal 5, e.sass_line
1645
+ end
1646
+
1647
+ def test_multiline_property_runtime_error
1648
+ render <<SCSS
1649
+ foo {
1650
+ bar: baz
1651
+ bar
1652
+ \#{$bang} }
1653
+ SCSS
1654
+ assert(false, "Expected syntax error")
1655
+ rescue Sass::SyntaxError => e
1656
+ assert_equal "Undefined variable: \"$bang\".", e.message
1657
+ assert_equal 4, e.sass_line
1658
+ end
1659
+
1660
+ def test_post_resolution_selector_error
1661
+ render "\n\nfoo \#{\") bar\"} {a: b}"
1662
+ assert(false, "Expected syntax error")
1663
+ rescue Sass::SyntaxError => e
1664
+ assert_equal 'Invalid CSS after "foo ": expected selector, was ") bar"', e.message
1665
+ assert_equal 3, e.sass_line
1666
+ end
1667
+
1668
+ def test_parent_in_mid_selector_error
1669
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1670
+ Invalid CSS after " .foo": expected "{", was "&.bar {a: b}"
1671
+
1672
+ "&.bar" may only be used at the beginning of a compound selector.
1673
+ MESSAGE
1674
+ flim {
1675
+ .foo&.bar {a: b}
1676
+ }
1677
+ SCSS
1678
+ end
1679
+
1680
+ def test_parent_after_selector_error
1681
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1682
+ Invalid CSS after " .foo.bar": expected "{", was "& {a: b}"
1683
+
1684
+ "&" may only be used at the beginning of a compound selector.
1685
+ MESSAGE
1686
+ flim {
1687
+ .foo.bar& {a: b}
1688
+ }
1689
+ SCSS
1690
+ end
1691
+
1692
+ def test_double_parent_selector_error
1693
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1694
+ Invalid CSS after " &": expected "{", was "& {a: b}"
1695
+
1696
+ "&" may only be used at the beginning of a compound selector.
1697
+ MESSAGE
1698
+ flim {
1699
+ && {a: b}
1700
+ }
1701
+ SCSS
1702
+ end
1703
+
1704
+ def test_no_lonely_else
1705
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1706
+ Invalid CSS: @else must come after @if
1707
+ MESSAGE
1708
+ @else {foo: bar}
1709
+ SCSS
1710
+ end
1711
+
1712
+ # Regression
1713
+
1714
+ def test_loud_comment_in_compressed_mode
1715
+ assert_equal(<<CSS, render(<<SCSS))
1716
+ /*! foo */
1717
+ CSS
1718
+ /*! foo */
1719
+ SCSS
1720
+ end
1721
+
1722
+ def test_parsing_decimals_followed_by_comments_doesnt_take_forever
1723
+ assert_equal(<<CSS, render(<<SCSS))
1724
+ .foo {
1725
+ padding: 4.21053% 4.21053% 5.63158%; }
1726
+ CSS
1727
+ .foo {
1728
+ padding: 4.21052631578947% 4.21052631578947% 5.631578947368421% /**/
1729
+ }
1730
+ SCSS
1731
+ end
1732
+
1733
+ def test_parsing_many_numbers_doesnt_take_forever
1734
+ values = ["80% 90%"] * 1000
1735
+ assert_equal(<<CSS, render(<<SCSS))
1736
+ .foo {
1737
+ padding: #{values.join(', ')}; }
1738
+ CSS
1739
+ .foo {
1740
+ padding: #{values.join(', ')};
1741
+ }
1742
+ SCSS
1743
+ end
1744
+
1745
+ def test_import_comments_in_imports
1746
+ assert_equal(<<CSS, render(<<SCSS))
1747
+ @import url(foo.css);
1748
+ @import url(bar.css);
1749
+ @import url(baz.css);
1750
+ CSS
1751
+ @import "foo.css", // this is a comment
1752
+ "bar.css", /* this is another comment */
1753
+ "baz.css"; // this is a third comment
1754
+ SCSS
1755
+ end
1756
+
1757
+ def test_reference_combinator_with_parent_ref
1758
+ assert_equal <<CSS, render(<<SCSS)
1759
+ a /foo/ b {
1760
+ c: d; }
1761
+ CSS
1762
+ a {& /foo/ b {c: d}}
1763
+ SCSS
1764
+ end
1765
+
1766
+ def test_newline_selector_rendered_multiple_times
1767
+ assert_equal <<CSS, render(<<SCSS)
1768
+ form input,
1769
+ form select {
1770
+ color: white; }
1771
+
1772
+ form input,
1773
+ form select {
1774
+ color: white; }
1775
+ CSS
1776
+ @for $i from 1 through 2 {
1777
+ form {
1778
+ input,
1779
+ select {
1780
+ color: white;
1781
+ }
1782
+ }
1783
+ }
1784
+ SCSS
1785
+ end
1786
+
1787
+ def test_prop_name_interpolation_after_hyphen
1788
+ assert_equal <<CSS, render(<<SCSS)
1789
+ a {
1790
+ -foo-bar: b; }
1791
+ CSS
1792
+ a { -\#{"foo"}-bar: b; }
1793
+ SCSS
1794
+ end
1795
+
1796
+ def test_star_plus_and_parent
1797
+ assert_equal <<CSS, render(<<SCSS)
1798
+ * + html foo {
1799
+ a: b; }
1800
+ CSS
1801
+ foo {*+html & {a: b}}
1802
+ SCSS
1803
+ end
1804
+
1805
+ def test_weird_added_space
1806
+ assert_equal <<CSS, render(<<SCSS)
1807
+ foo {
1808
+ bar: -moz-bip; }
1809
+ CSS
1810
+ $value : bip;
1811
+
1812
+ foo {
1813
+ bar: -moz-\#{$value};
1814
+ }
1815
+ SCSS
1816
+ end
1817
+
1818
+ def test_interpolation_with_bracket_on_next_line
1819
+ assert_equal <<CSS, render(<<SCSS)
1820
+ a.foo b {
1821
+ color: red; }
1822
+ CSS
1823
+ a.\#{"foo"} b
1824
+ {color: red}
1825
+ SCSS
1826
+ end
1827
+
1828
+ def test_extra_comma_in_mixin_arglist_error
1829
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE.rstrip) {render <<SCSS}
1830
+ Invalid CSS after "...clude foo(bar, ": expected mixin argument, was ");"
1831
+ MESSAGE
1832
+ @mixin foo($a1, $a2) {
1833
+ baz: $a1 $a2;
1834
+ }
1835
+
1836
+ .bar {
1837
+ @include foo(bar, );
1838
+ }
1839
+ SCSS
1840
+ end
1841
+
1842
+ def test_interpolation
1843
+ assert_equal <<CSS, render(<<SCSS)
1844
+ ul li#foo a span.label {
1845
+ foo: bar; }
1846
+ CSS
1847
+ $bar : "#foo";
1848
+ ul li\#{$bar} a span.label { foo: bar; }
1849
+ SCSS
1850
+ end
1851
+
1852
+ def test_mixin_with_keyword_args
1853
+ assert_equal <<CSS, render(<<SCSS)
1854
+ .mixed {
1855
+ required: foo;
1856
+ arg1: default-val1;
1857
+ arg2: non-default-val2; }
1858
+ CSS
1859
+ @mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
1860
+ required: $required;
1861
+ arg1: $arg1;
1862
+ arg2: $arg2;
1863
+ }
1864
+ .mixed { @include a-mixin(foo, $arg2: non-default-val2); }
1865
+ SCSS
1866
+ end
1867
+
1868
+ def test_passing_required_args_as_a_keyword_arg
1869
+ assert_equal <<CSS, render(<<SCSS)
1870
+ .mixed {
1871
+ required: foo;
1872
+ arg1: default-val1;
1873
+ arg2: default-val2; }
1874
+ CSS
1875
+ @mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
1876
+ required: $required;
1877
+ arg1: $arg1;
1878
+ arg2: $arg2; }
1879
+ .mixed { @include a-mixin($required: foo); }
1880
+ SCSS
1881
+ end
1882
+
1883
+ def test_passing_all_as_keyword_args_in_opposite_order
1884
+ assert_equal <<CSS, render(<<SCSS)
1885
+ .mixed {
1886
+ required: foo;
1887
+ arg1: non-default-val1;
1888
+ arg2: non-default-val2; }
1889
+ CSS
1890
+ @mixin a-mixin($required, $arg1: default-val1, $arg2: default-val2) {
1891
+ required: $required;
1892
+ arg1: $arg1;
1893
+ arg2: $arg2; }
1894
+ .mixed { @include a-mixin($arg2: non-default-val2, $arg1: non-default-val1, $required: foo); }
1895
+ SCSS
1896
+ end
1897
+
1898
+ def test_keyword_args_in_functions
1899
+ assert_equal <<CSS, render(<<SCSS)
1900
+ .keyed {
1901
+ color: rgba(170, 119, 204, 0.4); }
1902
+ CSS
1903
+ .keyed { color: rgba($color: #a7c, $alpha: 0.4) }
1904
+ SCSS
1905
+ end
1906
+
1907
+ def test_unknown_keyword_arg_raises_error
1908
+ assert_raise_message(Sass::SyntaxError, "Mixin a doesn't have an argument named $c.") {render <<SCSS}
1909
+ @mixin a($b: 1) { a: $b; }
1910
+ div { @include a(1, $c: 3); }
1911
+ SCSS
1912
+ end
1913
+
1914
+
1915
+ def test_newlines_removed_from_selectors_when_compressed
1916
+ assert_equal <<CSS, render(<<SCSS, :style => :compressed)
1917
+ z a,z b{display:block}
1918
+ CSS
1919
+ a
1920
+ , b {
1921
+ z & {
1922
+ display: block;
1923
+ }
1924
+ }
1925
+ SCSS
1926
+ end
1927
+
1928
+ def test_if_error_line
1929
+ assert_raise_line(2) {render(<<SCSS)}
1930
+ @if true {foo: bar}
1931
+ }
1932
+ SCSS
1933
+ end
1934
+
1935
+ def test_multiline_var
1936
+ assert_equal <<CSS, render(<<SCSS)
1937
+ foo {
1938
+ a: 3;
1939
+ b: false;
1940
+ c: a b c; }
1941
+ CSS
1942
+ foo {
1943
+ $var1: 1 +
1944
+ 2;
1945
+ $var2: true and
1946
+ false;
1947
+ $var3: a b
1948
+ c;
1949
+ a: $var1;
1950
+ b: $var2;
1951
+ c: $var3; }
1952
+ SCSS
1953
+ end
1954
+
1955
+ def test_mixin_content
1956
+ assert_equal <<CSS, render(<<SASS)
1957
+ .parent {
1958
+ background-color: red;
1959
+ border-color: red; }
1960
+ .parent .child {
1961
+ background-color: yellow;
1962
+ color: blue;
1963
+ border-color: yellow; }
1964
+ CSS
1965
+ $color: blue;
1966
+ @mixin context($class, $color: red) {
1967
+ .\#{$class} {
1968
+ background-color: $color;
1969
+ @content;
1970
+ border-color: $color;
1971
+ }
1972
+ }
1973
+ @include context(parent) {
1974
+ @include context(child, $color: yellow) {
1975
+ color: $color;
1976
+ }
1977
+ }
1978
+ SASS
1979
+ end
1980
+
1981
+ def test_empty_content
1982
+ assert_equal <<CSS, render(<<SCSS)
1983
+ a {
1984
+ b: c; }
1985
+ CSS
1986
+ @mixin foo { @content }
1987
+ a { b: c; @include foo {} }
1988
+ SCSS
1989
+ end
1990
+
1991
+ def test_options_passed_to_script
1992
+ assert_equal <<CSS, render(<<SCSS, :style => :compressed)
1993
+ foo{color:#000}
1994
+ CSS
1995
+ foo {color: darken(black, 10%)}
1996
+ SCSS
1997
+ end
1998
+
1999
+ # ref: https://github.com/nex3/sass/issues/104
2000
+ def test_no_buffer_overflow
2001
+ template = render <<SCSS
2002
+ .aaa {
2003
+ background-color: white;
2004
+ }
2005
+ .aaa .aaa .aaa {
2006
+ background-color: black;
2007
+ }
2008
+ .bbb {
2009
+ @extend .aaa;
2010
+ }
2011
+ .xxx {
2012
+ @extend .bbb;
2013
+ }
2014
+ .yyy {
2015
+ @extend .bbb;
2016
+ }
2017
+ .zzz {
2018
+ @extend .bbb;
2019
+ }
2020
+ SCSS
2021
+ Sass::SCSS::Parser.new(template, "test.scss").parse
2022
+ end
2023
+
2024
+ def test_extend_in_media_in_rule
2025
+ assert_equal(<<CSS, render(<<SCSS))
2026
+ @media screen {
2027
+ .foo {
2028
+ a: b; } }
2029
+ CSS
2030
+ .foo {
2031
+ @media screen {
2032
+ @extend %bar;
2033
+ }
2034
+ }
2035
+
2036
+ @media screen {
2037
+ %bar {
2038
+ a: b;
2039
+ }
2040
+ }
2041
+ SCSS
2042
+ end
2043
+ end