# -*- coding: utf-8; -*-
#
# This file is part of Superdesk.
#
# Copyright 2013, 2014, 2015 Sourcefabric z.u. and contributors.
#
# For the full copyright and license information, please see the
# AUTHORS and LICENSE files distributed with this source code, or
# at https://www.sourcefabric.org/superdesk/license
import datetime
from unittest import mock
from lxml import etree

from superdesk.utc import utcnow
from superdesk.tests import TestCase
from superdesk.publish import init_app
from superdesk.publish.formatters.newsml_1_2_formatter import NewsML12Formatter


@mock.patch("superdesk.publish.subscribers.SubscribersService.generate_sequence_number", lambda self, subscriber: 1)
class Newsml12FormatterTest(TestCase):
    article = {
        "_id": "urn:localhost.abc",
        "guid": "urn:localhost.abc",
        "source": "AAP",
        "anpa_category": [{"qcode": "a", "name": "Australian General News"}],
        "headline": "This is a test headline - для теста!",
        "byline": "joe",
        "slugline": "slugline",
        "subject": [{"qcode": "02011001"}, {"qcode": "02011002"}],
        "anpa_take_key": "take_key",
        "unique_id": "1",
        "body_html": "<p>The story body&nbsp;more to the story - больше историй</p>",
        "type": "text",
        "word_count": "1",
        "priority": 1,
        "_current_version": 5,
        "state": "published",
        "urgency": 2,
        "pubstatus": "usable",
        "dateline": {
            "source": "AAP",
            "text": "sample dateline",
            "located": {
                "alt_name": "",
                "state": "California",
                "city_code": "Los Angeles",
                "city": "Los Angeles",
                "dateline": "city",
                "country_code": "US",
                "country": "USA",
                "tz": "America/Los_Angeles",
                "state_code": "CA",
            },
        },
        "keywords": ["traffic"],
        "abstract": "sample abstract",
        "place": [
            {
                "qcode": "NSW",
                "name": "NSW",
                "state": "New South Wales",
                "country": "Australia",
                "world_region": "Oceania",
            }
        ],
        "ednote": "this is test",
        "body_footer": "<p>call helpline 999 if you are planning to quit smoking</p>",
        "company_codes": [{"name": "YANCOAL AUSTRALIA LIMITED", "qcode": "YAL", "security_exchange": "ASX"}],
    }

    preformatted = {
        "_id": "urn:localhost.123",
        "guid": "urn:localhost.123",
        "source": "AAP",
        "anpa_category": [{"qcode": "a", "name": "Australian General News"}],
        "headline": "This is a test headline - для теста!",
        "byline": "joe",
        "slugline": "slugline",
        "subject": [{"qcode": "02011001"}, {"qcode": "02011002"}],
        "anpa_take_key": "take_key",
        "unique_id": "1",
        "type": "preformatted",
        "body_html": "The story body",
        "word_count": "1",
        "_current_version": 5,
        "state": "published",
        "urgency": 2,
        "pubstatus": "usable",
        "dateline": {"text": "sample dateline"},
        "keywords": ["traffic"],
        "abstract": "sample abstract",
        "place": [
            {"qcode": "Australia", "name": "Australia", "state": "", "country": "Australia", "world_region": "Oceania"}
        ],
    }

    picture = {
        "_id": "tag:localhost:2015:cf15b059-b997-4e34-a103-85b8d7ea4ba3",
        "guid": "tag:localhost:2015:cf15b059-b997-4e34-a103-85b8d7ea4ba3",
        "firstcreated": "2015-09-20T06:12:57.000Z",
        "versioncreated": "2015-09-20T06:14:11.000Z",
        "dateline": {"source": "AAP", "date": "2015-08-14T04:45:53.000Z"},
        "renditions": {
            "viewImage": {
                "height": 415,
                "href": "http://localhost:5000/api/upload/55cd72811d41c828e1773786/raw?_schema=http",
                "media": "55cd72811d41c828e1773786",
                "mimetype": "image/jpeg",
                "width": 640,
            },
            "baseImage": {
                "height": 909,
                "href": "http://localhost:5000/api/upload/55cd72811d41c828e1773782/raw?_schema=http",
                "media": "55cd72811d41c828e1773782",
                "mimetype": "image/jpeg",
                "width": 1400,
            },
            "thumbnail": {
                "height": 120,
                "href": "http://localhost:5000/api/upload/55cd72811d41c828e1773784/raw?_schema=http",
                "media": "55cd72811d41c828e1773784",
                "mimetype": "image/jpeg",
                "width": 184,
            },
            "original": {
                "height": 2455,
                "href": "http://localhost:5000/api/upload/55cd72801d41c828e1773762/raw?_schema=http",
                "media": "55cd72801d41c828e1773762",
                "mimetype": "image/jpeg",
                "width": 3777,
            },
        },
        "state": "published",
        "anpa_category": [{"qcode": "a", "name": "Australian General News"}],
        "source": "AAP Image",
        "_current_version": 1,
        "original_source": "AAP Image/AAP",
        "description": "Federal Education Minister Christopher Pyne launches his new book NO ARCHIVING",
        "type": "picture",
        "slugline": "NUS CHRISTOPHER PYNE PROTEST",
        "headline": "NUS CHRISTOPHER PYNE PROTEST",
        "pubstatus": "usable",
        "ednote": "",
        "byline": "TRACEY NEARMY",
        "filemeta": {
            "yresolution": [300, 1],
            "exposuretime": [1, 200],
            "copyright": "                                                      ",
            "scenecapturetype": 0,
            "sensingmethod": 2,
            "fnumber": [14, 5],
            "flashpixversion": "0100",
            "xresolution": [300, 1],
            "resolutionunit": 2,
            "subsectimedigitized": "20",
            "exposureprogram": 1,
            "subsectimeoriginal": "20",
            "make": "NIKON CORPORATION",
            "focallengthin35mmfilm": 200,
            "scenetype": 1,
            "exifimageheight": 2455,
            "saturation": 0,
            "colorspace": 1,
            "subjectdistancerange": 0,
            "datetime": "2015:07:31 18:55:37",
            "software": "Photogene for iPad v4.3",
            "flash": 16,
            "focallength": [200, 1],
            "componentsconfiguration": "\u0001\u0002\u0003\u0000",
            "lightsource": 3,
            "artist": "                                    ",
            "isospeedratings": 2000,
            "whitepoint": [313, 1000],
            "sharpness": 2,
            "exposuremode": 1,
            "meteringmode": 3,
            "compressedbitsperpixel": [4, 1],
            "model": "NIKON D800E",
            "subsectime": "20",
            "datetimedigitized": "2015:07:31 18:55:37",
            "exifoffset": 406,
            "contrast": 0,
            "whitebalance": 1,
            "exifimagewidth": 3777,
            "datetimeoriginal": "2015:07:31 18:55:37",
            "customrendered": 0,
            "maxaperturevalue": [3, 1],
            "digitalzoomratio": [1, 1],
            "primarychromaticities": [16, 25],
            "length": 8009209,
            "exifversion": "0230",
            "gaincontrol": 2,
            "gamma": [11, 5],
            "filesource": 3,
        },
        "language": "en",
        "mimetype": "image/jpeg",
        "sign_off": "mar",
        "unique_id": 573,
    }

    video = {
        "_id": "urn:newsml:localhost:2015-09-20T16:12:57.333001:f3856812-0999-4ed8-b69e-68dcdeb1ed2e",
        "guid": "tag:localhost:2015:c11e11c4-cdbc-41ef-b939-2b30dd8365fb",
        "language": "en",
        "family_id": "urn:newsml:localhost:2015-09-20T16:12:57.333001:f3856812-0999-4ed8-b69e-68dcdeb1ed2e",
        "_current_version": 3,
        "versioncreated": "2015-09-20T06:14:11.000Z",
        "unique_id": 274,
        "renditions": {
            "original": {
                "media": "55fe4e691d41c8cac923ceb2",
                "href": "http://192.168.220.176:5000/api/upload/55fe4e691d41c8cac923ceb2/raw?_schema=http",
                "mimetype": "video/mp4",
            }
        },
        "state": "in_progress",
        "version_creator": "55ee82871d41c86ee1d78c45",
        "sign_off": "ADM",
        "media": "55fe4e691d41c8cac923ceb2",
        "source": "AAP",
        "original_source": "AAP Video/AAP",
        "pubstatus": "usable",
        "filemeta": {
            "mime_type": "video/mp4",
            "last_modification": "1904-01-01T00:00:00+00:00",
            "creation_date": "1904-01-01T00:00:00+00:00",
            "height": "270",
            "width": "480",
            "duration": "0:00:10.224000",
            "comment": "User volume: 100.0%",
            "length": 877869,
            "endian": "Big endian",
        },
        "event_id": "tag:localhost:2015:f3ae4441-4721-4987-8265-88d747b6a550",
        "original_creator": "55ee82871d41c86ee1d78c45",
        "expiry": "2016-12-21T14:14:11.000Z",
        "firstcreated": "2015-09-20T06:12:57.000Z",
        "_created": "2015-09-20T06:12:57.000Z",
        "type": "video",
        "unique_name": "#274",
        "mimetype": "video/mp4",
        "version": 2,
        "headline": "test video",
        "description": "test video",
        "abstract": "test video",
        "slugline": "test video keyword",
        "byline": "test video",
        "subject": [{"qcode": "01001000", "name": "archaeology", "parent": "01000000"}],
        "place": [{"qcode": "ACT", "name": "ACT"}],
        "anpa_category": [{"qcode": "a", "name": "Australian General News"}],
    }

    vocab = [
        {
            "_id": "rightsinfo",
            "items": [
                {
                    "name": "AAP",
                    "copyrightHolder": "copy right holder",
                    "copyrightNotice": "copy right notice",
                    "usageTerms": "terms",
                },
                {
                    "name": "default",
                    "copyrightHolder": "default copy right holder",
                    "copyrightNotice": "default copy right notice",
                    "usageTerms": "default terms",
                },
            ],
        }
    ]

    package = {
        "_id": "urn:newsml:localhost:2015-08-12T11:59:58.457029:7e90d257-92f6-406d-9186-95653b211701",
        "guid": "urn:newsml:localhost:2015-08-12T11:59:58.457029:7e90d257-92f6-406d-9186-95653b211701",
        "type": "composite",
        "_current_version": 1,
        "groups": [
            {"role": "grpRole:NEP", "id": "root", "refs": [{"idRef": "main"}]},
            {
                "role": "grpRole:main",
                "id": "main",
                "refs": [
                    {
                        "type": "text",
                        "renditions": {},
                        "itemClass": "icls:text",
                        "guid": "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b",
                        "residRef": "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b",
                        "location": "archive",
                        "headline": "US:US cop sacked over student shooting",
                        "slugline": "US Police",
                        "_current_version": 4,
                    }
                ],
            },
        ],
        "pubstatus": "usable",
        "state": "published",
        "marked_for_not_publication": False,
        "dateline": {
            "located": {
                "alt_name": "",
                "state": "California",
                "city_code": "Los Angeles",
                "city": "Los Angeles",
                "dateline": "city",
                "country_code": "US",
                "country": "USA",
                "tz": "America/Los_Angeles",
                "state_code": "CA",
            },
            "date": "2015-08-12T01:59:58.000Z",
            "source": "AAP",
            "text": "Los Angeles, Aug 11 AAP -",
        },
        "language": "en",
        "headline": "Cop sacked over student shooting",
        "source": "AAP",
        "slugline": "US Police",
        "anpa_category": [{"name": "International News", "qcode": "I"}],
        "subject": [{"name": "police", "parent": "02000000", "qcode": "02003000"}],
    }

    picture_package = {
        "_id": "urn:newsml:localhost:2015-08-13T14:07:59.846466:c659e21b-1ea2-48b7-9b35-e971ae9d1e6e",
        "guid": "urn:newsml:localhost:2015-08-13T14:07:59.846466:c659e21b-1ea2-48b7-9b35-e971ae9d1e6e",
        "language": "en",
        "pubstatus": "usable",
        "groups": [
            {"refs": [{"idRef": "main"}], "id": "root", "role": "grpRole:NEP"},
            {
                "refs": [
                    {
                        "guid": "20150813001165688150",
                        "headline": "Prison Riot",
                        "residRef": "tag:localhost:2015:0c12aa0a-82ef-4c58-a363-c5bd8a368037",
                        "location": "archive",
                        "type": "picture",
                        "slugline": "Prison Riot",
                        "renditions": {
                            "baseImage": {
                                "height": 1400,
                                "mimetype": "image/jpeg",
                                "width": 1120,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650a/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650a",
                            },
                            "thumbnail": {
                                "height": 120,
                                "mimetype": "image/jpeg",
                                "width": 96,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650c/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650c",
                            },
                            "viewImage": {
                                "height": 640,
                                "mimetype": "image/jpeg",
                                "width": 512,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650e/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650e",
                            },
                            "original": {
                                "height": 800,
                                "mimetype": "image/jpeg",
                                "width": 640,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b6508/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b6508",
                            },
                        },
                        "itemClass": "icls:picture",
                        "_current_version": 4,
                    }
                ],
                "id": "main",
                "role": "grpRole:main",
            },
        ],
        "type": "composite",
        "state": "published",
        "slugline": "Prison Riot",
        "description": "This Jan. 21, 2015 photo is of something)",
        "source": "AAP",
        "headline": "Prison Riot",
        "_current_version": 1,
        "dateline": {"date": "2015-08-13T04:07:59.000Z", "source": "AAP"},
        "marked_for_not_publication": False,
        "sign_off": "mar",
    }

    picture_text_package = {
        "_id": "urn:newsml:localhost:2015-08-13T14:07:59.846466:c659e21b-1ea2-48b7-9b35-e971ae9d1e6e",
        "guid": "urn:newsml:localhost:2015-08-13T14:07:59.846466:c659e21b-1ea2-48b7-9b35-e971ae9d1e6e",
        "language": "en",
        "pubstatus": "usable",
        "groups": [
            {"refs": [{"idRef": "main"}], "id": "root", "role": "grpRole:NEP"},
            {
                "refs": [
                    {
                        "type": "text",
                        "renditions": {},
                        "itemClass": "icls:text",
                        "guid": "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b",
                        "residRef": "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b",
                        "location": "archive",
                        "headline": "US:US cop sacked over student shooting",
                        "slugline": "US Police",
                        "_current_version": 4,
                    },
                    {
                        "guid": "20150813001165688150",
                        "headline": "Prison Riot",
                        "residRef": "tag:localhost:2015:0c12aa0a-82ef-4c58-a363-c5bd8a368037",
                        "location": "archive",
                        "type": "picture",
                        "slugline": "Prison Riot",
                        "renditions": {
                            "baseImage": {
                                "height": 1400,
                                "mimetype": "image/jpeg",
                                "width": 1120,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650a/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650a",
                            },
                            "thumbnail": {
                                "height": 120,
                                "mimetype": "image/jpeg",
                                "width": 96,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650c/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650c",
                            },
                            "viewImage": {
                                "height": 640,
                                "mimetype": "image/jpeg",
                                "width": 512,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650e/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650e",
                            },
                            "original": {
                                "height": 800,
                                "mimetype": "image/jpeg",
                                "width": 640,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b6508/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b6508",
                            },
                        },
                        "itemClass": "icls:picture",
                        "_current_version": 4,
                    },
                ],
                "id": "main",
                "role": "grpRole:main",
            },
        ],
        "type": "composite",
        "state": "published",
        "slugline": "Prison Riot",
        "description": "This Jan. 21, 2015 photo is of something)",
        "source": "AAP",
        "headline": "Prison Riot",
        "_current_version": 1,
        "dateline": {"date": "2015-08-13T04:07:59.000Z", "source": "AAP"},
        "marked_for_not_publication": False,
        "sign_off": "mar",
    }

    picture_text_package_multi_group = {
        "_id": "urn:newsml:localhost:2015-08-13T14:07:59.846466:c659e21b-1ea2-48b7-9b35-e971ae9d1e6e",
        "guid": "urn:newsml:localhost:2015-08-13T14:07:59.846466:c659e21b-1ea2-48b7-9b35-e971ae9d1e6e",
        "language": "en",
        "pubstatus": "usable",
        "groups": [
            {"refs": [{"idRef": "main"}, {"idRef": "picture"}], "id": "root", "role": "grpRole:NEP"},
            {
                "refs": [
                    {
                        "type": "text",
                        "renditions": {},
                        "itemClass": "icls:text",
                        "guid": "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b",
                        "residRef": "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b",
                        "location": "archive",
                        "headline": "US:US cop sacked over student shooting",
                        "slugline": "US Police",
                        "_current_version": 4,
                    }
                ],
                "id": "main",
                "role": "grpRole:main",
            },
            {
                "refs": [
                    {
                        "guid": "20150813001165688150",
                        "headline": "Prison Riot",
                        "residRef": "tag:localhost:2015:0c12aa0a-82ef-4c58-a363-c5bd8a368037",
                        "location": "archive",
                        "type": "picture",
                        "slugline": "Prison Riot",
                        "renditions": {
                            "baseImage": {
                                "height": 1400,
                                "mimetype": "image/jpeg",
                                "width": 1120,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650a/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650a",
                            },
                            "thumbnail": {
                                "height": 120,
                                "mimetype": "image/jpeg",
                                "width": 96,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650c/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650c",
                            },
                            "viewImage": {
                                "height": 640,
                                "mimetype": "image/jpeg",
                                "width": 512,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b650e/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b650e",
                            },
                            "original": {
                                "height": 800,
                                "mimetype": "image/jpeg",
                                "width": 640,
                                "href": "http://localhost:5000/api/upload/55cc03731d41c8cea12b6508/raw?_schema=http",
                                "media": "55cc03731d41c8cea12b6508",
                            },
                        },
                        "itemClass": "icls:picture",
                        "_current_version": 4,
                    }
                ],
                "id": "picture",
                "role": "grpRole:picture",
            },
        ],
        "type": "composite",
        "state": "published",
        "slugline": "Prison Riot",
        "description": "This Jan. 21, 2015 photo is of something)",
        "source": "AAP",
        "headline": "Prison Riot",
        "_current_version": 1,
        "dateline": {"date": "2015-08-13T04:07:59.000Z", "source": "AAP"},
        "marked_for_not_publication": False,
        "sign_off": "mar",
    }

    packaged_articles = [
        {
            "_id": "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b",
            "headline": "package article headline",
            "slugline": "slugline",
            "_current_version": 4,
            "state": "published",
            "pubStatus": "usable",
        },
        {
            "_id": "tag:localhost:2015:0c12aa0a-82ef-4c58-a363-c5bd8a368037",
            "headline": "package article headline",
            "slugline": "slugline",
            "_current_version": 4,
            "state": "published",
            "pubStatus": "usable",
        },
    ]

    now = datetime.datetime(2015, 6, 13, 11, 45, 19, 0)

    def setUp(self):
        self.article["state"] = "published"
        self._setup_dates(
            [
                self.article,
                self.video,
                self.picture,
                self.package,
                self.picture_package,
                self.preformatted,
                self.picture_text_package,
                self.picture_text_package_multi_group,
            ]
        )
        self.newsml = etree.Element("NewsML")
        self.formatter = NewsML12Formatter()
        self.formatter.now = self.now
        self.formatter.string_now = self.now.strftime("%Y%m%dT%H%M%S+0000")
        with self.app.app_context():
            init_app(self.app)
            self.app.data.insert("vocabularies", self.vocab)

    def _setup_dates(self, item_list):
        for item in item_list:
            item["firstcreated"] = self.now
            item["versioncreated"] = self.now

    def test_format_news_envelope(self):
        self.formatter._format_news_envelope(self.article, self.newsml, 7)
        self.assertEqual(self.newsml.find("TransmissionId").text, "7")
        self.assertEqual(self.newsml.find("DateAndTime").text, "20150613T114519+0000")
        self.assertEqual(self.newsml.find("Priority").get("FormalName"), "1")
        newsml = etree.Element("NewsML")
        self.formatter._format_news_envelope(self.preformatted, newsml, 7)
        self.assertEqual(newsml.find("Priority").get("FormalName"), "5")

    def test_format_identification(self):
        self.formatter._format_identification(self.article, self.newsml)
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/ProviderId").text, "sourcefabric.org")
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/DateId").text, "20150613")
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/NewsItemId").text, "urn:localhost.abc")
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/RevisionId").get("PreviousRevision"), "0")
        self.assertEqual(
            self.newsml.find("Identification/NewsIdentifier/PublicIdentifier").text, "urn:localhost.abc:5N"
        )
        self.assertEqual(self.newsml.find("Identification/DateLabel").text, "Saturday 13 June 2015")

    def test_format_identification_for_corrections(self):
        self.article["state"] = "corrected"
        self.article["_current_version"] = 7
        self.formatter._format_identification(self.article, self.newsml)
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/RevisionId").get("PreviousRevision"), "6")
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/RevisionId").get("Update"), "N")
        self.article["state"] = "killed"
        self.formatter._format_identification(self.article, self.newsml)
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/RevisionId").get("PreviousRevision"), "6")
        self.assertEqual(self.newsml.find("Identification/NewsIdentifier/RevisionId").get("Update"), "N")

    def test_format_news_management(self):
        self.formatter._format_news_management(self.article, self.newsml)
        self.assertEqual(self.newsml.find("NewsManagement/NewsItemType").get("FormalName"), "News")
        self.assertEqual(self.newsml.find("NewsManagement/FirstCreated").text, "20150613T114519+0000")
        self.assertEqual(self.newsml.find("NewsManagement/ThisRevisionCreated").text, "20150613T114519+0000")
        self.assertEqual(self.newsml.find("NewsManagement/Status").get("FormalName"), "usable")
        self.assertEqual(self.newsml.find("NewsManagement/Urgency").get("FormalName"), "2")
        self.assertEqual(self.newsml.find("NewsManagement/Instruction").get("FormalName"), "Update")

    def test_format_news_management_for_corrections(self):
        self.article["state"] = "corrected"
        self.formatter._format_news_management(self.article, self.newsml)
        self.assertEqual(self.newsml.find("NewsManagement/Instruction").get("FormalName"), "Correction")

    def test_format_news_component(self):
        self.formatter._format_news_component(self.article, self.newsml)
        self.assertEqual(self.newsml.find("NewsComponent/NewsComponent/Role").get("FormalName"), "Main")
        self.assertEqual(
            self.newsml.find("NewsComponent/NewsComponent/NewsLines/HeadLine").text,
            "This is a test headline - для теста!",
        )
        self.assertEqual(self.newsml.find("NewsComponent/NewsComponent/NewsLines/ByLine").text, "joe")
        self.assertEqual(self.newsml.find("NewsComponent/NewsComponent/NewsLines/DateLine").text, "sample dateline")
        self.assertEqual(self.newsml.find("NewsComponent/NewsComponent/NewsLines/CreditLine").text, "AAP")
        self.assertEqual(self.newsml.find("NewsComponent/NewsComponent/NewsLines/KeywordLine").text, "slugline")
        self.assertEqual(
            self.newsml.findall("NewsComponent/NewsComponent/DescriptiveMetadata/SubjectCode/Subject")[0].get(
                "FormalName"
            ),
            "02011001",
        )
        self.assertEqual(
            self.newsml.findall("NewsComponent/NewsComponent/DescriptiveMetadata/SubjectCode/Subject")[1].get(
                "FormalName"
            ),
            "02011002",
        )
        self.assertEqual(self.newsml.find("NewsComponent/NewsComponent/DescriptiveMetadata/Property").get("Value"), "a")
        self.assertEqual(
            self.newsml.findall("NewsComponent/NewsComponent/NewsComponent/ContentItem/DataContent")[0].text,
            "sample abstract",
        )
        self.assertEqual(
            self.newsml.findall(
                "NewsComponent/NewsComponent/NewsComponent/ContentItem/DataContent/nitf/body/body.content/p"
            )[0].text,
            "The story body\xa0more to the story - больше историй",
        )
        self.assertEqual(
            self.newsml.findall(
                "NewsComponent/NewsComponent/NewsComponent/ContentItem/DataContent/nitf/body/body.content/p"
            )[1].text,
            "call helpline 999 if you are planning to quit smoking",
        )
        self.assertEqual(self.newsml.find(".//NewsLines/NewsLine/NewsLineText").text, "this is test")

        company_info = self.newsml.find('NewsComponent/NewsComponent/Metadata/Property[@FormalName="Ticker Symbol"]')
        self.assertEqual(company_info.attrib["Value"], "YAL")

        company_info = self.newsml.find('NewsComponent/NewsComponent/Metadata/Property[@FormalName="Exchange"]')
        self.assertEqual(company_info.attrib["Value"], "ASX")

    def test_format_news_management_for_embargo(self):
        embargo_ts = utcnow() + datetime.timedelta(days=2)
        doc = self.article.copy()
        doc["embargo"] = embargo_ts

        self.formatter._format_news_management(doc, self.newsml)

        self.assertEqual(self.newsml.find("NewsManagement/NewsItemType").get("FormalName"), "News")
        self.assertEqual(self.newsml.find("NewsManagement/FirstCreated").text, "20150613T114519+0000")
        self.assertEqual(self.newsml.find("NewsManagement/ThisRevisionCreated").text, "20150613T114519+0000")
        self.assertEqual(self.newsml.find("NewsManagement/Urgency").get("FormalName"), "2")
        self.assertEqual(self.newsml.find("NewsManagement/Instruction").get("FormalName"), "Update")
        self.assertEqual(self.newsml.find("NewsManagement/Status").get("FormalName"), "Embargoed")
        self.assertEqual(self.newsml.find("NewsManagement/StatusWillChange/FutureStatus").get("FormalName"), "usable")
        self.assertEqual(self.newsml.find("NewsManagement/StatusWillChange/DateAndTime").text, embargo_ts.isoformat())

    def test_format_place(self):
        doc = self.article.copy()
        self.formatter._format_place(doc, self.newsml)
        self.assertEqual(
            self.newsml.find('Location/Property[@FormalName="CountryArea"]').get("Value"), "New South Wales"
        )
        self.assertEqual(self.newsml.find('Location/Property[@FormalName="Country"]').get("Value"), "Australia")
        self.assertEqual(self.newsml.find('Location/Property[@FormalName="WorldRegion"]').get("Value"), "Oceania")

    def test_format_dateline(self):
        doc = self.article.copy()
        self.formatter._format_dateline(doc, self.newsml)
        self.assertEqual(self.newsml.find('Location/Property[@FormalName="City"]').get("Value"), "Los Angeles")
        self.assertEqual(self.newsml.find('Location/Property[@FormalName="CountryArea"]').get("Value"), "California")
        self.assertEqual(self.newsml.find('Location/Property[@FormalName="Country"]').get("Value"), "USA")

    def test_duration(self):
        self.assertEqual(self.formatter._get_total_duration(None), 0)
        self.assertEqual(self.formatter._get_total_duration("dsf"), 0)
        self.assertEqual(self.formatter._get_total_duration("0:1:0.0000"), 60)
        self.assertEqual(self.formatter._get_total_duration("0:1:10.0000"), 70)
        self.assertEqual(self.formatter._get_total_duration("1:1:10.0000"), 3670)

    def test_format_picture(self):
        doc = self.picture.copy()
        seq, xml_str = self.formatter.format(doc, {"name": "Test Subscriber"})[0]
        xml = etree.fromstring(xml_str)

        self.assertEqual(
            xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/HeadLine").text, "NUS CHRISTOPHER PYNE PROTEST"
        )
        self.assertEqual(xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/ByLine").text, "TRACEY NEARMY")
        self.assertEqual(xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/CreditLine").text, "AAP Image/AAP")
        self.assertEqual(
            xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/KeywordLine").text, "NUS CHRISTOPHER PYNE PROTEST"
        )
        self.assertEqual(
            xml.find(
                ("NewsItem/NewsComponent/NewsComponent/DescriptiveMetadata/" 'Property[@FormalName="Category"]')
            ).get("Value"),
            "a",
        )

        for rendition, value in doc.get("renditions").items():
            xpath = './/Role[@FormalName="{}"]/../ContentItem'.format(rendition)
            content_item = xml.find(xpath)
            self.assertEqual(content_item.get("Href"), value.get("href"))
            self.assertEqual(content_item.find("MediaType").get("FormalName"), "Photo")
            self.assertEqual(content_item.find("Format").get("FormalName"), value.get("mimetype"))
            self.assertEqual(
                content_item.find('Characteristics/Property[@FormalName="Width"]').get("Value"), str(value.get("width"))
            )
            self.assertEqual(
                content_item.find('Characteristics/Property[@FormalName="Height"]').get("Value"),
                str(value.get("height")),
            )

    def test_format_video(self):
        doc = self.video.copy()
        seq, xml_str = self.formatter.format(doc, {"name": "Test Subscriber"})[0]
        xml = etree.fromstring(xml_str)
        self.assertEqual(xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/HeadLine").text, "test video")
        self.assertEqual(xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/ByLine").text, "test video")
        self.assertEqual(xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/CreditLine").text, "AAP Video/AAP")
        self.assertEqual(
            xml.find("NewsItem/NewsComponent/NewsComponent/NewsLines/KeywordLine").text, "test video keyword"
        )
        for rendition, value in doc.get("renditions").items():
            xpath = './/Role[@FormalName="{}"]/../ContentItem'.format(rendition)
            content_item = xml.find(xpath)
            self.assertEqual(content_item.get("Href"), value.get("href"))
            self.assertEqual(content_item.find("MediaType").get("FormalName"), "Video")
            self.assertEqual(content_item.find("Format").get("FormalName"), value.get("mimetype"))
            self.assertEqual(
                content_item.find('Characteristics/Property[@FormalName="Width"]').get("Value"),
                str(doc.get("filemeta", {}).get("width")),
            )
            self.assertEqual(
                content_item.find('Characteristics/Property[@FormalName="Height"]').get("Value"),
                str(doc.get("filemeta", {}).get("height")),
            )
            self.assertEqual(
                content_item.find('Characteristics/Property[@FormalName="TotalDuration"]').get("Value"), "10"
            )

    def test_format_package(self):
        doc = self.package.copy()
        seq, xml_str = self.formatter.format(doc, {"name": "Test Subscriber"})[0]
        xml = etree.fromstring(xml_str)
        self.assertEqual(
            xml.find('.//Role[@FormalName="root"]/../NewsComponent/Role').get("FormalName"), "grpRole:main"
        )
        self.assertEqual(
            xml.find('.//Role[@FormalName="root"]/../NewsComponent/NewsItemRef').get("NewsItem"),
            "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b:4N",
        )

    def test_format_picture_package(self):
        doc = self.picture_package.copy()
        seq, xml_str = self.formatter.format(doc, {"name": "Test Subscriber"})[0]
        xml = etree.fromstring(xml_str)
        self.assertEqual(
            xml.find('.//Role[@FormalName="root"]/../NewsComponent/Role').get("FormalName"), "grpRole:main"
        )
        self.assertEqual(
            xml.find('.//Role[@FormalName="root"]/../NewsComponent/NewsItemRef').get("NewsItem"),
            "tag:localhost:2015:0c12aa0a-82ef-4c58-a363-c5bd8a368037:4N",
        )

    def test_format_picture_text_package(self):
        doc = self.picture_text_package.copy()
        seq, xml_str = self.formatter.format(doc, {"name": "Test Subscriber"})[0]
        xml = etree.fromstring(xml_str)
        news_component = xml.find('.//Role[@FormalName="root"]/../NewsComponent')
        self.assertEqual(news_component.find("Role").get("FormalName"), "grpRole:main")
        news_item_refs = news_component.findall("NewsItemRef")
        self.assertEqual(
            news_item_refs[0].get("NewsItem"), "tag:localhost:2015:5838657b-b3ec-4e5a-9b39-36039e16400b:4N"
        )
        self.assertEqual(
            news_item_refs[1].get("NewsItem"), "tag:localhost:2015:0c12aa0a-82ef-4c58-a363-c5bd8a368037:4N"
        )
