mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
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:
parent
c2f245b40a
commit
e8d07772d9
@ -1283,6 +1283,9 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Install LSP test dependencies
|
name: Install LSP test dependencies
|
||||||
command: python -m pip install --user deepdiff colorama
|
command: python -m pip install --user deepdiff colorama
|
||||||
|
- run:
|
||||||
|
name: Inspect lsp.py
|
||||||
|
command: Get-Content ./test/lsp.py
|
||||||
- run:
|
- run:
|
||||||
name: Executing solc LSP test suite
|
name: Executing solc LSP test suite
|
||||||
command: python ./test/lsp.py .\build\solc\Release\solc.exe
|
command: python ./test/lsp.py .\build\solc\Release\solc.exe
|
||||||
|
70
test/lsp.py
70
test/lsp.py
@ -1,26 +1,57 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# pragma pylint: disable=too-many-lines
|
# pragma pylint: disable=too-many-lines
|
||||||
|
# test line 1
|
||||||
import argparse
|
import argparse
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import functools
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import re
|
|
||||||
import tty
|
|
||||||
import functools
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
from enum import Enum, auto
|
||||||
|
from itertools import islice
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from typing import Any, List, Optional, Tuple, Union
|
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
|
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.
|
Named tuple that holds various regexes used to parse the test specification.
|
||||||
"""
|
"""
|
||||||
@ -101,7 +132,6 @@ class BadHeader(Exception):
|
|||||||
def __init__(self, msg: str):
|
def __init__(self, msg: str):
|
||||||
super().__init__("Bad header: " + msg)
|
super().__init__("Bad header: " + msg)
|
||||||
|
|
||||||
|
|
||||||
class JsonRpcProcess:
|
class JsonRpcProcess:
|
||||||
exe_path: str
|
exe_path: str
|
||||||
exe_args: List[str]
|
exe_args: List[str]
|
||||||
@ -144,10 +174,12 @@ class JsonRpcProcess:
|
|||||||
# server quit
|
# server quit
|
||||||
return None
|
return None
|
||||||
line = line.decode("utf-8")
|
line = line.decode("utf-8")
|
||||||
|
if self.trace_io:
|
||||||
|
print(f"Received header-line: {escape_string(line)}")
|
||||||
if not line.endswith("\r\n"):
|
if not line.endswith("\r\n"):
|
||||||
raise BadHeader("missing newline")
|
raise BadHeader("missing newline")
|
||||||
# remove the "\r\n"
|
# Safely remove the "\r\n".
|
||||||
line = line[:-2]
|
line = line.rstrip("\r\n")
|
||||||
if line == '':
|
if line == '':
|
||||||
break # done with the headers
|
break # done with the headers
|
||||||
if line.startswith(CONTENT_LENGTH_HEADER):
|
if line.startswith(CONTENT_LENGTH_HEADER):
|
||||||
@ -589,7 +621,7 @@ class FileTestRunner:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
print("(u)pdate/(r)etry/(i)gnore?")
|
print("(u)pdate/(r)etry/(i)gnore?")
|
||||||
user_response = sys.stdin.read(1)
|
user_response = getCharFromStdin()
|
||||||
if user_response == "i":
|
if user_response == "i":
|
||||||
return self.TestResult.SuccessOrIgnored
|
return self.TestResult.SuccessOrIgnored
|
||||||
|
|
||||||
@ -787,7 +819,7 @@ class SolidityLSPTestSuite: # {{{
|
|||||||
in the test path (test/libsolidity/lsp).
|
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:
|
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:
|
def require_params_for_method(self, method_name: str, message: dict) -> Any:
|
||||||
"""
|
"""
|
||||||
@ -1059,7 +1091,7 @@ class SolidityLSPTestSuite: # {{{
|
|||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
print("(u)pdate/(r)etry/(s)kip file?")
|
print("(u)pdate/(r)etry/(s)kip file?")
|
||||||
user_response = sys.stdin.read(1)
|
user_response = getCharFromStdin()
|
||||||
if user_response == "u":
|
if user_response == "u":
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -1068,8 +1100,8 @@ class SolidityLSPTestSuite: # {{{
|
|||||||
# pragma pylint: disable=broad-except
|
# pragma pylint: disable=broad-except
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
if ret := self.user_interaction_failed_autoupdate(test):
|
if self.user_interaction_failed_autoupdate(test):
|
||||||
return ret
|
return True
|
||||||
elif user_response == 's':
|
elif user_response == 's':
|
||||||
return True
|
return True
|
||||||
elif user_response == 'r':
|
elif user_response == 'r':
|
||||||
@ -1077,7 +1109,7 @@ class SolidityLSPTestSuite: # {{{
|
|||||||
|
|
||||||
def user_interaction_failed_autoupdate(self, test):
|
def user_interaction_failed_autoupdate(self, test):
|
||||||
print("(e)dit/(r)etry/(s)kip file?")
|
print("(e)dit/(r)etry/(s)kip file?")
|
||||||
user_response = sys.stdin.read(1)
|
user_response = getCharFromStdin()
|
||||||
if user_response == "r":
|
if user_response == "r":
|
||||||
print("retrying...")
|
print("retrying...")
|
||||||
# pragma pylint: disable=no-member
|
# pragma pylint: disable=no-member
|
||||||
@ -1142,7 +1174,7 @@ class SolidityLSPTestSuite: # {{{
|
|||||||
marker = self.get_file_tags("lib")["@diagnostics"]
|
marker = self.get_file_tags("lib")["@diagnostics"]
|
||||||
self.expect_diagnostic(report['diagnostics'][0], code=2072, marker=marker)
|
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):
|
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
|
Finds all tags (e.g. @tagname) in the given test and returns them as a
|
||||||
@ -1653,10 +1685,8 @@ class SolidityLSPTestSuite: # {{{
|
|||||||
# }}}
|
# }}}
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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()
|
suite = SolidityLSPTestSuite()
|
||||||
exit_code = suite.main()
|
exit_code = suite.main()
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
Loading…
Reference in New Issue
Block a user