Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add @pattern support for constraint package #29

Merged
merged 14 commits into from
Jan 17, 2023
Merged
1 change: 0 additions & 1 deletion ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,3 @@ modules = [
{org = "ballerina", packageName = "test", moduleName = "test"}
]


2 changes: 2 additions & 0 deletions ballerina/constraint.bal
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,12 @@ public type NumberConstraints record {|
# + length - The number of characters of the constrained `string` type
# + minLength - The inclusive lower bound of the number of characters of the constrained `string` type
# + maxLength - The inclusive upper bound of the number of characters of the constrained `string` type
# + pattern - The regular expression to be matched with the constrained `string` type
public type StringConstraints record {|
int length?;
int minLength?;
int maxLength?;
string:RegExp pattern?;
|};

# Represents the constraints associated with `anydata[]` type.
Expand Down
26 changes: 25 additions & 1 deletion ballerina/tests/advanced_constraint_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,30 @@ type Person record {
minValue: 18
}
int age;
@String {
pattern: re `([a-zA-Z0-9._%\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,6})*`
}
string email?;
};

@test:Config {}
isolated function testMultipleConstraintSuccess() {
isolated function testMultipleConstraintSuccess1() {
Person rec = {name: "Steve", age: 18};
Person|error validation = validate(rec);
if validation is error {
test:assertFail("Unexpected error found.");
}
}

@test:Config {}
isolated function testMultipleConstraintSuccess2() {
Person rec = {name: "James", age: 18, email: "[email protected]"};
Person|error validation = validate(rec);
if validation is error {
test:assertFail("Unexpected error found.");
}
}

@test:Config {}
isolated function testMultipleConstraintFailure1() {
Person rec = {name: "John", age: 18};
Expand Down Expand Up @@ -83,6 +96,17 @@ isolated function testMultipleConstraintFailure4() {
}
}

@test:Config {}
isolated function testMultipleConstraintFailure5() {
Person rec = {name: "Joe", age: 16, email: "#invalid?mail&address"};
Person|error validation = validate(rec);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.age:minValue','$.email:pattern','$.name:minLength' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

// Testing multiple types of annotations in a single record field

type Student record {
Expand Down
19 changes: 19 additions & 0 deletions ballerina/tests/example_constraint_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ final json & readonly SAMPLE_PAYLOAD = {
"payment_gateway_names": [

],
"phone": "+94123456789",
"presentment_currency": "LKR",
"processed_at": "2022-06-28T15:28:38+05:30",
"processing_method": "",
Expand Down Expand Up @@ -485,6 +486,20 @@ isolated function testSampleFailure11() returns error? {
}
}

@test:Config {}
function testSampleFailure12() returns error? {
Order rec = check SAMPLE_PAYLOAD.cloneWithType();
rec.phone = "1234abcd90";
rec.email = "invalid_email?address@";
rec.customer.email = "This is a invalid email";
Order|error validation = validate(rec);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.customer.email:pattern','$.email:pattern','$.phone:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

public type Order record {
int app_id?;
CustomerAddress billing_address?;
Expand Down Expand Up @@ -514,6 +529,7 @@ public type Order record {
string customer_locale?;
DiscountApplication[] discount_applications?;
DiscountCode[] discount_codes?;
@String {pattern: re `([a-zA-Z0-9._%\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,6})*`}
string email?;
boolean estimated_taxes?;
string financial_status?;
Expand All @@ -535,6 +551,7 @@ public type Order record {
string payment_details?;
PaymentTerms payment_terms?;
string[] payment_gateway_names?;
@String {pattern: re `([0-9]{10})|(\+[0-9]{11})`}
string phone?;
@String {length: 3}
string presentment_currency?;
Expand Down Expand Up @@ -629,6 +646,7 @@ public type Customer record {
string currency?;
string created_at?;
string first_name?;
@String {pattern: re `([a-zA-Z0-9._%\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,6})*`}
string email?;
Address default_address?;
int id?;
Expand All @@ -641,6 +659,7 @@ public type Customer record {
string note?;
@Int {minValueExclusive: 0}
int orders_count?;
@String {pattern: re `([0-9]{10})|(\+[0-9]{11})`}
string phone?;
SmsMarketingConsent sms_marketing_consent?;
string state?;
Expand Down
54 changes: 52 additions & 2 deletions ballerina/tests/string_constraint_on_record_field_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,45 @@ isolated function testStringConstraintMaxLengthOnRecordFieldFailure() {
}
}

type StringConstraintPatternOnRecordField record {
@String {
pattern: re `[0-9]{9}[v|V]|[0-9]{12}`
}
string value;
};

@test:Config {}
function StringConstraintPatternOnRecordFieldSuccess() {
StringConstraintPatternOnRecordField typ = {value: "964537342v"};
StringConstraintPatternOnRecordField|error validation = validate(typ);
if validation is error {
test:assertFail("Unexpected error found.");
}
}

@test:Config {}
function StringConstraintPatternOnRecordFieldFailure() {
StringConstraintPatternOnRecordField typ = {value: "9b4s37342v"};
StringConstraintPatternOnRecordField|error validation = validate(typ);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.value:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

type StringConstraintOnRecordField record {
@String {
minLength: 6,
maxLength: 12
maxLength: 12,
pattern: re `[a-z0-9](_?[a-z0-9])+`
}
string value;
};

@test:Config {}
isolated function testStringConstraintOnRecordFieldSuccess1() {
StringConstraintOnRecordField rec = {value: "b@!s3cr3t"};
StringConstraintOnRecordField rec = {value: "6a1_s3cr3t"};
StringConstraintOnRecordField|error validation = validate(rec);
if validation is error {
test:assertFail("Unexpected error found.");
Expand Down Expand Up @@ -197,3 +225,25 @@ isolated function testStringConstraintOnRecordFieldFailure2() {
test:assertFail("Expected error not found.");
}
}

@test:Config {}
isolated function testStringConstraintOnRecordFieldFailure3() {
StringConstraintOnRecordField rec = {value: "_6a1_u5er"};
StringConstraintOnRecordField|error validation = validate(rec);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.value:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

@test:Config {}
isolated function testStringConstraintOnRecordFieldFailure4() {
StringConstraintOnRecordField rec = {value: "_6a1_s3cr3t_u5er"};
StringConstraintOnRecordField|error validation = validate(rec);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.value:maxLength','$.value:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,37 @@ isolated function testStringConstraintMaxLengthOnTypeAsRecordFieldFailure() {
}
}

type StringConstraintPatternOnTypeAsRecordField record {
StringConstraintPatternOnType value;
};

@test:Config {}
function StringConstraintPatternOnTypeAsRecordFieldSuccess() {
StringConstraintPatternOnTypeAsRecordField typ = {value: "199645307342"};
StringConstraintPatternOnTypeAsRecordField|error validation = validate(typ);
if validation is error {
test:assertFail("Unexpected error found.");
}
}

@test:Config {}
function StringConstraintPatternOnTypeAsRecordFieldFailure() {
StringConstraintPatternOnTypeAsRecordField typ = {value: "199b453o7342"};
StringConstraintPatternOnTypeAsRecordField|error validation = validate(typ);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.value:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

type StringConstraintOnTypeAsRecordField record {
StringConstraintOnType value;
};

@test:Config {}
isolated function testStringConstraintOnTypeAsRecordFieldSuccess1() {
StringConstraintOnTypeAsRecordField rec = {value: "b@!s3cr3t"};
StringConstraintOnTypeAsRecordField rec = {value: "6a1_s3cr3t"};
StringConstraintOnTypeAsRecordField|error validation = validate(rec);
if validation is error {
test:assertFail("Unexpected error found.");
Expand Down Expand Up @@ -184,3 +208,26 @@ isolated function testStringConstraintOnTypeAsRecordFieldFailure2() {
test:assertFail("Expected error not found.");
}
}

@test:Config {}
isolated function testStringConstraintOnTypeAsRecordFieldFailure3() {
StringConstraintOnTypeAsRecordField rec = {value: "_6a1_u5er"};
StringConstraintOnTypeAsRecordField|error validation = validate(rec);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.value:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

@test:Config {}
isolated function testStringConstraintOnTypeAsRecordFieldFailure4() {
StringConstraintOnTypeAsRecordField rec = {value: "_6a1_s3cr3t_u5er"};
StringConstraintOnTypeAsRecordField|error validation = validate(rec);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$.value:maxLength','$.value:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

72 changes: 70 additions & 2 deletions ballerina/tests/string_constraint_on_type_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,61 @@ isolated function testStringConstraintMaxLengthOnTypeFailure() {
}
}

@String {
pattern: re `[0-9]{9}[v|V]|[0-9]{12}`
}
type StringConstraintPatternOnType string;

@test:Config {}
function testStringConstraintPatternOnTypeSuccess1() {
StringConstraintPatternOnType typ = "964537342V";
StringConstraintPatternOnType|error validation = validate(typ);
if validation is error {
test:assertFail("Unexpected error found.");
}
}

@test:Config {}
function testStringConstraintPatternOnTypeSuccess2() {
StringConstraintPatternOnType typ = "199645370342";
StringConstraintPatternOnType|error validation = validate(typ);
if validation is error {
test:assertFail("Unexpected error found.");
}
}

@test:Config {}
function testStringConstraintPatternOnTypeFailure1() {
StringConstraintPatternOnType typ = "19964537034234";
StringConstraintPatternOnType|error validation = validate(typ);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

@test:Config {}
function testStringConstraintPatternOnTypeFailure2() {
StringConstraintPatternOnType typ = "199645345A";
StringConstraintPatternOnType|error validation = validate(typ);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

@String {
minLength: 6,
maxLength: 12
maxLength: 12,
pattern: re `[a-z0-9](_?[a-z0-9])+`
}
type StringConstraintOnType string;

@test:Config {}
isolated function testStringConstraintOnTypeSuccess1() {
StringConstraintOnType typ = "b@!s3cr3t";
StringConstraintOnType typ = "6a1_s3cr3t";
StringConstraintOnType|error validation = validate(typ);
if validation is error {
test:assertFail("Unexpected error found.");
Expand Down Expand Up @@ -187,3 +233,25 @@ isolated function testStringConstraintOnTypeFailure2() {
test:assertFail("Expected error not found.");
}
}

@test:Config {}
isolated function testStringConstraintOnTypeFailure3() {
StringConstraintOnType typ = "_6a1_u5er";
StringConstraintOnType|error validation = validate(typ);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}

@test:Config {}
isolated function testStringConstraintOnTypeFailure4() {
StringConstraintOnType typ = "_6a1_s3cr3t_u5er";
StringConstraintOnType|error validation = validate(typ);
if validation is error {
test:assertEquals(validation.message(), "Validation failed for '$:maxLength','$:pattern' constraint(s).");
} else {
test:assertFail("Expected error not found.");
}
}
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Fixed
- [Fix unexpected errors due to custom annotations](https://github.com/ballerina-platform/ballerina-standard-library/issues/3817)

### Added
- [Add `@pattern` constraint on string types](https://github.com/ballerina-platform/ballerina-standard-library/issues/3179)

## [1.0.1] - 2022-11-29

### Fixed
Expand Down
Loading