Skip to content

Commit de18857

Browse files
committed
Add verify
1 parent f400da8 commit de18857

37 files changed

+1103
-999
lines changed

braillove-case-collector/verify.py

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import time
2+
import csv
3+
import os
4+
import glob
5+
import json
6+
from pywinauto.application import Application
7+
8+
pattern = " a1b'k2l`cif/msp\"e3h9o6r^djg>ntq,*5<-u8v.%[$+x!&;:4\\0z7(_?w]#y)="
9+
braille = "⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿"
10+
11+
12+
def raw_to_unicode_braille(raw_text: str) -> str:
13+
"""Convert 점사랑 raw output to unicode braille."""
14+
result = ""
15+
for ch in raw_text:
16+
if ch in pattern:
17+
result += braille[pattern.index(ch)]
18+
elif ch == "@":
19+
result += braille[8]
20+
elif ch == "|":
21+
result += braille[51]
22+
else:
23+
raise ValueError(f"Unknown character in output: {repr(ch)}")
24+
return result
25+
26+
27+
def main():
28+
app = None
29+
try:
30+
app = Application(backend="uia").start(
31+
r"C:\Program Files (x86)\Jeomsarang6\BrailleLove.exe"
32+
)
33+
print("BrailleLove started.")
34+
35+
main_window = app.window(title="점사랑 6.0")
36+
main_window.set_focus()
37+
main_window.maximize()
38+
39+
main_window.child_window(title="새문서", control_type="Button").click()
40+
main_window.child_window(title="확인(O)", control_type="Button").click()
41+
42+
main_window = app.window(title=app.windows()[0].window_text())
43+
pane = main_window.child_window(control_type="Pane", title="작업 영역")
44+
output_edit = main_window.child_window(control_type="Edit", title="")
45+
46+
test_case_files = sorted(glob.glob("../test_cases/*.csv"))
47+
if not test_case_files:
48+
print("No test case files found in ../test_cases/")
49+
return
50+
51+
total_cases = 0
52+
passed_cases = 0
53+
failed_cases = 0
54+
errors = 0
55+
failures_detail = []
56+
results_per_file = {}
57+
58+
for test_file in test_case_files:
59+
file_name = os.path.basename(test_file)
60+
print(f"\n--- {file_name} ---")
61+
file_total = 0
62+
file_passed = 0
63+
64+
with open(test_file, "r", encoding="utf-8") as f:
65+
reader = csv.reader(f)
66+
for row in reader:
67+
if not row or len(row) < 4:
68+
continue
69+
70+
korean_input = row[0].strip()
71+
expected_unicode = row[-1].strip()
72+
73+
if not korean_input or not expected_unicode:
74+
continue
75+
76+
file_total += 1
77+
total_cases += 1
78+
79+
try:
80+
# Type input into 점사랑
81+
time.sleep(0.3)
82+
pane.type_keys(
83+
korean_input.replace(" ", "{SPACE}")
84+
.replace("(", "{(}")
85+
.replace(")", "{)}"),
86+
pause=0.05,
87+
)
88+
time.sleep(0.3)
89+
90+
# Read output
91+
raw_output = output_edit.get_value()
92+
actual_unicode = raw_to_unicode_braille(raw_output)
93+
94+
if actual_unicode == expected_unicode:
95+
passed_cases += 1
96+
file_passed += 1
97+
else:
98+
failed_cases += 1
99+
detail = {
100+
"file": file_name,
101+
"input": korean_input,
102+
"expected": expected_unicode,
103+
"actual": actual_unicode,
104+
}
105+
failures_detail.append(detail)
106+
print(
107+
f" FAIL: '{korean_input}' expected={expected_unicode} actual={actual_unicode}"
108+
)
109+
110+
# Clear input
111+
main_window.set_focus()
112+
time.sleep(0.3)
113+
pane.type_keys("{BACKSPACE}" * len(korean_input))
114+
while output_edit.get_value() != "":
115+
pane.type_keys("{BACKSPACE}")
116+
117+
except Exception as e:
118+
errors += 1
119+
print(f" ERROR: '{korean_input}' -> {e}")
120+
# Try to clear
121+
try:
122+
main_window.set_focus()
123+
pane.type_keys("^a{DELETE}")
124+
time.sleep(0.5)
125+
except:
126+
pass
127+
128+
results_per_file[file_name] = {
129+
"total": file_total,
130+
"passed": file_passed,
131+
"failed": file_total - file_passed,
132+
}
133+
if file_total > 0:
134+
pct = file_passed / file_total * 100
135+
print(f" {file_passed}/{file_total} passed ({pct:.1f}%)")
136+
137+
# Summary
138+
print("\n" + "=" * 60)
139+
print("VERIFICATION SUMMARY")
140+
print("=" * 60)
141+
print(f"Total cases: {total_cases}")
142+
print(f"Passed: {passed_cases}")
143+
print(f"Failed: {failed_cases}")
144+
print(f"Errors: {errors}")
145+
if total_cases > 0:
146+
accuracy = passed_cases / total_cases * 100
147+
print(f"Accuracy: {accuracy:.2f}%")
148+
print("=" * 60)
149+
150+
# Per-file breakdown
151+
print("\nPer-file results:")
152+
for fname, stats in sorted(results_per_file.items()):
153+
pct = stats["passed"] / stats["total"] * 100 if stats["total"] > 0 else 0
154+
status = "PASS" if stats["failed"] == 0 else "FAIL"
155+
print(
156+
f" [{status}] {fname}: {stats['passed']}/{stats['total']} ({pct:.1f}%)"
157+
)
158+
159+
# Save results to JSON
160+
report = {
161+
"total": total_cases,
162+
"passed": passed_cases,
163+
"failed": failed_cases,
164+
"errors": errors,
165+
"accuracy_percent": round(passed_cases / total_cases * 100, 2)
166+
if total_cases > 0
167+
else 0,
168+
"per_file": results_per_file,
169+
"failures": failures_detail[:100], # Cap at 100 for readability
170+
}
171+
with open("../jeomsarang_verify_result.json", "w", encoding="utf-8") as f:
172+
json.dump(report, f, ensure_ascii=False, indent=2)
173+
print(f"\nDetailed results saved to jeomsarang_verify_result.json")
174+
175+
except Exception as e:
176+
print(f"Error: {e}")
177+
import traceback
178+
179+
traceback.print_exc()
180+
finally:
181+
if app:
182+
app.kill()
183+
print("BrailleLove terminated.")
184+
185+
186+
if __name__ == "__main__":
187+
main()

0 commit comments

Comments
 (0)