1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using System.Text.Encodings.Web;
9 using System.Text.Unicode;
10 using Xunit;
11 
12 namespace Microsoft.Framework.WebEncoders
13 {
14     public static class TextEncoderSettingsExtensions
15     {
IsCharacterAllowed(this TextEncoderSettings settings, char character)16         public static bool IsCharacterAllowed(this TextEncoderSettings settings, char character)
17         {
18             var bitmap = settings.GetAllowedCharacters();
19             return bitmap.IsCharacterAllowed(character);
20         }
21     }
22 
23     public class TextEncoderSettingsTests
24     {
25         [Fact]
Ctor_Parameterless_CreatesEmptyFilter()26         public void Ctor_Parameterless_CreatesEmptyFilter()
27         {
28             var filter = new TextEncoderSettings();
29             Assert.Equal(0, filter.GetAllowedCodePoints().Count());
30         }
31 
32         [Fact]
Ctor_OtherTextEncoderSettingsAsInterface()33         public void Ctor_OtherTextEncoderSettingsAsInterface()
34         {
35             // Arrange
36             var originalFilter = new OddTextEncoderSettings();
37 
38             // Act
39             var newFilter = new TextEncoderSettings(originalFilter);
40 
41             // Assert
42             for (int i = 0; i <= Char.MaxValue; i++)
43             {
44                 Assert.Equal((i % 2) == 1, newFilter.IsCharacterAllowed((char)i));
45             }
46         }
47 
48         [Fact]
Ctor_OtherTextEncoderSettingsAsConcreteType_Clones()49         public void Ctor_OtherTextEncoderSettingsAsConcreteType_Clones()
50         {
51             // Arrange
52             var originalFilter = new TextEncoderSettings();
53             originalFilter.AllowCharacter('x');
54 
55             // Act
56             var newFilter = new TextEncoderSettings(originalFilter);
57             newFilter.AllowCharacter('y');
58 
59             // Assert
60             Assert.True(originalFilter.IsCharacterAllowed('x'));
61             Assert.False(originalFilter.IsCharacterAllowed('y'));
62             Assert.True(newFilter.IsCharacterAllowed('x'));
63             Assert.True(newFilter.IsCharacterAllowed('y'));
64         }
65 
66         [Fact]
Ctor_UnicodeRanges()67         public void Ctor_UnicodeRanges()
68         {
69             // Act
70             var filter = new TextEncoderSettings(UnicodeRanges.LatinExtendedA, UnicodeRanges.LatinExtendedC);
71 
72             // Assert
73             for (int i = 0; i < 0x0100; i++)
74             {
75                 Assert.False(filter.IsCharacterAllowed((char)i));
76             }
77             for (int i = 0x0100; i <= 0x017F; i++)
78             {
79                 Assert.True(filter.IsCharacterAllowed((char)i));
80             }
81             for (int i = 0x0180; i < 0x2C60; i++)
82             {
83                 Assert.False(filter.IsCharacterAllowed((char)i));
84             }
85             for (int i = 0x2C60; i <= 0x2C7F; i++)
86             {
87                 Assert.True(filter.IsCharacterAllowed((char)i));
88             }
89             for (int i = 0x2C80; i <= Char.MaxValue; i++)
90             {
91                 Assert.False(filter.IsCharacterAllowed((char)i));
92             }
93         }
94 
95         [Fact]
Ctor_Null_UnicodeRanges()96         public void Ctor_Null_UnicodeRanges()
97         {
98             Assert.Throws<ArgumentNullException>("allowedRanges", () => new TextEncoderSettings(default(UnicodeRange[])));
99         }
100 
101 
102         [Fact]
Ctor_Null_TextEncoderSettings()103         public void Ctor_Null_TextEncoderSettings()
104         {
105             Assert.Throws<ArgumentNullException>("other", () => new TextEncoderSettings(default(TextEncoderSettings)));
106         }
107 
108         [Fact]
AllowChar()109         public void AllowChar()
110         {
111             // Arrange
112             var filter = new TextEncoderSettings();
113             filter.AllowCharacter('\u0100');
114 
115             // Assert
116             Assert.True(filter.IsCharacterAllowed('\u0100'));
117             Assert.False(filter.IsCharacterAllowed('\u0101'));
118         }
119 
120         [Fact]
AllowChars_Array()121         public void AllowChars_Array()
122         {
123             // Arrange
124             var filter = new TextEncoderSettings();
125             filter.AllowCharacters('\u0100', '\u0102');
126 
127             // Assert
128             Assert.True(filter.IsCharacterAllowed('\u0100'));
129             Assert.False(filter.IsCharacterAllowed('\u0101'));
130             Assert.True(filter.IsCharacterAllowed('\u0102'));
131             Assert.False(filter.IsCharacterAllowed('\u0103'));
132         }
133 
134         [Fact]
AllowChars_String()135         public void AllowChars_String()
136         {
137             // Arrange
138             var filter = new TextEncoderSettings();
139             filter.AllowCharacters('\u0100', '\u0102');
140 
141             // Assert
142             Assert.True(filter.IsCharacterAllowed('\u0100'));
143             Assert.False(filter.IsCharacterAllowed('\u0101'));
144             Assert.True(filter.IsCharacterAllowed('\u0102'));
145             Assert.False(filter.IsCharacterAllowed('\u0103'));
146         }
147 
148 
149         [Fact]
AllowChars_Null()150         public void AllowChars_Null()
151         {
152             TextEncoderSettings filter = new TextEncoderSettings();
153             Assert.Throws<ArgumentNullException>("characters", () => filter.AllowCharacters(null));
154         }
155 
156         [Fact]
AllowFilter()157         public void AllowFilter()
158         {
159             // Arrange
160             var filter = new TextEncoderSettings(UnicodeRanges.BasicLatin);
161             filter.AllowCodePoints(new OddTextEncoderSettings().GetAllowedCodePoints());
162 
163             // Assert
164             for (int i = 0; i <= 0x007F; i++)
165             {
166                 Assert.True(filter.IsCharacterAllowed((char)i));
167             }
168             for (int i = 0x0080; i <= Char.MaxValue; i++)
169             {
170                 Assert.Equal((i % 2) == 1, filter.IsCharacterAllowed((char)i));
171             }
172         }
173 
174         [Fact]
AllowFilter_NullCodePoints()175         public void AllowFilter_NullCodePoints()
176         {
177             TextEncoderSettings filter = new TextEncoderSettings(UnicodeRanges.BasicLatin);
178             Assert.Throws<ArgumentNullException>("codePoints", () => filter.AllowCodePoints(null));
179         }
180 
181         [Fact]
AllowFilter_NonBMP()182         public void AllowFilter_NonBMP()
183         {
184             TextEncoderSettings filter = new TextEncoderSettings();
185             filter.AllowCodePoints(Enumerable.Range(0x10000, 20));
186             Assert.Empty(filter.GetAllowedCodePoints());
187         }
188 
189         [Fact]
AllowRange()190         public void AllowRange()
191         {
192             // Arrange
193             var filter = new TextEncoderSettings();
194             filter.AllowRange(UnicodeRanges.LatinExtendedA);
195 
196             // Assert
197             for (int i = 0; i < 0x0100; i++)
198             {
199                 Assert.False(filter.IsCharacterAllowed((char)i));
200             }
201             for (int i = 0x0100; i <= 0x017F; i++)
202             {
203                 Assert.True(filter.IsCharacterAllowed((char)i));
204             }
205             for (int i = 0x0180; i <= Char.MaxValue; i++)
206             {
207                 Assert.False(filter.IsCharacterAllowed((char)i));
208             }
209         }
210 
211         [Fact]
AllowRange_NullRange()212         public void AllowRange_NullRange()
213         {
214             TextEncoderSettings filter = new TextEncoderSettings();
215             Assert.Throws<ArgumentNullException>("range", () => filter.AllowRange(null));
216         }
217 
218         [Fact]
AllowRanges()219         public void AllowRanges()
220         {
221             // Arrange
222             var filter = new TextEncoderSettings();
223             filter.AllowRanges(UnicodeRanges.LatinExtendedA, UnicodeRanges.LatinExtendedC);
224 
225             // Assert
226             for (int i = 0; i < 0x0100; i++)
227             {
228                 Assert.False(filter.IsCharacterAllowed((char)i));
229             }
230             for (int i = 0x0100; i <= 0x017F; i++)
231             {
232                 Assert.True(filter.IsCharacterAllowed((char)i));
233             }
234             for (int i = 0x0180; i < 0x2C60; i++)
235             {
236                 Assert.False(filter.IsCharacterAllowed((char)i));
237             }
238             for (int i = 0x2C60; i <= 0x2C7F; i++)
239             {
240                 Assert.True(filter.IsCharacterAllowed((char)i));
241             }
242             for (int i = 0x2C80; i <= Char.MaxValue; i++)
243             {
244                 Assert.False(filter.IsCharacterAllowed((char)i));
245             }
246         }
247 
248         [Fact]
AllowRanges_NullRange()249         public void AllowRanges_NullRange()
250         {
251             TextEncoderSettings filter = new TextEncoderSettings();
252             Assert.Throws<ArgumentNullException>("ranges", () => filter.AllowRanges(null));
253         }
254 
255         [Fact]
Clear()256         public void Clear()
257         {
258             // Arrange
259             var filter = new TextEncoderSettings();
260             for (int i = 1; i <= Char.MaxValue; i++)
261             {
262                 filter.AllowCharacter((char)i);
263             }
264 
265             // Act
266             filter.Clear();
267 
268             // Assert
269             for (int i = 0; i <= Char.MaxValue; i++)
270             {
271                 Assert.False(filter.IsCharacterAllowed((char)i));
272             }
273         }
274 
275         [Fact]
ForbidChar()276         public void ForbidChar()
277         {
278             // Arrange
279             var filter = new TextEncoderSettings(UnicodeRanges.BasicLatin);
280             filter.ForbidCharacter('x');
281 
282             // Assert
283             Assert.True(filter.IsCharacterAllowed('w'));
284             Assert.False(filter.IsCharacterAllowed('x'));
285             Assert.True(filter.IsCharacterAllowed('y'));
286             Assert.True(filter.IsCharacterAllowed('z'));
287         }
288 
289         [Fact]
ForbidChars_Array()290         public void ForbidChars_Array()
291         {
292             // Arrange
293             var filter = new TextEncoderSettings(UnicodeRanges.BasicLatin);
294             filter.ForbidCharacters('x', 'z');
295 
296             // Assert
297             Assert.True(filter.IsCharacterAllowed('w'));
298             Assert.False(filter.IsCharacterAllowed('x'));
299             Assert.True(filter.IsCharacterAllowed('y'));
300             Assert.False(filter.IsCharacterAllowed('z'));
301         }
302 
303         [Fact]
ForbidChars_String()304         public void ForbidChars_String()
305         {
306             // Arrange
307             var filter = new TextEncoderSettings(UnicodeRanges.BasicLatin);
308             filter.ForbidCharacters('x', 'z');
309 
310             // Assert
311             Assert.True(filter.IsCharacterAllowed('w'));
312             Assert.False(filter.IsCharacterAllowed('x'));
313             Assert.True(filter.IsCharacterAllowed('y'));
314             Assert.False(filter.IsCharacterAllowed('z'));
315         }
316 
317 
318         [Fact]
ForbidChars_Null()319         public void ForbidChars_Null()
320         {
321             TextEncoderSettings filter = new TextEncoderSettings(UnicodeRanges.BasicLatin);
322             Assert.Throws<ArgumentNullException>("characters", () => filter.ForbidCharacters(null));
323         }
324 
325         [Fact]
ForbidRange()326         public void ForbidRange()
327         {
328             // Arrange
329             var filter = new TextEncoderSettings(new OddTextEncoderSettings());
330             filter.ForbidRange(UnicodeRanges.Specials);
331 
332             // Assert
333             for (int i = 0; i <= 0xFFEF; i++)
334             {
335                 Assert.Equal((i % 2) == 1, filter.IsCharacterAllowed((char)i));
336             }
337             for (int i = 0xFFF0; i <= Char.MaxValue; i++)
338             {
339                 Assert.False(filter.IsCharacterAllowed((char)i));
340             }
341         }
342 
343         [Fact]
ForbidRange_Null()344         public void ForbidRange_Null()
345         {
346             TextEncoderSettings filter = new TextEncoderSettings();
347             Assert.Throws<ArgumentNullException>("range", () => filter.ForbidRange(null));
348         }
349 
350         [Fact]
ForbidRanges()351         public void ForbidRanges()
352         {
353             // Arrange
354             var filter = new TextEncoderSettings(new OddTextEncoderSettings());
355             filter.ForbidRanges(UnicodeRanges.BasicLatin, UnicodeRanges.Specials);
356 
357             // Assert
358             for (int i = 0; i <= 0x007F; i++)
359             {
360                 Assert.False(filter.IsCharacterAllowed((char)i));
361             }
362             for (int i = 0x0080; i <= 0xFFEF; i++)
363             {
364                 Assert.Equal((i % 2) == 1, filter.IsCharacterAllowed((char)i));
365             }
366             for (int i = 0xFFF0; i <= Char.MaxValue; i++)
367             {
368                 Assert.False(filter.IsCharacterAllowed((char)i));
369             }
370         }
371 
372         [Fact]
ForbidRanges_Null()373         public void ForbidRanges_Null()
374         {
375             TextEncoderSettings filter = new TextEncoderSettings(new OddTextEncoderSettings());
376             Assert.Throws<ArgumentNullException>("ranges", () => filter.ForbidRanges(null));
377         }
378 
379         [Fact]
GetAllowedCodePoints()380         public void GetAllowedCodePoints()
381         {
382             // Arrange
383             var expected = Enumerable.Range(UnicodeRanges.BasicLatin.FirstCodePoint, UnicodeRanges.BasicLatin.Length)
384                 .Concat(Enumerable.Range(UnicodeRanges.Specials.FirstCodePoint, UnicodeRanges.Specials.Length))
385                 .Except(new int[] { 'x' })
386                 .OrderBy(i => i)
387                 .ToArray();
388 
389             var filter = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Specials);
390             filter.ForbidCharacter('x');
391 
392             // Act
393             var retVal = filter.GetAllowedCodePoints().OrderBy(i => i).ToArray();
394 
395             // Assert
396             Assert.Equal<int>(expected, retVal);
397         }
398 
399         // a code point filter which allows only odd code points through
400         private sealed class OddTextEncoderSettings : TextEncoderSettings
401         {
GetAllowedCodePoints()402             public override IEnumerable<int> GetAllowedCodePoints()
403             {
404                 for (int i = 1; i <= Char.MaxValue; i += 2)
405                 {
406                     yield return i;
407                 }
408             }
409         }
410     }
411 }
412