chore: 规范标点
This commit is contained in:
1 parent
15e79887fa
commit
3dd2231c70
81 files changed
+1751
-1751
No files matched your search
+23
-23
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""repl_edit_check.py - 验证 REPL 的行编辑行为 (方向键、Home/End、退格、历史)
|
||||
|
||||
只抓字节流是不够的:光标移动是靠转义序列实现的, 必须把输出回放到一个
|
||||
只抓字节流是不够的: 光标移动是靠转义序列实现的, 必须把输出回放到一个
|
||||
终端模型里才能知道"屏幕上最终长什么样". 所以这里带一个极简终端模拟器,
|
||||
只实现本编辑器用到的那几条控制序列.
|
||||
"""
|
||||
@@ -18,7 +18,7 @@ ROWS = 200
|
||||
|
||||
|
||||
class Term:
|
||||
"""极简终端模型:只实现 \\r \\n \\b、CSI 光标移动、CSI J/K 清屏"""
|
||||
"""极简终端模型: 只实现 \\r \\n \\b、CSI 光标移动、CSI J/K 清屏"""
|
||||
|
||||
def __init__(self, cols=COLS, rows=ROWS):
|
||||
self.cols, self.rows = cols, rows
|
||||
@@ -100,7 +100,7 @@ class Term:
|
||||
|
||||
def to_bytes(s):
|
||||
# 把源码里写的十六进制转义与真实非 ASCII 字符一起转成字节.
|
||||
# 不能直接用 unicode_escape:一条串里既有转义又有中文时, latin-1 那步会报错.
|
||||
# 不能直接用 unicode_escape: 一条串里既有转义又有中文时, latin-1 那步会报错.
|
||||
if isinstance(s, bytes):
|
||||
return s
|
||||
out = bytearray()
|
||||
@@ -147,7 +147,7 @@ def run(binary, args, keys, keyset_settle=0.10, settle=0.45, idle=0.03):
|
||||
def drain(timeout, idle=idle, until_ready=False):
|
||||
"""安静下来就返回, 不把整个 timeout 睡满.
|
||||
|
||||
idle 取得很小 (0.03s)是有依据的:行编辑器每次按键都在一个 fflush
|
||||
idle 取得很小 (0.03s)是有依据的: 行编辑器每次按键都在一个 fflush
|
||||
里把整屏重绘写完, 所以一次 read 之后基本就没了. 而提交输入触发请求
|
||||
时, 等待动画每 250ms 一帧, 永远不会安静, 于是照样等到 timeout ——
|
||||
那条路径的行为和以前一致, 不会因为 idle 调小而抢跑.
|
||||
@@ -179,7 +179,7 @@ def run(binary, args, keys, keyset_settle=0.10, settle=0.45, idle=0.03):
|
||||
drain(settle)
|
||||
|
||||
# 刻意不发 Ctrl-C (它会在光标处打出 ^C 标记并覆盖两个字),
|
||||
# 直接关掉 pty:最后那次重绘就是缓冲区的真值
|
||||
# 直接关掉 pty: 最后那次重绘就是缓冲区的真值
|
||||
try:
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
@@ -194,7 +194,7 @@ def run(binary, args, keys, keyset_settle=0.10, settle=0.45, idle=0.03):
|
||||
def wait_ready(fd, timeout=3.0):
|
||||
"""等到行编辑器回到提示符 (它会打开括号粘贴).
|
||||
|
||||
裸 pty 会话里不要用 time.sleep 猜时间:猜短了会 flaky, 猜长了每处都在
|
||||
裸 pty 会话里不要用 time.sleep 猜时间: 猜短了会 flaky, 猜长了每处都在
|
||||
白等. 进程退出 (EOF)也算等到. """
|
||||
READY = b"\x1b[?2004h"
|
||||
end = time.time() + timeout
|
||||
@@ -226,19 +226,19 @@ def main():
|
||||
binary = sys.argv[1] if len(sys.argv) > 1 else './ligent'
|
||||
base = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
# 编辑测试不会真的发请求, 但程序在缺 key 时会直接退出, 所以必须给一个
|
||||
# 默认关掉确认与自动存档:它们会打断被测行为.
|
||||
# 默认关掉确认与自动存档: 它们会打断被测行为.
|
||||
# 专门测确认的用例用 --extra 显式打开.
|
||||
args = ['--no-color', '--no-confirm', '--no-auto-save', '--api-key', 'test',
|
||||
'--base-url', base or 'http://127.0.0.1:1/v1']
|
||||
|
||||
# 被驱动的实例会读写输入历史. 整轮都指到临时文件:既不往用户真实的
|
||||
# 被驱动的实例会读写输入历史. 整轮都指到临时文件: 既不往用户真实的
|
||||
# ligent.history 里写测试垃圾, 方向键用例的结果也不会取决于开发者机器
|
||||
# 上碰巧有什么历史.
|
||||
scratch = os.path.join(tempfile.gettempdir(), "ligent_edit_hist_%d" % os.getpid())
|
||||
os.environ["LIGENT_HISTORY"] = scratch
|
||||
|
||||
cases = []
|
||||
# 方向键左移后插入:光标必须落在中间
|
||||
# 方向键左移后插入: 光标必须落在中间
|
||||
cases.append(("左方向键移动光标后插入",
|
||||
['hello world'] + [LEFT] * 5 + ['X'],
|
||||
'ligent> hello Xworld'))
|
||||
@@ -274,7 +274,7 @@ def main():
|
||||
'ligent> cd'))
|
||||
PASTE = '\\x1b[200~'
|
||||
PASTE_END = '\\x1b[201~'
|
||||
cases.append(("粘贴多行:整段插入, 不逐行提交",
|
||||
cases.append(("粘贴多行: 整段插入, 不逐行提交",
|
||||
[PASTE + 'line1\nline2\nline3' + PASTE_END],
|
||||
['ligent> line1', 'line2', 'line3']))
|
||||
cases.append(("粘贴后可继续编辑",
|
||||
@@ -294,7 +294,7 @@ def main():
|
||||
'ligent> 中文Xabc'))
|
||||
|
||||
# 粘贴进来的原始字节里可能夹着控制字符. read_paste 是原样收下的 (不走
|
||||
# classify), 所以必须清洗:终端按制表位展开 \t, 编辑器只当 1 列;
|
||||
# classify), 所以必须清洗: 终端按制表位展开 \t, 编辑器只当 1 列;
|
||||
# ESC 会被终端真的执行掉; \r 把光标拉回行首.
|
||||
cases.append(("粘贴里的制表符按制表位展开",
|
||||
[PASTE + 'a\\tb' + PASTE_END, 'X'],
|
||||
@@ -338,15 +338,15 @@ def main():
|
||||
# 上面的用例都带 --no-color, 所以这里单独补一组彩色的.
|
||||
color_args = [a for a in args if a != '--no-color'] + ['--color']
|
||||
color_cases = [
|
||||
("彩色提示符:左移后插入",
|
||||
("彩色提示符: 左移后插入",
|
||||
['hello world'] + [LEFT] * 5 + ['X'], 'ligent> hello Xworld'),
|
||||
("彩色提示符:Home 后插入",
|
||||
("彩色提示符: Home 后插入",
|
||||
['world', '\\x01', 'hello '], 'ligent> hello world'),
|
||||
("彩色提示符:End 后追加",
|
||||
("彩色提示符: End 后追加",
|
||||
['abc', '\\x05', '!'], 'ligent> abc!'),
|
||||
("彩色提示符:中文按字符移动",
|
||||
("彩色提示符: 中文按字符移动",
|
||||
['中文abc'] + [LEFT] * 3 + ['X'], 'ligent> 中文Xabc'),
|
||||
("彩色提示符:退格",
|
||||
("彩色提示符: 退格",
|
||||
['abcd', '\\x7f'], 'ligent> abc'),
|
||||
]
|
||||
for name, keys, want in color_cases:
|
||||
@@ -363,7 +363,7 @@ def main():
|
||||
print(" 实际: %r" % got)
|
||||
|
||||
# 上面那些用例只比屏幕内容, 而颜色在终端模型里是被剥掉的 —— 包没包住
|
||||
# 输入的字看不出来. 所以这里直接查字节:绿色区间必须一直延续到用户敲的
|
||||
# 输入的字看不出来. 所以这里直接查字节: 绿色区间必须一直延续到用户敲的
|
||||
# 内容之后. 只包提示符的话, 提示符自带的 reset 会让输入掉回默认色.
|
||||
raw = run(binary, color_args, ['greenme'])
|
||||
txt = raw.decode('utf-8', 'replace')
|
||||
@@ -378,7 +378,7 @@ def main():
|
||||
print(" ✗ 输入的字也被包在绿色里")
|
||||
print(" 绿色区间: %r" % inside)
|
||||
|
||||
# 粘贴多行后提交:必须作为"一条"消息发出去 (回显里能看到内嵌换行)
|
||||
# 粘贴多行后提交: 必须作为"一条"消息发出去 (回显里能看到内嵌换行)
|
||||
if base:
|
||||
raw = run(binary, args,
|
||||
[PASTE + 'ECHO_TEST 第一行\n第二行\n第三行' + PASTE_END, '\\r'],
|
||||
@@ -393,7 +393,7 @@ def main():
|
||||
print(" ✗ 粘贴的多行作为一条消息提交")
|
||||
print(" 屏幕尾部: %r" % term.nonempty()[-6:])
|
||||
|
||||
# 上下方向键取历史:需要真的提交一行, 所以只有在给了服务端时才测
|
||||
# 上下方向键取历史: 需要真的提交一行, 所以只有在给了服务端时才测
|
||||
if base:
|
||||
raw = run(binary, args, ['recalldemo', '\\r'], keyset_settle=0.8,
|
||||
settle=0.6, idle=0.5)
|
||||
@@ -412,15 +412,15 @@ def main():
|
||||
print(" 提示符行: %r" % lines[-3:])
|
||||
cases.append(("history", [], "ligent> firstline"))
|
||||
|
||||
# 历史要跨进程:上一个实例敲过的, 新实例按上方向键就能翻到.
|
||||
# 用独立的 LIGENT_HISTORY, 免得受其他用例和真实历史文件影响.
|
||||
# 历史要跨进程: 上一个实例敲过的, 新实例按上方向键就能翻到.
|
||||
# 用独立的 LIGENT_HISTORY, 以免受其他用例和真实历史文件影响.
|
||||
hist = os.path.join(tempfile.gettempdir(), "ligent_hist_check_%d" % os.getpid())
|
||||
for p in (hist, hist + ".tmp"):
|
||||
if os.path.exists(p):
|
||||
os.unlink(p)
|
||||
os.environ["LIGENT_HISTORY"] = hist
|
||||
try:
|
||||
# 实时性:进程还活着、还没退出, 文件里就该已经有这条了
|
||||
# 实时性: 进程还活着、还没退出, 文件里就该已经有这条了
|
||||
pid, fd = pty.fork()
|
||||
if pid == 0:
|
||||
os.environ['TERM'] = 'xterm-256color'
|
||||
@@ -478,7 +478,7 @@ def main():
|
||||
term = Term()
|
||||
term.feed(raw.decode('utf-8', 'replace'))
|
||||
prompts = [l for l in term.nonempty() if l.startswith('ligent> ')]
|
||||
# 期望:Ctrl-C 丢掉了 "garbage", 之后那一行只含 "typed"
|
||||
# 期望: Ctrl-C 丢掉了 "garbage", 之后那一行只含 "typed"
|
||||
last = prompts[-1] if prompts else ''
|
||||
ok = len(prompts) >= 2 and 'garbage' not in last and 'typed' in last
|
||||
if not ok:
|
||||
|
||||
Reference in new issue
Block a user