def run_cov_with_arg(self, args): MANAGER = cov_manager.CovManager() with MANAGER.temp_manager(): c = cov_config.ConfigNamespace() cov_mod.parse_args(args, namespace=c) inference_extension.enable() klara.initialize(c) c.output_file = self.result cov_mod.run(c) return self.result.getvalue()
import pytest import os import pathlib import sys import tempfile import unittest from textwrap import dedent from klara.contract.__main__ import run from klara.contract.config import ContractConfig from klara.klara_z3 import cov_manager, inference_extension from ..helper import base_test MANAGER = cov_manager.CovManager() class KlaraBaseTest(base_test.BaseTest): _TEST_MODULE_NAME = "contract_test" unique_id = 0 @classmethod def setUpClass(cls) -> None: config = ContractConfig() MANAGER.initialize(config) inference_extension.enable() def setUp(self) -> None: super(KlaraBaseTest, self).setUp() self.cwd = os.getcwd()
class BaseCovTest(BaseTestPatchCondResult): sample_data_xml = None cwd = os.getcwd() cov_manager = cov_manager.CovManager() def tearDown(self): prm_data.clear() @classmethod def setUpClass(cls): super(BaseCovTest, cls).setUpClass() @classmethod def tearDownClass(cls) -> None: super(BaseCovTest, cls).tearDownClass() def init_solver(self, **kwargs): prm_data.append(ET.parse(self.sample_data_xml.open())) config = self.setup_cov_config(py_version=3, analyze_procedure=True, entry_class="MyClass", entry_func="Top", enable_infer_sequence=True, overwrite=True, **kwargs) inference_extension.enable() return config def run_solver_with_cov(self, ast_str, max_iterations, expected_coverage=100, expected_return=None, **kwargs): config = self.init_solver(**kwargs) MANAGER.config = config MANAGER.register_transform(nodes.FunctionDef, transform_init, lambda x: x.name == "init") MANAGER.register_transform(nodes.Subscript, _infer_end_subscript, is_cfg) result = cov_solve(ast_str, cov_config=config) self.assertLessEqual(len(result), max_iterations) _, filename = tempfile.mkstemp(prefix="test_sample", suffix=".py") with open(filename, "w") as file: file.write(ast_str) spec = importlib.util.spec_from_file_location("test_sample", str(filename)) module = importlib.util.module_from_spec(spec) sys.modules["test_sample"] = module coverage_instance = coverage.Coverage(include="*test_sample*") coverage_instance.start() spec.loader.exec_module(module) expected_return = expected_return or list() expected_return = list(expected_return) for r in result: c = module.MyClass() c.cfg = DictWrapper(r) c.init() val = c.Top() if val in expected_return: expected_return.remove(val) assert len( expected_return) == 0, "values: {} has not been return".format( expected_return) coverage_instance.stop() coverage_percentage = coverage_instance.report() if coverage_percentage < expected_coverage: parent_function = inspect.getframeinfo( inspect.currentframe().f_back).function output_dir = str(self.cwd / ("test_" + str(parent_function))) if os.path.exists(output_dir): shutil.rmtree(output_dir) os.makedirs(output_dir) with open(os.path.join(output_dir, "dump_result.json"), "w") as json_file: json.dump(result, json_file, indent=4) coverage_instance.html_report(directory=output_dir) self.fail( "Coverage: {}%, does not match the expected coverage: {}%." "\nPlease check directory: {} for coverage information".format( coverage_percentage, expected_coverage, output_dir)) del sys.modules["test_sample"] del module os.remove(filename) def run_and_assert_line_fix(self, ast_str, linenos, func, minimal_len=None, **kwargs): config = self.init_solver(**kwargs, cover_lines=linenos) MANAGER.register_transform(nodes.FunctionDef, transform_init, lambda x: x.name == "init") MANAGER.register_transform(nodes.Subscript, _infer_end_subscript, is_cfg) result = line_fix_solve(ast_str, config) minimal_len = len(linenos) if minimal_len is None else minimal_len assert len(linenos) >= len(result) >= minimal_len for res in result: assert func(res) return result def run_fix_all_and_assert_line_fix(self, ast_str, func, **kwargs): config = self.init_solver(**kwargs, cover_all=True) MANAGER.register_transform(nodes.FunctionDef, transform_init, lambda x: x.name == "init") MANAGER.register_transform(nodes.Subscript, _infer_end_subscript, is_cfg) result = line_fix_solve(ast_str, config) assert result for res in result: assert func(res) return result def run_cover_return(self, ast_str, max_iterations, func, lt_flag=False, **kwargs): config = self.init_solver(**kwargs) MANAGER.register_transform(nodes.FunctionDef, transform_init, lambda x: x.name == "init") MANAGER.register_transform(nodes.Subscript, _infer_end_subscript, is_cfg) result = cov_solve(ast_str, cov_config=config) if lt_flag: assert len(result) <= max_iterations else: assert len(result) == max_iterations for res in result: assert func(res) def run_result_return(self, ast_str, **kwargs): config = self.init_solver(**kwargs) MANAGER.register_transform(nodes.FunctionDef, transform_init, lambda x: x.name == "init") MANAGER.register_transform(nodes.Subscript, _infer_end_subscript, is_cfg) with utilities.temp_config(MANAGER, config): as_tree = self.cov_manager.build_tree(ast_str) c = self.cov_manager.build_cfg(as_tree) df = solver.DepFinder(c, as_tree) df.solve_classdef() for cls in df.classes: top_level = cls.get_latest_stmt(df.entry_func) yield from top_level.infer_return_value(df.context)
def initialize(config: Config = None, smt_disable: bool = False) -> None: """initialize klara to a different configuration :param config: a config object of type Klara.Config to fine tune configuration :param smt_disable: disable z3 solver support :return: None """ if smt_disable: manager = _core_manager.AstManager() manager.initialize(config or Config()) _infer_extension.disable() else: MANAGER.initialize(config or Config()) _infer_extension.enable() MANAGER = _manager.CovManager() """A Central manager responsible to cache result, and various common operation across module""" initialize() def parse(source: str, py2: bool = False) -> Module: """parse python code as ast, apply analysis transformation and return modified tree :param source: python source file as string :param py2: True if `source` is python 2, False if it's in python 3 :return: a modified abstract syntax tree with inference support """ MANAGER.config.py_version = 2 if py2 else 3 tree = MANAGER.build_tree(source) MANAGER.build_cfg(tree) return tree