Skip to content

Commit

Permalink
Prepare new class PhoneNumberValidator - currently just reusing Phone…
Browse files Browse the repository at this point in the history
…LibWrapper to access PhoneLib logic. First testcase set taken from PhoneNumberNormalizer as starting point. Define expected behaviour and outcomment all testcases which currently do not work.

Those can be used to test logic addition to capture more detailed behaviour than phone lib. After standard cases work, next phase will be to include special testcases from PhoneNumberUtil test folder.
  • Loading branch information
Anrufliste committed May 1, 2024
1 parent 79e9647 commit bea290e
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 80 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright © 2023 Deutsche Telekom AG ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.telekom.phonenumbernormalizer;

import de.telekom.phonenumbernormalizer.numberplans.PhoneNumberValidationResult;
import de.telekom.phonenumbernormalizer.dto.DeviceContext;

/**
* An interface for dependency injection - for direct use within your code just use {@link PhoneNumberValidatorImpl}.
*/
public interface PhoneNumberValidator {

/**
* Validates the number using PhoneLib with some additions to compensate.
* @param number plain number to validate
* @param regionCode ISO2 code of the country, which number-plan is used for normalization
* @return PhoneNumberValidationResult reason if the number is possible (and maybe its limited context) or why not.
*/
PhoneNumberValidationResult isPhoneNumberPossibleWithReason(String number, String regionCode);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright © 2023 Deutsche Telekom AG ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.telekom.phonenumbernormalizer;

import de.telekom.phonenumbernormalizer.numberplans.PhoneNumberValidationResult;
import de.telekom.phonenumbernormalizer.numberplans.PhoneLibWrapper;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


/**
* Concrete implementation of {@link PhoneNumberValidator} using {@link PhoneLibWrapper} to validate a number by mitigating some inaccuracies when it comes to number plans of optional NDC and NAC as zero.
*/
@RequiredArgsConstructor
@Component
public class PhoneNumberValidatorImpl implements PhoneNumberValidator {

private static final Logger LOGGER = LoggerFactory.getLogger(PhoneNumberValidatorImpl.class);


@Override
public PhoneNumberValidationResult isPhoneNumberPossibleWithReason(String number, String regionCode) {

PhoneLibWrapper wrapper = new PhoneLibWrapper(number, regionCode);

// boolean hasNoCCAndNoNAC = wrapper.hasNoCountryCodeNorNationalAccessCode();

// return PhoneNumberValidationResult.INVALID_DRAMA_NUMBER;

return wrapper.validate();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,57 @@ public static String getRegionCodeForCountryCode(String countryCode) {
}
}


/**
* Using PhoneLib to check the number by isPossibleWithReason code. If number has been parsed during initialization
* this is a straight invocation, so no compensation of some inaccuracy is done here. Otherwise, parsing is done
* locally and exceptions are directly mapped to a result.
* </p>
* @return PhoneNumberUtil.ValidationResult which is PhoneLib isPossible Reason code
*
* @see PhoneLibWrapper#PhoneLibWrapper(String, String)
*/
private PhoneNumberUtil.ValidationResult isPossibleWithReason() {
if (semiNormalizedNumber == null) {
try {
Phonenumber.PhoneNumber tempNumber = phoneUtil.parse(dialableNumber, regionCode);
return phoneUtil.isPossibleNumberWithReason(tempNumber);
// international prefix is added by the lib even if it's not valid in the number plan.
} catch (NumberParseException e) {
LOGGER.info("could not parse normalize number: {}", dialableNumber);
LOGGER.debug("{}", e.getMessage());

switch (e.getErrorType()) {
case INVALID_COUNTRY_CODE:
return PhoneNumberUtil.ValidationResult.INVALID_COUNTRY_CODE;
case TOO_SHORT_NSN:
return PhoneNumberUtil.ValidationResult.TOO_SHORT;
case TOO_SHORT_AFTER_IDD:
return PhoneNumberUtil.ValidationResult.TOO_SHORT;
case TOO_LONG:
return PhoneNumberUtil.ValidationResult.TOO_LONG;
default:
// NOT_A_NUMBER
return PhoneNumberUtil.ValidationResult.INVALID_LENGTH;
}
}
}
return phoneUtil.isPossibleNumberWithReason(semiNormalizedNumber);
}


/**
* Using PhoneLib to check the number by isPossibleWithReason code by internal wrapper method isPossibleWithReason
* and map the result to PhoneNumberValidationResult type
*
* @return PhoneNumberValidationResult
*
* @see PhoneLibWrapper#isPossibleWithReason()
* @see PhoneNumberValidationResult
*/
public PhoneNumberValidationResult validate() {
return PhoneNumberValidationResult.byPhoneLibValidationResult(isPossibleWithReason());
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,24 @@ public ValidationResult getPhoneLibValidationResult() {
return phoneLibResult;
}

public static PhoneNumberValidationResult byPhoneLibValidationResult(ValidationResult result) {
switch(result){
case IS_POSSIBLE:
return PhoneNumberValidationResult.IS_POSSIBLE;
case IS_POSSIBLE_LOCAL_ONLY:
return PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY;
case INVALID_LENGTH:
return PhoneNumberValidationResult.INVALID_LENGTH;
case INVALID_COUNTRY_CODE:
return PhoneNumberValidationResult.INVALID_COUNTRY_CODE;
case TOO_SHORT:
return PhoneNumberValidationResult.TOO_SHORT;
case TOO_LONG:
return PhoneNumberValidationResult.TOO_LONG;
}
return null;
}

/**
* Returns if the validation result identifies a possible number regardless of calling limitations
* @return boolean true for any IS_POSSIBLE(_xxx) enum value
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright © 2023 Deutsche Telekom AG ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.telekom.phonenumbernormalizer

import de.telekom.phonenumbernormalizer.dto.DeviceContext
import de.telekom.phonenumbernormalizer.dto.DeviceContextDto
import de.telekom.phonenumbernormalizer.dto.DeviceContextLineType
import de.telekom.phonenumbernormalizer.numberplans.PhoneNumberValidationResult
import spock.lang.Specification

class PhoneNumberValidatorImplTest extends Specification {

PhoneNumberValidator target

def "setup"() {
target = new PhoneNumberValidatorImpl()
}

def "validate Number by RegionCode"(String number, String countryCode, expectedResult) {
given:

when:
"validate number: $number for country: $countryCode"
PhoneNumberValidationResult result = target.isPhoneNumberPossibleWithReason(number, countryCode)

then:
"it should validate to: $expectedResult"
result == expectedResult

where:
number | countryCode | expectedResult
null | "DE" | PhoneNumberValidationResult.INVALID_LENGTH
// NDC+ national Romania numbers might be longer than 9 digits
"0040(0176) 3 0 6 9 6541" | "DE" | PhoneNumberValidationResult.TOO_LONG
"0040 176 3 0 6 9 6542" | "DE" | PhoneNumberValidationResult.TOO_LONG
"004017630696543" | "DE" | PhoneNumberValidationResult.TOO_LONG
"0040-0176 3 0 6 9 6544" | "DE" | PhoneNumberValidationResult.TOO_LONG
"+49176 3 0 6 9 6544" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE
// "0176 3 0 6 9 6544" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_NATIONAL_ONLY
"+49203556677" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE
// "0203556677" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_NATIONAL_ONLY
// "203556677" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY
// "556677" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY
// "5566778" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY
// "55667789" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY
// "556677889" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY
// "5566778899" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY
// "55667788990" | "DE" | PhoneNumberValidationResult.IS_POSSIBLE_LOCAL_ONLY
// "000" | "AU" | PhoneNumberValidationResult.IS_POSSIBLE_NATIONAL_ONLY
"+39012345678" | "IT" | PhoneNumberValidationResult.IS_POSSIBLE
// "012345678" | "IT" | PhoneNumberValidationResult.IS_POSSIBLE_NATIONAL_ONLY
"+39312345678" | "IT" | PhoneNumberValidationResult.IS_POSSIBLE
// "312345678" | "IT" | PhoneNumberValidationResult.IS_POSSIBLE_NATIONAL_ONLY
}

}
Loading

0 comments on commit bea290e

Please sign in to comment.