From 5a66ea56f6de65b7154af0b7cd95b4b1da1444f6 Mon Sep 17 00:00:00 2001 From: bal0sk Date: Mon, 20 Apr 2026 16:38:44 +0200 Subject: [PATCH 1/4] Fix system z3 being prioritized over local This fixes the issue of ninja crashing when building using nix flakes, when z3 is installed on the system, by prioritizing FindZ3 script before falling back to Z3Config. --- CMakeLists.txt | 2 +- cmake/FindZ3.cmake | 2 +- diffkemp/simpll/CMakeLists.txt | 8 ++++---- tests/unit_tests/simpll/CMakeLists.txt | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82c8958e7..720f093e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set(CMAKE_CXX_STANDARD 17) -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) +list(PREPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) include(GNUInstallDirs) diff --git a/cmake/FindZ3.cmake b/cmake/FindZ3.cmake index d63f967c9..d5a026c07 100644 --- a/cmake/FindZ3.cmake +++ b/cmake/FindZ3.cmake @@ -5,7 +5,7 @@ # Z3_CXX_INCLUDE_DIRS - the z3 C++ include directory # Z3_LIBRARIES - Link these to use libbpf -find_path (Z3_CXX_INCLUDE_DIRS z3++.h) +find_path (Z3_CXX_INCLUDE_DIRS z3++.h PATH_SUFFIXES z3) find_library (Z3_LIBRARIES z3) diff --git a/diffkemp/simpll/CMakeLists.txt b/diffkemp/simpll/CMakeLists.txt index e16cbba6d..3d0ab2726 100644 --- a/diffkemp/simpll/CMakeLists.txt +++ b/diffkemp/simpll/CMakeLists.txt @@ -34,11 +34,11 @@ execute_process(COMMAND llvm-config --system-libs OUTPUT_VARIABLE system_libs OUTPUT_STRIP_TRAILING_WHITESPACE) -# Try to find system-wide Z3 (e.g. local build) -find_package(Z3 CONFIG) +# Use our FindZ3.cmake (e.g. nix build) +find_package(Z3 MODULE) if (NOT ${Z3_FOUND}) - # Use our FindZ3.cmake (e.g. nix build) - find_package(Z3 REQUIRED MODULE) + # Try to find system-wide Z3 (e.g. local build) + find_package(Z3 REQUIRED CONFIG) endif() add_library(simpll-lib ${srcs} ${passes} ${library}) diff --git a/tests/unit_tests/simpll/CMakeLists.txt b/tests/unit_tests/simpll/CMakeLists.txt index 4e50fdfdf..78ca3a687 100644 --- a/tests/unit_tests/simpll/CMakeLists.txt +++ b/tests/unit_tests/simpll/CMakeLists.txt @@ -21,11 +21,11 @@ execute_process(COMMAND llvm-config --system-libs OUTPUT_VARIABLE system_libs OUTPUT_STRIP_TRAILING_WHITESPACE) -# Try to find system-wide Z3 (e.g. local build) -find_package(Z3 CONFIG) +# Use our FindZ3.cmake (e.g. nix build) +find_package(Z3 MODULE) if (NOT ${Z3_FOUND}) - # Use our FindZ3.cmake (e.g. nix build) - find_package(Z3 REQUIRED MODULE) + # Try to find system-wide Z3 (e.g. local build) + find_package(Z3 REQUIRED CONFIG) endif() target_include_directories(simpllTests PRIVATE ${Z3_CXX_INCLUDE_DIRS}) From 65a7bcefe90ee06c2ca1269e37bb3dca9140ca7d Mon Sep 17 00:00:00 2001 From: davidkre525 Date: Sat, 7 Mar 2026 15:05:07 +0000 Subject: [PATCH 2/4] Add comparison of global variables If a global variable is present in the symbol list during function comparison, a group of all functions using this global variable is created, similarly how sysctl comparison is treated. In this case, the overall Result (root of the Result tree) can contain both functions and function groups. Group_kind field was also added to Result so it is possible to distinguish between different kinds of groups, e.g. sysctl and glob_var. --- diffkemp/building/build_kernel.py | 35 +++------------------------ diffkemp/building/build_utils.py | 39 ++++++++++++++++++++++++++++++- diffkemp/compare.py | 18 ++++++++++---- diffkemp/output.py | 6 ++--- diffkemp/semdiff/result.py | 24 ++++++++++++------- diffkemp/snapshot.py | 3 +++ tests/unit_tests/result_test.py | 15 +++++++----- 7 files changed, 84 insertions(+), 56 deletions(-) diff --git a/diffkemp/building/build_kernel.py b/diffkemp/building/build_kernel.py index 218742e41..9c4680990 100644 --- a/diffkemp/building/build_kernel.py +++ b/diffkemp/building/build_kernel.py @@ -4,6 +4,7 @@ from diffkemp.snapshot import Snapshot from diffkemp.building.build_utils import ( generate_from_function_list, + add_funcs_for_globvar, read_symbol_list, EMSG_EMPTY_SYMBOL_LIST) import errno @@ -97,7 +98,8 @@ def generate_from_sysctl_list(snapshot, sysctl_list): # Proc handler function for sysctl _add_proc_handler(snapshot, sysctl, proc_fun) # Adds functions which use the sysctl data variable - _add_funcs_for_data(snapshot, sysctl, sysctl_mod, proc_fun) + data = sysctl_mod.get_data(sysctl) + add_funcs_for_globvar(snapshot, sysctl, data, proc_fun) def _add_proc_handler(snapshot, sysctl, proc_fun): @@ -118,34 +120,3 @@ def _add_proc_handler(snapshot, sysctl, proc_fun): snapshot.source_tree.source_dir))) except SourceNotFoundException: print(" could not build proc handler") - - -def _add_funcs_for_data(snapshot, sysctl, sysctl_mod, proc_fun): - data = sysctl_mod.get_data(sysctl) - - if not data: - return - - for module in \ - snapshot.source_tree.get_modules_using_symbol(data.name): - # For now, we only support the x86 architecture in kernel - if "/arch/" in module.llvm and \ - "/arch/x86/" not in module.llvm: - continue - - curr_mod_path = os.path.relpath(module.llvm, - snapshot.source_tree.source_dir) - for func in module.get_functions_using_param(data): - if func == proc_fun: - continue - - snapshot.add_fun( - name=func, - llvm_mod=module, - glob_var=data.name, - tag="using data variable \"{}\"".format(data.name), - group=sysctl) - print(" {}: {} (using data variable \"{}\")".format( - func, - curr_mod_path, - data.name)) diff --git a/diffkemp/building/build_utils.py b/diffkemp/building/build_utils.py index 2c15da68a..2c5bcf164 100644 --- a/diffkemp/building/build_utils.py +++ b/diffkemp/building/build_utils.py @@ -1,4 +1,5 @@ from diffkemp.llvm_ir.source_tree import SourceNotFoundException +from diffkemp.llvm_ir.llvm_module import LlvmParam import sys import os @@ -41,9 +42,45 @@ def generate_from_function_list(snapshot, fun_list): snapshot.add_fun(symbol, llvm_mod) print(os.path.relpath(llvm_mod.llvm, snapshot.source_tree.source_dir)) + elif llvm_mod.has_global(symbol): + print() + if add_funcs_for_globvar(snapshot, symbol, LlvmParam(symbol)): + snapshot.list_kind = "glob_var" else: snapshot.add_fun(symbol, None) - print("not a function") + print("not a function nor a global variable") except SourceNotFoundException: print("source not found") snapshot.add_fun(symbol, None) + + +def add_funcs_for_globvar(snapshot, name, data, skip_fun=None): + functions_added = False + if not data: + return functions_added + + for module in \ + snapshot.source_tree.get_modules_using_symbol(data.name): + # For now, we only support the x86 architecture in kernel + if "/arch/" in module.llvm and \ + "/arch/x86/" not in module.llvm: + continue + + curr_mod_path = os.path.relpath(module.llvm, + snapshot.source_tree.source_dir) + for func in module.get_functions_using_param(data): + if skip_fun is not None and func == skip_fun: + continue + + functions_added = True + snapshot.add_fun( + name=func, + llvm_mod=module, + glob_var=data.name, + tag="using global variable \"{}\"".format(data.name), + group=name) + print(" {}: {} (using global variable \"{}\")".format( + func, + curr_mod_path, + data.name)) + return functions_added diff --git a/diffkemp/compare.py b/diffkemp/compare.py index 791d3eac5..64db77f3b 100644 --- a/diffkemp/compare.py +++ b/diffkemp/compare.py @@ -33,7 +33,7 @@ def compare(args): class GroupInfo: def __init__(self, group, group_name, enable_module_cache, config, - output_dir): + output_dir, group_kind): self.group = group self.group_name = group_name self.group_dir = self._get_group_dir(output_dir) @@ -44,6 +44,7 @@ def __init__(self, group, group_name, enable_module_cache, config, self.cache = SimpLLCache(mkdtemp()) self.module_cache = {} self.group_result = None + self.group_kind = group_kind def _get_group_dir(self, output_dir): if output_dir is not None and self.group_name is not None: @@ -92,7 +93,8 @@ def __init__(self, cmd_args): self.result = Result(Result.Kind.NONE, cmd_args.snapshot_dir_old, cmd_args.snapshot_dir_new, start_time=default_timer(), - hierarchy_level=Result.HierarchyLevel.OVERALL) + hierarchy=Result.Hierarchy( + Result.Hierarchy.Level.OVERALL)) self.regex_pattern = re.compile(cmd_args.regex_filter) \ if cmd_args.regex_filter else None self.output_dir = None @@ -130,11 +132,15 @@ def _default_output_dir(self): return base_dirname def _compare_snapshots(self): + # group_name could be None or str, which are uncomparable for group_name, group in sorted(self.config.snapshot_first - .fun_groups.items()): + .fun_groups.items(), + key=lambda item: (item[0] is not None, + item[0])): group_info = GroupInfo(group, group_name, self.args.enable_module_cache, - self.config, self.output_dir) + self.config, self.output_dir, + self.config.snapshot_first.list_kind) self._compare_groups(group_info) self._finalize_output() @@ -149,7 +155,9 @@ def _compare_groups(self, group_info): Result.Kind.NONE, group_name, group_name, - hierarchy_level=Result.HierarchyLevel.GROUP) + hierarchy=Result.Hierarchy( + Result.Hierarchy.Level.GROUP, + group_info.group_kind)) else: group_info.group_result = self.result diff --git a/diffkemp/output.py b/diffkemp/output.py index b99b4ee22..c28526b57 100644 --- a/diffkemp/output.py +++ b/diffkemp/output.py @@ -35,7 +35,7 @@ def _create_output(self): def _create_results(self, current_result, name=None): """:param current_result: node in the result class tree""" - if current_result.hierarchy_level == Result.HierarchyLevel.FUNCTION: + if current_result.hierarchy.level == Result.Hierarchy.Level.FUNCTION: return self._create_function_result(current_result, name) inner_results = [] @@ -44,11 +44,11 @@ def _create_results(self, current_result, name=None): if result is not None: inner_results.append(result) - if current_result.hierarchy_level == Result.HierarchyLevel.OVERALL: + if current_result.hierarchy.level == Result.Hierarchy.Level.OVERALL: return inner_results # hierarchy_level == GROUP return { - "sysctl": name, # sysctl is the only usecase of groups + current_result.hierarchy.group_kind: name, "results": inner_results } diff --git a/diffkemp/semdiff/result.py b/diffkemp/semdiff/result.py index a02751461..ebba30b91 100644 --- a/diffkemp/semdiff/result.py +++ b/diffkemp/semdiff/result.py @@ -183,11 +183,16 @@ def __init__(self, name, filename=None, line=None, callstack=None, self.diff_kind = diff_kind self.covered = covered - class HierarchyLevel(IntEnum): + class Hierarchy: """Describes position of result instance in result comparison tree""" - OVERALL = 0 - GROUP = 1 - FUNCTION = 2 + class Level(IntEnum): + OVERALL = 0 + GROUP = 1 + FUNCTION = 2 + + def __init__(self, level, group_kind=None): + self.level = level + self.group_kind = group_kind class SymbolStat: def __init__(self): @@ -199,7 +204,8 @@ def __init__(self): self.empty_diff = 0 def __init__(self, kind, first_name, second_name, start_time=None, - stop_time=None, hierarchy_level=HierarchyLevel.FUNCTION): + stop_time=None, + hierarchy=Hierarchy(Hierarchy.Level.FUNCTION)): self.kind = kind self.first = Result.Entity(first_name) self.second = Result.Entity(second_name) @@ -209,7 +215,7 @@ def __init__(self, kind, first_name, second_name, start_time=None, self.inner = dict() self.start_time = start_time self.stop_time = stop_time - self.hierarchy_level = hierarchy_level + self.hierarchy = hierarchy def __str__(self): return str(self.kind) @@ -264,7 +270,7 @@ def report_symbol_stat(self, show_errors=False): def print_function_names(self, kind): for name, result in self.inner.items(): - if result.hierarchy_level == Result.HierarchyLevel.FUNCTION: + if result.hierarchy.level == Result.Hierarchy.Level.FUNCTION: if result.kind == kind: print(name) else: @@ -273,7 +279,7 @@ def print_function_names(self, kind): def _populate_symbol_stat(self, stats): """Aggregate statistics about analysed symbols.""" for result in self.inner.values(): - if result.hierarchy_level == Result.HierarchyLevel.FUNCTION: + if result.hierarchy.level == Result.Hierarchy.Level.FUNCTION: stats.total += 1 stats.eq += result.kind == Result.Kind.EQUAL stats.neq += result.kind == Result.Kind.NOT_EQUAL @@ -306,7 +312,7 @@ def __hash__(self): return hash(self.res.first.name) def _populate_unique_diffs(result, unique_diffs): - if result.hierarchy_level == Result.HierarchyLevel.FUNCTION: + if result.hierarchy.level == Result.Hierarchy.Level.FUNCTION: for _, inner_res in result.inner.items(): if (inner_res.diff == "" and inner_res.first.covered): diff --git a/diffkemp/snapshot.py b/diffkemp/snapshot.py index 165a2e1d8..b63879c38 100644 --- a/diffkemp/snapshot.py +++ b/diffkemp/snapshot.py @@ -229,6 +229,9 @@ def _from_yaml(self, yaml_file): if "sysctl" in g: group = g["sysctl"] functions = g["functions"] + elif "glob_var" in g: + group = g["glob_var"] + functions = g["functions"] else: group = None functions = g diff --git a/tests/unit_tests/result_test.py b/tests/unit_tests/result_test.py index 07749a17b..3eb4acf35 100644 --- a/tests/unit_tests/result_test.py +++ b/tests/unit_tests/result_test.py @@ -123,7 +123,7 @@ def single_function_result(graph): @pytest.fixture def multi_functions_result(graph, single_function_result): result = Result(Result.Kind.NONE, "old-snapshot-path", "new-snapshot-path", - hierarchy_level=Result.HierarchyLevel.OVERALL) + hierarchy=Result.Hierarchy(Result.Hierarchy.Level.OVERALL)) result.add_inner(single_function_result) result.graph = graph yield result @@ -132,9 +132,10 @@ def multi_functions_result(graph, single_function_result): @pytest.fixture def sysctl_group_result(graph, single_function_result): result = Result(Result.Kind.NONE, "old-snapshot-path", "new-snapshot-path", - hierarchy_level=Result.HierarchyLevel.OVERALL) + hierarchy=Result.Hierarchy(Result.Hierarchy.Level.OVERALL)) group_result = Result(Result.Kind.NONE, "group_name", "group_name", - hierarchy_level=Result.HierarchyLevel.GROUP) + hierarchy=Result.Hierarchy( + Result.Hierarchy.Level.GROUP, "sysctl")) group_result.add_inner(single_function_result) result.add_inner(group_result) result.graph = graph @@ -144,11 +145,13 @@ def sysctl_group_result(graph, single_function_result): @pytest.fixture def multi_groups_result(graph, single_function_result): result = Result(Result.Kind.NONE, "old-snapshot-path", "new-snapshot-path", - hierarchy_level=Result.HierarchyLevel.OVERALL) + hierarchy=Result.Hierarchy(Result.Hierarchy.Level.OVERALL)) outer_group_result = Result(Result.Kind.NONE, "outer_name", "outer_name", - hierarchy_level=Result.HierarchyLevel.GROUP) + hierarchy=Result.Hierarchy( + Result.Hierarchy.Level.GROUP, "sysctl")) inner_group_result = Result(Result.Kind.NONE, "inner_name", "inner_name", - hierarchy_level=Result.HierarchyLevel.GROUP) + hierarchy=Result.Hierarchy( + Result.Hierarchy.Level.GROUP, "sysctl")) inner_group_result.add_inner(single_function_result) outer_group_result.add_inner(inner_group_result) result.add_inner(outer_group_result) From b76c7db81a9c19ffd6a69fe37a5f9b6bc474eaa7 Mon Sep 17 00:00:00 2001 From: davidkre525 Date: Tue, 24 Mar 2026 23:25:13 +0000 Subject: [PATCH 3/4] Adjust result viewer for new result format The result viewer was changed to handle different shapes of the result comparison tree. The viewer displays differences in the same way as before the change, that is it only shows the differences found in functions, not how these functions are aggregated in groups. --- view/src/Result.js | 90 ++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/view/src/Result.js b/view/src/Result.js index 1305b7bb3..902b2c4d2 100644 --- a/view/src/Result.js +++ b/view/src/Result.js @@ -36,16 +36,6 @@ export default class Result { /** Absolute path to new snapshot. */ newSnapshot; - /** - * Comparison results with the following structure: - * -results: - * -sysctl: name (this field exists only in case of sysctl comparison) - * results: - * -function: name - * -diffs - */ - results; - /** * Create Result from YAML file. * @param {Object} yaml YAML file describing result of diffkemp compare. @@ -54,56 +44,70 @@ export default class Result { this.definitions = yaml.definitions; this.oldSnapshot = yaml['old-snapshot']; this.newSnapshot = yaml['new-snapshot']; - if (yaml.results.length !== 0 && !('function' in yaml.results[0])) { - this.results = yaml.results; - } else { - this.results = [{ results: yaml.results }]; - } - // Sort differing functions of each compared function - this.results.forEach((groupResult) => { - groupResult.results.forEach((result) => { - result.diffs.sort((diffA, diffB) => compareFunctionNames(diffA.function, diffB.function)); + this.#sortDifferingFunctions(yaml); + this.#createAllCompAndDiffFuns(yaml); + } + + /** + * Sort differing functions of each compared function + */ + #sortDifferingFunctions(result) { + if ('diffs' in result) { + result.diffs.sort((diffA, diffB) => compareFunctionNames(diffA.function, diffB.function)); + } else { + result.results.forEach((subresult) => { + this.#sortDifferingFunctions(subresult); }); - }); - this.#createAllCompAndDiffFuns(); + } } /** * Creates allCompFuns and allDiffFuns fields. - * Expects that names of differing functions are sorted in the `results`. + * Expects that names of differing functions are sorted in the `result`. + * If one function is present in multiple groups, only the first occourrence + * is stored in the #allCompFuns Map. */ - #createAllCompAndDiffFuns() { + #createAllCompAndDiffFuns(result) { // Map(compFunName, Map(diffFunName, diff)) this.#allCompFuns = new Map(); // Map(diffFunName, [...compFunNames]) this.#allDiffFuns = new Map(); - // foreach group (sysctl or all functions) - this.results.forEach((groupResult) => { - // foreach result (compared function) - groupResult.results.forEach((result) => { - if (!this.#allCompFuns.has(result.function)) { - // Map(diffFunName, diff) - const diffFunsForComp = new Map(); - // for each diff (differing function) - result.diffs.forEach((diff) => { - diffFunsForComp.set(diff.function, diff); - if (this.#allDiffFuns.has(diff.function)) { - this.#allDiffFuns.get(diff.function).push(result.function); - } else { - this.#allDiffFuns.set(diff.function, [result.function]); - } - }); - this.#allCompFuns.set(result.function, diffFunsForComp); - } - }); - }); + // populate allCompFuns and allDiffFuns recursively + this.#compAndDiffFunsRec(result); // sort all compared functions this.#allCompFuns = new Map([...this.#allCompFuns] .sort((a, b) => compareFunctionNames(a[0], b[0]))); // sort keys (differing function names) in the map this.#allDiffFuns = new Map([...this.#allDiffFuns] .sort((a, b) => compareFunctionNames(a[0], b[0]))); + // sort compFunNames for each diffFunName + this.#allDiffFuns.forEach((compFunNames) => { + compFunNames.sort((funA, funB) => compareFunctionNames(funA, funB)); + }); + } + + #compAndDiffFunsRec(result) { + if (!('diffs' in result)) { + result.results.forEach((subresult) => { + this.#compAndDiffFunsRec(subresult); + }); + return; + } + if (!this.#allCompFuns.has(result.function)) { + // Map(diffFunName, diff) + const diffFunsForComp = new Map(); + // for each diff (differing function) + result.diffs.forEach((diff) => { + diffFunsForComp.set(diff.function, diff); + if (this.#allDiffFuns.has(diff.function)) { + this.#allDiffFuns.get(diff.function).push(result.function); + } else { + this.#allDiffFuns.set(diff.function, [result.function]); + } + }); + this.#allCompFuns.set(result.function, diffFunsForComp); + } } /** From a5aa1518a9d6f2d35ebfba1614500015af4c3334 Mon Sep 17 00:00:00 2001 From: davidkre525 Date: Wed, 25 Mar 2026 08:22:37 +0000 Subject: [PATCH 4/4] Add tests for the result viewer A few tests were added to test whether the result viewer can handle different shapes of the result comparison tree. --- view/src/tests/Result.test.js | 95 +++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/view/src/tests/Result.test.js b/view/src/tests/Result.test.js index 0af8f8c0a..d07df08fa 100644 --- a/view/src/tests/Result.test.js +++ b/view/src/tests/Result.test.js @@ -39,14 +39,77 @@ const yaml = { ], }; +const yamlGroups = { + results: [ + { + function: 'fun3', + diffs: [ + { + function: 'fun2', + 'old-callstack': [], + 'new-callstack': [], + }, + { + function: 'fun3', + 'old-callstack': [], + 'new-callstack': [], + }, + ], + }, + { + glob_var: 'glob1', + results: [ + { + function: 'fun1', + diffs: [ + { + function: 'fun2', + 'old-callstack': [], + 'new-callstack': [], + }, + { + function: 'fun1', + 'old-callstack': [], + 'new-callstack': [], + }, + ], + }, + ], + }, + { + multi_group: 'multi1', + results: [ + { + glob_var: 'glob2', + results: [ + { + function: 'fun4', + diffs: [ + { + function: 'fun4', + 'old-callstack': [], + 'new-callstack': [], + }, + ], + }, + ], + }, + ], + }, + ], +}; + let result = null; +let resultGroups = null; beforeAll(() => { result = new Result(yaml); + resultGroups = new Result(yamlGroups); }); test('getCompFuns should return sorted array of all compared functions', () => { expect(result.getCompFuns()).toEqual(['down_read', 'scsi_host_alloc']); + expect(resultGroups.getCompFuns()).toEqual(['fun1', 'fun3', 'fun4']); }); test('getCompFuns for differing function should return sorted array of compared functions which differs in specified function', () => { @@ -54,6 +117,10 @@ test('getCompFuns for differing function should return sorted array of compared 'down_read', 'scsi_host_alloc', ]); + expect(resultGroups.getCompFuns('fun2')).toEqual([ + 'fun1', + 'fun3', + ]); }); test('getDiffFuns should return sorted array of all differing functions', () => { @@ -62,6 +129,12 @@ test('getDiffFuns should return sorted array of all differing functions', () => 'down_read', 'scsi_host_alloc', ]); + expect(resultGroups.getDiffFuns()).toEqual([ + 'fun1', + 'fun2', + 'fun3', + 'fun4', + ]); }); test('getDiffFuns for compared function should return sorted array of function in which the compared function differs', () => { @@ -69,44 +142,66 @@ test('getDiffFuns for compared function should return sorted array of function i '__down_read', 'scsi_host_alloc', ]); + expect(resultGroups.getDiffFuns('fun1')).toEqual([ + 'fun1', + 'fun2', + ]); }); test('getNextCompName should return next compared function', () => { expect(result.getNextCompName('down_read')).toEqual('scsi_host_alloc'); + expect(resultGroups.getNextCompName('fun1')).toEqual('fun3'); }); test('getPrevCompName should return previous compared function', () => { expect(result.getPrevCompName('scsi_host_alloc')).toEqual('down_read'); + expect(resultGroups.getPrevCompName('fun4')).toEqual('fun3'); }); test('getNextDiffFunNameForComp should return next differing function for compared function', () => { expect( result.getNextDiffFunNameForComp('down_read', '__down_read'), ).toEqual('down_read'); + expect( + resultGroups.getNextDiffFunNameForComp('fun3', 'fun2'), + ).toEqual('fun3'); }); + test('getPrevDiffFunNameForComp should return previous differing function for compared function', () => { expect(result.getPrevDiffFunNameForComp('down_read', 'down_read')).toEqual( '__down_read', ); + expect(resultGroups.getPrevDiffFunNameForComp('fun1', 'fun2')).toEqual( + 'fun1', + ); }); + test('getDiff should return item from results diffs for specified compared and differing function', () => { expect(result.getDiff('down_read', 'down_read')).toBe( yaml.results[0].diffs[1], ); + expect(resultGroups.getDiff('fun4', 'fun4')).toBe( + yamlGroups.results[2].results[0].results[0].diffs[0], + ); }); test('isFirstCompFun should return true for first compared function', () => { expect(result.isFirstCompFun('down_read')).toBe(true); + expect(resultGroups.isFirstCompFun('fun1')).toBe(true); }); test('isLastCompFun should return true for last compared function', () => { expect(result.isLastCompFun('scsi_host_alloc')).toBe(true); + expect(resultGroups.isLastCompFun('fun4')).toBe(true); }); test('isFirstDiffFunForComp should return true for first differing function of compared function', () => { expect(result.isFirstDiffFunForComp('down_read', '__down_read')).toBe(true); + expect(resultGroups.isFirstDiffFunForComp('fun1', 'fun1')).toBe(true); }); test('isLastDiffFunForComp should return true for last differing function of compared function', () => { expect(result.isLastDiffFunForComp('down_read', 'down_read')).toBe(true); + expect(resultGroups.isLastDiffFunForComp('fun4', 'fun4')).toBe(true); }); test('getFirstDiffFunForComp should return first differing function for compared function', () => { expect(result.getFirstDiffFunForComp('down_read')).toEqual('__down_read'); + expect(resultGroups.getFirstDiffFunForComp('fun3')).toEqual('fun2'); });