import json
import unittest
from urllib.error import HTTPError

from prepare_listing_readme import API, SLUG, SVN, prepare


class PublishedListingTests(unittest.TestCase):
    def setUp(self):
        self.readme = "=== aisthetix ===\nStable tag: 0.8.2\n\nNew copy\n"
        self.responses = {
            API: json.dumps({"slug": SLUG, "version": "0.8.1"}),
            f"{SVN}/trunk/{SLUG}.php": " * Version: 0.8.1\n",
            f"{SVN}/tags/0.8.1/{SLUG}.php": " * Version: 0.8.1\n",
            f"{SVN}/tags/0.8.1/readme.txt": "Stable tag: 0.8.1\n",
        }

    def test_only_stable_header_changes_when_main_is_ahead(self):
        updated, evidence = prepare(self.readme, self.responses.__getitem__)
        self.assertEqual(updated, self.readme.replace("Stable tag: 0.8.2", "Stable tag: 0.8.1"))
        self.assertEqual(evidence["published_stable_tag"], "0.8.1")

    def test_current_release_and_crlf_preserved(self):
        readme = self.readme.replace("0.8.2", "0.8.1").replace("\n", "\r\n")
        self.assertEqual(prepare(readme, self.responses.__getitem__)[0], readme)

    def test_rejects_invalid_or_other_plugin_api_result(self):
        for info in ({"slug": "other", "version": "0.8.1"}, {"slug": SLUG, "version": "../trunk"}, {"slug": SLUG, "version": None}, {"error": "Plugin not found"}):
            with self.subTest(info=info):
                self.responses[API] = json.dumps(info)
                with self.assertRaises(ValueError):
                    prepare(self.readme, self.responses.__getitem__)

    def test_rejects_svn_version_mismatch(self):
        for ref in ("trunk", "tags/0.8.1"):
            with self.subTest(ref=ref):
                url = f"{SVN}/{ref}/{SLUG}.php"
                saved = self.responses[url]
                self.responses[url] = " * Version: 0.8.2\n"
                with self.assertRaises(ValueError):
                    prepare(self.readme, self.responses.__getitem__)
                self.responses[url] = saved

    def test_rejects_missing_tag_or_network_failure(self):
        for failing_url in self.responses:
            with self.subTest(url=failing_url):
                def read(url):
                    if url == failing_url:
                        raise HTTPError(url, 404, "Not found", {}, None)
                    return self.responses[url]
                with self.assertRaises(HTTPError) as caught:
                    prepare(self.readme, read)
                caught.exception.close()

    def test_rejects_stale_tag_readme(self):
        self.responses[f"{SVN}/tags/0.8.1/readme.txt"] = "Stable tag: 0.8.2\n"
        with self.assertRaises(ValueError):
            prepare(self.readme, self.responses.__getitem__)

    def test_rejects_missing_or_duplicate_local_headers(self):
        for readme in ("No header\n", self.readme + "Stable tag: 0.8.1\n"):
            with self.subTest(readme=readme), self.assertRaises(ValueError):
                prepare(readme, self.responses.__getitem__)


if __name__ == "__main__":
    unittest.main()
