test_declare.lua 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. ---
  2. -- test_declare.lua
  3. --
  4. -- Declare unit test suites, and fetch tests from them.
  5. --
  6. -- Author Jason Perkins
  7. -- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
  8. ---
  9. local p = premake
  10. local m = p.modules.self_test
  11. local _ = {}
  12. _.suites = {}
  13. _.suppressed = {}
  14. ---
  15. -- Declare a new test suite.
  16. --
  17. -- @param suiteName
  18. -- A unique name for the suite. This name will be displayed as part of
  19. -- test failure messages, and also to select the suite when using the
  20. -- `--test-only` command line parameter. Best to avoid spaces and special
  21. -- characters which might not be command line friendly. An error will be
  22. -- raised if the name is not unique.
  23. -- @return
  24. -- The new test suite object.
  25. ---
  26. function m.declare(suiteName)
  27. if _.suites[suiteName] then
  28. error('Duplicate test suite "'.. suiteName .. '"', 2)
  29. end
  30. local _suite = {}
  31. -- Setup a metatable for the test suites to use, this will catch duplicate tests
  32. local suite = setmetatable({}, {
  33. __index = _suite,
  34. __newindex = function (table, key, value)
  35. if m.detectDuplicateTests and _suite[key] ~= nil then
  36. error('Duplicate test "'.. key .. '"', 2)
  37. end
  38. _suite[key] = value
  39. end,
  40. __pairs = function (table) return pairs(_suite) end,
  41. __ipairs = function (table) return ipairs(_suite) end,
  42. })
  43. suite._SCRIPT_DIR = _SCRIPT_DIR
  44. suite._TESTS_DIR = _TESTS_DIR
  45. _.suites[suiteName] = suite
  46. return suite
  47. end
  48. ---
  49. -- Prevent a particular test or suite of tests from running.
  50. --
  51. -- @param identifier
  52. -- A test or suite identifier, indicating which tests should be suppressed,
  53. -- in the form "suiteName" or "suiteName.testName".
  54. ---
  55. function m.suppress(identifier)
  56. if type(identifier) == "table" then
  57. for i = 1, #identifier do
  58. m.suppress(identifier[i])
  59. end
  60. else
  61. _.suppressed[identifier] = true
  62. end
  63. end
  64. function m.isSuppressed(identifier)
  65. return _.suppressed[identifier]
  66. end
  67. ---
  68. -- Returns true if the provided test object represents a valid test.
  69. ---
  70. function m.isValid(test)
  71. if type(test.testFunction) ~= "function" then
  72. return false
  73. end
  74. if test.testName == "setup" or test.testName == "teardown" then
  75. return false
  76. end
  77. return true
  78. end
  79. ---
  80. -- Return the table of declared test suites.
  81. ---
  82. function m.getSuites()
  83. return _.suites
  84. end
  85. ---
  86. -- Fetch test objects via the string identifier.
  87. --
  88. -- @param identifier
  89. -- An optional test or suite identifier, indicating which tests should be
  90. -- run, in the form "suiteName" or "suiteName.testName". If not specified,
  91. -- the global test object, representing all test suites, will be returned.
  92. -- Use "*" to match any part of a suite or test name
  93. -- @return
  94. -- On success, returns an array of test objects, which should be considered opaque.
  95. -- On failure, returns `nil` and an error.
  96. ---
  97. function m.getTestsWithIdentifier(identifier)
  98. local suiteName, testName = m.parseTestIdentifier(identifier)
  99. if suiteName ~= nil and string.contains(suiteName, "*") then
  100. local tests = {}
  101. local pattern = string.gsub(suiteName, "*", ".*")
  102. for _suiteName, suite in pairs(_.suites) do
  103. local length = string.len(_suiteName)
  104. local start, finish = string.find(_suiteName, pattern)
  105. if start == 1 and finish == length then
  106. if testName ~= nil then
  107. if string.contains(testName, "*") then
  108. local testPattern = string.gsub(testName, "*", ".*")
  109. for _testName, test in pairs(suite) do
  110. length = string.len(_testName)
  111. start, finish = string.find(_testName, testPattern)
  112. if start == 1 and finish == length then
  113. table.insert(tests, {
  114. suiteName = _suiteName,
  115. suite = suite,
  116. testName = _testName,
  117. testFunction = test,
  118. })
  119. end
  120. end
  121. else
  122. table.insert(tests, {
  123. suiteName = _suiteName,
  124. suite = suite,
  125. testName = testName,
  126. testFunction = suite[testName],
  127. })
  128. end
  129. else
  130. table.insert(tests, {
  131. suiteName = _suiteName,
  132. suite = suite,
  133. testName = nil,
  134. testFunction = nil,
  135. })
  136. end
  137. end
  138. end
  139. return tests
  140. else
  141. local suite, test, err = _.checkTestIdentifier(_.suites, suiteName, testName)
  142. if err then
  143. return nil, err
  144. end
  145. return {
  146. {
  147. suiteName = suiteName,
  148. suite = suite,
  149. testName = testName,
  150. testFunction = test
  151. }
  152. }
  153. end
  154. end
  155. ---
  156. -- Parse a test identifier and split it into separate suite and test names.
  157. --
  158. -- @param identifier
  159. -- A test identifier, which may be nil or an empty string, a test suite
  160. -- name, or a suite and test with the format "suiteName.testName".
  161. -- @return
  162. -- Two values: the suite name and the test name, or nil if not included
  163. -- in the identifier.
  164. ---
  165. function m.parseTestIdentifier(identifier)
  166. local suiteName, testName
  167. if identifier then
  168. local parts = string.explode(identifier, ".", true)
  169. suiteName = iif(parts[1] ~= "", parts[1], nil)
  170. testName = iif(parts[2] ~= "", parts[2], nil)
  171. end
  172. return suiteName, testName
  173. end
  174. function _.checkTestIdentifier(suites, suiteName, testName)
  175. local suite, test
  176. if suiteName then
  177. suite = suites[suiteName]
  178. if not suite then
  179. return nil, nil, "No such test suite '" .. suiteName .. "'"
  180. end
  181. if testName then
  182. test = suite[testName]
  183. if not _.isValidTestPair(testName, test) then
  184. return nil, nil, "No such test '" .. suiteName .. "." .. testName .. "'"
  185. end
  186. end
  187. end
  188. return suite, test
  189. end
  190. function _.isValidTestPair(testName, testFunc)
  191. if type(testFunc) ~= "function" then
  192. return false
  193. end
  194. if testName == "setup" or testName == "teardown" then
  195. return false
  196. end
  197. return true
  198. end