sflkit 0.2.17__tar.gz → 0.2.19__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sflkit-0.2.17/src/sflkit.egg-info → sflkit-0.2.19}/PKG-INFO +1 -1
- {sflkit-0.2.17 → sflkit-0.2.19}/pyproject.toml +1 -1
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/__init__.py +1 -1
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/config.py +14 -1
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/instrumentation/__init__.py +4 -6
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/instrumentation/dir_instrumentation.py +4 -3
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/instrumentation/file_instrumentation.py +5 -4
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/mapping.py +17 -9
- sflkit-0.2.19/src/sflkit/runners/resources/__init__.py +0 -0
- sflkit-0.2.19/src/sflkit/runners/resources/pytest_main.py +82 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/runners/run.py +47 -12
- {sflkit-0.2.17 → sflkit-0.2.19/src/sflkit.egg-info}/PKG-INFO +1 -1
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit.egg-info/SOURCES.txt +2 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_config.py +1 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_instrumentation.py +71 -6
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_runner.py +1 -1
- {sflkit-0.2.17 → sflkit-0.2.19}/LICENSE +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/README.md +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/setup.cfg +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/__init__.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/analysis_type.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/analyzer.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/factory.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/mapping.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/predicate.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/similarity.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/spectra.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/analysis/suggestion.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/cli.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/color.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/__init__.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/extract.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/finder.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/language.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/meta.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/python/__init__.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/python/extract.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/python/factory.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/python/finder.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/python/visitor.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/language/visitor.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/logger.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/model/__init__.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/model/event_file.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/model/model.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/model/scope.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit/runners/__init__.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit.egg-info/dependency_links.txt +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit.egg-info/entry_points.txt +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit.egg-info/requires.txt +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/src/sflkit.egg-info/top_level.txt +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_analysis_objects.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_cli.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_color.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_coverage.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_events.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_execution.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_language.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_predicates.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_scope.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_spectra.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_suggestions.py +0 -0
- {sflkit-0.2.17 → sflkit-0.2.19}/tests/test_visitors.py +0 -0
|
@@ -8,7 +8,7 @@ from sflkit.instrumentation.dir_instrumentation import DirInstrumentation
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def instrument_config(conf: Config):
|
|
11
|
-
instrumentation = DirInstrumentation(conf.visitor)
|
|
11
|
+
instrumentation = DirInstrumentation(conf.visitor, conf.mapping.path)
|
|
12
12
|
instrumentation.instrument(
|
|
13
13
|
conf.target_path,
|
|
14
14
|
conf.instrument_working,
|
|
@@ -77,6 +77,7 @@ class Config:
|
|
|
77
77
|
self.instrument_working = None
|
|
78
78
|
self.runner = None
|
|
79
79
|
self.mapping = None
|
|
80
|
+
self.mapping_path = None
|
|
80
81
|
if path:
|
|
81
82
|
if isinstance(path, configparser.ConfigParser):
|
|
82
83
|
config = path
|
|
@@ -143,10 +144,12 @@ class Config:
|
|
|
143
144
|
self.metrics = [Spectrum.Ochiai]
|
|
144
145
|
|
|
145
146
|
run_id_generator = IDGenerator()
|
|
147
|
+
if "mapping" in events:
|
|
148
|
+
self.mapping_path = Path(events["mapping"])
|
|
146
149
|
try:
|
|
147
150
|
self.mapping = EventMapping.load(self)
|
|
148
151
|
except InstrumentationError:
|
|
149
|
-
self.mapping = EventMapping()
|
|
152
|
+
self.mapping = EventMapping(path=self.mapping_path)
|
|
150
153
|
if "passing" in events:
|
|
151
154
|
self.passing = self.get_event_files(
|
|
152
155
|
list(csv.reader([events["passing"]]))[0],
|
|
@@ -198,6 +201,7 @@ class Config:
|
|
|
198
201
|
visitor: ASTVisitor = None,
|
|
199
202
|
passing: List[EventFile] = None,
|
|
200
203
|
failing: List[EventFile] = None,
|
|
204
|
+
mapping: EventMapping = None,
|
|
201
205
|
instrument_include: List[str] = None,
|
|
202
206
|
instrument_exclude: List[str] = None,
|
|
203
207
|
instrument_working: str = None,
|
|
@@ -220,6 +224,10 @@ class Config:
|
|
|
220
224
|
conf.instrument_exclude = instrument_exclude if instrument_exclude else list()
|
|
221
225
|
conf.instrument_working = instrument_working
|
|
222
226
|
conf.runner = runner
|
|
227
|
+
if mapping:
|
|
228
|
+
conf.mapping = mapping
|
|
229
|
+
if mapping.path:
|
|
230
|
+
conf.mapping_path = mapping.path
|
|
223
231
|
return conf
|
|
224
232
|
|
|
225
233
|
@staticmethod
|
|
@@ -263,6 +271,7 @@ class Config:
|
|
|
263
271
|
metrics=None,
|
|
264
272
|
passing=None,
|
|
265
273
|
failing=None,
|
|
274
|
+
mapping_path=None,
|
|
266
275
|
working=None,
|
|
267
276
|
include=None,
|
|
268
277
|
exclude=None,
|
|
@@ -288,6 +297,8 @@ class Config:
|
|
|
288
297
|
conf["events"]["passing"] = passing
|
|
289
298
|
if failing:
|
|
290
299
|
conf["events"]["failing"] = failing
|
|
300
|
+
if mapping_path:
|
|
301
|
+
conf["events"]["mapping"] = mapping_path
|
|
291
302
|
if working:
|
|
292
303
|
conf["instrumentation"]["path"] = working
|
|
293
304
|
if include:
|
|
@@ -320,6 +331,8 @@ class Config:
|
|
|
320
331
|
conf["events"]["passing"] = ",".join(e.path for e in self.passing)
|
|
321
332
|
if self.failing:
|
|
322
333
|
conf["events"]["failing"] = ",".join(e.path for e in self.failing)
|
|
334
|
+
if self.mapping_path:
|
|
335
|
+
conf["events"]["mapping"] = str(self.mapping_path)
|
|
323
336
|
if self.instrument_working:
|
|
324
337
|
conf["instrumentation"]["path"] = str(self.instrument_working)
|
|
325
338
|
if self.instrument_include:
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import json
|
|
2
1
|
from abc import abstractmethod
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from sflkitlib.events import event
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import List, Optional
|
|
6
4
|
|
|
7
5
|
from sflkit import Config
|
|
8
6
|
from sflkit.language.visitor import ASTVisitor
|
|
@@ -10,9 +8,9 @@ from sflkit.mapping import EventMapping
|
|
|
10
8
|
|
|
11
9
|
|
|
12
10
|
class Instrumentation:
|
|
13
|
-
def __init__(self, visitor: ASTVisitor):
|
|
11
|
+
def __init__(self, visitor: ASTVisitor, mapping_path: Optional[Path] = None):
|
|
14
12
|
self.visitor = visitor
|
|
15
|
-
self.events = EventMapping()
|
|
13
|
+
self.events = EventMapping(path=mapping_path)
|
|
16
14
|
|
|
17
15
|
@abstractmethod
|
|
18
16
|
def instrument(
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import queue
|
|
3
3
|
import re
|
|
4
4
|
import shutil
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
from typing import List, Optional, Iterable, Tuple
|
|
6
7
|
|
|
7
8
|
from sflkit.instrumentation import Instrumentation
|
|
@@ -11,9 +12,9 @@ from sflkit.logger import LOGGER
|
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class DirInstrumentation(Instrumentation):
|
|
14
|
-
def __init__(self, visitor: ASTVisitor):
|
|
15
|
-
super().__init__(visitor)
|
|
16
|
-
self.file_instrumentation = FileInstrumentation(visitor)
|
|
15
|
+
def __init__(self, visitor: ASTVisitor, mapping_path: Optional[Path] = None):
|
|
16
|
+
super().__init__(visitor, mapping_path)
|
|
17
|
+
self.file_instrumentation = FileInstrumentation(visitor, mapping_path)
|
|
17
18
|
|
|
18
19
|
@staticmethod
|
|
19
20
|
def check_included(element: str, includes: Optional[Iterable[str]]):
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import List, Optional
|
|
2
3
|
|
|
3
4
|
from sflkit.instrumentation import Instrumentation
|
|
4
5
|
from sflkit.language.visitor import ASTVisitor
|
|
@@ -6,13 +7,13 @@ from sflkit.mapping import EventMapping
|
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class FileInstrumentation(Instrumentation):
|
|
9
|
-
def __init__(self, visitor: ASTVisitor):
|
|
10
|
-
super().__init__(visitor)
|
|
10
|
+
def __init__(self, visitor: ASTVisitor, mapping_path: Optional[Path] = None):
|
|
11
|
+
super().__init__(visitor, mapping_path)
|
|
11
12
|
|
|
12
13
|
def instrument(
|
|
13
14
|
self, src: str, dst: str, suffixes: List[str] = None, file: str = ""
|
|
14
15
|
):
|
|
15
16
|
self.visitor.instrument(src, dst, file)
|
|
16
17
|
self.events = EventMapping(
|
|
17
|
-
{event.event_id: event for event in self.visitor.events}
|
|
18
|
+
{event.event_id: event for event in self.visitor.events}, self.events.path
|
|
18
19
|
)
|
|
@@ -13,37 +13,45 @@ class InstrumentationError(RuntimeError):
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class EventMapping:
|
|
16
|
-
def __init__(
|
|
16
|
+
def __init__(
|
|
17
|
+
self, mapping: Dict[int, Event] = None, path: Optional[os.PathLike] = None
|
|
18
|
+
):
|
|
17
19
|
self.mapping = mapping or dict()
|
|
20
|
+
self.path = path
|
|
18
21
|
|
|
19
22
|
def get(self, event_id) -> Optional[Event]:
|
|
20
23
|
return self.mapping.get(event_id, None)
|
|
21
24
|
|
|
22
25
|
@staticmethod
|
|
23
|
-
def get_path(identifier: str):
|
|
26
|
+
def get_path(identifier: str) -> Path:
|
|
24
27
|
return SFLKIT_PATH / f"{identifier}.json"
|
|
25
28
|
|
|
26
29
|
@staticmethod
|
|
27
30
|
def load(config: Any):
|
|
28
31
|
if not hasattr(config, "identifier"):
|
|
29
32
|
raise InstrumentationError(f"Argument does not have an identifier")
|
|
30
|
-
return EventMapping.load_from_file(
|
|
33
|
+
return EventMapping.load_from_file(
|
|
34
|
+
config.mapping_path or EventMapping.get_path(config.identifier()),
|
|
35
|
+
config.target_path,
|
|
36
|
+
)
|
|
31
37
|
|
|
32
38
|
@staticmethod
|
|
33
|
-
def load_from_file(
|
|
34
|
-
file = EventMapping.get_path(identifier)
|
|
39
|
+
def load_from_file(file: Path, path: os.PathLike):
|
|
35
40
|
if file.exists():
|
|
36
|
-
return EventMapping(load_json(file))
|
|
41
|
+
return EventMapping(load_json(file), file)
|
|
37
42
|
else:
|
|
38
43
|
raise InstrumentationError(
|
|
39
|
-
f"Cannot find information about instrumentation of {
|
|
44
|
+
f"Cannot find information about instrumentation of {path or file}"
|
|
40
45
|
)
|
|
41
46
|
|
|
42
47
|
def write(self, config):
|
|
43
48
|
if not hasattr(config, "identifier"):
|
|
44
49
|
raise InstrumentationError(f"Argument does not have an identifier")
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
if self.path:
|
|
51
|
+
file = self.path
|
|
52
|
+
else:
|
|
53
|
+
SFLKIT_PATH.mkdir(parents=True, exist_ok=True)
|
|
54
|
+
file = self.get_path(config.identifier())
|
|
47
55
|
with file.open("w") as fp:
|
|
48
56
|
json.dump(list(self.mapping.values()), fp, cls=EventEncoder)
|
|
49
57
|
|
|
File without changes
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from typing import Optional, Union, List, Sequence
|
|
4
|
+
|
|
5
|
+
# noinspection PyPackageRequirements
|
|
6
|
+
from _pytest._code import ExceptionInfo
|
|
7
|
+
|
|
8
|
+
# noinspection PyPackageRequirements
|
|
9
|
+
from _pytest._io import TerminalWriter
|
|
10
|
+
|
|
11
|
+
# noinspection PyPackageRequirements
|
|
12
|
+
from _pytest.config import (
|
|
13
|
+
ExitCode,
|
|
14
|
+
_prepareconfig,
|
|
15
|
+
ConftestImportFailure,
|
|
16
|
+
UsageError,
|
|
17
|
+
filter_traceback_for_conftest_import_failure,
|
|
18
|
+
_PluggyPlugin,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def pytest_collection_finish(session):
|
|
23
|
+
"""
|
|
24
|
+
Called after collection has been performed and modified.
|
|
25
|
+
"""
|
|
26
|
+
file = os.getenv("SFLKIT_PYTEST_COLLECTION_FINISH_FILE", "tmp_sflkit_pytest")
|
|
27
|
+
with open(file, "w") as f:
|
|
28
|
+
for item in session.items:
|
|
29
|
+
f.write(item.nodeid + "\n")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main(
|
|
33
|
+
args: Optional[Union[List[str], "os.PathLike[str]"]] = None,
|
|
34
|
+
plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None,
|
|
35
|
+
) -> Union[int, ExitCode]:
|
|
36
|
+
"""Perform an in-process test run.
|
|
37
|
+
|
|
38
|
+
:param args: List of command line arguments.
|
|
39
|
+
:param plugins: List of plugin objects to be auto-registered during initialization.
|
|
40
|
+
|
|
41
|
+
:returns: An exit code.
|
|
42
|
+
"""
|
|
43
|
+
try:
|
|
44
|
+
try:
|
|
45
|
+
config = _prepareconfig(args, plugins)
|
|
46
|
+
except ConftestImportFailure as e:
|
|
47
|
+
exc_info = ExceptionInfo.from_exc_info(e.excinfo)
|
|
48
|
+
tw = TerminalWriter(sys.stderr)
|
|
49
|
+
tw.line(f"ImportError while loading conftest '{e.path}'.", red=True)
|
|
50
|
+
exc_info.traceback = exc_info.traceback.filter(
|
|
51
|
+
filter_traceback_for_conftest_import_failure
|
|
52
|
+
)
|
|
53
|
+
exc_repr = (
|
|
54
|
+
exc_info.getrepr(style="short", chain=False)
|
|
55
|
+
if exc_info.traceback
|
|
56
|
+
else exc_info.exconly()
|
|
57
|
+
)
|
|
58
|
+
formatted_tb = str(exc_repr)
|
|
59
|
+
for line in formatted_tb.splitlines():
|
|
60
|
+
tw.line(line.rstrip(), red=True)
|
|
61
|
+
return ExitCode.USAGE_ERROR
|
|
62
|
+
else:
|
|
63
|
+
try:
|
|
64
|
+
config.hook.pytest_collection_finish = pytest_collection_finish
|
|
65
|
+
ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
|
|
66
|
+
config=config
|
|
67
|
+
)
|
|
68
|
+
try:
|
|
69
|
+
return ExitCode(ret)
|
|
70
|
+
except ValueError:
|
|
71
|
+
return ret
|
|
72
|
+
finally:
|
|
73
|
+
config._ensure_unconfigure()
|
|
74
|
+
except UsageError as e:
|
|
75
|
+
tw = TerminalWriter(sys.stderr)
|
|
76
|
+
for msg in e.args:
|
|
77
|
+
tw.line(f"ERROR: {msg}\n", red=True)
|
|
78
|
+
return ExitCode.USAGE_ERROR
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
main(sys.argv[1:])
|
|
@@ -9,6 +9,8 @@ import subprocess
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import List, Dict, Optional, Tuple
|
|
11
11
|
|
|
12
|
+
from sflkit.logger import LOGGER
|
|
13
|
+
|
|
12
14
|
Environment = Dict[str, str]
|
|
13
15
|
|
|
14
16
|
PYTEST_RESULT_PATTERN = re.compile(
|
|
@@ -118,6 +120,15 @@ class VoidRunner(Runner):
|
|
|
118
120
|
|
|
119
121
|
|
|
120
122
|
class PytestRunner(Runner):
|
|
123
|
+
def __init__(
|
|
124
|
+
self,
|
|
125
|
+
re_filter: str = r".*",
|
|
126
|
+
timeout=DEFAULT_TIMEOUT,
|
|
127
|
+
set_python_path: bool = False,
|
|
128
|
+
):
|
|
129
|
+
super().__init__(re_filter, timeout)
|
|
130
|
+
self.set_python_path = set_python_path
|
|
131
|
+
|
|
121
132
|
@staticmethod
|
|
122
133
|
def _common_base(directory: Path, tests: List[str]) -> Path:
|
|
123
134
|
parts = directory.parts
|
|
@@ -165,25 +176,49 @@ class PytestRunner(Runner):
|
|
|
165
176
|
directory = directory.absolute()
|
|
166
177
|
if files:
|
|
167
178
|
if isinstance(files, (str, os.PathLike)):
|
|
168
|
-
c.append(files)
|
|
179
|
+
c.append(str(files))
|
|
169
180
|
else:
|
|
170
|
-
c += files
|
|
181
|
+
c += [str(f) for f in files]
|
|
171
182
|
if base:
|
|
172
183
|
if not files:
|
|
173
|
-
c.append(base)
|
|
184
|
+
c.append(str(base))
|
|
174
185
|
root_dir = directory / base
|
|
175
186
|
else:
|
|
176
187
|
root_dir = directory
|
|
177
|
-
|
|
178
|
-
|
|
188
|
+
tmp = Path(f"tmp_sflkit_pytest_tmp_{id(self)}").absolute()
|
|
189
|
+
pytest_main = (
|
|
190
|
+
Path(__file__).parent.resolve() / "resources" / "pytest_main.py"
|
|
191
|
+
).absolute()
|
|
192
|
+
environ = dict(environ or os.environ)
|
|
193
|
+
environ["SFLKIT_PYTEST_COLLECTION_FINISH_FILE"] = str(tmp)
|
|
194
|
+
if self.set_python_path:
|
|
195
|
+
if "PYTHONPATH" in environ:
|
|
196
|
+
environ["PYTHONPATH"] = str(directory) + ":" + environ["PYTHONPATH"]
|
|
197
|
+
else:
|
|
198
|
+
environ["PYTHONPATH"] = str(directory)
|
|
199
|
+
process = subprocess.run(
|
|
200
|
+
[
|
|
201
|
+
"python3",
|
|
202
|
+
str(pytest_main),
|
|
203
|
+
"--collect-only",
|
|
204
|
+
]
|
|
205
|
+
+ c,
|
|
179
206
|
stdout=subprocess.PIPE,
|
|
207
|
+
stderr=subprocess.PIPE,
|
|
180
208
|
env=environ,
|
|
181
209
|
cwd=directory,
|
|
182
|
-
)
|
|
183
|
-
|
|
184
|
-
if
|
|
185
|
-
|
|
186
|
-
|
|
210
|
+
)
|
|
211
|
+
LOGGER.info(f"pytest collection finished with {process.returncode}")
|
|
212
|
+
if not tmp.exists():
|
|
213
|
+
tmp = directory / "tmp_sflkit_pytest"
|
|
214
|
+
if tmp.exists():
|
|
215
|
+
with open(tmp, "r") as f:
|
|
216
|
+
tests = [line.strip() for line in f.readlines()]
|
|
217
|
+
os.remove(tmp)
|
|
218
|
+
return self._normalize_paths(tests, directory, root_dir)
|
|
219
|
+
else:
|
|
220
|
+
LOGGER.warn(f"Could not find {tmp}")
|
|
221
|
+
return []
|
|
187
222
|
|
|
188
223
|
@staticmethod
|
|
189
224
|
def __get_pytest_result__(
|
|
@@ -207,7 +242,7 @@ class PytestRunner(Runner):
|
|
|
207
242
|
) -> TestResult:
|
|
208
243
|
try:
|
|
209
244
|
output = subprocess.run(
|
|
210
|
-
["
|
|
245
|
+
["python3", "-m", "pytest", test],
|
|
211
246
|
stdout=subprocess.PIPE,
|
|
212
247
|
env=environ,
|
|
213
248
|
cwd=directory,
|
|
@@ -288,7 +323,7 @@ class InputRunner(Runner):
|
|
|
288
323
|
result = TestResult.FAILING
|
|
289
324
|
try:
|
|
290
325
|
process = subprocess.run(
|
|
291
|
-
["
|
|
326
|
+
["python3", self.access] + test,
|
|
292
327
|
stdout=subprocess.PIPE,
|
|
293
328
|
stderr=subprocess.PIPE,
|
|
294
329
|
env=environ,
|
|
@@ -42,6 +42,8 @@ src/sflkit/model/model.py
|
|
|
42
42
|
src/sflkit/model/scope.py
|
|
43
43
|
src/sflkit/runners/__init__.py
|
|
44
44
|
src/sflkit/runners/run.py
|
|
45
|
+
src/sflkit/runners/resources/__init__.py
|
|
46
|
+
src/sflkit/runners/resources/pytest_main.py
|
|
45
47
|
tests/test_analysis_objects.py
|
|
46
48
|
tests/test_cli.py
|
|
47
49
|
tests/test_color.py
|
|
@@ -2,8 +2,7 @@ import atexit
|
|
|
2
2
|
import os
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
from sflkitlib.events import event, EventType
|
|
5
|
+
from sflkitlib.events import EventType
|
|
7
6
|
|
|
8
7
|
from sflkit import instrument_config, Config
|
|
9
8
|
from utils import BaseTest
|
|
@@ -106,6 +105,76 @@ class TestInstrumentation(BaseTest):
|
|
|
106
105
|
)
|
|
107
106
|
)
|
|
108
107
|
|
|
108
|
+
def test_mapping_output(self):
|
|
109
|
+
instrument_config(
|
|
110
|
+
Config.create(
|
|
111
|
+
path=os.path.join(BaseTest.TEST_RESOURCES, "test_instrumentation"),
|
|
112
|
+
language="python",
|
|
113
|
+
events="line",
|
|
114
|
+
predicates="line",
|
|
115
|
+
working=BaseTest.TEST_DIR,
|
|
116
|
+
mapping_path="mapping.json",
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
mapping = Path("mapping.json")
|
|
120
|
+
self.assertTrue(mapping.exists())
|
|
121
|
+
self.assertTrue(mapping.is_file())
|
|
122
|
+
|
|
123
|
+
def test_instrument_exclude(self):
|
|
124
|
+
src = Path(BaseTest.TEST_RESOURCES, "test_exclude")
|
|
125
|
+
dst = Path(BaseTest.TEST_DIR)
|
|
126
|
+
instrument_config(
|
|
127
|
+
Config.create(
|
|
128
|
+
path=str(src),
|
|
129
|
+
language="python",
|
|
130
|
+
events="line",
|
|
131
|
+
predicates="line",
|
|
132
|
+
working=BaseTest.TEST_DIR,
|
|
133
|
+
include="included",
|
|
134
|
+
exclude=os.path.join("included", "excluded"),
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
included = dst / "included"
|
|
138
|
+
excluded = included / "excluded"
|
|
139
|
+
a = included / "a.py"
|
|
140
|
+
b = excluded / "b.py"
|
|
141
|
+
c = dst / "c.py"
|
|
142
|
+
|
|
143
|
+
included_src = src / "included"
|
|
144
|
+
excluded_src = included_src / "excluded"
|
|
145
|
+
a_src = included_src / "a.py"
|
|
146
|
+
b_src = excluded_src / "b.py"
|
|
147
|
+
c_src = src / "c.py"
|
|
148
|
+
|
|
149
|
+
self.assertTrue(included.exists())
|
|
150
|
+
self.assertTrue(included.is_dir())
|
|
151
|
+
self.assertTrue(excluded.exists())
|
|
152
|
+
self.assertTrue(excluded.is_dir())
|
|
153
|
+
self.assertTrue(a.exists())
|
|
154
|
+
self.assertTrue(a.is_file())
|
|
155
|
+
self.assertTrue(b.exists())
|
|
156
|
+
self.assertTrue(b.is_file())
|
|
157
|
+
self.assertTrue(c.exists())
|
|
158
|
+
self.assertTrue(c.is_file())
|
|
159
|
+
|
|
160
|
+
with open(a, "r") as fp:
|
|
161
|
+
a_content = fp.read()
|
|
162
|
+
with open(a_src, "r") as fp:
|
|
163
|
+
a_src_content = fp.read()
|
|
164
|
+
self.assertNotEqual(a_src_content, a_content)
|
|
165
|
+
|
|
166
|
+
with open(b, "r") as fp:
|
|
167
|
+
b_content = fp.read()
|
|
168
|
+
with open(b_src, "r") as fp:
|
|
169
|
+
b_src_content = fp.read()
|
|
170
|
+
self.assertEqual(b_src_content, b_content)
|
|
171
|
+
|
|
172
|
+
with open(c, "r") as fp:
|
|
173
|
+
c_content = fp.read()
|
|
174
|
+
with open(c_src, "r") as fp:
|
|
175
|
+
c_src_content = fp.read()
|
|
176
|
+
self.assertEqual(c_src_content, c_content)
|
|
177
|
+
|
|
109
178
|
|
|
110
179
|
class TestLib(BaseTest):
|
|
111
180
|
@classmethod
|
|
@@ -131,10 +200,6 @@ class TestLib(BaseTest):
|
|
|
131
200
|
def setUp(self) -> None:
|
|
132
201
|
self.events = None
|
|
133
202
|
|
|
134
|
-
def load(self) -> None:
|
|
135
|
-
self.lib.dump_events()
|
|
136
|
-
self.events = event.load(self.TEST_PATH)
|
|
137
|
-
|
|
138
203
|
def tearDown(self) -> None:
|
|
139
204
|
# noinspection PyBroadException
|
|
140
205
|
try:
|
|
@@ -37,7 +37,7 @@ class RunnerTests(BaseTest):
|
|
|
37
37
|
exclude="tests",
|
|
38
38
|
)
|
|
39
39
|
instrument_config(config)
|
|
40
|
-
runner = PytestRunner()
|
|
40
|
+
runner = PytestRunner(set_python_path=True)
|
|
41
41
|
output = Path(BaseTest.TEST_DIR, "events").absolute()
|
|
42
42
|
runner.run(
|
|
43
43
|
Path(BaseTest.TEST_DIR), output, files=[Path("tests", "test_middle.py")]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|