local describe = require("lua_test.test").describe
local test = require("lua_test.test").test
local expect = require("lua_test.test").expect
local function create_mock_actors()
return {
sakura = { name = "さくら", spot = 0 },
kero = { name = "うにゅう", spot = 1 },
}
end
describe("SAKURA_BUILDER - talk token", function()
test("talkトークンがtalk_to_scriptで変換される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("Hello")):toBeTruthy()
end)
test("句点にはウェイトタグが挿入される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "あ。" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\_w%[950%]")):toBeTruthy()
end)
test("読点にはウェイトタグが挿入される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "あ、" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\_w%[450%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - surface token", function()
test("surfaceトークンを \\s[id] に変換する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "" },
{ type = "surface", id = 5 },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\s%[5%]")):toBeTruthy()
end)
test("文字列IDをサポートする", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "" },
{ type = "surface", id = "smile" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\s%[smile%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - wait token", function()
test("waitトークンを \\w[ms] に変換する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "" },
{ type = "wait", ms = 500 },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\w%[500%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - newline token", function()
test("newlineトークンを \\n に変換する(n=1)", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "" },
{ type = "newline", n = 1 },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\n")):toBeTruthy()
end)
test("複数改行を連続出力する(n=3)", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "" },
{ type = "newline", n = 3 },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\n\\n\\n")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - clear token", function()
test("clearトークンを \\c に変換する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "" },
{ type = "clear" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\c")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - raw_script token", function()
test("raw_scriptトークンをそのまま出力する(エスケープなし)", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "" },
{ type = "raw_script", text = "\\![open,calendar]" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[open,calendar%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - yield token", function()
test("yieldトークンは無視される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "surface", id = 5 },
{ type = "yield" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\s%[5%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - \\e終端", function()
test("出力末尾に \\e を付与する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:sub(-2)):toBe("\\e")
end)
test("空トークン配列でも \\e を付与する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local result = BUILDER.build({}, {})
expect(result):toBe("\\e")
end)
end)
describe("SAKURA_BUILDER - 複合シナリオ", function()
test("複数トークンを正しく連結する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
{ type = "surface", id = 5 },
{ type = "wait", ms = 100 },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "Hi" },
{ type = "newline", n = 1 },
{ type = "clear" },
}
},
}
local result = BUILDER.build(tokens, { spot_newlines = 1.5 })
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(result:find("Hello")):toBeTruthy()
expect(result:find("\\s%[5%]")):toBeTruthy()
expect(result:find("\\w%[100%]")):toBeTruthy()
expect(result:find("\\n%[150%]")):toBeTruthy() expect(result:find("\\p%[1%]")):toBeTruthy()
expect(result:find("Hi")):toBeTruthy()
expect(result:find("\\n")):toBeTruthy()
expect(result:find("\\c")):toBeTruthy()
expect(result:sub(-2)):toBe("\\e")
end)
end)
describe("SAKURA_BUILDER - talk_to_script変換", function()
test("テキストがtalk_to_scriptで変換される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "50 off sale" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("50 off sale")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - spotトークン処理", function()
test("spotトークン処理でactor_spots[actor.name]が正しく更新される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(result:find("Hello")):toBeTruthy()
end)
test("複数actorのspot独立管理を確認", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hi Sakura" },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "Hi Kero" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(result:find("\\p%[1%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - clear_spotトークン処理", function()
test("clear_spotトークン処理でactor_spots={}にリセットされる", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 5 },
{ type = "clear_spot" },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Reset" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(result:find("Reset")):toBeTruthy()
end)
test("clear_spotトークン処理でlast_actor=nilにリセットされる", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Before" },
}
},
{ type = "clear_spot" },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "After" },
}
},
}
local result = BUILDER.build(tokens, {})
local count = 0
for _ in result:gmatch("\\p%[0%]") do
count = count + 1
end
expect(count):toBe(2)
end)
end)
describe("SAKURA_BUILDER - actorトークンのactor切り替え検出", function()
test("actor_spots未設定時にデフォルト値0を使用する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(result:find("Hello")):toBeTruthy()
end)
test("last_actor != token.actor時に\\p[spot]を出力する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "First" },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "Second" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\p%[0%].*First")):toBeTruthy()
expect(result:find("\\p%[1%].*Second")):toBeTruthy()
end)
test("spot変更時に\\n[N]を出力する(Nはconfig.spot_newlines * 100)", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "First" },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "Second" },
}
},
}
local result = BUILDER.build(tokens, { spot_newlines = 1.5 })
expect(result:find("\\n%[150%]")):toBeTruthy()
end)
test("同じactorの連続actorトークンではスポットタグを出力しない", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "First" },
}
},
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Second" },
}
},
}
local result = BUILDER.build(tokens, {})
local count = 0
for _ in result:gmatch("\\p%[0%]") do
count = count + 1
end
expect(count):toBe(1)
expect(result:find("FirstSecond")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - 統合シナリオ(グループ化トークン構造)", function()
test("set_spot()なしでのtalk() → デフォルトspot(0)使用を確認", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "No spot set" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(result:find("No spot set")):toBeTruthy()
end)
test("set_spot() → talk() → spot切り替えとスポットタグ出力を確認", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Sakura speaks" },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "Kero speaks" },
}
},
}
local result = BUILDER.build(tokens, { spot_newlines = 1.5 })
expect(result:find("\\p%[0%]Sakura speaks")):toBeTruthy()
expect(result:find("\\n%[150%]\\p%[1%]Kero speaks")):toBeTruthy()
end)
test("clear_spot() → talk() → デフォルトspot(0)への復帰を確認", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 5 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "At spot 5" },
}
},
{ type = "clear_spot" },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Back to default" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\p%[5%]")):toBeTruthy()
expect(result:find("\\p%[0%]")):toBeTruthy() end)
end)
describe("SAKURA_BUILDER - persist-spot-position: 純粋関数性テスト (Task 5.3)", function()
test("入力テーブルがspotトークンで直接変更されることを確認", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local input_spots = {}
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
BUILDER.build(tokens, {}, input_spots)
expect(input_spots["さくら"]):toBe(0)
expect(input_spots["うにゅう"]):toBe(1)
end)
test("nil入力時に空テーブルとして扱われることを確認", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
local result = BUILDER.build(tokens, {}, nil)
expect(result:find("\\p%[0%]")):toBeTruthy()
end)
test("spotトークンでinput_spotsが直接変更される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local input_spots = {}
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
local result = BUILDER.build(tokens, {}, input_spots)
expect(type(result)):toBe("string")
expect(input_spots["さくら"]):toBe(0)
end)
test("後方互換性: actor_spots省略時も正常動作", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("Hello")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - persist-spot-position: clear_spotトークン処理 (Task 5.4)", function()
test("clear_spotトークンで入力のactor_spotsがリセットされる", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local input_spots = { ["さくら"] = 5, ["うにゅう"] = 3 }
local tokens = {
{ type = "clear_spot" },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Reset" },
}
},
}
local result = BUILDER.build(tokens, {}, input_spots)
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(input_spots["さくら"]):toBe(nil)
expect(input_spots["うにゅう"]):toBe(nil)
end)
test("直接変更: clear_spotで入力テーブルのエントリがクリアされる", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local input_spots = { ["さくら"] = 5, ["うにゅう"] = 3 }
local tokens = {
{ type = "clear_spot" },
}
BUILDER.build(tokens, {}, input_spots)
expect(input_spots["さくら"]):toBe(nil)
expect(input_spots["うにゅう"]):toBe(nil)
end)
end)
describe("SAKURA_BUILDER - persist-spot-position: spotトークン処理 (Task 5.5)", function()
test("spotトークンで入力のactor_spotsが正しく更新される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local input_spots = { ["さくら"] = 0 }
local tokens = {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hi" },
}
},
}
BUILDER.build(tokens, {}, input_spots)
expect(input_spots["さくら"]):toBe(0)
expect(input_spots["うにゅう"]):toBe(1)
end)
test("入力actor_spotsの値を引き継いでスポットタグが出力される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local input_spots = { ["さくら"] = 0, ["うにゅう"] = 1 }
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Still here" },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "Me too" },
}
},
}
local result = BUILDER.build(tokens, { spot_newlines = 1.5 }, input_spots)
expect(result:find("\\p%[0%]")):toBeTruthy()
expect(result:find("\\p%[1%]")):toBeTruthy()
expect(result:find("\\n%[150%]")):toBeTruthy()
expect(input_spots["さくら"]):toBe(0)
expect(input_spots["うにゅう"]):toBe(1)
end)
end)
describe("SAKURA_BUILDER - sakura_scriptトークン処理", function()
test("sakura_scriptトークンがtalk_to_scriptで変換される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "sakura_script", actor = actors.sakura, text = "\\n" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\n")):toBeTruthy()
expect(result:sub(-2)):toBe("\\e")
end)
test("talk + sakura_script混合がそれぞれ処理される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "Hello" },
{ type = "sakura_script", actor = actors.sakura, text = "\\w9" },
{ type = "talk", actor = actors.sakura, text = "World" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("Hello")):toBeTruthy()
expect(result:find("\\w9")):toBeTruthy()
expect(result:find("World")):toBeTruthy()
end)
test("raw_scriptトークンの既存動作が変化していない", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "raw_script", text = "\\![open,notepad]" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[open,notepad%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - choiceトークン処理", function()
test("choiceトークンを \\![*]\\q[display,target] に変換する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice", display = "こんにちは", target = "挨拶" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[%*%]\\q%[こんにちは,挨拶%]")):toBeTruthy()
expect(result:sub(-2)):toBe("\\e")
end)
test("displayテキスト内の ] をエスケープする", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice", display = "yes]no", target = "分岐" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[%*%]\\q%[yes\\]no,分岐%]")):toBeTruthy()
end)
test("displayテキスト内の , をエスケープする", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice", display = "A,B", target = "分岐" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[%*%]\\q%[A\\,B,分岐%]")):toBeTruthy()
end)
test("displayテキスト内の \\ をエスケープする", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice", display = "a\\b", target = "分岐" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[%*%]\\q%[a\\\\b,分岐%]")):toBeTruthy()
end)
test("displayテキスト内の複合デリミタをエスケープする(], ,, \\)", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice", display = "yes]or,no\\maybe", target = "挨拶" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[%*%]\\q%[yes\\]or\\,no\\\\maybe,挨拶%]")):toBeTruthy()
end)
test("targetテキスト内のデリミタもエスケープされる", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice", display = "はい", target = "a],b\\c" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[%*%]\\q%[はい,a\\]\\,b\\\\c%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - choice_timeoutトークン処理", function()
test("choice_timeoutトークンを \\![set,choicetimeout,<ms>] に変換する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice_timeout", seconds = 5 },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[set,choicetimeout,5000%]")):toBeTruthy()
expect(result:sub(-2)):toBe("\\e")
end)
test("choice_timeout seconds=nil の場合は 0 を出力する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice_timeout", seconds = nil },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[set,choicetimeout,0%]")):toBeTruthy()
end)
test("choice_timeout 小数秒をミリ秒に変換し floor する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "choice_timeout", seconds = 2.5 },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("\\!%[set,choicetimeout,2500%]")):toBeTruthy()
end)
end)
describe("SAKURA_BUILDER - choice統合シナリオ", function()
test("talk + choice_timeout + choice の複合トークンが正しく連結される", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local actors = create_mock_actors()
local tokens = {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "選んでね" },
{ type = "choice_timeout", seconds = 10 },
{ type = "choice", display = "はい", target = "yes_route" },
{ type = "choice", display = "いいえ", target = "no_route" },
}
},
}
local result = BUILDER.build(tokens, {})
expect(result:find("選んでね")):toBeTruthy()
expect(result:find("\\!%[set,choicetimeout,10000%]")):toBeTruthy()
expect(result:find("\\!%[%*%]\\q%[はい,yes_route%]")):toBeTruthy()
expect(result:find("\\!%[%*%]\\q%[いいえ,no_route%]")):toBeTruthy()
expect(result:sub(-2)):toBe("\\e")
end)
end)
describe("SAKURA_BUILDER - string-buffer: 空入力 (Task 3.1)", function()
test("空の grouped_tokens で build() が \\e のみを返す", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local result = BUILDER.build({}, {})
expect(result):toBe("\\e")
end)
test("空入力はネイティブ/フォールバック両経路で \\e のみを返す", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local buf = require("pasta.buf")
local native = BUILDER.build({}, {})
local fallback = BUILDER.build({}, { buffer_factory = buf.new_fallback })
expect(native):toBe("\\e")
expect(fallback):toBe("\\e")
expect(fallback):toBe(native)
end)
end)
describe("SAKURA_BUILDER - string-buffer: フォールバック実走バイト一致 (Task 3.1)", function()
local function make_complex_tokens(actors)
return {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 1 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "こんにちは。今日は、いい天気。" },
{ type = "surface", id = 5 },
{ type = "wait", ms = 100 },
{ type = "newline", n = 2 },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "Hi there" },
{ type = "sakura_script", actor = actors.kero, text = "\\w9" },
{ type = "clear" },
{ type = "choice_timeout", seconds = 5 },
{ type = "choice", display = "はい]", target = "yes,route" },
{ type = "raw_script", text = "\\![open,calendar]" },
}
},
}
end
test("複合入力(spot/talk/surface/wait/newline/choice 等)でバイト一致する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local buf = require("pasta.buf")
local actors = create_mock_actors()
local config = { spot_newlines = 1.5 }
local native_spots = {}
local native = BUILDER.build(make_complex_tokens(actors), config, native_spots)
local fb_spots = {}
local fb_config = { spot_newlines = 1.5, buffer_factory = buf.new_fallback }
local fallback = BUILDER.build(make_complex_tokens(actors), fb_config, fb_spots)
expect(fallback):toBe(native)
expect(#native > 2):toBeTruthy()
expect(native:sub(-2)):toBe("\\e")
expect(fb_spots["さくら"]):toBe(native_spots["さくら"])
expect(fb_spots["うにゅう"]):toBe(native_spots["うにゅう"])
end)
test("spot 変更・改行を含む入力でバイト一致する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local buf = require("pasta.buf")
local actors = create_mock_actors()
local function make_tokens()
return {
{ type = "spot", actor = actors.sakura, spot = 0 },
{ type = "spot", actor = actors.kero, spot = 2 },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "おはよう。" },
}
},
{
type = "actor",
actor = actors.kero,
tokens = {
{ type = "talk", actor = actors.kero, text = "おはよ、ございます。" },
{ type = "newline", n = 3 },
}
},
{ type = "clear_spot" },
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "またね。" },
}
},
}
end
local config = { spot_newlines = 2.0 }
local native = BUILDER.build(make_tokens(), config, {})
local fallback = BUILDER.build(make_tokens(), { spot_newlines = 2.0, buffer_factory = buf.new_fallback }, {})
expect(fallback):toBe(native)
expect(native:find("\\n%[200%]")):toBeTruthy()
expect(native:sub(-2)):toBe("\\e")
end)
test("choice/raw_script/sakura_script を含む単一actor入力でバイト一致する", function()
local BUILDER = require("pasta.shiori.sakura_builder")
local buf = require("pasta.buf")
local actors = create_mock_actors()
local function make_tokens()
return {
{
type = "actor",
actor = actors.sakura,
tokens = {
{ type = "talk", actor = actors.sakura, text = "選んでね" },
{ type = "choice_timeout", seconds = 10 },
{ type = "choice", display = "A,B]C\\D", target = "route]1" },
{ type = "sakura_script", actor = actors.sakura, text = "\\_w[200]" },
{ type = "raw_script", text = "\\![open,notepad]" },
}
},
}
end
local native = BUILDER.build(make_tokens(), {}, {})
local fallback = BUILDER.build(make_tokens(), { buffer_factory = buf.new_fallback }, {})
expect(fallback):toBe(native)
expect(native:find("\\!%[%*%]\\q%[A\\,B\\]C\\\\D,route\\]1%]")):toBeTruthy()
expect(native:sub(-2)):toBe("\\e")
end)
end)