|
| 1 | +defmodule Floki.CSSEscapeTest do |
| 2 | + use ExUnit.Case, async: true |
| 3 | + |
| 4 | + doctest Floki.CSSEscape |
| 5 | + |
| 6 | + test "null character" do |
| 7 | + assert Floki.CSSEscape.escape(<<0>>) == <<0xFFFD::utf8>> |
| 8 | + assert Floki.CSSEscape.escape("a\u0000") == "a\ufffd" |
| 9 | + assert Floki.CSSEscape.escape("\u0000b") == "\ufffdb" |
| 10 | + assert Floki.CSSEscape.escape("a\u0000b") == "a\ufffdb" |
| 11 | + end |
| 12 | + |
| 13 | + test "replacement character" do |
| 14 | + assert Floki.CSSEscape.escape(<<0xFFFD::utf8>>) == <<0xFFFD::utf8>> |
| 15 | + assert Floki.CSSEscape.escape("a\ufffd") == "a\ufffd" |
| 16 | + assert Floki.CSSEscape.escape("\ufffdb") == "\ufffdb" |
| 17 | + assert Floki.CSSEscape.escape("a\ufffdb") == "a\ufffdb" |
| 18 | + end |
| 19 | + |
| 20 | + test "invalid input" do |
| 21 | + assert_raise ArgumentError, fn -> Floki.CSSEscape.escape(nil) end |
| 22 | + end |
| 23 | + |
| 24 | + test "control characters" do |
| 25 | + assert Floki.CSSEscape.escape(<<0x01, 0x02, 0x1E, 0x1F>>) == "\\1 \\2 \\1E \\1F " |
| 26 | + end |
| 27 | + |
| 28 | + test "leading digit" do |
| 29 | + for {digit, expected} <- Enum.zip(0..9, ~w(30 31 32 33 34 35 36 37 38 39)) do |
| 30 | + assert Floki.CSSEscape.escape("#{digit}a") == "\\#{expected} a" |
| 31 | + end |
| 32 | + end |
| 33 | + |
| 34 | + test "non-leading digit" do |
| 35 | + for digit <- 0..9 do |
| 36 | + assert Floki.CSSEscape.escape("a#{digit}b") == "a#{digit}b" |
| 37 | + end |
| 38 | + end |
| 39 | + |
| 40 | + test "leading hyphen and digit" do |
| 41 | + for {digit, expected} <- Enum.zip(0..9, ~w(30 31 32 33 34 35 36 37 38 39)) do |
| 42 | + assert Floki.CSSEscape.escape("-#{digit}a") == "-\\#{expected} a" |
| 43 | + end |
| 44 | + end |
| 45 | + |
| 46 | + test "hyphens" do |
| 47 | + assert Floki.CSSEscape.escape("-") == "\\-" |
| 48 | + assert Floki.CSSEscape.escape("-a") == "-a" |
| 49 | + assert Floki.CSSEscape.escape("--") == "--" |
| 50 | + assert Floki.CSSEscape.escape("--a") == "--a" |
| 51 | + end |
| 52 | + |
| 53 | + test "non-ASCII and special characters" do |
| 54 | + assert Floki.CSSEscape.escape("🤷🏻♂️-_©") == "🤷🏻♂️-_©" |
| 55 | + |
| 56 | + assert Floki.CSSEscape.escape( |
| 57 | + <<0x7F, |
| 58 | + "\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f">> |
| 59 | + ) == |
| 60 | + "\\7F \u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f" |
| 61 | + |
| 62 | + assert Floki.CSSEscape.escape("\u00a0\u00a1\u00a2") == "\u00a0\u00a1\u00a2" |
| 63 | + end |
| 64 | + |
| 65 | + test "alphanumeric characters" do |
| 66 | + assert Floki.CSSEscape.escape("a0123456789b") == "a0123456789b" |
| 67 | + assert Floki.CSSEscape.escape("abcdefghijklmnopqrstuvwxyz") == "abcdefghijklmnopqrstuvwxyz" |
| 68 | + assert Floki.CSSEscape.escape("ABCDEFGHIJKLMNOPQRSTUVWXYZ") == "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 69 | + end |
| 70 | + |
| 71 | + test "space and exclamation mark" do |
| 72 | + assert Floki.CSSEscape.escape(<<0x20, 0x21, 0x78, 0x79>>) == "\\ \\!xy" |
| 73 | + end |
| 74 | + |
| 75 | + test "unicode characters" do |
| 76 | + # astral symbol (U+1D306 TETRAGRAM FOR CENTRE) |
| 77 | + assert Floki.CSSEscape.escape(<<0x1D306::utf8>>) == <<0x1D306::utf8>> |
| 78 | + end |
| 79 | +end |
0 commit comments