Skip to content

Commit

Permalink
Merge pull request #135 from atschabu/utf8validator
Browse files Browse the repository at this point in the history
fix(validation) #119: allow valid UTF8 values
  • Loading branch information
lilgallon authored Oct 3, 2024
2 parents ccd627d + 7e4a362 commit 35a3b49
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ class RegularHoursSetAtTheSameTimeAsTwentyFourSevenConstraint : Constraint
data class SameStringValueConstraint(val reference: String) : Constraint

fun String.isPrintableAscii(): Boolean = matches("[\\x20-\\x7E]*".toRegex())
fun String.isPrintableUtf8(): Boolean = matches("[\\x20-\\x7E]*".toRegex())
fun String.isNonPrintableUtf8(): Boolean = matches(".*[\\x00-\\x1F\\x7F\\x80-\\x9F]+.*".toRegex()) // C0, DEL, C1

/**
* Valid if the given string only has printable ASCII characters and is smaller or has the same length as the given one.
*/
fun <E> Validator<E>.Property<String?>.isPrintableUtf8() =
this.validate(PrintableUtf8Constraint()) {
it == null || it.isPrintableUtf8()
it == null || !it.isNonPrintableUtf8()
}

/**
Expand Down Expand Up @@ -207,7 +207,7 @@ fun PricePartial.validate(): PricePartial = validate(this) {
fun DisplayTextPartial.validate(): DisplayTextPartial = validate(this) {
validate(DisplayTextPartial::language).isLanguage()
validate(DisplayTextPartial::text)
.isPrintableAscii()
.isPrintableUtf8()
.hasNoHtml()
.hasMaxLengthOf(512)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ EncodingMethod field.
@Partial
data class SignedValue(
val nature: CiString,
val plainData: CiString,
val signedData: CiString,
val plainData: String,
val signedData: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fun CdrPartial.validate(): CdrPartial =
validate(CdrPartial::totalParkingTime).isBigDecimalPositive()
totalParkingCost?.validate()
totalReservationCost?.validate()
validate(CdrPartial::remark).isPrintableAscii().hasMaxLengthOf(255)
validate(CdrPartial::remark).isPrintableUtf8().hasMaxLengthOf(255)
validate(CdrPartial::invoiceReferenceId).isPrintableAscii().hasMaxLengthOf(39)
// credit: nothing to validate
validate(CdrPartial::creditReferenceId).isPrintableAscii().hasMaxLengthOf(39)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,45 +195,59 @@ fun ConnectorPartial.validate(): ConnectorPartial = validate(this) {
fun Location.validate(): Location = validate(this) {
toPartial().validate()
}

fun EnvironmentalImpact.validate(): EnvironmentalImpact = validate(this) {
toPartial().validate()
}

fun EnergySource.validate(): EnergySource = validate(this) {
toPartial().validate()
}

fun EnergyMix.validate(): EnergyMix = validate(this) {
toPartial().validate()
}

fun ExceptionalPeriod.validate(): ExceptionalPeriod = validate(this) {
toPartial().validate()
}

fun RegularHours.validate(): RegularHours = validate(this) {
toPartial().validate()
}
fun Hours.validate(): Hours = validate(this) { hours ->

fun Hours.validate(): Hours = validate(this) {
toPartial().validate()
}

fun Image.validate(): Image = validate(this) {
toPartial().validate()
}

fun BusinessDetails.validate(): BusinessDetails = validate(this) {
toPartial().validate()
}

fun GeoLocation.validate(): GeoLocation = validate(this) {
toPartial().validate()
}

fun AdditionalGeoLocation.validate(): AdditionalGeoLocation = validate(this) {
toPartial().validate()
}

fun DisplayText.validate(): DisplayText = validate(this) {
toPartial().validate()
}

fun StatusSchedule.validate(): StatusSchedule = validate(this) {
toPartial().validate()
}

fun Evse.validate(): Evse = validate(this) {
toPartial().validate()
}

fun Connector.validate(): Connector = validate(this) {
toPartial().validate()
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ fun TokenPartial.validate(): TokenPartial = validate(this) {
validate(TokenPartial::uid).isPrintableAscii().hasMaxLengthOf(36)
// type : nothing to validate
validate(TokenPartial::contractId).isPrintableAscii().hasMaxLengthOf(36)
validate(TokenPartial::visualNumber).isPrintableAscii().hasMaxLengthOf(64)
validate(TokenPartial::issuer).isPrintableAscii().hasMaxLengthOf(64)
validate(TokenPartial::visualNumber).isPrintableUtf8().hasMaxLengthOf(64)
validate(TokenPartial::issuer).isPrintableUtf8().hasMaxLengthOf(64)
validate(TokenPartial::groupId).isPrintableAscii().hasMaxLengthOf(36)
// valid : nothing to validate
// whitelist : nothing to validate
Expand Down Expand Up @@ -55,11 +55,11 @@ fun LocationReferencesPartial.validate(): LocationReferencesPartial = validate(t
}

fun EnergyContractPartial.validate(): EnergyContractPartial = validate(this) {
validate(EnergyContractPartial::supplierName).isPrintableAscii().hasMaxLengthOf(64)
validate(EnergyContractPartial::supplierName).isPrintableUtf8().hasMaxLengthOf(64)
validate(EnergyContractPartial::contractId).isPrintableAscii().hasMaxLengthOf(64)
}

fun DisplayText.validate(): DisplayText = org.valiktor.validate(this) {
fun DisplayText.validate(): DisplayText = validate(this) {
toPartial().validate()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ class LocationsValidatorTest {
fun `BusinessDetails validator`() {
expectCatching {
validBusinessDetails.validate()
validBusinessDetails.copy(name = validUtf8String).validate()
validBusinessDetails.copy(website = null).validate()
validBusinessDetails.copy(logo = null).validate()
}.isSuccess()
Expand All @@ -494,6 +495,10 @@ class LocationsValidatorTest {
validBusinessDetails.copy(name = generateRandomString(101)).validate()
}.isFailure()

expectCatching {
validBusinessDetails.copy(name = "with non-printable: \n").validate()
}.isFailure()

expectCatching {
validBusinessDetails.copy(website = "not an url").validate()
}.isFailure()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import java.time.Instant
val validUrl = "https://abc.com"
val validLatitude = "-15.234567"
val validLongitude = "23.234567"
val validUtf8String = "abc 1234 èñü 谢谢"

val validStatusSchedule = StatusSchedule(
periodBegin = Instant.parse("2022-04-28T08:00:00.000Z"),
Expand All @@ -18,7 +19,7 @@ val validStatusSchedule = StatusSchedule(

val validDisplayText = DisplayText(
language = "fr",
text = "abcdef",
text = validUtf8String,
)

val validGeoLocation = GeoLocation(
Expand Down

0 comments on commit 35a3b49

Please sign in to comment.