# Path: onecodex/exceptions.py
# class ValidationError(OneCodexException):
#     pass
# 
# Path: onecodex/metadata_upload.py
# def validate_appendables(appendables, api):
#     appendables["valid_tags"] = []
#     appendables["valid_metadata"] = {"custom": {}}
#     validate_tags(appendables, api)
#     validate_metadata(appendables, api)
#     return appendables
# 
# def validate_tags(appendables, api):
#     if "tags" not in appendables:
#         return
# 
#     tag_array = appendables["tags"]
#     for tag in tag_array:
#         name_property = api.Tags._resource._schema["properties"]["name"]
#         if len(tag) > name_property.get("maxLength", 1000):
#             raise ValidationError("{} is too long".format(tag))
# 
#         appendables["valid_tags"].append({"name": tag})
# 
# def validate_metadata(appendables, api):
#     if "metadata" not in appendables:
#         return
# 
#     schema_props = metadata_properties(api)
#     for key, value in appendables["metadata"].items():
#         if is_blacklisted(key):
#             raise ValidationError("{} cannot be manually updated".format(key))
# 
#         if key in schema_props.keys():
#             settable_value = validate_metadata_against_schema(schema_props, key, value)
#             appendables["valid_metadata"][key] = settable_value
#         else:
#             coerced_value = coerce_custom_value(value)
#             appendables["valid_metadata"]["custom"][key] = coerced_value
# 
# def validate_metadata_against_schema(schema_props, key, value):
#     schema_rules = schema_props[key]
#     if "enum" in schema_rules:
#         return validate_enum(value, schema_rules)
#     elif "number" in schema_rules["type"]:
#         return validate_number(value, schema_rules)
#     elif "boolean" in schema_rules["type"]:
#         return validate_boolean(value)
#     elif "format" in schema_rules and "date-time" in schema_rules["format"]:
#         return validate_datetime(value)
#     else:
#         return value
# 
# def validate_number(value, schema_rules):
#     num_value = value
#     try:
#         num_value = float(value)
#     except ValueError:
#         raise ValidationError("{} must be a number".format(value))
#     if "minimum" in schema_rules and num_value <= schema_rules["minimum"]:
#         raise ValidationError(
#             "{} must be larger than the minimum value: {}".format(value, schema_rules["minimum"])
#         )
#     if "maximum" in schema_rules and num_value >= schema_rules["maximum"]:
#         raise ValidationError(
#             "{} must be smaller than the maximum value: {}".format(value, schema_rules["maximum"])
#         )
#     return num_value
# 
# def validate_enum(value, schema_rules):
#     if value not in schema_rules["enum"]:
#         # This is gross, but is necessary for string comparison between Python2 ([u'Illumina HiSeq']) and Python3 (['Illumina Hiseq']). On the plus side, it makes the error message more Human Readable.
#         error_array = []
#         for rule in schema_rules["enum"]:
#             if rule:
#                 error_array.append(str(rule))
#             else:
#                 error_array.append(rule)
#         raise ValidationError(
#             "{} is not a valid value for this key. Value must be one of the following options: {}".format(
#                 value, error_array
#             )
#         )
#     return value
# 
# def validate_boolean(value):
#     if value.lower() in truthy_values():
#         return True
#     elif value.lower() in falsy_values():
#         return False
#     else:
#         raise ValidationError('{} must be either "true" or "false"'.format(value))
# 
# def validate_datetime(value):
#     if not is_iso_8601_compliant(value):
#         raise ValidationError(
#             '"{}" must be formatted in iso8601 compliant date format. Example: "2018-05-15T16:21:36+00:00"'.format(
#                 value
#             )
#         )
# 
#     return value
# 
# def is_blacklisted(key):
#     return key in ["$uri", "custom"]
# 
# def coerce_custom_value(value):
#     try:
#         return float(value)
#     except ValueError:
#         pass
# 
#     if value.lower() in truthy_values():
#         return True
# 
#     if value.lower() in falsy_values():
#         return False
# 
#     # String case, includes dates in JSON
#     return value


import mock
import pytest
    import numpy as np
    import pandas as pd
from onecodex.exceptions import ValidationError
from onecodex.metadata_upload import (
    validate_appendables,
    validate_tags,
    validate_metadata,
    validate_metadata_against_schema,
    validate_number,
    validate_enum,
    validate_boolean,
    validate_datetime,
    is_blacklisted,
    coerce_custom_value,
)


def test_validate_number_valid(ocx):
    schema_props = schema_rules(ocx, "location_lat")
    valid_number = validate_number("50", schema_props)
    assert valid_number == 50


def test_validate_number_invalid_large(ocx):
    schema_props = schema_rules(ocx, "location_lat")
    with pytest.raises(ValidationError) as exception_info:
        validate_number("200", schema_props)
    assert "200 must be smaller than the maximum value: 90.0" in str(exception_info)


def test_validate_number_invalid_small(ocx):
    schema_props = schema_rules(ocx, "location_lat")
    with pytest.raises(ValidationError) as exception_info:
        validate_number("-200", schema_props)
    assert "-200 must be larger than the minimum value: -90.0" in str(exception_info)


def test_validate_enum_valid(ocx):
    schema_props = schema_rules(ocx, "platform")
    validate_enum("Illumina HiSeq", schema_props)


def test_validate_enum_invalid(ocx):
    schema_props = schema_rules(ocx, "platform")
    with pytest.raises(ValidationError) as exception_info:

# Path: onecodex/exceptions.py
# class ValidationError(OneCodexException):
#     pass
# 
# Path: onecodex/metadata_upload.py
# def validate_appendables(appendables, api):
#     appendables["valid_tags"] = []
#     appendables["valid_metadata"] = {"custom": {}}
#     validate_tags(appendables, api)
#     validate_metadata(appendables, api)
#     return appendables
# 
# def validate_tags(appendables, api):
#     if "tags" not in appendables:
#         return
# 
#     tag_array = appendables["tags"]
#     for tag in tag_array:
#         name_property = api.Tags._resource._schema["properties"]["name"]
#         if len(tag) > name_property.get("maxLength", 1000):
#             raise ValidationError("{} is too long".format(tag))
# 
#         appendables["valid_tags"].append({"name": tag})
# 
# def validate_metadata(appendables, api):
#     if "metadata" not in appendables:
#         return
# 
#     schema_props = metadata_properties(api)
#     for key, value in appendables["metadata"].items():
#         if is_blacklisted(key):
#             raise ValidationError("{} cannot be manually updated".format(key))
# 
#         if key in schema_props.keys():
#             settable_value = validate_metadata_against_schema(schema_props, key, value)
#             appendables["valid_metadata"][key] = settable_value
#         else:
#             coerced_value = coerce_custom_value(value)
#             appendables["valid_metadata"]["custom"][key] = coerced_value
# 
# def validate_metadata_against_schema(schema_props, key, value):
#     schema_rules = schema_props[key]
#     if "enum" in schema_rules:
#         return validate_enum(value, schema_rules)
#     elif "number" in schema_rules["type"]:
#         return validate_number(value, schema_rules)
#     elif "boolean" in schema_rules["type"]:
#         return validate_boolean(value)
#     elif "format" in schema_rules and "date-time" in schema_rules["format"]:
#         return validate_datetime(value)
#     else:
#         return value
# 
# def validate_number(value, schema_rules):
#     num_value = value
#     try:
#         num_value = float(value)
#     except ValueError:
#         raise ValidationError("{} must be a number".format(value))
#     if "minimum" in schema_rules and num_value <= schema_rules["minimum"]:
#         raise ValidationError(
#             "{} must be larger than the minimum value: {}".format(value, schema_rules["minimum"])
#         )
#     if "maximum" in schema_rules and num_value >= schema_rules["maximum"]:
#         raise ValidationError(
#             "{} must be smaller than the maximum value: {}".format(value, schema_rules["maximum"])
#         )
#     return num_value
# 
# def validate_enum(value, schema_rules):
#     if value not in schema_rules["enum"]:
#         # This is gross, but is necessary for string comparison between Python2 ([u'Illumina HiSeq']) and Python3 (['Illumina Hiseq']). On the plus side, it makes the error message more Human Readable.
#         error_array = []
#         for rule in schema_rules["enum"]:
#             if rule:
#                 error_array.append(str(rule))
#             else:
#                 error_array.append(rule)
#         raise ValidationError(
#             "{} is not a valid value for this key. Value must be one of the following options: {}".format(
#                 value, error_array
#             )
#         )
#     return value
# 
# def validate_boolean(value):
#     if value.lower() in truthy_values():
#         return True
#     elif value.lower() in falsy_values():
#         return False
#     else:
#         raise ValidationError('{} must be either "true" or "false"'.format(value))
# 
# def validate_datetime(value):
#     if not is_iso_8601_compliant(value):
#         raise ValidationError(
#             '"{}" must be formatted in iso8601 compliant date format. Example: "2018-05-15T16:21:36+00:00"'.format(
#                 value
#             )
#         )
# 
#     return value
# 
# def is_blacklisted(key):
#     return key in ["$uri", "custom"]
# 
# def coerce_custom_value(value):
#     try:
#         return float(value)
#     except ValueError:
#         pass
# 
#     if value.lower() in truthy_values():
#         return True
# 
#     if value.lower() in falsy_values():
#         return False
# 
#     # String case, includes dates in JSON
#     return value


# Path: tests/test_metadata_upload.py
import mock
import pytest
    import numpy as np
    import pandas as pd
from onecodex.exceptions import ValidationError
from onecodex.metadata_upload import (
    validate_appendables,
    validate_tags,
    validate_metadata,
    validate_metadata_against_schema,
    validate_number,
    validate_enum,
    validate_boolean,
    validate_datetime,
    is_blacklisted,
    coerce_custom_value,
)



def test_validate_number_valid(ocx):
    schema_props = schema_rules(ocx, "location_lat")
    valid_number = validate_number("50", schema_props)
    assert valid_number == 50


def test_validate_number_invalid_large(ocx):
    schema_props = schema_rules(ocx, "location_lat")
    with pytest.raises(ValidationError) as exception_info:
        validate_number("200", schema_props)
    assert "200 must be smaller than the maximum value: 90.0" in str(exception_info)


def test_validate_number_invalid_small(ocx):
    schema_props = schema_rules(ocx, "location_lat")
    with pytest.raises(ValidationError) as exception_info:
        validate_number("-200", schema_props)
    assert "-200 must be larger than the minimum value: -90.0" in str(exception_info)


def test_validate_enum_valid(ocx):
    schema_props = schema_rules(ocx, "platform")
    validate_enum("Illumina HiSeq", schema_props)


def test_validate_enum_invalid(ocx):
    schema_props = schema_rules(ocx, "platform")
    with pytest.raises(ValidationError) as exception_info:

        validate_enum("Foo", schema_props)