diff --git a/src/main/java/com/cflint/CFLint.java b/src/main/java/com/cflint/CFLint.java index b6956d325..ec4b4d2e0 100644 --- a/src/main/java/com/cflint/CFLint.java +++ b/src/main/java/com/cflint/CFLint.java @@ -425,12 +425,19 @@ public String stripLineComments(final String cfscript) { private void process(final CFScriptStatement expression, final String filename, final Element elem, final CFIdentifier functionName) { - process(expression,filename,elem,functionName.Decompile(0)); + process(expression,filename,elem,functionName.getName()); } private void process(final CFScriptStatement expression, final String filename, final Element elem, - final String functionName) { + String functionName) { final Context context = new Context(filename, elem, functionName, inAssignment, handler); + context.setInComponent(inComponent); + + if (expression instanceof CFFuncDeclStatement) { + final CFFuncDeclStatement function = (CFFuncDeclStatement) expression; + functionName = function.getName().getName(); + context.setFunctionName(functionName); + } for (final CFLintScanner plugin : extensions) { try{ diff --git a/src/main/java/com/cflint/plugins/Context.java b/src/main/java/com/cflint/plugins/Context.java index 4ff4fac35..358f6783e 100644 --- a/src/main/java/com/cflint/plugins/Context.java +++ b/src/main/java/com/cflint/plugins/Context.java @@ -147,7 +147,7 @@ public int startLine() { if(element != null && element.getSource() !=null) return element.getSource().getRow(element.getBegin()); else - return 1; + return 1; // not zero } protected String componentFromFile(String filename) { diff --git a/src/main/java/com/cflint/plugins/core/MethodNameChecker.java b/src/main/java/com/cflint/plugins/core/MethodNameChecker.java new file mode 100644 index 000000000..ef1a88fe4 --- /dev/null +++ b/src/main/java/com/cflint/plugins/core/MethodNameChecker.java @@ -0,0 +1,106 @@ +package com.cflint.plugins.core; + +import ro.fortsoft.pf4j.Extension; +import net.htmlparser.jericho.Element; +import net.htmlparser.jericho.Attributes; +import cfml.parsing.cfscript.script.CFScriptStatement; +import cfml.parsing.cfscript.script.CFFuncDeclStatement; + + +import com.cflint.BugInfo; +import com.cflint.BugList; +import com.cflint.plugins.CFLintScannerAdapter; +import com.cflint.plugins.Context; + +import java.util.regex.Pattern; + +@Extension +public class MethodNameChecker extends CFLintScannerAdapter { + final String severity = "INFO"; + + @Override + public void expression(final CFScriptStatement expression, final Context context, final BugList bugs) { + if (expression instanceof CFFuncDeclStatement) { + final CFFuncDeclStatement method = (CFFuncDeclStatement) expression; + int lineNo = method.getLine() + context.startLine() - 1; + checkNameForBugs(context.getFunctionName(), context.getFilename(), lineNo, bugs); + } + } + + @Override + public void element(final Element element, final Context context, final BugList bugs) { + if (element.getName().equals("cffunction")) { + int lineNo = element.getSource().getRow(element.getBegin()); + checkNameForBugs(context.getFunctionName(), context.getFilename(), lineNo, bugs); + } + } + + public void checkNameForBugs(String method, String filename, int line, BugList bugs) { + int minMethodLength = ValidName.MIN_METHOD_LENGTH; + int maxMethodLength = ValidName.MAX_METHOD_LENGTH; + int maxMethodWords = ValidName.MAX_METHOD_WORDS; + + if (getParameter("MinLength") != null) { + try { + minMethodLength = Integer.parseInt(getParameter("MinLength")); + } catch(Exception e) {} + } + + if (getParameter("MaxLength") != null) { + try { + maxMethodLength = Integer.parseInt(getParameter("MaxLength")); + } catch(Exception e) {} + } + + if (getParameter("MaxWords") != null) { + try { + maxMethodWords = Integer.parseInt(getParameter("MaxWords")); + } catch(Exception e) {} + } + + ValidName name = new ValidName(minMethodLength, maxMethodLength, maxMethodWords); + + if (name.isInvalid(method)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("METHOD_INVALID_NAME") + .setSeverity(severity).setFilename(filename) + .setMessage("Method name " + method + " is not a valid name. Please use CamelCase or underscores.") + .build()); + } + if (name.isUpperCase(method)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("METHOD_ALLCAPS_NAME") + .setSeverity(severity).setFilename(filename) + .setMessage("Method name " + method + " should not be upper case.") + .build()); + } + if (name.tooShort(method)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("METHOD_TOO_SHORT") + .setSeverity(severity).setFilename(filename) + .setMessage("Method name " + method + " should be longer than " + minMethodLength + " characters.") + .build()); + } + if (name.tooLong(method)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("METHOD_TOO_LONG") + .setSeverity(severity).setFilename(filename) + .setMessage("Method name " + method + " should be shorter than " + maxMethodLength + " characters.") + .build()); + } + if (!name.isUpperCase(method) && name.tooWordy(method)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("METHOD_TOO_WORDY") + .setSeverity(severity).setFilename(filename) + .setMessage("Method name " + method + " is too wordy, can you think of a more concise name?") + .build()); + } + if (name.isTemporary(method)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("METHOD_IS_TEMPORARY") + .setSeverity(severity).setFilename(filename) + .setMessage("Method name " + method + " could be named better.") + .build()); + } + if (name.hasPrefixOrPostfix(method)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("METHOD_HAS_PREFIX_OR_POSTFIX") + .setSeverity(severity).setFilename(filename) + .setMessage("Method name has prefix or postfix " + method + " and could be named better.") + .build()); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/cflint/plugins/core/ValidName.java b/src/main/java/com/cflint/plugins/core/ValidName.java new file mode 100644 index 000000000..1c8aa63f0 --- /dev/null +++ b/src/main/java/com/cflint/plugins/core/ValidName.java @@ -0,0 +1,132 @@ + +package com.cflint.plugins.core; + +import java.util.regex.Pattern; + +public class ValidName { + public static final int MIN_VAR_LENGTH = 3; + public static final int MAX_VAR_LENGTH = 20; + public static final int MAX_VAR_WORDS = 4; + + public static final int MIN_METHOD_LENGTH = 3; + public static final int MAX_METHOD_LENGTH = 25; + public static final int MAX_METHOD_WORDS = 5; + + protected int minLength = MIN_VAR_LENGTH; + protected int maxLength = MAX_VAR_LENGTH; + protected int maxWords = MAX_VAR_WORDS; + + public ValidName() { + } + + public ValidName(int minLength, int maxLength, int maxWords) { + this.minLength = minLength; + this.maxLength = maxLength; + this.maxWords = maxWords; + } + + public boolean isInvalid(String name) { + return !validChars(name) || endsInNumber(name) || !(isSameCase(name) || isCamelCaseLower(name) || usesUnderscores(name)); + } + + public boolean validChars(String name) { + Pattern valid = Pattern.compile("^[A-Za-z0-9_]+$"); + return valid.matcher(name).matches(); + } + + public boolean isUpperCase(String name) { + return name.toUpperCase().equals(name); + } + + public boolean isSameCase(String name) { + return name.equals(name.toLowerCase()) || name.equals(name.toUpperCase()); + } + + public boolean isCamelCaseLower(String name) { + // [A-Z0-9]{2,5} catch names like productID, phone4G, requestURL etc etc + Pattern valid = Pattern.compile("^[a-z0-9]+([A-Z]{1,5}[a-z0-9]+)*([A-Z0-9]{2,5}){0,1}$"); + return valid.matcher(name).matches(); + } + + public boolean isCamelCaseUpper(String name) { + Pattern valid = Pattern.compile("^([A-Z]{1,5}[a-z0-9]+)+([A-Z0-9]{2,5}){0,1}$"); + return valid.matcher(name).matches(); + } + + public boolean usesUnderscores(String name) { + return name.indexOf('_') != -1; + } + + public boolean endsInNumber(String name) { + char lastLetter = name.charAt(name.length() - 1); + + if (Character.isDigit(lastLetter)) { + return true; + } + + return false; + } + + public boolean tooShort(String name) { + return name.length() < minLength; + } + + public boolean tooLong(String name) { + return name.length() > maxLength; + } + + public boolean tooWordy(String name) { + String[] words = name.split("[A-Z_]+"); + int count = 0; + + for (int i = 0; i < words.length; i++) { + if (words[i] != null && !words[i].equals("")) { + count++; + } + } + + return count > maxWords; + } + + public boolean isTemporary(String name) { + String[] wordsToAvoid = {"temp", "tmp", "var", "func", "obj", "object", "bool", "struct", "string", "array", "comp"}; + String sentence = name.replaceAll("_", " "); + sentence = sentence.replaceAll("(\\p{Ll})(\\p{Lu})","$1 $2"); + String[] words = sentence.split(" "); + + for (String badWord : wordsToAvoid) { + for (String word : words) { + if (word.toLowerCase().equals(badWord)) + { + return true; + } + } + } + + return false; + } + + public boolean hasPrefixOrPostfix(String name) { + String[] namesToAvoid = {"s", "st", "str", "o", "obj", "b", "q", "a", "arr", "this", "my"}; + String sentence = name.replaceAll("_", " "); + sentence = sentence.replaceAll("(\\p{Ll})(\\p{Lu})","$1 $2"); + String[] words = sentence.split(" "); + String firstWord = words[0]; + String lastWord = words[words.length-1]; + + if (words.length > 1) { + for (String badName : namesToAvoid) { + if (firstWord.toLowerCase().equals(badName)) + { + return true; + } + if (lastWord.toLowerCase().equals(badName)) + { + return true; + } + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/main/java/com/cflint/plugins/core/VariableNameChecker.java b/src/main/java/com/cflint/plugins/core/VariableNameChecker.java new file mode 100644 index 000000000..552f2b99a --- /dev/null +++ b/src/main/java/com/cflint/plugins/core/VariableNameChecker.java @@ -0,0 +1,111 @@ +package com.cflint.plugins.core; + +import ro.fortsoft.pf4j.Extension; +import net.htmlparser.jericho.Element; +import net.htmlparser.jericho.Attributes; +import cfml.parsing.cfscript.CFAssignmentExpression; +import cfml.parsing.cfscript.CFExpression; +import cfml.parsing.cfscript.CFFullVarExpression; +import cfml.parsing.cfscript.CFIdentifier; +import cfml.parsing.cfscript.CFVarDeclExpression; + +import com.cflint.BugInfo; +import com.cflint.BugList; +import com.cflint.plugins.CFLintScannerAdapter; +import com.cflint.plugins.Context; + +import java.util.regex.Pattern; + +@Extension +public class VariableNameChecker extends CFLintScannerAdapter { + final String severity = "INFO"; + + public void expression(final CFExpression expression, final Context context, final BugList bugs) { + if (expression instanceof CFVarDeclExpression) { + final CFVarDeclExpression cfVarDeclExpression = (CFVarDeclExpression)expression; + int lineNo = expression.getLine() + context.startLine() - 1; + checkNameForBugs(cfVarDeclExpression.getName(), context.getFilename(), lineNo, bugs); + } + else if (expression instanceof CFFullVarExpression) { + final CFFullVarExpression cfFullVarExpression = (CFFullVarExpression)expression; + for(final CFExpression subexpression : cfFullVarExpression.getExpressions()){ + expression(subexpression,context,bugs); + } + } + else if (expression instanceof CFIdentifier) { + String varName = ((CFIdentifier) expression).getName(); + int lineNo = ((CFIdentifier) expression).getLine() + context.startLine() - 1; + + checkNameForBugs(varName, context.getFilename(), lineNo, bugs); + } + } + + public void checkNameForBugs(String variable, String filename, int line, BugList bugs) { + int minVarLength = ValidName.MIN_VAR_LENGTH; + int maxVarLength = ValidName.MAX_VAR_LENGTH; + int maxVarWords = ValidName.MAX_VAR_WORDS; + + if (getParameter("MinLength") != null) { + try { + minVarLength = Integer.parseInt(getParameter("MinLength")); + } catch(Exception e) {} + } + + if (getParameter("MaxLength") != null) { + try { + maxVarLength = Integer.parseInt(getParameter("MaxLength")); + } catch(Exception e) {} + } + + if (getParameter("MaxWords") != null) { + try { + maxVarWords = Integer.parseInt(getParameter("MaxWords")); + } catch(Exception e) {} + } + + ValidName name = new ValidName(minVarLength, maxVarLength, maxVarWords); + + if (name.isInvalid(variable)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("VAR_INVALID_NAME") + .setSeverity(severity).setFilename(filename) + .setMessage("Variable " + variable + " is not a valid name. Please use CamelCase or underscores.") + .build()); + } + if (name.isUpperCase(variable)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("VAR_ALLCAPS_NAME") + .setSeverity(severity).setFilename(filename) + .setMessage("Variable " + variable + " should not be upper case.") + .build()); + } + if (name.tooShort(variable)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("VAR_TOO_SHORT") + .setSeverity(severity).setFilename(filename) + .setMessage("Variable " + variable + " should be longer than " + minVarLength + " characters.") + .build()); + } + if (name.tooLong(variable)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("VAR_TOO_LONG") + .setSeverity(severity).setFilename(filename) + .setMessage("Variable " + variable + " should be shorter than " + maxVarLength + " characters.") + .build()); + } + if (!name.isUpperCase(variable) && name.tooWordy(variable)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("VAR_TOO_WORDY") + .setSeverity(severity).setFilename(filename) + .setMessage("Variable " + variable + " is too wordy, can you think of a more concise name?") + .build()); + } + if (name.isTemporary(variable)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("VAR_IS_TEMPORARY") + .setSeverity(severity).setFilename(filename) + .setMessage("Temporary variable " + variable + " could be named better.") + .build()); + } + if (name.hasPrefixOrPostfix(variable)) { + bugs.add(new BugInfo.BugInfoBuilder().setLine(line).setMessageCode("VAR_HAS_PREFIX_OR_POSTFIX") + .setSeverity(severity).setFilename(filename) + .setMessage("Variable has prefix or postfix " + variable + " and could be named better.") + .build()); + } + } +} \ No newline at end of file diff --git a/src/main/resources/cflint.definition.json b/src/main/resources/cflint.definition.json index 572e96894..eb44e8d5d 100644 --- a/src/main/resources/cflint.definition.json +++ b/src/main/resources/cflint.definition.json @@ -449,6 +449,102 @@ } ], "parameter": [] + }, + { + "name": "VariableNameChecker", + "className": "VariableNameChecker", + "message": [ + { + "code": "VAR_INVALID_NAME", + "severity": "INFO" + }, + { + "code": "VAR_ALLCAPS_NAME", + "severity": "INFO" + }, + { + "code": "VAR_TOO_SHORT", + "severity": "INFO" + }, + { + "code": "VAR_TOO_LONG", + "severity": "INFO" + }, + { + "code": "VAR_TOO_WORDY", + "severity": "INFO" + }, + { + "code": "VAR_IS_TEMPORARY", + "severity": "INFO" + }, + { + "code": "VAR_HAS_PREFIX_OR_POSTFIX", + "severity": "INFO" + } + ], + "parameter": [ + { + "name": "MinLength", + "value": "3" + }, + { + "name": "MaxLength", + "value": "20" + }, + { + "name": "MaxWords", + "value": "4" + } + ] + }, + { + "name": "MethodNameChecker", + "className": "MethodNameChecker", + "message": [ + { + "code": "METHOD_INVALID_NAME", + "severity": "INFO" + }, + { + "code": "METHOD_ALLCAPS_NAME", + "severity": "INFO" + }, + { + "code": "METHOD_TOO_SHORT", + "severity": "INFO" + }, + { + "code": "METHOD_TOO_LONG", + "severity": "INFO" + }, + { + "code": "METHOD_TOO_WORDY", + "severity": "INFO" + }, + { + "code": "METHOD_IS_TEMPORARY", + "severity": "INFO" + }, + { + "code": "METHOD_HAS_PREFIX_OR_POSTFIX", + "severity": "INFO" + } + ], + "parameter": [ + { + "name": "MinLength", + "value": "3" + }, + { + "name": "MaxLength", + "value": "25" + }, + { + "name": "MaxWords", + "value": "5" + } + ] } ] } \ No newline at end of file diff --git a/src/main/resources/cflint.definition.xml b/src/main/resources/cflint.definition.xml index ed9ad5f6a..2620ca36c 100644 --- a/src/main/resources/cflint.definition.xml +++ b/src/main/resources/cflint.definition.xml @@ -211,4 +211,50 @@ WARNING + + + INFO + + + INFO + + + INFO + + + INFO + + + INFO + + + INFO + + + INFO + + + + + INFO + + + INFO + + + INFO + + + INFO + + + INFO + + + INFO + + + INFO + + diff --git a/src/test/java/com/cflint/TestCFBugs_MethodNames.java b/src/test/java/com/cflint/TestCFBugs_MethodNames.java new file mode 100644 index 000000000..664b7bf04 --- /dev/null +++ b/src/test/java/com/cflint/TestCFBugs_MethodNames.java @@ -0,0 +1,290 @@ +package com.cflint; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import cfml.parsing.reporting.ParseException; + +import com.cflint.config.CFLintPluginInfo.PluginInfoRule; +import com.cflint.config.CFLintPluginInfo.PluginInfoRule.PluginMessage; +import com.cflint.config.ConfigRuntime; +import com.cflint.plugins.core.MethodNameChecker; + +public class TestCFBugs_MethodNames { + + private CFLint cfBugs; + + @Before + public void setUp() { + final ConfigRuntime conf = new ConfigRuntime(); + final PluginInfoRule pluginRule = new PluginInfoRule(); + pluginRule.setName("MethodNameChecker"); + conf.getRules().add(pluginRule); + PluginMessage pluginMessage = new PluginMessage("METHOD_INVALID_NAME"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("METHOD_ALLCAPS_NAME"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("METHOD_TOO_SHORT"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginRule.addParameter("MinLength", "3"); + pluginRule.addParameter("MaxLength", "20"); + pluginMessage = new PluginMessage("METHOD_TOO_LONG"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("METHOD_TOO_WORDY"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginRule.addParameter("MaxWords", "4"); + pluginMessage = new PluginMessage("METHOD_IS_TEMPORARY"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("METHOD_HAS_PREFIX_OR_POSTFIX"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + + final MethodNameChecker checker = new MethodNameChecker(); + cfBugs = new CFLint(conf, checker); + } + + @Test + public void testValidNamesTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + Collection> result = cfBugs.getBugs().getBugList().values(); + assertEquals(0, result.size()); + } + + @Test + public void testUpercaseNameTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_ALLCAPS_NAME", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void invalidCharsInNameTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameEndsInNumberTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameTooShortTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_TOO_SHORT", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameTooLongTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_TOO_LONG", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameTooWordyTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_TOO_WORDY", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameIsTemporyTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().get("METHOD_IS_TEMPORARY"); + assertEquals(1, result.size()); + assertEquals("METHOD_IS_TEMPORARY", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameHasPrefixOrPostfixTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_HAS_PREFIX_OR_POSTFIX", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + + @Test + public void testValidNamesScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + Collection> result = cfBugs.getBugs().getBugList().values(); + assertEquals(0, result.size()); + } + + @Test + public void testUpercaseNameScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function UPPERCASE() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_ALLCAPS_NAME", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void invalidCharsInNameScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function method$name() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameEndsInNumberScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function method23() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameTooShortScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function a() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_TOO_SHORT", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameTooLongScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function isaveryveryverylongmethodname() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_TOO_LONG", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameTooWordyScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function isFarTooWordyMethodName() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_TOO_WORDY", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameIsTemporyScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function temp() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().get("METHOD_IS_TEMPORARY"); + assertEquals(1, result.size()); + assertEquals("METHOD_IS_TEMPORARY", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + + @Test + public void nameHasPrefixOrPostfixScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function thisMethod() {\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(1, result.size()); + assertEquals("METHOD_HAS_PREFIX_OR_POSTFIX", result.get(0).getMessageCode()); + assertEquals(2, result.get(0).getLine()); + } + +} diff --git a/src/test/java/com/cflint/TestCFBugs_VariableNames.java b/src/test/java/com/cflint/TestCFBugs_VariableNames.java new file mode 100644 index 000000000..91fadf49a --- /dev/null +++ b/src/test/java/com/cflint/TestCFBugs_VariableNames.java @@ -0,0 +1,460 @@ +package com.cflint; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import cfml.parsing.reporting.ParseException; + +import com.cflint.config.CFLintPluginInfo.PluginInfoRule; +import com.cflint.config.CFLintPluginInfo.PluginInfoRule.PluginMessage; +import com.cflint.config.ConfigRuntime; +import com.cflint.plugins.core.VariableNameChecker; + +public class TestCFBugs_VariableNames { + + private CFLint cfBugs; + + @Before + public void setUp() { + final ConfigRuntime conf = new ConfigRuntime(); + final PluginInfoRule pluginRule = new PluginInfoRule(); + pluginRule.setName("VariableNameChecker"); + conf.getRules().add(pluginRule); + PluginMessage pluginMessage = new PluginMessage("VAR_INVALID_NAME"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("VAR_ALLCAPS_NAME"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("VAR_TOO_SHORT"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginRule.addParameter("MinLength", "3"); + pluginRule.addParameter("MaxLength", "20"); + pluginMessage = new PluginMessage("VAR_TOO_LONG"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("VAR_TOO_WORDY"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginRule.addParameter("MaxWords", "4"); + pluginMessage = new PluginMessage("VAR_IS_TEMPORARY"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + pluginMessage = new PluginMessage("VAR_HAS_PREFIX_OR_POSTFIX"); + pluginMessage.setSeverity("INFO"); + pluginRule.getMessages().add(pluginMessage); + + final VariableNameChecker checker = new VariableNameChecker(); + cfBugs = new CFLint(conf, checker); + } + + @Test + public void testValidNamesTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + Collection> result = cfBugs.getBugs().getBugList().values(); + assertEquals(0, result.size()); + } + + @Test + public void testUpercaseNameTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(4, result.size()); + assertEquals("VAR_ALLCAPS_NAME", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_ALLCAPS_NAME", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_ALLCAPS_NAME", result.get(2).getMessageCode()); + assertEquals(6, result.get(2).getLine()); + assertEquals("VAR_ALLCAPS_NAME", result.get(3).getMessageCode()); + assertEquals(7, result.get(3).getLine()); + } + + @Test + public void invalidCharsInNameTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(3, result.size()); + assertEquals("VAR_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + } + + @Test + public void nameEndsInNumberTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(3, result.size()); + assertEquals("VAR_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + } + + @Test + public void nameTooShortTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(3, result.size()); + assertEquals("VAR_TOO_SHORT", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_TOO_SHORT", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_TOO_SHORT", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + } + + @Test + public void nameTooLongTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(2, result.size()); + assertEquals("VAR_TOO_LONG", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_TOO_LONG", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + } + + @Test + public void nameTooWordyTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(2, result.size()); + assertEquals("VAR_TOO_WORDY", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_TOO_WORDY", result.get(1).getMessageCode()); + assertEquals(5, result.get(1).getLine()); + } + + @Test + public void nameIsTemporyTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().get("VAR_IS_TEMPORARY"); + assertEquals(7, result.size()); + assertEquals("VAR_IS_TEMPORARY", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(3).getMessageCode()); + assertEquals(6, result.get(3).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(4).getMessageCode()); + assertEquals(7, result.get(4).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(5).getMessageCode()); + assertEquals(8, result.get(5).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(6).getMessageCode()); + assertEquals(9, result.get(6).getLine()); + } + + @Test + public void nameHasPrefixOrPostfixTag() throws ParseException, IOException { + final String tagSrc = "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\r\n" + + ""; + cfBugs.process(tagSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(7, result.size()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(3).getMessageCode()); + assertEquals(6, result.get(3).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(4).getMessageCode()); + assertEquals(7, result.get(4).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(5).getMessageCode()); + assertEquals(8, result.get(5).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(6).getMessageCode()); + assertEquals(9, result.get(6).getLine()); + } + + + @Test + public void testValidNamesScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " var firstName = \"Fred\";\r\n" + + " first_name = \"Fred\";\r\n" + + " firstname = \"Fred\";\r\n" + + " name.first = \"Fred\";\r\n" + + " name.last = \"Smith\";\r\n" + + " names[1] = \"Smith\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + Collection> result = cfBugs.getBugs().getBugList().values(); + assertEquals(0, result.size()); + } + + @Test + public void testUpercaseNameScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " var FIRSTNAME = \"Fred\";\r\n" + + " LAST_NAME = \"Smith\";\r\n" + + " names = {};\r\n" + + " name.FIRST = \"Fred\";\r\n" + + " NAMES[1] = \"Fred\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(4, result.size()); + assertEquals("VAR_ALLCAPS_NAME", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_ALLCAPS_NAME", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_ALLCAPS_NAME", result.get(2).getMessageCode()); + assertEquals(6, result.get(2).getLine()); + assertEquals("VAR_ALLCAPS_NAME", result.get(3).getMessageCode()); + assertEquals(7, result.get(3).getLine()); + } + + @Test + public void invalidCharsInNameScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " var $name = \"Fred\";\r\n" + + " last$name = \"Smith\";\r\n" + + " last.$name = \"Smith\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(3, result.size()); + assertEquals("VAR_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + } + + @Test + public void nameEndsInNumberScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " name_1 = \"Fred\";\r\n" + + " name2 = \"Smith\";\r\n" + + " last.name1 = \"Fred\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(3, result.size()); + assertEquals("VAR_INVALID_NAME", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_INVALID_NAME", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + } + + @Test + public void nameTooShortScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " a = \"Fred\";\r\n" + + " b = \"Smith\";\r\n" + + " last.a = \"Fred\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(3, result.size()); + assertEquals("VAR_TOO_SHORT", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_TOO_SHORT", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_TOO_SHORT", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + } + + @Test + public void nameTooLongScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " isaveryveryverylongvariablename = \"Fred\";\r\n" + + " isa.veryveryverylongvariablename = \"Fred\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(2, result.size()); + assertEquals("VAR_TOO_LONG", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_TOO_LONG", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + } + + @Test + public void nameTooWordyScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " nameIsFarTooWordy = \"Fred\";\r\n" + + " nameIsOK = \"Fred\";\r\n" + + " name.isAlsoFarTooWordy = \"Fred\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(2, result.size()); + assertEquals("VAR_TOO_WORDY", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_TOO_WORDY", result.get(1).getMessageCode()); + assertEquals(5, result.get(1).getLine()); + } + + @Test + public void nameIsTemporyScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " temp = \"Fred\";\r\n" + + " name.temp = \"Fred\";\r\n" + + " obj = \"Fred\";\r\n" + + " struct = \"Fred\";\r\n" + + " tempName = \"Fred\";\r\n" + + " nameObj = \"Fred\";\r\n" + + " nameString = \"Fred\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().get("VAR_IS_TEMPORARY"); + assertEquals(7, result.size()); + assertEquals("VAR_IS_TEMPORARY", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(3).getMessageCode()); + assertEquals(6, result.get(3).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(4).getMessageCode()); + assertEquals(7, result.get(4).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(5).getMessageCode()); + assertEquals(8, result.get(5).getLine()); + assertEquals("VAR_IS_TEMPORARY", result.get(6).getMessageCode()); + assertEquals(9, result.get(6).getLine()); + } + + @Test + public void nameHasPrefixOrPostfixScript() throws ParseException, IOException { + final String scriptSrc = "component {\r\n" + + "function test() {\r\n" + + " sName = \"Fred\";\r\n" + + " nameSt = {first:\"Fred\"};\r\n" + + " oName = {first:\"Fred\"};\r\n" + + " bOff = true;\r\n" + + " arrNames = [\"Fred\"];\r\n" + + " thisName = \"Fred\";\r\n" + + " myName = \"Fred\";\r\n" + + "}\r\n" + + "}"; + cfBugs.process(scriptSrc, "test"); + final List result = cfBugs.getBugs().getBugList().values().iterator().next(); + assertEquals(7, result.size()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(0).getMessageCode()); + assertEquals(3, result.get(0).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(1).getMessageCode()); + assertEquals(4, result.get(1).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(2).getMessageCode()); + assertEquals(5, result.get(2).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(3).getMessageCode()); + assertEquals(6, result.get(3).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(4).getMessageCode()); + assertEquals(7, result.get(4).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(5).getMessageCode()); + assertEquals(8, result.get(5).getLine()); + assertEquals("VAR_HAS_PREFIX_OR_POSTFIX", result.get(6).getMessageCode()); + assertEquals(9, result.get(6).getLine()); + } + +} diff --git a/src/test/java/com/cflint/TestValidNames.java b/src/test/java/com/cflint/TestValidNames.java new file mode 100644 index 000000000..e0fcdd05d --- /dev/null +++ b/src/test/java/com/cflint/TestValidNames.java @@ -0,0 +1,158 @@ +package com.cflint; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import com.cflint.plugins.core.ValidName; + +public class TestValidNames { + + private ValidName name; + + @Before + public void setUp() { + name = new ValidName(3, 20, 3); + } + + @Test + public void testInvalid() { + assertFalse(name.isInvalid("camelCase")); + assertFalse(name.isInvalid("product_id")); + assertFalse(name.isInvalid("size")); + assertFalse(name.isInvalid("lowercase")); + assertFalse(name.isInvalid("UPPERCASE")); + assertFalse(name.isInvalid("99_bottles_of_beer")); + + assertTrue(name.isInvalid("UppperCaseCamel")); + assertTrue(name.isInvalid("endsInNumber99")); + } + + @Test + public void testValidChars() { + assertTrue(name.validChars("camelCase")); + assertTrue(name.validChars("product_id")); + assertTrue(name.validChars("99_bottles_of_beer")); + + assertFalse(name.validChars("no$items")); + assertFalse(name.validChars("no-items")); + assertFalse(name.validChars("no+items")); + } + + @Test + public void testIsCamelCaseLower() { + assertTrue(name.isCamelCaseLower("product")); + assertTrue(name.isCamelCaseLower("camelCase")); + assertTrue(name.isCamelCaseLower("product4G")); + assertTrue(name.isCamelCaseLower("productID")); + assertTrue(name.isCamelCaseLower("requestViaHTTPS")); + assertTrue(name.isCamelCaseLower("myURLRequest")); + + assertFalse(name.isCamelCaseLower("product_id")); + assertFalse(name.isCamelCaseLower("UpperCase")); + assertFalse(name.isCamelCaseLower("Uppercase")); + assertFalse(name.isCamelCaseLower("ProductID")); + assertFalse(name.isCamelCaseLower("PRODUCTID")); + } + + @Test + public void testIsCamelCaseUpper() { + assertTrue(name.isCamelCaseUpper("Product")); + assertTrue(name.isCamelCaseUpper("PamelCase")); + assertTrue(name.isCamelCaseUpper("Product4G")); + assertTrue(name.isCamelCaseUpper("ProductID")); + assertTrue(name.isCamelCaseUpper("RequestViaHTTPS")); + assertTrue(name.isCamelCaseUpper("MyURLRequest")); + + assertFalse(name.isCamelCaseUpper("product")); + assertFalse(name.isCamelCaseUpper("Product_id")); + assertFalse(name.isCamelCaseUpper("Product_Id")); + assertFalse(name.isCamelCaseUpper("PRODUCTID")); + } + + @Test + public void testUsesUnderscores() { + assertTrue(name.usesUnderscores("product_name")); + assertTrue(name.usesUnderscores("_atstart")); + assertTrue(name.usesUnderscores("atend_")); + assertTrue(name.usesUnderscores("lots_of_under_scores")); + + assertFalse(name.usesUnderscores("productName")); + assertFalse(name.usesUnderscores("productname")); + } + + @Test + public void testEndsInNumber() { + assertTrue(name.endsInNumber("endsInNumber99")); + assertTrue(name.endsInNumber("temp2")); + + assertFalse(name.endsInNumber("productName")); + assertFalse(name.endsInNumber("phone4G")); + assertFalse(name.endsInNumber("99beers")); + } + + @Test + public void testTooShort() { + assertTrue(name.tooShort("a")); + assertTrue(name.tooShort("to")); + + assertFalse(name.tooShort("the")); + assertFalse(name.tooShort("chars")); + assertFalse(name.tooShort("averylongname")); + } + + @Test + public void testTooLong() { + assertTrue(name.tooLong("123456789012345678901")); + assertTrue(name.tooLong("aVeryLongNameThatIsTooLong")); + + assertFalse(name.tooLong("shortName")); + assertFalse(name.tooLong("short_name")); + assertFalse(name.tooLong("12345678901234567890")); + } + + + @Test + public void testTooWordy() { + assertTrue(name.tooWordy("thisIsAVeryWordyName")); + assertTrue(name.tooWordy("alsoFarTooWordy")); + + assertFalse(name.tooWordy("ProductName")); + assertFalse(name.tooWordy("aSimpleName")); + assertFalse(name.tooWordy("simple")); + } + + @Test + public void testIsTemporary() { + assertTrue(name.isTemporary("temp")); + assertTrue(name.isTemporary("tmp")); + assertTrue(name.isTemporary("myVar")); + assertTrue(name.isTemporary("aFunc")); + assertTrue(name.isTemporary("nameObj")); + assertTrue(name.isTemporary("name_obj")); + assertTrue(name.isTemporary("tmp_array")); + + assertFalse(name.isTemporary("temperature")); + assertFalse(name.isTemporary("productName")); + assertFalse(name.isTemporary("first_name")); + } + + @Test + public void testHasPrefixOrPostfix() { + assertTrue(name.hasPrefixOrPostfix("stName")); + assertTrue(name.hasPrefixOrPostfix("oPerson")); + assertTrue(name.hasPrefixOrPostfix("qGet")); + assertTrue(name.hasPrefixOrPostfix("nameStr")); + assertTrue(name.hasPrefixOrPostfix("bValid")); + + assertFalse(name.isTemporary("temperature")); + assertFalse(name.isTemporary("strength")); + assertFalse(name.isTemporary("argument")); + assertFalse(name.isTemporary("first_name")); + } +}