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