from unittest import TestCase
import json
import subprocess
import sys
import os

from jsonschema import Draft4Validator, ValidationError, cli, __version__
from jsonschema.compat import NativeIO


def fake_validator(*errors):
    errors = list(reversed(errors))

    class FakeValidator(object):
        def __init__(self, *args, **kwargs):
            pass

        def iter_errors(self, instance):
            if errors:
                return errors.pop()
            return []

        def check_schema(self, schema):
            pass

    return FakeValidator


class TestParser(TestCase):

    FakeValidator = fake_validator()
    instance_file = "foo.json"
    schema_file = "schema.json"

    def setUp(self):
        cli.open = self.fake_open
        self.addCleanup(delattr, cli, "open")

    def fake_open(self, path):
        if path == self.instance_file:
            contents = ""
        elif path == self.schema_file:
            contents = {}
        else:  # pragma: no cover
            self.fail("What is {!r}".format(path))
        return NativeIO(json.dumps(contents))

    def test_find_validator_by_fully_qualified_object_name(self):
        arguments = cli.parse_args(
            [
                "--validator",
                "jsonschema.tests.test_cli.TestParser.FakeValidator",
                "--instance", self.instance_file,
                self.schema_file,
            ]
        )
        self.assertIs(arguments["validator"], self.FakeValidator)

    def test_find_validator_in_jsonschema(self):
        arguments = cli.parse_args(
            [
                "--validator", "Draft4Validator",
                "--instance", self.instance_file,
                self.schema_file,
            ]
        )
        self.assertIs(arguments["validator"], Draft4Validator)


class TestCLI(TestCase):
    instance_file_1 = "foo1.json"
    instance_file_2 = "foo2.json"
    schema_file = "schema.json"

    def setUp(self):
        cli.open = self.fake_open
        self.addCleanup(delattr, cli, "open")

    def fake_open(self, path):
        if path == self.instance_file_1:
            contents = "1"
        elif path == self.instance_file_2:
            contents = "25"
        elif path == self.schema_file:
            contents = """
                {
                    "anyOf": [
                        {"minimum": 20},
                        {"type": "string"},
                        {"required": true}
                    ]
                }
            """
        else:  # pragma: no cover
            self.fail("What is {!r}".format(path))
        return NativeIO(contents)

    def test_draft3_schema_draft4_validator(self):
        stdout, stderr = NativeIO(), NativeIO()
        exit_code = cli.run(
            {
                "validator": Draft4Validator,
                "schema": "schema.json",
                "instances": ["foo1.json"],
                "error_format": "{error.message}",
                "output": "plain",
            },
            stdout=stdout,
            stderr=stderr,
        )
        self.assertFalse(stdout.getvalue())
        self.assertTrue(stderr.getvalue())
        self.assertEqual(exit_code, 0)

    def test_successful_validation(self):
        stdout, stderr = NativeIO(), NativeIO()
        exit_code = cli.run(
            {
                "validator": fake_validator(),
                "schema": "schema.json",
                "instances": ["foo2.json"],
                "error_format": "{error.message}",
                "output": "plain",
            },
            stdout=stdout,
            stderr=stderr,
        )
        self.assertFalse(stdout.getvalue())
        self.assertFalse(stderr.getvalue())
        self.assertEqual(exit_code, 0)

    def test_unsuccessful_validation(self):
        error = ValidationError("I am an error!", instance=1)
        stdout, stderr = NativeIO(), NativeIO()
        exit_code = cli.run(
            {
                "validator": fake_validator([error]),
                "schema": "schema.json",
                "instances": ["foo1.json"],
                "error_format": "{error.instance} - {error.message}",
                "output": "plain",
            },
            stdout=stdout,
            stderr=stderr,
        )
        self.assertFalse(stdout.getvalue())
        self.assertEqual(stderr.getvalue(), "1 - I am an error!\n")
        self.assertEqual(exit_code, 1)

    def test_unsuccessful_validation_multiple_instances(self):
        first_errors = [
            ValidationError("9", instance=1),
            ValidationError("8", instance=1),
        ]
        second_errors = [ValidationError("7", instance=2)]
        stdout, stderr = NativeIO(), NativeIO()
        exit_code = cli.run(
            {
                "validator": fake_validator(first_errors, second_errors),
                "schema": "schema.json",
                "instances": ["foo1.json", "foo2.json"],
                "error_format": "{error.instance} - {error.message}",
                "output": "plain",
            },
            stdout=stdout,
            stderr=stderr,
        )
        self.assertFalse(stdout.getvalue())
        self.assertEqual(stderr.getvalue(), "1 - 9\n1 - 8\n2 - 7\n")
        self.assertEqual(exit_code, 1)

    def test_license(self):
        output = subprocess.check_output(
            [sys.executable, "-m", "pip", "show", "jsonschema"],
            stderr=subprocess.STDOUT,
        )
        self.assertIn(b"License: MIT", output)

    def test_version(self):
        version = subprocess.check_output(
            [sys.executable, "-m", "jsonschema", "--version"],
            stderr=subprocess.STDOUT,
        )
        version = version.decode("utf-8").strip()
        self.assertEqual(version, __version__)

    def test_piping(self):
        stdout, stderr, stdin = NativeIO(), NativeIO(), NativeIO("{}")
        exit_code = cli.run(
            {
                "validator": fake_validator(),
                "schema": "schema.json",
                "instances": [],
                "error_format": "{error.message}",
                "output": "plain",
            },
            stdout=stdout,
            stderr=stderr,
            stdin=stdin,
        )
        self.assertFalse(stdout.getvalue())
        self.assertFalse(stderr.getvalue())
        self.assertEqual(exit_code, 0)

@@ -67,18 +67,8 @@
  sys
-%0Aimport os
 %0A%0Afr

Remove unused import os