Skip to content

Commit

Permalink
tests: split local and local type tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hishamhm committed Aug 21, 2024
1 parent 7a1fa02 commit 2bd5357
Show file tree
Hide file tree
Showing 2 changed files with 257 additions and 253 deletions.
295 changes: 42 additions & 253 deletions spec/declaration/local_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,48 @@ describe("local", function()
local z: number
z = x + y
]]))

it("'type', 'record' and 'enum' are not reserved keywords", util.check([[
local type = type
local record: string = "hello"
local enum: number = 123
print(record)
print(enum + 123)
]]))

it("reports unset and untyped values as errors in tl mode", util.check_type_error([[
local record T
x: number
y: number
end
function T:returnsTwo(): number, number
return self.x, self.y
end
function T:method()
local a, b = self.returnsTwo and self:returnsTwo()
end
]], {
{ msg = "assignment in declaration did not produce an initial value for variable 'b'" },
}))

it("reports unset values as unknown in Lua mode", util.lax_check([[
local record T
x: number
y: number
end
function T:returnsTwo(): number, number
return self.x, self.y
end
function T:method()
local a, b = self.returnsTwo and self:returnsTwo()
end
]], {
{ msg = "b" },
}))
end)

describe("multiple declaration", function()
Expand Down Expand Up @@ -63,230 +105,6 @@ describe("local", function()
z = x + string.byte(y)
]]))
end)

it("reports unset and untyped values as errors in tl mode", util.check_type_error([[
local type T = record
x: number
y: number
end
function T:returnsTwo(): number, number
return self.x, self.y
end
function T:method()
local a, b = self.returnsTwo and self:returnsTwo()
end
]], {
{ msg = "assignment in declaration did not produce an initial value for variable 'b'" },
}))

it("reports unset values as unknown in Lua mode", util.lax_check([[
local type T = record
x: number
y: number
end
function T:returnsTwo(): number, number
return self.x, self.y
end
function T:method()
local a, b = self.returnsTwo and self:returnsTwo()
end
]], {
{ msg = "b" },
}))

it("local type can declare a type alias for table", util.check([[
local type PackTable = table.PackTable
local args: table.PackTable<integer> = table.pack(1, 2, 3)
]]))

it("local type can declare a nominal type alias (regression test for #238)", function ()
util.mock_io(finally, {
["module.tl"] = [[
local record module
record Type
data: number
end
end
return module
]],
["main.tl"] = [[
local module = require "module"
local type Boo = module.Type
local var: Boo = { dato = 0 }
print(var.dato)
]],
})
local result, err = tl.process("main.tl")

assert.same({}, result.syntax_errors)
assert.same({
{ y = 3, x = 35, filename = "main.tl", msg = "in local declaration: var: unknown field dato" },
{ y = 4, x = 26, filename = "main.tl", msg = "invalid key 'dato' in record 'var' of type Boo" },
}, result.type_errors)
end)

it("local type can resolve a nominal with generics (regression test for #777)", function ()
util.mock_io(finally, {
["module.tl"] = [[
local record module
record Foo<K>
something: K
end
end
return module
]],
["main.tl"] = [[
local module = require "module"
local record Boo
field: MyFoo<string>
end
local type MyFoo<Z> = module.Foo<Z>
local b: Boo = { field = { something = "hi" } }
local c: Boo = { field = { something = 123 } }
]],
})
local result, err = tl.process("main.tl")

assert.same({}, result.syntax_errors)
assert.same({
{ y = 10, x = 55, filename = "main.tl", msg = "in record field: something: got integer, expected string" },
}, result.type_errors)
end)

it("catches unknown types", util.check_type_error([[
local type MyType = UnknownType
]], {
{ msg = "unknown type UnknownType" }
}))

it("nominal types can take type arguments", util.check([[
local record Foo<R>
item: R
end
local type Foo2 = Foo
local type Bla = Foo<number>
local x: Bla = { item = 123 }
local y: Foo2<number> = { item = 123 }
]]))

it("types declared as nominal types are aliases", util.check([[
local record Foo<R>
item: R
end
local type Foo2 = Foo
local type FooNumber = Foo<number>
local x: FooNumber = { item = 123 }
local y: Foo2<number> = { item = 123 }
local type Foo3 = Foo
local type Foo4 = Foo2
local zep: Foo2<string> = { item = "hello" }
local zip: Foo3<string> = zep
local zup: Foo4<string> = zip
]]))

it("nested types can be resolved as aliases", util.check([[
local record Foo<R>
enum LocalEnum
"loc"
end
record Nested
x: {LocalEnum}
y: R
end
item: R
end
local type Nested = Foo.Nested
]]))

it("'type', 'record' and 'enum' are not reserved keywords", util.check([[
local type = type
local record: string = "hello"
local enum: number = 123
print(record)
print(enum + 123)
]]))

it("local type can require a module", function ()
util.mock_io(finally, {
["class.tl"] = [[
local record Class
data: number
end
return Class
]],
["main.tl"] = [[
local type Class = require("class")
local obj: Class = { data = 2 }
]],
})
local result, err = tl.process("main.tl")

assert.same({}, result.syntax_errors)
assert.same({}, result.type_errors)
end)

it("local type can require a module and type is usable", function ()
util.mock_io(finally, {
["class.tl"] = [[
local record Class
data: number
end
return Class
]],
["main.tl"] = [[
local type Class = require("class")
local obj: Class = { invalid = 2 }
]],
})
local result, err = tl.process("main.tl")

assert.same({}, result.syntax_errors)
assert.same({
{ y = 2, x = 37, filename = "main.tl", msg = "in local declaration: obj: unknown field invalid" },
}, result.type_errors)
end)

it("local type can require a module and its globals are visible", function ()
util.mock_io(finally, {
["class.tl"] = [[
global record Glob
hello: number
end
local record Class
data: number
end
return Class
]],
["main.tl"] = [[
local type Class = require("class")
local obj: Glob = { hello = 2 }
local obj2: Glob = { invalid = 2 }
]],
})
local result, err = tl.process("main.tl")

assert.same({}, result.syntax_errors)
assert.same({
{ y = 3, x = 37, filename = "main.tl", msg = "in local declaration: obj2: unknown field invalid" },
}, result.type_errors)
end)
end)

describe("annotation", function()
Expand Down Expand Up @@ -567,33 +385,4 @@ describe("local", function()
{ y = 9, msg = "_bar1: got number, expected Bar" },
{ y = 10, msg = "_bar2: Foo is not a Bar" },
}))

it("does not accept type arguments declared twice", util.check_syntax_error([[
local type Foo<T> = record<T>
end
]], {
{ y = 1, msg = "cannot declare type arguments twice in type declaration" },
}))

it("propagates type arguments correctly", util.check_type_error([[
local record module
record Foo<A, B>
first: A
second: B
end
end
-- note inverted arguments
local type MyFoo<X, Y> = module.Foo<Y, X>
local record Boo
field: MyFoo<string, integer>
end
local b: Boo = { field = { first = "first", second = 2 } } -- bad, not inverted!
local c: Boo = { field = { first = 1, second = "second" } } -- good, inverted!
]], {
{ y = 15, x = 42, msg = 'in record field: first: got string "first", expected integer' },
{ y = 15, x = 60, msg = 'in record field: second: got integer, expected string' },
}))
end)
Loading

0 comments on commit 2bd5357

Please sign in to comment.