sass 3.3.0 → 3.4.25

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 (208) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/CONTRIBUTING.md +148 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +76 -62
  7. data/Rakefile +104 -24
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/VERSION_NAME +1 -1
  11. data/bin/sass +1 -1
  12. data/bin/scss +1 -1
  13. data/extra/sass-spec-ref.sh +32 -0
  14. data/extra/update_watch.rb +1 -1
  15. data/lib/sass/cache_stores/filesystem.rb +9 -5
  16. data/lib/sass/cache_stores/memory.rb +4 -5
  17. data/lib/sass/callbacks.rb +2 -2
  18. data/lib/sass/css.rb +12 -13
  19. data/lib/sass/deprecation.rb +55 -0
  20. data/lib/sass/engine.rb +106 -70
  21. data/lib/sass/environment.rb +39 -19
  22. data/lib/sass/error.rb +17 -20
  23. data/lib/sass/exec/base.rb +199 -0
  24. data/lib/sass/exec/sass_convert.rb +283 -0
  25. data/lib/sass/exec/sass_scss.rb +440 -0
  26. data/lib/sass/exec.rb +5 -771
  27. data/lib/sass/features.rb +9 -2
  28. data/lib/sass/importers/base.rb +8 -3
  29. data/lib/sass/importers/filesystem.rb +30 -38
  30. data/lib/sass/logger/base.rb +8 -2
  31. data/lib/sass/logger/delayed.rb +50 -0
  32. data/lib/sass/logger.rb +8 -3
  33. data/lib/sass/media.rb +1 -4
  34. data/lib/sass/plugin/compiler.rb +224 -90
  35. data/lib/sass/plugin/configuration.rb +38 -22
  36. data/lib/sass/plugin/merb.rb +2 -2
  37. data/lib/sass/plugin/rack.rb +3 -3
  38. data/lib/sass/plugin/rails.rb +1 -1
  39. data/lib/sass/plugin/staleness_checker.rb +4 -4
  40. data/lib/sass/plugin.rb +6 -5
  41. data/lib/sass/script/css_lexer.rb +1 -1
  42. data/lib/sass/script/css_parser.rb +2 -3
  43. data/lib/sass/script/css_variable_warning.rb +52 -0
  44. data/lib/sass/script/functions.rb +739 -318
  45. data/lib/sass/script/lexer.rb +134 -54
  46. data/lib/sass/script/parser.rb +252 -56
  47. data/lib/sass/script/tree/funcall.rb +13 -6
  48. data/lib/sass/script/tree/interpolation.rb +127 -4
  49. data/lib/sass/script/tree/list_literal.rb +31 -4
  50. data/lib/sass/script/tree/literal.rb +4 -0
  51. data/lib/sass/script/tree/node.rb +21 -3
  52. data/lib/sass/script/tree/operation.rb +54 -1
  53. data/lib/sass/script/tree/selector.rb +26 -0
  54. data/lib/sass/script/tree/string_interpolation.rb +59 -38
  55. data/lib/sass/script/tree/variable.rb +1 -1
  56. data/lib/sass/script/tree.rb +1 -0
  57. data/lib/sass/script/value/base.rb +17 -14
  58. data/lib/sass/script/value/bool.rb +0 -5
  59. data/lib/sass/script/value/color.rb +78 -42
  60. data/lib/sass/script/value/helpers.rb +119 -2
  61. data/lib/sass/script/value/list.rb +0 -15
  62. data/lib/sass/script/value/map.rb +1 -1
  63. data/lib/sass/script/value/null.rb +0 -5
  64. data/lib/sass/script/value/number.rb +112 -31
  65. data/lib/sass/script/value/string.rb +102 -13
  66. data/lib/sass/script/value.rb +0 -1
  67. data/lib/sass/script.rb +3 -3
  68. data/lib/sass/scss/css_parser.rb +24 -4
  69. data/lib/sass/scss/parser.rb +290 -383
  70. data/lib/sass/scss/rx.rb +17 -9
  71. data/lib/sass/scss/static_parser.rb +306 -4
  72. data/lib/sass/scss.rb +0 -2
  73. data/lib/sass/selector/abstract_sequence.rb +35 -18
  74. data/lib/sass/selector/comma_sequence.rb +114 -19
  75. data/lib/sass/selector/pseudo.rb +266 -0
  76. data/lib/sass/selector/sequence.rb +146 -40
  77. data/lib/sass/selector/simple.rb +22 -33
  78. data/lib/sass/selector/simple_sequence.rb +122 -39
  79. data/lib/sass/selector.rb +57 -197
  80. data/lib/sass/shared.rb +2 -2
  81. data/lib/sass/source/map.rb +31 -14
  82. data/lib/sass/source/position.rb +4 -4
  83. data/lib/sass/stack.rb +2 -8
  84. data/lib/sass/supports.rb +10 -13
  85. data/lib/sass/tree/at_root_node.rb +1 -0
  86. data/lib/sass/tree/charset_node.rb +1 -1
  87. data/lib/sass/tree/comment_node.rb +1 -1
  88. data/lib/sass/tree/css_import_node.rb +9 -1
  89. data/lib/sass/tree/directive_node.rb +8 -2
  90. data/lib/sass/tree/error_node.rb +18 -0
  91. data/lib/sass/tree/extend_node.rb +1 -1
  92. data/lib/sass/tree/function_node.rb +9 -0
  93. data/lib/sass/tree/import_node.rb +6 -5
  94. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  95. data/lib/sass/tree/node.rb +5 -3
  96. data/lib/sass/tree/prop_node.rb +6 -7
  97. data/lib/sass/tree/rule_node.rb +26 -11
  98. data/lib/sass/tree/visitors/check_nesting.rb +56 -32
  99. data/lib/sass/tree/visitors/convert.rb +59 -44
  100. data/lib/sass/tree/visitors/cssize.rb +34 -30
  101. data/lib/sass/tree/visitors/deep_copy.rb +6 -1
  102. data/lib/sass/tree/visitors/extend.rb +15 -13
  103. data/lib/sass/tree/visitors/perform.rb +87 -50
  104. data/lib/sass/tree/visitors/set_options.rb +15 -1
  105. data/lib/sass/tree/visitors/to_css.rb +72 -43
  106. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  107. data/lib/sass/util/normalized_map.rb +0 -1
  108. data/lib/sass/util/subset_map.rb +2 -3
  109. data/lib/sass/util.rb +334 -154
  110. data/lib/sass/version.rb +7 -7
  111. data/lib/sass.rb +10 -8
  112. data/test/sass/cache_test.rb +62 -20
  113. data/test/sass/callbacks_test.rb +1 -1
  114. data/test/sass/compiler_test.rb +24 -11
  115. data/test/sass/conversion_test.rb +241 -50
  116. data/test/sass/css2sass_test.rb +73 -5
  117. data/test/sass/css_variable_test.rb +132 -0
  118. data/test/sass/encoding_test.rb +219 -0
  119. data/test/sass/engine_test.rb +343 -260
  120. data/test/sass/exec_test.rb +12 -2
  121. data/test/sass/extend_test.rb +333 -44
  122. data/test/sass/functions_test.rb +353 -260
  123. data/test/sass/importer_test.rb +40 -21
  124. data/test/sass/logger_test.rb +1 -1
  125. data/test/sass/more_results/more_import.css +1 -1
  126. data/test/sass/more_templates/more1.sass +10 -10
  127. data/test/sass/more_templates/more_import.sass +2 -2
  128. data/test/sass/plugin_test.rb +24 -21
  129. data/test/sass/results/compact.css +1 -1
  130. data/test/sass/results/complex.css +4 -4
  131. data/test/sass/results/expanded.css +1 -1
  132. data/test/sass/results/import.css +1 -1
  133. data/test/sass/results/import_charset_ibm866.css +2 -2
  134. data/test/sass/results/mixins.css +17 -17
  135. data/test/sass/results/nested.css +1 -1
  136. data/test/sass/results/parent_ref.css +2 -2
  137. data/test/sass/results/script.css +5 -5
  138. data/test/sass/results/scss_import.css +1 -1
  139. data/test/sass/script_conversion_test.rb +71 -39
  140. data/test/sass/script_test.rb +714 -123
  141. data/test/sass/scss/css_test.rb +213 -30
  142. data/test/sass/scss/rx_test.rb +8 -4
  143. data/test/sass/scss/scss_test.rb +766 -22
  144. data/test/sass/source_map_test.rb +263 -95
  145. data/test/sass/superselector_test.rb +210 -0
  146. data/test/sass/templates/_partial.sass +1 -1
  147. data/test/sass/templates/basic.sass +10 -10
  148. data/test/sass/templates/bork1.sass +1 -1
  149. data/test/sass/templates/bork5.sass +1 -1
  150. data/test/sass/templates/compact.sass +10 -10
  151. data/test/sass/templates/complex.sass +187 -187
  152. data/test/sass/templates/compressed.sass +10 -10
  153. data/test/sass/templates/expanded.sass +10 -10
  154. data/test/sass/templates/import.sass +2 -2
  155. data/test/sass/templates/importee.sass +3 -3
  156. data/test/sass/templates/mixins.sass +22 -22
  157. data/test/sass/templates/multiline.sass +4 -4
  158. data/test/sass/templates/nested.sass +13 -13
  159. data/test/sass/templates/parent_ref.sass +12 -12
  160. data/test/sass/templates/script.sass +70 -70
  161. data/test/sass/templates/scss_import.scss +2 -1
  162. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  163. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  164. data/test/sass/templates/subdir/subdir.sass +3 -3
  165. data/test/sass/templates/units.sass +10 -10
  166. data/test/sass/test_helper.rb +1 -1
  167. data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
  168. data/test/sass/util/normalized_map_test.rb +1 -1
  169. data/test/sass/util/subset_map_test.rb +2 -2
  170. data/test/sass/util_test.rb +46 -45
  171. data/test/sass/value_helpers_test.rb +5 -7
  172. data/test/sass-spec.yml +3 -0
  173. data/test/test_helper.rb +7 -6
  174. data/vendor/listen/CHANGELOG.md +1 -228
  175. data/vendor/listen/Gemfile +5 -15
  176. data/vendor/listen/README.md +111 -77
  177. data/vendor/listen/Rakefile +0 -42
  178. data/vendor/listen/lib/listen/adapter.rb +195 -82
  179. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  180. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  181. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  182. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  183. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  184. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  185. data/vendor/listen/lib/listen/listener.rb +135 -37
  186. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  187. data/vendor/listen/lib/listen/version.rb +1 -1
  188. data/vendor/listen/lib/listen.rb +33 -19
  189. data/vendor/listen/listen.gemspec +6 -0
  190. data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
  191. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  192. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  193. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  194. data/vendor/listen/spec/listen_spec.rb +15 -21
  195. data/vendor/listen/spec/spec_helper.rb +4 -0
  196. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  197. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  198. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  199. metadata +310 -300
  200. data/CONTRIBUTING +0 -3
  201. data/ext/mkrf_conf.rb +0 -27
  202. data/lib/sass/script/value/deprecated_false.rb +0 -55
  203. data/lib/sass/scss/script_lexer.rb +0 -15
  204. data/lib/sass/scss/script_parser.rb +0 -25
  205. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  206. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  207. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  208. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
2
3
  require File.dirname(__FILE__) + '/../test_helper'
3
4
  require 'sass/engine'
4
5
 
@@ -17,35 +18,67 @@ module Sass::Script::Functions
17
18
  include Sass::Script::Functions::UserFunctions
18
19
  end
19
20
 
20
- class SassScriptTest < Test::Unit::TestCase
21
+ class SassScriptTest < MiniTest::Test
21
22
  include Sass::Script
22
23
 
23
- def test_color_checks_input
24
- assert_raise_message(ArgumentError, "Blue value -1 must be between 0 and 255") {Sass::Script::Value::Color.new([1, 2, -1])}
25
- assert_raise_message(ArgumentError, "Red value 256 must be between 0 and 255") {Sass::Script::Value::Color.new([256, 2, 3])}
24
+ def test_color_clamps_input
25
+ assert_equal 0, Sass::Script::Value::Color.new([1, 2, -1]).blue
26
+ assert_equal 255, Sass::Script::Value::Color.new([256, 2, 3]).red
26
27
  end
27
28
 
28
- def test_color_checks_rgba_input
29
- assert_raise_message(ArgumentError, "Alpha channel 1.1 must be between 0 and 1") {Sass::Script::Value::Color.new([1, 2, 3, 1.1])}
30
- assert_raise_message(ArgumentError, "Alpha channel -0.1 must be between 0 and 1") {Sass::Script::Value::Color.new([1, 2, 3, -0.1])}
29
+ def test_color_clamps_rgba_input
30
+ assert_equal 1, Sass::Script::Value::Color.new([1, 2, 3, 1.1]).alpha
31
+ assert_equal 0, Sass::Script::Value::Color.new([1, 2, 3, -0.1]).alpha
32
+ end
33
+
34
+ def test_color_from_hex
35
+ assert_equal Sass::Script::Value::Color.new([0,0,0]), Sass::Script::Value::Color.from_hex('000000')
36
+ assert_equal Sass::Script::Value::Color.new([0,0,0]), Sass::Script::Value::Color.from_hex('#000000')
31
37
  end
32
38
 
33
39
  def test_string_escapes
34
40
  assert_equal "'", resolve("\"'\"")
35
41
  assert_equal '"', resolve("\"\\\"\"")
36
- assert_equal "\\\\", resolve("\"\\\\\"")
37
- assert_equal "\\02fa", resolve("\"\\02fa\"")
38
-
39
- assert_equal "'", resolve("'\\''")
40
- assert_equal '"', resolve("'\"'")
41
- assert_equal "\\\\", resolve("'\\\\'")
42
- assert_equal "\\02fa", resolve("'\\02fa'")
42
+ assert_equal "\\", resolve("\"\\\\\"")
43
+ assert_equal "", resolve("\"\\2603\"")
44
+ assert_equal "☃f", resolve("\"\\2603 f\"")
45
+ assert_equal "☃x", resolve("\"\\2603x\"")
46
+ assert_equal "\\2603", resolve("\"\\\\2603\"")
47
+ assert_equal "\#{foo}", resolve("\"\\\#{foo}\"")
48
+
49
+ # U+FFFD is the replacement character, "�".
50
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\0\"")
51
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\FFFFFF\"")
52
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\D800\"")
53
+ assert_equal [0xD7FF].pack("U"), resolve("\"\\D7FF\"")
54
+ assert_equal [0xFFFD].pack("U"), resolve("\"\\DFFF\"")
55
+ assert_equal [0xE000].pack("U"), resolve("\"\\E000\"")
56
+ end
57
+
58
+ def test_string_escapes_are_resolved_before_operators
59
+ assert_equal "true", resolve('"abc" == "\61\62\63"')
60
+ end
61
+
62
+ def test_string_quote
63
+ assert_equal '"foo"', resolve_quoted('"foo"')
64
+ assert_equal "'f\"oo'", resolve_quoted('"f\"oo"')
65
+ assert_equal "\"f'oo\"", resolve_quoted("'f\\'oo'")
66
+ assert_equal "\"f'o\\\"o\"", resolve_quoted("'f\\'o\"o'")
67
+ assert_equal '"foo bar"', resolve_quoted('"foo\20 bar"')
68
+ assert_equal '"foo\a bar"', resolve_quoted('"foo\a bar"')
69
+ assert_equal '"x\ay"', resolve_quoted('"x\a y"')
70
+ assert_equal '"\a "', resolve_quoted('"\a\20"')
71
+ assert_equal '"\a abcdef"', resolve_quoted('"\a abcdef"')
72
+ assert_equal '"☃abcdef"', resolve_quoted('"\2603 abcdef"')
73
+ assert_equal '"\\\\"', resolve_quoted('"\\\\"')
74
+ assert_equal '"foobar"', resolve_quoted("\"foo\\\nbar\"")
75
+ assert_equal '"#{foo}"', resolve_quoted("\"\\\#{foo}\"")
43
76
  end
44
77
 
45
78
  def test_color_names
46
79
  assert_equal "white", resolve("white")
47
- assert_equal "white", resolve("#ffffff")
48
- assert_equal "#fffffe", resolve("white - #000001")
80
+ assert_equal "#ffffff", resolve("#ffffff")
81
+ silence_warnings {assert_equal "#fffffe", resolve("white - #000001")}
49
82
  assert_equal "transparent", resolve("transparent")
50
83
  assert_equal "transparent", resolve("rgba(0, 0, 0, 0)")
51
84
  end
@@ -64,36 +97,63 @@ class SassScriptTest < Test::Unit::TestCase
64
97
  end
65
98
 
66
99
  def test_rgba_color_math
67
- assert_equal "rgba(50, 50, 100, 0.35)", resolve("rgba(1, 1, 2, 0.35) * rgba(50, 50, 50, 0.35)")
68
- assert_equal "rgba(52, 52, 52, 0.25)", resolve("rgba(2, 2, 2, 0.25) + rgba(50, 50, 50, 0.25)")
100
+ silence_warnings {assert_equal "rgba(50, 50, 100, 0.35)", resolve("rgba(1, 1, 2, 0.35) * rgba(50, 50, 50, 0.35)")}
101
+ silence_warnings {assert_equal "rgba(52, 52, 52, 0.25)", resolve("rgba(2, 2, 2, 0.25) + rgba(50, 50, 50, 0.25)")}
69
102
 
70
103
  assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)") do
71
- resolve("rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)")
104
+ silence_warnings {resolve("rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)")}
72
105
  end
73
106
  assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: #123456 * rgba(50, 50, 50, 0.75)") do
74
- resolve("#123456 * rgba(50, 50, 50, 0.75)")
107
+ silence_warnings {resolve("#123456 * rgba(50, 50, 50, 0.75)")}
75
108
  end
76
109
  assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(50, 50, 50, 0.75) / #123456") do
77
- resolve("rgba(50, 50, 50, 0.75) / #123456")
110
+ silence_warnings {resolve("rgba(50, 50, 50, 0.75) / #123456")}
78
111
  end
79
112
  end
80
113
 
81
114
  def test_rgba_number_math
82
- assert_equal "rgba(49, 49, 49, 0.75)", resolve("rgba(50, 50, 50, 0.75) - 1")
83
- assert_equal "rgba(100, 100, 100, 0.75)", resolve("rgba(50, 50, 50, 0.75) * 2")
115
+ silence_warnings {assert_equal "rgba(49, 49, 49, 0.75)", resolve("rgba(50, 50, 50, 0.75) - 1")}
116
+ silence_warnings {assert_equal "rgba(100, 100, 100, 0.75)", resolve("rgba(50, 50, 50, 0.75) * 2")}
84
117
  end
85
118
 
86
119
  def test_rgba_rounding
87
120
  assert_equal "rgba(10, 1, 0, 0.12346)", resolve("rgba(10.0, 1.23456789, 0.0, 0.1234567)")
88
121
  end
89
122
 
123
+ def test_rgb_calc
124
+ assert_equal "rgb(calc(255 - 5), 0, 0)", resolve("rgb(calc(255 - 5), 0, 0)")
125
+ end
126
+
127
+ def test_rgba_calc
128
+ assert_equal "rgba(calc(255 - 5), 0, 0, 0.1)",
129
+ resolve("rgba(calc(255 - 5), 0, 0, 0.1)")
130
+ assert_equal "rgba(127, 0, 0, calc(0.1 + 0.5))",
131
+ resolve("rgba(127, 0, 0, calc(0.1 + 0.5))")
132
+ end
133
+
134
+ def test_rgba_shorthand_calc
135
+ assert_equal "rgba(255, 0, 0, calc(0.1 + 0.5))",
136
+ resolve("rgba(red, calc(0.1 + 0.5))")
137
+ end
138
+
139
+ def test_hsl_calc
140
+ assert_equal "hsl(calc(360 * 5 / 6), 50%, 50%)", resolve("hsl(calc(360 * 5 / 6), 50%, 50%)")
141
+ end
142
+
143
+ def test_hsla_calc
144
+ assert_equal "hsla(calc(360 * 5 / 6), 50%, 50%, 0.1)",
145
+ resolve("hsla(calc(360 * 5 / 6), 50%, 50%, 0.1)")
146
+ assert_equal "hsla(270, 50%, 50%, calc(0.1 + 0.1))",
147
+ resolve("hsla(270, 50%, 50%, calc(0.1 + 0.1))")
148
+ end
149
+
90
150
  def test_compressed_colors
91
151
  assert_equal "#123456", resolve("#123456", :style => :compressed)
92
152
  assert_equal "rgba(1,2,3,0.5)", resolve("rgba(1, 2, 3, 0.5)", :style => :compressed)
93
153
  assert_equal "#123", resolve("#112233", :style => :compressed)
94
154
  assert_equal "#000", resolve("black", :style => :compressed)
95
155
  assert_equal "red", resolve("#f00", :style => :compressed)
96
- assert_equal "blue", resolve("#00f", :style => :compressed)
156
+ assert_equal "blue", resolve("blue", :style => :compressed)
97
157
  assert_equal "navy", resolve("#000080", :style => :compressed)
98
158
  assert_equal "navy #fff", resolve("#000080 white", :style => :compressed)
99
159
  assert_equal "This color is #fff", resolve('"This color is #{ white }"', :style => :compressed)
@@ -131,43 +191,45 @@ class SassScriptTest < Test::Unit::TestCase
131
191
  end
132
192
 
133
193
  def test_interpolation_near_operators
134
- assert_equal '3 , 7', resolve('#{1 + 2} , #{3 + 4}')
135
- assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}')
136
- assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}')
137
- assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}')
138
- assert_equal '3, 7, 11', resolve('#{1 + 2}, #{3 + 4}, #{5 + 6}')
139
- assert_equal '3, 7, 11', resolve('3, #{3 + 4}, 11')
140
- assert_equal '3, 7, 11', resolve('3, 7, #{5 + 6}')
141
-
142
- assert_equal '3 / 7', resolve('3 / #{3 + 4}')
143
- assert_equal '3 /7', resolve('3 /#{3 + 4}')
144
- assert_equal '3/ 7', resolve('3/ #{3 + 4}')
145
- assert_equal '3/7', resolve('3/#{3 + 4}')
146
-
147
- assert_equal '3 * 7', resolve('#{1 + 2} * 7')
148
- assert_equal '3* 7', resolve('#{1 + 2}* 7')
149
- assert_equal '3 *7', resolve('#{1 + 2} *7')
150
- assert_equal '3*7', resolve('#{1 + 2}*7')
151
-
152
- assert_equal '-3', resolve('-#{1 + 2}')
153
- assert_equal '- 3', resolve('- #{1 + 2}')
154
-
155
- assert_equal '5 + 3 * 7', resolve('5 + #{1 + 2} * #{3 + 4}')
156
- assert_equal '5 +3 * 7', resolve('5 +#{1 + 2} * #{3 + 4}')
157
- assert_equal '5+3 * 7', resolve('5+#{1 + 2} * #{3 + 4}')
158
- assert_equal '3 * 7 + 5', resolve('#{1 + 2} * #{3 + 4} + 5')
159
- assert_equal '3 * 7+ 5', resolve('#{1 + 2} * #{3 + 4}+ 5')
160
- assert_equal '3 * 7+5', resolve('#{1 + 2} * #{3 + 4}+5')
161
-
162
- assert_equal '5/3 + 7', resolve('5 / (#{1 + 2} + #{3 + 4})')
163
- assert_equal '5/3 + 7', resolve('5 /(#{1 + 2} + #{3 + 4})')
164
- assert_equal '5/3 + 7', resolve('5 /( #{1 + 2} + #{3 + 4} )')
165
- assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4}) / 5')
166
- assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4})/ 5')
167
- assert_equal '3 + 7/5', resolve('( #{1 + 2} + #{3 + 4} )/ 5')
168
-
169
- assert_equal '3 + 5', resolve('#{1 + 2} + 2 + 3')
170
- assert_equal '3 +5', resolve('#{1 + 2} +2 + 3')
194
+ silence_warnings do
195
+ assert_equal '3 , 7', resolve('#{1 + 2} , #{3 + 4}')
196
+ assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}')
197
+ assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}')
198
+ assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}')
199
+ assert_equal '3, 7, 11', resolve('#{1 + 2}, #{3 + 4}, #{5 + 6}')
200
+ assert_equal '3, 7, 11', resolve('3, #{3 + 4}, 11')
201
+ assert_equal '3, 7, 11', resolve('3, 7, #{5 + 6}')
202
+
203
+ assert_equal '3 / 7', resolve('3 / #{3 + 4}')
204
+ assert_equal '3 /7', resolve('3 /#{3 + 4}')
205
+ assert_equal '3/ 7', resolve('3/ #{3 + 4}')
206
+ assert_equal '3/7', resolve('3/#{3 + 4}')
207
+
208
+ assert_equal '3 * 7', resolve('#{1 + 2} * 7')
209
+ assert_equal '3* 7', resolve('#{1 + 2}* 7')
210
+ assert_equal '3 *7', resolve('#{1 + 2} *7')
211
+ assert_equal '3*7', resolve('#{1 + 2}*7')
212
+
213
+ assert_equal '-3', resolve('-#{1 + 2}')
214
+ assert_equal '- 3', resolve('- #{1 + 2}')
215
+
216
+ assert_equal '5 + 3 * 7', resolve('5 + #{1 + 2} * #{3 + 4}')
217
+ assert_equal '5 +3 * 7', resolve('5 +#{1 + 2} * #{3 + 4}')
218
+ assert_equal '5+3 * 7', resolve('5+#{1 + 2} * #{3 + 4}')
219
+ assert_equal '3 * 7 + 5', resolve('#{1 + 2} * #{3 + 4} + 5')
220
+ assert_equal '3 * 7+ 5', resolve('#{1 + 2} * #{3 + 4}+ 5')
221
+ assert_equal '3 * 7+5', resolve('#{1 + 2} * #{3 + 4}+5')
222
+
223
+ assert_equal '5/3 + 7', resolve('5 / (#{1 + 2} + #{3 + 4})')
224
+ assert_equal '5/3 + 7', resolve('5 /(#{1 + 2} + #{3 + 4})')
225
+ assert_equal '5/3 + 7', resolve('5 /( #{1 + 2} + #{3 + 4} )')
226
+ assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4}) / 5')
227
+ assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4})/ 5')
228
+ assert_equal '3 + 7/5', resolve('( #{1 + 2} + #{3 + 4} )/ 5')
229
+
230
+ assert_equal '3 + 5', resolve('#{1 + 2} + 2 + 3')
231
+ assert_equal '3 +5', resolve('#{1 + 2} +2 + 3')
232
+ end
171
233
  end
172
234
 
173
235
  def test_string_interpolation
@@ -180,6 +242,18 @@ class SassScriptTest < Test::Unit::TestCase
180
242
  assert_equal "foo1bar5baz4bang", resolve('\'foo#{1 + "bar#{2 + 3}baz" + 4}bang\'')
181
243
  end
182
244
 
245
+ def test_interpolation_in_interpolation
246
+ assert_equal 'foo', resolve('#{#{foo}}')
247
+ assert_equal 'foo', resolve('"#{#{foo}}"')
248
+ assert_equal 'foo', resolve('#{"#{foo}"}')
249
+ assert_equal 'foo', resolve('"#{"#{foo}"}"')
250
+ end
251
+
252
+ def test_interpolation_with_newline
253
+ assert_equal "\nbang", resolve('"#{"\a "}bang"')
254
+ assert_equal "\n\nbang", resolve('"#{"\a "}\a bang"')
255
+ end
256
+
183
257
  def test_rule_interpolation
184
258
  assert_equal(<<CSS, render(<<SASS))
185
259
  foo bar baz bang {
@@ -255,8 +329,8 @@ SASS
255
329
  assert_equal eval('1 2 3.0'), eval('1 2 3')
256
330
  assert_equal eval('1, 2, 3.0'), eval('1, 2, 3')
257
331
  assert_equal eval('(1 2), (3, 4), (5 6)'), eval('(1 2), (3, 4), (5 6)')
258
- assert_not_equal eval('1, 2, 3'), eval('1 2 3')
259
- assert_not_equal eval('1'), eval('"1"')
332
+ refute_equal eval('1, 2, 3'), eval('1 2 3')
333
+ refute_equal eval('1'), eval('"1"')
260
334
  end
261
335
 
262
336
  def test_booleans
@@ -310,12 +384,24 @@ SASS
310
384
  assert_equal "-1", resolve("-1")
311
385
  end
312
386
 
387
+ def test_subtraction_vs_minus_vs_identifier
388
+ assert_equal "0.25em", resolve("1em-.75")
389
+ assert_equal "0.25em", resolve("1em-0.75")
390
+ assert_equal "1em -0.75", resolve("1em -.75")
391
+ assert_equal "1em -0.75", resolve("1em -0.75")
392
+ assert_equal "1em- 0.75", resolve("1em- .75")
393
+ assert_equal "1em- 0.75", resolve("1em- 0.75")
394
+ assert_equal "0.25em", resolve("1em - .75")
395
+ assert_equal "0.25em", resolve("1em - 0.75")
396
+ end
397
+
313
398
  def test_string_ops
314
399
  assert_equal '"foo" "bar"', resolve('"foo" "bar"')
315
400
  assert_equal "true 1", resolve('true 1')
316
401
  assert_equal '"foo", "bar"', resolve("'foo' , 'bar'")
317
402
  assert_equal "true, 1", resolve('true , 1')
318
403
  assert_equal "foobar", resolve('"foo" + "bar"')
404
+ assert_equal "\nfoo\nxyz", resolve('"\a foo" + "\axyz"')
319
405
  assert_equal "true1", resolve('true + 1')
320
406
  assert_equal '"foo"-"bar"', resolve("'foo' - 'bar'")
321
407
  assert_equal "true-1", resolve('true - 1')
@@ -418,16 +504,65 @@ SASS
418
504
 
419
505
  def test_functions
420
506
  assert_equal "#80ff80", resolve("hsl(120, 100%, 75%)")
421
- assert_equal "#81ff81", resolve("hsl(120, 100%, 75%) + #010001")
507
+ silence_warnings {assert_equal "#81ff81", resolve("hsl(120, 100%, 75%) + #010001")}
422
508
  end
423
509
 
424
510
  def test_operator_unit_conversion
425
511
  assert_equal "1.1cm", resolve("1cm + 1mm")
512
+ assert_equal "8q", resolve("4q + 1mm")
513
+ assert_equal "40.025cm", resolve("40cm + 1q")
426
514
  assert_equal "2in", resolve("1in + 96px")
427
515
  assert_equal "true", resolve("2mm < 1cm")
428
516
  assert_equal "true", resolve("10mm == 1cm")
429
- assert_equal "true", resolve("1 == 1cm")
430
517
  assert_equal "true", resolve("1.1cm == 11mm")
518
+ assert_equal "true", resolve("2mm == 8q")
519
+ assert_equal "false", resolve("2px > 3q")
520
+
521
+ Sass::Deprecation.allow_double_warnings do
522
+ assert_warning(<<WARNING) {assert_equal "true", resolve("1 == 1cm")}
523
+ DEPRECATION WARNING on line 1 of test_operator_unit_conversion_inline.sass:
524
+ The result of `1 == 1cm` will be `false` in future releases of Sass.
525
+ Unitless numbers will no longer be equal to the same numbers with units.
526
+ WARNING
527
+
528
+ assert_warning(<<WARNING) {assert_equal "false", resolve("1 != 1cm")}
529
+ DEPRECATION WARNING on line 1 of test_operator_unit_conversion_inline.sass:
530
+ The result of `1 != 1cm` will be `true` in future releases of Sass.
531
+ Unitless numbers will no longer be equal to the same numbers with units.
532
+ WARNING
533
+ end
534
+ end
535
+
536
+ def test_length_units
537
+ assert_equal "2.54", resolve("(1in/1cm)")
538
+ assert_equal "2.3622", resolve("(1cm/1pc)")
539
+ assert_equal "4.23333", resolve("(1pc/1mm)")
540
+ assert_equal "2.83465", resolve("(1mm/1pt)")
541
+ assert_equal "1.33333", resolve("(1pt/1px)")
542
+ assert_equal "0.01042", resolve("(1px/1in)")
543
+ assert_equal "1.05833", resolve("(1px/1q)")
544
+ assert_equal "0.05906", resolve("(1q/1pc)")
545
+ end
546
+
547
+ def test_angle_units
548
+ assert_equal "1.11111", resolve("(1deg/1grad)")
549
+ assert_equal "0.01571", resolve("(1grad/1rad)")
550
+ assert_equal "0.15915", resolve("(1rad/1turn)")
551
+ assert_equal "360", resolve("(1turn/1deg)")
552
+ end
553
+
554
+ def test_time_units
555
+ assert_equal "1000", resolve("(1s/1ms)")
556
+ end
557
+
558
+ def test_frequency_units
559
+ assert_equal "0.001", resolve("(1Hz/1kHz)")
560
+ end
561
+
562
+ def test_resolution_units
563
+ assert_equal "0.3937", resolve("(1dpi/1dpcm)")
564
+ assert_equal "0.02646", resolve("(1dpcm/1dppx)")
565
+ assert_equal "96", resolve("(1dppx/1dpi)")
431
566
  end
432
567
 
433
568
  def test_operations_have_options
@@ -462,23 +597,30 @@ SASS
462
597
  assert_equal "0.5", resolve("$var", {}, env("var" => eval("1px/2px")))
463
598
  end
464
599
 
465
- def test_colors_with_wrong_number_of_digits
466
- assert_raise_message(Sass::SyntaxError,
467
- "Colors must have either three or six digits: '#0'") {eval("#0")}
600
+ # Regression test for issue 1786.
601
+ def test_slash_division_within_list
602
+ assert_equal "1 1/2 1/2", resolve("(1 1/2 1/2)")
603
+ assert_equal "1/2 1/2", resolve("(1/2 1/2)")
604
+ assert_equal "1/2", resolve("(1/2,)")
605
+ end
606
+
607
+ def test_non_ident_colors_with_wrong_number_of_digits
468
608
  assert_raise_message(Sass::SyntaxError,
469
- "Colors must have either three or six digits: '#12'") {eval("#12")}
609
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#1"') {eval("#1")}
470
610
  assert_raise_message(Sass::SyntaxError,
471
- "Colors must have either three or six digits: '#abcd'") {eval("#abcd")}
611
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#12"') {eval("#12")}
472
612
  assert_raise_message(Sass::SyntaxError,
473
- "Colors must have either three or six digits: '#abcdE'") {eval("#abcdE")}
613
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#1234"') {eval("#1234")}
474
614
  assert_raise_message(Sass::SyntaxError,
475
- "Colors must have either three or six digits: '#abcdEFA'") {eval("#abcdEFA")}
615
+ 'Invalid CSS after "": expected expression (e.g. 1px, bold), was "#12345"') {eval("#12345")}
616
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "": expected expression (e.g. ' \
617
+ '1px, bold), was "#1234567"') {eval("#1234567")}
476
618
  end
477
619
 
478
620
  def test_case_insensitive_color_names
479
- assert_equal "blue", resolve("BLUE")
480
- assert_equal "red", resolve("rEd")
481
- assert_equal "#7f4000", resolve("mix(GrEeN, ReD)")
621
+ assert_equal "BLUE", resolve("BLUE")
622
+ assert_equal "rEd", resolve("rEd")
623
+ assert_equal "#804000", resolve("mix(GrEeN, ReD)")
482
624
  end
483
625
 
484
626
  def test_empty_list
@@ -523,7 +665,7 @@ SASS
523
665
  assert_raise_message(Sass::SyntaxError, 'Duplicate key 2px in map (2px: bar, 1px + 1px: baz).') do
524
666
  eval("(2px: bar, 1px + 1px: baz)")
525
667
  end
526
- assert_raise_message(Sass::SyntaxError, 'Duplicate key #0000ff in map (blue: bar, blue: baz).') do
668
+ assert_raise_message(Sass::SyntaxError, 'Duplicate key #0000ff in map (blue: bar, #00f: baz).') do
527
669
  eval("(blue: bar, #00f: baz)")
528
670
  end
529
671
  end
@@ -558,7 +700,7 @@ SASS
558
700
  return if RUBY_PLATFORM =~ /java/
559
701
 
560
702
  # Don't validate the message; it's different on Rubinius.
561
- assert_raise(ArgumentError) {resolve("arg-error()")}
703
+ assert_raises(ArgumentError) {resolve("arg-error()")}
562
704
  end
563
705
 
564
706
  def test_shallow_argument_error_unwrapped
@@ -570,49 +712,37 @@ SASS
570
712
  assert_equal "true", resolve("$ie or $undef", {}, env('ie' => Sass::Script::Value::Bool.new(true)))
571
713
  end
572
714
 
573
- def test_setting_global_variable_locally_warns
574
- assert_warning(<<WARNING) {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
575
- DEPRECATION WARNING on line 4 of test_setting_global_variable_locally_warns_inline.scss:
576
- Assigning to global variable "$var" by default is deprecated.
577
- In future versions of Sass, this will create a new local variable.
578
- If you want to assign to the global variable, use "$var: x !global" instead.
579
- Note that this will be incompatible with Sass 3.2.
580
- WARNING
581
- .foo {
582
- a: x; }
583
-
584
- .bar {
585
- b: x; }
586
- CSS
587
- $var: 1;
588
-
589
- .foo {
590
- $var: x;
591
- a: $var;
592
- }
593
-
594
- .bar {
595
- b: $var;
596
- }
597
- SCSS
598
- end
599
-
600
- def test_setting_global_variable_locally_warns_only_once
601
- assert_warning(<<WARNING) {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
602
- DEPRECATION WARNING on line 3 of test_setting_global_variable_locally_warns_only_once_inline.scss:
603
- Assigning to global variable "$var" by default is deprecated.
604
- In future versions of Sass, this will create a new local variable.
605
- If you want to assign to the global variable, use "$var: x !global" instead.
606
- Note that this will be incompatible with Sass 3.2.
607
- WARNING
608
- CSS
609
- $var: 1;
610
-
611
- @mixin foo {$var: x}
612
- @include foo;
613
- @include foo;
614
- @include foo;
615
- SCSS
715
+ def test_selector
716
+ env = Sass::Environment.new
717
+ assert_equal "true", resolve("& == null", {}, env)
718
+
719
+ env.selector = selector('.foo.bar .baz.bang, .bip.bop')
720
+ assert_equal ".foo.bar .baz.bang, .bip.bop", resolve("&", {}, env)
721
+ assert_equal ".foo.bar .baz.bang", resolve("nth(&, 1)", {}, env)
722
+ assert_equal ".bip.bop", resolve("nth(&, 2)", {}, env)
723
+ assert_equal ".foo.bar", resolve("nth(nth(&, 1), 1)", {}, env)
724
+ assert_equal ".baz.bang", resolve("nth(nth(&, 1), 2)", {}, env)
725
+ assert_equal ".bip.bop", resolve("nth(nth(&, 2), 1)", {}, env)
726
+ assert_equal "string", resolve("type-of(nth(nth(&, 1), 1))", {}, env)
727
+
728
+ env.selector = selector('.foo > .bar')
729
+ assert_equal ".foo > .bar", resolve("&", {}, env)
730
+ assert_equal ".foo > .bar", resolve("nth(&, 1)", {}, env)
731
+ assert_equal ".foo", resolve("nth(nth(&, 1), 1)", {}, env)
732
+ assert_equal ">", resolve("nth(nth(&, 1), 2)", {}, env)
733
+ assert_equal ".bar", resolve("nth(nth(&, 1), 3)", {}, env)
734
+ end
735
+
736
+ def test_selector_with_newlines
737
+ env = Sass::Environment.new
738
+ env.selector = selector(".foo.bar\n.baz.bang,\n\n.bip.bop")
739
+ assert_equal ".foo.bar .baz.bang, .bip.bop", resolve("&", {}, env)
740
+ assert_equal ".foo.bar .baz.bang", resolve("nth(&, 1)", {}, env)
741
+ assert_equal ".bip.bop", resolve("nth(&, 2)", {}, env)
742
+ assert_equal ".foo.bar", resolve("nth(nth(&, 1), 1)", {}, env)
743
+ assert_equal ".baz.bang", resolve("nth(nth(&, 1), 2)", {}, env)
744
+ assert_equal ".bip.bop", resolve("nth(nth(&, 2), 1)", {}, env)
745
+ assert_equal "string", resolve("type-of(nth(nth(&, 1), 1))", {}, env)
616
746
  end
617
747
 
618
748
  def test_setting_global_variable_globally
@@ -637,7 +767,7 @@ $var: 2;
637
767
  SCSS
638
768
  end
639
769
 
640
- def test_setting_global_variable_with_flag
770
+ def test_setting_global_variable_locally
641
771
  assert_no_warning {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
642
772
  .bar {
643
773
  a: x;
@@ -663,7 +793,7 @@ $var3: 3;
663
793
  SCSS
664
794
  end
665
795
 
666
- def test_setting_global_variable_with_flag_and_default
796
+ def test_setting_global_variable_locally_with_default
667
797
  assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
668
798
  .bar {
669
799
  a: 1;
@@ -688,10 +818,267 @@ $var1: 1;
688
818
  SCSS
689
819
  end
690
820
 
821
+ def test_setting_local_variable
822
+ assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
823
+ .a {
824
+ value: inside; }
825
+
826
+ .b {
827
+ value: outside; }
828
+ CSS
829
+ $var: outside;
830
+
831
+ .a {
832
+ $var: inside;
833
+ value: $var;
834
+ }
835
+
836
+ .b {
837
+ value: $var;
838
+ }
839
+ SCSS
840
+ end
841
+
842
+ def test_setting_local_variable_from_inner_scope
843
+ assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
844
+ .a .b {
845
+ value: inside; }
846
+ .a .c {
847
+ value: inside; }
848
+ CSS
849
+ .a {
850
+ $var: outside;
851
+
852
+ .b {
853
+ $var: inside;
854
+ value: $var;
855
+ }
856
+
857
+ .c {
858
+ value: $var;
859
+ }
860
+ }
861
+ SCSS
862
+ end
863
+
864
+ def test_if_can_assign_to_global_variables
865
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
866
+ .a {
867
+ b: 2; }
868
+ CSS
869
+ $var: 1;
870
+ @if true {$var: 2}
871
+ .a {b: $var}
872
+ SCSS
873
+ end
874
+
875
+ def test_else_can_assign_to_global_variables
876
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
877
+ .a {
878
+ b: 2; }
879
+ CSS
880
+ $var: 1;
881
+ @if false {}
882
+ @else {$var: 2}
883
+ .a {b: $var}
884
+ SCSS
885
+ end
886
+
887
+ def test_for_can_assign_to_global_variables
888
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
889
+ .a {
890
+ b: 2; }
891
+ CSS
892
+ $var: 1;
893
+ @for $i from 1 to 2 {$var: 2}
894
+ .a {b: $var}
895
+ SCSS
896
+ end
897
+
898
+ def test_each_can_assign_to_global_variables
899
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
900
+ .a {
901
+ b: 2; }
902
+ CSS
903
+ $var: 1;
904
+ @each $a in 1 {$var: 2}
905
+ .a {b: $var}
906
+ SCSS
907
+ end
908
+
909
+ def test_while_can_assign_to_global_variables
910
+ assert_equal <<CSS, render(<<SCSS, :syntax => :scss)
911
+ .a {
912
+ b: 2; }
913
+ CSS
914
+ $var: 1;
915
+ @while $var != 2 {$var: 2}
916
+ .a {b: $var}
917
+ SCSS
918
+ end
919
+
920
+ def test_if_doesnt_leak_local_variables
921
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
922
+ render(<<SCSS, :syntax => :scss)
923
+ @if true {$var: 1}
924
+ .a {b: $var}
925
+ SCSS
926
+ end
927
+ end
928
+
929
+ def test_else_doesnt_leak_local_variables
930
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
931
+ render(<<SCSS, :syntax => :scss)
932
+ @if false {}
933
+ @else {$var: 1}
934
+ .a {b: $var}
935
+ SCSS
936
+ end
937
+ end
938
+
939
+ def test_for_doesnt_leak_local_variables
940
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
941
+ render(<<SCSS, :syntax => :scss)
942
+ @for $i from 1 to 2 {$var: 1}
943
+ .a {b: $var}
944
+ SCSS
945
+ end
946
+ end
947
+
948
+ def test_each_doesnt_leak_local_variables
949
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
950
+ render(<<SCSS, :syntax => :scss)
951
+ @each $a in 1 {$var: 1}
952
+ .a {b: $var}
953
+ SCSS
954
+ end
955
+ end
956
+
957
+ def test_while_doesnt_leak_local_variables
958
+ assert_raise_message(Sass::SyntaxError, 'Undefined variable: "$var".') do
959
+ render(<<SCSS, :syntax => :scss)
960
+ $iter: true;
961
+ @while $iter {
962
+ $var: 1;
963
+ $iter: false;
964
+ }
965
+ .a {b: $var}
966
+ SCSS
967
+ end
968
+ end
969
+
970
+ def test_color_format_is_preserved_by_default
971
+ assert_equal "blue", resolve("blue")
972
+ assert_equal "bLuE", resolve("bLuE")
973
+ assert_equal "#00f", resolve("#00f")
974
+ assert_equal "blue #00F", resolve("blue #00F")
975
+ assert_equal "blue", resolve("nth(blue #00F, 1)")
976
+ assert_equal "#00F", resolve("nth(blue #00F, 2)")
977
+ end
978
+
979
+ def test_color_format_isnt_always_preserved_in_compressed_style
980
+ assert_equal "red", resolve("red", :style => :compressed)
981
+ assert_equal "red", resolve("#f00", :style => :compressed)
982
+ assert_equal "red red", resolve("red #f00", :style => :compressed)
983
+ assert_equal "red", resolve("nth(red #f00, 2)", :style => :compressed)
984
+ end
985
+
986
+ def test_color_format_is_sometimes_preserved_in_compressed_style
987
+ assert_equal "ReD", resolve("ReD", :style => :compressed)
988
+ assert_equal "blue", resolve("blue", :style => :compressed)
989
+ assert_equal "#00f", resolve("#00f", :style => :compressed)
990
+ end
991
+
992
+ def test_color_format_isnt_preserved_when_modified
993
+ assert_equal "magenta", resolve("change-color(#f00, $blue: 255)")
994
+ end
995
+
996
+ def test_ids
997
+ assert_equal "#foo", resolve("#foo")
998
+ assert_equal "#abcd", resolve("#abcd")
999
+ assert_equal "#abc-def", resolve("#abc-def")
1000
+ assert_equal "#abc_def", resolve("#abc_def")
1001
+ assert_equal "#uvw-xyz", resolve("#uvw-xyz")
1002
+ assert_equal "#uvw_xyz", resolve("#uvw_xyz")
1003
+ assert_equal "#uvwxyz", resolve("#uvw + xyz")
1004
+ end
1005
+
1006
+ def test_scientific_notation
1007
+ assert_equal "2000", resolve("2e3")
1008
+ assert_equal "2000", resolve("2E3")
1009
+ assert_equal "2000", resolve("2e+3")
1010
+ assert_equal "2000em", resolve("2e3em")
1011
+ assert_equal "25000000000", resolve("2.5e10")
1012
+ assert_equal "0.1234", resolve("1234e-4")
1013
+ assert_equal "12.34", resolve("1.234e1")
1014
+ end
1015
+
1016
+ def test_identifier_units
1017
+ assert_equal "5-foo", resolve("2-foo + 3-foo")
1018
+ assert_equal "5-foo-", resolve("2-foo- + 3-foo-")
1019
+ assert_equal "5-\\u2603", resolve("2-\\u2603 + 3-\\u2603")
1020
+ end
1021
+
1022
+ def test_backslash_newline_in_string
1023
+ assert_equal 'foobar', resolve("\"foo\\\nbar\"")
1024
+ assert_equal 'foobar', resolve("'foo\\\nbar'")
1025
+ end
1026
+
1027
+ def test_unclosed_special_fun
1028
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(foo()": expected ")", was ""') do
1029
+ resolve("calc(foo()")
1030
+ end
1031
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(#{\')\'}": expected ")", was ""') do
1032
+ resolve("calc(\#{')'}")
1033
+ end
1034
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "calc(#{foo": expected "}", was ""') do
1035
+ resolve("calc(\#{foo")
1036
+ end
1037
+ end
1038
+
1039
+ def test_special_fun_with_interpolation
1040
+ assert_equal "calc())", resolve("calc(\#{')'})")
1041
+ assert_equal "calc(# {foo})", resolve("calc(# {foo})")
1042
+ end
1043
+
691
1044
  # Regression Tests
692
1045
 
1046
+ def test_interpolation_after_string
1047
+ assert_equal '"foobar" 2', resolve('"foobar" #{2}')
1048
+ assert_equal "calc(1 + 2) 3", resolve('calc(1 + 2) #{3}')
1049
+ end
1050
+
1051
+ def test_repeatedly_modified_color
1052
+ assert_equal(<<CSS, render(<<SASS))
1053
+ a {
1054
+ link-color: #161C14;
1055
+ link-color-hover: black;
1056
+ link-color-tap: rgba(22, 28, 20, 0.3); }
1057
+ CSS
1058
+ $green: #161C14
1059
+ $link-color: $green
1060
+ $link-color-hover: darken($link-color, 10%)
1061
+ $link-color-tap: rgba($green, 0.3)
1062
+
1063
+ a
1064
+ link-color: $link-color
1065
+ link-color-hover: $link-color-hover
1066
+ link-color-tap: $link-color-tap
1067
+ SASS
1068
+ end
1069
+
1070
+ def test_inspect_divided_numbers
1071
+ assert_equal "1px/2px", resolve("inspect(1px/2px)")
1072
+ assert_equal "0.5", resolve("inspect((1px/2px))")
1073
+ end
1074
+
693
1075
  def test_minus_without_whitespace
694
1076
  assert_equal "5px", resolve("15px-10px")
1077
+ assert_equal "5px-", resolve("15px--10px-")
1078
+ end
1079
+
1080
+ def test_minus_preceded_by_comment
1081
+ assert_equal "15px -10px", resolve("15px/**/-10px")
695
1082
  end
696
1083
 
697
1084
  def test_user_defined_function_forces_division
@@ -716,7 +1103,7 @@ CSS
716
1103
  a
717
1104
  b: foo() / 2
718
1105
  SASS
719
- end
1106
+ end
720
1107
 
721
1108
  def test_funcall_has_higher_precedence_than_color_name
722
1109
  assert_equal "teal(12)", resolve("teal(12)")
@@ -732,6 +1119,17 @@ end
732
1119
  assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)")
733
1120
  end
734
1121
 
1122
+ def test_and_or_not_disallowed_as_function_names
1123
+ %w[and or not].each do |name|
1124
+ assert_raise_message(Sass::SyntaxError, "Invalid function name \"#{name}\".") do
1125
+ render(<<SASS)
1126
+ @function #{name}()
1127
+ @return null
1128
+ SASS
1129
+ end
1130
+ end
1131
+ end
1132
+
735
1133
  def test_interpolation_after_hash
736
1134
  assert_equal "#2", resolve('"##{1 + 1}"')
737
1135
  end
@@ -787,15 +1185,208 @@ end
787
1185
  assert_equal "NaN", resolve("(0.0/0.0)")
788
1186
  end
789
1187
 
1188
+ def test_equality_uses_an_epsilon
1189
+ # At least on my machine, this calculation introduces a floating point error:
1190
+ # 29.0 / 7 * 7
1191
+ # => 29.000000000000004
1192
+ assert_equal "true", resolve("29 == (29 / 7 * 7)")
1193
+ end
1194
+
1195
+ def test_compressed_output_of_numbers_with_leading_zeros
1196
+ assert_equal "1.5", resolve("1.5", :style => :compressed)
1197
+ assert_equal ".5", resolve("0.5", :style => :compressed)
1198
+ assert_equal "-.5", resolve("-0.5", :style => :compressed)
1199
+ assert_equal "0.5", resolve("0.5", :style => :compact)
1200
+ end
1201
+
1202
+ def test_interpolation_without_deprecation_warning
1203
+ assert_no_warning {assert_equal "a", resolve('#{a}')}
1204
+ assert_no_warning {assert_equal "abc", resolve('a#{b}c')}
1205
+ assert_no_warning {assert_equal "+ a", resolve('+ #{a}')}
1206
+ assert_no_warning {assert_equal "/ a", resolve('/ #{a}')}
1207
+ assert_no_warning {assert_equal "1 / a", resolve('1 / #{a}')}
1208
+ assert_no_warning {assert_equal "a / b", resolve('#{a} / #{b}')}
1209
+ assert_no_warning {assert_equal "foo(1 = a)", resolve('foo(1 = #{a})')}
1210
+ assert_no_warning {assert_equal "foo(a = b)", resolve('foo(#{a} = #{b})')}
1211
+ assert_no_warning {assert_equal "-a", resolve('-#{a}')}
1212
+ assert_no_warning {assert_equal "1-a", resolve('1-#{a}')}
1213
+ assert_no_warning {assert_equal "a- 1", resolve('#{a}- 1')}
1214
+ assert_no_warning {assert_equal "a-1", resolve('#{a}-1')}
1215
+ assert_no_warning {assert_equal "a-b", resolve('#{a}-#{b}')}
1216
+ assert_no_warning {assert_equal "a1", resolve('#{a}1')}
1217
+ assert_no_warning {assert_equal "ab", resolve('#{a}b')}
1218
+ assert_no_warning {assert_equal "1a", resolve('1#{a}')}
1219
+ assert_no_warning {assert_equal "ba", resolve('b#{a}')}
1220
+ end
1221
+
1222
+ def test_leading_interpolation_with_deprecation_warning
1223
+ assert_equal "ab == 1", resolve_with_interp_warning('#{a + b} == 1')
1224
+ assert_equal "ab != 1", resolve_with_interp_warning('#{a + b} != 1')
1225
+ assert_equal "ab > 1", resolve_with_interp_warning('#{a + b} > 1')
1226
+ assert_equal "ab >= 1", resolve_with_interp_warning('#{a + b} >= 1')
1227
+ assert_equal "ab < 1", resolve_with_interp_warning('#{a + b} < 1')
1228
+ assert_equal "ab <= 1", resolve_with_interp_warning('#{a + b} <= 1')
1229
+ assert_equal "ab + 1", resolve_with_interp_warning('#{a + b} + 1')
1230
+ assert_equal "ab * 1", resolve_with_interp_warning('#{a + b} * 1')
1231
+ assert_equal "ab - 1", resolve_with_interp_warning('#{a + b} - 1')
1232
+ assert_equal "ab % 1", resolve_with_interp_warning('#{a + b} % 1')
1233
+ assert_equal(
1234
+ "abvar",
1235
+ resolve_with_interp_warning(
1236
+ '#{a + b}$var', '"#{a + b}#{$var}"',
1237
+ env('var' => Sass::Script::Value::String.new("var"))))
1238
+ assert_equal(
1239
+ "varab",
1240
+ resolve_with_interp_warning(
1241
+ '$var#{a + b}', '"#{$var}#{a + b}"',
1242
+ env('var' => Sass::Script::Value::String.new("var"))))
1243
+ assert_equal "ab1", resolve_with_interp_warning('#{a + b}(1)', '"#{a + b}1"')
1244
+ assert_equal "1ab", resolve_with_interp_warning('(1)#{a + b}', '"1#{a + b}"')
1245
+ end
1246
+
1247
+ def test_trailing_interpolation_with_deprecation_warning
1248
+ assert_equal "not ab", resolve_with_interp_warning('not #{a + b}')
1249
+ assert_equal "1 and ab", resolve_with_interp_warning('1 and #{a + b}')
1250
+ assert_equal "1 or ab", resolve_with_interp_warning('1 or #{a + b}')
1251
+ assert_equal "1 == ab", resolve_with_interp_warning('1 == #{a + b}')
1252
+ assert_equal "1 != ab", resolve_with_interp_warning('1 != #{a + b}')
1253
+ assert_equal "1 > ab", resolve_with_interp_warning('1 > #{a + b}')
1254
+ assert_equal "1 >= ab", resolve_with_interp_warning('1 >= #{a + b}')
1255
+ assert_equal "1 < ab", resolve_with_interp_warning('1 < #{a + b}')
1256
+ assert_equal "1 <= ab", resolve_with_interp_warning('1 <= #{a + b}')
1257
+ assert_equal "1 + ab", resolve_with_interp_warning('1 + #{a + b}')
1258
+ assert_equal "1 * ab", resolve_with_interp_warning('1 * #{a + b}')
1259
+ assert_equal "1 - ab", resolve_with_interp_warning('1 - #{a + b}')
1260
+ assert_equal "1 % ab", resolve_with_interp_warning('1 % #{a + b}')
1261
+ assert_equal "- ab", resolve_with_interp_warning('- #{a + b}')
1262
+ assert_equal "1- ab", resolve_with_interp_warning('1- #{a + b}')
1263
+ assert_equal "- ab 2 3", resolve_with_interp_warning('- #{a + b} 2 3', '"- #{a + b} #{2 3}"')
1264
+ end
1265
+
1266
+ def test_brackteing_interpolation_with_deprecation_warning
1267
+ assert_equal "ab == cd", resolve_with_interp_warning('#{a + b} == #{c + d}')
1268
+ assert_equal "ab != cd", resolve_with_interp_warning('#{a + b} != #{c + d}')
1269
+ assert_equal "ab > cd", resolve_with_interp_warning('#{a + b} > #{c + d}')
1270
+ assert_equal "ab >= cd", resolve_with_interp_warning('#{a + b} >= #{c + d}')
1271
+ assert_equal "ab < cd", resolve_with_interp_warning('#{a + b} < #{c + d}')
1272
+ assert_equal "ab <= cd", resolve_with_interp_warning('#{a + b} <= #{c + d}')
1273
+ assert_equal "ab + cd", resolve_with_interp_warning('#{a + b} + #{c + d}')
1274
+ assert_equal "ab * cd", resolve_with_interp_warning('#{a + b} * #{c + d}')
1275
+ assert_equal "ab - cd", resolve_with_interp_warning('#{a + b} - #{c + d}')
1276
+ assert_equal "ab % cd", resolve_with_interp_warning('#{a + b} % #{c + d}')
1277
+ end
1278
+
1279
+ def test_interp_warning_formatting
1280
+ resolve_with_interp_warning('#{1} + 1', '"1 + 1"')
1281
+ resolve_with_interp_warning('#{1} + "foo"', '\'1 + "foo"\'')
1282
+ resolve_with_interp_warning('#{1} + \'foo\'', '\'1 + "foo"\'')
1283
+
1284
+ resolve_with_interp_warning('#{1} + "#{a + b}"', '\'1 + "#{a + b}"\'')
1285
+ resolve_with_interp_warning('"#{a + b}" + #{1}', '\'"#{a + b}" + 1\'')
1286
+ resolve_with_interp_warning('"#{a + b}" + #{1} + "#{c + d}"', '\'"#{a + b}" + 1 + "#{c + d}"\'')
1287
+
1288
+ resolve_with_interp_warning('#{1} + "\'"', '"1 + \\"\'\\""')
1289
+ resolve_with_interp_warning('#{1} + \'"\'', '"1 + \'\\"\'"')
1290
+ resolve_with_interp_warning('#{1} + "\'\\""', '"1 + \\"\'\\\\\\"\\""')
1291
+ end
1292
+
1293
+ def test_inactive_lazy_interpolation_deprecation_warning
1294
+ assert_equal '1, 2, 3', assert_no_warning {resolve('1, #{2}, 3')}
1295
+ assert_equal '1, 2, 3', assert_no_warning {resolve('1, 2, #{3}')}
1296
+ assert_equal '1,2,3', assert_no_warning {resolve('1,#{2},3')}
1297
+ assert_equal '1 2 3', assert_no_warning {resolve('#{1} 2 3')}
1298
+ assert_equal '1 2 3', assert_no_warning {resolve('1 #{2} 3')}
1299
+ assert_equal '1 2 3', assert_no_warning {resolve('1 2 #{3}')}
1300
+
1301
+ assert_equal '+1 2 3', assert_no_warning {resolve('+#{1} 2 3')}
1302
+ assert_equal '-1 2 3', assert_no_warning {resolve('-#{1} 2 3')}
1303
+ assert_equal '/1 2 3', assert_no_warning {resolve('/#{1} 2 3')}
1304
+
1305
+ assert_equal '1, 2, 31', assert_no_warning {resolve('(1, #{2}, 3) + 1')}
1306
+ assert_equal '11, 2, 3', assert_no_warning {resolve('1 + (1, #{2}, 3)')}
1307
+
1308
+ assert_equal 'a, b, c', assert_no_warning {resolve('selector-parse((a, #{b}, c))')}
1309
+ end
1310
+
1311
+ def test_active_lazy_interpolation_deprecation_warning
1312
+ Sass::Deprecation.allow_double_warnings do
1313
+ assert_equal "1, 2, 3", resolve_with_lazy_interp_warning('quote((1, #{2}, 3))', '"1, 2, 3"')
1314
+ assert_equal "1", resolve_with_lazy_interp_warning('length((1, #{2}, 3))', '"1, 2, 3"')
1315
+ assert_equal "1, 2, 3", resolve_with_lazy_interp_warning('inspect((1, #{2}, 3))', '"1, 2, 3"')
1316
+ assert_equal "string", resolve_with_lazy_interp_warning('type-of((1, #{2}, 3))', '"1, 2, 3"')
1317
+
1318
+ assert_equal "+1 2 3", resolve_with_lazy_interp_warning('quote((+#{1} 2 3))', '"+1 #{2 3}"')
1319
+ assert_equal "/1 2 3", resolve_with_lazy_interp_warning('quote((/#{1} 2 3))', '"/1 #{2 3}"')
1320
+ assert_equal "-1 2 3", resolve_with_lazy_interp_warning('quote((-#{1} 2 3))', '"-1 #{2 3}"')
1321
+ end
1322
+ end
1323
+
1324
+ def test_comparison_of_complex_units
1325
+ # Tests for issue #1960
1326
+ Sass::Deprecation.allow_double_warnings do
1327
+ assert_warning(<<WARNING) do
1328
+ DEPRECATION WARNING on line 1 of test_comparison_of_complex_units_inline.sass:
1329
+ The result of `10 == 10px` will be `false` in future releases of Sass.
1330
+ Unitless numbers will no longer be equal to the same numbers with units.
1331
+ WARNING
1332
+ assert_equal "true", resolve("10 == 2 * 5px")
1333
+ end
1334
+ assert_warning(<<WARNING) do
1335
+ DEPRECATION WARNING on line 1 of test_comparison_of_complex_units_inline.sass:
1336
+ The result of `10 == 10px*px` will be `false` in future releases of Sass.
1337
+ Unitless numbers will no longer be equal to the same numbers with units.
1338
+ WARNING
1339
+ assert_equal "true", resolve("10 == 2px * 5px")
1340
+ end
1341
+ end
1342
+
1343
+ assert_equal "true", resolve("10px * 1px == 2px * 5px")
1344
+ assert_equal "true", resolve("5px * 1px < 2px * 5px")
1345
+ end
1346
+
790
1347
  private
791
1348
 
1349
+ def resolve_with_lazy_interp_warning(str, contents = nil, environment = env)
1350
+ contents ||= "\"#{str}\""
1351
+ result = assert_warning(<<WARNING) {resolve(str, {}, environment)}
1352
+ DEPRECATION WARNING on line 1 of #{filename_for_test}:
1353
+ \#{} interpolation near operators will be simplified in a future version of Sass.
1354
+ To preserve the current behavior, use quotes:
1355
+
1356
+ unquote(#{contents})
1357
+ WARNING
1358
+ $_sass_deprecated_interp_warnings = nil
1359
+ result
1360
+ end
1361
+
1362
+ def resolve_with_interp_warning(str, contents = nil, environment = env)
1363
+ contents ||= "\"#{str}\""
1364
+ assert_warning(<<WARNING) {resolve(str, {}, environment)}
1365
+ DEPRECATION WARNING on line 1 of #{filename_for_test}:
1366
+ \#{} interpolation near operators will be simplified in a future version of Sass.
1367
+ To preserve the current behavior, use quotes:
1368
+
1369
+ unquote(#{contents})
1370
+
1371
+ You can use the sass-convert command to automatically fix most cases.
1372
+ WARNING
1373
+ end
1374
+
792
1375
  def resolve(str, opts = {}, environment = env)
793
1376
  munge_filename opts
794
1377
  val = eval(str, opts, environment)
795
1378
  assert_kind_of Sass::Script::Value::Base, val
1379
+ val.options = opts
796
1380
  val.is_a?(Sass::Script::Value::String) ? val.value : val.to_s
797
1381
  end
798
1382
 
1383
+ def resolve_quoted(str, opts = {}, environment = env)
1384
+ munge_filename opts
1385
+ val = eval(str, opts, environment)
1386
+ assert_kind_of Sass::Script::Value::Base, val
1387
+ val.to_s
1388
+ end
1389
+
799
1390
  def assert_unquoted(str, opts = {}, environment = env)
800
1391
  munge_filename opts
801
1392
  val = eval(str, opts, environment)