sass 3.3.14 → 3.4.0.rc.1

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +5 -5
  4. data/VERSION +1 -1
  5. data/VERSION_DATE +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +0 -5
  10. data/lib/sass/css.rb +1 -3
  11. data/lib/sass/engine.rb +28 -39
  12. data/lib/sass/environment.rb +13 -17
  13. data/lib/sass/error.rb +6 -9
  14. data/lib/sass/exec.rb +5 -771
  15. data/lib/sass/exec/base.rb +187 -0
  16. data/lib/sass/exec/sass_convert.rb +264 -0
  17. data/lib/sass/exec/sass_scss.rb +419 -0
  18. data/lib/sass/features.rb +6 -0
  19. data/lib/sass/importers.rb +0 -1
  20. data/lib/sass/importers/base.rb +5 -1
  21. data/lib/sass/importers/filesystem.rb +4 -21
  22. data/lib/sass/media.rb +1 -4
  23. data/lib/sass/plugin/compiler.rb +32 -136
  24. data/lib/sass/script/css_lexer.rb +1 -1
  25. data/lib/sass/script/functions.rb +363 -39
  26. data/lib/sass/script/lexer.rb +68 -50
  27. data/lib/sass/script/parser.rb +29 -14
  28. data/lib/sass/script/tree.rb +1 -0
  29. data/lib/sass/script/tree/funcall.rb +1 -1
  30. data/lib/sass/script/tree/interpolation.rb +19 -1
  31. data/lib/sass/script/tree/selector.rb +26 -0
  32. data/lib/sass/script/value.rb +0 -1
  33. data/lib/sass/script/value/bool.rb +0 -5
  34. data/lib/sass/script/value/color.rb +32 -12
  35. data/lib/sass/script/value/helpers.rb +107 -0
  36. data/lib/sass/script/value/list.rb +0 -15
  37. data/lib/sass/script/value/null.rb +0 -5
  38. data/lib/sass/script/value/number.rb +60 -14
  39. data/lib/sass/script/value/string.rb +53 -9
  40. data/lib/sass/scss/css_parser.rb +8 -2
  41. data/lib/sass/scss/parser.rb +175 -319
  42. data/lib/sass/scss/rx.rb +14 -5
  43. data/lib/sass/scss/static_parser.rb +298 -1
  44. data/lib/sass/selector.rb +56 -193
  45. data/lib/sass/selector/abstract_sequence.rb +28 -13
  46. data/lib/sass/selector/comma_sequence.rb +91 -12
  47. data/lib/sass/selector/pseudo.rb +256 -0
  48. data/lib/sass/selector/sequence.rb +99 -31
  49. data/lib/sass/selector/simple.rb +14 -25
  50. data/lib/sass/selector/simple_sequence.rb +101 -37
  51. data/lib/sass/shared.rb +1 -1
  52. data/lib/sass/source/map.rb +23 -9
  53. data/lib/sass/stack.rb +0 -6
  54. data/lib/sass/supports.rb +1 -1
  55. data/lib/sass/tree/at_root_node.rb +1 -0
  56. data/lib/sass/tree/directive_node.rb +7 -1
  57. data/lib/sass/tree/error_node.rb +18 -0
  58. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  59. data/lib/sass/tree/prop_node.rb +1 -1
  60. data/lib/sass/tree/rule_node.rb +11 -6
  61. data/lib/sass/tree/visitors/check_nesting.rb +3 -4
  62. data/lib/sass/tree/visitors/convert.rb +8 -17
  63. data/lib/sass/tree/visitors/cssize.rb +12 -24
  64. data/lib/sass/tree/visitors/deep_copy.rb +5 -0
  65. data/lib/sass/tree/visitors/perform.rb +43 -28
  66. data/lib/sass/tree/visitors/set_options.rb +5 -0
  67. data/lib/sass/tree/visitors/to_css.rb +14 -13
  68. data/lib/sass/util.rb +94 -90
  69. data/test/sass/cache_test.rb +1 -1
  70. data/test/sass/callbacks_test.rb +1 -1
  71. data/test/sass/compiler_test.rb +5 -14
  72. data/test/sass/conversion_test.rb +47 -1
  73. data/test/sass/css2sass_test.rb +3 -3
  74. data/test/sass/encoding_test.rb +219 -0
  75. data/test/sass/engine_test.rb +128 -191
  76. data/test/sass/exec_test.rb +2 -2
  77. data/test/sass/extend_test.rb +234 -17
  78. data/test/sass/functions_test.rb +268 -213
  79. data/test/sass/importer_test.rb +31 -21
  80. data/test/sass/logger_test.rb +1 -1
  81. data/test/sass/more_results/more_import.css +1 -1
  82. data/test/sass/plugin_test.rb +12 -11
  83. data/test/sass/results/compact.css +1 -1
  84. data/test/sass/results/complex.css +4 -4
  85. data/test/sass/results/expanded.css +1 -1
  86. data/test/sass/results/import.css +1 -1
  87. data/test/sass/results/import_charset_ibm866.css +2 -2
  88. data/test/sass/results/mixins.css +17 -17
  89. data/test/sass/results/nested.css +1 -1
  90. data/test/sass/results/parent_ref.css +2 -2
  91. data/test/sass/results/script.css +3 -3
  92. data/test/sass/results/scss_import.css +1 -1
  93. data/test/sass/script_conversion_test.rb +7 -4
  94. data/test/sass/script_test.rb +202 -79
  95. data/test/sass/scss/css_test.rb +95 -25
  96. data/test/sass/scss/rx_test.rb +4 -4
  97. data/test/sass/scss/scss_test.rb +363 -19
  98. data/test/sass/source_map_test.rb +48 -41
  99. data/test/sass/superselector_test.rb +191 -0
  100. data/test/sass/templates/scss_import.scss +2 -1
  101. data/test/sass/test_helper.rb +1 -1
  102. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  103. data/test/sass/util/normalized_map_test.rb +1 -1
  104. data/test/sass/util/subset_map_test.rb +2 -2
  105. data/test/sass/util_test.rb +1 -1
  106. data/test/sass/value_helpers_test.rb +3 -3
  107. data/test/test_helper.rb +2 -2
  108. metadata +30 -7
  109. data/lib/sass/importers/deprecated_path.rb +0 -51
  110. data/lib/sass/script/value/deprecated_false.rb +0 -55
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/../test_helper'
3
3
  require 'sass/util/test'
4
4
  require 'tmpdir'
5
5
 
6
- class ExecTest < Test::Unit::TestCase
6
+ class ExecTest < MiniTest::Test
7
7
  include Sass::Util::Test
8
8
 
9
9
  def setup
@@ -19,7 +19,7 @@ class ExecTest < Test::Unit::TestCase
19
19
  src = get_path("src.scss")
20
20
  dest = get_path("dest.css")
21
21
  write(src, ".ruleset { margin: 0 }")
22
- assert(exec(*%w[scss -t expanded --unix-newlines].push(src, dest)))
22
+ assert(exec(*%w[scss --sourcemap=none -t expanded --unix-newlines].push(src, dest)))
23
23
  assert_equal(".ruleset {\n margin: 0;\n}\n", read(dest))
24
24
  end
25
25
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
3
 
4
- class ExtendTest < Test::Unit::TestCase
4
+ class ExtendTest < MiniTest::Test
5
5
  def test_basic
6
6
  assert_equal <<CSS, render(<<SCSS)
7
7
  .foo, .bar {
@@ -310,9 +310,183 @@ SCSS
310
310
  end
311
311
 
312
312
  def test_negation_unification
313
- assert_unification ':not(.foo).baz', ':not(.bar) {@extend .baz}', ':not(.foo).baz, :not(.foo):not(.bar)'
314
- assert_unification ':not(.foo).baz', ':not(.foo) {@extend .baz}', ':not(.foo)'
315
- assert_unification ':not([a=b]).baz', ':not([a = b]) {@extend .baz}', ':not([a=b])'
313
+ assert_extends ':not(.foo).baz', ':not(.bar) {@extend .baz}', ':not(.foo).baz, :not(.foo):not(.bar)'
314
+ # Unifying to :not(.foo) here would reduce the specificity of the original selector.
315
+ assert_extends ':not(.foo).baz', ':not(.foo) {@extend .baz}', ':not(.foo).baz, :not(.foo)'
316
+ end
317
+
318
+ def test_prefixed_pseudoclass_unification
319
+ assert_unification(
320
+ ':nth-child(2n+1 of .foo).baz',
321
+ ':nth-child(2n of .foo) {@extend .baz}',
322
+ ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n of .foo)')
323
+
324
+ assert_unification(
325
+ ':nth-child(2n+1 of .foo).baz',
326
+ ':nth-child(2n+1 of .bar) {@extend .baz}',
327
+ ':nth-child(2n+1 of .foo).baz, :nth-child(2n+1 of .foo):nth-child(2n+1 of .bar)')
328
+
329
+ assert_unification(
330
+ ':nth-child(2n+1 of .foo).baz',
331
+ ':nth-child(2n+1 of .foo) {@extend .baz}',
332
+ ':nth-child(2n+1 of .foo)')
333
+ end
334
+
335
+ def test_extend_into_not
336
+ assert_extends(':not(.foo)', '.x {@extend .foo}', ':not(.foo, .x)')
337
+ assert_extends(':not(.foo.bar)', '.x {@extend .bar}', ':not(.foo.bar, .foo.x)')
338
+ assert_extends(
339
+ ':not(.foo.bar, .baz.bar)',
340
+ '.x {@extend .bar}',
341
+ ':not(.foo.bar, .foo.x, .baz.bar, .baz.x)')
342
+ end
343
+
344
+ def test_extend_into_mergeable_pseudoclasses
345
+ assert_extends(':matches(.foo)', '.x {@extend .foo}', ':matches(.foo, .x)')
346
+ assert_extends(':matches(.foo.bar)', '.x {@extend .bar}', ':matches(.foo.bar, .foo.x)')
347
+ assert_extends(
348
+ ':matches(.foo.bar, .baz.bar)',
349
+ '.x {@extend .bar}',
350
+ ':matches(.foo.bar, .foo.x, .baz.bar, .baz.x)')
351
+
352
+ assert_extends(':-moz-any(.foo)', '.x {@extend .foo}', ':-moz-any(.foo, .x)')
353
+ assert_extends(':current(.foo)', '.x {@extend .foo}', ':current(.foo, .x)')
354
+ assert_extends(':has(.foo)', '.x {@extend .foo}', ':has(.foo, .x)')
355
+ assert_extends(':host(.foo)', '.x {@extend .foo}', ':host(.foo, .x)')
356
+ assert_extends(':host-context(.foo)', '.x {@extend .foo}', ':host-context(.foo, .x)')
357
+ assert_extends(':nth-child(n of .foo)', '.x {@extend .foo}', ':nth-child(n of .foo, .x)')
358
+ assert_extends(
359
+ ':nth-last-child(n of .foo)',
360
+ '.x {@extend .foo}',
361
+ ':nth-last-child(n of .foo, .x)')
362
+ end
363
+
364
+ def test_complex_extend_into_pseudoclass
365
+ assert_extends(':not(.bar)', '.x .y {@extend .bar}', ':not(.bar, .x .y)')
366
+ assert_extends(':matches(.bar)', '.x .y {@extend .bar}', ':matches(.bar, .x .y)')
367
+ assert_extends(':current(.bar)', '.x .y {@extend .bar}', ':current(.bar, .x .y)')
368
+ assert_extends(':has(.bar)', '.x .y {@extend .bar}', ':has(.bar, .x .y)')
369
+ assert_extends(':host(.bar)', '.x .y {@extend .bar}', ':host(.bar, .x .y)')
370
+ assert_extends(':host-context(.bar)', '.x .y {@extend .bar}', ':host-context(.bar, .x .y)')
371
+ assert_extends(
372
+ ':-moz-any(.bar)',
373
+ '.x .y {@extend .bar}',
374
+ ':-moz-any(.bar, .x .y)')
375
+ assert_extends(
376
+ ':nth-child(n of .bar)',
377
+ '.x .y {@extend .bar}',
378
+ ':nth-child(n of .bar, .x .y)')
379
+ assert_extends(
380
+ ':nth-last-child(n of .bar)',
381
+ '.x .y {@extend .bar}',
382
+ ':nth-last-child(n of .bar, .x .y)')
383
+ end
384
+
385
+ def test_extend_over_selector_pseudoclass
386
+ assert_extends(':not(.foo)', '.x {@extend :not(.foo)}', ':not(.foo), .x')
387
+ assert_extends(
388
+ ':matches(.foo, .bar)',
389
+ '.x {@extend :matches(.foo, .bar)}',
390
+ ':matches(.foo, .bar), .x')
391
+ end
392
+
393
+ def test_matches_within_not
394
+ assert_extends(
395
+ ':not(.foo, .bar)',
396
+ ':matches(.x, .y) {@extend .foo}',
397
+ ':not(.foo, .x, .y, .bar)')
398
+ end
399
+
400
+ def test_pseudoclasses_merge
401
+ assert_extends(':matches(.foo)', ':matches(.bar) {@extend .foo}', ':matches(.foo, .bar)')
402
+ assert_extends(':-moz-any(.foo)', ':-moz-any(.bar) {@extend .foo}', ':-moz-any(.foo, .bar)')
403
+ assert_extends(':current(.foo)', ':current(.bar) {@extend .foo}', ':current(.foo, .bar)')
404
+ assert_extends(
405
+ ':nth-child(n of .foo)',
406
+ ':nth-child(n of .bar) {@extend .foo}',
407
+ ':nth-child(n of .foo, .bar)')
408
+ assert_extends(
409
+ ':nth-last-child(n of .foo)',
410
+ ':nth-last-child(n of .bar) {@extend .foo}',
411
+ ':nth-last-child(n of .foo, .bar)')
412
+ end
413
+
414
+ def test_nesting_pseudoclasses_merge
415
+ assert_extends(':has(.foo)', ':has(.bar) {@extend .foo}', ':has(.foo, :has(.bar))')
416
+ assert_extends(':host(.foo)', ':host(.bar) {@extend .foo}', ':host(.foo, :host(.bar))')
417
+ assert_extends(
418
+ ':host-context(.foo)',
419
+ ':host-context(.bar) {@extend .foo}',
420
+ ':host-context(.foo, :host-context(.bar))')
421
+ end
422
+
423
+ def test_not_unifies_with_unique_values
424
+ assert_unification('foo', ':not(bar) {@extend foo}', ':not(bar)')
425
+ assert_unification('#foo', ':not(#bar) {@extend #foo}', ':not(#bar)')
426
+ end
427
+
428
+ def test_not_adds_no_specificity
429
+ assert_specificity_equals(':not(.foo)', '.foo')
430
+ end
431
+
432
+ def test_matches_has_a_specificity_range
433
+ # `:matches(.foo, #bar)` has minimum specificity equal to that of `.foo`,
434
+ # which means `:matches(.foo, #bar) .a` can have less specificity than
435
+ # `#b.a`. Thus the selector generated by `#b.a` should be preserved.
436
+ assert_equal <<CSS, render(<<SCSS)
437
+ :matches(.foo, #bar) .a, :matches(.foo, #bar) #b.a {
438
+ a: b; }
439
+ CSS
440
+ :matches(.foo, #bar) %x {a: b}
441
+ .a {@extend %x}
442
+ #b.a {@extend %x}
443
+ SCSS
444
+
445
+ # `:matches(.foo, #bar)` has maximum specificity equal to that of `#bar`,
446
+ # which means `:matches(.foo, #bar).b` can have greater specificity than `.a
447
+ # .b`. Thus the selector generated by `:matches(.foo, #bar).b` should be
448
+ # preserved.
449
+ assert_equal <<CSS, render(<<SCSS)
450
+ .a .b, .a .b:matches(.foo, #bar) {
451
+ a: b; }
452
+ CSS
453
+ .a %x {a: b}
454
+ .b {@extend %x}
455
+ .b:matches(.foo, #bar) {@extend %x}
456
+ SCSS
457
+ end
458
+
459
+ def test_extend_into_not_and_normal_extend
460
+ assert_equal <<CSS, render(<<SCSS)
461
+ .x:not(.y, .bar), .foo:not(.y, .bar) {
462
+ a: b; }
463
+ CSS
464
+ .x:not(.y) {a: b}
465
+ .foo {@extend .x}
466
+ .bar {@extend .y}
467
+ SCSS
468
+ end
469
+
470
+ def test_extend_into_matches_and_normal_extend
471
+ assert_equal <<CSS, render(<<SCSS)
472
+ .x:matches(.y, .bar), .foo:matches(.y, .bar) {
473
+ a: b; }
474
+ CSS
475
+ .x:matches(.y) {a: b}
476
+ .foo {@extend .x}
477
+ .bar {@extend .y}
478
+ SCSS
479
+ end
480
+
481
+ def test_multilayer_pseudoclass_extend
482
+ assert_equal <<CSS, render(<<SCSS)
483
+ :matches(.x, .foo, .bar) {
484
+ a: b; }
485
+ CSS
486
+ :matches(.x) {a: b}
487
+ .foo {@extend .x}
488
+ .bar {@extend .foo}
489
+ SCSS
316
490
  end
317
491
 
318
492
  def test_comma_extendee
@@ -516,7 +690,7 @@ SCSS
516
690
  end
517
691
 
518
692
  def test_nested_extender_with_trailing_child_selector
519
- assert_raise(Sass::SyntaxError, "bar > can't extend: invalid selector") do
693
+ assert_raises(Sass::SyntaxError, "bar > can't extend: invalid selector") do
520
694
  render("bar > {@extend .baz}")
521
695
  end
522
696
  end
@@ -650,10 +824,10 @@ SCSS
650
824
 
651
825
  def test_basic_extend_loop
652
826
  assert_equal <<CSS, render(<<SCSS)
653
- .bar, .foo {
827
+ .foo, .bar {
654
828
  a: b; }
655
829
 
656
- .foo, .bar {
830
+ .bar, .foo {
657
831
  c: d; }
658
832
  CSS
659
833
  .foo {a: b; @extend .bar}
@@ -663,13 +837,13 @@ SCSS
663
837
 
664
838
  def test_three_level_extend_loop
665
839
  assert_equal <<CSS, render(<<SCSS)
666
- .baz, .bar, .foo {
840
+ .foo, .baz, .bar {
667
841
  a: b; }
668
842
 
669
- .foo, .baz, .bar {
843
+ .bar, .foo, .baz {
670
844
  c: d; }
671
845
 
672
- .bar, .foo, .baz {
846
+ .baz, .bar, .foo {
673
847
  e: f; }
674
848
  CSS
675
849
  .foo {a: b; @extend .bar}
@@ -692,6 +866,18 @@ CSS
692
866
  SCSS
693
867
  end
694
868
 
869
+ def test_cross_loop
870
+ # The first law of extend means the selector should stick around.
871
+ assert_equal <<CSS, render(<<SCSS)
872
+ .foo.bar, .foo, .bar {
873
+ a: b; }
874
+ CSS
875
+ .foo.bar {a: b}
876
+ .foo {@extend .bar}
877
+ .bar {@extend .foo}
878
+ SCSS
879
+ end
880
+
695
881
  def test_multiple_extender_merges_with_superset_selector
696
882
  assert_equal <<CSS, render(<<SCSS)
697
883
  a.bar.baz, a.foo {
@@ -830,6 +1016,17 @@ $foo: foo;
830
1016
  SCSS
831
1017
  end
832
1018
 
1019
+ def test_placeholder_in_selector_pseudoclass
1020
+ assert_equal <<CSS, render(<<SCSS)
1021
+ :matches(.bar, .baz) {
1022
+ color: blue; }
1023
+ CSS
1024
+ :matches(%foo) {color: blue}
1025
+ .bar {@extend %foo}
1026
+ .baz {@extend %foo}
1027
+ SCSS
1028
+ end
1029
+
833
1030
  def test_media_in_placeholder_selector
834
1031
  assert_equal <<CSS, render(<<SCSS)
835
1032
  .baz {
@@ -1005,7 +1202,7 @@ SCSS
1005
1202
  end
1006
1203
 
1007
1204
  def test_extend_with_subject_transfers_subject_to_extender
1008
- assert_equal(<<CSS, render(<<SCSS))
1205
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1009
1206
  foo bar! baz, foo .bip .bap! baz, .bip foo .bap! baz {
1010
1207
  a: b; }
1011
1208
  CSS
@@ -1013,7 +1210,7 @@ foo bar! baz {a: b}
1013
1210
  .bip .bap {@extend bar}
1014
1211
  SCSS
1015
1212
 
1016
- assert_equal(<<CSS, render(<<SCSS))
1213
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1017
1214
  foo.x bar.y! baz.z, foo.x .bip bar.bap! baz.z, .bip foo.x bar.bap! baz.z {
1018
1215
  a: b; }
1019
1216
  CSS
@@ -1023,7 +1220,7 @@ SCSS
1023
1220
  end
1024
1221
 
1025
1222
  def test_extend_with_subject_retains_subject_on_target
1026
- assert_equal(<<CSS, render(<<SCSS))
1223
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1027
1224
  .foo! .bar, .foo! .bip .bap, .bip .foo! .bap {
1028
1225
  a: b; }
1029
1226
  CSS
@@ -1033,7 +1230,7 @@ SCSS
1033
1230
  end
1034
1231
 
1035
1232
  def test_extend_with_subject_transfers_subject_to_target
1036
- assert_equal(<<CSS, render(<<SCSS))
1233
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1037
1234
  a.foo .bar, .bip a.bap! .bar {
1038
1235
  a: b; }
1039
1236
  CSS
@@ -1043,7 +1240,7 @@ SCSS
1043
1240
  end
1044
1241
 
1045
1242
  def test_extend_with_subject_retains_subject_on_extender
1046
- assert_equal(<<CSS, render(<<SCSS))
1243
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1047
1244
  .foo .bar, .foo .bip! .bap, .bip! .foo .bap {
1048
1245
  a: b; }
1049
1246
  CSS
@@ -1053,7 +1250,7 @@ SCSS
1053
1250
  end
1054
1251
 
1055
1252
  def test_extend_with_subject_fails_with_conflicting_subject
1056
- assert_equal(<<CSS, render(<<SCSS))
1253
+ silence_warnings {assert_equal(<<CSS, render(<<SCSS))}
1057
1254
  x! .bar {
1058
1255
  a: b; }
1059
1256
  CSS
@@ -1408,7 +1605,7 @@ Use "@extend #{target} !optional" if the extend should be able to fail.
1408
1605
  ERR
1409
1606
  end
1410
1607
 
1411
- def assert_unification(selector, extension, unified)
1608
+ def assert_unification(selector, extension, unified, nested = true)
1412
1609
  # Do some trickery so the first law of extend doesn't get in our way.
1413
1610
  assert_extends(
1414
1611
  "%-a #{selector}",
@@ -1416,6 +1613,22 @@ ERR
1416
1613
  unified.split(', ').map {|s| "-a #{s}"}.join(', '))
1417
1614
  end
1418
1615
 
1616
+ def assert_specificity_equals(sel1, sel2)
1617
+ assert_specificity_gte(sel1, sel2)
1618
+ assert_specificity_gte(sel2, sel1)
1619
+ end
1620
+
1621
+ def assert_specificity_gte(sel1, sel2)
1622
+ assert_equal <<CSS, render(<<SCSS)
1623
+ #{sel1} .a {
1624
+ a: b; }
1625
+ CSS
1626
+ #{sel1} %-a {a: b}
1627
+ .a {@extend %-a}
1628
+ #{sel2}.a {@extend %-a}
1629
+ SCSS
1630
+ end
1631
+
1419
1632
  def render_unification(selector, extension)
1420
1633
  render_extends(
1421
1634
  "%-a #{selector}",
@@ -1429,6 +1642,10 @@ ERR
1429
1642
  CSS
1430
1643
  end
1431
1644
 
1645
+ def assert_extends_to_nothing(selector, extension)
1646
+ assert_equal '', render_extends(selector, extension)
1647
+ end
1648
+
1432
1649
  def render_extends(selector, extension)
1433
1650
  render(<<SCSS)
1434
1651
  #{selector} {a: b}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require 'test/unit'
2
+ require 'minitest/autorun'
3
3
  require File.dirname(__FILE__) + '/../test_helper'
4
4
  require File.dirname(__FILE__) + '/test_helper'
5
5
  require 'sass/script'
@@ -19,6 +19,12 @@ module Sass::Script::Functions
19
19
  Sass::Script::Value::String.new("only-kw-args(" + kwargs.keys.map {|a| a.to_s}.sort.join(", ") + ")")
20
20
  end
21
21
  declare :only_kw_args, [], :var_kwargs => true
22
+
23
+ def deprecated_arg_fn(arg1, arg2, arg3 = nil)
24
+ Sass::Script::Value::List.new([arg1, arg2, arg3 || Sass::Script::Value::Null.new], :space)
25
+ end
26
+ declare :deprecated_arg_fn, [:arg1, :arg2, :arg3], :deprecated => [:arg_1, :arg_2, :arg3]
27
+ declare :deprecated_arg_fn, [:arg1, :arg2], :deprecated => [:arg_1, :arg_2]
22
28
  end
23
29
 
24
30
  module Sass::Script::Functions::UserFunctions
@@ -45,7 +51,7 @@ module Sass::Script::Functions
45
51
  include Sass::Script::Functions::UserFunctions
46
52
  end
47
53
 
48
- class SassFunctionTest < Test::Unit::TestCase
54
+ class SassFunctionTest < MiniTest::Test
49
55
  # Tests taken from:
50
56
  # http://www.w3.org/Style/CSS/Test/CSS3/Color/20070927/html4/t040204-hsl-h-rotating-b.htm
51
57
  # http://www.w3.org/Style/CSS/Test/CSS3/Color/20070927/html4/t040204-hsl-values-b.htm
@@ -123,12 +129,6 @@ class SassFunctionTest < Test::Unit::TestCase
123
129
  assert_equal("50%", evaluate("percentage($number: 0.5)"))
124
130
  end
125
131
 
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
130
- end
131
-
132
132
  def test_percentage_checks_types
133
133
  assert_error_message("$number: 25px is not a unitless number for `percentage'", "percentage(25px)")
134
134
  assert_error_message("$number: #cccccc is not a unitless number for `percentage'", "percentage(#ccc)")
@@ -142,12 +142,6 @@ WARNING
142
142
  assert_equal("5px", evaluate("round($number: 5.49px)"))
143
143
  end
144
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
150
-
151
145
  def test_round_checks_types
152
146
  assert_error_message("$value: #cccccc is not a number for `round'", "round(#ccc)")
153
147
  end
@@ -158,12 +152,6 @@ WARNING
158
152
  assert_equal("4px", evaluate("floor($number: 4.8px)"))
159
153
  end
160
154
 
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
166
-
167
155
  def test_floor_checks_types
168
156
  assert_error_message("$value: \"foo\" is not a number for `floor'", "floor(\"foo\")")
169
157
  end
@@ -174,12 +162,6 @@ WARNING
174
162
  assert_equal("5px", evaluate("ceil($number: 4.8px)"))
175
163
  end
176
164
 
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
165
  def test_ceil_checks_types
184
166
  assert_error_message("$value: \"a\" is not a number for `ceil'", "ceil(\"a\")")
185
167
  end
@@ -192,12 +174,6 @@ WARNING
192
174
  assert_equal("5px", evaluate("abs($number: 5px)"))
193
175
  end
194
176
 
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
200
-
201
177
  def test_abs_checks_types
202
178
  assert_error_message("$value: #aaaaaa is not a number for `abs'", "abs(#aaa)")
203
179
  end
@@ -840,32 +816,6 @@ WARNING
840
816
  assert_equal("rgba(255, 0, 0, 0)", evaluate("mix($color1: transparentize(#f00, 1), $color2: #00f, $weight: 100%)"))
841
817
  end
842
818
 
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
867
- end
868
-
869
819
  def test_mix_tests_types
870
820
  assert_error_message("$color1: \"foo\" is not a color for `mix'", "mix(\"foo\", #f00, 10%)")
871
821
  assert_error_message("$color2: \"foo\" is not a color for `mix'", "mix(#f00, \"foo\", 10%)")
@@ -995,7 +945,6 @@ WARNING
995
945
  assert_equal('ab', evaluate('str-slice(abcd,1,2)')) # for completeness
996
946
  assert_equal('abcd', evaluate('str-slice(abcd,1,4)')) # at the end points
997
947
  assert_equal('abcd', evaluate('str-slice(abcd,0,4)')) # when start is before the start of the string
998
- assert_equal('', evaluate('str-slice(abcd,1,0)')) # when end is before the start of the string
999
948
  assert_equal('abcd', evaluate('str-slice(abcd,1,100)')) # when end is past the end of the string
1000
949
  assert_equal('', evaluate('str-slice(abcd,2,1)')) # when end is before start
1001
950
  assert_equal('"bc"', evaluate('str-slice("abcd",2,3)')) # when used with a quoted string
@@ -1085,22 +1034,6 @@ MSG
1085
1034
  assert_equal(%Q{false}, evaluate("comparable($number1: 100px, $number2: 3em)"))
1086
1035
  end
1087
1036
 
1088
- def test_comparable_deprecated_arg_name
1089
- assert_warning <<WARNING do
1090
- DEPRECATION WARNING: The `$number-1' argument for `comparable()' has been renamed to `$number1'.
1091
- DEPRECATION WARNING: The `$number-2' argument for `comparable()' has been renamed to `$number2'.
1092
- WARNING
1093
- assert_equal("false", evaluate("comparable($number-1: 100px, $number-2: 3em)"))
1094
- end
1095
-
1096
- assert_warning <<WARNING do
1097
- DEPRECATION WARNING: The `$number_1' argument for `comparable()' has been renamed to `$number1'.
1098
- DEPRECATION WARNING: The `$number_2' argument for `comparable()' has been renamed to `$number2'.
1099
- WARNING
1100
- assert_equal("false", evaluate("comparable($number_1: 100px, $number_2: 3em)"))
1101
- end
1102
- end
1103
-
1104
1037
  def test_comparable_checks_types
1105
1038
  assert_error_message("$number1: #ff0000 is not a number for `comparable'", "comparable(#f00, 1px)")
1106
1039
  assert_error_message("$number2: #ff0000 is not a number for `comparable'", "comparable(1px, #f00)")
@@ -1258,76 +1191,17 @@ WARNING
1258
1191
  end
1259
1192
 
1260
1193
  def test_index
1194
+ null = Sass::Script::Value::Null.new
1261
1195
  assert_equal("1", evaluate("index(1px solid blue, 1px)"))
1262
1196
  assert_equal("2", evaluate("index(1px solid blue, solid)"))
1263
1197
  assert_equal("3", evaluate("index(1px solid blue, #00f)"))
1264
1198
  assert_equal("1", evaluate("index(1px, 1px)"))
1265
- assert_equal("false", evaluate("index(1px solid blue, 1em)"))
1266
- assert_equal("false", evaluate("index(1px solid blue, notfound)"))
1267
- assert_equal("false", evaluate("index(1px, #00f)"))
1199
+ assert_equal(null, perform("index(1px solid blue, 1em)"))
1200
+ assert_equal(null, perform("index(1px solid blue, notfound)"))
1201
+ assert_equal(null, perform("index(1px, #00f)"))
1268
1202
 
1269
1203
  assert_equal("1", evaluate("index((foo: bar, bar: baz), (foo bar))"))
1270
- assert_equal("false", evaluate("index((foo: bar, bar: baz), (foo: bar))"))
1271
- end
1272
-
1273
- def test_index_deprecation_warning
1274
- assert_warning(<<WARNING) do
1275
- DEPRECATION WARNING: The return value of index() will change from "false" to
1276
- "null" in future versions of Sass. For compatibility, avoid using "== false" on
1277
- the return value. For example, instead of "@if index(...) == false", just write
1278
- "@if not index(...)".
1279
- WARNING
1280
- assert_equal("true", evaluate("index(1, 2 3 4) == false"))
1281
- end
1282
-
1283
- assert_warning(<<WARNING) do
1284
- DEPRECATION WARNING: The return value of index() will change from "false" to
1285
- "null" in future versions of Sass. For compatibility, avoid using "!= null" on
1286
- the return value.
1287
- WARNING
1288
- assert_equal("true", evaluate("index(1, 2 3 4) != null"))
1289
- end
1290
-
1291
- assert_warning(<<WARNING) do
1292
- DEPRECATION WARNING: The return value of index() will change from "false" to
1293
- "null" in future versions of Sass. For compatibility, avoid using "== false" on
1294
- the return value. For example, instead of "@if index(...) == false", just write
1295
- "@if not index(...)".
1296
- WARNING
1297
- assert_equal("true", evaluate("false == index(1, 2 3 4)"))
1298
- end
1299
-
1300
- assert_warning(<<WARNING) do
1301
- DEPRECATION WARNING: The return value of index() will change from "false" to
1302
- "null" in future versions of Sass. For compatibility, avoid using "!= null" on
1303
- the return value.
1304
- WARNING
1305
- assert_equal("true", evaluate("null != index(1, 2 3 4)"))
1306
- end
1307
- end
1308
-
1309
- def test_index_deprecation_warning_is_only_emitted_once_per_call
1310
- assert_warning(<<WARNING) do
1311
- DEPRECATION WARNING: The return value of index() will change from "false" to
1312
- "null" in future versions of Sass. For compatibility, avoid using "== false" on
1313
- the return value. For example, instead of "@if index(...) == false", just write
1314
- "@if not index(...)".
1315
- on line 3 of test_index_deprecation_warning_is_only_emitted_once_per_call_inline.scss
1316
- DEPRECATION WARNING: The return value of index() will change from "false" to
1317
- "null" in future versions of Sass. For compatibility, avoid using "== false" on
1318
- the return value. For example, instead of "@if index(...) == false", just write
1319
- "@if not index(...)".
1320
- on line 6 of test_index_deprecation_warning_is_only_emitted_once_per_call_inline.scss
1321
- WARNING
1322
- render(<<SCSS)
1323
- @for $i from 1 to 10 {
1324
- $var1: index(1, 2 3 4);
1325
- $var2: $var1 == false;
1326
- $var3: $var1 != null;
1327
- }
1328
- $var4: index(1, 2 3 4) == false;
1329
- SCSS
1330
- end
1204
+ assert_equal(null, perform("index((foo: bar, bar: baz), (foo: bar))"))
1331
1205
  end
1332
1206
 
1333
1207
  def test_list_separator
@@ -1447,7 +1321,7 @@ SCSS
1447
1321
  50.times do
1448
1322
  last_id, current_id = current_id, evaluate("unique-id()")
1449
1323
  assert_match(/u[a-z0-9]{8}/, current_id)
1450
- assert_not_equal last_id, current_id
1324
+ refute_equal last_id, current_id
1451
1325
  end
1452
1326
  end
1453
1327
 
@@ -1458,16 +1332,6 @@ SCSS
1458
1332
  assert_equal "null", perform("map-get((), foo)").to_sass
1459
1333
  end
1460
1334
 
1461
- def test_map_get_deprecation_warning
1462
- assert_warning(<<WARNING) do
1463
- DEPRECATION WARNING: Passing lists of pairs to map-get is deprecated and will
1464
- be removed in future versions of Sass. Use Sass maps instead. For details, see
1465
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1466
- WARNING
1467
- assert_equal "1", evaluate("map-get((foo 1) (bar 2), foo)")
1468
- end
1469
- end
1470
-
1471
1335
  def test_map_get_checks_type
1472
1336
  assert_error_message("$map: 12 is not a map for `map-get'", "map-get(12, bar)")
1473
1337
  end
@@ -1481,26 +1345,6 @@ WARNING
1481
1345
  perform("map-merge((foo: 1, bar: 2), ())").to_sass)
1482
1346
  end
1483
1347
 
1484
- def test_map_merge_deprecation_warning
1485
- assert_warning(<<WARNING) do
1486
- DEPRECATION WARNING: Passing lists of pairs to map-merge is deprecated and will
1487
- be removed in future versions of Sass. Use Sass maps instead. For details, see
1488
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1489
- WARNING
1490
- assert_equal("(foo: 1, bar: 2, baz: 3)",
1491
- perform("map-merge((foo 1, bar 2), (baz: 3))").to_sass)
1492
- end
1493
-
1494
- assert_warning(<<WARNING) do
1495
- DEPRECATION WARNING: Passing lists of pairs to map-merge is deprecated and will
1496
- be removed in future versions of Sass. Use Sass maps instead. For details, see
1497
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1498
- WARNING
1499
- assert_equal("(baz: 3, foo: 1, bar: 2)",
1500
- perform("map-merge((baz: 3), (foo 1, bar 2))").to_sass)
1501
- end
1502
- end
1503
-
1504
1348
  def test_map_merge_checks_type
1505
1349
  assert_error_message("$map1: 12 is not a map for `map-merge'", "map-merge(12, (foo: 1))")
1506
1350
  assert_error_message("$map2: 12 is not a map for `map-merge'", "map-merge((foo: 1), 12)")
@@ -1509,18 +1353,12 @@ WARNING
1509
1353
  def test_map_remove
1510
1354
  assert_equal("(foo: 1, baz: 3)",
1511
1355
  perform("map-remove((foo: 1, bar: 2, baz: 3), bar)").to_sass)
1356
+ assert_equal("(foo: 1, baz: 3)",
1357
+ perform("map-remove($map: (foo: 1, bar: 2, baz: 3), $key: bar)").to_sass)
1358
+ assert_equal("()",
1359
+ perform("map-remove((foo: 1, bar: 2, baz: 3), foo, bar, baz)").to_sass)
1512
1360
  assert_equal("()", perform("map-remove((), foo)").to_sass)
1513
- end
1514
-
1515
- def test_map_remove_deprecation_warning
1516
- assert_warning(<<WARNING) do
1517
- DEPRECATION WARNING: Passing lists of pairs to map-remove is deprecated and will
1518
- be removed in future versions of Sass. Use Sass maps instead. For details, see
1519
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1520
- WARNING
1521
- assert_equal("(foo: 1, baz: 3)",
1522
- perform("map-remove((foo 1, bar 2, baz 3), bar)").to_sass)
1523
- end
1361
+ assert_equal("()", perform("map-remove((), foo, bar)").to_sass)
1524
1362
  end
1525
1363
 
1526
1364
  def test_map_remove_checks_type
@@ -1533,17 +1371,6 @@ WARNING
1533
1371
  assert_equal("()", perform("map-keys(())").to_sass)
1534
1372
  end
1535
1373
 
1536
- def test_map_keys_deprecation_warning
1537
- assert_warning(<<WARNING) do
1538
- DEPRECATION WARNING: Passing lists of pairs to map-keys is deprecated and will
1539
- be removed in future versions of Sass. Use Sass maps instead. For details, see
1540
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1541
- WARNING
1542
- assert_equal("foo, bar",
1543
- perform("map-keys((foo 1, bar 2))").to_sass)
1544
- end
1545
- end
1546
-
1547
1374
  def test_map_keys_checks_type
1548
1375
  assert_error_message("$map: 12 is not a map for `map-keys'", "map-keys(12)")
1549
1376
  end
@@ -1555,16 +1382,6 @@ WARNING
1555
1382
  assert_equal("()", perform("map-values(())").to_sass)
1556
1383
  end
1557
1384
 
1558
- def test_map_values_deprecation_warning
1559
- assert_warning(<<WARNING) do
1560
- DEPRECATION WARNING: Passing lists of pairs to map-values is deprecated and will
1561
- be removed in future versions of Sass. Use Sass maps instead. For details, see
1562
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1563
- WARNING
1564
- assert_equal("1, 2", perform("map-values((foo 1, bar 2))").to_sass)
1565
- end
1566
- end
1567
-
1568
1385
  def test_map_values_checks_type
1569
1386
  assert_error_message("$map: 12 is not a map for `map-values'", "map-values(12)")
1570
1387
  end
@@ -1575,16 +1392,6 @@ WARNING
1575
1392
  assert_equal "false", evaluate("map-has-key((), foo)")
1576
1393
  end
1577
1394
 
1578
- def test_map_has_key_deprecation_warning
1579
- assert_warning(<<WARNING) do
1580
- DEPRECATION WARNING: Passing lists of pairs to map-has-key is deprecated and will
1581
- be removed in future versions of Sass. Use Sass maps instead. For details, see
1582
- http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
1583
- WARNING
1584
- assert_equal("true", evaluate("map-has-key((foo 1, bar 1), foo)"))
1585
- end
1586
- end
1587
-
1588
1395
  def test_map_has_key_checks_type
1589
1396
  assert_error_message("$map: 12 is not a map for `map-has-key'", "map-has-key(12, foo)")
1590
1397
  end
@@ -1839,7 +1646,255 @@ SCSS
1839
1646
  if Sass::Script::Functions.instance_variable_defined?("@random_number_generator")
1840
1647
  Sass::Script::Functions.send(:remove_instance_variable, "@random_number_generator")
1841
1648
  end
1842
- assert_not_equal evaluate("random()"), evaluate("random()")
1649
+ refute_equal evaluate("random()"), evaluate("random()")
1650
+ end
1651
+
1652
+ def test_deprecated_arg_names
1653
+ assert_warning <<WARNING do
1654
+ DEPRECATION WARNING: The `$arg-1' argument for `deprecated-arg-fn()' has been renamed to `$arg1'.
1655
+ DEPRECATION WARNING: The `$arg-2' argument for `deprecated-arg-fn()' has been renamed to `$arg2'.
1656
+ WARNING
1657
+ assert_equal("1 2 3",
1658
+ evaluate("deprecated-arg-fn($arg-1: 1, $arg-2: 2, $arg3: 3)"))
1659
+ end
1660
+
1661
+ assert_warning <<WARNING do
1662
+ DEPRECATION WARNING: The `$arg-1' argument for `deprecated-arg-fn()' has been renamed to `$arg1'.
1663
+ DEPRECATION WARNING: The `$arg-2' argument for `deprecated-arg-fn()' has been renamed to `$arg2'.
1664
+ WARNING
1665
+ assert_equal("1 2",
1666
+ evaluate("deprecated-arg-fn($arg-1: 1, $arg-2: 2)"))
1667
+ end
1668
+
1669
+ assert_warning <<WARNING do
1670
+ DEPRECATION WARNING: The `$arg_1' argument for `deprecated-arg-fn()' has been renamed to `$arg1'.
1671
+ DEPRECATION WARNING: The `$arg_2' argument for `deprecated-arg-fn()' has been renamed to `$arg2'.
1672
+ WARNING
1673
+ assert_equal("1 2",
1674
+ evaluate("deprecated-arg-fn($arg_1: 1, $arg_2: 2)"))
1675
+ end
1676
+ end
1677
+
1678
+ def test_non_deprecated_arg_names
1679
+ assert_equal("1 2 3", evaluate("deprecated-arg-fn($arg1: 1, $arg2: 2, $arg3: 3)"))
1680
+ assert_equal("1 2", evaluate("deprecated-arg-fn($arg1: 1, $arg2: 2)"))
1681
+ end
1682
+
1683
+ ## Selector Functions
1684
+
1685
+ def test_selector_argument_parsing
1686
+ assert_equal("true", evaluate("selector-parse('.foo') == (join(('.foo',), (), space),)"))
1687
+ assert_equal("true", evaluate("selector-parse('.foo .bar') == ('.foo' '.bar',)"))
1688
+ assert_equal("true",
1689
+ evaluate("selector-parse('.foo .bar, .baz .bang') == ('.foo' '.bar', '.baz' '.bang')"))
1690
+
1691
+ assert_equal(".foo %bar", evaluate("selector-parse('.foo %bar')"))
1692
+
1693
+ assert_equal("true",
1694
+ evaluate("selector-parse(('.foo', '.bar')) == selector-parse('.foo, .bar')"))
1695
+ assert_equal("true",
1696
+ evaluate("selector-parse('.foo' '.bar') == selector-parse('.foo .bar')"))
1697
+
1698
+ assert_equal("true", evaluate("selector-parse(('.foo' '.bar', '.baz' '.bang')) == " +
1699
+ "selector-parse('.foo .bar, .baz .bang')"))
1700
+ assert_equal("true", evaluate("selector-parse(('.foo .bar', '.baz .bang')) == " +
1701
+ "selector-parse('.foo .bar, .baz .bang')"))
1702
+
1703
+ # This may throw an error in the future.
1704
+ assert_equal("true", evaluate("selector-parse(('.foo, .bar' '.baz, .bang')) == " +
1705
+ "selector-parse('.foo, .bar .baz, .bang')"))
1706
+ end
1707
+
1708
+ def test_selector_argument_validation
1709
+ assert_error_message("$selector: 12 is not a valid selector: it must be a string,\n" +
1710
+ "a list of strings, or a list of lists of strings for `selector-parse'", "selector-parse(12)")
1711
+ assert_error_message("$selector: (((\".foo\" \".bar\"), \".baz\") (\".bang\", \".qux\")) is not a valid selector: it must be a string,\n" +
1712
+ "a list of strings, or a list of lists of strings for `selector-parse'",
1713
+ "selector-parse(('.foo' '.bar', '.baz') ('.bang', '.qux'))")
1714
+ assert_error_message("$selector: \".#\" is not a valid selector: Invalid CSS after \".\": " +
1715
+ "expected class name, was \"#\" for `selector-parse'", "selector-parse('.#')")
1716
+ assert_error_message("$selector: \"&.foo\" is not a valid selector: Invalid CSS after \"\": " +
1717
+ "expected selector, was \"&.foo\" for `selector-parse'", "selector-parse('&.foo')")
1718
+ end
1719
+
1720
+ def test_selector_nest
1721
+ assert_equal(".foo", evaluate("selector-nest('.foo')"))
1722
+ assert_equal(".foo .bar", evaluate("selector-nest('.foo', '.bar')"))
1723
+ assert_equal(".foo .bar .baz", evaluate("selector-nest('.foo', '.bar', '.baz')"))
1724
+ assert_equal(".a .foo .b .bar", evaluate("selector-nest('.a .foo', '.b .bar')"))
1725
+ assert_equal(".foo.bar", evaluate("selector-nest('.foo', '&.bar')"))
1726
+ assert_equal(".baz .foo.bar", evaluate("selector-nest('.foo', '&.bar', '.baz &')"))
1727
+ end
1728
+
1729
+ def test_selector_nest_checks_types
1730
+ assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
1731
+ "a list of strings, or a list of lists of strings for `selector-nest'",
1732
+ "selector-nest(12)")
1733
+ assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
1734
+ "a list of strings, or a list of lists of strings for `selector-nest'",
1735
+ "selector-nest('.foo', 12)")
1736
+ end
1737
+
1738
+ def test_selector_nest_argument_validation
1739
+ assert_error_message("$selectors: At least one selector must be passed for `selector-nest'",
1740
+ "selector-nest()")
1741
+ end
1742
+
1743
+ def test_selector_append
1744
+ assert_equal(".foo.bar", evaluate("selector-append('.foo', '.bar')"))
1745
+ assert_equal(".a .foo.b .bar", evaluate("selector-append('.a .foo', '.b .bar')"))
1746
+ assert_equal(".foo-suffix", evaluate("selector-append('.foo', '-suffix')"))
1747
+ assert_equal(".foo.bar, .foo-suffix", evaluate("selector-append('.foo', '.bar, -suffix')"))
1748
+ assert_equal(".foo--suffix", evaluate("selector-append('.foo', '--suffix')"))
1749
+ assert_equal(".foo.bar, .foo--suffix", evaluate("selector-append('.foo', '.bar, --suffix')"))
1750
+ end
1751
+
1752
+ def test_selector_append_checks_types
1753
+ assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
1754
+ "a list of strings, or a list of lists of strings for `selector-append'",
1755
+ "selector-append(12)")
1756
+ assert_error_message("$selectors: 12 is not a valid selector: it must be a string,\n" +
1757
+ "a list of strings, or a list of lists of strings for `selector-append'",
1758
+ "selector-append('.foo', 12)")
1759
+ end
1760
+
1761
+ def test_selector_append_errors
1762
+ assert_error_message("$selectors: At least one selector must be passed for `selector-append'",
1763
+ "selector-append()")
1764
+ assert_error_message("Can't append \"> .bar\" to \".foo\" for `selector-append'",
1765
+ "selector-append('.foo', '> .bar')")
1766
+ assert_error_message("Can't append \"*.bar\" to \".foo\" for `selector-append'",
1767
+ "selector-append('.foo', '*.bar')")
1768
+ assert_error_message("Can't append \"ns|suffix\" to \".foo\" for `selector-append'",
1769
+ "selector-append('.foo', 'ns|suffix')")
1770
+ end
1771
+
1772
+ def test_selector_extend
1773
+ assert_equal(".foo .x, .foo .a .bar, .a .foo .bar",
1774
+ evaluate("selector-extend('.foo .x', '.x', '.a .bar')"))
1775
+ assert_equal(".foo .x, .foo .bang, .x.bar, .bar.bang",
1776
+ evaluate("selector-extend('.foo .x, .x.bar', '.x', '.bang')"))
1777
+ assert_equal(".y .x, .foo .x, .y .foo, .foo .foo",
1778
+ evaluate("selector-extend('.y .x', '.x, .y', '.foo')"))
1779
+ assert_equal(".foo .x, .foo .bar, .foo .bang",
1780
+ evaluate("selector-extend('.foo .x', '.x', '.bar, .bang')"))
1781
+ assert_equal(".foo.x, .foo",
1782
+ evaluate("selector-extend('.foo.x', '.x', '.foo')"))
1783
+ end
1784
+
1785
+ def test_selector_extend_checks_types
1786
+ assert_error_message("$selector: 12 is not a valid selector: it must be a string,\n" +
1787
+ "a list of strings, or a list of lists of strings for `selector-extend'",
1788
+ "selector-extend(12, '.foo', '.bar')")
1789
+ assert_error_message("$extendee: 12 is not a valid selector: it must be a string,\n" +
1790
+ "a list of strings, or a list of lists of strings for `selector-extend'",
1791
+ "selector-extend('.foo', 12, '.bar')")
1792
+ assert_error_message("$extender: 12 is not a valid selector: it must be a string,\n" +
1793
+ "a list of strings, or a list of lists of strings for `selector-extend'",
1794
+ "selector-extend('.foo', '.bar', 12)")
1795
+ end
1796
+
1797
+ def test_selector_extend_errors
1798
+ assert_error_message("Can't extend .bar .baz: can't extend nested selectors for " +
1799
+ "`selector-extend'", "selector-extend('.foo', '.bar .baz', '.bang')")
1800
+ assert_error_message("Can't extend >: invalid selector for `selector-extend'",
1801
+ "selector-extend('.foo', '>', '.bang')")
1802
+ assert_error_message(".bang > can't extend: invalid selector for `selector-extend'",
1803
+ "selector-extend('.foo', '.bar', '.bang >')")
1804
+ end
1805
+
1806
+ def test_selector_replace
1807
+ assert_equal(".bar", evaluate("selector-replace('.foo', '.foo', '.bar')"))
1808
+ assert_equal(".foo.baz", evaluate("selector-replace('.foo.bar', '.bar', '.baz')"))
1809
+ assert_equal(".a .foo.baz", evaluate("selector-replace('.foo.bar', '.bar', '.a .baz')"))
1810
+ assert_equal(".foo.bar", evaluate("selector-replace('.foo.bar', '.baz.bar', '.qux')"))
1811
+ assert_equal(".bar.qux", evaluate("selector-replace('.foo.bar.baz', '.foo.baz', '.qux')"))
1812
+
1813
+ assert_equal(":not(.bar)", evaluate("selector-replace(':not(.foo)', '.foo', '.bar')"))
1814
+ assert_equal(".bar", evaluate("selector-replace(':not(.foo)', ':not(.foo)', '.bar')"))
1815
+ end
1816
+
1817
+ def test_selector_replace_checks_types
1818
+ assert_error_message("$selector: 12 is not a valid selector: it must be a string,\n" +
1819
+ "a list of strings, or a list of lists of strings for `selector-replace'",
1820
+ "selector-replace(12, '.foo', '.bar')")
1821
+ assert_error_message("$original: 12 is not a valid selector: it must be a string,\n" +
1822
+ "a list of strings, or a list of lists of strings for `selector-replace'",
1823
+ "selector-replace('.foo', 12, '.bar')")
1824
+ assert_error_message("$replacement: 12 is not a valid selector: it must be a string,\n" +
1825
+ "a list of strings, or a list of lists of strings for `selector-replace'",
1826
+ "selector-replace('.foo', '.bar', 12)")
1827
+ end
1828
+
1829
+ def test_selector_replace_errors
1830
+ assert_error_message("Can't extend .bar .baz: can't extend nested selectors for " +
1831
+ "`selector-replace'", "selector-replace('.foo', '.bar .baz', '.bang')")
1832
+ assert_error_message("Can't extend >: invalid selector for `selector-replace'",
1833
+ "selector-replace('.foo', '>', '.bang')")
1834
+ assert_error_message(".bang > can't extend: invalid selector for `selector-replace'",
1835
+ "selector-replace('.foo', '.bar', '.bang >')")
1836
+ end
1837
+
1838
+ def test_selector_unify
1839
+ assert_equal(".foo", evaluate("selector-unify('.foo', '.foo')"))
1840
+ assert_equal(".foo.bar", evaluate("selector-unify('.foo', '.bar')"))
1841
+ assert_equal(".foo.bar.baz", evaluate("selector-unify('.foo.bar', '.bar.baz')"))
1842
+ assert_equal(".a .b .foo.bar, .b .a .foo.bar", evaluate("selector-unify('.a .foo', '.b .bar')"))
1843
+ assert_equal(".a .foo.bar", evaluate("selector-unify('.a .foo', '.a .bar')"))
1844
+ assert_equal("", evaluate("selector-unify('p', 'a')"))
1845
+ assert_equal("", evaluate("selector-unify('.foo >', '.bar')"))
1846
+ assert_equal("", evaluate("selector-unify('.foo', '.bar >')"))
1847
+ assert_equal(".foo.baz, .foo.bang, .bar.baz, .bar.bang",
1848
+ evaluate("selector-unify('.foo, .bar', '.baz, .bang')"))
1849
+ end
1850
+
1851
+ def test_selector_unify_checks_types
1852
+ assert_error_message("$selector1: 12 is not a valid selector: it must be a string,\n" +
1853
+ "a list of strings, or a list of lists of strings for `selector-unify'",
1854
+ "selector-unify(12, '.foo')")
1855
+ assert_error_message("$selector2: 12 is not a valid selector: it must be a string,\n" +
1856
+ "a list of strings, or a list of lists of strings for `selector-unify'",
1857
+ "selector-unify('.foo', 12)")
1858
+ end
1859
+
1860
+ def test_simple_selectors
1861
+ assert_equal('(.foo,)', evaluate("inspect(simple-selectors('.foo'))"))
1862
+ assert_equal('.foo, .bar', evaluate("inspect(simple-selectors('.foo.bar'))"))
1863
+ assert_equal('.foo, .bar, :pseudo("flip, flap")',
1864
+ evaluate("inspect(simple-selectors('.foo.bar:pseudo(\"flip, flap\")'))"))
1865
+ end
1866
+
1867
+ def test_simple_selectors_checks_types
1868
+ assert_error_message("$selector: 12 is not a string for `simple-selectors'",
1869
+ "simple-selectors(12)")
1870
+ end
1871
+
1872
+ def test_simple_selectors_errors
1873
+ assert_error_message("$selector: \".foo .bar\" is not a compound selector for `simple-selectors'",
1874
+ "simple-selectors('.foo .bar')")
1875
+ assert_error_message("$selector: \".foo,.bar\" is not a compound selector for `simple-selectors'",
1876
+ "simple-selectors('.foo,.bar')")
1877
+ assert_error_message("$selector: \".#\" is not a valid selector: Invalid CSS after \".\": " +
1878
+ "expected class name, was \"#\" for `simple-selectors'", "simple-selectors('.#')")
1879
+ end
1880
+
1881
+ def test_is_superselector
1882
+ assert_equal("true", evaluate("is-superselector('.foo', '.foo.bar')"))
1883
+ assert_equal("false", evaluate("is-superselector('.foo.bar', '.foo')"))
1884
+ assert_equal("true", evaluate("is-superselector('.foo', '.foo')"))
1885
+ assert_equal("true", evaluate("is-superselector('.bar', '.foo .bar')"))
1886
+ assert_equal("false", evaluate("is-superselector('.foo .bar', '.bar')"))
1887
+ assert_equal("true", evaluate("is-superselector('.foo .bar', '.foo > .bar')"))
1888
+ assert_equal("false", evaluate("is-superselector('.foo > .bar', '.foo .bar')"))
1889
+ end
1890
+
1891
+ def test_is_superselector_checks_types
1892
+ assert_error_message("$super: 12 is not a valid selector: it must be a string,\n" +
1893
+ "a list of strings, or a list of lists of strings for `is-superselector'",
1894
+ "is-superselector(12, '.foo')")
1895
+ assert_error_message("$sub: 12 is not a valid selector: it must be a string,\n" +
1896
+ "a list of strings, or a list of lists of strings for `is-superselector'",
1897
+ "is-superselector('.foo', 12)")
1843
1898
  end
1844
1899
 
1845
1900
  ## Regression Tests