mirror of
https://github.com/littensy/charm.git
synced 2026-10-22 04:14:08 +00:00
refactor: improve error traceback
This commit is contained in:
parent
ee6237c4a2
commit
eab89077f6
6 changed files with 285 additions and 56 deletions
|
|
@ -408,17 +408,6 @@ test("should run cleanups outside any evaluation context", function()
|
|||
assert(calls == 0, "should not run after b update")
|
||||
end)
|
||||
|
||||
test.skip("infinite recursion should eventually throw", function()
|
||||
local counter, setCounter = signal(0)
|
||||
|
||||
local success = pcall(function()
|
||||
effect(function()
|
||||
setCounter(counter() + 1)
|
||||
end)
|
||||
end)
|
||||
assert(not success, "should have thrown")
|
||||
end)
|
||||
|
||||
test("should not retrigger the effect if the cleanup modifies one of the dependencies", function()
|
||||
local a, setA = signal(0)
|
||||
local calls = {}
|
||||
|
|
|
|||
|
|
@ -92,13 +92,4 @@ test("should dispose inner effects if created in an effect", function()
|
|||
assert(triggers == 2, "ran after dispose")
|
||||
end)
|
||||
|
||||
test("should disallow yielding", function()
|
||||
local success = pcall(function()
|
||||
effectScope(function()
|
||||
coroutine.yield()
|
||||
end)
|
||||
end)
|
||||
assert(not success, "should error on yield")
|
||||
end)
|
||||
|
||||
return {}
|
||||
|
|
|
|||
200
packages/charm/test/errors.test.luau
Normal file
200
packages/charm/test/errors.test.luau
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
--!optimize 1
|
||||
|
||||
local Charm = require("../src")
|
||||
local test = require("../../../tests/test")
|
||||
|
||||
test("should disallow yielding", function()
|
||||
local success = pcall(function()
|
||||
Charm.effectScope(function()
|
||||
coroutine.yield()
|
||||
end)
|
||||
end)
|
||||
assert(not success, "should error on yield")
|
||||
end)
|
||||
|
||||
test.describe("traceback", function()
|
||||
local DEFAULT_ERROR = "Test error"
|
||||
|
||||
local function fail(message: string?)
|
||||
error(message or DEFAULT_ERROR, 0)
|
||||
end
|
||||
|
||||
local function indirectError(message: string?)
|
||||
fail(message)
|
||||
end
|
||||
|
||||
local function assertStackTrace(err: unknown, expectation: string?)
|
||||
expectation = expectation or DEFAULT_ERROR
|
||||
assert(type(err) == "string", "Expected error to be a string")
|
||||
assert(string.find(err, expectation), `Expected error message to be "{expectation}", got: {err}`)
|
||||
assert(string.find(err, "fail"), `Expected stack trace to contain fail, got: {err}`)
|
||||
assert(string.find(err, "indirectError"), `Expected stack trace to contain indirectError, got: {err}`)
|
||||
end
|
||||
|
||||
test("signal update", function()
|
||||
local _, err = pcall(function()
|
||||
local _, setSrc = Charm.signal(0)
|
||||
setSrc(function()
|
||||
indirectError()
|
||||
return 1
|
||||
end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("atom update", function()
|
||||
local _, err = pcall(function()
|
||||
local src = Charm.atom(0)
|
||||
src(function()
|
||||
indirectError()
|
||||
return 1
|
||||
end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("computed", function()
|
||||
local _, err = pcall(function()
|
||||
local src = Charm.computed(function()
|
||||
indirectError()
|
||||
end)
|
||||
src()
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("effect init", function()
|
||||
local _, err = pcall(function()
|
||||
Charm.effect(function()
|
||||
indirectError()
|
||||
end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("effect run", function()
|
||||
local _, err = pcall(function()
|
||||
local src, setSrc = Charm.signal(0)
|
||||
Charm.effect(function()
|
||||
if src() == 1 then
|
||||
indirectError()
|
||||
end
|
||||
end)
|
||||
setSrc(1)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("effect cleanups", function()
|
||||
local _, err = pcall(function()
|
||||
local dispose = Charm.effect(function()
|
||||
Charm.onCleanup(function()
|
||||
indirectError("onCleanup")
|
||||
end)
|
||||
return function()
|
||||
indirectError("returned cleanup")
|
||||
end
|
||||
end)
|
||||
dispose()
|
||||
end)
|
||||
assertStackTrace(err, "onCleanup")
|
||||
assertStackTrace(err, "returned cleanup")
|
||||
end)
|
||||
|
||||
test("trigger", function()
|
||||
local _, err = pcall(function()
|
||||
Charm.trigger(function()
|
||||
indirectError()
|
||||
end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("untracked", function()
|
||||
local _, err = pcall(function()
|
||||
Charm.effectScope(function()
|
||||
Charm.untracked(function()
|
||||
indirectError()
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("batch", function()
|
||||
local _, err = pcall(function()
|
||||
Charm.batch(function()
|
||||
indirectError()
|
||||
end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("subscribe getter", function()
|
||||
local _, err = pcall(function()
|
||||
Charm.subscribe(function()
|
||||
indirectError()
|
||||
end, function() end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("subscribe callback", function()
|
||||
local _, err = pcall(function()
|
||||
local src, setSrc = Charm.signal(0)
|
||||
Charm.subscribe(src, function()
|
||||
indirectError()
|
||||
end)
|
||||
setSrc(1)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("listen getter", function()
|
||||
local _, err = pcall(function()
|
||||
Charm.listen(function()
|
||||
indirectError()
|
||||
end, function() end)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("listen callback", function()
|
||||
local _, err = pcall(function()
|
||||
local src, setSrc = Charm.signal(0)
|
||||
Charm.listen(src, function()
|
||||
indirectError()
|
||||
end)
|
||||
setSrc(1)
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("mapped getter", function()
|
||||
local _, err = pcall(function()
|
||||
local src = Charm.mapped(function()
|
||||
indirectError()
|
||||
return { 1 }
|
||||
end, function()
|
||||
return 1
|
||||
end)
|
||||
src()
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
|
||||
test("mapped transform", function()
|
||||
local _, err = pcall(function()
|
||||
local src = Charm.mapped(function()
|
||||
return { 1 }
|
||||
end, function()
|
||||
indirectError()
|
||||
return 1
|
||||
end)
|
||||
src()
|
||||
end)
|
||||
assertStackTrace(err)
|
||||
end)
|
||||
end)
|
||||
|
||||
return {}
|
||||
|
|
@ -12,6 +12,10 @@ test.describe("effectScope", function()
|
|||
require("@self/effectScope.test")
|
||||
end)
|
||||
|
||||
test.describe("error", function()
|
||||
require("@self/errors.test")
|
||||
end)
|
||||
|
||||
test.describe("gc", function()
|
||||
require("@self/gc.test")
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -167,4 +167,32 @@ test("should allow disposal during removal", function()
|
|||
assert(table.concat(edits) == "+1+2+3+4-1-2-3-4", `bad edits: {table.concat(edits)}`)
|
||||
end)
|
||||
|
||||
test("should not hang on error after recursive update", function()
|
||||
local items, setItems = signal({})
|
||||
|
||||
observe(items, function()
|
||||
setItems({ {} })
|
||||
error("test error")
|
||||
end)
|
||||
|
||||
local success, err = pcall(function()
|
||||
setItems({ {} })
|
||||
end)
|
||||
assert(not success, "should error")
|
||||
assert(string.find(tostring(err), "test error"), `bad error: {err}`)
|
||||
end)
|
||||
|
||||
test("should not hang on error after recursive init", function()
|
||||
local items, setItems = signal({ {} })
|
||||
|
||||
local success, err = pcall(function()
|
||||
observe(items, function()
|
||||
setItems({ {} })
|
||||
error("test error")
|
||||
end)
|
||||
end)
|
||||
assert(not success, "should error")
|
||||
assert(string.find(tostring(err), "test error"), `bad error: {err}`)
|
||||
end)
|
||||
|
||||
return {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue