def test_walk_releases__sfdx(self, extract_github):
        project_config = create_project_config()
        project_config.project__git__prefix_release = "rel/"
        project_config.project__name = "Project"

        task = create_task(GenerateDataDictionary, {},
                           project_config=project_config)
        task._init_schema()

        repo = Mock()
        release = Mock()
        release.draft = False
        release.prerelease = False
        release.tag_name = "rel/1.1"
        repo.releases.return_value = [release]
        task._process_sfdx_release = Mock()
        extract_github.return_value.namelist.return_value = [
            "force-app/main/default/objects/"
        ]
        p = Package(repo, "Test", "test__", "rel/")

        task._walk_releases(p)

        task._process_sfdx_release.assert_called_once_with(
            extract_github.return_value,
            PackageVersion(p, StrictVersion("1.1")))
    def test_process_field_element__valid_values_global_value_set(self):
        xml_source = """<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>Type__c</fullName>
    <label>Type</label>
    <type>Picklist</type>
    <valueSet>
        <valueSetName>Test Value Set</valueSetName>
    </valueSet>
</CustomField>
"""
        task = create_task(GenerateDataDictionary, {})

        task._init_schema()
        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))

        task._process_field_element(
            "test__Test__c",
            metadata_tree.fromstring(xml_source.encode("utf-8")), v)

        assert task.fields["test__Test__c.test__Type__c"] == [
            FieldDetail(
                v,
                "test__Test__c",
                "test__Type__c",
                "Type",
                "Picklist",
                "",
                "",
                "Global Value Set Test Value Set",
            )
        ]
    def test_process_sfdx_release__handles_object_not_found(self):
        field_source = b"""<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
        <fullName>Type__c</fullName>
        <label>Type</label>
        <type>Text</type>
        <length>128</length>
    </CustomField>
"""

        def zip_read(filename):
            return field_source

        task = create_task(GenerateDataDictionary, {})
        task._init_schema()

        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))

        zip_file = Mock()
        zip_file.read.side_effect = zip_read
        zip_file.namelist.return_value = [
            "force-app/main/default/objects/Child__c/fields/Lookup__c.field-meta.xml"
        ]
        task._process_object_element = Mock()
        task._process_field_element = Mock()
        task._should_process_object_fields = Mock(return_value=True)

        task._process_sfdx_release(zip_file, v)

        task._should_process_object_fields.assert_called_once_with(
            "test__Child__c", None)
    def test_process_field_element__master_detail(self):
        xml_source = """<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>Lookup__c</fullName>
    <label>Test</label>
    <type>MasterDetail</type>
    <referenceTo>Test__c</referenceTo>
</CustomField>
"""
        task = create_task(GenerateDataDictionary, {})
        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))

        task._init_schema()
        task._process_field_element(
            "test__Test__c",
            metadata_tree.fromstring(xml_source.encode("utf-8")), v)

        assert "test__Test__c.test__Lookup__c" in task.fields
        assert task.fields["test__Test__c.test__Lookup__c"] == [
            FieldDetail(
                v,
                "test__Test__c",
                "test__Lookup__c",
                "Test",
                "Master-Detail Relationship to test__Test__c",
                "",
                "",
                "",
            )
        ]
    def test_process_sfdx_release__skips_custom_settings_fields(self):
        object_source = b"""<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
    <customSettingsType>Hierarchy</customSettingsType>
    <description>Description</description>
    <label>Test</label>
</CustomObject>"""
        field_source = b"""<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
        <fullName>Type__c</fullName>
        <label>Type</label>
        <type>Text</type>
        <length>128</length>
    </CustomField>
"""

        def zip_read(filename):
            if filename.endswith(".object-meta.xml"):
                return object_source

            return field_source

        task = create_task(GenerateDataDictionary, {})
        task._init_schema()

        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))

        zip_file = Mock()
        zip_file.read.side_effect = zip_read
        zip_file.namelist.return_value = [
            "force-app/main/default/objects/Child__c/Child__c.object-meta.xml",
            "force-app/main/default/objects/Child__c/fields/Lookup__c.field-meta.xml",
            "force-app/main/default/objects/Parent__c/Parent__c.object-meta.xml",
            ".gitignore",
            "test__c.object-meta.xml",
        ]
        task._process_object_element = Mock()
        task._process_field_element = Mock()
        task._process_sfdx_release(zip_file, v)

        task._process_field_element.assert_not_called()

        zip_file.read.assert_has_calls([
            call(
                "force-app/main/default/objects/Child__c/Child__c.object-meta.xml"
            ),
            call(
                "force-app/main/default/objects/Child__c/Child__c.object-meta.xml"
            ),
            call(
                "force-app/main/default/objects/Parent__c/Parent__c.object-meta.xml"
            ),
        ])
        assert task.omit_sobjects == set(["test__Child__c", "test__Parent__c"])
    def test_write_object_results(self):
        task = create_task(GenerateDataDictionary, {})

        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))
        v2 = PackageVersion(p, StrictVersion("1.2"))
        task.package_versions = {p: [v2.version, v.version]}
        task.sobjects = {
            "test__Test__c":
            [SObjectDetail(v, "test__Test__c", "Test", "Description")]
        }

        f = io.StringIO()
        task._write_object_results(f)

        f.seek(0)
        result = f.read()

        assert (
            result ==
            "Object Label,Object API Name,Object Description,Version Introduced,Version Deleted\r\nTest,test__Test__c,Description,Test 1.1,Test 1.2\r\n"
        )
    def test_process_object_element__standard(self):
        xml_source = """<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<description>Description</description>
<label>Test</label>
</CustomObject>"""

        task = create_task(GenerateDataDictionary, {})

        task._init_schema()
        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))
        task._process_object_element(
            "Account", metadata_tree.fromstring(xml_source.encode("utf-8")), v)

        assert "Account" not in task.sobjects
    def test_process_object_element(self):
        xml_source = """<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
    <description>Description</description>
    <label>Test Object</label>
    <fields>
        <fullName>Type__c</fullName>
        <inlineHelpText>Type of field.</inlineHelpText>
        <description>Desc</description>
        <label>Type</label>
        <type>Text</type>
        <length>128</length>
    </fields>
</CustomObject>"""

        task = create_task(GenerateDataDictionary, {})

        task._init_schema()
        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))
        task._process_object_element(
            "test__Test__c",
            metadata_tree.fromstring(xml_source.encode("utf-8")), v)

        assert task.sobjects == {
            "test__Test__c":
            [SObjectDetail(v, "test__Test__c", "Test Object", "Description")]
        }
        assert task.fields == {
            "test__Test__c.test__Type__c": [
                FieldDetail(
                    v,
                    "test__Test__c",
                    "test__Type__c",
                    "Type",
                    "Text (128)",
                    "Type of field.",
                    "Desc",
                    "",
                )
            ]
        }
    def test_process_field_element__standard(self):
        xml_source = """<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>Account</fullName>
    <label>Account</label>
    <type>Lookup</type>
    <referenceTo>Account</referenceTo>
</CustomField>
"""
        task = create_task(GenerateDataDictionary, {})

        task._init_schema()
        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))

        task._process_field_element(
            "test__Test__c",
            metadata_tree.fromstring(xml_source.encode("utf-8")), v)

        assert "test__Test__c.Account" not in task.fields
    def test_process_field_element__number_length(self):
        xml_source = """<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>Type__c</fullName>
    <label>Type</label>
    <type>Number</type>
    <precision>18</precision>
    <scale>2</scale>
</CustomField>
"""
        task = create_task(GenerateDataDictionary, {})

        task._init_schema()
        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))

        task._process_field_element(
            "test__Test__c",
            metadata_tree.fromstring(xml_source.encode("utf-8")), v)

        assert task.fields["test__Test__c.test__Type__c"] == [
            FieldDetail(v, "test__Test__c", "test__Type__c", "Type",
                        "Number (16.2)", "", "", "")
        ]
    def test_write_field_results(self):
        task = create_task(GenerateDataDictionary, {})

        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))
        v2 = PackageVersion(p, StrictVersion("1.2"))
        task.package_versions = {p: [v2.version, v.version]}
        task.omit_sobjects = set()
        task.sobjects = {
            "test__Test__c": [
                SObjectDetail(v, "test__Test__c", "Test Object", "Desc"),
                SObjectDetail(v2, "test__Test__c", "Test Object", "Desc"),
            ]
        }
        task.fields = {
            "Account.test__Desc__c": [
                FieldDetail(v2, "Account", "test__Desc__c", "Desc", "Text", "",
                            "", "")
            ],
            "test__Test__c.test__Type__c": [
                FieldDetail(
                    v,
                    "test__Test__c",
                    "test__Type__c",
                    "Type",
                    "Picklist",
                    "Help",
                    "Description",
                    "Foo; Bar",
                ),
                FieldDetail(
                    v2,
                    "test__Test__c",
                    "test__Type__c",
                    "Type",
                    "Picklist",
                    "New Help",
                    "Description",
                    "Foo; Bar; New Value",
                ),
            ],
            "test__Test__c.test__Account__c": [
                FieldDetail(
                    v,
                    "test__Test__c",
                    "test__Account__c",
                    "Account",
                    "Lookup to Account",
                    "Help",
                    "Description",
                    "",
                )
            ],
        }

        f = io.StringIO()
        task._write_field_results(f)
        f.seek(0)
        result = f.read()

        assert result == (
            "Object Label,Object API Name,Field Label,Field API Name,Type,Picklist Values,Help Text,Field Description,Version Introduced,Version Picklist Values Last Changed,Version Help Text Last Changed,Version Deleted\r\n"
            "Account,Account,Desc,test__Desc__c,Text,,,,Test 1.2,,,\r\n"
            "Test Object,test__Test__c,Type,test__Type__c,Picklist,Foo; Bar; New Value,New Help,Description,Test 1.1,Test 1.2,Test 1.2,\r\n"
            "Test Object,test__Test__c,Account,test__Account__c,Lookup to Account,,Help,Description,Test 1.1,,,Test 1.2\r\n"
        )
    def test_process_field_element__updated(self):
        xml_source = """<?xml version="1.0" encoding="UTF-8"?>
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>Account__c</fullName>
    <inlineHelpText>{}</inlineHelpText>
    <label>Account</label>
    <type>Lookup</type>
    <referenceTo>Account</referenceTo>
</CustomField>
"""
        task = create_task(GenerateDataDictionary, {})

        task._init_schema()
        p = Package(None, "Test", "test__", "rel/")
        v = PackageVersion(p, StrictVersion("1.1"))
        v2 = PackageVersion(p, StrictVersion("1.2"))

        task._process_field_element(
            "test__Test__c",
            metadata_tree.fromstring(
                xml_source.format("Initial").encode("utf-8")),
            v,
        )

        assert task.fields["test__Test__c.test__Account__c"] == [
            FieldDetail(
                v,
                "test__Test__c",
                "test__Account__c",
                "Account",
                "Lookup to Account",
                "Initial",
                "",
                "",
            )
        ]

        task._process_field_element(
            "test__Test__c",
            metadata_tree.fromstring(xml_source.format("New").encode("utf-8")),
            v2,
        )
        assert task.fields["test__Test__c.test__Account__c"] == [
            FieldDetail(
                v,
                "test__Test__c",
                "test__Account__c",
                "Account",
                "Lookup to Account",
                "Initial",
                "",
                "",
            ),
            FieldDetail(
                v2,
                "test__Test__c",
                "test__Account__c",
                "Account",
                "Lookup to Account",
                "New",
                "",
                "",
            ),
        ]