import configparser
import unittest
from pathlib import Path

from TM1py.Objects import Dimension, Hierarchy, Element
from TM1py.Objects import ElementAttribute
from TM1py.Services import TM1Service


class TestDimensionService(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        """
        Establishes a connection to TM1 and creates objects to use across all tests
        """

        # Connection to TM1
        cls.config = configparser.ConfigParser()
        cls.config.read(Path(__file__).parent.joinpath('config.ini'))
        cls.tm1 = TM1Service(**cls.config['tm1srv01'])

        cls.prefix = "TM1py_Tests_Dimension_"
        cls.dimension_name = cls.prefix + "Some_Dimension"
        cls.hierarchy_name = cls.dimension_name
        cls.dimension_name_with_multi_hierarchy = cls.prefix + "Dimension_With_Multiple_Hierarchies"

    @classmethod
    def setUp(cls):
        cls.create_dimension()

    @classmethod
    def tearDown(cls):
        cls.delete_dimensions()

    @classmethod
    def create_dimension(cls):
        root_element = Element(name='Root', element_type='Consolidated')
        elements = [root_element]
        edges = {}
        for i in range(1, 1001):
            element_name = "Element {}".format(i)
            elements.append(Element(name=element_name, element_type='Numeric'))
            edges[('Root', element_name)] = i
        element_attributes = [
            ElementAttribute(name='Name Long', attribute_type='Alias'),
            ElementAttribute(name='Name Short', attribute_type='Alias')]
        h = Hierarchy(
            name=cls.dimension_name,
            dimension_name=cls.dimension_name,
            elements=elements,
            edges=edges,
            element_attributes=element_attributes)
        d = Dimension(name=cls.dimension_name, hierarchies=[h])
        cls.tm1.dimensions.create(d)

    @classmethod
    def create_dimension_with_multiple_hierarchies(cls):
        dimension = Dimension(cls.dimension_name_with_multi_hierarchy)
        dimension.add_hierarchy(
            Hierarchy(
                name="Hierarchy1",
                dimension_name=dimension.name,
                elements=[Element("Elem1", "Numeric"), Element("Elem2", "Numeric"), Element("Elem3", "Numeric")]))
        dimension.add_hierarchy(
            Hierarchy(
                name="Hierarchy2",
                dimension_name=dimension.name,
                elements=[Element("Elem1", "Numeric"), Element("Elem2", "Numeric"), Element("Elem3", "Numeric")]))
        dimension.add_hierarchy(
            Hierarchy(
                name="Hierarchy3",
                dimension_name=dimension.name,
                elements=[Element("Elem1", "Numeric"), Element("Elem2", "Numeric"), Element("Elem3", "Numeric")]))
        cls.tm1.dimensions.create(dimension)

    @classmethod
    def delete_dimensions(cls):
        cls.tm1.dimensions.delete(cls.dimension_name)
        if cls.tm1.dimensions.exists(cls.dimension_name_with_multi_hierarchy):
            cls.tm1.dimensions.delete(cls.dimension_name_with_multi_hierarchy)

    def test_get_dimension(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        self.assertIsInstance(d, Dimension)
        self.assertEqual(d.name, self.dimension_name)
        h = d.hierarchies[0]
        self.assertIsInstance(h, Hierarchy)
        self.assertEqual(h.name, self.dimension_name)
        self.assertEqual(len(h.elements), 1001)
        self.assertEqual(len(h.edges), 1000)

    def test_dimension__get__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        h = d[self.dimension_name]
        self.assertIsInstance(h, Hierarchy)
        self.assertEqual(h.name, self.dimension_name)
        self.assertEqual(len(h.elements), 1001)
        self.assertEqual(len(h.edges), 1000)

    def test_dimension__contains__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        self.assertIn(self.dimension_name, d)

    def test_dimension__iter__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        first_hierarchy = next(h for h in d)
        self.assertIsInstance(first_hierarchy, Hierarchy)
        self.assertEqual(first_hierarchy.name, self.dimension_name)
        self.assertEqual(len(first_hierarchy.elements), 1001)
        self.assertEqual(len(first_hierarchy.edges), 1000)

    def test_dimension__len__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        self.assertEqual(len(d), 1)

    def test_update_dimension(self):
        # get dimension from tm1
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        # create element objects
        elements = [Element(name='e1', element_type='Consolidated'),
                    Element(name='e2', element_type='Numeric'),
                    Element(name='e3', element_type='Numeric'),
                    Element(name='e4', element_type='Numeric')]
        # create edge objects
        edges = {
            ('e1', 'e2'): 1,
            ('e1', 'e3'): 1,
            ('e1', 'e4'): 1}
        # create the element_attributes objects
        element_attributes = [ElementAttribute(name='Name Long', attribute_type='Alias'),
                              ElementAttribute(name='Name Short', attribute_type='Alias'),
                              ElementAttribute(name='Currency', attribute_type='String')]
        # create hierarchy object
        hierarchy = Hierarchy(name=self.dimension_name, dimension_name=self.dimension_name, elements=elements,
                              element_attributes=element_attributes, edges=edges)

        # replace existing hierarchy with new hierarchy
        d.remove_hierarchy(self.dimension_name)
        d.add_hierarchy(hierarchy)

        # update dimension in TM1
        self.tm1.dimensions.update(d)

        # Test
        dimension = self.tm1.dimensions.get(self.dimension_name)
        self.assertEqual(len(dimension.hierarchies[0].elements), len(elements))

    def test_update_dimension_remove_hierarchy(self):
        self.create_dimension_with_multiple_hierarchies()
        dimension = self.tm1.dimensions.get(self.dimension_name_with_multi_hierarchy)
        self.assertEqual(dimension.hierarchy_names, ['Hierarchy1', 'Hierarchy2', 'Hierarchy3', 'Leaves'])
        dimension.remove_hierarchy('Hierarchy2')
        dimension.remove_hierarchy('Hierarchy3')
        self.tm1.dimensions.update(dimension)
        dimension = self.tm1.dimensions.get(self.dimension_name_with_multi_hierarchy)
        self.assertEqual(dimension.hierarchy_names, ['Hierarchy1', 'Leaves'])

    def test_get_all_names(self):
        self.assertIn(self.dimension_name, self.tm1.dimensions.get_all_names())

    def test_get_number_of_dimensions(self):
        number_of_dimensions = self.tm1.dimensions.get_number_of_dimensions()
        self.assertIsInstance(number_of_dimensions, int)

    def test_execute_mdx(self):
        mdx = "{TM1SubsetAll(" + self.dimension_name + ")}"
        elements = self.tm1.dimensions.execute_mdx(self.dimension_name, mdx)
        self.assertEqual(len(elements), 1001)

        mdx = "{ Tm1FilterByLevel ( {TM1SubsetAll(" + self.dimension_name + ")}, 0) }"
        elements = self.tm1.dimensions.execute_mdx(self.dimension_name, mdx)
        self.assertEqual(len(elements), 1000)
        for element in elements:
            self.assertTrue(element.startswith("Element"))

    def test_hierarchy_names(self):
        # create dimension with two Hierarchies
        self.create_dimension_with_multiple_hierarchies()

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(
            set(dimension.hierarchy_names),
            {"Leaves", "Hierarchy1", "Hierarchy2", "Hierarchy3"})

        dimension.remove_hierarchy("Hierarchy1")
        self.assertEqual(
            set(dimension.hierarchy_names),
            {"Leaves", "Hierarchy2", "Hierarchy3"})

    def test_remove_leaves_hierarchy(self):
        # create dimension with two Hierarchies
        self.create_dimension_with_multiple_hierarchies()
        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)

        try:
            dimension.remove_hierarchy("LEAVES")
            raise Exception("Did not throw expected Exception")
        except ValueError:
            pass

    def test_remove_hierarchy(self):
        # create dimension with two Hierarchies
        self.create_dimension_with_multiple_hierarchies()

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(len(dimension.hierarchies), 4)
        self.assertIn("Hierarchy1", dimension)
        self.assertIn("Hierarchy2", dimension)
        self.assertIn("Hierarchy3", dimension)
        self.assertIn("Leaves", dimension)

        dimension.remove_hierarchy("Hierarchy1")
        self.tm1.dimensions.update(dimension)

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(len(dimension.hierarchies), 3)
        self.assertNotIn("Hierarchy1", dimension)
        self.assertIn("Hierarchy2", dimension)
        self.assertIn("Hierarchy3", dimension)
        self.assertIn("Leaves", dimension)

        dimension.remove_hierarchy("H i e r a r c h y 3".upper())
        self.tm1.dimensions.update(dimension)

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(len(dimension.hierarchies), 2)
        self.assertNotIn("Hierarchy1", dimension)
        self.assertIn("Hierarchy2", dimension)
        self.assertNotIn("Hierarchy3", dimension)
        self.assertIn("Leaves", dimension)

    def test_rename_dimension(self):
        original_dimension_name = self.prefix + "Original_Dimension"
        renamed_dimension_name = self.prefix + "Renamed_Dimension"

        # if dimensions exist in TM1.. delete them
        for dim_name in (original_dimension_name, renamed_dimension_name):
            if self.tm1.dimensions.exists(dim_name):
                self.tm1.dimensions.delete(dimension_name=dim_name)

        # create dimension
        original_dimension = Dimension(original_dimension_name)
        hierarchy = Hierarchy(name=original_dimension_name, dimension_name=original_dimension_name)
        hierarchy.add_element(element_name="Total", element_type="Consolidated")
        hierarchy.add_element(element_name="Elem1", element_type="Numeric")
        hierarchy.add_element(element_name="Elem2", element_type="Numeric")
        hierarchy.add_element(element_name="Elem3", element_type="Numeric")
        hierarchy.add_edge(parent="Total", component="Elem1", weight=1)
        hierarchy.add_edge(parent="Total", component="Elem2", weight=1)
        hierarchy.add_edge(parent="Total", component="Elem3", weight=1)
        original_dimension.add_hierarchy(hierarchy)
        self.tm1.dimensions.create(original_dimension)

        # rename
        renamed_dimension = self.tm1.dimensions.get(original_dimension.name)
        renamed_dimension.name = renamed_dimension_name
        self.tm1.dimensions.create(renamed_dimension)

        # challenge equality of dimensions
        summary1 = self.tm1.dimensions.hierarchies.get_hierarchy_summary(
            dimension_name=original_dimension_name,
            hierarchy_name=original_dimension_name)
        summary2 = self.tm1.dimensions.hierarchies.get_hierarchy_summary(
            dimension_name=renamed_dimension_name,
            hierarchy_name=renamed_dimension_name)
        self.assertEqual(summary1, summary2)

        # delete
        for dim_name in (original_dimension_name, renamed_dimension_name):
            self.tm1.dimensions.delete(dimension_name=dim_name)

    @classmethod
    def tearDownClass(cls):
        cls.tm1.logout()


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

import configparser
import unittest
from pathlib import Path

from TM1py.Objects import Dimension, Hierarchy, Element
from TM1py.Objects import ElementAttribute
from TM1py.Services import TM1Service


class TestDimensionService(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        """
        Establishes a connection to TM1 and creates objects to use across all tests
        """

        # Connection to TM1
        cls.config = configparser.ConfigParser()
        cls.config.read(Path(__file__).parent.joinpath('config.ini'))
        cls.tm1 = TM1Service(**cls.config['tm1srv01'])

        cls.prefix = "TM1py_Tests_Dimension_"
        cls.dimension_name = cls.prefix + "Some_Dimension"
        cls.hierarchy_name = cls.dimension_name
        cls.dimension_name_with_multi_hierarchy = cls.prefix + "Dimension_With_Multiple_Hierarchies"

    @classmethod
    def setUp(cls):
        cls.create_dimension()

    @classmethod
    def tearDown(cls):
        cls.delete_dimensions()

    @classmethod
    def create_dimension(cls):
        root_element = Element(name='Root', element_type='Consolidated')
        elements = [root_element]
        edges = {}
        for i in range(1, 1001):
            element_name = "Element {}".format(i)
            elements.append(Element(name=element_name, element_type='Numeric'))
            edges[('Root', element_name)] = i
        element_attributes = [
            ElementAttribute(name='Name Long', attribute_type='Alias'),
            ElementAttribute(name='Name Short', attribute_type='Alias')]
        h = Hierarchy(
            name=cls.dimension_name,
            dimension_name=cls.dimension_name,
            elements=elements,
            edges=edges,
            element_attributes=element_attributes)
        d = Dimension(name=cls.dimension_name, hierarchies=[h])
        cls.tm1.dimensions.create(d)

    @classmethod
    def create_dimension_with_multiple_hierarchies(cls):
        dimension = Dimension(cls.dimension_name_with_multi_hierarchy)
        dimension.add_hierarchy(
            Hierarchy(
                name="Hierarchy1",
                dimension_name=dimension.name,
                elements=[Element("Elem1", "Numeric"), Element("Elem2", "Numeric"), Element("Elem3", "Numeric")]))
        dimension.add_hierarchy(
            Hierarchy(
                name="Hierarchy2",
                dimension_name=dimension.name,
                elements=[Element("Elem1", "Numeric"), Element("Elem2", "Numeric"), Element("Elem3", "Numeric")]))
        dimension.add_hierarchy(
            Hierarchy(
                name="Hierarchy3",
                dimension_name=dimension.name,
                elements=[Element("Elem1", "Numeric"), Element("Elem2", "Numeric"), Element("Elem3", "Numeric")]))
        cls.tm1.dimensions.create(dimension)

    @classmethod
    def delete_dimensions(cls):
        cls.tm1.dimensions.delete(cls.dimension_name)
        if cls.tm1.dimensions.exists(cls.dimension_name_with_multi_hierarchy):
            cls.tm1.dimensions.delete(cls.dimension_name_with_multi_hierarchy)

    def test_get_dimension(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        self.assertIsInstance(d, Dimension)
        self.assertEqual(d.name, self.dimension_name)
        h = d.hierarchies[0]
        self.assertIsInstance(h, Hierarchy)
        self.assertEqual(h.name, self.dimension_name)
        self.assertEqual(len(h.elements), 1001)
        self.assertEqual(len(h.edges), 1000)

    def test_dimension__get__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        h = d[self.dimension_name]
        self.assertIsInstance(h, Hierarchy)
        self.assertEqual(h.name, self.dimension_name)
        self.assertEqual(len(h.elements), 1001)
        self.assertEqual(len(h.edges), 1000)

    def test_dimension__contains__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        self.assertIn(self.dimension_name, d)

    def test_dimension__iter__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        first_hierarchy = next(h for h in d)
        self.assertIsInstance(first_hierarchy, Hierarchy)
        self.assertEqual(first_hierarchy.name, self.dimension_name)
        self.assertEqual(len(first_hierarchy.elements), 1001)
        self.assertEqual(len(first_hierarchy.edges), 1000)

    def test_dimension__len__(self):
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        self.assertEqual(len(d), 1)

    def test_update_dimension(self):
        # get dimension from tm1
        d = self.tm1.dimensions.get(dimension_name=self.dimension_name)
        # create element objects
        elements = [Element(name='e1', element_type='Consolidated'),
                    Element(name='e2', element_type='Numeric'),
                    Element(name='e3', element_type='Numeric'),
                    Element(name='e4', element_type='Numeric')]
        # create edge objects
        edges = {
            ('e1', 'e2'): 1,
            ('e1', 'e3'): 1,
            ('e1', 'e4'): 1}
        # create the element_attributes objects
        element_attributes = [ElementAttribute(name='Name Long', attribute_type='Alias'),
                              ElementAttribute(name='Name Short', attribute_type='Alias'),
                              ElementAttribute(name='Currency', attribute_type='String')]
        # create hierarchy object
        hierarchy = Hierarchy(name=self.dimension_name, dimension_name=self.dimension_name, elements=elements,
                              element_attributes=element_attributes, edges=edges)

        # replace existing hierarchy with new hierarchy
        d.remove_hierarchy(self.dimension_name)
        d.add_hierarchy(hierarchy)

        # update dimension in TM1
        self.tm1.dimensions.update(d)

        # Test
        dimension = self.tm1.dimensions.get(self.dimension_name)
        self.assertEqual(len(dimension.hierarchies[0].elements), len(elements))

    def test_update_dimension_remove_hierarchy(self):
        self.create_dimension_with_multiple_hierarchies()
        dimension = self.tm1.dimensions.get(self.dimension_name_with_multi_hierarchy)
        self.assertEqual(dimension.hierarchy_names, ['Hierarchy1', 'Hierarchy2', 'Hierarchy3', 'Leaves'])
        dimension.remove_hierarchy('Hierarchy2')
        dimension.remove_hierarchy('Hierarchy3')
        self.tm1.dimensions.update(dimension)
        dimension = self.tm1.dimensions.get(self.dimension_name_with_multi_hierarchy)
        self.assertEqual(dimension.hierarchy_names, ['Hierarchy1', 'Leaves'])

    def test_get_all_names(self):
        self.assertIn(self.dimension_name, self.tm1.dimensions.get_all_names())

    def test_get_number_of_dimensions(self):
        number_of_dimensions = self.tm1.dimensions.get_number_of_dimensions()
        self.assertIsInstance(number_of_dimensions, int)

    def test_execute_mdx(self):
        mdx = "{TM1SubsetAll(" + self.dimension_name + ")}"
        elements = self.tm1.dimensions.execute_mdx(self.dimension_name, mdx)
        self.assertEqual(len(elements), 1001)

        mdx = "{ Tm1FilterByLevel ( {TM1SubsetAll(" + self.dimension_name + ")}, 0) }"
        elements = self.tm1.dimensions.execute_mdx(self.dimension_name, mdx)
        self.assertEqual(len(elements), 1000)
        for element in elements:
            self.assertTrue(element.startswith("Element"))

    def test_hierarchy_names(self):
        # create dimension with two Hierarchies
        self.create_dimension_with_multiple_hierarchies()

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(
            set(dimension.hierarchy_names),
            {"Leaves", "Hierarchy1", "Hierarchy2", "Hierarchy3"})

        dimension.remove_hierarchy("Hierarchy1")
        self.assertEqual(
            set(dimension.hierarchy_names),
            {"Leaves", "Hierarchy2", "Hierarchy3"})

    def test_remove_leaves_hierarchy(self):
        # create dimension with two Hierarchies
        self.create_dimension_with_multiple_hierarchies()
        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)

        try:
            dimension.remove_hierarchy("LEAVES")
            raise Exception("Did not throw expected Exception")
        except ValueError:
            pass

    def test_remove_hierarchy(self):
        # create dimension with two Hierarchies
        self.create_dimension_with_multiple_hierarchies()

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(len(dimension.hierarchies), 4)
        self.assertIn("Hierarchy1", dimension)
        self.assertIn("Hierarchy2", dimension)
        self.assertIn("Hierarchy3", dimension)
        self.assertIn("Leaves", dimension)

        dimension.remove_hierarchy("Hierarchy1")
        self.tm1.dimensions.update(dimension)

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(len(dimension.hierarchies), 3)
        self.assertNotIn("Hierarchy1", dimension)
        self.assertIn("Hierarchy2", dimension)
        self.assertIn("Hierarchy3", dimension)
        self.assertIn("Leaves", dimension)

        dimension.remove_hierarchy("H i e r a r c h y 3".upper())
        self.tm1.dimensions.update(dimension)

        dimension = self.tm1.dimensions.get(dimension_name=self.dimension_name_with_multi_hierarchy)
        self.assertEqual(len(dimension.hierarchies), 2)
        self.assertNotIn("Hierarchy1", dimension)
        self.assertIn("Hierarchy2", dimension)
        self.assertNotIn("Hierarchy3", dimension)
        self.assertIn("Leaves", dimension)

    def test_rename_dimension(self):
        original_dimension_name = self.prefix + "Original_Dimension"
        renamed_dimension_name = self.prefix + "Renamed_Dimension"

        # if dimensions exist in TM1.. delete them
        for dim_name in (original_dimension_name, renamed_dimension_name):
            if self.tm1.dimensions.exists(dim_name):
                self.tm1.dimensions.delete(dimension_name=dim_name)

        # create dimension
        original_dimension = Dimension(original_dimension_name)
        hierarchy = Hierarchy(name=original_dimension_name, dimension_name=original_dimension_name)
        hierarchy.add_element(element_name="Total", element_type="Consolidated")
        hierarchy.add_element(element_name="Elem1", element_type="Numeric")
        hierarchy.add_element(element_name="Elem2", element_type="Numeric")
        hierarchy.add_element(element_name="Elem3", element_type="Numeric")
        hierarchy.add_edge(parent="Total", component="Elem1", weight=1)
        hierarchy.add_edge(parent="Total", component="Elem2", weight=1)
        hierarchy.add_edge(parent="Total", component="Elem3", weight=1)
        original_dimension.add_hierarchy(hierarchy)
        self.tm1.dimensions.create(original_dimension)

        # rename
        renamed_dimension = self.tm1.dimensions.get(original_dimension.name)
        renamed_dimension.name = renamed_dimension_name
        self.tm1.dimensions.create(renamed_dimension)

        # challenge equality of dimensions
        summary1 = self.tm1.dimensions.hierarchies.get_hierarchy_summary(
            dimension_name=original_dimension_name,
            hierarchy_name=original_dimension_name)
        summary2 = self.tm1.dimensions.hierarchies.get_hierarchy_summary(
            dimension_name=renamed_dimension_name,
            hierarchy_name=renamed_dimension_name)
        self.assertEqual(summary1, summary2)

        # delete
        for dim_name in (original_dimension_name, renamed_dimension_name):
            self.tm1.dimensions.delete(dimension_name=dim_name)

    @classmethod
    def tearDownClass(cls):
        cls.tm1.logout()


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

Establishes a connection to TM1 and creates objects to use across all tests # Connection to TM1 # get dimension from tm1 # create element objects # create edge objects # create the element_attributes objects # create hierarchy object # replace existing hierarchy with new hierarchy # update dimension in TM1 # Test # create dimension with two Hierarchies # create dimension with two Hierarchies # create dimension with two Hierarchies # if dimensions exist in TM1.. delete them # create dimension # rename # challenge equality of dimensions # delete