sass 3.1.0 → 3.3.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 (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -1,37 +1,43 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'test/unit'
3
3
  require File.dirname(__FILE__) + '/../test_helper'
4
+ require File.dirname(__FILE__) + '/test_helper'
4
5
  require 'sass/script'
6
+ require 'mock_importer'
5
7
 
6
8
  module Sass::Script::Functions
7
9
  def no_kw_args
8
- Sass::Script::String.new("no-kw-args")
10
+ Sass::Script::Value::String.new("no-kw-args")
9
11
  end
10
12
 
11
13
  def only_var_args(*args)
12
- Sass::Script::String.new("only-var-args("+args.map{|a| a.plus(Sass::Script::Number.new(1)).to_s }.join(", ")+")")
14
+ Sass::Script::Value::String.new("only-var-args("+args.map{|a| a.plus(Sass::Script::Value::Number.new(1)).to_s }.join(", ")+")")
13
15
  end
14
16
  declare :only_var_args, [], :var_args => true
15
17
 
16
18
  def only_kw_args(kwargs)
17
- Sass::Script::String.new("only-kw-args(" + kwargs.keys.map {|a| a.to_s}.sort.join(", ") + ")")
19
+ Sass::Script::Value::String.new("only-kw-args(" + kwargs.keys.map {|a| a.to_s}.sort.join(", ") + ")")
18
20
  end
19
21
  declare :only_kw_args, [], :var_kwargs => true
20
22
  end
21
23
 
22
24
  module Sass::Script::Functions::UserFunctions
23
- def call_options_on_new_literal
24
- str = Sass::Script::String.new("foo")
25
+ def call_options_on_new_value
26
+ str = Sass::Script::Value::String.new("foo")
25
27
  str.options[:foo]
26
28
  str
27
29
  end
28
30
 
29
31
  def user_defined
30
- Sass::Script::String.new("I'm a user-defined string!")
32
+ Sass::Script::Value::String.new("I'm a user-defined string!")
31
33
  end
32
34
 
33
35
  def _preceding_underscore
34
- Sass::Script::String.new("I'm another user-defined string!")
36
+ Sass::Script::Value::String.new("I'm another user-defined string!")
37
+ end
38
+
39
+ def fetch_the_variable
40
+ environment.var('variable')
35
41
  end
36
42
  end
37
43
 
@@ -47,25 +53,29 @@ class SassFunctionTest < Test::Unit::TestCase
47
53
  hsls, rgbs = chunk.strip.split("====")
48
54
  hsls.strip.split("\n").zip(rgbs.strip.split("\n")) do |hsl, rgb|
49
55
  hsl_method = "test_hsl: #{hsl} = #{rgb}"
50
- define_method(hsl_method) do
51
- assert_equal(evaluate(rgb), evaluate(hsl))
56
+ unless method_defined?(hsl_method)
57
+ define_method(hsl_method) do
58
+ assert_equal(evaluate(rgb), evaluate(hsl))
59
+ end
52
60
  end
53
61
 
54
62
  rgb_to_hsl_method = "test_rgb_to_hsl: #{rgb} = #{hsl}"
55
- define_method(rgb_to_hsl_method) do
56
- rgb_color = perform(rgb)
57
- hsl_color = perform(hsl)
58
-
59
- white = hsl_color.lightness == 100
60
- black = hsl_color.lightness == 0
61
- grayscale = white || black || hsl_color.saturation == 0
62
-
63
- assert_in_delta(hsl_color.hue, rgb_color.hue, 0.0001,
64
- "Hues should be equal") unless grayscale
65
- assert_in_delta(hsl_color.saturation, rgb_color.saturation, 0.0001,
66
- "Saturations should be equal") unless white || black
67
- assert_in_delta(hsl_color.lightness, rgb_color.lightness, 0.0001,
68
- "Lightnesses should be equal")
63
+ unless method_defined?(rgb_to_hsl_method)
64
+ define_method(rgb_to_hsl_method) do
65
+ rgb_color = perform(rgb)
66
+ hsl_color = perform(hsl)
67
+
68
+ white = hsl_color.lightness == 100
69
+ black = hsl_color.lightness == 0
70
+ grayscale = white || black || hsl_color.saturation == 0
71
+
72
+ assert_in_delta(hsl_color.hue, rgb_color.hue, 0.0001,
73
+ "Hues should be equal") unless grayscale
74
+ assert_in_delta(hsl_color.saturation, rgb_color.saturation, 0.0001,
75
+ "Saturations should be equal") unless white || black
76
+ assert_in_delta(hsl_color.lightness, rgb_color.lightness, 0.0001,
77
+ "Lightnesses should be equal")
78
+ end
69
79
  end
70
80
  end
71
81
  end
@@ -76,13 +86,13 @@ class SassFunctionTest < Test::Unit::TestCase
76
86
 
77
87
  def test_hsl_checks_bounds
78
88
  assert_error_message("Saturation -114 must be between 0% and 100% for `hsl'", "hsl(10, -114, 12)");
79
- assert_error_message("Lightness 256 must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)");
89
+ assert_error_message("Lightness 256% must be between 0% and 100% for `hsl'", "hsl(10, 10, 256%)");
80
90
  end
81
91
 
82
92
  def test_hsl_checks_types
83
- assert_error_message("\"foo\" is not a number for `hsl'", "hsl(\"foo\", 10, 12)");
84
- assert_error_message("\"foo\" is not a number for `hsl'", "hsl(10, \"foo\", 12)");
85
- assert_error_message("\"foo\" is not a number for `hsl'", "hsl(10, 10, \"foo\")");
93
+ assert_error_message("$hue: \"foo\" is not a number for `hsl'", "hsl(\"foo\", 10, 12)");
94
+ assert_error_message("$saturation: \"foo\" is not a number for `hsl'", "hsl(10, \"foo\", 12)");
95
+ assert_error_message("$lightness: \"foo\" is not a number for `hsl'", "hsl(10, 10, \"foo\")");
86
96
  end
87
97
 
88
98
  def test_hsla
@@ -94,54 +104,84 @@ class SassFunctionTest < Test::Unit::TestCase
94
104
 
95
105
  def test_hsla_checks_bounds
96
106
  assert_error_message("Saturation -114 must be between 0% and 100% for `hsla'", "hsla(10, -114, 12, 1)");
97
- assert_error_message("Lightness 256 must be between 0% and 100% for `hsla'", "hsla(10, 10, 256%, 0)");
107
+ assert_error_message("Lightness 256% must be between 0% and 100% for `hsla'", "hsla(10, 10, 256%, 0)");
98
108
  assert_error_message("Alpha channel -0.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, -0.1)");
99
109
  assert_error_message("Alpha channel 1.1 must be between 0 and 1 for `hsla'", "hsla(10, 10, 10, 1.1)");
100
110
  end
101
111
 
102
112
  def test_hsla_checks_types
103
- assert_error_message("\"foo\" is not a number for `hsla'", "hsla(\"foo\", 10, 12, 0.3)");
104
- assert_error_message("\"foo\" is not a number for `hsla'", "hsla(10, \"foo\", 12, 0)");
105
- assert_error_message("\"foo\" is not a number for `hsla'", "hsla(10, 10, \"foo\", 1)");
106
- assert_error_message("\"foo\" is not a number for `hsla'", "hsla(10, 10, 10, \"foo\")");
113
+ assert_error_message("$hue: \"foo\" is not a number for `hsla'", "hsla(\"foo\", 10, 12, 0.3)");
114
+ assert_error_message("$saturation: \"foo\" is not a number for `hsla'", "hsla(10, \"foo\", 12, 0)");
115
+ assert_error_message("$lightness: \"foo\" is not a number for `hsla'", "hsla(10, 10, \"foo\", 1)");
116
+ assert_error_message("$alpha: \"foo\" is not a number for `hsla'", "hsla(10, 10, 10, \"foo\")");
107
117
  end
108
118
 
109
119
  def test_percentage
110
120
  assert_equal("50%", evaluate("percentage(.5)"))
111
121
  assert_equal("100%", evaluate("percentage(1)"))
112
122
  assert_equal("25%", evaluate("percentage(25px / 100px)"))
113
- assert_equal("50%", evaluate("percentage($value: 0.5)"))
123
+ assert_equal("50%", evaluate("percentage($number: 0.5)"))
124
+ end
125
+
126
+ def test_percentage_deprecated_arg_name
127
+ assert_warning(<<WARNING) {assert_equal("50%", evaluate("percentage($value: 0.5)"))}
128
+ DEPRECATION WARNING: The `$value' argument for `percentage()' has been renamed to `$number'.
129
+ WARNING
114
130
  end
115
131
 
116
132
  def test_percentage_checks_types
117
- assert_error_message("25px is not a unitless number for `percentage'", "percentage(25px)")
118
- assert_error_message("#cccccc is not a unitless number for `percentage'", "percentage(#ccc)")
119
- assert_error_message("\"string\" is not a unitless number for `percentage'", %Q{percentage("string")})
133
+ assert_error_message("$number: 25px is not a unitless number for `percentage'", "percentage(25px)")
134
+ assert_error_message("$number: #cccccc is not a unitless number for `percentage'", "percentage(#ccc)")
135
+ assert_error_message("$number: \"string\" is not a unitless number for `percentage'", %Q{percentage("string")})
120
136
  end
121
137
 
122
138
  def test_round
123
139
  assert_equal("5", evaluate("round(4.8)"))
124
140
  assert_equal("5px", evaluate("round(4.8px)"))
125
141
  assert_equal("5px", evaluate("round(5.49px)"))
126
- assert_equal("5px", evaluate("round($value: 5.49px)"))
142
+ assert_equal("5px", evaluate("round($number: 5.49px)"))
143
+ end
144
+
145
+ def test_round_deprecated_arg_name
146
+ assert_warning(<<WARNING) {assert_equal("5px", evaluate("round($value: 5.49px)"))}
147
+ DEPRECATION WARNING: The `$value' argument for `round()' has been renamed to `$number'.
148
+ WARNING
149
+ end
127
150
 
128
- assert_error_message("#cccccc is not a number for `round'", "round(#ccc)")
151
+ def test_round_checks_types
152
+ assert_error_message("$value: #cccccc is not a number for `round'", "round(#ccc)")
129
153
  end
130
154
 
131
155
  def test_floor
132
156
  assert_equal("4", evaluate("floor(4.8)"))
133
157
  assert_equal("4px", evaluate("floor(4.8px)"))
134
- assert_equal("4px", evaluate("floor($value: 4.8px)"))
158
+ assert_equal("4px", evaluate("floor($number: 4.8px)"))
159
+ end
160
+
161
+ def test_floor_deprecated_arg_name
162
+ assert_warning(<<WARNING) {assert_equal("4px", evaluate("floor($value: 4.8px)"))}
163
+ DEPRECATION WARNING: The `$value' argument for `floor()' has been renamed to `$number'.
164
+ WARNING
165
+ end
135
166
 
136
- assert_error_message("\"foo\" is not a number for `floor'", "floor(\"foo\")")
167
+ def test_floor_checks_types
168
+ assert_error_message("$value: \"foo\" is not a number for `floor'", "floor(\"foo\")")
137
169
  end
138
170
 
139
171
  def test_ceil
140
172
  assert_equal("5", evaluate("ceil(4.1)"))
141
173
  assert_equal("5px", evaluate("ceil(4.8px)"))
142
- assert_equal("5px", evaluate("ceil($value: 4.8px)"))
174
+ assert_equal("5px", evaluate("ceil($number: 4.8px)"))
175
+ end
143
176
 
144
- assert_error_message("\"a\" is not a number for `ceil'", "ceil(\"a\")")
177
+ def test_ceil_deprecated_arg_name
178
+ assert_warning(<<WARNING) {assert_equal("5px", evaluate("ceil($value: 4.8px)"))}
179
+ DEPRECATION WARNING: The `$value' argument for `ceil()' has been renamed to `$number'.
180
+ WARNING
181
+ end
182
+
183
+ def test_ceil_checks_types
184
+ assert_error_message("$value: \"a\" is not a number for `ceil'", "ceil(\"a\")")
145
185
  end
146
186
 
147
187
  def test_abs
@@ -149,51 +189,79 @@ class SassFunctionTest < Test::Unit::TestCase
149
189
  assert_equal("5px", evaluate("abs(-5px)"))
150
190
  assert_equal("5", evaluate("abs(5)"))
151
191
  assert_equal("5px", evaluate("abs(5px)"))
152
- assert_equal("5px", evaluate("abs($value: 5px)"))
192
+ assert_equal("5px", evaluate("abs($number: 5px)"))
193
+ end
194
+
195
+ def test_abs_deprecated_arg_name
196
+ assert_warning(<<WARNING) {assert_equal("5px", evaluate("abs($value: 5px)"))}
197
+ DEPRECATION WARNING: The `$value' argument for `abs()' has been renamed to `$number'.
198
+ WARNING
199
+ end
153
200
 
154
- assert_error_message("#aaaaaa is not a number for `abs'", "abs(#aaa)")
201
+ def test_abs_checks_types
202
+ assert_error_message("$value: #aaaaaa is not a number for `abs'", "abs(#aaa)")
203
+ end
204
+
205
+ def test_min
206
+ assert_equal("1", evaluate("min(1, 2, 3)"))
207
+ assert_equal("1", evaluate("min(3px, 2px, 1)"))
208
+ assert_equal("4em", evaluate("min(4em)"))
209
+ assert_equal("10cm", evaluate("min(10cm, 6in)"))
210
+
211
+ assert_error_message("#aaaaaa is not a number for `min'", "min(#aaa)")
212
+ assert_error_message("Incompatible units: 'px' and 'em'.", "min(3em, 4em, 1px)")
213
+ end
214
+
215
+ def test_max
216
+ assert_equal("3", evaluate("max(1, 2, 3)"))
217
+ assert_equal("3", evaluate("max(3, 2px, 1px)"))
218
+ assert_equal("4em", evaluate("max(4em)"))
219
+ assert_equal("6in", evaluate("max(10cm, 6in)"))
220
+
221
+ assert_error_message("#aaaaaa is not a number for `max'", "max(#aaa)")
222
+ assert_error_message("Incompatible units: 'px' and 'em'.", "max(3em, 4em, 1px)")
155
223
  end
156
224
 
157
225
  def test_rgb
158
226
  assert_equal("#123456", evaluate("rgb(18, 52, 86)"))
159
227
  assert_equal("#beaded", evaluate("rgb(190, 173, 237)"))
160
- assert_equal("#00ff7f", evaluate("rgb(0, 255, 127)"))
161
- assert_equal("#00ff7f", evaluate("rgb($red: 0, $green: 255, $blue: 127)"))
228
+ assert_equal("springgreen", evaluate("rgb(0, 255, 127)"))
229
+ assert_equal("springgreen", evaluate("rgb($red: 0, $green: 255, $blue: 127)"))
162
230
  end
163
231
 
164
232
  def test_rgb_percent
165
233
  assert_equal("#123456", evaluate("rgb(7.1%, 20.4%, 34%)"))
166
234
  assert_equal("#beaded", evaluate("rgb(74.7%, 173, 93%)"))
167
235
  assert_equal("#beaded", evaluate("rgb(190, 68%, 237)"))
168
- assert_equal("#00ff7f", evaluate("rgb(0%, 100%, 50%)"))
236
+ assert_equal("springgreen", evaluate("rgb(0%, 100%, 50%)"))
169
237
  end
170
238
 
171
239
  def test_rgb_tests_bounds
172
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
240
+ assert_error_message("$red: Color value 256 must be between 0 and 255 for `rgb'",
173
241
  "rgb(256, 1, 1)")
174
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
242
+ assert_error_message("$green: Color value 256 must be between 0 and 255 for `rgb'",
175
243
  "rgb(1, 256, 1)")
176
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
244
+ assert_error_message("$blue: Color value 256 must be between 0 and 255 for `rgb'",
177
245
  "rgb(1, 1, 256)")
178
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgb'",
246
+ assert_error_message("$green: Color value 256 must be between 0 and 255 for `rgb'",
179
247
  "rgb(1, 256, 257)")
180
- assert_error_message("Color value -1 must be between 0 and 255 inclusive for `rgb'",
248
+ assert_error_message("$red: Color value -1 must be between 0 and 255 for `rgb'",
181
249
  "rgb(-1, 1, 1)")
182
250
  end
183
251
 
184
252
  def test_rgb_test_percent_bounds
185
- assert_error_message("Color value 100.1% must be between 0% and 100% inclusive for `rgb'",
253
+ assert_error_message("$red: Color value 100.1% must be between 0% and 100% for `rgb'",
186
254
  "rgb(100.1%, 0, 0)")
187
- assert_error_message("Color value -0.1% must be between 0% and 100% inclusive for `rgb'",
255
+ assert_error_message("$green: Color value -0.1% must be between 0% and 100% for `rgb'",
188
256
  "rgb(0, -0.1%, 0)")
189
- assert_error_message("Color value 101% must be between 0% and 100% inclusive for `rgb'",
257
+ assert_error_message("$blue: Color value 101% must be between 0% and 100% for `rgb'",
190
258
  "rgb(0, 0, 101%)")
191
259
  end
192
260
 
193
261
  def test_rgb_tests_types
194
- assert_error_message("\"foo\" is not a number for `rgb'", "rgb(\"foo\", 10, 12)");
195
- assert_error_message("\"foo\" is not a number for `rgb'", "rgb(10, \"foo\", 12)");
196
- assert_error_message("\"foo\" is not a number for `rgb'", "rgb(10, 10, \"foo\")");
262
+ assert_error_message("$red: \"foo\" is not a number for `rgb'", "rgb(\"foo\", 10, 12)");
263
+ assert_error_message("$green: \"foo\" is not a number for `rgb'", "rgb(10, \"foo\", 12)");
264
+ assert_error_message("$blue: \"foo\" is not a number for `rgb'", "rgb(10, 10, \"foo\")");
197
265
  end
198
266
 
199
267
  def test_rgba
@@ -203,28 +271,28 @@ class SassFunctionTest < Test::Unit::TestCase
203
271
  assert_equal("rgba(0, 255, 127, 0)", evaluate("rgba($red: 0, $green: 255, $blue: 127, $alpha: 0)"))
204
272
  end
205
273
 
206
- def test_rgb_tests_bounds
207
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
274
+ def test_rgba_tests_bounds
275
+ assert_error_message("$red: Color value 256 must be between 0 and 255 for `rgba'",
208
276
  "rgba(256, 1, 1, 0.3)")
209
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
277
+ assert_error_message("$green: Color value 256 must be between 0 and 255 for `rgba'",
210
278
  "rgba(1, 256, 1, 0.3)")
211
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
279
+ assert_error_message("$blue: Color value 256 must be between 0 and 255 for `rgba'",
212
280
  "rgba(1, 1, 256, 0.3)")
213
- assert_error_message("Color value 256 must be between 0 and 255 inclusive for `rgba'",
281
+ assert_error_message("$green: Color value 256 must be between 0 and 255 for `rgba'",
214
282
  "rgba(1, 256, 257, 0.3)")
215
- assert_error_message("Color value -1 must be between 0 and 255 inclusive for `rgba'",
283
+ assert_error_message("$red: Color value -1 must be between 0 and 255 for `rgba'",
216
284
  "rgba(-1, 1, 1, 0.3)")
217
- assert_error_message("Alpha channel -0.2 must be between 0 and 1 inclusive for `rgba'",
285
+ assert_error_message("Alpha channel -0.2 must be between 0 and 1 for `rgba'",
218
286
  "rgba(1, 1, 1, -0.2)")
219
- assert_error_message("Alpha channel 1.2 must be between 0 and 1 inclusive for `rgba'",
287
+ assert_error_message("Alpha channel 1.2 must be between 0 and 1 for `rgba'",
220
288
  "rgba(1, 1, 1, 1.2)")
221
289
  end
222
290
 
223
291
  def test_rgba_tests_types
224
- assert_error_message("\"foo\" is not a number for `rgba'", "rgba(\"foo\", 10, 12, 0.2)");
225
- assert_error_message("\"foo\" is not a number for `rgba'", "rgba(10, \"foo\", 12, 0.1)");
226
- assert_error_message("\"foo\" is not a number for `rgba'", "rgba(10, 10, \"foo\", 0)");
227
- assert_error_message("\"foo\" is not a number for `rgba'", "rgba(10, 10, 10, \"foo\")");
292
+ assert_error_message("$red: \"foo\" is not a number for `rgba'", "rgba(\"foo\", 10, 12, 0.2)");
293
+ assert_error_message("$green: \"foo\" is not a number for `rgba'", "rgba(10, \"foo\", 12, 0.1)");
294
+ assert_error_message("$blue: \"foo\" is not a number for `rgba'", "rgba(10, 10, \"foo\", 0)");
295
+ assert_error_message("$alpha: \"foo\" is not a number for `rgba'", "rgba(10, 10, 10, \"foo\")");
228
296
  end
229
297
 
230
298
  def test_rgba_with_color
@@ -234,8 +302,8 @@ class SassFunctionTest < Test::Unit::TestCase
234
302
  end
235
303
 
236
304
  def test_rgba_with_color_tests_types
237
- assert_error_message("\"foo\" is not a color for `rgba'", "rgba(\"foo\", 0.2)");
238
- assert_error_message("\"foo\" is not a number for `rgba'", "rgba(blue, \"foo\")");
305
+ assert_error_message("$color: \"foo\" is not a color for `rgba'", "rgba(\"foo\", 0.2)");
306
+ assert_error_message("$alpha: \"foo\" is not a number for `rgba'", "rgba(blue, \"foo\")");
239
307
  end
240
308
 
241
309
  def test_rgba_tests_num_args
@@ -251,7 +319,7 @@ class SassFunctionTest < Test::Unit::TestCase
251
319
  end
252
320
 
253
321
  def test_red_exception
254
- assert_error_message("12 is not a color for `red'", "red(12)")
322
+ assert_error_message("$color: 12 is not a color for `red'", "red(12)")
255
323
  end
256
324
 
257
325
  def test_green
@@ -260,7 +328,7 @@ class SassFunctionTest < Test::Unit::TestCase
260
328
  end
261
329
 
262
330
  def test_green_exception
263
- assert_error_message("12 is not a color for `green'", "green(12)")
331
+ assert_error_message("$color: 12 is not a color for `green'", "green(12)")
264
332
  end
265
333
 
266
334
  def test_blue
@@ -269,7 +337,7 @@ class SassFunctionTest < Test::Unit::TestCase
269
337
  end
270
338
 
271
339
  def test_blue_exception
272
- assert_error_message("12 is not a color for `blue'", "blue(12)")
340
+ assert_error_message("$color: 12 is not a color for `blue'", "blue(12)")
273
341
  end
274
342
 
275
343
  def test_hue
@@ -278,7 +346,7 @@ class SassFunctionTest < Test::Unit::TestCase
278
346
  end
279
347
 
280
348
  def test_hue_exception
281
- assert_error_message("12 is not a color for `hue'", "hue(12)")
349
+ assert_error_message("$color: 12 is not a color for `hue'", "hue(12)")
282
350
  end
283
351
 
284
352
  def test_saturation
@@ -288,7 +356,7 @@ class SassFunctionTest < Test::Unit::TestCase
288
356
  end
289
357
 
290
358
  def test_saturation_exception
291
- assert_error_message("12 is not a color for `saturation'", "saturation(12)")
359
+ assert_error_message("$color: 12 is not a color for `saturation'", "saturation(12)")
292
360
  end
293
361
 
294
362
  def test_lightness
@@ -298,7 +366,7 @@ class SassFunctionTest < Test::Unit::TestCase
298
366
  end
299
367
 
300
368
  def test_lightness_exception
301
- assert_error_message("12 is not a color for `lightness'", "lightness(12)")
369
+ assert_error_message("$color: 12 is not a color for `lightness'", "lightness(12)")
302
370
  end
303
371
 
304
372
  def test_alpha
@@ -309,7 +377,19 @@ class SassFunctionTest < Test::Unit::TestCase
309
377
  end
310
378
 
311
379
  def test_alpha_exception
312
- assert_error_message("12 is not a color for `alpha'", "alpha(12)")
380
+ assert_error_message("$color: 12 is not a color for `alpha'", "alpha(12)")
381
+ end
382
+
383
+ def test_opacity
384
+ assert_equal("1", evaluate("opacity(#123456)"))
385
+ assert_equal("0.34", evaluate("opacity(rgba(0, 1, 2, 0.34))"))
386
+ assert_equal("0", evaluate("opacity(hsla(0, 1, 2, 0))"))
387
+ assert_equal("0", evaluate("opacity($color: hsla(0, 1, 2, 0))"))
388
+ assert_equal("opacity(20%)", evaluate("opacity(20%)"))
389
+ end
390
+
391
+ def test_opacity_exception
392
+ assert_error_message("$color: \"foo\" is not a color for `opacity'", "opacity(foo)")
313
393
  end
314
394
 
315
395
  def test_opacify
@@ -331,16 +411,16 @@ class SassFunctionTest < Test::Unit::TestCase
331
411
  end
332
412
 
333
413
  def test_opacify_tests_types
334
- assert_error_message("\"foo\" is not a color for `opacify'", "opacify(\"foo\", 10%)")
335
- assert_error_message("\"foo\" is not a number for `opacify'", "opacify(#fff, \"foo\")")
414
+ assert_error_message("$color: \"foo\" is not a color for `opacify'", "opacify(\"foo\", 10%)")
415
+ assert_error_message("$amount: \"foo\" is not a number for `opacify'", "opacify(#fff, \"foo\")")
336
416
  end
337
417
 
338
418
  def test_transparentize
339
419
  assert_equal("rgba(0, 0, 0, 0.3)", evaluate("transparentize(rgba(0, 0, 0, 0.5), 0.2)"))
340
420
  assert_equal("rgba(0, 0, 0, 0.1)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 0.1)"))
341
421
  assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-out(rgba(0, 0, 0, 0.5), 0.3px)"))
342
- assert_equal("rgba(0, 0, 0, 0)", evaluate("fade_out(rgba(0, 0, 0, 0.2), 0.2)"))
343
- assert_equal("rgba(0, 0, 0, 0)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 1)"))
422
+ assert_equal("transparent", evaluate("fade_out(rgba(0, 0, 0, 0.2), 0.2)"))
423
+ assert_equal("transparent", evaluate("transparentize(rgba(0, 0, 0, 0.2), 1)"))
344
424
  assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize(rgba(0, 0, 0, 0.2), 0)"))
345
425
  assert_equal("rgba(0, 0, 0, 0.2)", evaluate("transparentize($color: rgba(0, 0, 0, 0.2), $amount: 0)"))
346
426
  assert_equal("rgba(0, 0, 0, 0.2)", evaluate("fade-out($color: rgba(0, 0, 0, 0.2), $amount: 0)"))
@@ -354,8 +434,8 @@ class SassFunctionTest < Test::Unit::TestCase
354
434
  end
355
435
 
356
436
  def test_transparentize_tests_types
357
- assert_error_message("\"foo\" is not a color for `transparentize'", "transparentize(\"foo\", 10%)")
358
- assert_error_message("\"foo\" is not a number for `transparentize'", "transparentize(#fff, \"foo\")")
437
+ assert_error_message("$color: \"foo\" is not a color for `transparentize'", "transparentize(\"foo\", 10%)")
438
+ assert_error_message("$amount: \"foo\" is not a number for `transparentize'", "transparentize(#fff, \"foo\")")
359
439
  end
360
440
 
361
441
  def test_lighten
@@ -376,8 +456,8 @@ class SassFunctionTest < Test::Unit::TestCase
376
456
  end
377
457
 
378
458
  def test_lighten_tests_types
379
- assert_error_message("\"foo\" is not a color for `lighten'", "lighten(\"foo\", 10%)")
380
- assert_error_message("\"foo\" is not a number for `lighten'", "lighten(#fff, \"foo\")")
459
+ assert_error_message("$color: \"foo\" is not a color for `lighten'", "lighten(\"foo\", 10%)")
460
+ assert_error_message("$amount: \"foo\" is not a number for `lighten'", "lighten(#fff, \"foo\")")
381
461
  end
382
462
 
383
463
  def test_darken
@@ -398,8 +478,8 @@ class SassFunctionTest < Test::Unit::TestCase
398
478
  end
399
479
 
400
480
  def test_darken_tests_types
401
- assert_error_message("\"foo\" is not a color for `darken'", "darken(\"foo\", 10%)")
402
- assert_error_message("\"foo\" is not a number for `darken'", "darken(#fff, \"foo\")")
481
+ assert_error_message("$color: \"foo\" is not a color for `darken'", "darken(\"foo\", 10%)")
482
+ assert_error_message("$amount: \"foo\" is not a number for `darken'", "darken(#fff, \"foo\")")
403
483
  end
404
484
 
405
485
  def test_saturate
@@ -411,6 +491,7 @@ class SassFunctionTest < Test::Unit::TestCase
411
491
  assert_equal("#88aa88", evaluate("saturate(#8a8, 0%)"))
412
492
  assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate(rgba(136, 85, 85, 0.5), 20%)"))
413
493
  assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate($color: rgba(136, 85, 85, 0.5), $amount: 20%)"))
494
+ assert_equal("saturate(50%)", evaluate("saturate(50%)"))
414
495
  end
415
496
 
416
497
  def test_saturate_tests_bounds
@@ -421,8 +502,8 @@ class SassFunctionTest < Test::Unit::TestCase
421
502
  end
422
503
 
423
504
  def test_saturate_tests_types
424
- assert_error_message("\"foo\" is not a color for `saturate'", "saturate(\"foo\", 10%)")
425
- assert_error_message("\"foo\" is not a number for `saturate'", "saturate(#fff, \"foo\")")
505
+ assert_error_message("$color: \"foo\" is not a color for `saturate'", "saturate(\"foo\", 10%)")
506
+ assert_error_message("$amount: \"foo\" is not a number for `saturate'", "saturate(#fff, \"foo\")")
426
507
  end
427
508
 
428
509
  def test_desaturate
@@ -444,8 +525,8 @@ class SassFunctionTest < Test::Unit::TestCase
444
525
  end
445
526
 
446
527
  def test_desaturate_tests_types
447
- assert_error_message("\"foo\" is not a color for `desaturate'", "desaturate(\"foo\", 10%)")
448
- assert_error_message("\"foo\" is not a number for `desaturate'", "desaturate(#fff, \"foo\")")
528
+ assert_error_message("$color: \"foo\" is not a color for `desaturate'", "desaturate(\"foo\", 10%)")
529
+ assert_error_message("$amount: \"foo\" is not a number for `desaturate'", "desaturate(#fff, \"foo\")")
449
530
  end
450
531
 
451
532
  def test_adjust_hue
@@ -461,8 +542,8 @@ class SassFunctionTest < Test::Unit::TestCase
461
542
  end
462
543
 
463
544
  def test_adjust_hue_tests_types
464
- assert_error_message("\"foo\" is not a color for `adjust-hue'", "adjust-hue(\"foo\", 10%)")
465
- assert_error_message("\"foo\" is not a number for `adjust-hue'", "adjust-hue(#fff, \"foo\")")
545
+ assert_error_message("$color: \"foo\" is not a color for `adjust-hue'", "adjust-hue(\"foo\", 10%)")
546
+ assert_error_message("$degrees: \"foo\" is not a number for `adjust-hue'", "adjust-hue(#fff, \"foo\")")
466
547
  end
467
548
 
468
549
  def test_adjust_color
@@ -520,7 +601,7 @@ class SassFunctionTest < Test::Unit::TestCase
520
601
  end
521
602
 
522
603
  def test_adjust_color_tests_types
523
- assert_error_message("\"foo\" is not a color for `adjust-color'", "adjust-color(foo, $hue: 10)")
604
+ assert_error_message("$color: \"foo\" is not a color for `adjust-color'", "adjust-color(foo, $hue: 10)")
524
605
  # HSL
525
606
  assert_error_message("$hue: \"foo\" is not a number for `adjust-color'",
526
607
  "adjust-color(blue, $hue: foo)")
@@ -626,7 +707,7 @@ class SassFunctionTest < Test::Unit::TestCase
626
707
  end
627
708
 
628
709
  def test_scale_color_tests_types
629
- assert_error_message("\"foo\" is not a color for `scale-color'", "scale-color(foo, $red: 10%)")
710
+ assert_error_message("$color: \"foo\" is not a color for `scale-color'", "scale-color(foo, $red: 10%)")
630
711
  # HSL
631
712
  assert_error_message("$saturation: \"foo\" is not a number for `scale-color'",
632
713
  "scale-color(blue, $saturation: foo)")
@@ -654,9 +735,9 @@ class SassFunctionTest < Test::Unit::TestCase
654
735
  "scale-color(blue, $alpha: -101%)")
655
736
 
656
737
  # Unit
657
- assert_error_message("$saturation: Amount 80 must be a % (e.g. 80%) for `scale-color'",
738
+ assert_error_message("Expected $saturation to have a unit of % but got 80 for `scale-color'",
658
739
  "scale-color(blue, $saturation: 80)")
659
- assert_error_message("$alpha: Amount 0.5 must be a % (e.g. 0.5%) for `scale-color'",
740
+ assert_error_message("Expected $alpha to have a unit of % but got 0.5 for `scale-color'",
660
741
  "scale-color(blue, $alpha: 0.5)")
661
742
 
662
743
  # Unknown argument
@@ -697,7 +778,7 @@ class SassFunctionTest < Test::Unit::TestCase
697
778
  end
698
779
 
699
780
  def test_change_color_tests_types
700
- assert_error_message("\"foo\" is not a color for `change-color'", "change-color(foo, $red: 10%)")
781
+ assert_error_message("$color: \"foo\" is not a color for `change-color'", "change-color(foo, $red: 10%)")
701
782
  # HSL
702
783
  assert_error_message("$saturation: \"foo\" is not a number for `change-color'",
703
784
  "change-color(blue, $saturation: foo)")
@@ -713,15 +794,15 @@ class SassFunctionTest < Test::Unit::TestCase
713
794
 
714
795
  def test_change_color_argument_errors
715
796
  # Range
716
- assert_error_message("Saturation must be between 0 and 100 for `change-color'",
797
+ assert_error_message("Saturation 101% must be between 0% and 100% for `change-color'",
717
798
  "change-color(blue, $saturation: 101%)")
718
- assert_error_message("Lightness must be between 0 and 100 for `change-color'",
799
+ assert_error_message("Lightness 101% must be between 0% and 100% for `change-color'",
719
800
  "change-color(blue, $lightness: 101%)")
720
- assert_error_message("Red value must be between 0 and 255 for `change-color'",
801
+ assert_error_message("Red value -1 must be between 0 and 255 for `change-color'",
721
802
  "change-color(blue, $red: -1)")
722
- assert_error_message("Green value must be between 0 and 255 for `change-color'",
803
+ assert_error_message("Green value 256 must be between 0 and 255 for `change-color'",
723
804
  "change-color(blue, $green: 256)")
724
- assert_error_message("Blue value must be between 0 and 255 for `change-color'",
805
+ assert_error_message("Blue value 500 must be between 0 and 255 for `change-color'",
725
806
  "change-color(blue, $blue: 500)")
726
807
 
727
808
  # Unknown argument
@@ -735,6 +816,13 @@ class SassFunctionTest < Test::Unit::TestCase
735
816
  "change-color(blue, $lightness: 10%, $red: 120)");
736
817
  end
737
818
 
819
+ def test_ie_hex_str
820
+ assert_equal("#FFAA11CC", evaluate('ie-hex-str(#aa11cc)'))
821
+ assert_equal("#FFAA11CC", evaluate('ie-hex-str(#a1c)'))
822
+ assert_equal("#FFAA11CC", evaluate('ie-hex-str(#A1c)'))
823
+ assert_equal("#80FF0000", evaluate('ie-hex-str(rgba(255, 0, 0, 0.5))'))
824
+ end
825
+
738
826
  def test_mix
739
827
  assert_equal("#7f007f", evaluate("mix(#f00, #00f)"))
740
828
  assert_equal("#7f7f7f", evaluate("mix(#f00, #0ff)"))
@@ -749,13 +837,39 @@ class SassFunctionTest < Test::Unit::TestCase
749
837
  assert_equal("blue", evaluate("mix(transparentize(#f00, 1), #00f, 0%)"))
750
838
  assert_equal("rgba(0, 0, 255, 0)", evaluate("mix(#f00, transparentize(#00f, 1), 0%)"))
751
839
  assert_equal("rgba(255, 0, 0, 0)", evaluate("mix(transparentize(#f00, 1), #00f, 100%)"))
752
- assert_equal("rgba(255, 0, 0, 0)", evaluate("mix($color-1: transparentize(#f00, 1), $color-2: #00f, $weight: 100%)"))
840
+ assert_equal("rgba(255, 0, 0, 0)", evaluate("mix($color1: transparentize(#f00, 1), $color2: #00f, $weight: 100%)"))
841
+ end
842
+
843
+ def test_mix_deprecated_arg_name
844
+ assert_warning <<WARNING do
845
+ DEPRECATION WARNING: The `$color-1' argument for `mix()' has been renamed to `$color1'.
846
+ DEPRECATION WARNING: The `$color-2' argument for `mix()' has been renamed to `$color2'.
847
+ WARNING
848
+ assert_equal("rgba(255, 0, 0, 0)",
849
+ evaluate("mix($color-1: transparentize(#f00, 1), $color-2: #00f, $weight: 100%)"))
850
+ end
851
+
852
+ assert_warning <<WARNING do
853
+ DEPRECATION WARNING: The `$color-1' argument for `mix()' has been renamed to `$color1'.
854
+ DEPRECATION WARNING: The `$color-2' argument for `mix()' has been renamed to `$color2'.
855
+ WARNING
856
+ assert_equal("rgba(0, 0, 255, 0.5)",
857
+ evaluate("mix($color-1: transparentize(#f00, 1), $color-2: #00f)"))
858
+ end
859
+
860
+ assert_warning <<WARNING do
861
+ DEPRECATION WARNING: The `$color_1' argument for `mix()' has been renamed to `$color1'.
862
+ DEPRECATION WARNING: The `$color_2' argument for `mix()' has been renamed to `$color2'.
863
+ WARNING
864
+ assert_equal("rgba(0, 0, 255, 0.5)",
865
+ evaluate("mix($color_1: transparentize(#f00, 1), $color_2: #00f)"))
866
+ end
753
867
  end
754
868
 
755
869
  def test_mix_tests_types
756
- assert_error_message("\"foo\" is not a color for `mix'", "mix(\"foo\", #f00, 10%)")
757
- assert_error_message("\"foo\" is not a color for `mix'", "mix(#f00, \"foo\", 10%)")
758
- assert_error_message("\"foo\" is not a number for `mix'", "mix(#f00, #baf, \"foo\")")
870
+ assert_error_message("$color1: \"foo\" is not a color for `mix'", "mix(\"foo\", #f00, 10%)")
871
+ assert_error_message("$color2: \"foo\" is not a color for `mix'", "mix(#f00, \"foo\", 10%)")
872
+ assert_error_message("$weight: \"foo\" is not a number for `mix'", "mix(#f00, #baf, \"foo\")")
759
873
  end
760
874
 
761
875
  def test_mix_tests_bounds
@@ -772,32 +886,36 @@ class SassFunctionTest < Test::Unit::TestCase
772
886
  assert_equal("white", evaluate("grayscale(white)"))
773
887
  assert_equal("black", evaluate("grayscale(black)"))
774
888
  assert_equal("black", evaluate("grayscale($color: black)"))
889
+
890
+ assert_equal("grayscale(2)", evaluate("grayscale(2)"))
891
+ assert_equal("grayscale(-5px)", evaluate("grayscale(-5px)"))
775
892
  end
776
893
 
777
894
  def tets_grayscale_tests_types
778
- assert_error_message("\"foo\" is not a color for `grayscale'", "grayscale(\"foo\")")
895
+ assert_error_message("$color: \"foo\" is not a color for `grayscale'", "grayscale(\"foo\")")
779
896
  end
780
897
 
781
898
  def test_complement
782
899
  assert_equal("#ccbbaa", evaluate("complement(#abc)"))
783
- assert_equal("aqua", evaluate("complement(red)"))
784
- assert_equal("red", evaluate("complement(aqua)"))
900
+ assert_equal("cyan", evaluate("complement(red)"))
901
+ assert_equal("red", evaluate("complement(cyan)"))
785
902
  assert_equal("white", evaluate("complement(white)"))
786
903
  assert_equal("black", evaluate("complement(black)"))
787
904
  assert_equal("black", evaluate("complement($color: black)"))
788
905
  end
789
906
 
790
907
  def tets_complement_tests_types
791
- assert_error_message("\"foo\" is not a color for `complement'", "complement(\"foo\")")
908
+ assert_error_message("$color: \"foo\" is not a color for `complement'", "complement(\"foo\")")
792
909
  end
793
910
 
794
911
  def test_invert
795
912
  assert_equal("#112233", evaluate("invert(#edc)"))
796
913
  assert_equal("rgba(245, 235, 225, 0.5)", evaluate("invert(rgba(10, 20, 30, 0.5))"))
914
+ assert_equal("invert(20%)", evaluate("invert(20%)"))
797
915
  end
798
916
 
799
917
  def test_invert_tests_types
800
- assert_error_message("\"foo\" is not a color for `invert'", "invert(\"foo\")")
918
+ assert_error_message("$color: \"foo\" is not a color for `invert'", "invert(\"foo\")")
801
919
  end
802
920
 
803
921
  def test_unquote
@@ -813,7 +931,83 @@ class SassFunctionTest < Test::Unit::TestCase
813
931
  end
814
932
 
815
933
  def test_quote_tests_type
816
- assert_error_message("#ff0000 is not a string for `quote'", "quote(#f00)")
934
+ assert_error_message("$string: #ff0000 is not a string for `quote'", "quote(#f00)")
935
+ end
936
+
937
+ def test_str_length
938
+ assert_equal('3', evaluate('str-length(foo)'))
939
+ end
940
+
941
+ def test_str_length_requires_a_string
942
+ assert_error_message("$string: #ff0000 is not a string for `str-length'", "str-length(#f00)")
943
+ end
944
+
945
+ def test_str_insert
946
+ assert_equal('Xabcd', evaluate('str-insert(abcd, X, 0)'))
947
+ assert_equal('Xabcd', evaluate('str-insert(abcd, X, 1)'))
948
+ assert_equal('abcXd', evaluate('str-insert(abcd, X, 4)'))
949
+ assert_equal('abcdX', evaluate('str-insert(abcd, X, 100)'))
950
+ assert_equal('Xabcd', evaluate('str-insert(abcd, X, -100)'))
951
+ assert_equal('aXbcd', evaluate('str-insert(abcd, X, -4)'))
952
+ assert_equal('abcdX', evaluate('str-insert(abcd, X, -1)'))
953
+ end
954
+
955
+ def test_str_insert_maintains_quote_of_primary_string
956
+ assert_equal('"Xfoo"', evaluate('str-insert("foo", X, 1)'))
957
+ assert_equal('"Xfoo"', evaluate('str-insert("foo", "X", 1)'))
958
+ assert_equal('Xfoo', evaluate('str-insert(foo, "X", 1)'))
959
+ end
960
+
961
+ def test_str_insert_asserts_types
962
+ assert_error_message("$string: #ff0000 is not a string for `str-insert'", "str-insert(#f00, X, 1)")
963
+ assert_error_message("$insert: #ff0000 is not a string for `str-insert'", "str-insert(foo, #f00, 1)")
964
+ assert_error_message("$index: #ff0000 is not a number for `str-insert'", "str-insert(foo, X, #f00)")
965
+ assert_error_message("Expected $index to be unitless but got 10px for `str-insert'", "str-insert(foo, X, 10px)")
966
+ end
967
+
968
+ def test_str_index
969
+ assert_equal('1', evaluate('str-index(abcd, a)'))
970
+ assert_equal('1', evaluate('str-index(abcd, ab)'))
971
+ assert_equal(Sass::Script::Value::Null.new, perform('str-index(abcd, X)'))
972
+ assert_equal('3', evaluate('str-index(abcd, c)'))
973
+ end
974
+
975
+ def test_str_index_asserts_types
976
+ assert_error_message("$string: #ff0000 is not a string for `str-index'", "str-index(#f00, X)")
977
+ assert_error_message("$substring: #ff0000 is not a string for `str-index'", "str-index(asdf, #f00)")
978
+ end
979
+
980
+ def test_to_lower_case
981
+ assert_equal('abcd', evaluate('to-lower-case(ABCD)'))
982
+ assert_equal('"abcd"', evaluate('to-lower-case("ABCD")'))
983
+ assert_error_message("$string: #ff0000 is not a string for `to-lower-case'", "to-lower-case(#f00)")
984
+ end
985
+
986
+ def test_to_upper_case
987
+ assert_equal('ABCD', evaluate('to-upper-case(abcd)'))
988
+ assert_equal('"ABCD"', evaluate('to-upper-case("abcd")'))
989
+ assert_error_message("$string: #ff0000 is not a string for `to-upper-case'", "to-upper-case(#f00)")
990
+ end
991
+
992
+ def test_str_slice
993
+ assert_equal('bc', evaluate('str-slice(abcd,2,3)')) # in the middle of the string
994
+ assert_equal('a', evaluate('str-slice(abcd,1,1)')) # when start = end
995
+ assert_equal('ab', evaluate('str-slice(abcd,1,2)')) # for completeness
996
+ assert_equal('abcd', evaluate('str-slice(abcd,1,4)')) # at the end points
997
+ assert_equal('abcd', evaluate('str-slice(abcd,0,4)')) # when start is before the start of the string
998
+ assert_equal('abcd', evaluate('str-slice(abcd,1,100)')) # when end is past the end of the string
999
+ assert_equal('', evaluate('str-slice(abcd,2,1)')) # when end is before start
1000
+ assert_equal('"bc"', evaluate('str-slice("abcd",2,3)')) # when used with a quoted string
1001
+ assert_equal('bcd', evaluate('str-slice(abcd,2)')) # when end is omitted, you get the remainder of the string
1002
+ assert_equal('cd', evaluate('str-slice(abcd,-2)')) # when start is negative, it counts from the beginning
1003
+ assert_equal('bc', evaluate('str-slice(abcd,2,-2)')) # when end is negative it counts in from the end
1004
+ assert_equal('', evaluate('str-slice(abcd,3,-3)')) # when end is negative and comes before the start
1005
+ assert_equal('bc', evaluate('str-slice(abcd,-3,-2)')) # when both are negative
1006
+ assert_error_message("$string: #ff0000 is not a string for `str-slice'", "str-slice(#f00,2,3)")
1007
+ assert_error_message("$start-at: #ff0000 is not a number for `str-slice'", "str-slice(abcd,#f00,3)")
1008
+ assert_error_message("$end-at: #ff0000 is not a number for `str-slice'", "str-slice(abcd,2,#f00)")
1009
+ assert_error_message("Expected $end-at to be unitless but got 3px for `str-slice'", "str-slice(abcd,2,3px)")
1010
+ assert_error_message("Expected $start-at to be unitless but got 2px for `str-slice'", "str-slice(abcd,2px,3)")
817
1011
  end
818
1012
 
819
1013
  def test_user_defined_function
@@ -825,12 +1019,17 @@ class SassFunctionTest < Test::Unit::TestCase
825
1019
  assert_equal("I'm another user-defined string!", evaluate("-preceding-underscore()"))
826
1020
  end
827
1021
 
828
- def test_options_on_new_literals_fails
829
- assert_error_message(<<MSG, "call-options-on-new-literal()")
830
- The #options attribute is not set on this Sass::Script::String.
1022
+ def test_user_defined_function_using_environment
1023
+ environment = env('variable' => Sass::Script::Value::String.new('The variable'))
1024
+ assert_equal("The variable", evaluate("fetch_the_variable()", environment))
1025
+ end
1026
+
1027
+ def test_options_on_new_values_fails
1028
+ assert_error_message(<<MSG, "call-options-on-new-value()")
1029
+ The #options attribute is not set on this Sass::Script::Value::String.
831
1030
  This error is probably occurring because #to_s was called
832
- on this literal within a custom Sass function without first
833
- setting the #option attribute.
1031
+ on this value within a custom Sass function without first
1032
+ setting the #options attribute.
834
1033
  MSG
835
1034
  end
836
1035
 
@@ -841,6 +1040,23 @@ MSG
841
1040
  assert_equal("bool", evaluate("type-of(true)"))
842
1041
  assert_equal("color", evaluate("type-of(#fff)"))
843
1042
  assert_equal("color", evaluate("type-of($value: #fff)"))
1043
+ assert_equal("null", evaluate("type-of(null)"))
1044
+ assert_equal("list", evaluate("type-of(1 2 3)"))
1045
+ assert_equal("list", evaluate("type-of((1, 2, 3))"))
1046
+ assert_equal("list", evaluate("type-of(())"))
1047
+ assert_equal("map", evaluate("type-of((foo: bar))"))
1048
+ end
1049
+
1050
+ def test_feature_exists
1051
+ assert_raises ArgumentError do
1052
+ Sass.add_feature("my-test-feature")
1053
+ end
1054
+ Sass.add_feature("-my-test-feature")
1055
+ assert_equal("true", evaluate("feature-exists(-my-test-feature)"))
1056
+ assert_equal("false", evaluate("feature-exists(whatisthisidontevenknow)"))
1057
+ assert_equal("true", evaluate("feature-exists($feature: -my-test-feature)"))
1058
+ ensure
1059
+ Sass::Features::KNOWN_FEATURES.delete("-my-test-feature")
844
1060
  end
845
1061
 
846
1062
  def test_unit
@@ -848,25 +1064,45 @@ MSG
848
1064
  assert_equal(%Q{"px"}, evaluate("unit(100px)"))
849
1065
  assert_equal(%Q{"em*px"}, evaluate("unit(10px * 5em)"))
850
1066
  assert_equal(%Q{"em*px"}, evaluate("unit(5em * 10px)"))
851
- assert_equal(%Q{"em*px/cm*rem"}, evaluate("unit(10px * 5em / 30cm / 1rem)"))
1067
+ assert_equal(%Q{"em/rem"}, evaluate("unit(10px * 5em / 30cm / 1rem)"))
1068
+ assert_equal(%Q{"em*vh/cm*rem"}, evaluate("unit(10vh * 5em / 30cm / 1rem)"))
852
1069
  assert_equal(%Q{"px"}, evaluate("unit($number: 100px)"))
853
- assert_error_message("#ff0000 is not a number for `unit'", "unit(#f00)")
1070
+ assert_error_message("$number: #ff0000 is not a number for `unit'", "unit(#f00)")
854
1071
  end
855
1072
 
856
1073
  def test_unitless
857
1074
  assert_equal(%Q{true}, evaluate("unitless(100)"))
858
1075
  assert_equal(%Q{false}, evaluate("unitless(100px)"))
859
1076
  assert_equal(%Q{false}, evaluate("unitless($number: 100px)"))
860
- assert_error_message("#ff0000 is not a number for `unitless'", "unitless(#f00)")
1077
+ assert_error_message("$number: #ff0000 is not a number for `unitless'", "unitless(#f00)")
861
1078
  end
862
1079
 
863
1080
  def test_comparable
864
1081
  assert_equal(%Q{true}, evaluate("comparable(2px, 1px)"))
865
1082
  assert_equal(%Q{true}, evaluate("comparable(10cm, 3mm)"))
866
1083
  assert_equal(%Q{false}, evaluate("comparable(100px, 3em)"))
867
- assert_equal(%Q{false}, evaluate("comparable($number-1: 100px, $number-2: 3em)"))
868
- assert_error_message("#ff0000 is not a number for `comparable'", "comparable(#f00, 1px)")
869
- assert_error_message("#ff0000 is not a number for `comparable'", "comparable(1px, #f00)")
1084
+ assert_equal(%Q{false}, evaluate("comparable($number1: 100px, $number2: 3em)"))
1085
+ end
1086
+
1087
+ def test_comparable_deprecated_arg_name
1088
+ assert_warning <<WARNING do
1089
+ DEPRECATION WARNING: The `$number-1' argument for `comparable()' has been renamed to `$number1'.
1090
+ DEPRECATION WARNING: The `$number-2' argument for `comparable()' has been renamed to `$number2'.
1091
+ WARNING
1092
+ assert_equal("false", evaluate("comparable($number-1: 100px, $number-2: 3em)"))
1093
+ end
1094
+
1095
+ assert_warning <<WARNING do
1096
+ DEPRECATION WARNING: The `$number_1' argument for `comparable()' has been renamed to `$number1'.
1097
+ DEPRECATION WARNING: The `$number_2' argument for `comparable()' has been renamed to `$number2'.
1098
+ WARNING
1099
+ assert_equal("false", evaluate("comparable($number_1: 100px, $number_2: 3em)"))
1100
+ end
1101
+ end
1102
+
1103
+ def test_comparable_checks_types
1104
+ assert_error_message("$number1: #ff0000 is not a number for `comparable'", "comparable(#f00, 1px)")
1105
+ assert_error_message("$number2: #ff0000 is not a number for `comparable'", "comparable(1px, #f00)")
870
1106
  end
871
1107
 
872
1108
  def test_length
@@ -877,20 +1113,47 @@ MSG
877
1113
  assert_equal("1", evaluate("length(#f00)"))
878
1114
  assert_equal("0", evaluate("length(())"))
879
1115
  assert_equal("4", evaluate("length(1 2 () 3)"))
1116
+
1117
+ assert_equal("2", evaluate("length((foo: bar, bar: baz))"))
880
1118
  end
881
1119
 
882
1120
  def test_nth
883
1121
  assert_equal("1", evaluate("nth(1 2 3, 1)"))
884
1122
  assert_equal("2", evaluate("nth(1 2 3, 2)"))
1123
+ assert_equal("3", evaluate("nth(1 2 3, -1)"))
1124
+ assert_equal("1", evaluate("nth(1 2 3, -3)"))
885
1125
  assert_equal("3", evaluate("nth((1, 2, 3), 3)"))
1126
+ assert_equal("3", evaluate("nth($list: (1, 2, 3), $n: 3)"))
886
1127
  assert_equal("foo", evaluate("nth(foo, 1)"))
887
1128
  assert_equal("bar baz", evaluate("nth(foo (bar baz) bang, 2)"))
888
- assert_error_message("List index 0 must be greater than or equal to 1 for `nth'", "nth(foo, 0)")
889
- assert_error_message("List index -10 must be greater than or equal to 1 for `nth'", "nth(foo, -10)")
890
- assert_error_message("List index 1.5 must be an integer for `nth'", "nth(foo, 1.5)")
1129
+ assert_error_message("List index 0 must be a non-zero integer for `nth'", "nth(foo, 0)")
1130
+ assert_error_message("List index is -10 but list is only 1 item long for `nth'", "nth(foo, -10)")
1131
+ assert_error_message("List index 1.5 must be a non-zero integer for `nth'", "nth(foo, 1.5)")
891
1132
  assert_error_message("List index is 5 but list is only 4 items long for `nth'", "nth(1 2 3 4, 5)")
892
1133
  assert_error_message("List index is 2 but list is only 1 item long for `nth'", "nth(foo, 2)")
893
1134
  assert_error_message("List index is 1 but list has no items for `nth'", "nth((), 1)")
1135
+ assert_error_message("$n: \"foo\" is not a number for `nth'", "nth(1 2 3, foo)")
1136
+
1137
+ assert_equal("foo bar", evaluate("nth((foo: bar, bar: baz), 1)"))
1138
+ assert_equal("bar baz", evaluate("nth((foo: bar, bar: baz), 2)"))
1139
+ end
1140
+
1141
+ def test_set_nth
1142
+ assert_equal("a 2 3", evaluate("set-nth(1 2 3, 1, a)"))
1143
+ assert_equal("1 a 3", evaluate("set-nth(1 2 3, 2, a)"))
1144
+ assert_equal("1 2 a", evaluate("set-nth(1 2 3, -1, a)"))
1145
+ assert_equal("a 2 3", evaluate("set-nth(1 2 3, -3, a)"))
1146
+ assert_equal("a 2 3", evaluate("set-nth($list: 1 2 3, $n: -3, $value: a)"))
1147
+ assert_equal("1, 2, a", evaluate("set-nth((1, 2, 3), 3, a)"))
1148
+ assert_equal("a", evaluate("set-nth(foo, 1, a)"))
1149
+ assert_equal("foo, a b, baz", evaluate("set-nth((foo, bar, baz), 2, (a b))"))
1150
+ assert_error_message("List index 0 must be a non-zero integer for `set-nth'", "set-nth(foo, 0, a)")
1151
+ assert_error_message("List index is -10 but list is only 1 item long for `set-nth'", "set-nth(foo, -10, a)")
1152
+ assert_error_message("List index 1.5 must be a non-zero integer for `set-nth'", "set-nth(foo, 1.5, a)")
1153
+ assert_error_message("List index is 5 but list is only 4 items long for `set-nth'", "set-nth(1 2 3 4, 5, a)")
1154
+ assert_error_message("List index is 2 but list is only 1 item long for `set-nth'", "set-nth(foo, 2, a)")
1155
+ assert_error_message("List index is 1 but list has no items for `set-nth'", "set-nth((), 1, a)")
1156
+ assert_error_message("$n: \"foo\" is not a number for `set-nth'", "set-nth(1 2 3, foo, a)")
894
1157
  end
895
1158
 
896
1159
  def test_join
@@ -929,6 +1192,20 @@ MSG
929
1192
  assert_equal("false", evaluate("(1, 2, ()) == join((), (1, 2))"))
930
1193
 
931
1194
  assert_error_message("Separator name must be space, comma, or auto for `join'", "join(1, 2, baboon)")
1195
+ assert_error_message("$separator: 12 is not a string for `join'", "join(1, 2, 12)")
1196
+
1197
+ assert_equal("foo bar, bar baz, baz bip, bip bop",
1198
+ perform("join((foo: bar, bar: baz), (baz: bip, bip: bop))").to_sass)
1199
+ assert_equal("(foo bar) (bar baz) (baz bip) (bip bop)",
1200
+ perform("join((foo: bar, bar: baz), (baz: bip, bip: bop), space)").to_sass)
1201
+ assert_equal("foo bar (baz bip) (bip bop)",
1202
+ perform("join(foo bar, (baz: bip, bip: bop))").to_sass)
1203
+ assert_equal("foo bar, bar baz, bip, bop",
1204
+ perform("join((foo: bar, bar: baz), bip bop)").to_sass)
1205
+ assert_equal("baz bip, bip bop",
1206
+ perform("join((), (baz: bip, bip: bop))").to_sass)
1207
+ assert_equal("foo bar, bar baz",
1208
+ perform("join((foo: bar, bar: baz), ())").to_sass)
932
1209
  end
933
1210
 
934
1211
  def test_append
@@ -963,11 +1240,145 @@ MSG
963
1240
  assert_equal("true", evaluate("(1 2) == nth(append((), 1 2), 1)"))
964
1241
 
965
1242
  assert_error_message("Separator name must be space, comma, or auto for `append'", "append(1, 2, baboon)")
1243
+ assert_error_message("$separator: 12 is not a string for `append'", "append(1, 2, 12)")
1244
+
1245
+ assert_equal("1 2 (foo: bar)", perform("append(1 2, (foo: bar))").to_sass)
1246
+ assert_equal("foo bar, bar baz, 1", perform("append((foo: bar, bar: baz), 1)").to_sass)
1247
+ assert_equal("foo bar, bar baz, (baz: bip)",
1248
+ perform("append((foo: bar, bar: baz), (baz: bip))").to_sass)
1249
+ end
1250
+
1251
+ def test_zip
1252
+ assert_equal("1 3 5, 2 4 6", evaluate("zip(1 2, 3 4, 5 6)"))
1253
+ assert_equal("1 4 7, 2 5 8", evaluate("zip(1 2 3, 4 5 6, 7 8)"))
1254
+ assert_equal("1 2 3", evaluate("zip(1, 2, 3)"))
1255
+ assert_equal("(foo bar) 1 3, (bar baz) 2 4",
1256
+ perform("zip((foo: bar, bar: baz), 1 2, 3 4)").to_sass)
1257
+ end
1258
+
1259
+ def test_index
1260
+ assert_equal("1", evaluate("index(1px solid blue, 1px)"))
1261
+ assert_equal("2", evaluate("index(1px solid blue, solid)"))
1262
+ assert_equal("3", evaluate("index(1px solid blue, #00f)"))
1263
+ assert_equal("1", evaluate("index(1px, 1px)"))
1264
+ assert_equal("false", evaluate("index(1px solid blue, 1em)"))
1265
+ assert_equal("false", evaluate("index(1px solid blue, notfound)"))
1266
+ assert_equal("false", evaluate("index(1px, #00f)"))
1267
+
1268
+ assert_equal("1", evaluate("index((foo: bar, bar: baz), (foo bar))"))
1269
+ assert_equal("false", evaluate("index((foo: bar, bar: baz), (foo: bar))"))
1270
+ end
1271
+
1272
+ def test_index_deprecation_warning
1273
+ assert_warning(<<WARNING) do
1274
+ DEPRECATION WARNING: The return value of index() will change from "false" to
1275
+ "null" in future versions of Sass. For compatibility, avoid using "== false" on
1276
+ the return value. For example, instead of "@if index(...) == false", just write
1277
+ "@if index(...)".
1278
+ WARNING
1279
+ assert_equal("true", evaluate("index(1, 2 3 4) == false"))
1280
+ end
1281
+
1282
+ assert_warning(<<WARNING) do
1283
+ DEPRECATION WARNING: The return value of index() will change from "false" to
1284
+ "null" in future versions of Sass. For compatibility, avoid using "!= null" on
1285
+ the return value.
1286
+ WARNING
1287
+ assert_equal("true", evaluate("index(1, 2 3 4) != null"))
1288
+ end
1289
+
1290
+ assert_warning(<<WARNING) do
1291
+ DEPRECATION WARNING: The return value of index() will change from "false" to
1292
+ "null" in future versions of Sass. For compatibility, avoid using "== false" on
1293
+ the return value. For example, instead of "@if index(...) == false", just write
1294
+ "@if index(...)".
1295
+ WARNING
1296
+ assert_equal("true", evaluate("false == index(1, 2 3 4)"))
1297
+ end
1298
+
1299
+ assert_warning(<<WARNING) do
1300
+ DEPRECATION WARNING: The return value of index() will change from "false" to
1301
+ "null" in future versions of Sass. For compatibility, avoid using "!= null" on
1302
+ the return value.
1303
+ WARNING
1304
+ assert_equal("true", evaluate("null != index(1, 2 3 4)"))
1305
+ end
1306
+ end
1307
+
1308
+ def test_index_deprecation_warning_is_only_emitted_once_per_call
1309
+ assert_warning(<<WARNING) do
1310
+ DEPRECATION WARNING: The return value of index() will change from "false" to
1311
+ "null" in future versions of Sass. For compatibility, avoid using "== false" on
1312
+ the return value. For example, instead of "@if index(...) == false", just write
1313
+ "@if index(...)".
1314
+ on line 3 of test_index_deprecation_warning_is_only_emitted_once_per_call_inline.scss
1315
+ DEPRECATION WARNING: The return value of index() will change from "false" to
1316
+ "null" in future versions of Sass. For compatibility, avoid using "== false" on
1317
+ the return value. For example, instead of "@if index(...) == false", just write
1318
+ "@if index(...)".
1319
+ on line 6 of test_index_deprecation_warning_is_only_emitted_once_per_call_inline.scss
1320
+ WARNING
1321
+ render(<<SCSS)
1322
+ @for $i from 1 to 10 {
1323
+ $var1: index(1, 2 3 4);
1324
+ $var2: $var1 == false;
1325
+ $var3: $var1 != null;
1326
+ }
1327
+ $var4: index(1, 2 3 4) == false;
1328
+ SCSS
1329
+ end
1330
+ end
1331
+
1332
+ def test_list_separator
1333
+ assert_equal("space", evaluate("list-separator(1 2 3 4 5)"))
1334
+ assert_equal("comma", evaluate("list-separator((foo, bar, baz, bip))"))
1335
+ assert_equal("comma", evaluate("list-separator((foo, bar, baz bip))"))
1336
+ assert_equal("comma", evaluate("list-separator((foo, bar, (baz, bip)))"))
1337
+ assert_equal("space", evaluate("list-separator(#f00)"))
1338
+ assert_equal("space", evaluate("list-separator(())"))
1339
+ assert_equal("space", evaluate("list-separator(1 2 () 3)"))
1340
+
1341
+ assert_equal("comma", evaluate("list-separator((foo: bar, bar: baz))"))
966
1342
  end
967
1343
 
968
1344
  def test_if
969
1345
  assert_equal("1px", evaluate("if(true, 1px, 2px)"))
970
1346
  assert_equal("2px", evaluate("if(false, 1px, 2px)"))
1347
+ assert_equal("2px", evaluate("if(null, 1px, 2px)"))
1348
+ assert_equal("1px", evaluate("if(true, 1px, $broken)"))
1349
+ assert_equal("1px", evaluate("if(false, $broken, 1px)"))
1350
+ assert_equal("1px", evaluate("if(false, $if-true: $broken, $if-false: 1px)"))
1351
+ assert_equal("1px", evaluate("if(true, $if-true: 1px, $if-false: $broken)"))
1352
+ assert_equal(<<CSS, render(<<SCSS))
1353
+ .if {
1354
+ result: yay; }
1355
+ CSS
1356
+ .if {
1357
+ $something: yay;
1358
+ result: if(true, $if-true: $something, $if-false: $broken);
1359
+ }
1360
+ SCSS
1361
+ assert_equal(<<CSS, render(<<SCSS))
1362
+ .if {
1363
+ result: 1px; }
1364
+ CSS
1365
+ .if {
1366
+ $splat: 1px, 2px;
1367
+ result: if(true, $splat...);
1368
+ }
1369
+ SCSS
1370
+ end
1371
+
1372
+ def test_counter
1373
+ assert_equal("counter(foo)", evaluate("counter(foo)"))
1374
+ assert_equal('counter(item,".")', evaluate('counter(item, ".")'))
1375
+ assert_equal('counter(item,".")', evaluate('counter(item,".")'))
1376
+ end
1377
+
1378
+ def test_counters
1379
+ assert_equal("counters(foo)", evaluate("counters(foo)"))
1380
+ assert_equal('counters(item,".")', evaluate('counters(item, ".")'))
1381
+ assert_equal('counters(item,".")', evaluate('counters(item,".")'))
971
1382
  end
972
1383
 
973
1384
  def test_keyword_args_rgb
@@ -980,23 +1391,47 @@ MSG
980
1391
  end
981
1392
 
982
1393
  def test_keyword_args_rgba_with_extra_args
983
- assert_equal(%Q{rgba(255, 255, 255, 0.5)}, evaluate("rgba($red: 255, $green: 255, $blue: 255, $alpha: 0.5, $extra: error)"))
1394
+ evaluate("rgba($red: 255, $green: 255, $blue: 255, $alpha: 0.5, $extra: error)")
1395
+ flunk("Expected exception")
984
1396
  rescue Sass::SyntaxError => e
985
- assert_equal("Function rgba doesn't take an argument named $extra", e.message)
1397
+ assert_equal("Function rgba doesn't have an argument named $extra", e.message)
986
1398
  end
987
1399
 
988
1400
  def test_keyword_args_must_have_signature
989
1401
  evaluate("no-kw-args($fake: value)")
1402
+ flunk("Expected exception")
990
1403
  rescue Sass::SyntaxError => e
991
1404
  assert_equal("Function no_kw_args doesn't support keyword arguments", e.message)
992
1405
  end
993
1406
 
994
1407
  def test_keyword_args_with_missing_argument
995
1408
  evaluate("rgb($red: 255, $green: 255)")
1409
+ flunk("Expected exception")
996
1410
  rescue Sass::SyntaxError => e
997
1411
  assert_equal("Function rgb requires an argument named $blue", e.message)
998
1412
  end
999
1413
 
1414
+ def test_keyword_args_with_extra_argument
1415
+ evaluate("rgb($red: 255, $green: 255, $blue: 255, $purple: 255)")
1416
+ flunk("Expected exception")
1417
+ rescue Sass::SyntaxError => e
1418
+ assert_equal("Function rgb doesn't have an argument named $purple", e.message)
1419
+ end
1420
+
1421
+ def test_keyword_args_with_positional_and_keyword_argument
1422
+ evaluate("rgb(255, 255, 255, $red: 255)")
1423
+ flunk("Expected exception")
1424
+ rescue Sass::SyntaxError => e
1425
+ assert_equal("Function rgb was passed argument $red both by position and by name", e.message)
1426
+ end
1427
+
1428
+ def test_keyword_args_with_keyword_before_positional_argument
1429
+ evaluate("rgb($red: 255, 255, 255)")
1430
+ flunk("Expected exception")
1431
+ rescue Sass::SyntaxError => e
1432
+ assert_equal("Positional arguments must come before keyword arguments.", e.message)
1433
+ end
1434
+
1000
1435
  def test_only_var_args
1001
1436
  assert_equal "only-var-args(2px, 3px, 4px)", evaluate("only-var-args(1px, 2px, 3px)")
1002
1437
  end
@@ -1005,14 +1440,439 @@ MSG
1005
1440
  assert_equal "only-kw-args(a, b, c)", evaluate("only-kw-args($a: 1, $b: 2, $c: 3)")
1006
1441
  end
1007
1442
 
1443
+ def test_unique_id
1444
+ last_id, current_id = nil, evaluate("unique-id()")
1445
+
1446
+ 50.times do
1447
+ last_id, current_id = current_id, evaluate("unique-id()")
1448
+ assert_match(/u[a-z0-9]{8}/, current_id)
1449
+ assert_not_equal last_id, current_id
1450
+ end
1451
+ end
1452
+
1453
+ def test_map_get
1454
+ assert_equal "1", evaluate("map-get((foo: 1, bar: 2), foo)")
1455
+ assert_equal "2", evaluate("map-get((foo: 1, bar: 2), bar)")
1456
+ assert_equal "null", perform("map-get((foo: 1, bar: 2), baz)").to_sass
1457
+ assert_equal "null", perform("map-get((), foo)").to_sass
1458
+ end
1459
+
1460
+ def test_map_get_deprecation_warning
1461
+ assert_warning(<<WARNING) do
1462
+ DEPRECATION WARNING: Passing lists of pairs to map-get is deprecated and will
1463
+ be removed in future versions of Sass. Use Sass maps instead. For details, see
1464
+ http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1465
+ WARNING
1466
+ assert_equal "1", evaluate("map-get((foo 1) (bar 2), foo)")
1467
+ end
1468
+ end
1469
+
1470
+ def test_map_get_checks_type
1471
+ assert_error_message("$map: 12 is not a map for `map-get'", "map-get(12, bar)")
1472
+ end
1473
+
1474
+ def test_map_merge
1475
+ assert_equal("(foo: 1, bar: 2, baz: 3)",
1476
+ perform("map-merge((foo: 1, bar: 2), (baz: 3))").to_sass)
1477
+ assert_equal("(foo: 1, bar: 2)",
1478
+ perform("map-merge((), (foo: 1, bar: 2))").to_sass)
1479
+ assert_equal("(foo: 1, bar: 2)",
1480
+ perform("map-merge((foo: 1, bar: 2), ())").to_sass)
1481
+ end
1482
+
1483
+ def test_map_merge_deprecation_warning
1484
+ assert_warning(<<WARNING) do
1485
+ DEPRECATION WARNING: Passing lists of pairs to map-merge is deprecated and will
1486
+ be removed in future versions of Sass. Use Sass maps instead. For details, see
1487
+ http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1488
+ WARNING
1489
+ assert_equal("(foo: 1, bar: 2, baz: 3)",
1490
+ perform("map-merge((foo 1, bar 2), (baz: 3))").to_sass)
1491
+ end
1492
+
1493
+ assert_warning(<<WARNING) do
1494
+ DEPRECATION WARNING: Passing lists of pairs to map-merge is deprecated and will
1495
+ be removed in future versions of Sass. Use Sass maps instead. For details, see
1496
+ http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1497
+ WARNING
1498
+ assert_equal("(baz: 3, foo: 1, bar: 2)",
1499
+ perform("map-merge((baz: 3), (foo 1, bar 2))").to_sass)
1500
+ end
1501
+ end
1502
+
1503
+ def test_map_merge_checks_type
1504
+ assert_error_message("$map1: 12 is not a map for `map-merge'", "map-merge(12, (foo: 1))")
1505
+ assert_error_message("$map2: 12 is not a map for `map-merge'", "map-merge((foo: 1), 12)")
1506
+ end
1507
+
1508
+ def test_map_remove
1509
+ assert_equal("(foo: 1, baz: 3)",
1510
+ perform("map-remove((foo: 1, bar: 2, baz: 3), bar)").to_sass)
1511
+ assert_equal("()", perform("map-remove((), foo)").to_sass)
1512
+ end
1513
+
1514
+ def test_map_remove_deprecation_warning
1515
+ assert_warning(<<WARNING) do
1516
+ DEPRECATION WARNING: Passing lists of pairs to map-remove is deprecated and will
1517
+ be removed in future versions of Sass. Use Sass maps instead. For details, see
1518
+ http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1519
+ WARNING
1520
+ assert_equal("(foo: 1, baz: 3)",
1521
+ perform("map-remove((foo 1, bar 2, baz 3), bar)").to_sass)
1522
+ end
1523
+ end
1524
+
1525
+ def test_map_remove_checks_type
1526
+ assert_error_message("$map: 12 is not a map for `map-remove'", "map-remove(12, foo)")
1527
+ end
1528
+
1529
+ def test_map_keys
1530
+ assert_equal("foo, bar",
1531
+ perform("map-keys((foo: 1, bar: 2))").to_sass)
1532
+ assert_equal("()", perform("map-keys(())").to_sass)
1533
+ end
1534
+
1535
+ def test_map_keys_deprecation_warning
1536
+ assert_warning(<<WARNING) do
1537
+ DEPRECATION WARNING: Passing lists of pairs to map-keys is deprecated and will
1538
+ be removed in future versions of Sass. Use Sass maps instead. For details, see
1539
+ http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1540
+ WARNING
1541
+ assert_equal("foo, bar",
1542
+ perform("map-keys((foo 1, bar 2))").to_sass)
1543
+ end
1544
+ end
1545
+
1546
+ def test_map_keys_checks_type
1547
+ assert_error_message("$map: 12 is not a map for `map-keys'", "map-keys(12)")
1548
+ end
1549
+
1550
+ def test_map_values
1551
+ assert_equal("1, 2", perform("map-values((foo: 1, bar: 2))").to_sass)
1552
+ assert_equal("1, 2, 2",
1553
+ perform("map-values((foo: 1, bar: 2, baz: 2))").to_sass)
1554
+ assert_equal("()", perform("map-values(())").to_sass)
1555
+ end
1556
+
1557
+ def test_map_values_deprecation_warning
1558
+ assert_warning(<<WARNING) do
1559
+ DEPRECATION WARNING: Passing lists of pairs to map-values is deprecated and will
1560
+ be removed in future versions of Sass. Use Sass maps instead. For details, see
1561
+ http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1562
+ WARNING
1563
+ assert_equal("1, 2", perform("map-values((foo 1, bar 2))").to_sass)
1564
+ end
1565
+ end
1566
+
1567
+ def test_map_values_checks_type
1568
+ assert_error_message("$map: 12 is not a map for `map-values'", "map-values(12)")
1569
+ end
1570
+
1571
+ def test_map_has_key
1572
+ assert_equal "true", evaluate("map-has-key((foo: 1, bar: 1), foo)")
1573
+ assert_equal "false", evaluate("map-has-key((foo: 1, bar: 1), baz)")
1574
+ assert_equal "false", evaluate("map-has-key((), foo)")
1575
+ end
1576
+
1577
+ def test_map_has_key_deprecation_warning
1578
+ assert_warning(<<WARNING) do
1579
+ DEPRECATION WARNING: Passing lists of pairs to map-has-key is deprecated and will
1580
+ be removed in future versions of Sass. Use Sass maps instead. For details, see
1581
+ http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1582
+ WARNING
1583
+ assert_equal("true", evaluate("map-has-key((foo 1, bar 1), foo)"))
1584
+ end
1585
+ end
1586
+
1587
+ def test_map_has_key_checks_type
1588
+ assert_error_message("$map: 12 is not a map for `map-has-key'", "map-has-key(12, foo)")
1589
+ end
1590
+
1591
+ def test_keywords
1592
+ # The actual functionality is tested in tests where real arglists are passed.
1593
+ assert_error_message("$args: 12 is not a variable argument list for `keywords'", "keywords(12)")
1594
+ assert_error_message(
1595
+ "$args: (1 2 3) is not a variable argument list for `keywords'", "keywords(1 2 3)")
1596
+ end
1597
+
1598
+ def test_partial_list_of_pairs_doesnt_work_as_a_map
1599
+ assert_raises(Sass::SyntaxError) {evaluate("map-get((foo bar, baz bang, bip), 1)")}
1600
+ assert_raises(Sass::SyntaxError) {evaluate("map-get((foo bar, baz bang, bip bap bop), 1)")}
1601
+ assert_raises(Sass::SyntaxError) {evaluate("map-get((foo bar), 1)")}
1602
+ end
1603
+
1604
+ def test_assert_unit
1605
+ ctx = Sass::Script::Functions::EvaluationContext.new(Sass::Environment.new(nil, {}))
1606
+ ctx.assert_unit Sass::Script::Value::Number.new(10, ["px"], []), "px"
1607
+ ctx.assert_unit Sass::Script::Value::Number.new(10, [], []), nil
1608
+
1609
+ begin
1610
+ ctx.assert_unit Sass::Script::Value::Number.new(10, [], []), "px"
1611
+ fail
1612
+ rescue ArgumentError => e
1613
+ assert_equal "Expected 10 to have a unit of px", e.message
1614
+ end
1615
+
1616
+ begin
1617
+ ctx.assert_unit Sass::Script::Value::Number.new(10, ["px"], []), nil
1618
+ fail
1619
+ rescue ArgumentError => e
1620
+ assert_equal "Expected 10px to be unitless", e.message
1621
+ end
1622
+
1623
+ begin
1624
+ ctx.assert_unit Sass::Script::Value::Number.new(10, [], []), "px", "arg"
1625
+ fail
1626
+ rescue ArgumentError => e
1627
+ assert_equal "Expected $arg to have a unit of px but got 10", e.message
1628
+ end
1629
+
1630
+ begin
1631
+ ctx.assert_unit Sass::Script::Value::Number.new(10, ["px"], []), nil, "arg"
1632
+ fail
1633
+ rescue ArgumentError => e
1634
+ assert_equal "Expected $arg to be unitless but got 10px", e.message
1635
+ end
1636
+ end
1637
+
1638
+ def test_call_with_positional_arguments
1639
+ assert_equal evaluate("lighten(blue, 5%)"), evaluate("call(lighten, blue, 5%)")
1640
+ end
1641
+
1642
+ def test_call_with_keyword_arguments
1643
+ assert_equal(
1644
+ evaluate("lighten($color: blue, $amount: 5%)"),
1645
+ evaluate("call(lighten, $color: blue, $amount: 5%)"))
1646
+ end
1647
+
1648
+ def test_call_with_keyword_and_positional_arguments
1649
+ assert_equal(
1650
+ evaluate("lighten(blue, $amount: 5%)"),
1651
+ evaluate("call(lighten, blue, $amount: 5%)"))
1652
+ end
1653
+
1654
+ def test_call_with_dynamic_name
1655
+ assert_equal(
1656
+ evaluate("lighten($color: blue, $amount: 5%)"),
1657
+ evaluate("call($fn, $color: blue, $amount: 5%)",
1658
+ env("fn" => Sass::Script::String.new("lighten"))))
1659
+ end
1660
+
1661
+ def test_call_uses_local_scope
1662
+ assert_equal <<CSS, render(<<SCSS)
1663
+ .first-scope {
1664
+ a: local; }
1665
+
1666
+ .second-scope {
1667
+ a: global; }
1668
+ CSS
1669
+ @function foo() {@return global}
1670
+
1671
+ .first-scope {
1672
+ @function foo() {@return local}
1673
+ a: call(foo);
1674
+ }
1675
+
1676
+ .second-scope {
1677
+ a: call(foo);
1678
+ }
1679
+ SCSS
1680
+ end
1681
+
1682
+ def test_call_unknown_function
1683
+ assert_equal evaluate("unknown(red, blue)"), evaluate("call(unknown, red, blue)")
1684
+ end
1685
+
1686
+ def test_call_with_non_string_argument
1687
+ assert_error_message "$name: 3px is not a string for `call'", "call(3px)"
1688
+ end
1689
+
1690
+ def test_errors_in_called_function
1691
+ assert_error_message "$color: 3px is not a color for `lighten'", "call(lighten, 3px, 5%)"
1692
+ end
1693
+
1694
+ def test_variable_exists
1695
+ assert_equal <<CSS, render(<<SCSS)
1696
+ .test {
1697
+ false: false;
1698
+ true: true;
1699
+ true: true;
1700
+ true: true;
1701
+ true: true; }
1702
+ CSS
1703
+ $global-var: has-value;
1704
+ .test {
1705
+ false: variable-exists(foo);
1706
+ $foo: has-value;
1707
+ true: variable-exists(foo);
1708
+ true: variable-exists($name: foo);
1709
+ true: variable-exists(global-var);
1710
+ true: variable-exists($name: global-var);
1711
+ }
1712
+ SCSS
1713
+ end
1714
+
1715
+ def test_variable_exists_checks_type
1716
+ assert_error_message("$name: 1 is not a string for `variable-exists'", "variable-exists(1)")
1717
+ end
1718
+
1719
+ def test_global_variable_exists
1720
+ assert_equal <<CSS, render(<<SCSS)
1721
+ .test {
1722
+ false: false;
1723
+ false: false;
1724
+ true: true;
1725
+ true: true;
1726
+ false: false;
1727
+ true: true;
1728
+ true: true; }
1729
+ CSS
1730
+ $g: something;
1731
+ $h: null;
1732
+ $false: global-variable-exists(foo);
1733
+ $true: global-variable-exists(g);
1734
+ $named: global-variable-exists($name: g);
1735
+ .test {
1736
+ $foo: locally-defined;
1737
+ false: global-variable-exists(foo);
1738
+ false: global-variable-exists(foo2);
1739
+ true: global-variable-exists(g);
1740
+ true: global-variable-exists(h);
1741
+ false: $false;
1742
+ true: $true;
1743
+ true: $named;
1744
+ }
1745
+ SCSS
1746
+ end
1747
+
1748
+ def test_global_variable_exists_checks_type
1749
+ assert_error_message("$name: 1 is not a string for `global-variable-exists'",
1750
+ "global-variable-exists(1)")
1751
+ end
1752
+
1753
+ def test_function_exists
1754
+ # built-ins
1755
+ assert_equal "true", evaluate("function-exists(lighten)")
1756
+ # with named argument
1757
+ assert_equal "true", evaluate("function-exists($name: lighten)")
1758
+ # user-defined
1759
+ assert_equal <<CSS, render(<<SCSS)
1760
+ .test {
1761
+ foo-exists: true;
1762
+ bar-exists: false; }
1763
+ CSS
1764
+ @function foo() { @return "foo" }
1765
+ .test {
1766
+ foo-exists: function-exists(foo);
1767
+ bar-exists: function-exists(bar);
1768
+ }
1769
+ SCSS
1770
+ end
1771
+
1772
+ def test_function_exists_checks_type
1773
+ assert_error_message("$name: 1 is not a string for `function-exists'", "function-exists(1)")
1774
+ end
1775
+
1776
+ def test_mixin_exists
1777
+ assert_equal "false", evaluate("mixin-exists(foo)")
1778
+ # with named argument
1779
+ assert_equal "false", evaluate("mixin-exists($name: foo)")
1780
+ assert_equal <<CSS, render(<<SCSS)
1781
+ .test {
1782
+ foo-exists: true;
1783
+ bar-exists: false; }
1784
+ CSS
1785
+ @mixin foo() { foo: exists }
1786
+ .test {
1787
+ foo-exists: mixin-exists(foo);
1788
+ bar-exists: mixin-exists(bar);
1789
+ }
1790
+ SCSS
1791
+ end
1792
+
1793
+ def test_mixin_exists_checks_type
1794
+ assert_error_message("$name: 1 is not a string for `mixin-exists'", "mixin-exists(1)")
1795
+ end
1796
+
1797
+ def test_inspect
1798
+ assert_equal "()", evaluate("inspect(())")
1799
+ assert_equal "null", evaluate("inspect(null)")
1800
+ assert_equal "1px null 3px", evaluate("inspect(1px null 3px)")
1801
+ assert_equal "(a: 1, b: 2)", evaluate("inspect((a: 1, b: 2))")
1802
+ end
1803
+
1804
+ def test_random
1805
+ Sass::Script::Functions.random_seed = 1
1806
+ assert_equal "0.41702", evaluate("random()")
1807
+ assert_equal "13", evaluate("random(100)")
1808
+ end
1809
+
1810
+ def test_random_works_without_a_seed
1811
+ if Sass::Script::Functions.instance_variable_defined?("@random_number_generator")
1812
+ Sass::Script::Functions.send(:remove_instance_variable, "@random_number_generator")
1813
+ end
1814
+
1815
+ result = perform("random()")
1816
+ assert_kind_of Sass::Script::Number, result
1817
+ assert result.value >= 0, "Random number was below 0"
1818
+ assert result.value <= 1, "Random number was above 1"
1819
+ end
1820
+
1821
+ def test_random_with_limit_one
1822
+ # Passing 1 as the limit should always return 1, since limit calls return
1823
+ # integers from 1 to the argument, so when the argument is 1, its a predicatble
1824
+ # outcome
1825
+ assert "1", evaluate("random(1)")
1826
+ end
1827
+
1828
+ def test_random_with_limit_too_low
1829
+ assert_error_message("$limit 0 must be greater than or equal to 1 for `random'", "random(0)")
1830
+ end
1831
+
1832
+ def test_random_with_non_integer_limit
1833
+ assert_error_message("Expected $limit to be an integer but got 1.5 for `random'", "random(1.5)")
1834
+ end
1835
+
1836
+ # This could *possibly* fail, but exceedingly unlikely
1837
+ def test_random_is_semi_unique
1838
+ if Sass::Script::Functions.instance_variable_defined?("@random_number_generator")
1839
+ Sass::Script::Functions.send(:remove_instance_variable, "@random_number_generator")
1840
+ end
1841
+ assert_not_equal evaluate("random()"), evaluate("random()")
1842
+ end
1843
+
1844
+ ## Regression Tests
1845
+
1846
+ def test_inspect_nested_empty_lists
1847
+ assert_equal "() ()", evaluate("inspect(() ())")
1848
+ end
1849
+
1850
+ def test_saturation_bounds
1851
+ assert_equal "#fbfdff", evaluate("hsl(hue(#fbfdff), saturation(#fbfdff), lightness(#fbfdff))")
1852
+ end
1853
+
1008
1854
  private
1855
+ def env(hash = {}, parent = nil)
1856
+ env = Sass::Environment.new(parent)
1857
+ hash.each {|k, v| env.set_var(k, v)}
1858
+ env
1859
+ end
1009
1860
 
1010
- def evaluate(value)
1011
- Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new).to_s
1861
+ def evaluate(value, environment = env)
1862
+ result = perform(value, environment)
1863
+ assert_kind_of Sass::Script::Value::Base, result
1864
+ return result.to_s
1012
1865
  end
1013
1866
 
1014
- def perform(value)
1015
- Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new)
1867
+ def perform(value, environment = env)
1868
+ Sass::Script::Parser.parse(value, 0, 0).perform(environment)
1869
+ end
1870
+
1871
+ def render(sass, options = {})
1872
+ options[:syntax] ||= :scss
1873
+ munge_filename options
1874
+ options[:importer] ||= MockImporter.new
1875
+ Sass::Engine.new(sass, options).render
1016
1876
  end
1017
1877
 
1018
1878
  def assert_error_message(message, value)
@@ -1021,5 +1881,4 @@ MSG
1021
1881
  rescue Sass::SyntaxError => e
1022
1882
  assert_equal(message, e.message)
1023
1883
  end
1024
-
1025
1884
  end