chromium/tools/android/dependency_analysis/serialization_unittest.py

#!/usr/bin/env python3
# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for dependency_analysis.serialization."""

import unittest
import unittest.mock

import class_dependency
import class_json_consts
import graph
import json_consts
import package_dependency
import group_json_consts
import serialization


class TestSerialization(unittest.TestCase):
    """Unit tests for various de/serialization functions."""
    CLASS_1 = 'p1.c1'
    CLASS_2 = 'p1.c2'
    CLASS_3 = 'p2.c3'
    BUILD_TARGET_1 = '//build/target:one'
    BUILD_TARGET_2 = '//build/target:two'
    CLASS_1_NESTED_1 = 'abc'
    CLASS_1_NESTED_2 = 'def'
    CLASS_2_NESTED_1 = 'ghi'

    # The lists in the following JSON are sorted,
    # since we sort lists when serializing (for easier testing).
    JSON_CLASS_GRAPH = {
        json_consts.NODES: [
            {
                json_consts.NAME: CLASS_1,
                json_consts.META: {
                    class_json_consts.PACKAGE:
                    'p1',
                    class_json_consts.CLASS:
                    'c1',
                    class_json_consts.BUILD_TARGETS: [BUILD_TARGET_1],
                    class_json_consts.NESTED_CLASSES:
                    [CLASS_1_NESTED_1, CLASS_1_NESTED_2],
                },
            },
            {
                json_consts.NAME: CLASS_2,
                json_consts.META: {
                    class_json_consts.PACKAGE: 'p1',
                    class_json_consts.CLASS: 'c2',
                    class_json_consts.BUILD_TARGETS: [],
                    class_json_consts.NESTED_CLASSES: [CLASS_2_NESTED_1],
                },
            },
            {
                json_consts.NAME: CLASS_3,
                json_consts.META: {
                    class_json_consts.PACKAGE:
                    'p2',
                    class_json_consts.CLASS:
                    'c3',
                    class_json_consts.BUILD_TARGETS:
                    [BUILD_TARGET_1, BUILD_TARGET_2],
                    class_json_consts.NESTED_CLASSES: [],
                },
            },
        ],
        json_consts.EDGES: [
            {
                json_consts.BEGIN: CLASS_1,
                json_consts.END: CLASS_2,
            },
            {
                json_consts.BEGIN: CLASS_1,
                json_consts.END: CLASS_3,
            },
            {
                json_consts.BEGIN: CLASS_2,
                json_consts.END: CLASS_3,
            },
        ],
    }

    JSON_PACKAGE_GRAPH = {
        json_consts.NODES: [
            {
                json_consts.NAME: 'p1',
                json_consts.META: {
                    group_json_consts.CLASSES: [CLASS_1, CLASS_2],
                },
            },
            {
                json_consts.NAME: 'p2',
                json_consts.META: {
                    group_json_consts.CLASSES: [CLASS_3],
                },
            },
        ],
        json_consts.EDGES: [
            {
                json_consts.BEGIN: 'p1',
                json_consts.END: 'p1',
                json_consts.META: {
                    group_json_consts.CLASS_EDGES: [
                        [CLASS_1, CLASS_2],
                    ],
                },
            },
            {
                json_consts.BEGIN: 'p1',
                json_consts.END: 'p2',
                json_consts.META: {
                    group_json_consts.CLASS_EDGES: [
                        [CLASS_1, CLASS_3],
                        [CLASS_2, CLASS_3],
                    ],
                },
            },
        ],
    }

    def test_class_serialization(self):
        """Tests JSON serialization of a class dependency graph."""
        test_graph = class_dependency.JavaClassDependencyGraph()
        test_graph.add_edge_if_new(self.CLASS_1, self.CLASS_2)
        test_graph.add_edge_if_new(self.CLASS_1, self.CLASS_3)
        test_graph.add_edge_if_new(self.CLASS_2, self.CLASS_3)
        test_graph.get_node_by_key(self.CLASS_1).add_nested_class(
            self.CLASS_1_NESTED_1)
        test_graph.get_node_by_key(self.CLASS_1).add_nested_class(
            self.CLASS_1_NESTED_2)
        test_graph.get_node_by_key(self.CLASS_2).add_nested_class(
            self.CLASS_2_NESTED_1)
        test_graph.get_node_by_key(self.CLASS_1).add_build_target(
            self.BUILD_TARGET_1)
        test_graph.get_node_by_key(self.CLASS_3).add_build_target(
            self.BUILD_TARGET_1)
        test_graph.get_node_by_key(self.CLASS_3).add_build_target(
            self.BUILD_TARGET_2)

        test_json_obj = serialization.create_json_obj_from_graph(test_graph)

        self.assertEqual(test_json_obj, self.JSON_CLASS_GRAPH)

    def test_package_serialization(self):
        """Tests JSON serialization of a package dependency graph."""
        class_graph = class_dependency.JavaClassDependencyGraph()
        class_graph.add_edge_if_new(self.CLASS_1, self.CLASS_2)
        class_graph.add_edge_if_new(self.CLASS_1, self.CLASS_3)
        class_graph.add_edge_if_new(self.CLASS_2, self.CLASS_3)
        class_graph.get_node_by_key(self.CLASS_1).add_nested_class(
            self.CLASS_1_NESTED_1)
        class_graph.get_node_by_key(self.CLASS_1).add_nested_class(
            self.CLASS_1_NESTED_2)
        class_graph.get_node_by_key(self.CLASS_2).add_nested_class(
            self.CLASS_2_NESTED_1)

        package_graph = package_dependency.JavaPackageDependencyGraph(
            class_graph)
        test_json_obj = serialization.create_json_obj_from_graph(package_graph)

        self.assertEqual(test_json_obj, self.JSON_PACKAGE_GRAPH)

    def test_class_deserialization(self):
        """Tests JSON deserialization of a class dependency graph.

        Since we only ever construct package graphs from class graphs
        (and that feature is tested elsewhere), we do not need to test
        deserialization of package dependency graphs as well.
        """
        test_graph = serialization.create_class_graph_from_json_obj(
            self.JSON_CLASS_GRAPH)

        node_1 = test_graph.get_node_by_key(self.CLASS_1)
        node_2 = test_graph.get_node_by_key(self.CLASS_2)
        node_3 = test_graph.get_node_by_key(self.CLASS_3)

        self.assertIsNotNone(node_1)
        self.assertIsNotNone(node_2)
        self.assertIsNotNone(node_3)
        self.assertEqual(node_1.nested_classes,
                         {self.CLASS_1_NESTED_1, self.CLASS_1_NESTED_2})
        self.assertEqual(node_2.nested_classes, {self.CLASS_2_NESTED_1})
        self.assertEqual(node_3.nested_classes, set())
        self.assertEqual(node_1.build_targets, {self.BUILD_TARGET_1})
        self.assertEqual(node_2.build_targets, set())
        self.assertEqual(node_3.build_targets,
                         {self.BUILD_TARGET_1, self.BUILD_TARGET_2})
        self.assertEqual(
            graph.sorted_edges_by_name(test_graph.edges),
            graph.sorted_edges_by_name([(node_1, node_2), (node_1, node_3),
                                        (node_2, node_3)]))


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