quad/quad-base/test/smoke.plugin.luau
qwreey-agent-selene 297c4d459c
design: quad-types 패키지 신설 — AddPlugin<Self,P> + CheckedQuad<T> 실측 설계
quad-roblox가 quad-base를 런타임 주입(QuadRoblox(Quad): QuadRoblox)으로만
받으면 pesde 의존 선언이 필요 없어 보이지만, 타입 참조용 require도
런타임에 실제 실행됨을 실측 확인 — dev-dependency로 두면 게시 후
소비자 환경에서 크래시함. 해법으로 구현 없는 타입 계약 전용 워크스페이스
패키지 quad-types 신설, quad-base/quad-roblox 모두 이것만 의존하도록
전환.

AddPlugin<Self,P>(self:Self,fn:(Self)->P):Self&P — 제네릭 self로 둬야
체이닝이 누적됨을 실측 확인(고정하면 이전 확장을 잃음), quad-base에
실제 mutate 기반 구현 반영.

CheckedQuad<T> 버전 체크는 배선하며 세 번 깨짐 — error() 대신
print+types.never, 함수 본문 로컬 별칭 대신 리턴 타입 표현식에 직접,
그리고 가장 중요하게 type function을 한 번이라도 거친 값(패스스루
포함)은 이후 AddPlugin 같은 제네릭 self 체이닝이 조용히 깨진다는 새
Luau 함정 발견 — typing-limits.md §6으로 승격. 최종 설계(검증 결과를
원본과 격리된 가상 필드로)만 AddPlugin과 완전히 호환.

부수로 quad-base 자신도 quad-types workspace 의존 때문에 CLI symlink
함정(지난 세션 발견)에 걸림 — 로컬 테스트용 symlink 실체화로 임시 우회.

Co-authored-by: qwreey <me@qwreey.moe>
2026-08-19 17:09:16 +09:00

55 lines
1.6 KiB
Text

--[[ 임시 스모크 테스트 — Quad.Version/AddPlugin이 실제로 동작하는지 확인 ]]
local Quad = require("../src")
print("=== 1. Version 필드가 pesde.toml과 맞음 ===")
assert(Quad.Version == "0.0.0", "quad-base/pesde.toml의 version과 일치해야 함")
print("PASS")
print()
print("=== 2. AddPlugin이 원본 identity를 유지한 채(mutate) 확장 필드를 추가함 ===")
do
local function springPlugin(_self)
return {
Spring = function(_selfArg, v)
return v * 2
end,
}
end
local withSpring = Quad:AddPlugin(springPlugin)
assert(withSpring == Quad, "AddPlugin은 원본 module을 그대로 mutate+반환해야 함(RunInit 추적이 identity에 의존)")
assert(withSpring:Spring(21) == 42, "확장된 메소드가 실제로 동작해야 함")
assert(withSpring.debug == false, "원본 필드는 그대로 남아있어야 함")
print("PASS")
end
print()
print("=== 3. 체이닝 — 여러 플러그인을 연속으로 추가해도 전부 누적됨 ===")
do
local m = Quad.New()
local function pluginA(_self)
return {
A = function(_selfArg)
return "a"
end,
}
end
local function pluginB(_self)
return {
B = function(_selfArg)
return "b"
end,
}
end
local withBoth = m:AddPlugin(pluginA):AddPlugin(pluginB)
assert(withBoth:A() == "a", "pluginA의 확장 메소드가 동작해야 함")
assert(withBoth:B() == "b", "pluginB의 확장 메소드가 동작해야 함")
assert(withBoth.debug == false, "원본 필드는 체이닝 후에도 남아있어야 함")
print("PASS")
end
print()
print("=== ALL PASS ===")