PageRenderTime 49ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/training-web/vendor/bundle/gems/sass-3.2.9/test/sass/scss/css_test.rb

https://bitbucket.org/ohimmelreich/asalia-training
Ruby | 1093 lines | 983 code | 93 blank | 17 comment | 1 complexity | 3ea2a64e1da493dab17a02621bef07b6 MD5 | raw file
  1. #!/usr/bin/env ruby
  2. # -*- coding: utf-8 -*-
  3. require File.dirname(__FILE__) + '/test_helper'
  4. require 'sass/scss/css_parser'
  5. # These tests just test the parsing of CSS
  6. # (both standard and any hacks we intend to support).
  7. # Tests of SCSS-specific behavior go in scss_test.rb.
  8. class ScssCssTest < Test::Unit::TestCase
  9. include ScssTestHelper
  10. def test_basic_scss
  11. assert_parses <<SCSS
  12. selector {
  13. property: value;
  14. property2: value; }
  15. SCSS
  16. assert_equal <<CSS, render('sel{p:v}')
  17. sel {
  18. p: v; }
  19. CSS
  20. end
  21. def test_empty_rule
  22. assert_equal "", render("#foo .bar {}")
  23. assert_equal "", render(<<SCSS)
  24. #foo .bar {
  25. }
  26. SCSS
  27. end
  28. def test_cdo_and_cdc_ignored_at_toplevel
  29. assert_equal <<CSS, render(<<SCSS)
  30. foo {
  31. bar: baz; }
  32. bar {
  33. bar: baz; }
  34. baz {
  35. bar: baz; }
  36. CSS
  37. foo {bar: baz}
  38. <!--
  39. bar {bar: baz}
  40. -->
  41. baz {bar: baz}
  42. SCSS
  43. end
  44. if Sass::Util.ruby1_8?
  45. def test_unicode
  46. assert_parses <<SCSS
  47. @charset "UTF-8";
  48. foo {
  49. bar: föö bâr; }
  50. SCSS
  51. assert_parses <<SCSS
  52. foo {
  53. bar: föö bâr; }
  54. SCSS
  55. end
  56. else
  57. def test_unicode
  58. assert_parses <<SCSS
  59. @charset "UTF-8";
  60. foo {
  61. bar: föö bâr; }
  62. SCSS
  63. assert_equal <<CSS, render(<<SCSS)
  64. @charset "UTF-8";
  65. foo {
  66. bar: föö bâr; }
  67. CSS
  68. foo {
  69. bar: föö bâr; }
  70. SCSS
  71. end
  72. end
  73. def test_invisible_comments
  74. assert_equal <<CSS, render(<<SCSS)
  75. foo {
  76. a: d; }
  77. CSS
  78. foo {a: /* b; c: */ d}
  79. SCSS
  80. assert_equal <<CSS, render(<<SCSS)
  81. foo {
  82. a: d; }
  83. CSS
  84. foo {a /*: b; c */: d}
  85. SCSS
  86. end
  87. def test_crazy_comments
  88. # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/t040109-c17-comments-00-b.xht
  89. assert_equal <<CSS, render(<<SCSS)
  90. /* This is a CSS comment. */
  91. .one {
  92. color: green; }
  93. /* Another comment */
  94. /* The following should not be used:
  95. .two {color: red;} */
  96. .three {
  97. color: green;
  98. /* color: red; */ }
  99. /**
  100. .four {color: red;} */
  101. .five {
  102. color: green; }
  103. /**/
  104. .six {
  105. color: green; }
  106. /*********/
  107. .seven {
  108. color: green; }
  109. /* a comment **/
  110. .eight {
  111. color: green; }
  112. CSS
  113. /* This is a CSS comment. */
  114. .one {color: green;} /* Another comment */
  115. /* The following should not be used:
  116. .two {color: red;} */
  117. .three {color: green; /* color: red; */}
  118. /**
  119. .four {color: red;} */
  120. .five {color: green;}
  121. /**/
  122. .six {color: green;}
  123. /*********/
  124. .seven {color: green;}
  125. /* a comment **/
  126. .eight {color: green;}
  127. SCSS
  128. end
  129. def test_rule_comments
  130. assert_parses <<SCSS
  131. /* Foo */
  132. .foo {
  133. a: b; }
  134. SCSS
  135. assert_equal <<CSS, render(<<SCSS)
  136. /* Foo
  137. * Bar */
  138. .foo {
  139. a: b; }
  140. CSS
  141. /* Foo
  142. * Bar */.foo {
  143. a: b; }
  144. SCSS
  145. end
  146. def test_property_comments
  147. assert_parses <<SCSS
  148. .foo {
  149. /* Foo */
  150. a: b; }
  151. SCSS
  152. assert_equal <<CSS, render(<<SCSS)
  153. .foo {
  154. /* Foo
  155. * Bar */
  156. a: b; }
  157. CSS
  158. .foo {
  159. /* Foo
  160. * Bar */a: b; }
  161. SCSS
  162. end
  163. def test_selector_comments
  164. assert_equal <<CSS, render(<<SCSS)
  165. .foo #bar:baz(bip) {
  166. a: b; }
  167. CSS
  168. .foo /* .a #foo */ #bar:baz(/* bang )*/ bip) {
  169. a: b; }
  170. SCSS
  171. end
  172. def test_lonely_comments
  173. assert_parses <<SCSS
  174. /* Foo
  175. * Bar */
  176. SCSS
  177. assert_parses <<SCSS
  178. .foo {
  179. /* Foo
  180. * Bar */ }
  181. SCSS
  182. end
  183. def test_multiple_comments
  184. assert_parses <<SCSS
  185. /* Foo
  186. * Bar */
  187. /* Baz
  188. * Bang */
  189. SCSS
  190. assert_parses <<SCSS
  191. .foo {
  192. /* Foo
  193. * Bar */
  194. /* Baz
  195. * Bang */ }
  196. SCSS
  197. assert_equal <<CSS, render(<<SCSS)
  198. .foo {
  199. /* Foo Bar */
  200. /* Baz Bang */ }
  201. CSS
  202. .foo {
  203. /* Foo Bar *//* Baz Bang */ }
  204. SCSS
  205. end
  206. def test_bizarrely_formatted_comments
  207. assert_parses <<SCSS
  208. .foo {
  209. /* Foo
  210. Bar
  211. Baz */
  212. a: b; }
  213. SCSS
  214. assert_parses <<SCSS
  215. .foo {
  216. /* Foo
  217. Bar
  218. Baz */
  219. a: b; }
  220. SCSS
  221. assert_equal <<CSS, render(<<SCSS)
  222. .foo {
  223. /* Foo
  224. Bar */
  225. a: b; }
  226. CSS
  227. .foo {/* Foo
  228. Bar */
  229. a: b; }
  230. SCSS
  231. assert_equal <<CSS, render(<<SCSS)
  232. .foo {
  233. /* Foo
  234. Bar
  235. Baz */
  236. a: b; }
  237. CSS
  238. .foo {/* Foo
  239. Bar
  240. Baz */
  241. a: b; }
  242. SCSS
  243. end
  244. ## Declarations
  245. def test_vendor_properties
  246. assert_parses <<SCSS
  247. foo {
  248. -moz-foo-bar: blat;
  249. -o-flat-blang: wibble; }
  250. SCSS
  251. end
  252. def test_empty_declarations
  253. assert_equal <<CSS, render(<<SCSS)
  254. foo {
  255. bar: baz; }
  256. CSS
  257. foo {;;;;
  258. bar: baz;;;;
  259. ;;}
  260. SCSS
  261. end
  262. def test_basic_property_types
  263. assert_parses <<SCSS
  264. foo {
  265. a: 2;
  266. b: 2.3em;
  267. c: 50%;
  268. d: "fraz bran";
  269. e: flanny-blanny-blan;
  270. f: url(http://sass-lang.com);
  271. g: U+ffa?;
  272. h: #aabbcc; }
  273. SCSS
  274. end
  275. def test_functions
  276. assert_parses <<SCSS
  277. foo {
  278. a: foo-bar(12);
  279. b: -foo-bar-baz(13, 14 15); }
  280. SCSS
  281. end
  282. def test_unary_minus
  283. assert_parses <<SCSS
  284. foo {
  285. a: -2;
  286. b: -2.3em;
  287. c: -50%;
  288. d: -foo(bar baz); }
  289. SCSS
  290. end
  291. def test_operators
  292. assert_parses <<SCSS
  293. foo {
  294. a: foo bar baz;
  295. b: foo, #aabbcc, -12;
  296. c: 1px/2px/-3px;
  297. d: foo bar, baz/bang; }
  298. SCSS
  299. end
  300. def test_important
  301. assert_parses <<SCSS
  302. foo {
  303. a: foo !important;
  304. b: foo bar !important;
  305. b: foo, bar !important; }
  306. SCSS
  307. end
  308. def test_initial_hyphen
  309. assert_parses <<SCSS
  310. foo {
  311. a: -moz-bar-baz;
  312. b: foo -o-bar-baz; }
  313. SCSS
  314. end
  315. def test_ms_long_filter_syntax
  316. assert_equal <<CSS, render(<<SCSS)
  317. foo {
  318. filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000000);
  319. filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000000); }
  320. CSS
  321. foo {
  322. filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000000);
  323. filter:progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#c0ff3300, endColorstr=#ff000000); }
  324. SCSS
  325. end
  326. def test_ms_short_filter_syntax
  327. assert_parses <<SCSS
  328. foo {
  329. filter: alpha(opacity=20);
  330. filter: alpha(opacity=20, enabled=true);
  331. filter: blaznicate(foo=bar, baz=bang bip, bart=#fa4600); }
  332. SCSS
  333. end
  334. def test_declaration_hacks
  335. assert_parses <<SCSS
  336. foo {
  337. _name: val;
  338. *name: val;
  339. :name: val;
  340. .name: val;
  341. #name: val;
  342. name/**/: val;
  343. name/*\\**/: val;
  344. name: val; }
  345. SCSS
  346. end
  347. def test_trailing_hash_hack
  348. assert_parses <<SCSS
  349. foo {
  350. foo: bar;
  351. #baz: bang;
  352. #bip: bop; }
  353. SCSS
  354. end
  355. def test_zero_arg_functions
  356. assert_parses <<SCSS
  357. foo {
  358. a: foo();
  359. b: bar baz-bang() bip; }
  360. SCSS
  361. end
  362. def test_expression_function
  363. assert_parses <<SCSS
  364. foo {
  365. a: 12px expression(1 + (3 / Foo.bar("baz" + "bang") + function() {return 12;}) % 12); }
  366. SCSS
  367. end
  368. def test_calc_function
  369. assert_parses <<SCSS
  370. foo {
  371. a: 12px calc(100%/3 - 2*1em - 2*1px);
  372. b: 12px -moz-calc(100%/3 - 2*1em - 2*1px);
  373. b: 12px -webkit-calc(100%/3 - 2*1em - 2*1px);
  374. b: 12px -foobar-calc(100%/3 - 2*1em - 2*1px); }
  375. SCSS
  376. end
  377. def test_element_function
  378. assert_parses <<SCSS
  379. foo {
  380. a: -moz-element(#foo);
  381. b: -webkit-element(#foo);
  382. b: -foobar-element(#foo); }
  383. SCSS
  384. end
  385. def test_unary_ops
  386. assert_equal <<CSS, render(<<SCSS)
  387. foo {
  388. a: -0.5em;
  389. b: +0.5em;
  390. c: -foo(12px);
  391. d: +foo(12px); }
  392. CSS
  393. foo {
  394. a: -0.5em;
  395. b: +0.5em;
  396. c: -foo(12px);
  397. d: +foo(12px); }
  398. SCSS
  399. end
  400. def test_css_string_escapes
  401. assert_parses <<SCSS
  402. foo {
  403. a: "\\foo bar";
  404. b: "foo\\ bar";
  405. c: "\\2022 \\0020";
  406. d: "foo\\\\bar";
  407. e: "foo\\"'bar"; }
  408. SCSS
  409. end
  410. def test_css_ident_escapes
  411. assert_parses <<SCSS
  412. foo {
  413. a: \\foo bar;
  414. b: foo\\ bar;
  415. c: \\2022 \\0020;
  416. d: foo\\\\bar;
  417. e: foo\\"\\'bar; }
  418. SCSS
  419. end
  420. ## Directives
  421. def test_namespace_directive
  422. assert_parses '@namespace "http://www.w3.org/Profiles/xhtml1-strict";'
  423. assert_parses '@namespace url(http://www.w3.org/Profiles/xhtml1-strict);'
  424. assert_parses '@namespace html url("http://www.w3.org/Profiles/xhtml1-strict");'
  425. end
  426. def test_media_directive
  427. assert_parses <<SCSS
  428. @media all {
  429. rule1 {
  430. prop: val; }
  431. rule2 {
  432. prop: val; } }
  433. SCSS
  434. assert_parses <<SCSS
  435. @media screen, print {
  436. rule1 {
  437. prop: val; }
  438. rule2 {
  439. prop: val; } }
  440. SCSS
  441. end
  442. def test_media_directive_with_keywords
  443. assert_parses <<SCSS
  444. @media screen and (-webkit-min-device-pixel-ratio: 0) {
  445. a: b; }
  446. SCSS
  447. assert_parses <<SCSS
  448. @media only screen, print and (foo: 0px) and (bar: flam(12px solid)) {
  449. a: b; }
  450. SCSS
  451. end
  452. def test_import_directive
  453. assert_parses '@import "foo.css";'
  454. assert_parses "@import 'foo.css';"
  455. assert_parses '@import url("foo.css");'
  456. assert_parses "@import url('foo.css');"
  457. assert_parses '@import url(foo.css);'
  458. end
  459. def test_import_directive_with_media
  460. assert_parses '@import "foo.css" screen;'
  461. assert_parses '@import "foo.css" screen, print;'
  462. assert_parses '@import "foo.css" screen, print and (foo: 0);'
  463. assert_parses '@import "foo.css" screen, only print, screen and (foo: 0);'
  464. end
  465. def test_page_directive
  466. assert_parses <<SCSS
  467. @page {
  468. prop1: val;
  469. prop2: val; }
  470. SCSS
  471. assert_parses <<SCSS
  472. @page flap {
  473. prop1: val;
  474. prop2: val; }
  475. SCSS
  476. assert_parses <<SCSS
  477. @page :first {
  478. prop1: val;
  479. prop2: val; }
  480. SCSS
  481. assert_parses <<SCSS
  482. @page flap:first {
  483. prop1: val;
  484. prop2: val; }
  485. SCSS
  486. end
  487. def test_blockless_directive_without_semicolon
  488. assert_equal "@foo \"bar\";\n", render('@foo "bar"')
  489. end
  490. def test_directive_with_lots_of_whitespace
  491. assert_equal "@foo \"bar\";\n", render('@foo "bar" ;')
  492. end
  493. def test_empty_blockless_directive
  494. assert_parses "@foo;"
  495. end
  496. def test_multiple_blockless_directives
  497. assert_parses <<SCSS
  498. @foo bar;
  499. @bar baz;
  500. SCSS
  501. end
  502. def test_empty_block_directive
  503. assert_parses "@foo {}"
  504. assert_equal "@foo {}\n", render(<<SCSS)
  505. @foo {
  506. }
  507. SCSS
  508. end
  509. def test_multiple_block_directives
  510. assert_parses <<SCSS
  511. @foo bar {
  512. a: b; }
  513. @bar baz {
  514. c: d; }
  515. SCSS
  516. end
  517. def test_block_directive_with_rule_and_property
  518. assert_parses <<SCSS
  519. @foo {
  520. rule {
  521. a: b; }
  522. a: b; }
  523. SCSS
  524. end
  525. def test_block_directive_with_semicolon
  526. assert_equal <<CSS, render(<<SCSS)
  527. @foo {
  528. a: b; }
  529. @bar {
  530. a: b; }
  531. CSS
  532. @foo {a:b};
  533. @bar {a:b};
  534. SCSS
  535. end
  536. def test_moz_document_directive
  537. assert_equal <<CSS, render(<<SCSS)
  538. @-moz-document url(http://www.w3.org/),
  539. url-prefix(http://www.w3.org/Style/),
  540. domain(mozilla.org),
  541. regexp("^https:.*") {
  542. .foo {
  543. a: b; } }
  544. CSS
  545. @-moz-document url(http://www.w3.org/),
  546. url-prefix(http://www.w3.org/Style/),
  547. domain(mozilla.org),
  548. regexp("^https:.*") {
  549. .foo {a: b}
  550. }
  551. SCSS
  552. end
  553. def test_supports
  554. assert_equal <<CSS, render(<<SCSS)
  555. @supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
  556. .foo {
  557. a: b; } }
  558. @supports (a: b) {
  559. .foo {
  560. a: b; } }
  561. CSS
  562. @supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
  563. .foo {
  564. a: b;
  565. }
  566. }
  567. @supports (a: b) {
  568. .foo {
  569. a: b;
  570. }
  571. }
  572. SCSS
  573. assert_equal <<CSS, render(<<SCSS)
  574. @-prefix-supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
  575. .foo {
  576. a: b; } }
  577. CSS
  578. @-prefix-supports (a: b) and (c: d) or (not (d: e)) and ((not (f: g)) or (not ((h: i) and (j: k)))) {
  579. .foo {
  580. a: b;
  581. }
  582. }
  583. SCSS
  584. end
  585. ## Selectors
  586. # Taken from http://dev.w3.org/csswg/selectors4/#overview
  587. def test_summarized_selectors
  588. assert_selector_parses('*')
  589. assert_selector_parses('E')
  590. assert_selector_parses('E:not(s)')
  591. assert_selector_parses('E:not(s1, s2)')
  592. assert_selector_parses('E:matches(s1, s2)')
  593. assert_selector_parses('E.warning')
  594. assert_selector_parses('E#myid')
  595. assert_selector_parses('E[foo]')
  596. assert_selector_parses('E[foo="bar"]')
  597. assert_selector_parses('E[foo="bar" i]')
  598. assert_selector_parses('E[foo~="bar"]')
  599. assert_selector_parses('E[foo^="bar"]')
  600. assert_selector_parses('E[foo$="bar"]')
  601. assert_selector_parses('E[foo*="bar"]')
  602. assert_selector_parses('E[foo|="en"]')
  603. assert_selector_parses('E:dir(ltr)')
  604. assert_selector_parses('E:lang(fr)')
  605. assert_selector_parses('E:lang(zh, *-hant)')
  606. assert_selector_parses('E:any-link')
  607. assert_selector_parses('E:link')
  608. assert_selector_parses('E:visited')
  609. assert_selector_parses('E:local-link')
  610. assert_selector_parses('E:local-link(0)')
  611. assert_selector_parses('E:target')
  612. assert_selector_parses('E:scope')
  613. assert_selector_parses('E:current')
  614. assert_selector_parses('E:current(s)')
  615. assert_selector_parses('E:past')
  616. assert_selector_parses('E:future')
  617. assert_selector_parses('E:active')
  618. assert_selector_parses('E:hover')
  619. assert_selector_parses('E:focus')
  620. assert_selector_parses('E:enabled')
  621. assert_selector_parses('E:disabled')
  622. assert_selector_parses('E:checked')
  623. assert_selector_parses('E:indeterminate')
  624. assert_selector_parses('E:default')
  625. assert_selector_parses('E:in-range')
  626. assert_selector_parses('E:out-of-range')
  627. assert_selector_parses('E:required')
  628. assert_selector_parses('E:optional')
  629. assert_selector_parses('E:read-only')
  630. assert_selector_parses('E:read-write')
  631. assert_selector_parses('E:root')
  632. assert_selector_parses('E:empty')
  633. assert_selector_parses('E:first-child')
  634. assert_selector_parses('E:nth-child(n)')
  635. assert_selector_parses('E:last-child')
  636. assert_selector_parses('E:nth-last-child(n)')
  637. assert_selector_parses('E:only-child')
  638. assert_selector_parses('E:first-of-type')
  639. assert_selector_parses('E:nth-of-type(n)')
  640. assert_selector_parses('E:last-of-type')
  641. assert_selector_parses('E:nth-last-of-type(n)')
  642. assert_selector_parses('E:only-of-type')
  643. assert_selector_parses('E:nth-match(n of selector)')
  644. assert_selector_parses('E:nth-last-match(n of selector)')
  645. assert_selector_parses('E:column(selector)')
  646. assert_selector_parses('E:nth-column(n)')
  647. assert_selector_parses('E:nth-last-column(n)')
  648. assert_selector_parses('E F')
  649. assert_selector_parses('E > F')
  650. assert_selector_parses('E + F')
  651. assert_selector_parses('E ~ F')
  652. assert_selector_parses('E /foo/ F')
  653. assert_selector_parses('E! > F')
  654. assert_selector_parses('E /ns|foo/ F')
  655. assert_selector_parses('E /*|foo/ F')
  656. end
  657. # Taken from http://dev.w3.org/csswg/selectors4/#overview, but without element
  658. # names.
  659. def test_summarized_selectors
  660. assert_selector_parses(':not(s)')
  661. assert_selector_parses(':not(s1, s2)')
  662. assert_selector_parses(':matches(s1, s2)')
  663. assert_selector_parses('.warning')
  664. assert_selector_parses('#myid')
  665. assert_selector_parses('[foo]')
  666. assert_selector_parses('[foo="bar"]')
  667. assert_selector_parses('[foo="bar" i]')
  668. assert_selector_parses('[foo~="bar"]')
  669. assert_selector_parses('[foo^="bar"]')
  670. assert_selector_parses('[foo$="bar"]')
  671. assert_selector_parses('[foo*="bar"]')
  672. assert_selector_parses('[foo|="en"]')
  673. assert_selector_parses(':dir(ltr)')
  674. assert_selector_parses(':lang(fr)')
  675. assert_selector_parses(':lang(zh, *-hant)')
  676. assert_selector_parses(':any-link')
  677. assert_selector_parses(':link')
  678. assert_selector_parses(':visited')
  679. assert_selector_parses(':local-link')
  680. assert_selector_parses(':local-link(0)')
  681. assert_selector_parses(':target')
  682. assert_selector_parses(':scope')
  683. assert_selector_parses(':current')
  684. assert_selector_parses(':current(s)')
  685. assert_selector_parses(':past')
  686. assert_selector_parses(':future')
  687. assert_selector_parses(':active')
  688. assert_selector_parses(':hover')
  689. assert_selector_parses(':focus')
  690. assert_selector_parses(':enabled')
  691. assert_selector_parses(':disabled')
  692. assert_selector_parses(':checked')
  693. assert_selector_parses(':indeterminate')
  694. assert_selector_parses(':default')
  695. assert_selector_parses(':in-range')
  696. assert_selector_parses(':out-of-range')
  697. assert_selector_parses(':required')
  698. assert_selector_parses(':optional')
  699. assert_selector_parses(':read-only')
  700. assert_selector_parses(':read-write')
  701. assert_selector_parses(':root')
  702. assert_selector_parses(':empty')
  703. assert_selector_parses(':first-child')
  704. assert_selector_parses(':nth-child(n)')
  705. assert_selector_parses(':last-child')
  706. assert_selector_parses(':nth-last-child(n)')
  707. assert_selector_parses(':only-child')
  708. assert_selector_parses(':first-of-type')
  709. assert_selector_parses(':nth-of-type(n)')
  710. assert_selector_parses(':last-of-type')
  711. assert_selector_parses(':nth-last-of-type(n)')
  712. assert_selector_parses(':only-of-type')
  713. assert_selector_parses(':nth-match(n of selector)')
  714. assert_selector_parses(':nth-last-match(n of selector)')
  715. assert_selector_parses(':column(selector)')
  716. assert_selector_parses(':nth-column(n)')
  717. assert_selector_parses(':nth-last-column(n)')
  718. end
  719. def test_attribute_selectors_with_identifiers
  720. assert_selector_parses('[foo~=bar]')
  721. assert_selector_parses('[foo^=bar]')
  722. assert_selector_parses('[foo$=bar]')
  723. assert_selector_parses('[foo*=bar]')
  724. assert_selector_parses('[foo|=en]')
  725. end
  726. def test_nth_selectors
  727. assert_selector_parses(':nth-child(-n)')
  728. assert_selector_parses(':nth-child(+n)')
  729. assert_selector_parses(':nth-child(even)')
  730. assert_selector_parses(':nth-child(odd)')
  731. assert_selector_parses(':nth-child(50)')
  732. assert_selector_parses(':nth-child(-50)')
  733. assert_selector_parses(':nth-child(+50)')
  734. assert_selector_parses(':nth-child(2n+3)')
  735. assert_selector_parses(':nth-child(2n-3)')
  736. assert_selector_parses(':nth-child(+2n-3)')
  737. assert_selector_parses(':nth-child(-2n+3)')
  738. assert_selector_parses(':nth-child(-2n+ 3)')
  739. assert_equal(<<CSS, render(<<SCSS))
  740. :nth-child(2n + 3) {
  741. a: b; }
  742. CSS
  743. :nth-child( 2n + 3 ) {
  744. a: b; }
  745. SCSS
  746. end
  747. def test_selectors_containing_selectors
  748. assert_selector_can_contain_selectors(':not(<sel>)')
  749. assert_selector_can_contain_selectors(':current(<sel>)')
  750. assert_selector_can_contain_selectors(':nth-match(n of <sel>)')
  751. assert_selector_can_contain_selectors(':nth-last-match(n of <sel>)')
  752. assert_selector_can_contain_selectors(':column(<sel>)')
  753. assert_selector_can_contain_selectors(':-moz-any(<sel>)')
  754. end
  755. def assert_selector_can_contain_selectors(sel)
  756. try = lambda {|subsel| assert_selector_parses(sel.gsub('<sel>', subsel))}
  757. try['foo|bar']
  758. try['*|bar']
  759. try['foo|*']
  760. try['*|*']
  761. try['#blah']
  762. try['.blah']
  763. try['[foo]']
  764. try['[foo^="bar"]']
  765. try['[baz|foo~="bar"]']
  766. try[':hover']
  767. try[':nth-child(2n + 3)']
  768. try['h1, h2, h3']
  769. try['#foo, bar, [baz]']
  770. # Not technically allowed for most selectors, but what the heck
  771. try[':not(#foo)']
  772. try['a#foo.bar']
  773. try['#foo .bar > baz']
  774. end
  775. def test_namespaced_selectors
  776. assert_selector_parses('foo|E')
  777. assert_selector_parses('*|E')
  778. assert_selector_parses('foo|*')
  779. assert_selector_parses('*|*')
  780. end
  781. def test_namespaced_attribute_selectors
  782. assert_selector_parses('[foo|bar=baz]')
  783. assert_selector_parses('[*|bar=baz]')
  784. assert_selector_parses('[foo|bar|=baz]')
  785. end
  786. def test_comma_selectors
  787. assert_selector_parses('E, F')
  788. assert_selector_parses('E F, G H')
  789. assert_selector_parses('E > F, G > H')
  790. end
  791. def test_selectors_with_newlines
  792. assert_selector_parses("E,\nF")
  793. assert_selector_parses("E\nF")
  794. assert_selector_parses("E, F\nG, H")
  795. end
  796. def test_expression_fallback_selectors
  797. assert_selector_parses('0%')
  798. assert_selector_parses('60%')
  799. assert_selector_parses('100%')
  800. assert_selector_parses('12px')
  801. assert_selector_parses('"foo"')
  802. end
  803. def test_functional_pseudo_selectors
  804. assert_selector_parses(':foo("bar")')
  805. assert_selector_parses(':foo(bar)')
  806. assert_selector_parses(':foo(12px)')
  807. assert_selector_parses(':foo(+)')
  808. assert_selector_parses(':foo(-)')
  809. assert_selector_parses(':foo(+"bar")')
  810. assert_selector_parses(':foo(-++--baz-"bar"12px)')
  811. end
  812. def test_selector_hacks
  813. assert_selector_parses('> E')
  814. assert_selector_parses('+ E')
  815. assert_selector_parses('~ E')
  816. assert_selector_parses('> > E')
  817. assert_equal <<CSS, render(<<SCSS)
  818. > > E {
  819. a: b; }
  820. CSS
  821. >> E {
  822. a: b; }
  823. SCSS
  824. assert_selector_parses('E*')
  825. assert_selector_parses('E*.foo')
  826. assert_selector_parses('E*:hover')
  827. end
  828. def test_spaceless_combo_selectors
  829. assert_equal "E > F {\n a: b; }\n", render("E>F { a: b;} ")
  830. assert_equal "E ~ F {\n a: b; }\n", render("E~F { a: b;} ")
  831. assert_equal "E + F {\n a: b; }\n", render("E+F { a: b;} ")
  832. end
  833. ## Errors
  834. def test_invalid_directives
  835. assert_not_parses("identifier", '@<err> import "foo";')
  836. assert_not_parses("identifier", '@<err>12 "foo";')
  837. end
  838. def test_invalid_classes
  839. assert_not_parses("class name", 'p.<err> foo {a: b}')
  840. assert_not_parses("class name", 'p.<err>1foo {a: b}')
  841. end
  842. def test_invalid_ids
  843. assert_not_parses("id name", 'p#<err> foo {a: b}')
  844. end
  845. def test_no_properties_at_toplevel
  846. assert_not_parses('pseudoclass or pseudoelement', 'a:<err> b;')
  847. end
  848. def test_no_scss_directives
  849. assert_parses('@import "foo.sass";')
  850. assert_parses <<SCSS
  851. @mixin foo {
  852. a: b; }
  853. SCSS
  854. end
  855. def test_no_variables
  856. assert_not_parses("selector or at-rule", "<err>$var = 12;")
  857. assert_not_parses('"}"', "foo { <err>!var = 12; }")
  858. end
  859. def test_no_parent_selectors
  860. assert_not_parses('"{"', "foo <err>&.bar {a: b}")
  861. end
  862. def test_no_selector_interpolation
  863. assert_not_parses('"{"', 'foo <err>#{"bar"}.baz {a: b}')
  864. end
  865. def test_no_prop_name_interpolation
  866. assert_not_parses('":"', 'foo {a<err>#{"bar"}baz: b}')
  867. end
  868. def test_no_prop_val_interpolation
  869. assert_not_parses('"}"', 'foo {a: b <err>#{"bar"} c}')
  870. end
  871. def test_no_string_interpolation
  872. assert_parses <<SCSS
  873. foo {
  874. a: "bang \#{1 + " bar "} bip"; }
  875. SCSS
  876. end
  877. def test_no_sass_script_values
  878. assert_not_parses('"}"', 'foo {a: b <err>* c}')
  879. end
  880. def test_no_nested_rules
  881. assert_not_parses('":"', 'foo {bar <err>{a: b}}')
  882. assert_not_parses('"}"', 'foo {<err>[bar=baz] {a: b}}')
  883. end
  884. def test_no_nested_properties
  885. assert_not_parses('expression (e.g. 1px, bold)', 'foo {bar: <err>{a: b}}')
  886. assert_not_parses('expression (e.g. 1px, bold)', 'foo {bar: bang <err>{a: b}}')
  887. end
  888. def test_no_nested_directives
  889. assert_not_parses('"}"', 'foo {<err>@bar {a: b}}')
  890. end
  891. def test_error_with_windows_newlines
  892. render <<SCSS
  893. foo {bar}\r
  894. baz {a: b}
  895. SCSS
  896. assert(false, "Expected syntax error")
  897. rescue Sass::SyntaxError => e
  898. assert_equal 'Invalid CSS after "foo {bar": expected ":", was "}"', e.message
  899. assert_equal 1, e.sass_line
  900. end
  901. ## Regressions
  902. def test_double_space_string
  903. assert_equal(<<CSS, render(<<SCSS))
  904. .a {
  905. content: " a"; }
  906. CSS
  907. .a {
  908. content: " a";
  909. }
  910. SCSS
  911. end
  912. def test_very_long_number_with_important_doesnt_take_forever
  913. assert_equal(<<CSS, render(<<SCSS))
  914. .foo {
  915. width: 97.916666666666666666666666666667% !important; }
  916. CSS
  917. .foo {
  918. width: 97.916666666666666666666666666667% !important;
  919. }
  920. SCSS
  921. end
  922. def test_selector_without_closing_bracket
  923. assert_not_parses('"]"', "foo[bar <err>{a: b}")
  924. end
  925. def test_closing_line_comment_end_with_compact_output
  926. assert_equal(<<CSS, render(<<SCSS, :style => :compact))
  927. /* foo */
  928. bar { baz: bang; }
  929. CSS
  930. /*
  931. * foo
  932. */
  933. bar {baz: bang}
  934. SCSS
  935. end
  936. def test_single_line_comment_within_multiline_comment
  937. assert_equal(<<CSS, render(<<SCSS))
  938. body {
  939. /*
  940. //comment here
  941. */ }
  942. CSS
  943. body {
  944. /*
  945. //comment here
  946. */
  947. }
  948. SCSS
  949. end
  950. def test_malformed_media
  951. render <<SCSS
  952. @media {
  953. margin: 0;
  954. }
  955. SCSS
  956. assert(false, "Expected syntax error")
  957. rescue Sass::SyntaxError => e
  958. assert_equal 'Invalid CSS after "@media ": expected media query (e.g. print, screen, print and screen), was "{"', e.message
  959. assert_equal 1, e.sass_line
  960. end
  961. private
  962. def assert_selector_parses(selector)
  963. assert_parses <<SCSS
  964. #{selector} {
  965. a: b; }
  966. SCSS
  967. end
  968. def render(scss, options = {})
  969. tree = Sass::SCSS::CssParser.new(scss, options[:filename]).parse
  970. tree.options = Sass::Engine::DEFAULT_OPTIONS.merge(options)
  971. tree.render
  972. end
  973. end