0

I wrote a string validator to check username/password. I pass a string, a min required length. The length of the first string i pass is 4 (username) and the second time 8 (password).

I then store these values in a companion object and let my return variable, an Enum with a string value, use the min length variable reference from the companion object to specify min length in the string message.

The problem is the first time it works as intended and the string writes 4 as min length. The second time however, when I bump the length to 8, the output still says 4.

Code:

//Calling from somewhere else
 val usernameStrengthResult = StringStrengthValidator.evaluateStrength(registrationUserData.fullName,8)
 val passwordStrengthResult = StringStrengthValidator.evaluateStrength(registrationUserData.password,8)

-------------------------------------------------------------------  
 companion object {                                 

 //--------REQUIREMENTS--------                 
 var REQUIRED_LENGTH = 0                                               

fun evaluateStrength(clientString: String, requiredLength: Int?= null){

  //Setting companion value to the new length limit
  requiredLength?.let { REQUIRED_LENGTH = it } 

  return when {                                                               
     clientString.length < REQUIRED_LENGTH -> StringStrengthReport.TO_SHORT 
    }
}

-------------------------------------------------------------------
//I use REQUIRED_LENGTH to construct a message
enum class StringStrengthReport(val message: String){                                          
    TO_SHORT("is to short. ${StringStrengthValidator.REQUIRED_LENGTH} characters are required")
}

The weirdest part is that when im debugging the value is shown as 8 (the second time) but the string still gets constructed with the 4.

It seams that once the value have been read one, it will not change. Has anyone else had a similar problem?

EDIT: Full code

class StringStrengthValidator {

    companion object {

        //--------REQUIREMENTS--------
        var REQUIRED_LENGTH = 8
        var MAXIMUM_LENGTH = 32
        private var REQUIRE_SPECIAL_CHARACTERS = false
        private var REQUIRE_DIGITS = false
        private var REQUIRE_LOWER_CASE = false
        private var REQUIRE_UPPER_CASE = false

        fun evaluateStrength(clientString: String,
                             requiredLength: Int?= null,
                             maxLength: Int? = null,
                             requireSpecial: Boolean? = null,
                             requireDigits: Boolean?= null,
                             requireLowerCase: Boolean? = null,
                             requireUpperCase:Boolean? =null)
                : StringStrengthReport {

            requiredLength?.let { REQUIRED_LENGTH = it }
            maxLength?.let { MAXIMUM_LENGTH = it }
            requireSpecial?.let { REQUIRE_SPECIAL_CHARACTERS = it }
            requireDigits?.let { REQUIRE_DIGITS = it }
            requireLowerCase?.let { REQUIRE_LOWER_CASE = it }
            requireUpperCase?.let { REQUIRE_UPPER_CASE = it }


            var hasUpper = false
            var hasLower = false
            var hasDigit = false
            var hasSpecial = false

            for (i in 0 until clientString.length) {
                val c = clientString[i]

                when {
                    isSpecialCharacter(hasSpecial, c) -> hasSpecial = true
                    isDigit(hasDigit, c) -> hasDigit = true
                    isUpperCase(hasUpper, c) -> hasUpper = true
                    else -> hasLower = true
                }
            }

           return when {
                clientString.length < REQUIRED_LENGTH -> StringStrengthReport.TO_SHORT
                REQUIRE_LOWER_CASE && !hasLower -> StringStrengthReport.LOWER_CASE_REQUIRED
                REQUIRE_UPPER_CASE && !hasUpper -> StringStrengthReport.UPPER_CASE_REQUIRED
                REQUIRE_DIGITS && !hasDigit -> StringStrengthReport.DIGIT_REQUIRED
                REQUIRE_SPECIAL_CHARACTERS && !hasSpecial -> StringStrengthReport.SPECIAL_CHARACTER_REQUIRED
                clientString.length > MAXIMUM_LENGTH ->StringStrengthReport.MAX_LENGTH_EXCEEDED
                else -> StringStrengthReport.VALID_STRING
            }

        }

        private fun isUpperCase(hasUpper: Boolean, c: Char) =
                !hasUpper && Character.isUpperCase(c)

        private fun isDigit(hasDigit: Boolean, c: Char) = !hasDigit && Character.isDigit(c)

        private fun isSpecialCharacter(hasSpecial: Boolean, c: Char) =
                !hasSpecial && !Character.isLetterOrDigit(c)

        fun validateEmail(email: String):Boolean {
            return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()
        }

        fun validateRegisterCredentials(registrationUserData: RegistrationUserData): CredentialStrengthReport {

            val isEmailValid = StringStrengthValidator.validateEmail(registrationUserData.email)
            val usernameStrengthResult = StringStrengthValidator.evaluateStrength(registrationUserData.fullName,8,32)
            val passwordStrengthResult = StringStrengthValidator.evaluateStrength(registrationUserData.password,8,32)

            var reportMessage = ""
            if (!isEmailValid) reportMessage += "Incorrect Email format\n"
            val isUsernameValid = usernameStrengthResult == StringStrengthReport.VALID_STRING
            if (!isUsernameValid) reportMessage += "Username ${usernameStrengthResult.message}\n"
            val isPasswordValid = passwordStrengthResult == StringStrengthReport.VALID_STRING
            if (!isPasswordValid)reportMessage += "Password ${passwordStrengthResult.message}\n"

            return CredentialStrengthReport(isEmailValid, isUsernameValid, isPasswordValid, reportMessage)

        }
    }

}

enum class StringStrengthReport(val message: String){
    TO_SHORT("is to short. ${StringStrengthValidator.REQUIRED_LENGTH} characters are required"),
    LOWER_CASE_REQUIRED("requires at least one lower case character"),
    UPPER_CASE_REQUIRED("requires at least one upper case character"),
    DIGIT_REQUIRED("requires at least one digit"),
    SPECIAL_CHARACTER_REQUIRED("requires at least one special character (i.e !&?#%)"),
    MAX_LENGTH_EXCEEDED("is to long. Maximum length is ${StringStrengthValidator.MAXIMUM_LENGTH} characters"),
    VALID_STRING("is valid")
}

class CredentialStrengthReport(val isEmailValid: Boolean,
                               val isUsernameValid:Boolean,
                               val isPasswordValid: Boolean,
                               val resultMessage: String){

    val isCredentialsValid:Boolean
    get() {return isEmailValid && isUsernameValid && isPasswordValid}
}
Joel Broström
  • 3,530
  • 1
  • 34
  • 61
  • 3
    *I then store these values in a companion object* - why would you do that – Tim Oct 25 '18 at 07:57
  • Why `evaluateStrength` has no return type? Post full code, and not some weird cutted parts. – Demigod Oct 25 '18 at 08:05
  • Since you asked so nicely :) – Joel Broström Oct 25 '18 at 08:20
  • I'm not sure what you're trying to achieve but the fact that you want to store values in a companion object sounds like a big code smell. Static values are _evil_. – lelloman Oct 25 '18 at 08:22
  • @JoelBroström As I can see, you store `requiredLength` parameter to the `REQUIRED_LENGTH` static variable every time (which is 8), but not the `clientString.length`. Cause here `requiredLength?.let { REQUIRED_LENGTH = it }` `it` is the `requiredLength`. Right? – Demigod Oct 25 '18 at 08:26

0 Answers0