Merge remote-tracking branch 'origin/main_desktop_1' into main_laptop_1
This commit is contained in:
@@ -229,4 +229,22 @@ section("names", () => {
|
||||
eq("통째 지움 → 이름 빠짐", [b.시트[0].이름정의.length, v("B1")], [0, "#NAME?"]);
|
||||
});
|
||||
|
||||
// ── 5. 104-2 — 행 · 열 넣기 · 지우기 때 조건부서식 · 유효성 범위도 같이(기본 번들 안 — remap 을 그대로 옮겨 적음) ──
|
||||
section("condfmt_validation_follow_rowcol", () => {
|
||||
const { C } = require("./helper_spreadsheet_engine.cjs");
|
||||
const b = book({ A1: 1, B1: 2 });
|
||||
b.시트[0].조건부서식 = [
|
||||
{ id: "cf1", 범위: [A.parseRange("A1:A1")], 조건: { 종류: "글포함", 글: "x" }, 스타일: {} },
|
||||
];
|
||||
b.시트[0].유효성 = [
|
||||
{ id: "v1", 범위: [A.parseRange("B1:B1")], 규칙: { 종류: "정수" }, 어기면: "막음", 메시지: "" },
|
||||
];
|
||||
C.applyCommand(b, { 종류: "행넣기", 시트: "s1", at: 0, 수: 1 });
|
||||
eq("조건부서식 — 행 넣은 뒤 범위", A.rangeToA1(b.시트[0].조건부서식[0].범위[0]), "A2:A2");
|
||||
eq("유효성 — 행 넣은 뒤 범위", A.rangeToA1(b.시트[0].유효성[0].범위[0]), "B2:B2");
|
||||
C.applyCommand(b, { 종류: "열지우기", 시트: "s1", at: 0, 수: 1 }); // A 열 지움
|
||||
eq("조건부서식 — 범위를 다 잃으면 규칙째 빠짐", b.시트[0].조건부서식.length, 0);
|
||||
eq("유효성 — B 열이 A 로 당겨짐", A.rangeToA1(b.시트[0].유효성[0].범위[0]), "A2:A2");
|
||||
});
|
||||
|
||||
process.stdout.write(JSON.stringify(results));
|
||||
|
||||
@@ -61,5 +61,40 @@ import { a1, assertEqual, makeBook, makeCtx, makeSheet, v } from "./test_stage2_
|
||||
assertEqual(book.시트[0].칸[a1(2, 0)], undefined, "위로 당김 · 마지막 자리 빔");
|
||||
}
|
||||
|
||||
// 104-2 — 밀기 · 당기기에도 알약 연결(`연결`)이 따라감.
|
||||
// A1=1 B1=2 C1=3 · B1 에 알약 k1 · B1:B1 자리에 오른쪽으로 밀기 → 알약도 C1 로.
|
||||
{
|
||||
const book = makeBook([
|
||||
makeSheet(
|
||||
"s1",
|
||||
{ [a1(0, 0)]: v(1), [a1(0, 1)]: v(2), [a1(0, 2)]: v(3) },
|
||||
{ 연결: [{ 키: "k1", 칸: a1(0, 1) }] },
|
||||
),
|
||||
]);
|
||||
const ctx = makeCtx(book, "s1");
|
||||
insertShiftRight(ctx, { r0: 0, c0: 1, r1: 0, c1: 1 });
|
||||
assertEqual(book.시트[0].연결, [{ 키: "k1", 칸: a1(0, 2) }], "오른쪽 밀기 · 알약 연결도 C1 로");
|
||||
}
|
||||
|
||||
// A1=1 B1=2 C1=3 · A1 · B1 에 알약 둘 · A1:A1 삭제(왼쪽 당김) → A1 알약은 지운 자리라 빠짐 · B1 알약은
|
||||
// A1 로 당겨짐.
|
||||
{
|
||||
const book = makeBook([
|
||||
makeSheet(
|
||||
"s1",
|
||||
{ [a1(0, 0)]: v(1), [a1(0, 1)]: v(2), [a1(0, 2)]: v(3) },
|
||||
{
|
||||
연결: [
|
||||
{ 키: "k1", 칸: a1(0, 0) },
|
||||
{ 키: "k2", 칸: a1(0, 1) },
|
||||
],
|
||||
},
|
||||
),
|
||||
]);
|
||||
const ctx = makeCtx(book, "s1");
|
||||
deleteShiftLeft(ctx, { r0: 0, c0: 0, r1: 0, c1: 0 });
|
||||
assertEqual(book.시트[0].연결, [{ 키: "k2", 칸: a1(0, 0) }], "왼쪽 당김 · 지운 자리 알약은 빠짐 · 나머지는 당겨짐");
|
||||
}
|
||||
|
||||
if (process.exitCode) process.exit(process.exitCode);
|
||||
console.log("spreadsheet_insert_dialog 시험 끝");
|
||||
|
||||
@@ -182,6 +182,91 @@ def test_면적_저장_뒤_도면_표_글_바뀜_자리_크기_그대로_표_없
|
||||
assert t1_rec["값"]["s1!B2"] == "20.00" and t2_rec["값"] == {"s1!B1": "10.00"} # 표 없어도 기록
|
||||
|
||||
|
||||
NAMED_SHEET = {**SHEET, "이름정의": [{"이름": "도면_T1", "범위": {"r0": 0, "c0": 1, "r1": 1, "c1": 2}}]}
|
||||
NAMED_BOOK = {**BOOK, "시트": [NAMED_SHEET]}
|
||||
|
||||
|
||||
def test_이름으로_범위를_풂_104_1():
|
||||
got = sheet_node.area_tables([{"book": NAMED_BOOK, "시트": "s1", "범위": "", "이름": "도면_T1"}])[0]
|
||||
assert got["ok"] and got["범위"] == "B1:C2" # 이름정의가 가리키는 지금 범위로(저장된 범위는 안 봄)
|
||||
|
||||
|
||||
def test_이름이_지워졌으면_이름없음_104_1():
|
||||
got = sheet_node.area_tables([{"book": BOOK, "시트": "s1", "범위": "B1:C2", "이름": "도면_없음"}])[0]
|
||||
assert not got["ok"] and got["까닭"] == area_table.NAME_GONE
|
||||
|
||||
|
||||
def test_define_names_있으면_갱신_없으면_더함_104_1():
|
||||
added = sheet_node.define_names(
|
||||
[{"book": BOOK, "시트": "s1", "범위": "B1:C2", "이름": "도면_T9"}]
|
||||
)[0]
|
||||
assert added["ok"]
|
||||
names = added["book"]["시트"][0]["이름정의"]
|
||||
assert {"이름": "도면_T9", "범위": {"r0": 0, "c0": 1, "r1": 1, "c1": 2}} in names
|
||||
again = sheet_node.define_names(
|
||||
[{"book": added["book"], "시트": "s1", "범위": "A1:A1", "이름": "도면_T9"}]
|
||||
)[0]
|
||||
kept = [n for n in again["book"]["시트"][0]["이름정의"] if n["이름"] == "도면_T9"]
|
||||
assert kept == [{"이름": "도면_T9", "범위": {"r0": 0, "c0": 0, "r1": 0, "c1": 0}}] # 갱신(둘 아님)
|
||||
|
||||
|
||||
def _named_link_drawing(folder: Path) -> None:
|
||||
"""연결표 T1 에 `이름`(104-1) · 이름정의가 가리키는 지금 범위는 B1:C2(저장된 범위는 A1:B2 — 낡음)."""
|
||||
with store.at(folder):
|
||||
got = store.read("structure", "rv")
|
||||
doc = got["문서"]
|
||||
doc["연결표"] = [{"연결": "T1", "시트": "s1", "범위": "A1:B2", "이름": "도면_T1", "값": {}}]
|
||||
store.write("structure", "rv", got["판"], doc)
|
||||
|
||||
|
||||
def test_저장_때_이름이_가리키는_범위로_갱신_104_1(world):
|
||||
system = world["system"]
|
||||
_named_link_drawing(system)
|
||||
with store.at(system):
|
||||
got = store.read("area", "rv")
|
||||
doc = got["문서"]
|
||||
doc["시트"][0]["이름정의"] = [{"이름": "도면_T1", "범위": {"r0": 0, "c0": 1, "r1": 1, "c1": 2}}]
|
||||
store.write("area", "rv", got["판"], doc)
|
||||
drawing = store.read("structure", "rv")["문서"]
|
||||
assert drawing["연결표"][0]["범위"] == "B1:C2" # 옛(A1:B2) 아님 — 이름이 가리키는 지금 범위
|
||||
|
||||
|
||||
def test_이름_통째_지워지면_연결_끊고_지운연결_104_1(world):
|
||||
system = world["system"]
|
||||
_named_link_drawing(system) # 이름정의 없는 책 — 이름이 없는 것과 같음
|
||||
with store.at(system):
|
||||
got = store.read("area", "rv")
|
||||
store.write("area", "rv", got["판"], got["문서"]) # 면적 저장 → refresh_drawing
|
||||
drawing = store.read("structure", "rv")["문서"]
|
||||
assert drawing["연결표"] == [] # 연결 끊김(도면 표 엔티티는 안 지움)
|
||||
assert drawing["지운연결"] == ["T1"]
|
||||
|
||||
|
||||
def test_이름_정의_엔드포인트_104_1(world):
|
||||
world["session"]["role"] = "SYSTEM_ADMIN" # system 층 쓰기 권한
|
||||
client = world["client"]
|
||||
res = client.post(
|
||||
"/api/m02/layers/system/area/rv/name",
|
||||
json={"시트": "s1", "범위": "B1:C2", "이름": "도면_T5"},
|
||||
)
|
||||
assert res.status_code == 200, res.text
|
||||
with store.at(world["system"]):
|
||||
names = store.read("area", "rv")["문서"]["시트"][0]["이름정의"]
|
||||
assert {"이름": "도면_T5", "범위": {"r0": 0, "c0": 1, "r1": 1, "c1": 2}} in names
|
||||
|
||||
|
||||
def test_보내기_취소_엔드포인트_104_3(world):
|
||||
world["session"]["role"] = "SYSTEM_ADMIN" # system 층 쓰기 권한
|
||||
system = world["system"]
|
||||
_named_link_drawing(system)
|
||||
client = world["client"]
|
||||
res = client.post("/api/m02/layers/system/structures/rv/unlink", json={"연결": "T1"})
|
||||
assert res.status_code == 200, res.text
|
||||
with store.at(system):
|
||||
doc = store.read("structure", "rv")["문서"]
|
||||
assert doc["연결표"] == [] # 도면 엔티티는 이 길에서 안 건드림(지우기는 도면에서)
|
||||
|
||||
|
||||
def test_프로젝트_층_길도_같은_맞춤(world, tmp_path):
|
||||
project = tmp_path / "project"
|
||||
import shutil
|
||||
|
||||
@@ -172,7 +172,15 @@ def test_저장_연결표는_남은_표만(got):
|
||||
now = {"s1!B2": "1.5", "s1!C2": "2"}
|
||||
assert got["saved"] == [
|
||||
{"연결": "T1", "장": "", "시트": "s1", "범위": "A1:A1", "글자크기": 3, "값": now},
|
||||
{"연결": "T2", "장": "", "시트": "s1", "범위": "B2:C2", "글자크기": 2.5, "값": now},
|
||||
{
|
||||
"연결": "T2",
|
||||
"장": "",
|
||||
"시트": "s1",
|
||||
"범위": "B2:C2",
|
||||
"이름": "도면_T2", # 104-1 — 새로 놓은 표만 이름정의(옛 T1 기록은 그대로 범위만)
|
||||
"글자크기": 2.5,
|
||||
"값": now,
|
||||
},
|
||||
]
|
||||
assert got["plain"] is False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user