lib/compile.js

  1. // Copyright 2018 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. 'use strict';
  15. var handlebars = require('handlebars');
  16. var helpers = require('./handlebar-helpers')
  17. var fs = require('fs')
  18. var path = require('path')
  19. var DefaultTemplateDirectory = path.join(__dirname, '..', 'templates');
  20. var TopLevelTemplateName = 'topLevel.handlebars';
  21. var PathTemplateName = 'pathLevel.handlebars';
  22. var OperationTemplateName = 'operationLevel.handlebars';
  23. var TransactionTemplateName = 'transactionLevel.handlebars';
  24. /**
  25. * @namespace compilation
  26. */
  27. module.exports = compile
  28. handlebars.registerHelper('notEmptyObject', helpers.notEmptyObject)
  29. handlebars.registerHelper('json', helpers.json)
  30. handlebars.registerHelper('isNotDefaultStatusCode',
  31. helpers.isNotDefaultStatusCode)
  32. /**
  33. * GeneratedTest is the set of results from procressing a spec & compiling the test code
  34. * @typedef {object} GeneratedTest
  35. * @memberof compilation
  36. * @property {string} filename A file name based off of the path being tested
  37. * @property {string} contents Generated test file contents
  38. */
  39. /**
  40. * Compiles the templated test files with the given processed API spec data
  41. * @function compile
  42. * @memberof compilation
  43. * @instance
  44. * @param {processing.ProcessedSpec} processed the API spec data processed for test generation
  45. * @param {object} options for use in compilation of the tests
  46. * @return {compilation.GeneratedTest[]}
  47. */
  48. function compile(processed, options) {
  49. var tests = []
  50. processed.tests.forEach(function (processedPath, ndx, arr) {
  51. var pathTest = compilePathLevel(processedPath, processed, options)
  52. if (pathTest !== null) {
  53. tests.push({
  54. 'filename': processedPath.name + '-test.js',
  55. 'contents': pathTest
  56. })
  57. }
  58. });
  59. if (tests.length === 0) {
  60. return null
  61. }
  62. return tests
  63. }
  64. /**
  65. * GeneratedPath is the result of procressing a path & compiling the path-level test code
  66. * @typedef {object} GeneratedPath
  67. * @memberof compilation
  68. * @property {string} test the generated test code portion
  69. */
  70. /**
  71. * Compiles the path level 'describe' content
  72. * @function compilePathLevel
  73. * @memberof compilation
  74. * @instance
  75. * @param {processing.ProcessedPath} processedPath the processed path object to be compiled
  76. * @param {processing.ProcessedSpec} processed the entire processed API spec
  77. * @param {object} options for use in test compilation
  78. * @return {compilation.GeneratedPath}
  79. */
  80. function compilePathLevel(processedPath, processed, options) {
  81. var tests = []
  82. var requireLevelCompiler = prepareTemplate(
  83. path.join(
  84. options.templates ? options.templates : DefaultTemplateDirectory,
  85. TopLevelTemplateName
  86. )
  87. )
  88. var pathLevelCompiler = prepareTemplate(
  89. path.join(
  90. options.templates ? options.templates : DefaultTemplateDirectory,
  91. PathTemplateName
  92. )
  93. )
  94. processedPath.operations.forEach(function (processedOp, ndx, arr) {
  95. var opLevelTest = compileOperationLevel(processedOp, processedPath,
  96. processed, options)
  97. if (opLevelTest !== null) {
  98. tests.push(opLevelTest)
  99. }
  100. })
  101. var pathLevelDescribe = pathLevelCompiler({
  102. 'pathLevelDescription': processedPath.pathLevelDescription,
  103. 'tests': tests
  104. })
  105. return requireLevelCompiler({'test': pathLevelDescribe})
  106. }
  107. /**
  108. * GeneratedOp is the result of procressing an operation & compiling the operation-level test code
  109. * @typedef {object} GeneratedOp
  110. * @memberof compilation
  111. * @property {string} operationLevelDescription the operation level description to use incompilation
  112. * @property {compilation.GeneratedTransaction[]} operationLevelTests Generated test file contents
  113. */
  114. /**
  115. * Compiles the operation level 'describe' content
  116. * @function compileOperationLevel
  117. * @memberof compilation
  118. * @instance
  119. * @param {processing.ProcessedOp} processedOp the processed operation object to be compiled
  120. * @param {processing.ProcessedPath} processedPath the parent processed path object
  121. * @param {processing.ProcessedSpec} processed the entire processed API spec
  122. * @param {object} options for use in test compilation
  123. * @return {compilation.GeneratedOp}
  124. */
  125. function compileOperationLevel(processedOp, processedPath, processed, options) {
  126. var tests = []
  127. var operationLevelCompiler = prepareTemplate(
  128. path.join(
  129. options.templates ? options.templates : DefaultTemplateDirectory,
  130. OperationTemplateName
  131. )
  132. )
  133. processedOp.transactions.forEach(function (transaction, ndx, arr) {
  134. var transactionTest = compileTransactionLevel(transaction, processedOp,
  135. processedPath, processed, options)
  136. tests.push(transactionTest)
  137. })
  138. return operationLevelCompiler({
  139. 'operationLevelDescription': processedOp.operationLevelDescription,
  140. 'operationLevelTests': tests
  141. })
  142. }
  143. /**
  144. * GeneratedTransaction is the compiled unit test code for a specific transaction
  145. * @typedef {string} GeneratedTransaction
  146. * @memberof compilation
  147. */
  148. /**
  149. * Compiles the operation level 'describe' content
  150. * @function compileTransactionLevel
  151. * @memberof compilation
  152. * @instance
  153. * @param {processing.ProcessedTransaction} transaction the processed transaction object to be compiled
  154. * @param {processing.ProcessedOp} processedOp the parent processed operation object
  155. * @param {processing.ProcessedPath} processedPath the parent processed path object
  156. * @param {processing.ProcessedSpec} processed the entire processed API spec
  157. * @param {object} options for use in test compilation
  158. * @return {compilation.GeneratedTransaction}
  159. */
  160. function compileTransactionLevel(transaction, processedOp, processedPath,
  161. processed, options) {
  162. var transactionCompiler = prepareTemplate(
  163. path.join(
  164. options.templates ? options.templates : DefaultTemplateDirectory,
  165. TransactionTemplateName
  166. )
  167. )
  168. return transactionCompiler(transaction)
  169. }
  170. /**
  171. * prepares a handlebars template for the template given by the path
  172. * @function prepareTemplate
  173. * @memberof compilation
  174. * @instance
  175. * @param {string} templatePath path to the template to load
  176. * @return {function}
  177. */
  178. function prepareTemplate(templatePath) {
  179. var source = fs.readFileSync(templatePath, 'utf8');
  180. return handlebars.compile(source, {noEscape: true})
  181. }