lsp.py: Port to support running on Windows & adapt to changes due to prior merged PR.

- lsp.py: Fixes invalid-syntax by Python interpreter on Windows CI (older Python version).
- lsp.py: Savely strip CRLF from right side of the string, ignoring accidental multiple occurrences of \r (such as \r\r\n).
- lsp.py: Fixes reading single character from stdin (wrt. Windows platform).
- lsp.py: Adds header line reading to I/O tracing (useful for debugging).
- lsp.py: When running the tests on Windows, don't care test file content's newlines but simply expect LFs (instead of CRLF for example).
- Apply pylint notes.
- Fixing use of @functools.lru_cache for older python versions (CircleCI Windows)
This commit is contained in:
Christian Parpart 2022-04-25 17:21:45 +02:00
parent c2f245b40a
commit e8d07772d9
2 changed files with 53 additions and 20 deletions

View File

@ -1283,6 +1283,9 @@ jobs:
- run:
name: Install LSP test dependencies
command: python -m pip install --user deepdiff colorama
- run:
name: Inspect lsp.py
command: Get-Content ./test/lsp.py
- run:
name: Executing solc LSP test suite
command: python ./test/lsp.py .\build\solc\Release\solc.exe

View File

@ -1,26 +1,57 @@
#!/usr/bin/env python3
# pragma pylint: disable=too-many-lines
# test line 1
import argparse
import fnmatch
import functools
import json
import os
import re
import subprocess
import sys
import traceback
import re
import tty
import functools
from collections import namedtuple
from copy import deepcopy
from enum import Enum, auto
from itertools import islice
from pathlib import PurePath
from typing import Any, List, Optional, Tuple, Union
from itertools import islice
from enum import Enum, auto
import colorama # Enables the use of SGR & CUP terminal VT sequences on Windows.
import colorama # Enables the use of SGR & CUP terminal VT sequences on Windows.
from deepdiff import DeepDiff
if os.name == 'nt':
# pragma pylint: disable=import-error
import msvcrt
else:
import tty
# Turn off user input buffering so we get the input immediately,
# not only after a line break
tty.setcbreak(sys.stdin.fileno())
def escape_string(text: str) -> str:
"""
Trivially escapes given input string's \r \n and \\.
"""
return text.translate(str.maketrans({
"\r": r"\r",
"\n": r"\n",
"\\": r"\\"
}))
def getCharFromStdin():
"""
Gets a single character from stdin without line-buffering.
"""
if os.name == 'nt':
# pragma pylint: disable=import-error
return msvcrt.getch().decode("utf-8")
else:
return sys.stdin.buffer.read(1)
"""
Named tuple that holds various regexes used to parse the test specification.
"""
@ -101,7 +132,6 @@ class BadHeader(Exception):
def __init__(self, msg: str):
super().__init__("Bad header: " + msg)
class JsonRpcProcess:
exe_path: str
exe_args: List[str]
@ -144,10 +174,12 @@ class JsonRpcProcess:
# server quit
return None
line = line.decode("utf-8")
if self.trace_io:
print(f"Received header-line: {escape_string(line)}")
if not line.endswith("\r\n"):
raise BadHeader("missing newline")
# remove the "\r\n"
line = line[:-2]
# Safely remove the "\r\n".
line = line.rstrip("\r\n")
if line == '':
break # done with the headers
if line.startswith(CONTENT_LENGTH_HEADER):
@ -589,7 +621,7 @@ class FileTestRunner:
while True:
print("(u)pdate/(r)etry/(i)gnore?")
user_response = sys.stdin.read(1)
user_response = getCharFromStdin()
if user_response == "i":
return self.TestResult.SuccessOrIgnored
@ -787,7 +819,7 @@ class SolidityLSPTestSuite: # {{{
in the test path (test/libsolidity/lsp).
"""
with open(self.get_test_file_path(test_case_name), mode="r", encoding="utf-8", newline='') as f:
return f.read()
return f.read().replace("\r\n", "\n")
def require_params_for_method(self, method_name: str, message: dict) -> Any:
"""
@ -1059,7 +1091,7 @@ class SolidityLSPTestSuite: # {{{
"""
while True:
print("(u)pdate/(r)etry/(s)kip file?")
user_response = sys.stdin.read(1)
user_response = getCharFromStdin()
if user_response == "u":
while True:
try:
@ -1068,8 +1100,8 @@ class SolidityLSPTestSuite: # {{{
# pragma pylint: disable=broad-except
except Exception as e:
print(e)
if ret := self.user_interaction_failed_autoupdate(test):
return ret
if self.user_interaction_failed_autoupdate(test):
return True
elif user_response == 's':
return True
elif user_response == 'r':
@ -1077,7 +1109,7 @@ class SolidityLSPTestSuite: # {{{
def user_interaction_failed_autoupdate(self, test):
print("(e)dit/(r)etry/(s)kip file?")
user_response = sys.stdin.read(1)
user_response = getCharFromStdin()
if user_response == "r":
print("retrying...")
# pragma pylint: disable=no-member
@ -1142,7 +1174,7 @@ class SolidityLSPTestSuite: # {{{
marker = self.get_file_tags("lib")["@diagnostics"]
self.expect_diagnostic(report['diagnostics'][0], code=2072, marker=marker)
@functools.lru_cache # pragma pylint: disable=lru-cache-decorating-method
@functools.lru_cache() # pragma pylint: disable=lru-cache-decorating-method
def get_file_tags(self, test_name: str, verbose=False):
"""
Finds all tags (e.g. @tagname) in the given test and returns them as a
@ -1653,10 +1685,8 @@ class SolidityLSPTestSuite: # {{{
# }}}
# }}}
if __name__ == "__main__":
# Turn off user input buffering so we get the input immediately,
# not only after a line break
tty.setcbreak(sys.stdin.fileno())
suite = SolidityLSPTestSuite()
exit_code = suite.main()
sys.exit(exit_code)