@@ -3,6 +3,7 @@ package scala.xml
3
3
import org .junit .Test
4
4
import org .junit .Assert .assertTrue
5
5
import org .junit .Assert .assertEquals
6
+ import org .junit .Assert .assertNotEquals
6
7
7
8
class UtilityTest {
8
9
@@ -63,4 +64,133 @@ class UtilityTest {
63
64
assertEquals(" <node><!-- comment --></node>" , Utility .serialize(x, stripComments = false ).toString)
64
65
}
65
66
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
+ }
66
196
}
0 commit comments