aliddle-sass 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 (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