haml-edge 2.3.100 → 2.3.148

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 (54) hide show
  1. data/.yardopts +3 -0
  2. data/EDGE_GEM_VERSION +1 -1
  3. data/Rakefile +14 -2
  4. data/VERSION +1 -1
  5. data/extra/haml-mode.el +97 -11
  6. data/extra/sass-mode.el +2 -2
  7. data/lib/haml/engine.rb +2 -2
  8. data/lib/haml/exec.rb +121 -25
  9. data/lib/haml/filters.rb +1 -1
  10. data/lib/haml/helpers/action_view_mods.rb +2 -1
  11. data/lib/haml/helpers/xss_mods.rb +43 -13
  12. data/lib/haml/helpers.rb +38 -17
  13. data/lib/haml/html.rb +13 -4
  14. data/lib/haml/precompiler.rb +24 -3
  15. data/lib/haml/template/plugin.rb +7 -3
  16. data/lib/haml/template.rb +3 -3
  17. data/lib/haml/util.rb +40 -0
  18. data/lib/sass/callbacks.rb +50 -0
  19. data/lib/sass/css.rb +1 -1
  20. data/lib/sass/engine.rb +45 -5
  21. data/lib/sass/error.rb +6 -3
  22. data/lib/sass/files.rb +8 -1
  23. data/lib/sass/plugin/rails.rb +2 -2
  24. data/lib/sass/plugin.rb +260 -28
  25. data/lib/sass/script/color.rb +216 -30
  26. data/lib/sass/script/functions.rb +356 -74
  27. data/lib/sass/script/lexer.rb +7 -4
  28. data/lib/sass/script/number.rb +2 -0
  29. data/lib/sass/script/parser.rb +1 -1
  30. data/lib/sass/script.rb +3 -0
  31. data/lib/sass/tree/node.rb +1 -1
  32. data/lib/sass/tree/root_node.rb +6 -0
  33. data/lib/sass/tree/rule_node.rb +1 -0
  34. data/lib/sass.rb +4 -0
  35. data/test/haml/engine_test.rb +25 -0
  36. data/test/haml/helper_test.rb +81 -1
  37. data/test/haml/html2haml_test.rb +13 -0
  38. data/test/haml/spec/README.md +97 -0
  39. data/test/haml/spec/lua_haml_spec.lua +30 -0
  40. data/test/haml/spec/ruby_haml_test.rb +19 -0
  41. data/test/haml/spec/tests.json +534 -0
  42. data/test/haml/spec_test.rb +0 -0
  43. data/test/haml/template_test.rb +18 -4
  44. data/test/haml/util_test.rb +0 -0
  45. data/test/sass/callbacks_test.rb +61 -0
  46. data/test/sass/css2sass_test.rb +1 -0
  47. data/test/sass/engine_test.rb +70 -14
  48. data/test/sass/functions_test.rb +223 -3
  49. data/test/sass/plugin_test.rb +193 -25
  50. data/test/sass/results/options.css +1 -0
  51. data/test/sass/script_test.rb +5 -5
  52. data/test/sass/templates/options.sass +2 -0
  53. data/test/test_helper.rb +12 -5
  54. metadata +19 -9
@@ -98,6 +98,7 @@ MSG
98
98
  '@if' => "Invalid if directive '@if': expected expression.",
99
99
  '@while' => "Invalid while directive '@while': expected expression.",
100
100
  '@debug' => "Invalid debug directive '@debug': expected expression.",
101
+ "/* foo\n bar\n baz" => "Inconsistent indentation: previous line was indented by 4 spaces, but this line was indented by 2 spaces.",
101
102
 
102
103
  # Regression tests
103
104
  "a\n b:\n c\n d" => ["Illegal nesting: Only properties may be nested beneath properties.", 3],
@@ -251,19 +252,19 @@ SASS
251
252
  assert(false, "Exception not raised")
252
253
  rescue Sass::SyntaxError => err
253
254
  assert_equal(2, err.sass_line)
254
- assert_equal(test_filename, err.sass_filename)
255
+ assert_equal(filename_for_test, err.sass_filename)
255
256
  assert_equal("error-mixin", err.sass_mixin)
256
257
 
257
258
  assert_hash_has(err.sass_backtrace.first, :line => err.sass_line,
258
259
  :filename => err.sass_filename, :mixin => err.sass_mixin)
259
260
  assert_hash_has(err.sass_backtrace[1], :line => 5,
260
- :filename => test_filename, :mixin => "outer-mixin")
261
+ :filename => filename_for_test, :mixin => "outer-mixin")
261
262
  assert_hash_has(err.sass_backtrace[2], :line => 8,
262
- :filename => test_filename, :mixin => nil)
263
+ :filename => filename_for_test, :mixin => nil)
263
264
 
264
- assert_equal("#{test_filename}:2:in `error-mixin'", err.backtrace.first)
265
- assert_equal("#{test_filename}:5:in `outer-mixin'", err.backtrace[1])
266
- assert_equal("#{test_filename}:8", err.backtrace[2])
265
+ assert_equal("#{filename_for_test}:2:in `error-mixin'", err.backtrace.first)
266
+ assert_equal("#{filename_for_test}:5:in `outer-mixin'", err.backtrace[1])
267
+ assert_equal("#{filename_for_test}:8", err.backtrace[2])
267
268
  end
268
269
 
269
270
  def test_mixin_callsite_exception
@@ -280,11 +281,11 @@ SASS
280
281
  assert(false, "Exception not raised")
281
282
  rescue Sass::SyntaxError => err
282
283
  assert_hash_has(err.sass_backtrace.first, :line => 5,
283
- :filename => test_filename, :mixin => "one-arg-mixin")
284
+ :filename => filename_for_test, :mixin => "one-arg-mixin")
284
285
  assert_hash_has(err.sass_backtrace[1], :line => 5,
285
- :filename => test_filename, :mixin => "outer-mixin")
286
+ :filename => filename_for_test, :mixin => "outer-mixin")
286
287
  assert_hash_has(err.sass_backtrace[2], :line => 8,
287
- :filename => test_filename, :mixin => nil)
288
+ :filename => filename_for_test, :mixin => nil)
288
289
  end
289
290
 
290
291
  def test_mixin_exception_cssize
@@ -301,11 +302,11 @@ SASS
301
302
  assert(false, "Exception not raised")
302
303
  rescue Sass::SyntaxError => err
303
304
  assert_hash_has(err.sass_backtrace.first, :line => 2,
304
- :filename => test_filename, :mixin => "parent-ref-mixin")
305
+ :filename => filename_for_test, :mixin => "parent-ref-mixin")
305
306
  assert_hash_has(err.sass_backtrace[1], :line => 6,
306
- :filename => test_filename, :mixin => "outer-mixin")
307
+ :filename => filename_for_test, :mixin => "outer-mixin")
307
308
  assert_hash_has(err.sass_backtrace[2], :line => 8,
308
- :filename => test_filename, :mixin => nil)
309
+ :filename => filename_for_test, :mixin => nil)
309
310
  end
310
311
 
311
312
  def test_mixin_and_import_exception
@@ -424,6 +425,16 @@ CSS
424
425
  assert File.exists?(sassc_path("importee"))
425
426
  end
426
427
 
428
+ def test_nonexistent_extensionless_import
429
+ assert_warning(<<WARN) do
430
+ WARNING: nonexistent.sass not found. Using nonexistent.css instead.
431
+ This behavior is deprecated and will be removed in a future version.
432
+ If you really need nonexistent.css, import it explicitly.
433
+ WARN
434
+ assert_equal("@import url(nonexistent.css);\n", render("@import nonexistent"))
435
+ end
436
+ end
437
+
427
438
  def test_no_cache
428
439
  assert !File.exists?(sassc_path("importee"))
429
440
  renders_correctly("import", {
@@ -919,6 +930,36 @@ foo {
919
930
  CSS
920
931
  end
921
932
 
933
+ def test_comment_indentation_at_beginning_of_doc
934
+ assert_equal <<CSS, render(<<SASS)
935
+ /* foo
936
+ * bar
937
+ * baz */
938
+ foo {
939
+ a: b; }
940
+ CSS
941
+ /* foo
942
+ bar
943
+ baz
944
+ foo
945
+ a: b
946
+ SASS
947
+ end
948
+
949
+ def test_unusual_comment_indentation
950
+ assert_equal <<CSS, render(<<SASS)
951
+ foo {
952
+ /* foo
953
+ * bar
954
+ * baz */ }
955
+ CSS
956
+ foo
957
+ /* foo
958
+ bar
959
+ baz
960
+ SASS
961
+ end
962
+
922
963
  def test_attribute_selector_with_spaces
923
964
  assert_equal(<<CSS, render(<<SASS))
924
965
  a b[foo = bar] {
@@ -965,12 +1006,12 @@ SASS
965
1006
 
966
1007
  def test_empty_selector_warning
967
1008
  assert_warning(<<END) {render("foo bar")}
968
- WARNING on line 1:
1009
+ WARNING on line 1 of test_empty_selector_warning_inline.sass:
969
1010
  Selector "foo bar" doesn't have any properties and will not be rendered.
970
1011
  END
971
1012
 
972
1013
  assert_warning(<<END) {render(<<SASS)}
973
- WARNING on line 3:
1014
+ WARNING on line 3 of test_empty_selector_warning_inline.sass:
974
1015
  Selector
975
1016
  foo, bar, baz,
976
1017
  bang, bip, bop
@@ -981,6 +1022,11 @@ END
981
1022
  foo, bar, baz,
982
1023
  bang, bip, bop
983
1024
  SASS
1025
+
1026
+ assert_warning(<<END) {render("foo bar", :filename => nil)}
1027
+ WARNING on line 1:
1028
+ Selector "foo bar" doesn't have any properties and will not be rendered.
1029
+ END
984
1030
  end
985
1031
 
986
1032
  def test_root_level_pseudo_class_with_new_properties
@@ -1004,6 +1050,16 @@ p
1004
1050
  SASS
1005
1051
  end
1006
1052
 
1053
+ def test_nil_option
1054
+ assert_equal(<<CSS, render(<<SASS, :format => nil))
1055
+ foo {
1056
+ a: b; }
1057
+ CSS
1058
+ foo
1059
+ a: b
1060
+ SASS
1061
+ end
1062
+
1007
1063
  # Regression tests
1008
1064
 
1009
1065
  def test_parens_in_mixins
@@ -1,5 +1,6 @@
1
+ #!/usr/bin/env ruby
1
2
  require 'test/unit'
2
- require File.dirname(__FILE__) + '/../../lib/sass'
3
+ require File.dirname(__FILE__) + '/../test_helper'
3
4
  require 'sass/script'
4
5
 
5
6
  module Sass::Script::Functions::UserFunctions
@@ -21,10 +22,27 @@ class SassFunctionTest < Test::Unit::TestCase
21
22
  File.read(File.dirname(__FILE__) + "/data/hsl-rgb.txt").split("\n\n").each do |chunk|
22
23
  hsls, rgbs = chunk.strip.split("====")
23
24
  hsls.strip.split("\n").zip(rgbs.strip.split("\n")) do |hsl, rgb|
24
- method = "test_hsl: #{hsl} = #{rgb}"
25
- define_method(method) do
25
+ hsl_method = "test_hsl: #{hsl} = #{rgb}"
26
+ define_method(hsl_method) do
26
27
  assert_equal(evaluate(rgb), evaluate(hsl))
27
28
  end
29
+
30
+ rgb_to_hsl_method = "test_rgb_to_hsl: #{rgb} = #{hsl}"
31
+ define_method(rgb_to_hsl_method) do
32
+ rgb_color = perform(rgb)
33
+ hsl_color = perform(hsl)
34
+
35
+ white = hsl_color.lightness == 100
36
+ black = hsl_color.lightness == 0
37
+ grayscale = white || black || hsl_color.saturation == 0
38
+
39
+ assert_in_delta(hsl_color.hue, rgb_color.hue, 0.0001,
40
+ "Hues should be equal") unless grayscale
41
+ assert_in_delta(hsl_color.saturation, rgb_color.saturation, 0.0001,
42
+ "Saturations should be equal") unless white || black
43
+ assert_in_delta(hsl_color.lightness, rgb_color.lightness, 0.0001,
44
+ "Lightnesses should be equal")
45
+ end
28
46
  end
29
47
  end
30
48
 
@@ -173,6 +191,23 @@ class SassFunctionTest < Test::Unit::TestCase
173
191
  assert_error_message("\"foo\" is not a number for `rgba'", "rgba(10, 10, 10, \"foo\")");
174
192
  end
175
193
 
194
+ def test_rgba_with_color
195
+ assert_equal "rgba(16, 32, 48, 0.5)", evaluate("rgba(#102030, 0.5)")
196
+ assert_equal "rgba(0, 0, 255, 0.5)", evaluate("rgba(blue, 0.5)")
197
+ end
198
+
199
+ def test_rgba_with_color_tests_types
200
+ assert_error_message("\"foo\" is not a color for `rgba'", "rgba(\"foo\", 0.2)");
201
+ assert_error_message("\"foo\" is not a number for `rgba'", "rgba(blue, \"foo\")");
202
+ end
203
+
204
+ def test_rgba_tests_num_args
205
+ assert_error_message("wrong number of arguments (0 for 4) for `rgba'", "rgba()");
206
+ assert_error_message("wrong number of arguments (1 for 4) for `rgba'", "rgba(blue)");
207
+ assert_error_message("wrong number of arguments (3 for 4) for `rgba'", "rgba(1, 2, 3)");
208
+ assert_error_message("wrong number of arguments (5 for 4) for `rgba'", "rgba(1, 2, 3, 0.4, 5)");
209
+ end
210
+
176
211
  def test_red
177
212
  assert_equal("18", evaluate("red(#123456)"))
178
213
  end
@@ -197,6 +232,32 @@ class SassFunctionTest < Test::Unit::TestCase
197
232
  assert_error_message("12 is not a color for `blue'", "blue(12)")
198
233
  end
199
234
 
235
+ def test_hue
236
+ assert_equal("18deg", evaluate("hue(hsl(18, 50%, 20%))"))
237
+ end
238
+
239
+ def test_hue_exception
240
+ assert_error_message("12 is not a color for `hue'", "hue(12)")
241
+ end
242
+
243
+ def test_saturation
244
+ assert_equal("52%", evaluate("saturation(hsl(20, 52%, 20%))"))
245
+ assert_equal("52%", evaluate("saturation(hsl(20, 52, 20%))"))
246
+ end
247
+
248
+ def test_saturation_exception
249
+ assert_error_message("12 is not a color for `saturation'", "saturation(12)")
250
+ end
251
+
252
+ def test_lightness
253
+ assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86%))"))
254
+ assert_equal("86%", evaluate("lightness(hsl(120, 50%, 86))"))
255
+ end
256
+
257
+ def test_lightness_exception
258
+ assert_error_message("12 is not a color for `lightness'", "lightness(12)")
259
+ end
260
+
200
261
  def test_alpha
201
262
  assert_equal("1", evaluate("alpha(#123456)"))
202
263
  assert_equal("0.34", evaluate("alpha(rgba(0, 1, 2, 0.34))"))
@@ -249,6 +310,161 @@ class SassFunctionTest < Test::Unit::TestCase
249
310
  assert_error_message("\"foo\" is not a number for `transparentize'", "transparentize(#fff, \"foo\")")
250
311
  end
251
312
 
313
+ def test_lighten
314
+ assert_equal("#4d4d4d", evaluate("lighten(hsl(0, 0, 0), 30%)"))
315
+ assert_equal("#ee0000", evaluate("lighten(#800, 20%)"))
316
+ assert_equal("white", evaluate("lighten(#fff, 20%)"))
317
+ assert_equal("white", evaluate("lighten(#800, 100%)"))
318
+ assert_equal("#880000", evaluate("lighten(#800, 0%)"))
319
+ assert_equal("rgba(238, 0, 0, 0.5)", evaluate("lighten(rgba(136, 0, 0, 0.5), 20%)"))
320
+ end
321
+
322
+ def test_lighten_tests_bounds
323
+ assert_error_message("Amount -0.001 must be between 0% and 100% for `lighten'",
324
+ "lighten(#123, -0.001)")
325
+ assert_error_message("Amount 100.001 must be between 0% and 100% for `lighten'",
326
+ "lighten(#123, 100.001)")
327
+ end
328
+
329
+ def test_lighten_tests_types
330
+ assert_error_message("\"foo\" is not a color for `lighten'", "lighten(\"foo\", 10%)")
331
+ assert_error_message("\"foo\" is not a number for `lighten'", "lighten(#fff, \"foo\")")
332
+ end
333
+
334
+ def test_darken
335
+ assert_equal("#ff6a00", evaluate("darken(hsl(25, 100, 80), 30%)"))
336
+ assert_equal("#220000", evaluate("darken(#800, 20%)"))
337
+ assert_equal("black", evaluate("darken(#000, 20%)"))
338
+ assert_equal("black", evaluate("darken(#800, 100%)"))
339
+ assert_equal("#880000", evaluate("darken(#800, 0%)"))
340
+ assert_equal("rgba(34, 0, 0, 0.5)", evaluate("darken(rgba(136, 0, 0, 0.5), 20%)"))
341
+ end
342
+
343
+ def test_darken_tests_bounds
344
+ assert_error_message("Amount -0.001 must be between 0% and 100% for `darken'",
345
+ "darken(#123, -0.001)")
346
+ assert_error_message("Amount 100.001 must be between 0% and 100% for `darken'",
347
+ "darken(#123, 100.001)")
348
+ end
349
+
350
+ def test_darken_tests_types
351
+ assert_error_message("\"foo\" is not a color for `darken'", "darken(\"foo\", 10%)")
352
+ assert_error_message("\"foo\" is not a number for `darken'", "darken(#fff, \"foo\")")
353
+ end
354
+
355
+ def test_saturate
356
+ assert_equal("#d9f2d9", evaluate("saturate(hsl(120, 30, 90), 20%)"))
357
+ assert_equal("#9e3f3f", evaluate("saturate(#855, 20%)"))
358
+ assert_equal("black", evaluate("saturate(#000, 20%)"))
359
+ assert_equal("white", evaluate("saturate(#fff, 20%)"))
360
+ assert_equal("#33ff33", evaluate("saturate(#8a8, 100%)"))
361
+ assert_equal("#88aa88", evaluate("saturate(#8a8, 0%)"))
362
+ assert_equal("rgba(158, 63, 63, 0.5)", evaluate("saturate(rgba(136, 85, 85, 0.5), 20%)"))
363
+ end
364
+
365
+ def test_saturate_tests_bounds
366
+ assert_error_message("Amount -0.001 must be between 0% and 100% for `saturate'",
367
+ "saturate(#123, -0.001)")
368
+ assert_error_message("Amount 100.001 must be between 0% and 100% for `saturate'",
369
+ "saturate(#123, 100.001)")
370
+ end
371
+
372
+ def test_saturate_tests_types
373
+ assert_error_message("\"foo\" is not a color for `saturate'", "saturate(\"foo\", 10%)")
374
+ assert_error_message("\"foo\" is not a number for `saturate'", "saturate(#fff, \"foo\")")
375
+ end
376
+
377
+ def test_desaturate
378
+ assert_equal("#e3e8e3", evaluate("desaturate(hsl(120, 30, 90), 20%)"))
379
+ assert_equal("#726b6b", evaluate("desaturate(#855, 20%)"))
380
+ assert_equal("black", evaluate("desaturate(#000, 20%)"))
381
+ assert_equal("white", evaluate("desaturate(#fff, 20%)"))
382
+ assert_equal("#999999", evaluate("desaturate(#8a8, 100%)"))
383
+ assert_equal("#88aa88", evaluate("desaturate(#8a8, 0%)"))
384
+ assert_equal("rgba(114, 107, 107, 0.5)", evaluate("desaturate(rgba(136, 85, 85, 0.5), 20%)"))
385
+ end
386
+
387
+ def test_desaturate_tests_bounds
388
+ assert_error_message("Amount -0.001 must be between 0% and 100% for `desaturate'",
389
+ "desaturate(#123, -0.001)")
390
+ assert_error_message("Amount 100.001 must be between 0% and 100% for `desaturate'",
391
+ "desaturate(#123, 100.001)")
392
+ end
393
+
394
+ def test_desaturate_tests_types
395
+ assert_error_message("\"foo\" is not a color for `desaturate'", "desaturate(\"foo\", 10%)")
396
+ assert_error_message("\"foo\" is not a number for `desaturate'", "desaturate(#fff, \"foo\")")
397
+ end
398
+
399
+ def test_adjust_hue
400
+ assert_equal("#deeded", evaluate("adjust-hue(hsl(120, 30, 90), 60deg)"))
401
+ assert_equal("#ededde", evaluate("adjust-hue(hsl(120, 30, 90), -60deg)"))
402
+ assert_equal("#886a11", evaluate("adjust-hue(#811, 45deg)"))
403
+ assert_equal("black", evaluate("adjust-hue(#000, 45deg)"))
404
+ assert_equal("white", evaluate("adjust-hue(#fff, 45deg)"))
405
+ assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 360deg)"))
406
+ assert_equal("#88aa88", evaluate("adjust-hue(#8a8, 0deg)"))
407
+ assert_equal("rgba(136, 106, 17, 0.5)", evaluate("adjust-hue(rgba(136, 17, 17, 0.5), 45deg)"))
408
+ end
409
+
410
+ def test_adjust_hue_tests_types
411
+ assert_error_message("\"foo\" is not a color for `adjust-hue'", "adjust-hue(\"foo\", 10%)")
412
+ assert_error_message("\"foo\" is not a number for `adjust-hue'", "adjust-hue(#fff, \"foo\")")
413
+ end
414
+
415
+ def test_mix
416
+ assert_equal("#7f007f", evaluate("mix(#f00, #00f)"))
417
+ assert_equal("#7f7f7f", evaluate("mix(#f00, #0ff)"))
418
+ assert_equal("#7f9055", evaluate("mix(#f70, #0aa)"))
419
+ assert_equal("#3f00bf", evaluate("mix(#f00, #00f, 25%)"))
420
+ assert_equal("rgba(63, 0, 191, 0.75)", evaluate("mix(rgba(255, 0, 0, 0.5), #00f)"))
421
+ assert_equal("red", evaluate("mix(#f00, #00f, 100%)"))
422
+ assert_equal("blue", evaluate("mix(#f00, #00f, 0%)"))
423
+ assert_equal("rgba(255, 0, 0, 0.5)", evaluate("mix(#f00, transparentize(#00f, 1))"))
424
+ assert_equal("rgba(0, 0, 255, 0.5)", evaluate("mix(transparentize(#f00, 1), #00f)"))
425
+ assert_equal("red", evaluate("mix(#f00, transparentize(#00f, 1), 100%)"))
426
+ assert_equal("blue", evaluate("mix(transparentize(#f00, 1), #00f, 0%)"))
427
+ assert_equal("rgba(0, 0, 255, 0)", evaluate("mix(#f00, transparentize(#00f, 1), 0%)"))
428
+ assert_equal("rgba(255, 0, 0, 0)", evaluate("mix(transparentize(#f00, 1), #00f, 100%)"))
429
+ end
430
+
431
+ def test_mix_tests_types
432
+ assert_error_message("\"foo\" is not a color for `mix'", "mix(\"foo\", #f00, 10%)")
433
+ assert_error_message("\"foo\" is not a color for `mix'", "mix(#f00, \"foo\", 10%)")
434
+ assert_error_message("\"foo\" is not a number for `mix'", "mix(#f00, #baf, \"foo\")")
435
+ end
436
+
437
+ def test_mix_tests_bounds
438
+ assert_error_message("Weight -0.001 must be between 0% and 100% for `mix'",
439
+ "mix(#123, #456, -0.001)")
440
+ assert_error_message("Weight 100.001 must be between 0% and 100% for `mix'",
441
+ "mix(#123, #456, 100.001)")
442
+ end
443
+
444
+ def test_grayscale
445
+ assert_equal("#bbbbbb", evaluate("grayscale(#abc)"))
446
+ assert_equal("gray", evaluate("grayscale(#f00)"))
447
+ assert_equal("gray", evaluate("grayscale(#00f)"))
448
+ assert_equal("white", evaluate("grayscale(white)"))
449
+ assert_equal("black", evaluate("grayscale(black)"))
450
+ end
451
+
452
+ def tets_grayscale_tests_types
453
+ assert_error_message("\"foo\" is not a color for `grayscale'", "grayscale(\"foo\")")
454
+ end
455
+
456
+ def test_complement
457
+ assert_equal("#ccbbaa", evaluate("complement(#abc)"))
458
+ assert_equal("aqua", evaluate("complement(red)"))
459
+ assert_equal("red", evaluate("complement(aqua)"))
460
+ assert_equal("white", evaluate("complement(white)"))
461
+ assert_equal("black", evaluate("complement(black)"))
462
+ end
463
+
464
+ def tets_complement_tests_types
465
+ assert_error_message("\"foo\" is not a color for `complement'", "complement(\"foo\")")
466
+ end
467
+
252
468
  def test_user_defined_function
253
469
  assert_equal("I'm a user-defined string!", evaluate("user_defined()"))
254
470
  end
@@ -268,6 +484,10 @@ MSG
268
484
  Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new).to_s
269
485
  end
270
486
 
487
+ def perform(value)
488
+ Sass::Script::Parser.parse(value, 0, 0).perform(Sass::Environment.new)
489
+ end
490
+
271
491
  def assert_error_message(message, value)
272
492
  evaluate(value)
273
493
  flunk("Error message expected but not raised: #{message}")