@@ -3,6 +3,7 @@ package scala.xml
33import org .junit .Test
44import org .junit .Assert .assertTrue
55import org .junit .Assert .assertEquals
6+ import org .junit .Assert .assertNotEquals
67
78class UtilityTest {
89
@@ -63,4 +64,133 @@ class UtilityTest {
6364 assertEquals(" <node><!-- comment --></node>" , Utility .serialize(x, stripComments = false ).toString)
6465 }
6566
67+ val printableAscii : Seq [Char ] = {
68+ (' ' to '/' ) ++ // Punctuation
69+ ('0' to '9' ) ++ // Digits
70+ (':' to '@' ) ++ // Punctuation (cont.)
71+ ('A' to 'Z' ) ++ // Uppercase
72+ ('[' to '`' ) ++ // Punctuation (cont.)
73+ ('a' to 'z' ) ++ // Lowercase
74+ ('{' to '~' ) // Punctuation (cont.)
75+ }
76+
77+ val escapedChars : Seq [Char ] =
78+ Utility .Escapes .escMap.keys.toSeq
79+
80+ @ Test
81+ def escapePrintablesTest : Unit = {
82+ for {
83+ char <- (printableAscii.diff(escapedChars))
84+ } yield {
85+ assertEquals(char.toString, Utility .escape(char.toString))
86+ }
87+ }
88+
89+ @ Test
90+ def escapeEscapablesTest : Unit = {
91+ for {
92+ char <- escapedChars
93+ } yield {
94+ assertNotEquals(char.toString, Utility .escape(char.toString))
95+ }
96+ }
97+
98+ @ Test
99+ def escapeAsciiControlCharsTest : Unit = {
100+
101+ /* Escapes that Scala (Java) doesn't support.
102+ * \u0007 -> \a (bell)
103+ * \u001B -> \e (escape)
104+ * \u000B -> \v (vertical tab)
105+ * \u007F -> DEL (delete)
106+ */
107+ val input = " \u0007\b\u001B\f\n\r\t\u000B\u007F "
108+
109+ val expect = " \n\r\t\u007F "
110+
111+ val result = Utility .escape(input)
112+
113+ assertEquals(printfc(expect), printfc(result)) // Pretty,
114+ assertEquals(expect, result) // but verify.
115+ }
116+
117+ @ Test
118+ def escapeUnicodeExtendedControlCodesTest : Unit = {
119+ for {
120+ char <- ('\u0080 ' to '\u009f ' ) // Extended control codes (C1)
121+ } yield {
122+ assertEquals(char.toString, Utility .escape(char.toString))
123+ }
124+ }
125+
126+ @ Test
127+ def escapeUnicodeTwoBytesTest : Unit = {
128+ for {
129+ char <- ('\u00A0 ' to '\u07FF ' ) // Two bytes (cont.)
130+ } yield {
131+ assertEquals(char.toString, Utility .escape(char.toString))
132+ }
133+ }
134+
135+ @ Test
136+ def escapeUnicodeThreeBytesTest : Unit = {
137+ for {
138+ char <- ('\u0800 ' to '\uFFFF ' ) // Three bytes
139+ } yield {
140+ assertEquals(char.toString, Utility .escape(char.toString))
141+ }
142+ }
143+
144+ /**
145+ * Human-readable character printing
146+ *
147+ * Think of `od -c` of unix od(1) command.
148+ *
149+ * Or think of `printf("%c", i)` in C, but a little better.
150+ */
151+ def printfc (str : String ) = {
152+ str.map(prettyChar).mkString
153+ }
154+
155+ /**
156+ * Visual representation of characters that enhances output of
157+ * failed test assertions.
158+ */
159+ val prettyChar : Map [Char ,String ] = Map (
160+ '\u0000 ' -> " \\ 0" , // Null
161+ '\u0001 ' -> " ^A" , // Start of header
162+ '\u0002 ' -> " ^B" , // Start of text
163+ '\u0003 ' -> " ^C" , // End of text
164+ '\u0004 ' -> " ^D" , // End of transmission
165+ '\u0005 ' -> " ^E" , // Enquiry
166+ '\u0006 ' -> " ^F" , // Acknowledgment
167+ '\u0007 ' -> " \\ a" , // Bell (^G)
168+ '\b ' -> " \\ b" , // Backspace (^H)
169+ '\t ' -> " \\ t" , // Tab (^I)
170+ '\n ' -> " \\ n" , // Newline (^J)
171+ '\u000B ' -> " \\ v" , // Vertical tab (^K)
172+ '\f ' -> " \\ f" , // Form feed (^L)
173+ '\r ' -> " \\ r" , // Carriage return (^M)
174+ '\u000E ' -> " ^N" , // Shift out
175+ '\u000F ' -> " ^O" , // Shift in
176+ '\u0010 ' -> " ^P" , // Data link escape
177+ '\u0011 ' -> " ^Q" , // DC1 (XON)
178+ '\u0012 ' -> " ^R" , // DC2
179+ '\u0013 ' -> " ^S" , // DC3 (XOFF)
180+ '\u0014 ' -> " ^T" , // DC4
181+ '\u0015 ' -> " ^U" , // Negative acknowledgment
182+ '\u0016 ' -> " ^V" , // Synchronous idle
183+ '\u0017 ' -> " ^W" , // End of transmission block
184+ '\u0018 ' -> " ^X" , // Cancel
185+ '\u0019 ' -> " ^Y" , // End of medium
186+ '\u001A ' -> " ^Z" , // Substitute
187+ '\u001B ' -> " \\ e" , // Escape
188+ '\u001C ' -> " ^\\ " , // File separator
189+ '\u001D ' -> " ^]" , // Group separator
190+ '\u001E ' -> " ^^" , // Record separator
191+ '\u001F ' -> " ^_" , // Unit separator
192+ '\u007F ' -> " ^?" // Delete
193+ ).toMap.withDefault {
194+ key : Char => key.toString
195+ }
66196}
0 commit comments