blob: e28627aebb5bcfa65be4c6e2520b366bb9464050 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2017 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.checks;
import static com.puppycrawl.tools.checkstyle.checks.AvoidEscapedUnicodeCharactersCheck.MSG_KEY;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
import org.junit.Test;
import org.powermock.reflect.Whitebox;
import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
public class AvoidEscapedUnicodeCharactersCheckTest extends AbstractModuleTestSupport {
// C0 (ASCII and derivatives)
// https://en.wiktionary.org/wiki/Appendix:Control_characters#C0_.28ASCII_and_derivatives.29
private static final int[] C0_CONTROL_CHARACTER_INDICES = {
0x0000,
0x0001,
0x0002,
0x0003,
0x0004,
0x0005,
0x0006,
0x0007,
0x0008,
0x0009,
0x000a,
0x000b,
0x000c,
0x000d,
0x000e,
0x000f,
0x0010,
0x0011,
0x0012,
0x0013,
0x0014,
0x0015,
0x0016,
0x0017,
0x0018,
0x0019,
0x001a,
0x001b,
0x001c,
0x001d,
0x001e,
0x001f,
};
// C1 set
// https://en.wiktionary.org/wiki/Appendix:Control_characters#C1_set
private static final int[] C1_CONTROL_CHARACTER_INDICES = {
0x0080,
0x0081,
0x0082,
0x0083,
0x0084,
0x0085,
0x0086,
0x0087,
0x0088,
0x0089,
0x008a,
0x008b,
0x008c,
0x008d,
0x008e,
0x008f,
0x0090,
0x0091,
0x0092,
0x0093,
0x0094,
0x0095,
0x0096,
0x0097,
0x0098,
0x0099,
0x009a,
0x009b,
0x009c,
0x009d,
0x009e,
0x009f,
};
// Other control characters which do not occur in the C0 or C1 sets
// https://en.wiktionary.org/wiki/Appendix:Control_characters#Unicode_control_characters
private static final int[] OTHER_CONTROL_CHARACTER_INDICES = {
0x00ad,
0x034f,
0x070f,
0x180e,
0x200b,
0x200c,
0x200d,
0x200e,
0x200f,
0x202a,
0x202b,
0x202c,
0x202d,
0x202e,
0x2060,
0x2061,
0x2062,
0x2063,
0x2064,
0x206a,
0x206b,
0x206c,
0x206d,
0x206e,
0x206f,
0xfeff,
0xfff9,
0xfffa,
0xfffb,
};
@Override
protected String getPackageLocation() {
return "com/puppycrawl/tools/checkstyle/checks/avoidescapedunicodecharacters";
}
@Test
public void testGetRequiredTokens() {
final AvoidEscapedUnicodeCharactersCheck checkObj =
new AvoidEscapedUnicodeCharactersCheck();
final int[] expected = {
TokenTypes.STRING_LITERAL,
TokenTypes.CHAR_LITERAL,
};
assertArrayEquals("Required tokens differ from expected",
expected, checkObj.getRequiredTokens());
}
@Test
public void testDefault() throws Exception {
final DefaultConfiguration checkConfig =
createModuleConfig(AvoidEscapedUnicodeCharactersCheck.class);
final String[] expected = {
"7: " + getCheckMessage(MSG_KEY),
"9: " + getCheckMessage(MSG_KEY),
"11: " + getCheckMessage(MSG_KEY),
"15: " + getCheckMessage(MSG_KEY),
"16: " + getCheckMessage(MSG_KEY),
"20: " + getCheckMessage(MSG_KEY),
"24: " + getCheckMessage(MSG_KEY),
"25: " + getCheckMessage(MSG_KEY),
"27: " + getCheckMessage(MSG_KEY),
"31: " + getCheckMessage(MSG_KEY),
"32: " + getCheckMessage(MSG_KEY),
"33: " + getCheckMessage(MSG_KEY),
"34: " + getCheckMessage(MSG_KEY),
"42: " + getCheckMessage(MSG_KEY),
"59: " + getCheckMessage(MSG_KEY),
"60: " + getCheckMessage(MSG_KEY),
"61: " + getCheckMessage(MSG_KEY),
"62: " + getCheckMessage(MSG_KEY),
"72: " + getCheckMessage(MSG_KEY),
"73: " + getCheckMessage(MSG_KEY),
"74: " + getCheckMessage(MSG_KEY),
"75: " + getCheckMessage(MSG_KEY),
"76: " + getCheckMessage(MSG_KEY),
"77: " + getCheckMessage(MSG_KEY),
"79: " + getCheckMessage(MSG_KEY),
"82: " + getCheckMessage(MSG_KEY),
"86: " + getCheckMessage(MSG_KEY),
"87: " + getCheckMessage(MSG_KEY),
"88: " + getCheckMessage(MSG_KEY),
"89: " + getCheckMessage(MSG_KEY),
"92: " + getCheckMessage(MSG_KEY),
"93: " + getCheckMessage(MSG_KEY),
"94: " + getCheckMessage(MSG_KEY),
"98: " + getCheckMessage(MSG_KEY),
"104: " + getCheckMessage(MSG_KEY),
};
verify(checkConfig, getPath("InputAvoidEscapedUnicodeCharacters.java"), expected);
}
@Test
public void testAllowEscapesForControlCharacterSet() throws Exception {
final DefaultConfiguration checkConfig =
createModuleConfig(AvoidEscapedUnicodeCharactersCheck.class);
checkConfig.addAttribute("allowEscapesForControlCharacters", "true");
final String[] expected = {
"7: " + getCheckMessage(MSG_KEY),
"9: " + getCheckMessage(MSG_KEY),
"11: " + getCheckMessage(MSG_KEY),
"15: " + getCheckMessage(MSG_KEY),
"16: " + getCheckMessage(MSG_KEY),
"24: " + getCheckMessage(MSG_KEY),
"25: " + getCheckMessage(MSG_KEY),
"31: " + getCheckMessage(MSG_KEY),
"32: " + getCheckMessage(MSG_KEY),
"33: " + getCheckMessage(MSG_KEY),
"34: " + getCheckMessage(MSG_KEY),
"42: " + getCheckMessage(MSG_KEY),
"59: " + getCheckMessage(MSG_KEY),
"60: " + getCheckMessage(MSG_KEY),
"61: " + getCheckMessage(MSG_KEY),
"62: " + getCheckMessage(MSG_KEY),
"73: " + getCheckMessage(MSG_KEY),
"74: " + getCheckMessage(MSG_KEY),
"75: " + getCheckMessage(MSG_KEY),
"76: " + getCheckMessage(MSG_KEY),
"77: " + getCheckMessage(MSG_KEY),
"79: " + getCheckMessage(MSG_KEY),
"82: " + getCheckMessage(MSG_KEY),
"86: " + getCheckMessage(MSG_KEY),
"87: " + getCheckMessage(MSG_KEY),
"88: " + getCheckMessage(MSG_KEY),
"89: " + getCheckMessage(MSG_KEY),
"92: " + getCheckMessage(MSG_KEY),
"94: " + getCheckMessage(MSG_KEY),
"98: " + getCheckMessage(MSG_KEY),
"104: " + getCheckMessage(MSG_KEY),
};
verify(checkConfig, getPath("InputAvoidEscapedUnicodeCharacters.java"), expected);
}
@Test
public void testAllowByTailComment() throws Exception {
final DefaultConfiguration checkConfig =
createModuleConfig(AvoidEscapedUnicodeCharactersCheck.class);
checkConfig.addAttribute("allowByTailComment", "true");
final String[] expected = {
"7: " + getCheckMessage(MSG_KEY),
"15: " + getCheckMessage(MSG_KEY),
"24: " + getCheckMessage(MSG_KEY),
"31: " + getCheckMessage(MSG_KEY),
"33: " + getCheckMessage(MSG_KEY),
"34: " + getCheckMessage(MSG_KEY),
"59: " + getCheckMessage(MSG_KEY),
"60: " + getCheckMessage(MSG_KEY),
"61: " + getCheckMessage(MSG_KEY),
"62: " + getCheckMessage(MSG_KEY),
"73: " + getCheckMessage(MSG_KEY),
"74: " + getCheckMessage(MSG_KEY),
"75: " + getCheckMessage(MSG_KEY),
"76: " + getCheckMessage(MSG_KEY),
"77: " + getCheckMessage(MSG_KEY),
"79: " + getCheckMessage(MSG_KEY),
"82: " + getCheckMessage(MSG_KEY),
"92: " + getCheckMessage(MSG_KEY),
"98: " + getCheckMessage(MSG_KEY),
"104: " + getCheckMessage(MSG_KEY),
};
verify(checkConfig, getPath("InputAvoidEscapedUnicodeCharacters.java"), expected);
}
@Test
public void testAllowAllCharactersEscaped() throws Exception {
final DefaultConfiguration checkConfig =
createModuleConfig(AvoidEscapedUnicodeCharactersCheck.class);
checkConfig.addAttribute("allowIfAllCharactersEscaped", "true");
final String[] expected = {
"7: " + getCheckMessage(MSG_KEY),
"9: " + getCheckMessage(MSG_KEY),
"11: " + getCheckMessage(MSG_KEY),
"15: " + getCheckMessage(MSG_KEY),
"16: " + getCheckMessage(MSG_KEY),
"31: " + getCheckMessage(MSG_KEY),
"32: " + getCheckMessage(MSG_KEY),
"33: " + getCheckMessage(MSG_KEY),
"42: " + getCheckMessage(MSG_KEY),
"86: " + getCheckMessage(MSG_KEY),
"87: " + getCheckMessage(MSG_KEY),
"88: " + getCheckMessage(MSG_KEY),
"89: " + getCheckMessage(MSG_KEY),
"98: " + getCheckMessage(MSG_KEY),
};
verify(checkConfig, getPath("InputAvoidEscapedUnicodeCharacters.java"), expected);
}
@Test
public void allowNonPrintableEscapes() throws Exception {
final DefaultConfiguration checkConfig =
createModuleConfig(AvoidEscapedUnicodeCharactersCheck.class);
checkConfig.addAttribute("allowNonPrintableEscapes", "true");
final String[] expected = {
"7: " + getCheckMessage(MSG_KEY),
"9: " + getCheckMessage(MSG_KEY),
"11: " + getCheckMessage(MSG_KEY),
"15: " + getCheckMessage(MSG_KEY),
"16: " + getCheckMessage(MSG_KEY),
"24: " + getCheckMessage(MSG_KEY),
"25: " + getCheckMessage(MSG_KEY),
"31: " + getCheckMessage(MSG_KEY),
"32: " + getCheckMessage(MSG_KEY),
"33: " + getCheckMessage(MSG_KEY),
"34: " + getCheckMessage(MSG_KEY),
"42: " + getCheckMessage(MSG_KEY),
"86: " + getCheckMessage(MSG_KEY),
"87: " + getCheckMessage(MSG_KEY),
"88: " + getCheckMessage(MSG_KEY),
"89: " + getCheckMessage(MSG_KEY),
"93: " + getCheckMessage(MSG_KEY),
"94: " + getCheckMessage(MSG_KEY),
"98: " + getCheckMessage(MSG_KEY),
"104: " + getCheckMessage(MSG_KEY),
};
verify(checkConfig, getPath("InputAvoidEscapedUnicodeCharacters.java"), expected);
}
@Test
public void testGetAcceptableTokens() {
final AvoidEscapedUnicodeCharactersCheck check = new AvoidEscapedUnicodeCharactersCheck();
final int[] actual = check.getAcceptableTokens();
final int[] expected = {TokenTypes.STRING_LITERAL, TokenTypes.CHAR_LITERAL };
assertArrayEquals("Acceptable tokens differ from expected",
expected, actual);
}
@Test
public void testAllowEscapesForControlCharacterSetForAllCharacters() throws Exception {
final DefaultConfiguration checkConfig =
createModuleConfig(AvoidEscapedUnicodeCharactersCheck.class);
checkConfig.addAttribute("allowEscapesForControlCharacters", "true");
final int indexOfStartLineInInputFile = 6;
final String message = getCheckMessage(MSG_KEY);
final String[] expected = IntStream.rangeClosed(0, 0xffff)
.parallel()
.filter(val -> !isControlCharacter(val))
.mapToObj(msg -> indexOfStartLineInInputFile + msg + ": " + message)
.toArray(String[]::new);
verify(checkConfig,
getPath("InputAvoidEscapedUnicodeCharactersAllEscapedUnicodeCharacters.java"),
expected);
}
/**
* Method countMatches is used only inside isOnlyUnicodeValidChars method, and when
* pitest mutates 316:13 countMatches++ to countMatches-- it makes no difference for
* isOnlyUnicodeValidChars method as it applies countMatches to both cases in comparison.
* It is possible to kill mutation in countMatches method by changing code in
* isOnlyUnicodeValidChars, but it creates new uncoverable mutations and makes code harder
* to understand.
*
* @throws Exception when code tested throws some exception
*/
@Test
public void testCountMatches() throws Exception {
final Method countMatches = Whitebox.getMethod(AvoidEscapedUnicodeCharactersCheck.class,
"countMatches", Pattern.class, String.class);
final AvoidEscapedUnicodeCharactersCheck check = new AvoidEscapedUnicodeCharactersCheck();
final int actual = (int) countMatches.invoke(check,
Pattern.compile("\\\\u[a-fA-F0-9]{4}"), "\\u1234");
assertEquals("Unexpected matches count", 1, actual);
}
private static boolean isControlCharacter(final int character) {
return Arrays.binarySearch(C0_CONTROL_CHARACTER_INDICES, character) >= 0
|| Arrays.binarySearch(C1_CONTROL_CHARACTER_INDICES, character) >= 0
|| Arrays.binarySearch(OTHER_CONTROL_CHARACTER_INDICES, character) >= 0;
}
}