def test_validate_id_number_invalid_arg_valid_length():
    """
    Tests to see if the validate_id_number function raises the correct exception for an invalid valid_length arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.validate_id_number('1234567891011', False)
def test_validate_id_number_valid_length_specified():
    """
    Tests to see if the validate_id_number function correctly validates the given id number.
    This case tests the behaviour of specifying the valid_length arg
    """
    verifier = TextVerify()
    assert not verifier.validate_id_number('1234567891011', valid_length=15)
def test_validate_id_number_invalid_arg_id_number_2():
    """
    Tests to see if the validate_id_number function raises the correct exception for an invalid id_number arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.validate_id_number('1234Almost56')
def test_validate_id_number_valid():
    """
    Tests to see if the validate_id_number function correctly validates the given id number.
    This case tests whether it deems a valid id number as valid.
    """
    verifier = TextVerify()
    assert verifier.validate_id_number('7209170838080')
def test_validate_id_number_invalid():
    """
    Tests to see if the validate_id_number function correctly validates the given id number.
    This case tests whether it deems a invalid id number as invalid.
    """
    verifier = TextVerify()
    assert not verifier.validate_id_number('1234567891011')
def test_verify_threshold():
    """
    Tests the return value of the verify function with a specified threshold arg.
    """
    verifier = TextVerify()
    extracted_info = {
        'identity_number': '7101135111011',
        'surname': 'Doe',
        'names': 'John-Michael Robert',
        'sex': '####################################',
        'date_of_birth': '71-01-13',
        'country_of_birth': 'RSA',
        'status': 'Citizen',
        'nationality': 'RSA'
    }
    verifier_info = {
        'identity_number': '7101135111011',
        'surname': 'Doe',
        'names': 'John-Michael Robert',
        'sex': 'M',
        'date_of_birth': '71-01-13',
        'country_of_birth': 'RSA',
        'status': 'Citizen',
        'nationality': 'RSA'
    }
    assert verifier.verify(extracted_info, verifier_info,
                           threshold=90.0) == (False, 87.5)
def test_verify_invalid_arg_verbose():
    """
    Tests to see if the verify function raises the correct exception for an invalid verbose arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.verify({}, {}, verbose='nah fam')
def test_verify_invalid_arg_extracted_1():
    """
    Tests to see if the verify function raises the correct exception for an invalid extracted arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.verify('not quite', {})
def test_verify_invalid_arg_threshold():
    """
    Tests to see if the verify function raises the correct exception for an invalid threshold arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.verify({}, {}, threshold=['nope'])
def test_verify_invalid_arg_verifier_1():
    """
    Tests to see if the verify function raises the correct exception for an invalid verifier arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.verify({}, 'does not seem legit')
def test_verify_min_matches():
    """
    Tests the return value of the verify function with a specified minimum number of matches arg.
    """
    verifier = TextVerify()
    extracted_info = {
        'identity_number': '7101135111011',
        'surname': 'Doe',
        'names': 'John-Michael Robert',
        'sex': 'M',
        'not valid': '####################################',
        'not legit': '####################################',
        'not gonna work': '####################################',
        'try again': '####################################'
    }
    verifier_info = {
        'identity_number': '7101135111011',
        'surname': 'Doe',
        'names': 'John-Michael Robert',
        'sex': 'M',
        'date_of_birth': '71-01-13',
        'country_of_birth': 'RSA',
        'status': 'Citizen',
        'nationality': 'RSA'
    }
    assert verifier.verify(extracted_info, verifier_info,
                           min_matches=6) == (False, 0.0)
def test_verify_default_half_match():
    """
    Tests the return value of the verify function with default args.
    In this case we expect a 50% match.
    """
    verifier = TextVerify()
    extracted_info = {
        'identity_number': '7101135111011',
        'surname': 'Doe',
        'names': 'John-Michael Robert',
        'sex': 'M',
        'date_of_birth': '####################################',
        'country_of_birth': '####################################',
        'status': '####################################',
        'nationality': '####################################'
    }
    verifier_info = {
        'identity_number': '7101135111011',
        'surname': 'Doe',
        'names': 'John-Michael Robert',
        'sex': 'M',
        'date_of_birth': '71-01-13',
        'country_of_birth': 'RSA',
        'status': 'Citizen',
        'nationality': 'RSA'
    }
    assert verifier.verify(extracted_info, verifier_info) == (False, 50.0)
def test_verify_invalid_arg_min_matches():
    """
    Tests to see if the verify function raises the correct exception for an invalid min_matches arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.verify({}, {}, min_matches=['nope again'])
def test_verify_invalid_arg_verifier_2():
    """
    Tests to see if the verify function raises the correct exception for an invalid verifier arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.verify({'names': 'John Legit'},
                        {'names': ['not', 'John', 'legit']})
def test_verify_invalid_arg_extracted_2():
    """
    Tests to see if the verify function raises the correct exception for an invalid extracted arg.
    """
    verifier = TextVerify()
    with pytest.raises(TypeError):
        verifier.verify({'identity_number': 1234},
                        {'identity_number': '7101135111011'})
def test_verify_verbose_2():
    """
    Tests the return value of the verify function with a specified verbose arg.
    """
    verifier = TextVerify()
    extracted_info = {
        'identity_number': '7101135111011',
        'surname': 'Door',
        'names': 'John-Michael Robert',
        'sex': 'M',
        'date_of_birth': '71-01-13',
        'country_of_birth': 'GRSAGT',
        'nationality': 'RSA'
    }
    verifier_info = {
        'identity_number': '7101135111011',
        'surname': 'Doe',
        'names': 'John-Michael Robert',
        'sex': 'M',
        'date_of_birth': '71-01-13',
        'country_of_birth': 'RSA',
        'status': 'Citizen',
    }
    assert verifier.verify(extracted_info, verifier_info,
                           verbose=True) == (True, {
                               'identity_number': {
                                   'match_percentage': 100.0,
                                   'verifier_field_value': '7101135111011',
                                   'extracted_field_value': '7101135111011'
                               },
                               'surname': {
                                   'match_percentage': 57.14,
                                   'verifier_field_value': 'Doe',
                                   'extracted_field_value': 'Door'
                               },
                               'names': {
                                   'match_percentage': 100.0,
                                   'verifier_field_value':
                                   'John-Michael Robert',
                                   'extracted_field_value':
                                   'John-Michael Robert'
                               },
                               'sex': {
                                   'match_percentage': 100.0,
                                   'verifier_field_value': 'M',
                                   'extracted_field_value': 'M'
                               },
                               'date_of_birth': {
                                   'match_percentage': 100.0,
                                   'verifier_field_value': '71-01-13',
                                   'extracted_field_value': '71-01-13'
                               },
                               'country_of_birth': {
                                   'match_percentage': 66.67,
                                   'verifier_field_value': 'RSA',
                                   'extracted_field_value': 'GRSAGT'
                               },
                               'status': {
                                   'match_percentage': None,
                                   'verifier_field_value': 'Citizen',
                                   'extracted_field_value': None
                               },
                               'nationality': {
                                   'match_percentage': None,
                                   'verifier_field_value': None,
                                   'extracted_field_value': 'RSA'
                               },
                               'total': 87.3
                           })
def verify_id():
    """
    ----------------------------------------------------------------------
    Authors: Nicolai van Niekerk, Stephan Nell, Marthinus Hermann
    ----------------------------------------------------------------------
    Sample function to return a match percentage of an ID image and
    provided personal information and picture of face
    ----------------------------------------------------------------------
    URL: http://localhost:5000/verifyID
    ----------------------------------------------------------------------
    """
    data = {"success": False}
    # Get id image as numpy array
    # Check to see if an image was uploaded.
    if request.files.get("id_img", None) is not None:
        # Grab the uploaded image.
        image_of_id = grab_image(stream=request.files["id_img"])
    # Otherwise, assume that a URL was passed in.
    else:
        # Grab the URL from the request.
        url = request.args.get("url", None)
        # If the URL is None, then return an error.
        if url is None:
            data["error"] = "No URL provided."
            return jsonify(data)
            # Load the image and convert.
        image_of_id = grab_image(url=url)

    # Get face image as numpy array
    # Check to see if an image was uploaded.
    if request.files.get("face_img", None) is not None:
        # Grab the uploaded image.
        face = grab_image(stream=request.files["face_img"])
    # Otherwise, assume that a URL was passed in.
    else:
        # Grab the URL from the request.
        url = request.args.get("url", None)
        # If the URL is None, then return an error.
        if url is None:
            data["error"] = "No URL provided."
            return jsonify(data)
            # Load the image and convert.
        face = grab_image(url=url)

    entered_details = {
        "names": request.form['names'],
        "surname": request.form['surname'],
        "identity_number": request.form['idNumber'],
        "nationality": request.form['nationality'],
        "country_of_birth": request.form['cob'],
        "status": request.form['status'],
        "sex": request.form['gender'],
        "date_of_birth": request.form['dob']
    }

    # Extract face
    face_detector = FaceDetector(SHAPE_PREDICTOR_PATH)
    extracted_face1, _ = face_detector.extract_face(image_of_id)
    extracted_face2, _ = face_detector.extract_face(face)

    # Verify faces
    face_verifier = FaceVerify(SHAPE_PREDICTOR_PATH, FACE_RECOGNITION_PATH)
    (is_match, distance) = face_verifier.verify(extracted_face1,
                                                extracted_face2)

    # Extract text
    # Grab additional parameters specifying techniques
    preferences = {}
    logger.info("Setting Preferences")
    if 'blur_technique' in request.form:
        preferences['blur_method'] = request.form['blur_technique']
    if 'threshold_technique' in request.form:
        preferences['threshold_method'] = request.form['threshold_technique']
    if 'remove_face' in request.form:
        preferences['remove_face'] = request.form['remove_face']
    if 'remove_barcode' in request.form:
        preferences['remove_barcode'] = request.form['remove_barcode']
    if 'color' in request.form:
        preferences['color'] = request.form['color']
    if 'id_type' in request.form:
        preferences['id_type'] = request.form['id_type']

    extractor = TextExtractor(preferences)
    extracted_text = extractor.extract(image_of_id)

    # Verify text
    text_verifier = TextVerify()
    (is_pass,
     text_match_percentage) = text_verifier.verify(extracted_text,
                                                   entered_details)

    logger.info("Preparing Results...")
    result = {
        # text verification contributes to 40% of the total and face likeness for 60%
        "total_match": text_match_percentage * 0.4 + distance * 0.6,
        "text_match": text_match_percentage,
        "face_match": distance,
        "is_match": is_match,
        "is_pass": is_pass
    }
    return jsonify(result)
def test_verify_blank():
    """
    Tests the verify function with blank args.
    """
    verifier = TextVerify()
    assert verifier.verify({}, {}) == (False, 0.0)