summaryrefslogtreecommitdiff
path: root/Data/Libraries/Penlight/tests/test-strict.lua
blob: 12b0fad38af79613fb5cfce7521796c450c6976a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
require 'pl.compat' -- require this one before loading strict
local strict = require 'pl.strict'
local test = require 'pl.test'
local app = require 'pl.app'

-- in strict mode, you must assign to a global first, even if just nil.
test.assertraise(function()
   print(x)
   print 'ok?'
end,"variable 'x' is not declared")

-- can assign to globals in main (or from C extensions) but not anywhere else!
test.assertraise(function()
   Boo = 3
end,"assign to undeclared global 'Boo'")

Boo = true
Boo2 = nil

-- once declared, you can assign to globals from anywhere
(function() Boo = 42; Boo2 = 6*7 end)()

--- a module may use strict.module() to generate a simularly strict environment
-- (see lua/mymod.lua)
app.require_here 'lua'
local M = require 'mymod'

--- these are fine
M.answer()
M.question()

-- spelling mistakes become errors...
test.assertraise(function()
    print(M.Answer())
end,"variable 'Answer' is not declared in 'mymod'")

--- for the extra paranoid, you can choose to make all global tables strict...
strict.make_all_strict(_G)

test.assertraise(function()
    print(math.sine(1.2))
end,"variable 'sine' is not declared in 'math'")



-- module
do
  local testmodule = {
    hello = function() return "supremacy" end
  }
  -- make strict and allow extra field "world"
  strict.module("my_test", testmodule, { world = true })

  test.asserteq(testmodule.hello(), "supremacy")
  test.assertraise(function()
    print(testmodule.not_allowed_key)
  end, "variable 'not_allowed_key' is not declared in 'my_test'")

  test.asserteq(testmodule.world, nil)
  testmodule.world = "supremacy"
  test.asserteq(testmodule.world, "supremacy")


  -- table with a __newindex method
  local mod1 = strict.module("mod1", setmetatable(
    {
      hello = "world",
    }, {
      __newindex = function(self, key, value)
        if key == "Lua" then
          rawset(self, key, value)
        end
      end,
    }
  ))
  test.asserteq(mod1.hello, "world")
  mod1.Lua = "hello world"
  test.asserteq(mod1.Lua, "hello world")
  test.assertraise(function()
    print(mod1.not_allowed_key)
  end, "variable 'not_allowed_key' is not declared in 'mod1'")


  -- table with a __index method
  local mod1 = strict.module("mod1", setmetatable(
    {
      hello = "world",
    }, {
      __index = function(self, key)
        if key == "Lua" then
          return "rocks"
        end
      end,
    }
  ))
  test.asserteq(mod1.hello, "world")
  test.asserteq(mod1.Lua, "rocks")
  test.assertraise(function()
    print(mod1.not_allowed_key)
  end, "variable 'not_allowed_key' is not declared in 'mod1'")


  -- table with a __index table
  local mod1 = strict.module("mod1", setmetatable(
    {
      hello = "world",
    }, {
      __index = {
        Lua = "rocks!"
      }
    }
  ))
  test.asserteq(mod1.hello, "world")
  test.asserteq(mod1.Lua, "rocks!")
  test.assertraise(function()
    print(mod1.not_allowed_key)
  end, "variable 'not_allowed_key' is not declared in 'mod1'")

end


do
  -- closed_module
  -- what does this do? this does not seem a usefull function???

  local testmodule = {
    hello = function() return "supremacy" end
  }
  local M = strict.closed_module(testmodule, "my_test")

  -- read acces to original is granted, but not to the new one
  test.asserteq(testmodule.hello(), "supremacy")
  test.assertraise(function()
    print(M.hello())
  end, "variable 'hello' is not declared in 'my_test'")

  -- write access to both is granted
  testmodule.world = "domination"
  M.world = "domination"

  -- read acces to set field in original is granted, but not set
  test.asserteq(testmodule.world, nil)
  test.asserteq(M.world, "domination")

end