修:draw-ui / oil-motion 原被当子模块指针收录 ⇒ 改为正常文件入库(两份内容原先对别人是空的)
一、问题(本轮实测)
`draw-ui` 与 `oil-motion` 目录里**各自带一个内嵌 `.git`** ⇒ 上一次提交把它们记成了 **gitlink(子模块指针)**
⇒ 仓库里只存了一个不属于任何远端的 commit id,**别人克隆下来这两份是空的** ✗(`git status` 显示 ` m draw-ui` / ` m oil-motion` = 子模块内容有改动)。
二、处置(可回退)
· 把两处的 `.git` **挪走**(⛔ 不是删除)⇒ `归档/内嵌git-20261008/{draw-ui,oil-motion}.git`;
· `git rm --cached` 掉那两个 gitlink,再 `git add` 两个目录 ⇒ **按正常文件入库**(内容才真的进仓库)。
三、副作用(如实记)
挪走 `.git` 后,这两个技能**不能再原地 `git pull` 取上游更新**(要更新得重新拉一份覆盖);
如需恢复其本地仓库,把 `归档/内嵌git-20261008/` 里的 `.git` 挪回原处即可。
This commit is contained in:
1 parent
e03465c398
commit
237a09a5b0
161 files changed
+19429
-2
No files matched your search
@@ -0,0 +1,87 @@
|
||||
"""从真实CLI入口验证尺寸与截图前提,不启动浏览器。"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from threading import Thread
|
||||
from PIL import Image
|
||||
|
||||
SCRIPTS = Path(__file__).resolve().parents[1] / 'scripts'
|
||||
|
||||
class CalibrationTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.root = Path(self.temp.name)
|
||||
for name in ('reference', 'candidate'):
|
||||
Image.new('RGB', (32, 64), 'white').save(self.root / (name+'.png'))
|
||||
def tearDown(self):
|
||||
self.temp.cleanup()
|
||||
def compare(self, *extra):
|
||||
return subprocess.run([sys.executable, str(SCRIPTS/'compare_mockup.py'), '--reference', str(self.root/'reference.png'), '--candidate', str(self.root/'candidate.png'), '--out-dir', str(self.root/'comparison'), *extra], capture_output=True, text=True)
|
||||
def test_equal_and_invalid_clip(self):
|
||||
self.assertEqual(self.compare().returncode, 0)
|
||||
metrics=json.loads((self.root/'comparison/comparison-metrics.json').read_text())
|
||||
self.assertFalse(metrics['resized'])
|
||||
self.assertEqual(metrics['regions'][0]['mean_abs_diff'], 0)
|
||||
for clip in ['bad:0,0,33,2', '../escape:0,0,1,1', 'full:0,0,1,1', 'bad:0,0,-1,1']:
|
||||
with self.subTest(clip=clip):
|
||||
self.assertNotEqual(self.compare('--clip', clip).returncode, 0)
|
||||
def test_width_mismatch(self):
|
||||
Image.new('RGB', (33,64), 'white').save(self.root/'candidate.png')
|
||||
self.assertNotEqual(self.compare('--allow-height-difference').returncode, 0)
|
||||
self.assertFalse((self.root/'comparison').exists())
|
||||
def test_short_page_preserves_missing_tail(self):
|
||||
Image.new('RGB', (32,50), 'white').save(self.root/'candidate.png')
|
||||
self.assertNotEqual(self.compare().returncode, 0)
|
||||
self.assertEqual(self.compare('--allow-height-difference','--clip','tail:0,50,32,14').returncode, 0)
|
||||
metrics=json.loads((self.root/'comparison/comparison-metrics.json').read_text())
|
||||
self.assertEqual(metrics['height_delta'], -14)
|
||||
self.assertFalse(metrics['geometry_match'])
|
||||
with Image.open(metrics['unmatched_tails']['reference']) as tail:
|
||||
self.assertEqual(tail.size, (32,14))
|
||||
self.assertIn('status',metrics['regions'][-1])
|
||||
def test_capture_contract(self):
|
||||
expected={'url':'http://127.0.0.1:4187/','title':'测试页','viewport':{'width':32,'height':64},'dpr':1,'full_page':False,'screenshot_scale':'css'}
|
||||
capture={**expected,'fonts_ready':True,'images_ready':True,'document_height':64,'sections':[{'name':'hero','y':2}]}
|
||||
asset={'src':'http://127.0.0.1:4187/logo-v2.png','natural_width':2048}
|
||||
capture['assets']={'logo':asset}
|
||||
manifest={'expected':expected,'capture_metadata':'capture.json','reference':'reference.png','candidate':'candidate.png','section_positions':{'hero':1},'expected_assets':{'logo':asset}}
|
||||
(self.root/'run.json').write_text(json.dumps(manifest))
|
||||
variants=[({},True),({'title':'其他项目'},False),({'url':'http://127.0.0.1:9999/'},False),({'fonts_ready':False},False),({'images_ready':False},False),({'dpr':2},False),({'viewport':{'width':31,'height':64}},False),({'screenshot_scale':'device'},False),({'assets':{}},False),({'assets':{'logo':{**asset,'src':'http://127.0.0.1:4187/old.png'}}},False),({'assets':{'logo':{**asset,'natural_width':100}}},False)]
|
||||
for index,(changes,valid) in enumerate(variants):
|
||||
with self.subTest(changes=changes):
|
||||
(self.root/'capture.json').write_text(json.dumps({**capture,**changes}))
|
||||
out=self.root/f'verify-{index}'
|
||||
result=subprocess.run([sys.executable,str(SCRIPTS/'verify_capture.py'),'--manifest',str(self.root/'run.json'),'--out-dir',str(out)],capture_output=True,text=True)
|
||||
self.assertEqual(result.returncode==0,valid,result.stderr)
|
||||
if valid:
|
||||
self.assertEqual(json.loads((out/'verification.json').read_text())['section_positions'][0]['delta_y'],1)
|
||||
else:
|
||||
self.assertFalse(out.exists())
|
||||
|
||||
def test_preflight_identity(self):
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
self.wfile.write('<title>测试页</title>'.encode())
|
||||
def log_message(self,*args):
|
||||
pass
|
||||
server=HTTPServer(('127.0.0.1',0),Handler)
|
||||
thread=Thread(target=server.serve_forever,daemon=True)
|
||||
thread.start()
|
||||
try:
|
||||
for title,valid in [('测试页',True),('其他项目',False)]:
|
||||
(self.root/'run.json').write_text(json.dumps({'expected':{'url':f'http://127.0.0.1:{server.server_port}/','title':title}}))
|
||||
result=subprocess.run([sys.executable,str(SCRIPTS/'verify_capture.py'),'--manifest',str(self.root/'run.json'),'--preflight'],capture_output=True,text=True)
|
||||
self.assertEqual(result.returncode==0,valid,result.stderr)
|
||||
finally:
|
||||
server.shutdown()
|
||||
server.server_close()
|
||||
thread.join()
|
||||
|
||||
if __name__=='__main__':
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user