Commit 33dd036c authored by Henrique Nakashima's avatar Henrique Nakashima Committed by Commit Bot

[Android] Process all dependency jars when generating dependency json

generate_json_dependency_graph.py now takes as parameter a root build
target and parses all jars it depends on, directly or indirectly, rather
than parsing only a single jar.

Bug: 1081840
Change-Id: Ia05313ca178d917cb8e17a23af535f47525cfe96
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2285382
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
Reviewed-by: default avatarPeter Wen <wnwen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#786386}
parent 7d0b49b0
...@@ -4,28 +4,35 @@ As part of Chrome Modularization, this directory contains various tools for ...@@ -4,28 +4,35 @@ As part of Chrome Modularization, this directory contains various tools for
analyzing the dependencies contained within the Chrome Android project. analyzing the dependencies contained within the Chrome Android project.
## Usage ## Usage
Start by generating a JSON dependency file with a snapshot of the dependencies Start by generating a JSON dependency file with a snapshot of the dependencies
for your JAR using the **JSON dependency generator** command-line tool. for your JAR using the **JSON dependency generator** command-line tool.
This snapshot file can then be used as input for various other This snapshot file can then be used as input for various other
analysis tools listed below. analysis tools listed below.
## Command-line tools ## Command-line tools
The usage information for any of the following tools is also accessible via The usage information for any of the following tools is also accessible via
`toolname -h` or `toolname --help`. `toolname -h` or `toolname --help`.
#### JSON Dependency Generator #### JSON Dependency Generator
Runs [jdeps](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jdeps.html) Runs [jdeps](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jdeps.html)
on a given JAR and writes the resulting dependency graph into a JSON file. on a given JAR and writes the resulting dependency graph into a JSON file.
``` ```
usage: generate_json_dependency_graph.py [-h] -t TARGET -o OUTPUT [-j JDEPS_PATH] usage: generate_json_dependency_graph.py [-h] -C BUILD_OUTPUT_DIR -o OUTPUT
[-t TARGET] [-j JDEPS_PATH]
Runs jdeps (dependency analysis tool) on all JARs a root build target depends
on and writes the resulting dependency graph into a JSON file. The default
root build target is chrome/android:monochrome_public_bundle.
optional arguments: optional arguments:
-t TARGET, --target TARGET
Root build target.
-j JDEPS_PATH, --jdeps-path JDEPS_PATH -j JDEPS_PATH, --jdeps-path JDEPS_PATH
Path to the jdeps executable. Path to the jdeps executable.
required arguments: required arguments:
-t TARGET, --target TARGET -C BUILD_OUTPUT_DIR, --build_output_dir BUILD_OUTPUT_DIR
Path to the JAR file to run jdeps on. Build output directory.
-o OUTPUT, --output OUTPUT -o OUTPUT, --output OUTPUT
Path to the file to write JSON output to. Will be Path to the file to write JSON output to. Will be
created if it does not yet exist and overwrite created if it does not yet exist and overwrite
...@@ -62,14 +69,12 @@ required arguments: ...@@ -62,14 +69,12 @@ required arguments:
``` ```
## Example Usage ## Example Usage
This Linux example assumes Chromium is contained in a directory `~/cr` This Linux example assumes Chromium is contained in a directory `~/cr`
and that Chromium has been built as per the instructions and that Chromium has been built as per the instructions
[here](https://chromium.googlesource.com/chromium/src/+/master/docs/linux/build_instructions.md), [here](https://chromium.googlesource.com/chromium/src/+/master/docs/linux/build_instructions.md),
although the only things these assumptions affect are the file paths. although the only things these assumptions affect are the file paths.
``` ```
cd ~/cr/src/tools/android/dependency_analysis $ tools/android/dependency_analysis/generate_json_dependency_graph.py -C out/Debug -o ~/json_graph.txt
./generate_json_dependency_graph.py --target ~/cr/src/out/Default/obj/chrome/android/chrome_java__process_prebuilt.desugar.jar --output ./json_graph.txt
>>> Running jdeps and parsing output... >>> Running jdeps and parsing output...
>>> Parsed class-level dependency graph, got 3239 nodes and 19272 edges. >>> Parsed class-level dependency graph, got 3239 nodes and 19272 edges.
>>> Created package-level dependency graph, got 500 nodes and 4954 edges. >>> Created package-level dependency graph, got 500 nodes and 4954 edges.
...@@ -89,4 +94,4 @@ cd ~/cr/src/tools/android/dependency_analysis ...@@ -89,4 +94,4 @@ cd ~/cr/src/tools/android/dependency_analysis
>>> 1 class edge(s) comprising the dependency: >>> 1 class edge(s) comprising the dependency:
>>> AboutChromeSettings -> ChromeVersionInfo >>> AboutChromeSettings -> ChromeVersionInfo
>>> ... >>> ...
``` ```
\ No newline at end of file
# Lint as: python3
# Copyright 2020 The Chromium Authors. All rights reserved. # Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Implementation of the graph module for a [Java class] dependency graph.""" """Implementation of the graph module for a [Java class] dependency graph."""
import re import re
from typing import Tuple from typing import List, Tuple
import graph import graph
import class_json_consts import class_json_consts
...@@ -51,6 +52,7 @@ class JavaClass(graph.Node): ...@@ -51,6 +52,7 @@ class JavaClass(graph.Node):
self._class_name = class_name self._class_name = class_name
self._nested_classes = set() self._nested_classes = set()
self._build_targets = set()
@property @property
def package(self): def package(self):
...@@ -70,13 +72,21 @@ class JavaClass(graph.Node): ...@@ -70,13 +72,21 @@ class JavaClass(graph.Node):
"""A set of nested classes contained within this class.""" """A set of nested classes contained within this class."""
return self._nested_classes return self._nested_classes
@property
def build_targets(self) -> List[str]:
"""Which build target(s) contain the class."""
return self._build_targets
@nested_classes.setter @nested_classes.setter
def nested_classes(self, other): def nested_classes(self, other):
self._nested_classes = other self._nested_classes = other
def add_nested_class(self, nested: str): # pylint: disable=missing-function-docstring def add_nested_class(self, nested: str):
self._nested_classes.add(nested) self._nested_classes.add(nested)
def add_build_target(self, build_target: str) -> None:
self._build_targets.add(build_target)
def get_node_metadata(self): def get_node_metadata(self):
"""Generates JSON metadata for the current node. """Generates JSON metadata for the current node.
...@@ -85,12 +95,14 @@ class JavaClass(graph.Node): ...@@ -85,12 +95,14 @@ class JavaClass(graph.Node):
{ {
'package': str, 'package': str,
'class': str, 'class': str,
'build_targets' [ str, ... ]
'nested_classes': [ class_key, ... ], 'nested_classes': [ class_key, ... ],
} }
""" """
return { return {
class_json_consts.PACKAGE: self.package, class_json_consts.PACKAGE: self.package,
class_json_consts.CLASS: self.class_name, class_json_consts.CLASS: self.class_name,
class_json_consts.BUILD_TARGETS: sorted(self.build_targets),
class_json_consts.NESTED_CLASSES: sorted(self.nested_classes), class_json_consts.NESTED_CLASSES: sorted(self.nested_classes),
} }
...@@ -106,6 +118,3 @@ class JavaClassDependencyGraph(graph.Graph): ...@@ -106,6 +118,3 @@ class JavaClassDependencyGraph(graph.Graph):
package = re_match.group('package') package = re_match.group('package')
class_name = re_match.group('class_name') class_name = re_match.group('class_name')
return JavaClass(package, class_name) return JavaClass(package, class_name)
def add_nested_class_to_key(self, key: str, nested: str): # pylint: disable=missing-function-docstring
self.get_node_by_key(key).add_nested_class(nested)
...@@ -107,14 +107,6 @@ class TestJavaClassDependencyGraph(unittest.TestCase): ...@@ -107,14 +107,6 @@ class TestJavaClassDependencyGraph(unittest.TestCase):
self.assertEqual(created_node.class_name, 'class') self.assertEqual(created_node.class_name, 'class')
self.assertEqual(created_node.name, 'package.class') self.assertEqual(created_node.name, 'package.class')
def test_add_nested_class_to_key(self):
"""Tests adding a nested class to an existing node."""
added = self.test_graph.add_node_if_new('package.class')
added.add_nested_class = unittest.mock.Mock()
self.test_graph.add_nested_class_to_key('package.class', 'nested')
added.add_nested_class.assert_called_once_with('nested')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -6,4 +6,5 @@ ...@@ -6,4 +6,5 @@
# Node-specific constants # Node-specific constants
PACKAGE = 'package' # The package component of a class's full name. PACKAGE = 'package' # The package component of a class's full name.
CLASS = 'class' # The class component of a class's full name. CLASS = 'class' # The class component of a class's full name.
BUILD_TARGETS = 'build_targets' # Which build targets the class is in
NESTED_CLASSES = 'nested_classes' # Nested classes of a class. NESTED_CLASSES = 'nested_classes' # Nested classes of a class.
...@@ -8,12 +8,15 @@ import argparse ...@@ -8,12 +8,15 @@ import argparse
import pathlib import pathlib
import subprocess import subprocess
from typing import List, Tuple
import class_dependency import class_dependency
import package_dependency import package_dependency
import serialization import serialization
SRC_PATH = pathlib.Path(__file__).resolve().parents[3] # src/ SRC_PATH = pathlib.Path(__file__).resolve().parents[3] # src/
JDEPS_PATH = SRC_PATH.joinpath('third_party/jdk/current/bin/jdeps') JDEPS_PATH = SRC_PATH.joinpath('third_party/jdk/current/bin/jdeps')
DEFAULT_ROOT_TARGET = 'chrome/android:monochrome_public_bundle'
def class_is_interesting(name: str): def class_is_interesting(name: str):
...@@ -23,7 +26,8 @@ def class_is_interesting(name: str): ...@@ -23,7 +26,8 @@ def class_is_interesting(name: str):
return False return False
class JavaClassJdepsParser(object): # pylint: disable=useless-object-inheritance # pylint: disable=useless-object-inheritance
class JavaClassJdepsParser(object):
"""A parser for jdeps class-level dependency output.""" """A parser for jdeps class-level dependency output."""
def __init__(self): # pylint: disable=missing-function-docstring def __init__(self): # pylint: disable=missing-function-docstring
self._graph = class_dependency.JavaClassDependencyGraph() self._graph = class_dependency.JavaClassDependencyGraph()
...@@ -36,12 +40,12 @@ class JavaClassJdepsParser(object): # pylint: disable=useless-object-inheritanc ...@@ -36,12 +40,12 @@ class JavaClassJdepsParser(object): # pylint: disable=useless-object-inheritanc
""" """
return self._graph return self._graph
def parse_raw_jdeps_output(self, jdeps_output: str): def parse_raw_jdeps_output(self, build_target: str, jdeps_output: str):
"""Parses the entirety of the jdeps output.""" """Parses the entirety of the jdeps output."""
for line in jdeps_output.split('\n'): for line in jdeps_output.split('\n'):
self.parse_line(line) self.parse_line(build_target, line)
def parse_line(self, line: str): def parse_line(self, build_target: str, line: str):
"""Parses a line of jdeps output. """Parses a line of jdeps output.
The assumed format of the line starts with 'name_1 -> name_2'. The assumed format of the line starts with 'name_1 -> name_2'.
...@@ -66,17 +70,21 @@ class JavaClassJdepsParser(object): # pylint: disable=useless-object-inheritanc ...@@ -66,17 +70,21 @@ class JavaClassJdepsParser(object): # pylint: disable=useless-object-inheritanc
key_to, nested_to = class_dependency.split_nested_class_from_key( key_to, nested_to = class_dependency.split_nested_class_from_key(
dep_to) dep_to)
self._graph.add_node_if_new(key_from) from_node: class_dependency.JavaClass = self._graph.add_node_if_new(
key_from)
self._graph.add_node_if_new(key_to) self._graph.add_node_if_new(key_to)
if key_from != key_to: # Skip self-edges (class-nested dependency) if key_from != key_to: # Skip self-edges (class-nested dependency)
self._graph.add_edge_if_new(key_from, key_to) self._graph.add_edge_if_new(key_from, key_to)
if nested_from is not None: if nested_from is not None:
self._graph.add_nested_class_to_key(key_from, nested_from) from_node.add_nested_class(nested_from)
if nested_to is not None: if nested_to is not None:
self._graph.add_nested_class_to_key(key_from, nested_to) from_node.add_nested_class(nested_to)
from_node.add_build_target(build_target)
def run_jdeps(jdeps_path: str, filepath: str): def _run_jdeps(jdeps_path: str, filepath: pathlib.Path):
"""Runs jdeps on the given filepath and returns the output.""" """Runs jdeps on the given filepath and returns the output."""
jdeps_res = subprocess.run([jdeps_path, '-R', '-verbose:class', filepath], jdeps_res = subprocess.run([jdeps_path, '-R', '-verbose:class', filepath],
capture_output=True, capture_output=True,
...@@ -85,17 +93,66 @@ def run_jdeps(jdeps_path: str, filepath: str): ...@@ -85,17 +93,66 @@ def run_jdeps(jdeps_path: str, filepath: str):
return jdeps_res.stdout return jdeps_res.stdout
def _run_gn_desc_list_dependencies(build_output_dir: str, target: str):
"""Runs gn desc to list all jars that a target depends on.
This includes direct and indirect dependencies."""
gn_desc_res = subprocess.run(
['gn', 'desc', '--all', build_output_dir, target, 'deps'],
capture_output=True,
text=True,
check=True)
return gn_desc_res.stdout
JarTargetList = List[Tuple[str, pathlib.Path]]
def list_original_targets_and_jars(gn_desc_output: str,
build_output_dir: str) -> JarTargetList:
"""Parses gn desc output to list original java targets and output jar paths.
Returns a list of tuples (build_target: str, jar_path: str), where:
- build_target is the original java dependency target in the form
"//path/to:target"
- jar_path is the path to the built jar in the build_output_dir,
including the path to the output dir
"""
jar_tuples: JarTargetList = []
for build_target_line in gn_desc_output.split('\n'):
if not build_target_line.endswith('__compile_java'):
continue
build_target = build_target_line.strip()
original_build_target = build_target.replace('__compile_java', '')
jar_path = _get_jar_path_for_target(build_output_dir, build_target)
jar_tuples.append((original_build_target, jar_path))
return jar_tuples
def _get_jar_path_for_target(build_output_dir: str, build_target: str) -> str:
"""Calculates the output location of a jar for a java build target."""
target_path, target_name = build_target.split(':')
assert target_path.startswith('//'), \
f'Build target should start with "//" but is: "{build_target}"'
jar_dir = target_path[len('//'):]
jar_name = target_name.replace('__compile_java', '.javac.jar')
return pathlib.Path(build_output_dir) / 'obj' / jar_dir / jar_name
def main(): def main():
"""Runs jdeps and creates a JSON file from the output.""" """Runs jdeps on all JARs a build target depends on.
Creates a JSON file from the jdeps output."""
arg_parser = argparse.ArgumentParser( arg_parser = argparse.ArgumentParser(
description='Runs jdeps (dependency analysis tool) on a given JAR and ' description='Runs jdeps (dependency analysis tool) on all JARs a root '
'writes the resulting dependency graph into a JSON file.') 'build target depends on and writes the resulting dependency graph '
'into a JSON file. The default root build target is '
'chrome/android:monochrome_public_bundle.')
required_arg_group = arg_parser.add_argument_group('required arguments') required_arg_group = arg_parser.add_argument_group('required arguments')
required_arg_group.add_argument( required_arg_group.add_argument('-C',
'-t', '--build_output_dir',
'--target', required=True,
required=True, help='Build output directory.')
help='Path to the JAR file to run jdeps on.')
required_arg_group.add_argument( required_arg_group.add_argument(
'-o', '-o',
'--output', '--output',
...@@ -103,16 +160,28 @@ def main(): ...@@ -103,16 +160,28 @@ def main():
help='Path to the file to write JSON output to. Will be created ' help='Path to the file to write JSON output to. Will be created '
'if it does not yet exist and overwrite existing ' 'if it does not yet exist and overwrite existing '
'content if it does.') 'content if it does.')
arg_parser.add_argument('-t',
'--target',
default=DEFAULT_ROOT_TARGET,
help='Root build target.')
arg_parser.add_argument('-j', arg_parser.add_argument('-j',
'--jdeps-path', '--jdeps-path',
default=JDEPS_PATH, default=JDEPS_PATH,
help='Path to the jdeps executable.') help='Path to the jdeps executable.')
arguments = arg_parser.parse_args() arguments = arg_parser.parse_args()
print('Getting list of dependency jars...')
gn_desc_output = _run_gn_desc_list_dependencies(arguments.build_output_dir,
arguments.target)
target_jars: JarTargetList = list_original_targets_and_jars(
gn_desc_output, arguments.build_output_dir)
print('Running jdeps and parsing output...') print('Running jdeps and parsing output...')
raw_jdeps_output = run_jdeps(arguments.jdeps_path, arguments.target)
jdeps_parser = JavaClassJdepsParser() jdeps_parser = JavaClassJdepsParser()
jdeps_parser.parse_raw_jdeps_output(raw_jdeps_output) for build_target, target_jar in target_jars:
print(f'Running jdeps and parsing output for {target_jar}')
raw_jdeps_output = _run_jdeps(arguments.jdeps_path, target_jar)
jdeps_parser.parse_raw_jdeps_output(build_target, raw_jdeps_output)
class_graph = jdeps_parser.graph class_graph = jdeps_parser.graph
print(f'Parsed class-level dependency graph, ' print(f'Parsed class-level dependency graph, '
......
...@@ -4,9 +4,26 @@ ...@@ -4,9 +4,26 @@
# found in the LICENSE file. # found in the LICENSE file.
"""Unit tests for dependency_analysis.generate_json_dependency_graph.""" """Unit tests for dependency_analysis.generate_json_dependency_graph."""
import pathlib
import unittest import unittest
import generate_json_dependency_graph import generate_json_dependency_graph
GN_DESC_OUTPUT = """
//path/to/dep1:java
//path/to/dep1:java__build_config_crbug_908819
//path/to/dep1:java__compile_java
//path/to/dep1:java__dex
//path/to/dep2:java
//path/to/dep2:java__build_config_crbug_908819
//path/to/dep2:java__compile_java
//path/to/dep2:java__dex
//path/to/root:java
//path/to/root:java__build_config_crbug_908819
//path/to/root:java__compile_java
//path/to/root:java__dex
"""
class TestHelperFunctions(unittest.TestCase): class TestHelperFunctions(unittest.TestCase):
"""Unit tests for module-level helper functions.""" """Unit tests for module-level helper functions."""
...@@ -34,11 +51,31 @@ class TestHelperFunctions(unittest.TestCase): ...@@ -34,11 +51,31 @@ class TestHelperFunctions(unittest.TestCase):
generate_json_dependency_graph.class_is_interesting( generate_json_dependency_graph.class_is_interesting(
'java.lang.Object')) 'java.lang.Object'))
def test_list_original_targets_and_jars(self):
result = generate_json_dependency_graph.list_original_targets_and_jars(
GN_DESC_OUTPUT, 'out/Test')
self.assertEqual(len(result), 3)
self.assertEqual(
result[0],
('//path/to/dep1:java',
pathlib.Path('out/Test/obj/path/to/dep1/java.javac.jar')))
self.assertEqual(
result[1],
('//path/to/dep2:java',
pathlib.Path('out/Test/obj/path/to/dep2/java.javac.jar')))
self.assertEqual(
result[2],
('//path/to/root:java',
pathlib.Path('out/Test/obj/path/to/root/java.javac.jar')))
class TestJavaClassJdepsParser(unittest.TestCase): class TestJavaClassJdepsParser(unittest.TestCase):
"""Unit tests for """Unit tests for
dependency_analysis.class_dependency.JavaClassJdepsParser. dependency_analysis.class_dependency.JavaClassJdepsParser.
""" """
BUILD_TARGET = '//build/target:1'
def setUp(self): def setUp(self):
"""Sets up a new JavaClassJdepsParser.""" """Sets up a new JavaClassJdepsParser."""
self.parser = generate_json_dependency_graph.JavaClassJdepsParser() self.parser = generate_json_dependency_graph.JavaClassJdepsParser()
...@@ -46,19 +83,20 @@ class TestJavaClassJdepsParser(unittest.TestCase): ...@@ -46,19 +83,20 @@ class TestJavaClassJdepsParser(unittest.TestCase):
def test_parse_line(self): def test_parse_line(self):
"""Tests that new nodes + edges are added after a successful parse.""" """Tests that new nodes + edges are added after a successful parse."""
self.parser.parse_line( self.parser.parse_line(
self.BUILD_TARGET,
'org.chromium.a -> org.chromium.b org.chromium.c') 'org.chromium.a -> org.chromium.b org.chromium.c')
self.assertEqual(self.parser.graph.num_nodes, 2) self.assertEqual(self.parser.graph.num_nodes, 2)
self.assertEqual(self.parser.graph.num_edges, 1) self.assertEqual(self.parser.graph.num_edges, 1)
def test_parse_line_not_interesting(self): def test_parse_line_not_interesting(self):
"""Tests that nothing is changed if there is an uninteresting class.""" """Tests that nothing is changed if there is an uninteresting class."""
self.parser.parse_line('org.chromium.a -> b c') self.parser.parse_line(self.BUILD_TARGET, 'org.chromium.a -> b c')
self.assertEqual(self.parser.graph.num_nodes, 0) self.assertEqual(self.parser.graph.num_nodes, 0)
self.assertEqual(self.parser.graph.num_edges, 0) self.assertEqual(self.parser.graph.num_edges, 0)
def test_parse_line_too_short(self): def test_parse_line_too_short(self):
"""Tests that nothing is changed if the line is too short.""" """Tests that nothing is changed if the line is too short."""
self.parser.parse_line('org.chromium.a -> b') self.parser.parse_line(self.BUILD_TARGET, 'org.chromium.a -> b')
self.assertEqual(self.parser.graph.num_nodes, 0) self.assertEqual(self.parser.graph.num_nodes, 0)
self.assertEqual(self.parser.graph.num_edges, 0) self.assertEqual(self.parser.graph.num_edges, 0)
...@@ -66,19 +104,20 @@ class TestJavaClassJdepsParser(unittest.TestCase): ...@@ -66,19 +104,20 @@ class TestJavaClassJdepsParser(unittest.TestCase):
"""Tests that nothing is changed if the line contains `not found` """Tests that nothing is changed if the line contains `not found`
as the second class. as the second class.
""" """
self.parser.parse_line('org.chromium.a -> not found') self.parser.parse_line(self.BUILD_TARGET,
'org.chromium.a -> not found')
self.assertEqual(self.parser.graph.num_nodes, 0) self.assertEqual(self.parser.graph.num_nodes, 0)
self.assertEqual(self.parser.graph.num_edges, 0) self.assertEqual(self.parser.graph.num_edges, 0)
def test_parse_line_empty_string(self): def test_parse_line_empty_string(self):
"""Tests that nothing is changed if the line is empty.""" """Tests that nothing is changed if the line is empty."""
self.parser.parse_line('') self.parser.parse_line(self.BUILD_TARGET, '')
self.assertEqual(self.parser.graph.num_nodes, 0) self.assertEqual(self.parser.graph.num_nodes, 0)
self.assertEqual(self.parser.graph.num_edges, 0) self.assertEqual(self.parser.graph.num_edges, 0)
def test_parse_line_bad_input(self): def test_parse_line_bad_input(self):
"""Tests that nothing is changed if the line is nonsensical""" """Tests that nothing is changed if the line is nonsensical"""
self.parser.parse_line('bad_input') self.parser.parse_line(self.BUILD_TARGET, 'bad_input')
self.assertEqual(self.parser.graph.num_nodes, 0) self.assertEqual(self.parser.graph.num_nodes, 0)
self.assertEqual(self.parser.graph.num_edges, 0) self.assertEqual(self.parser.graph.num_edges, 0)
......
...@@ -20,6 +20,8 @@ class TestSerialization(unittest.TestCase): ...@@ -20,6 +20,8 @@ class TestSerialization(unittest.TestCase):
CLASS_1 = 'p1.c1' CLASS_1 = 'p1.c1'
CLASS_2 = 'p1.c2' CLASS_2 = 'p1.c2'
CLASS_3 = 'p2.c3' CLASS_3 = 'p2.c3'
BUILD_TARGET_1 = '//build/target:one'
BUILD_TARGET_2 = '//build/target:two'
CLASS_1_NESTED_1 = 'abc' CLASS_1_NESTED_1 = 'abc'
CLASS_1_NESTED_2 = 'def' CLASS_1_NESTED_2 = 'def'
CLASS_2_NESTED_1 = 'ghi' CLASS_2_NESTED_1 = 'ghi'
...@@ -35,6 +37,7 @@ class TestSerialization(unittest.TestCase): ...@@ -35,6 +37,7 @@ class TestSerialization(unittest.TestCase):
'p1', 'p1',
class_json_consts.CLASS: class_json_consts.CLASS:
'c1', 'c1',
class_json_consts.BUILD_TARGETS: [BUILD_TARGET_1],
class_json_consts.NESTED_CLASSES: class_json_consts.NESTED_CLASSES:
[CLASS_1_NESTED_1, CLASS_1_NESTED_2], [CLASS_1_NESTED_1, CLASS_1_NESTED_2],
}, },
...@@ -44,14 +47,19 @@ class TestSerialization(unittest.TestCase): ...@@ -44,14 +47,19 @@ class TestSerialization(unittest.TestCase):
json_consts.META: { json_consts.META: {
class_json_consts.PACKAGE: 'p1', class_json_consts.PACKAGE: 'p1',
class_json_consts.CLASS: 'c2', class_json_consts.CLASS: 'c2',
class_json_consts.BUILD_TARGETS: [],
class_json_consts.NESTED_CLASSES: [CLASS_2_NESTED_1], class_json_consts.NESTED_CLASSES: [CLASS_2_NESTED_1],
}, },
}, },
{ {
json_consts.NAME: CLASS_3, json_consts.NAME: CLASS_3,
json_consts.META: { json_consts.META: {
class_json_consts.PACKAGE: 'p2', class_json_consts.PACKAGE:
class_json_consts.CLASS: 'c3', 'p2',
class_json_consts.CLASS:
'c3',
class_json_consts.BUILD_TARGETS:
[BUILD_TARGET_1, BUILD_TARGET_2],
class_json_consts.NESTED_CLASSES: [], class_json_consts.NESTED_CLASSES: [],
}, },
}, },
...@@ -116,9 +124,18 @@ class TestSerialization(unittest.TestCase): ...@@ -116,9 +124,18 @@ class TestSerialization(unittest.TestCase):
test_graph.add_edge_if_new(self.CLASS_1, self.CLASS_2) 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_1, self.CLASS_3)
test_graph.add_edge_if_new(self.CLASS_2, self.CLASS_3) test_graph.add_edge_if_new(self.CLASS_2, self.CLASS_3)
test_graph.add_nested_class_to_key(self.CLASS_1, self.CLASS_1_NESTED_1) test_graph.get_node_by_key(self.CLASS_1).add_nested_class(
test_graph.add_nested_class_to_key(self.CLASS_1, self.CLASS_1_NESTED_2) self.CLASS_1_NESTED_1)
test_graph.add_nested_class_to_key(self.CLASS_2, self.CLASS_2_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) test_json_obj = serialization.create_json_obj_from_graph(test_graph)
...@@ -130,12 +147,12 @@ class TestSerialization(unittest.TestCase): ...@@ -130,12 +147,12 @@ class TestSerialization(unittest.TestCase):
class_graph.add_edge_if_new(self.CLASS_1, self.CLASS_2) 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_1, self.CLASS_3)
class_graph.add_edge_if_new(self.CLASS_2, self.CLASS_3) class_graph.add_edge_if_new(self.CLASS_2, self.CLASS_3)
class_graph.add_nested_class_to_key(self.CLASS_1, class_graph.get_node_by_key(self.CLASS_1).add_nested_class(
self.CLASS_1_NESTED_1) self.CLASS_1_NESTED_1)
class_graph.add_nested_class_to_key(self.CLASS_1, class_graph.get_node_by_key(self.CLASS_1).add_nested_class(
self.CLASS_1_NESTED_2) self.CLASS_1_NESTED_2)
class_graph.add_nested_class_to_key(self.CLASS_2, class_graph.get_node_by_key(self.CLASS_2).add_nested_class(
self.CLASS_2_NESTED_1) self.CLASS_2_NESTED_1)
package_graph = package_dependency.JavaPackageDependencyGraph( package_graph = package_dependency.JavaPackageDependencyGraph(
class_graph) class_graph)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment