├── .gitignore ├── .travis.yml ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── kotlin │ └── com │ └── markodevcic │ └── kvalidation │ ├── InnerValidator.kt │ ├── OnErrorBuilder.kt │ ├── PropertyContext.kt │ ├── RuleBuilder.kt │ ├── ValidationResult.kt │ ├── ValidationStrategy.kt │ ├── Validator.kt │ ├── ValidatorBase.kt │ ├── errors │ ├── ErrorLevel.kt │ └── ValidationError.kt │ ├── messages │ ├── DefaultMessageBuilder.kt │ └── MessageBuilder.kt │ └── validators │ ├── ContainsValidator.kt │ ├── EmailValidator.kt │ ├── EmptyValidator.kt │ ├── EqualValidator.kt │ ├── GreaterOrEqualThanValidator.kt │ ├── GreaterThanValidator.kt │ ├── LengthValidator.kt │ ├── LesserOrEqualThanValidator.kt │ ├── LesserThanValidator.kt │ ├── NonNullValidator.kt │ ├── NotEqualValidator.kt │ ├── NullValidator.kt │ ├── PatternValidator.kt │ ├── PropertyValidator.kt │ ├── PropertyValidatorBase.kt │ └── RangeValidator.kt └── test ├── java └── com │ └── markodevcic │ └── kvalidation │ └── JavaTest.java └── kotlin └── com └── markodevcic └── kvalidation ├── AbstractValidatorTests.kt ├── PreconditionTests.kt ├── TestObject.kt ├── TestObjectValidator.kt ├── messages └── DefaultMessageBuilderTest.kt └── validators ├── ContainsValidatorTests.kt ├── CustomValidatorTests.kt ├── EmailValidatorTests.kt ├── EmptyValidatorTest.kt ├── EqualValidatorTests.kt ├── GreaterOrEqualThanValidatorTests.kt ├── GreaterThanValidatorTests.kt ├── LengthValidatorTests.kt ├── LesserOrEqualThanValidatorTests.kt ├── LesserThanValidatorTests.kt ├── NonNullValidatorTests.kt ├── NotEqualValidatorTests.kt └── NullValidatorTests.kt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | build/ 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | sudo: false 3 | 4 | before_install: 5 | - chmod +x gradlew 6 | 7 | jdk: 8 | - openjdk10 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/deva666/KValidation.svg?branch=master)](https://travis-ci.org/deva666/KValidation) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 2 | 3 | # KValidation 4 | 5 | ### Validation library for Kotlin/Java ### 6 | 7 | --------------- 8 | 9 | ### Example: ### 10 | 11 | Create the validator class by extending the generic `ValidatorBase` class. 12 | 13 | ``` 14 | class UserValidator extends ValidatorBase { 15 | } 16 | ``` 17 | 18 | Java 19 | 20 | ``` 21 | User user = new User(); 22 | UserValidator validator = new UserValidator(user); 23 | 24 | validator.forProperty(User::getName) 25 | .length(4) 26 | .mustBe(n -> n.startsWith("J")) 27 | .notEqual("John") 28 | .onError() 29 | .errorMessage("Name should start with J, be 4 characters in length and not be John"); 30 | 31 | ValidationResult result = validator.validate(); 32 | 33 | if (result.isValid()) { 34 | // woohooo 35 | } else { 36 | for(ValidationError err : result.getValidationErrors()) { 37 | System.out.print(err.toString()); 38 | } 39 | } 40 | ``` 41 | 42 | Kotlin has even nicer syntax 43 | 44 | ``` 45 | val user = User() 46 | val validator = UserValidator(user) 47 | 48 | validator.forProperty { p -> p.name } rules { 49 | length(4) 50 | mustBe { n -> n.startsWith("J") } 51 | notEqual("John") 52 | } onError { 53 | errorMessage("Name should start with J, be 4 characters in length and not be John") 54 | } 55 | 56 | val result = validator.validate() 57 | ``` 58 | 59 | If you don't want to create a validator class, add InnerValidator inside the validated class 60 | 61 | ``` 62 | class User(private val name: String, private val age: Int) { 63 | val validator = InnerValidator(this) setRules { 64 | forProperty { p -> p.name } rules { 65 | equal("John") 66 | } 67 | } 68 | } 69 | ``` 70 | ---------------------------------------------------- 71 | ### Contributing ### 72 | Contributions are always welcome, just fork the project and submit a pull request. 73 | 74 | --------------------------------------------------- 75 | 76 | Written by [Marko Devcic](http://www.markodevcic.com) 77 | 78 | License [APL 2.0 ](http://www.apache.org/licenses/LICENSE-2.0) 79 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.markodevcic' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.3.41' 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | dependencies { 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | } 13 | } 14 | 15 | apply plugin: 'java' 16 | apply plugin: 'kotlin' 17 | 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 24 | testCompile group: 'junit', name: 'junit', version: '4.11' 25 | } 26 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deva666/KValidation/165a735f9a8012de28b1b1e6d54486f1e581ac1a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Aug 12 06:59:25 CEST 2019 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'kvalidation' 2 | 3 | -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/InnerValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation 18 | 19 | /** 20 | * Validator class that can be used inside of validated object 21 | * @sample class Person(private val name: String, private val age: Int) { 22 | * val validator = InnerValidator(this) setRules { 23 | * forProperty { p -> p.name } rules { 24 | * equal("John") 25 | * } 26 | * } 27 | * } 28 | */ 29 | class InnerValidator(instance: T) : ValidatorBase(instance) where T : Any { 30 | } 31 | 32 | infix fun InnerValidator.setRules(initializer: InnerValidator.() -> Unit): InnerValidator where T : Any { 33 | initializer(this) 34 | return this 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/OnErrorBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation 18 | 19 | import com.markodevcic.kvalidation.errors.ErrorLevel 20 | import com.markodevcic.kvalidation.messages.DefaultMessageBuilder 21 | import com.markodevcic.kvalidation.messages.MessageBuilder 22 | 23 | class OnErrorBuilder(private val propertyContext: PropertyContext) { 24 | 25 | /** 26 | * Sets the message to display when validation fails 27 | */ 28 | infix fun errorMessage(message: String): OnErrorBuilder { 29 | val messageBuilder = DefaultMessageBuilder(message) 30 | propertyContext.validators.forEach { v -> v.messageBuilder = messageBuilder } 31 | return this 32 | } 33 | 34 | /** 35 | * Sets the [MessageBuilder] to display error message for failed validation 36 | * For example, in Android getting a string from resources requires an instance of Context class 37 | * So custom message builder which gets a string from Android resources can be passed here 38 | */ 39 | infix fun errorMessage(messageBuilder: MessageBuilder): OnErrorBuilder { 40 | propertyContext.validators.forEach { v -> v.messageBuilder = messageBuilder } 41 | return this 42 | } 43 | 44 | /** 45 | * Sets the error code for validated property 46 | */ 47 | infix fun errorCode(code: Int): OnErrorBuilder { 48 | propertyContext.validators.forEach { v -> v.errorCode = code } 49 | return this 50 | } 51 | 52 | /** 53 | * Sets the error level for validated property 54 | */ 55 | infix fun errorLevel(errorLevel: ErrorLevel): OnErrorBuilder { 56 | propertyContext.validators.forEach { v -> v.errorLevel = errorLevel } 57 | return this 58 | } 59 | 60 | /** 61 | * Set the name of property being validated. 62 | * The name is displayed in each @see ValidationError debug message, for easier debugging 63 | */ 64 | infix fun propertyName(name: String): OnErrorBuilder { 65 | propertyContext.propertyName = name 66 | return this 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/PropertyContext.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation 18 | 19 | import com.markodevcic.kvalidation.validators.PropertyValidator 20 | import java.util.* 21 | 22 | /** 23 | * Context that holds property value producer, all the validators for specified property and optional property name 24 | * @param propertyName if defined, property name will be added to debug messages of [ValidationError] for easier debugging 25 | */ 26 | class PropertyContext(val valueFactory: (T) -> TProperty?, var propertyName: String? = null) { 27 | val validators = ArrayList() 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/RuleBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation 18 | 19 | import com.markodevcic.kvalidation.validators.* 20 | import java.util.regex.Pattern 21 | 22 | @Suppress("UNCHECKED_CAST") 23 | class RuleBuilder(val propertyContext: PropertyContext) { 24 | 25 | private var currentPropertyValidator: PropertyValidator? = null 26 | 27 | private fun setValidatorInternal(validator: PropertyValidator) { 28 | currentPropertyValidator = validator 29 | propertyContext.validators.add(validator) 30 | } 31 | 32 | /** 33 | * Sets a custom validator 34 | */ 35 | infix fun setValidator(validator: PropertyValidator): RuleBuilder { 36 | setValidatorInternal(validator) 37 | return this 38 | } 39 | 40 | /** 41 | * Sets a custom rule 42 | * @param predicate method accepting validated property and returning a boolean value indicating if the property is valid 43 | */ 44 | infix fun mustBe(predicate: (TProperty?) -> Boolean): RuleBuilder { 45 | val validator = object : PropertyValidatorBase() { 46 | override fun isValid(result: Any?): Boolean { 47 | return predicate.invoke(result as TProperty?) 48 | } 49 | } 50 | setValidatorInternal(validator) 51 | return this 52 | } 53 | 54 | /** 55 | * Sets the rule that property must not be null 56 | */ 57 | fun nonNull(): RuleBuilder { 58 | setValidatorInternal(NonNullValidator()) 59 | return this 60 | } 61 | 62 | /** 63 | * Sets the rule that property must be null 64 | * Cannot be used with other rules and validators 65 | * @throws [IllegalStateException] if there are other rules defined 66 | */ 67 | fun isNull() { 68 | if (propertyContext.validators.size != 0) { 69 | throw IllegalStateException("can't set is null validator with other validators") 70 | } 71 | setValidatorInternal(NullValidator()) 72 | } 73 | 74 | /** 75 | * Sets the rule that defines maximum length of string value of property 76 | */ 77 | infix fun length(max: Int): RuleBuilder { 78 | setValidatorInternal(LengthValidator(0, max)) 79 | return this 80 | } 81 | 82 | /** 83 | * Sets the rule that defines minimum and maximum length of string value of property 84 | */ 85 | fun length(min: Int, max: Int): RuleBuilder { 86 | setValidatorInternal(LengthValidator(min, max)) 87 | return this 88 | } 89 | 90 | /** 91 | * Sets the rule that property should be equal to another object of same type 92 | * Uses that type's equals method for comparison 93 | */ 94 | infix fun equal(other: TProperty): RuleBuilder { 95 | setValidatorInternal(EqualValidator(other)) 96 | return this 97 | } 98 | 99 | /** 100 | * Sets the rule that property should not be equal to another object of same type 101 | * Uses that type's equals method for comparison 102 | */ 103 | infix fun notEqual(other: TProperty): RuleBuilder { 104 | setValidatorInternal(NotEqualValidator(other)) 105 | return this 106 | } 107 | 108 | /** 109 | * Sets the rule that property should be less than defined [Number] 110 | * If property being validated is not subclass of [Number], validation fails 111 | */ 112 | infix fun lt(other: Number): RuleBuilder { 113 | setValidatorInternal(LesserThanValidator(other)) 114 | return this 115 | } 116 | 117 | /** 118 | * Sets the rule that property should be greater than defined [Number] 119 | * If property being validated is not subclass of [Number], validation fails 120 | */ 121 | infix fun gt(other: Number): RuleBuilder { 122 | setValidatorInternal(GreaterThanValidator(other)) 123 | return this 124 | } 125 | 126 | /** 127 | * Sets the rule that property should be less or equal than defined [Number] 128 | * If property being validated is not subclass of [Number], validation fails 129 | */ 130 | infix fun lte(other: Number): RuleBuilder { 131 | setValidatorInternal(LesserOrEqualThanValidator(other)) 132 | return this 133 | } 134 | 135 | /** 136 | * Sets the rule that property should be greater or equal than defined [Number] 137 | * If property being validated is not subclass of [Number], validation fails 138 | */ 139 | infix fun gte(other: Number): RuleBuilder { 140 | setValidatorInternal(GreaterOrEqualThanValidator(other)) 141 | return this 142 | } 143 | 144 | /** 145 | * Sets the rule that property should be inside defined [Iterable] 146 | */ 147 | infix fun isContainedIn(source: Iterable): RuleBuilder { 148 | setValidatorInternal(ContainsValidator(source)) 149 | return this 150 | } 151 | 152 | /** 153 | * Sets the rule that property should be between two numbers 154 | * If property being validated is not subclass of [Number], validation fails 155 | */ 156 | fun inRange(min: Number, max: Number): RuleBuilder { 157 | setValidatorInternal(RangeValidator(min, max)) 158 | return this 159 | } 160 | 161 | /** 162 | * Sets the rule that property should not contain any elements 163 | * If property being validated is not subclass of [Iterable], validation fails 164 | */ 165 | fun empty(): RuleBuilder { 166 | setValidatorInternal(EmptyValidator()) 167 | return this 168 | } 169 | 170 | /** 171 | * Sets the rule that string value of property should match an email regex 172 | */ 173 | fun email(): RuleBuilder { 174 | setValidatorInternal(EmailValidator()) 175 | return this 176 | } 177 | 178 | /** 179 | * Sets the rule that string value of property should match passed [Pattern] 180 | */ 181 | fun pattern(pattern: Pattern): RuleBuilder { 182 | setValidatorInternal(PatternValidator(pattern)) 183 | return this 184 | } 185 | 186 | /** 187 | * Sets a precondition for previously defined property 188 | * If precondition returns false, previous rule will not be executed 189 | * @sample 190 | * validator.forProperty { t -> t.name } rules { 191 | * nonNull() 192 | * length(7) 193 | * whenIs { t -> t.position > 3 } //length validator will be executed only when position is larger than 3, nonNull validator executes always 194 | * } 195 | */ 196 | infix fun whenIs(precondition: (T) -> Boolean): RuleBuilder { 197 | currentPropertyValidator?.precondition = { c -> precondition.invoke(c as T) } 198 | return this 199 | } 200 | 201 | /** 202 | * Sets a precondition for all previously defined properties 203 | * If precondition returns false, previous rule will not be executed 204 | * @sample 205 | * validator.forProperty { t -> t.name } rules { 206 | * nonNull() 207 | * length(7) 208 | * whenIsOnAll { t -> t.position > 3 } //length and nonNull validator will be executed only when position is larger than 3 209 | * } 210 | */ 211 | infix fun whenIsOnAll(precondition: (T) -> Boolean): RuleBuilder { 212 | propertyContext.validators.forEach { v -> 213 | v.precondition = { c -> precondition.invoke(c as T) } 214 | } 215 | return this 216 | } 217 | 218 | /** 219 | * Returns an [OnErrorBuilder] object for defining on error properties 220 | */ 221 | fun onError(): OnErrorBuilder { 222 | return OnErrorBuilder(propertyContext) 223 | } 224 | } 225 | 226 | -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/ValidationResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation 18 | 19 | import com.markodevcic.kvalidation.errors.ValidationError 20 | import java.util.* 21 | 22 | /** 23 | * Class that represents result of a validation 24 | * @property validationErrors holds all [ValidationError] that occurred 25 | * @property isValid is true if validation is without errors 26 | */ 27 | class ValidationResult() { 28 | 29 | val validationErrors = ArrayList() 30 | 31 | val isValid: Boolean 32 | get () { 33 | return validationErrors.size == 0 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/ValidationStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation 2 | 3 | enum class ValidationStrategy { 4 | FULL, 5 | STOP_ON_FIRST 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/Validator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation 18 | 19 | interface Validator { 20 | fun validate(): ValidationResult 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/ValidatorBase.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation 18 | 19 | import com.markodevcic.kvalidation.errors.ValidationError 20 | import com.markodevcic.kvalidation.validators.PropertyValidator 21 | import java.util.* 22 | 23 | /** 24 | * Base class for all validators 25 | * @param T the type of object being validated 26 | * @param consumer the actual object being validated 27 | */ 28 | abstract class ValidatorBase(private val consumer: T) : Validator where T : Any { 29 | private val contexts: MutableList> = ArrayList() 30 | 31 | var strategy = ValidationStrategy.FULL 32 | 33 | /** 34 | * Creates a rule builder object for defined property 35 | * @sample validator.forProperty(SomeObject::getName) 36 | * .notNull() 37 | * .equal("John") 38 | * @param valueFactory lambda that defines a property from the object being validated 39 | * @return [RuleBuilder] object 40 | */ 41 | fun forProperty(valueFactory: (T) -> TProperty?): RuleBuilder { 42 | val propertyContext = PropertyContext(valueFactory) 43 | contexts.add(propertyContext) 44 | return RuleBuilder(propertyContext) 45 | } 46 | 47 | /** 48 | * Validates the object 49 | * @return [ValidationResult] 50 | */ 51 | override fun validate(): ValidationResult { 52 | val result = ValidationResult() 53 | contexts.forEach { context -> 54 | val value = context.valueFactory(consumer) 55 | context.validators.forEach { validator -> 56 | if (validator.precondition?.invoke(consumer) != false && !validator.isValid(value)) { 57 | val error = createValidationError(validator, value, context.propertyName) 58 | result.validationErrors.add(error) 59 | if (strategy == ValidationStrategy.STOP_ON_FIRST) { 60 | return result 61 | } 62 | } 63 | } 64 | } 65 | return result 66 | } 67 | 68 | /** 69 | * Removes all defined rules 70 | */ 71 | fun clearAll() { 72 | contexts.clear() 73 | } 74 | 75 | private fun createValidationError(propertyValidator: PropertyValidator, value: TProperty?, propertyName: String?): ValidationError { 76 | val debugMessage = "$propertyValidator, received value: ${value ?: "null"}" + 77 | if (propertyName != null) ", property name: $propertyName" else "" 78 | return ValidationError(propertyValidator.messageBuilder?.getErrorMessage() 79 | ?: debugMessage, propertyValidator.errorLevel, propertyValidator.errorCode, debugMessage) 80 | } 81 | } 82 | 83 | /** 84 | * Extension function for defining rules, enables more readable syntax in Kotlin 85 | * @sample validator.forProperty {t -> t.name} rules { 86 | * nonNull() 87 | * equal("John") 88 | * } 89 | */ 90 | infix fun RuleBuilder.rules(ruleInit: RuleBuilder.() -> Unit): RuleBuilder { 91 | ruleInit.invoke(this) 92 | return this 93 | } 94 | 95 | /** 96 | * Extension function for defining on error properties, enables more readable syntax in Kotlin 97 | * @sample validator.forProperty {t -> t.name} rules { 98 | * nonNull() 99 | * equal("John") 100 | * } onError { 101 | * errorMessage("Name must be not null and John") 102 | * } 103 | */ 104 | infix fun RuleBuilder.onError(onErrorInit: OnErrorBuilder.() -> Unit) { 105 | onErrorInit(this.onError()) 106 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/errors/ErrorLevel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.errors 18 | 19 | enum class ErrorLevel { 20 | ERROR, 21 | WARNING, 22 | INFO 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/errors/ValidationError.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.errors 18 | 19 | class ValidationError(val message: String, val level: ErrorLevel, val errorCode: Int? = null, val debugMessage: String) { 20 | 21 | override fun toString(): String { 22 | return debugMessage 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/messages/DefaultMessageBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.messages 18 | 19 | class DefaultMessageBuilder(private val message: String) : MessageBuilder { 20 | override fun getErrorMessage(): String { 21 | return message 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/messages/MessageBuilder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.messages 18 | 19 | interface MessageBuilder { 20 | fun getErrorMessage(): String 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/ContainsValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class ContainsValidator(val source: Iterable) : PropertyValidatorBase() { 20 | 21 | override fun isValid(result: Any?): Boolean { 22 | return source.contains(result) 23 | } 24 | 25 | override fun toString(): String { 26 | return "Contains validator, expected value to be in collection $source" 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/EmailValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | import java.util.regex.Pattern 20 | 21 | internal class EmailValidator : PatternValidator(emailPattern) { 22 | 23 | override fun toString(): String { 24 | return "Email validator" 25 | } 26 | 27 | companion object { 28 | val emailPattern = Pattern.compile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$") 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/EmptyValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class EmptyValidator : PropertyValidatorBase() { 20 | override fun isValid(result: Any?): Boolean { 21 | if (result == null) { 22 | return true 23 | } else if (result is Iterable<*>) { 24 | return !result.any() 25 | } else { 26 | return false 27 | } 28 | } 29 | 30 | override fun toString(): String { 31 | return "Empty validator" 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/EqualValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class EqualValidator(private val other: Any?) : PropertyValidatorBase() { 20 | override fun isValid(result: Any?): Boolean { 21 | return result == other 22 | } 23 | 24 | override fun toString(): String { 25 | return "Equality validator, expected equal to: $other" 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/GreaterOrEqualThanValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class GreaterOrEqualThanValidator(private val target: Number) : PropertyValidatorBase() { 20 | 21 | override fun isValid(result: Any?): Boolean { 22 | if (result is Number) { 23 | return result.toDouble() >= target.toDouble() 24 | } else if (result == null) { 25 | return true 26 | } else { 27 | return false 28 | } 29 | } 30 | 31 | override fun toString(): String { 32 | return "Greater or equal than validator, expected value to be greater than: $target" 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/GreaterThanValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class GreaterThanValidator(private val target: Number) : PropertyValidatorBase() { 20 | 21 | override fun isValid(result: Any?): Boolean { 22 | if (result is Number) { 23 | return result.toDouble() > target.toDouble() 24 | } else if (result == null) { 25 | return true 26 | } else { 27 | return false 28 | } 29 | } 30 | 31 | override fun toString(): String { 32 | return "Greater than validator, expected value to be greater than: $target" 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/LengthValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class LengthValidator(private val min: Int, private val max: Int) : PropertyValidatorBase() { 20 | 21 | init { 22 | if (max < min) { 23 | throw IllegalArgumentException("max can't be lower than min") 24 | } 25 | } 26 | 27 | override fun isValid(result: Any?): Boolean { 28 | val text = result?.toString() ?: "" 29 | return text.length >= min && text.length <= max 30 | } 31 | 32 | override fun toString(): String { 33 | return "Length validator, expected text length between: $min - $max" 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/LesserOrEqualThanValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class LesserOrEqualThanValidator(private val target: Number) : PropertyValidatorBase() { 20 | override fun isValid(result: Any?): Boolean { 21 | if (result is Number) { 22 | return result.toDouble() <= target.toDouble() 23 | } else if (result == null) { 24 | return true 25 | } else { 26 | return false 27 | } 28 | } 29 | 30 | override fun toString(): String { 31 | return "Lesser or equal than validator, expected value to be less than: $target" 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/LesserThanValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class LesserThanValidator(private val target: Number) : PropertyValidatorBase() { 20 | override fun isValid(result: Any?): Boolean { 21 | if (result is Number) { 22 | return result.toDouble() < target.toDouble() 23 | } else if (result == null) { 24 | return true 25 | } else { 26 | return false 27 | } 28 | } 29 | 30 | override fun toString(): String { 31 | return "Lesser than validator, expected value to be less than: $target" 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/NonNullValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class NonNullValidator : PropertyValidatorBase() { 20 | 21 | override fun isValid(result: Any?): Boolean { 22 | return result != null 23 | } 24 | 25 | override fun toString(): String { 26 | return "Non null validator" 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/NotEqualValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class NotEqualValidator(private val other: Any?) : PropertyValidatorBase() { 20 | 21 | override fun isValid(result: Any?): Boolean { 22 | return result != other 23 | } 24 | 25 | override fun toString(): String { 26 | return "Not equal validator, expected not to be equal to: $other" 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/NullValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class NullValidator : PropertyValidatorBase() { 20 | 21 | override fun isValid(result: Any?): Boolean { 22 | return result == null 23 | } 24 | 25 | override fun toString(): String { 26 | return "Null validator" 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/PatternValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | import java.util.regex.Pattern 20 | 21 | open internal class PatternValidator(private val pattern: Pattern) : PropertyValidatorBase() { 22 | 23 | override fun isValid(result: Any?): Boolean { 24 | if (result == null) { 25 | return true 26 | } 27 | 28 | val matcher = pattern.matcher(result.toString()) 29 | return matcher.matches() 30 | } 31 | 32 | override fun toString(): String { 33 | return "Pattern validator, expected pattern to match $pattern" 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/PropertyValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | import com.markodevcic.kvalidation.errors.ErrorLevel 20 | import com.markodevcic.kvalidation.messages.MessageBuilder 21 | 22 | interface PropertyValidator { 23 | fun isValid(result: Any?): Boolean 24 | var precondition: ((Any) -> Boolean)? 25 | var messageBuilder: MessageBuilder? 26 | var errorCode: Int? 27 | var errorLevel: ErrorLevel 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/PropertyValidatorBase.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | import com.markodevcic.kvalidation.errors.ErrorLevel 20 | import com.markodevcic.kvalidation.messages.MessageBuilder 21 | 22 | abstract internal class PropertyValidatorBase : PropertyValidator { 23 | 24 | protected var _precondition: ((Any) -> Boolean)? = null 25 | override var precondition: ((Any) -> Boolean)? 26 | get() = _precondition 27 | set(value) { 28 | _precondition = value 29 | } 30 | 31 | protected var _messageBuilder: MessageBuilder? = null 32 | override var messageBuilder: MessageBuilder? 33 | get() = _messageBuilder 34 | set(value) { 35 | _messageBuilder = value 36 | } 37 | 38 | private var _errorCode: Int? = null 39 | override var errorCode: Int? 40 | get() = _errorCode 41 | set(value) { 42 | _errorCode = value 43 | } 44 | 45 | protected var _errorLevel = ErrorLevel.ERROR 46 | override var errorLevel: ErrorLevel 47 | get() = _errorLevel 48 | set(value) { 49 | _errorLevel = value 50 | } 51 | 52 | override fun toString(): String { 53 | return "Custom validator" 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/markodevcic/kvalidation/validators/RangeValidator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2016, Marko Devcic, madevcic@gmail.com, http://www.markodevcic.com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package com.markodevcic.kvalidation.validators 18 | 19 | internal class RangeValidator(private val min: Number, private val max: Number) : PropertyValidatorBase() { 20 | 21 | override fun isValid(result: Any?): Boolean { 22 | if (result is Number) { 23 | val resultDouble = result.toDouble() 24 | return resultDouble >= min.toDouble() && resultDouble <= max.toDouble() 25 | } else if (result == null) { 26 | return true 27 | } 28 | return false 29 | } 30 | 31 | override fun toString(): String { 32 | return "Range validator, expected to be between $min and $max" 33 | } 34 | } -------------------------------------------------------------------------------- /src/test/java/com/markodevcic/kvalidation/JavaTest.java: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class JavaTest { 7 | 8 | @Test 9 | public void testNonNullValidator() { 10 | TestObject testObject = new TestObject(); 11 | TestObjectValidator validator = new TestObjectValidator(testObject); 12 | 13 | validator.forProperty(TestObject::getName).nonNull(); 14 | 15 | ValidationResult result = validator.validate(); 16 | Assert.assertTrue(result.isValid()); 17 | Assert.assertTrue(result.getValidationErrors().isEmpty()); 18 | } 19 | 20 | @Test 21 | public void testRulesChaining() { 22 | TestObject testObject = new TestObject(); 23 | TestObjectValidator validator = new TestObjectValidator(testObject); 24 | 25 | validator.forProperty(TestObject::getName) 26 | .nonNull() 27 | .length(3, 6) 28 | .mustBe(s -> s.startsWith("J")) 29 | .onError() 30 | .propertyName("name"); 31 | 32 | testObject.setName("Patrick"); 33 | ValidationResult result = validator.validate(); 34 | Assert.assertFalse(result.isValid()); 35 | Assert.assertEquals(2, result.getValidationErrors().size()); 36 | 37 | testObject.setName("John"); 38 | result = validator.validate(); 39 | Assert.assertTrue(result.isValid()); 40 | Assert.assertEquals(0, result.getValidationErrors().size()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/AbstractValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation 2 | 3 | import com.markodevcic.kvalidation.errors.ErrorLevel 4 | import org.junit.Assert 5 | import org.junit.Test 6 | 7 | class AbstractValidatorTests { 8 | 9 | @Test 10 | fun testOnAllErrorSet() { 11 | val testObject = TestObject() 12 | val validator = TestObjectValidator(testObject) 13 | 14 | validator.forProperty { t -> t.name } rules { 15 | length(4) 16 | mustBe { t -> t!!.startsWith("J") } 17 | equal("John") 18 | } onError { 19 | errorLevel(ErrorLevel.WARNING) 20 | } 21 | validator.strategy = ValidationStrategy.FULL 22 | 23 | testObject.name = "Patrick" 24 | 25 | val result = validator.validate() 26 | Assert.assertFalse(result.isValid) 27 | Assert.assertEquals(3, result.validationErrors.size) 28 | result.validationErrors.forEach { e -> Assert.assertEquals(ErrorLevel.WARNING, e.level) } 29 | } 30 | 31 | @Test 32 | fun testOnAllMessageSet() { 33 | val testObject = TestObject() 34 | val validator = TestObjectValidator(testObject) 35 | 36 | validator.forProperty { t -> t.name } rules { 37 | length(4) 38 | mustBe { t -> t!!.startsWith("J") } 39 | equal("John") 40 | } onError { 41 | errorMessage("fail") 42 | } 43 | validator.strategy = ValidationStrategy.FULL 44 | 45 | testObject.name = "Patrick" 46 | 47 | val result = validator.validate() 48 | Assert.assertFalse(result.isValid) 49 | Assert.assertEquals(3, result.validationErrors.size) 50 | result.validationErrors.forEach { e -> Assert.assertEquals("fail", e.message) } 51 | } 52 | 53 | @Test 54 | fun testNoRulesSet() { 55 | val testObject = TestObject() 56 | val validator = TestObjectValidator(testObject) 57 | 58 | val result = validator.validate() 59 | Assert.assertTrue(result.isValid) 60 | Assert.assertEquals(0, result.validationErrors.size) 61 | } 62 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/PreconditionTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation 2 | 3 | import org.junit.Assert 4 | import org.junit.Test 5 | 6 | class PreconditionTests { 7 | 8 | @Test 9 | fun testPredicateOnRuleBuilder() { 10 | val testObject = TestObject() 11 | val validator = TestObjectValidator(testObject) 12 | 13 | validator.forProperty { t -> t.name } 14 | .mustBe { v -> v!!.length == 5 } 15 | .whenIs { t -> t.name != null } 16 | 17 | testObject.name = null 18 | 19 | var result = validator.validate() 20 | Assert.assertTrue(result.isValid) 21 | Assert.assertTrue(result.validationErrors.size == 0) 22 | 23 | testObject.name = "" 24 | result = validator.validate() 25 | Assert.assertFalse(result.isValid) 26 | Assert.assertTrue(result.validationErrors.size == 1) 27 | 28 | testObject.name = "Frank" 29 | result = validator.validate() 30 | Assert.assertTrue(result.isValid) 31 | Assert.assertTrue(result.validationErrors.size == 0) 32 | } 33 | 34 | @Test 35 | fun testPredicateOnRuleSetter() { 36 | val testObject = TestObject() 37 | val validator = TestObjectValidator(testObject) 38 | 39 | validator.forProperty { t -> t.name } rules { 40 | mustBe { v -> v!!.length == 5 } 41 | whenIs { t -> t.name != null } 42 | } 43 | 44 | testObject.name = null 45 | 46 | var result = validator.validate() 47 | Assert.assertTrue(result.isValid) 48 | Assert.assertTrue(result.validationErrors.size == 0) 49 | 50 | testObject.name = "" 51 | result = validator.validate() 52 | Assert.assertFalse(result.isValid) 53 | Assert.assertTrue(result.validationErrors.size == 1) 54 | 55 | testObject.name = "Frank" 56 | result = validator.validate() 57 | Assert.assertTrue(result.isValid) 58 | Assert.assertTrue(result.validationErrors.size == 0) 59 | } 60 | 61 | @Test 62 | fun testPredicatesOn2Rules() { 63 | val testObject = TestObject() 64 | val validator = TestObjectValidator(testObject) 65 | 66 | validator.forProperty { t -> t.name } 67 | .mustBe { v -> v!!.length == 0 } 68 | .whenIs { t -> t.position == 0 } 69 | .mustBe { v -> v!!.length == 1 } 70 | .whenIs { t -> t.position == 1 } 71 | 72 | testObject.name = "" 73 | testObject.position = 3 74 | 75 | var result = validator.validate() 76 | Assert.assertTrue(result.isValid) 77 | Assert.assertEquals(0, result.validationErrors.size) 78 | 79 | testObject.name = "AB" 80 | testObject.position = 0 81 | 82 | result = validator.validate() 83 | Assert.assertFalse(result.isValid) 84 | Assert.assertEquals(1, result.validationErrors.size) 85 | 86 | testObject.name = "" 87 | testObject.position = 0 88 | 89 | result = validator.validate() 90 | Assert.assertTrue(result.isValid) 91 | Assert.assertEquals(0, result.validationErrors.size) 92 | 93 | testObject.name = "A" 94 | testObject.position = 1 95 | 96 | result = validator.validate() 97 | Assert.assertTrue(result.isValid) 98 | Assert.assertEquals(0, result.validationErrors.size) 99 | 100 | testObject.name = "" 101 | testObject.position = 1 102 | 103 | result = validator.validate() 104 | Assert.assertFalse(result.isValid) 105 | Assert.assertEquals(1, result.validationErrors.size) 106 | } 107 | 108 | @Test 109 | fun testRuleBuilderOnAllPrecondition() { 110 | val testObject = TestObject() 111 | val validator = TestObjectValidator(testObject) 112 | 113 | validator.forProperty { t -> t.name } 114 | .mustBe { v -> v != null && v.length == 5 } 115 | .length(10) 116 | .whenIsOnAll { t -> t.position == 1 } 117 | 118 | testObject.name = "" 119 | testObject.position = 0 120 | 121 | val result = validator.validate() 122 | Assert.assertTrue(result.isValid) 123 | } 124 | 125 | @Test 126 | fun testRuleSetterOnAllPrecondition() { 127 | val testObject = TestObject() 128 | val validator = TestObjectValidator(testObject) 129 | 130 | validator.forProperty { t -> t.name } rules { 131 | mustBe { v -> v != null && v.length == 5 } 132 | length(10) 133 | whenIsOnAll { t -> t.position == 1 } 134 | } 135 | 136 | testObject.name = "" 137 | testObject.position = 0 138 | 139 | val result = validator.validate() 140 | Assert.assertTrue(result.isValid) 141 | } 142 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/TestObject.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation 2 | 3 | open class TestObject { 4 | var name: String? = "John" 5 | var position: Int? = 10 6 | var weight: Double? = 75.6 7 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/TestObjectValidator.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation 2 | 3 | class TestObjectValidator(testObject: TestObject) : ValidatorBase(testObject) { 4 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/messages/DefaultMessageBuilderTest.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.messages 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import com.markodevcic.kvalidation.onError 6 | import com.markodevcic.kvalidation.rules 7 | import org.junit.Assert 8 | import org.junit.Test 9 | 10 | class DefaultMessageBuilderTest { 11 | 12 | @Test 13 | fun testErrorMessageErrorSetter() { 14 | val testObject = TestObject() 15 | val validator = TestObjectValidator(testObject) 16 | 17 | validator.forProperty { t -> t.position } rules { 18 | gt(1000) 19 | notEqual(0) 20 | lt(1) 21 | inRange(300, 30000) 22 | } onError { 23 | errorMessage("you failed") 24 | propertyName("position") 25 | } 26 | 27 | testObject.position = 2 28 | 29 | val result = validator.validate() 30 | val errors = result.validationErrors 31 | errors.forEach { e -> Assert.assertTrue(e.message == "you failed") } 32 | } 33 | 34 | @Test 35 | fun testErrorMessageErrorBuilder() { 36 | val testObject = TestObject() 37 | val validator = TestObjectValidator(testObject) 38 | 39 | validator.forProperty { t -> t.position } 40 | .gt(1000) 41 | .notEqual(0) 42 | .lt(1) 43 | .inRange(300, 30000) 44 | .onError() 45 | .errorMessage("you failed") 46 | .propertyName("position") 47 | 48 | testObject.position = 2 49 | 50 | val result = validator.validate() 51 | val errors = result.validationErrors 52 | errors.forEach { e -> Assert.assertTrue(e.message == "you failed") } 53 | } 54 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/ContainsValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import com.markodevcic.kvalidation.rules 6 | import org.junit.Assert 7 | import org.junit.Test 8 | 9 | class ContainsValidatorTests{ 10 | 11 | @Test 12 | fun testContains() { 13 | val testObject = TestObject() 14 | val validator = TestObjectValidator(testObject) 15 | 16 | val set = hashSetOf("John", "Patrick", "David") 17 | 18 | validator.forProperty { t -> t.name } rules { 19 | isContainedIn(set) 20 | } 21 | 22 | testObject.name = "John" 23 | 24 | val result = validator.validate() 25 | Assert.assertTrue(result.isValid) 26 | } 27 | 28 | @Test 29 | fun testNotContained() { 30 | val testObject = TestObject() 31 | val validator = TestObjectValidator(testObject) 32 | 33 | val set = hashSetOf("John", "Patrick", "David") 34 | 35 | validator.forProperty { t -> t.name } rules { 36 | isContainedIn(set) 37 | } 38 | 39 | testObject.name = "Johnny" 40 | 41 | val result = validator.validate() 42 | Assert.assertFalse(result.isValid) 43 | } 44 | 45 | @Test 46 | fun testNullValue() { 47 | val testObject = TestObject() 48 | val validator = TestObjectValidator(testObject) 49 | 50 | val set = hashSetOf("John", "Patrick", "David") 51 | 52 | validator.forProperty { t -> t.name } rules { 53 | isContainedIn(set) 54 | } 55 | 56 | testObject.name = null 57 | 58 | val result = validator.validate() 59 | Assert.assertFalse(result.isValid) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/CustomValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import com.markodevcic.kvalidation.rules 6 | import org.junit.Assert 7 | import org.junit.Test 8 | 9 | class CustomValidatorTests { 10 | @Test 11 | fun testCustomValidator() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.position } 16 | .mustBe { v -> v == 10 } 17 | 18 | testObject.position = 1 19 | val failResult = validator.validate() 20 | Assert.assertFalse(failResult.isValid) 21 | Assert.assertTrue(failResult.validationErrors.size == 1) 22 | 23 | testObject.position = 10 24 | val okResult = validator.validate() 25 | Assert.assertTrue(okResult.isValid) 26 | Assert.assertTrue(okResult.validationErrors.size == 0) 27 | } 28 | 29 | @Test 30 | fun testNullableField() { 31 | val testObject = TestObject() 32 | val validator = TestObjectValidator(testObject) 33 | 34 | validator.forProperty { t -> t.position } rules { 35 | notEqual(Int.MAX_VALUE) 36 | lte(10) 37 | gte(5) 38 | } 39 | 40 | testObject.position = 33 41 | val result = validator.validate() 42 | Assert.assertFalse(result.isValid) 43 | Assert.assertEquals(1, result.validationErrors.size) 44 | 45 | validator.forProperty { t -> t.position } rules { 46 | lt(45) 47 | gt(5) 48 | notEqual(40) 49 | whenIsOnAll { t -> t.position != null } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/EmailValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import com.markodevcic.kvalidation.rules 6 | import org.junit.Assert 7 | import org.junit.Test 8 | 9 | class EmailValidatorTests{ 10 | @Test 11 | fun testValidEmail() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.name } rules { 16 | email() 17 | } 18 | testObject.name = "david@gmail.com" 19 | 20 | val result = validator.validate() 21 | Assert.assertTrue(result.isValid) 22 | } 23 | 24 | @Test 25 | fun testInValidEmail() { 26 | val testObject = TestObject() 27 | val validator = TestObjectValidator(testObject) 28 | 29 | validator.forProperty { t -> t.name } rules { 30 | email() 31 | } 32 | 33 | testObject.name = "david@david@gmail.com" 34 | 35 | val result = validator.validate() 36 | Assert.assertFalse(result.isValid) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/EmptyValidatorTest.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.InnerValidator 4 | import com.markodevcic.kvalidation.rules 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class EmptyValidatorTest { 9 | private class Testable { 10 | var collection = listOf() 11 | } 12 | 13 | private val testable = Testable() 14 | private val validator = InnerValidator(testable) 15 | 16 | @Test 17 | fun testEmptyCollection() { 18 | validator.clearAll() 19 | validator.forProperty { t -> t.collection } rules { 20 | empty() 21 | } 22 | 23 | testable.collection = listOf() 24 | 25 | val result = validator.validate() 26 | Assert.assertTrue(result.isValid) 27 | } 28 | 29 | @Test 30 | fun testNonEmptyCollection() { 31 | validator.clearAll() 32 | validator.forProperty { t -> t.collection } rules { 33 | empty() 34 | } 35 | 36 | testable.collection = listOf("aa") 37 | 38 | val result = validator.validate() 39 | Assert.assertFalse(result.isValid) 40 | } 41 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/EqualValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class EqualValidatorTests { 9 | 10 | @Test 11 | fun testEqualDoubles() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.weight } equal Double.NaN 16 | 17 | testObject.weight = 75.0 18 | var result = validator.validate() 19 | Assert.assertFalse(result.isValid) 20 | 21 | testObject.weight = Double.NaN 22 | result = validator.validate() 23 | Assert.assertTrue(result.isValid) 24 | } 25 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/GreaterOrEqualThanValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class GreaterOrEqualThanValidatorTests { 9 | 10 | @Test 11 | fun testGreaterThanInt() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.position } 16 | .gte(100) 17 | 18 | testObject.position = 100 19 | var result = validator.validate() 20 | Assert.assertTrue(result.isValid) 21 | 22 | testObject.position = 90 23 | result = validator.validate() 24 | Assert.assertFalse(result.isValid) 25 | } 26 | 27 | @Test 28 | fun testGreaterThanDouble() { 29 | val testObject = TestObject() 30 | val validator = TestObjectValidator(testObject) 31 | 32 | validator.forProperty { t -> t.weight } 33 | .gte(100.0) 34 | 35 | testObject.weight = 100.0 36 | var result = validator.validate() 37 | Assert.assertTrue(result.isValid) 38 | 39 | testObject.weight = 99.9 40 | result = validator.validate() 41 | Assert.assertFalse(result.isValid) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/GreaterThanValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class GreaterThanValidatorTests { 9 | 10 | @Test 11 | fun testGreaterThanInt() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.position } 16 | .gt(100) 17 | 18 | testObject.position = 101 19 | var result = validator.validate() 20 | Assert.assertTrue(result.isValid) 21 | 22 | testObject.position = 90 23 | result = validator.validate() 24 | Assert.assertFalse(result.isValid) 25 | } 26 | 27 | @Test 28 | fun testGreaterThanDouble() { 29 | val testObject = TestObject() 30 | val validator = TestObjectValidator(testObject) 31 | 32 | validator.forProperty { t -> t.weight } 33 | .gt(100.0) 34 | 35 | testObject.weight = 100.1 36 | var result = validator.validate() 37 | Assert.assertTrue(result.isValid) 38 | 39 | testObject.weight = 99.9 40 | result = validator.validate() 41 | Assert.assertFalse(result.isValid) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/LengthValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class LengthValidatorTests { 9 | 10 | @Test 11 | fun testMaxLength() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.name } 16 | .length(6) 17 | 18 | testObject.name = "John" 19 | var result = validator.validate() 20 | Assert.assertTrue(result.isValid) 21 | Assert.assertEquals(0, result.validationErrors.size) 22 | 23 | testObject.name = "Patrick" 24 | result = validator.validate() 25 | Assert.assertFalse(result.isValid) 26 | Assert.assertEquals(1, result.validationErrors.size) 27 | } 28 | 29 | @Test 30 | fun testMinAndMaxLength() { 31 | val testObject = TestObject() 32 | val validator = TestObjectValidator(testObject) 33 | 34 | validator.forProperty { t -> t.name } 35 | .length(3, 6) 36 | 37 | testObject.name = "John" 38 | var result = validator.validate() 39 | Assert.assertTrue(result.isValid) 40 | Assert.assertEquals(0, result.validationErrors.size) 41 | 42 | testObject.name = "Patrick" 43 | result = validator.validate() 44 | Assert.assertFalse(result.isValid) 45 | Assert.assertEquals(1, result.validationErrors.size) 46 | 47 | testObject.name = "" 48 | result = validator.validate() 49 | Assert.assertFalse(result.isValid) 50 | Assert.assertEquals(1, result.validationErrors.size) 51 | } 52 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/LesserOrEqualThanValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class LesserOrEqualThanValidatorTests { 9 | 10 | @Test 11 | fun testLesserThanInt() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.position } 16 | .lte(200) 17 | 18 | testObject.position = 200 19 | var result = validator.validate() 20 | Assert.assertTrue(result.isValid) 21 | 22 | testObject.position = 201 23 | result = validator.validate() 24 | Assert.assertFalse(result.isValid) 25 | } 26 | 27 | @Test 28 | fun testLesserThanDouble() { 29 | val testObject = TestObject() 30 | val validator = TestObjectValidator(testObject) 31 | 32 | validator.forProperty { t -> t.weight } 33 | .lte(100.0) 34 | 35 | testObject.weight = 100.0 36 | var result = validator.validate() 37 | Assert.assertTrue(result.isValid) 38 | 39 | testObject.weight = 100.1 40 | result = validator.validate() 41 | Assert.assertFalse(result.isValid) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/LesserThanValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class LesserThanValidatorTests { 9 | 10 | @Test 11 | fun testLesserThanInt() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.position } 16 | .lt(200) 17 | 18 | testObject.position = 100 19 | var result = validator.validate() 20 | Assert.assertTrue(result.isValid) 21 | 22 | testObject.position = 200 23 | result = validator.validate() 24 | Assert.assertFalse(result.isValid) 25 | } 26 | 27 | @Test 28 | fun testLesserThanDouble() { 29 | val testObject = TestObject() 30 | val validator = TestObjectValidator(testObject) 31 | 32 | validator.forProperty { t -> t.weight } 33 | .lt(100.0) 34 | 35 | testObject.weight = 99.9 36 | var result = validator.validate() 37 | Assert.assertTrue(result.isValid) 38 | 39 | testObject.weight = 100.0 40 | result = validator.validate() 41 | Assert.assertFalse(result.isValid) 42 | } 43 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/NonNullValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | 9 | class NonNullValidatorTests { 10 | 11 | @Test 12 | fun testNonNull() { 13 | val testObject = TestObject() 14 | val validator = TestObjectValidator(testObject) 15 | validator.forProperty { t -> t.name } 16 | .nonNull() 17 | 18 | testObject.name = null 19 | var validationResult = validator.validate() 20 | Assert.assertFalse(validationResult.isValid) 21 | Assert.assertEquals(1, validationResult.validationErrors.size) 22 | 23 | testObject.name = "John" 24 | validationResult = validator.validate() 25 | Assert.assertTrue(validationResult.isValid) 26 | Assert.assertEquals(0, validationResult.validationErrors.size) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/NotEqualValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class NotEqualValidatorTests { 9 | 10 | @Test 11 | fun testNotEqualDoubles() { 12 | val testObject = TestObject() 13 | val validator = TestObjectValidator(testObject) 14 | 15 | validator.forProperty { t -> t.weight } 16 | .notEqual(Double.NaN) 17 | 18 | testObject.weight = 75.0 19 | var result = validator.validate() 20 | Assert.assertTrue(result.isValid) 21 | 22 | testObject.weight = Double.NaN 23 | result = validator.validate() 24 | Assert.assertFalse(result.isValid) 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/markodevcic/kvalidation/validators/NullValidatorTests.kt: -------------------------------------------------------------------------------- 1 | package com.markodevcic.kvalidation.validators 2 | 3 | import com.markodevcic.kvalidation.TestObject 4 | import com.markodevcic.kvalidation.TestObjectValidator 5 | import org.junit.Assert 6 | import org.junit.Test 7 | 8 | class NullValidatorTests { 9 | @Test 10 | fun testNonNull() { 11 | val testObject = TestObject() 12 | val validator = TestObjectValidator(testObject) 13 | validator.forProperty { t -> t.name } 14 | .isNull() 15 | 16 | testObject.name = null 17 | var validationResult = validator.validate() 18 | Assert.assertTrue(validationResult.isValid) 19 | Assert.assertEquals(0, validationResult.validationErrors.size) 20 | 21 | testObject.name = "John" 22 | validationResult = validator.validate() 23 | Assert.assertFalse(validationResult.isValid) 24 | Assert.assertEquals(1, validationResult.validationErrors.size) 25 | } 26 | } --------------------------------------------------------------------------------