|
1 |
| -from typing import List, Optional, Generic, TypeVar, Dict |
2 |
| -from selfie_lib.CommentTracker import SnapshotFileLayout |
| 1 | +from typing import List, Optional, Generic, TypeVar, Dict, cast, Callable, Sequence |
3 | 2 | from abc import ABC, abstractmethod
|
4 | 3 | import inspect, threading
|
5 | 4 | from functools import total_ordering
|
6 | 5 |
|
| 6 | +from selfie_lib.SourceFile import SourceFile |
| 7 | +from selfie_lib.Literals import LiteralValue |
| 8 | +from selfie_lib.TypedPath import TypedPath |
| 9 | + |
| 10 | + |
7 | 11 | T = TypeVar("T")
|
8 | 12 | U = TypeVar("U")
|
9 | 13 |
|
10 | 14 |
|
| 15 | +class FS(ABC): |
| 16 | + @abstractmethod |
| 17 | + def file_walk(self, typed_path, walk: Callable[[Sequence["TypedPath"]], T]) -> T: |
| 18 | + pass |
| 19 | + |
| 20 | + def file_read(self, typed_path) -> str: |
| 21 | + return self.file_read_binary(typed_path).decode() |
| 22 | + |
| 23 | + def file_write(self, typed_path, content: str): |
| 24 | + self.file_write_binary(typed_path, content.encode()) |
| 25 | + |
| 26 | + @abstractmethod |
| 27 | + def file_read_binary(self, typed_path) -> bytes: |
| 28 | + pass |
| 29 | + |
| 30 | + @abstractmethod |
| 31 | + def file_write_binary(self, typed_path, content: bytes): |
| 32 | + pass |
| 33 | + |
| 34 | + @abstractmethod |
| 35 | + def assert_failed(self, message: str, expected=None, actual=None) -> Exception: |
| 36 | + pass |
| 37 | + |
| 38 | + |
| 39 | +class SnapshotFileLayout: |
| 40 | + def __init__(self, fs: FS): |
| 41 | + self.fs = fs |
| 42 | + |
| 43 | + def sourcePathForCall(self, location) -> "TypedPath": |
| 44 | + raise NotImplementedError("sourcePathForCall is not implemented") |
| 45 | + |
| 46 | + |
11 | 47 | @total_ordering
|
12 | 48 | class CallLocation:
|
13 | 49 | def __init__(self, file_name: Optional[str], line: int):
|
@@ -132,3 +168,34 @@ def recordInternal(
|
132 | 168 | class DiskWriteTracker(WriteTracker[T, U]):
|
133 | 169 | def record(self, key: T, snapshot: U, call: CallStack, layout: SnapshotFileLayout):
|
134 | 170 | super().recordInternal(key, snapshot, call, layout)
|
| 171 | + |
| 172 | + |
| 173 | +class InlineWriteTracker(WriteTracker[CallLocation, LiteralValue]): |
| 174 | + def record( |
| 175 | + self, |
| 176 | + key: CallLocation, |
| 177 | + snapshot: LiteralValue, |
| 178 | + call: CallStack, |
| 179 | + layout: SnapshotFileLayout, |
| 180 | + ): |
| 181 | + super().recordInternal(key, snapshot, call, layout) |
| 182 | + |
| 183 | + file = layout.sourcePathForCall(key) |
| 184 | + if snapshot.expected is not None: |
| 185 | + content = SourceFile(file.name, layout.fs.file_read(file)) |
| 186 | + try: |
| 187 | + snapshot = cast(LiteralValue, snapshot) |
| 188 | + parsed_value = content.parse_to_be_like(key.line).parse_literal( |
| 189 | + snapshot.format |
| 190 | + ) |
| 191 | + except Exception as e: |
| 192 | + raise AssertionError( |
| 193 | + f"Error while parsing the literal at {key.ide_link(layout)}. Please report this error at https://github.com/diffplug/selfie", |
| 194 | + e, |
| 195 | + ) |
| 196 | + if parsed_value != snapshot.expected: |
| 197 | + raise layout.fs.assert_failed( |
| 198 | + f"Selfie cannot modify the literal at {key.ide_link(layout)} because Selfie has a parsing bug. Please report this error at https://github.com/diffplug/selfie", |
| 199 | + snapshot.expected, |
| 200 | + parsed_value, |
| 201 | + ) |
0 commit comments