mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Update mock tests
This commit is contained in:
parent
04e28f390d
commit
b3c600acc3
13 changed files with 94 additions and 246 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
|
local typeof = typeof
|
||||||
|
|
||||||
if not game then
|
if not game then
|
||||||
script = (require :: any) "test/wrap-require"
|
script = require "test/wrap-require"
|
||||||
typeof = require "test/mock".typeof
|
typeof = require "test/mock".typeof :: any
|
||||||
end
|
end
|
||||||
|
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
|
|
||||||
local throw = require(script.Parent.throw)
|
|
||||||
local bind = require(script.Parent.bind)
|
local bind = require(script.Parent.bind)
|
||||||
local _, is_action = require(script.Parent.action)()
|
local _, is_action = require(script.Parent.action)()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
local warn = warn -- todo
|
local warn = warn
|
||||||
|
|
||||||
if not game then
|
if not game then
|
||||||
script = (require :: any) "test/wrap-require"
|
script = require "test/wrap-require"
|
||||||
warn = print
|
warn = print
|
||||||
end
|
end
|
||||||
|
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
local get = graph.get
|
|
||||||
local set_effect = graph.set_effect
|
local set_effect = graph.set_effect
|
||||||
local capture = graph.capture
|
local capture = graph.capture
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
|
local Instance = Instance
|
||||||
|
local typeof = typeof
|
||||||
|
|
||||||
if not game then
|
if not game then
|
||||||
script = (require :: any) "test/wrap-require"
|
script = require "test/wrap-require"
|
||||||
Instance = require("test/mock").Instance
|
Instance = require("test/mock").Instance
|
||||||
typeof = require("test/mock").typeof
|
typeof = require("test/mock").typeof
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
|
|
||||||
-- todo
|
|
||||||
local Enum = Enum
|
local Enum = Enum
|
||||||
local Color3 = Color3
|
local Color3 = Color3
|
||||||
local Vector3 = Vector3
|
local Vector3 = Vector3
|
||||||
|
|
||||||
if not game then
|
if not game then
|
||||||
local mock = require "test/mock"
|
local mock = require "test/mock"
|
||||||
Enum = mock.Enum :: any
|
Enum = mock.Enum
|
||||||
Color3 = mock.Color3 :: any
|
Color3 = mock.Color3
|
||||||
Vector3 = mock.Vector3 :: any
|
Vector3 = mock.Vector3
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
if not game then script = (require :: any) "test/wrap-require" end
|
if not game then script = require "test/wrap-require" end
|
||||||
|
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
local create = graph.create
|
local create = graph.create
|
||||||
local get = graph.get
|
|
||||||
local capture_and_link = graph.capture_and_link
|
local capture_and_link = graph.capture_and_link
|
||||||
|
|
||||||
local function derive<T>(fn: () -> T): () -> T
|
local function derive<T>(fn: () -> T): () -> T
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
if not game then script = (require :: any) "test/wrap-require" end
|
if not game then script = require "test/wrap-require" end
|
||||||
|
|
||||||
local flags = require(script.Parent.flags)
|
local flags = require(script.Parent.flags)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
-- v0.1.0
|
-- v0.1.0
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
if not game then script = (require :: any) "test/wrap-require" end
|
if not game then script = require "test/wrap-require" end
|
||||||
|
|
||||||
local create = require(script.create)
|
local create = require(script.create)
|
||||||
local source = require(script.source)
|
local source = require(script.source)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
if not game then script = (require :: any) "test/wrap-require" end
|
if not game then script = require "test/wrap-require" end
|
||||||
|
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
if not game then script = (require :: any) "test/wrap-require" end
|
if not game then script = require "test/wrap-require" end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
if not game then script = (require :: any) "test/wrap-require" end
|
if not game then script = require "test/wrap-require" end
|
||||||
|
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
local set_effect = graph.set_effect
|
local set_effect = graph.set_effect
|
||||||
|
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
--!nocheck
|
|
||||||
|
|
||||||
-- modified for use in pure luau
|
|
||||||
|
|
||||||
local task = { spawn = function(thread, ...)
|
|
||||||
local ok, err = coroutine.resume(thread, ...)
|
|
||||||
if not ok then error(err, 3) end
|
|
||||||
end }
|
|
||||||
|
|
||||||
export type Type = RBXScriptSignal & { Fire: (Type, ...any)-> () }
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------------------------------
|
|
||||||
-- Batched Yield-Safe Signal Implementation --
|
|
||||||
-- This is a Signal class which has effectively identical behavior to a --
|
|
||||||
-- normal RBXScriptSignal, with the only difference being a couple extra --
|
|
||||||
-- stack frames at the bottom of the stack trace when an error is thrown. --
|
|
||||||
-- This implementation caches runner coroutines, so the ability to yield in --
|
|
||||||
-- the signal handlers comes at minimal extra cost over a naive signal --
|
|
||||||
-- implementation that either always or never spawns a thread. --
|
|
||||||
-- --
|
|
||||||
-- API: --
|
|
||||||
-- local Signal = require(THIS MODULE) --
|
|
||||||
-- local sig = Signal.new() --
|
|
||||||
-- local connection = sig:Connect(function(arg1, arg2, ...) ... end) --
|
|
||||||
-- sig:Fire(arg1, arg2, ...) --
|
|
||||||
-- connection:Disconnect() --
|
|
||||||
-- sig:DisconnectAll() --
|
|
||||||
-- local arg1, arg2, ... = sig:Wait() --
|
|
||||||
-- --
|
|
||||||
-- Licence: --
|
|
||||||
-- Licenced under the MIT licence. --
|
|
||||||
-- --
|
|
||||||
-- Authors: --
|
|
||||||
-- stravant - July 31st, 2021 - Created the file. --
|
|
||||||
----------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- The currently idle thread to run the next handler on
|
|
||||||
local freeRunnerThread = nil
|
|
||||||
|
|
||||||
-- Function which acquires the currently idle handler runner thread, runs the
|
|
||||||
-- function fn on it, and then releases the thread, returning it to being the
|
|
||||||
-- currently idle one.
|
|
||||||
-- If there was a currently idle runner thread already, that's okay, that old
|
|
||||||
-- one will just get thrown and eventually GCed.
|
|
||||||
local function acquireRunnerThreadAndCallEventHandler(fn, ...)
|
|
||||||
local acquiredRunnerThread = freeRunnerThread
|
|
||||||
freeRunnerThread = nil
|
|
||||||
fn(...)
|
|
||||||
-- The handler finished running, this runner thread is free again.
|
|
||||||
freeRunnerThread = acquiredRunnerThread
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Coroutine runner that we create coroutines of. The coroutine can be
|
|
||||||
-- repeatedly resumed with functions to run followed by the argument to run
|
|
||||||
-- them with.
|
|
||||||
local function runEventHandlerInFreeThread()
|
|
||||||
-- Note: We cannot use the initial set of arguments passed to
|
|
||||||
-- runEventHandlerInFreeThread for a call to the handler, because those
|
|
||||||
-- arguments would stay on the stack for the duration of the thread's
|
|
||||||
-- existence, temporarily leaking references. Without access to raw bytecode
|
|
||||||
-- there's no way for us to clear the "..." references from the stack.
|
|
||||||
while true do
|
|
||||||
acquireRunnerThreadAndCallEventHandler(coroutine.yield())
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Connection class
|
|
||||||
local Connection = {}
|
|
||||||
Connection.__index = Connection
|
|
||||||
|
|
||||||
function Connection.new(signal, fn)
|
|
||||||
return setmetatable({
|
|
||||||
_connected = true,
|
|
||||||
_signal = signal,
|
|
||||||
_fn = fn,
|
|
||||||
_next = false,
|
|
||||||
}, Connection)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Connection:Disconnect()
|
|
||||||
self._connected = false
|
|
||||||
|
|
||||||
-- Unhook the node, but DON'T clear it. That way any fire calls that are
|
|
||||||
-- currently sitting on this node will be able to iterate forwards off of
|
|
||||||
-- it, but any subsequent fire calls will not hit it, and it will be GCed
|
|
||||||
-- when no more fire calls are sitting on it.
|
|
||||||
if self._signal._handlerListHead == self then
|
|
||||||
self._signal._handlerListHead = self._next
|
|
||||||
else
|
|
||||||
local prev = self._signal._handlerListHead
|
|
||||||
while prev and prev._next ~= self do
|
|
||||||
prev = prev._next
|
|
||||||
end
|
|
||||||
if prev then
|
|
||||||
prev._next = self._next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Make Connection strict
|
|
||||||
setmetatable(Connection, {
|
|
||||||
__index = function(tb, key)
|
|
||||||
error(("Attempt to get Connection::%s (not a valid member)"):format(tostring(key)), 2)
|
|
||||||
end,
|
|
||||||
__newindex = function(tb, key, value)
|
|
||||||
error(("Attempt to set Connection::%s (not a valid member)"):format(tostring(key)), 2)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Signal class
|
|
||||||
local Signal = {}
|
|
||||||
Signal.__index = Signal
|
|
||||||
|
|
||||||
Signal.__type = "RBXScriptSignal"
|
|
||||||
|
|
||||||
function Signal.new(): Type
|
|
||||||
return setmetatable({
|
|
||||||
_handlerListHead = false,
|
|
||||||
}, Signal) :: any
|
|
||||||
end
|
|
||||||
|
|
||||||
function Signal:Connect(fn)
|
|
||||||
if type(fn) ~= "function" then error(`attempt to connect non function (got { type(fn) })`, 2) end
|
|
||||||
local connection = Connection.new(self, fn)
|
|
||||||
if self._handlerListHead then
|
|
||||||
connection._next = self._handlerListHead
|
|
||||||
self._handlerListHead = connection
|
|
||||||
else
|
|
||||||
self._handlerListHead = connection
|
|
||||||
end
|
|
||||||
return connection
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Disconnect all handlers. Since we use a linked list it suffices to clear the
|
|
||||||
-- reference to the head handler.
|
|
||||||
function Signal:DisconnectAll()
|
|
||||||
self._handlerListHead = false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Signal:Fire(...) implemented by running the handler functions on the
|
|
||||||
-- coRunnerThread, and any time the resulting thread yielded without returning
|
|
||||||
-- to us, that means that it yielded to the Roblox scheduler and has been taken
|
|
||||||
-- over by Roblox scheduling, meaning we have to make a new coroutine runner.
|
|
||||||
function Signal:Fire(...)
|
|
||||||
local item = self._handlerListHead
|
|
||||||
while item do
|
|
||||||
if item._connected then
|
|
||||||
if not freeRunnerThread then
|
|
||||||
freeRunnerThread = coroutine.create(runEventHandlerInFreeThread)
|
|
||||||
-- Get the freeRunnerThread to the first yield
|
|
||||||
coroutine.resume(freeRunnerThread)
|
|
||||||
end
|
|
||||||
task.spawn(freeRunnerThread, item._fn, ...)
|
|
||||||
end
|
|
||||||
item = item._next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Implement Signal:Wait() in terms of a temporary connection using
|
|
||||||
-- a Signal:Connect() which disconnects itself.
|
|
||||||
function Signal:Wait()
|
|
||||||
local waitingCoroutine = coroutine.running()
|
|
||||||
local cn;
|
|
||||||
cn = self:Connect(function(...)
|
|
||||||
cn:Disconnect()
|
|
||||||
task.spawn(waitingCoroutine, ...)
|
|
||||||
end)
|
|
||||||
return coroutine.yield()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Implement Signal:Once() in terms of a connection which disconnects
|
|
||||||
-- itself before running the handler.
|
|
||||||
function Signal:Once(fn)
|
|
||||||
local cn;
|
|
||||||
cn = self:Connect(function(...)
|
|
||||||
if cn._connected then
|
|
||||||
cn:Disconnect()
|
|
||||||
end
|
|
||||||
fn(...)
|
|
||||||
end)
|
|
||||||
return cn
|
|
||||||
end
|
|
||||||
|
|
||||||
return Signal
|
|
||||||
111
test/mock.luau
111
test/mock.luau
|
|
@ -1,22 +1,58 @@
|
||||||
local Instance = {} do
|
--[[
|
||||||
local Signal = require "test/goodsignal"
|
|
||||||
type Signal = Signal.Type
|
|
||||||
|
|
||||||
type userdata = { __USERDATA: true }
|
contains mock Roblox API interfaces for unit testing
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Signal = {} :: any do
|
||||||
|
Signal.__index = Signal
|
||||||
|
Signal.__type = "RBXScriptSignal"
|
||||||
|
|
||||||
|
local function new_connection(signal, fn)
|
||||||
|
return {
|
||||||
|
signal = signal,
|
||||||
|
fn = fn,
|
||||||
|
|
||||||
|
Disconnect = function(self)
|
||||||
|
local i = table.find(signal.connections, self)
|
||||||
|
if not i then return end
|
||||||
|
table.remove(signal.connections, i)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.new()
|
||||||
|
return setmetatable({
|
||||||
|
connections = {}
|
||||||
|
}, Signal)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.Connect(self, fn)
|
||||||
|
local con = new_connection(self, fn)
|
||||||
|
table.insert(self.connections, con)
|
||||||
|
return con
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.fire(self, ...)
|
||||||
|
for i = #self.connections, 1, -1 do
|
||||||
|
self.connections[i].fn(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local Instance = {} :: any do
|
||||||
--[[
|
--[[
|
||||||
|
|
||||||
attempt to mimic roblox engine's method of userdata proxy to actual instance data
|
attempt to mimic roblox engine's method of userdata reflection
|
||||||
proxy can gc independantly of actual instance data
|
proxy can gc independantly of actual instance data
|
||||||
proxy prevents gc of actual instance data
|
proxy prevents gc of actual instance data
|
||||||
luau code never has direct access to actual instance data, only to proxy
|
user code never has direct access to actual instance data, only to proxy
|
||||||
|
internal weak map kept data -> proxy
|
||||||
proxy knows data
|
|
||||||
data does not know proxy
|
|
||||||
separate weak map kept data -> proxy
|
|
||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
type userdata = { __USERDATA: true }
|
||||||
|
|
||||||
type ProxyMT = {
|
type ProxyMT = {
|
||||||
proxy: userdata,
|
proxy: userdata,
|
||||||
data: Data,
|
data: Data,
|
||||||
|
|
@ -28,9 +64,9 @@ local Instance = {} do
|
||||||
name: string,
|
name: string,
|
||||||
parent: Data?,
|
parent: Data?,
|
||||||
children: { Data },
|
children: { Data },
|
||||||
changed: { [string]: Signal },
|
changed: { [string]: RBXScriptSignal },
|
||||||
properties: { [string]: unknown },
|
properties: { [string]: unknown },
|
||||||
destroying: Signal,
|
destroying: RBXScriptSignal,
|
||||||
class: string,
|
class: string,
|
||||||
type: "Instance"
|
type: "Instance"
|
||||||
}
|
}
|
||||||
|
|
@ -47,8 +83,6 @@ local Instance = {} do
|
||||||
return t :: T & {}
|
return t :: T & {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local proxies = {} :: { [Data]: userdata? }
|
local proxies = {} :: { [Data]: userdata? }
|
||||||
setmetatable(proxies :: any, { __mode = "v" })
|
setmetatable(proxies :: any, { __mode = "v" })
|
||||||
|
|
||||||
|
|
@ -96,7 +130,7 @@ local Instance = {} do
|
||||||
end
|
end
|
||||||
|
|
||||||
if data.changed[property] then
|
if data.changed[property] then
|
||||||
data.changed[property]:Fire()
|
Signal.fire(data.changed[property])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -175,17 +209,17 @@ local Instance = {} do
|
||||||
|
|
||||||
function methods.Destroy(userdata: userdata)
|
function methods.Destroy(userdata: userdata)
|
||||||
local data = get_data(userdata);
|
local data = get_data(userdata);
|
||||||
data.destroying:Fire()
|
Signal.fire(data.destroying)
|
||||||
data.parent = nil
|
data.parent = nil
|
||||||
if data.changed["Parent"] then
|
if data.changed["Parent"] then
|
||||||
data.changed["Parent"]:Fire()
|
Signal.fire(data.changed["Parent"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local Color3 = {} do
|
local Color3 = {} :: any do
|
||||||
function Color3.new(r, g, b): Color3
|
function Color3.new(r, g, b)
|
||||||
return setmetatable({ r = r, g = g, b = b}, Color3) :: any
|
return setmetatable({ r = r, g = g, b = b}, Color3)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Color3.__eq(a, b)
|
function Color3.__eq(a, b)
|
||||||
|
|
@ -193,9 +227,9 @@ local Color3 = {} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local Vector3 = {} do
|
local Vector3 = {} :: any do
|
||||||
function Vector3.new(x, y, z): Vector3
|
function Vector3.new(x, y, z)
|
||||||
return setmetatable({ x = x, y = y, z = z}, Vector3) :: any
|
return setmetatable({ x = x, y = y, z = z}, Vector3)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Vector3.__eq(a, b)
|
function Vector3.__eq(a, b)
|
||||||
|
|
@ -203,9 +237,9 @@ local Vector3 = {} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local Vector2 = {} do
|
local Vector2 = {} :: any do
|
||||||
function Vector2.new(x, y): Vector2
|
function Vector2.new(x, y)
|
||||||
return setmetatable({ x = x, y = y }, Vector2) :: any
|
return setmetatable({ x = x, y = y }, Vector2)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Vector2.__eq(a, b)
|
function Vector2.__eq(a, b)
|
||||||
|
|
@ -213,9 +247,9 @@ local Vector2 = {} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local UDim2 = {} do
|
local UDim2 = {} :: any do
|
||||||
function UDim2.fromScale(x, y): UDim2
|
function UDim2.fromScale(x, y)
|
||||||
return setmetatable({ x = { scale = x, offset = 0 }, y = { scale = y, offset = 0 } }, UDim2) :: any
|
return setmetatable({ x = { scale = x, offset = 0 }, y = { scale = y, offset = 0 } }, UDim2)
|
||||||
end
|
end
|
||||||
|
|
||||||
function UDim2.__eq(a, b)
|
function UDim2.__eq(a, b)
|
||||||
|
|
@ -237,18 +271,19 @@ local Enum = {} :: any do
|
||||||
end})
|
end})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function typeof(v): string
|
local typeof = function(v)
|
||||||
return if Instance.is_instance(v) then "Instance"
|
return if Instance.is_instance(v) then "Instance"
|
||||||
elseif getmetatable(v) and getmetatable(v).__type then getmetatable(v).__type
|
elseif getmetatable(v) and getmetatable(v).__type then getmetatable(v).__type
|
||||||
else type(v)
|
else type(v)
|
||||||
end
|
end :: any
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Instance = Instance,
|
Signal = Signal,
|
||||||
Color3 = Color3,
|
Instance = Instance :: typeof(Instance),
|
||||||
Vector3 = Vector3,
|
Color3 = Color3 :: typeof(Color3),
|
||||||
Vector2 = Vector2,
|
Vector3 = Vector3 :: typeof(Vector3),
|
||||||
UDim2 = UDim2,
|
Vector2 = Vector2 :: typeof(Vector2),
|
||||||
Enum = Enum,
|
UDim2 = UDim2 :: typeof(UDim2),
|
||||||
typeof = typeof
|
Enum = Enum :: typeof(Enum),
|
||||||
|
typeof = typeof :: typeof(typeof)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
local testkit = require("test/testkit")
|
local testkit = require("test/testkit")
|
||||||
local TEST, CASE, CHECK, FINISH, SKIP = testkit.test()
|
local TEST, CASE, CHECK, FINISH, SKIP = testkit.test()
|
||||||
|
|
||||||
local Signal = require "test/goodsignal"
|
|
||||||
local mock = require "test/mock"
|
local mock = require "test/mock"
|
||||||
|
|
||||||
|
local Instance, Signal = mock.Instance, mock.Signal
|
||||||
local Instance, Vector3, Color3, Vector2, UDim2 =
|
|
||||||
mock.Instance, mock.Vector3, mock.Color3, mock.Vector2, mock.UDim2
|
|
||||||
|
|
||||||
local vide = require "src/init"
|
local vide = require "src/init"
|
||||||
|
|
||||||
|
|
@ -1194,7 +1191,7 @@ TEST("Events", function()
|
||||||
-- testkit.print2(getmetatable(val))
|
-- testkit.print2(getmetatable(val))
|
||||||
|
|
||||||
CHECK(not connected)
|
CHECK(not connected)
|
||||||
val.Value = 1; val.Signal:Fire(val.Value)
|
val.Value = 1; Signal.fire(val.Signal, val.Value)
|
||||||
CHECK(connected)
|
CHECK(connected)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue