trackler 2.2.1.33 → 2.2.1.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (267) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/README.md +1 -1
  4. data/problem-specifications/exercises/palindrome-products/description.md +9 -3
  5. data/tracks/c/exercises/hamming/src/example.c +9 -8
  6. data/tracks/c/exercises/hamming/src/example.h +1 -1
  7. data/tracks/c/exercises/hamming/test/test_hamming.c +31 -7
  8. data/tracks/clojure/config.json +10 -0
  9. data/tracks/clojure/exercises/collatz-conjecture/README.md +34 -0
  10. data/tracks/clojure/exercises/collatz-conjecture/project.clj +4 -0
  11. data/tracks/clojure/exercises/collatz-conjecture/src/collatz_conjecture.clj +3 -0
  12. data/tracks/clojure/exercises/collatz-conjecture/src/example.clj +13 -0
  13. data/tracks/clojure/exercises/collatz-conjecture/test/collatz_conjecture_test.clj +29 -0
  14. data/tracks/coldfusion/.gitignore +1 -0
  15. data/tracks/coldfusion/.travis.yml +16 -4
  16. data/tracks/coldfusion/CONTRIBUTING.md +10 -0
  17. data/tracks/coldfusion/README.md +85 -6
  18. data/tracks/coldfusion/config.json +195 -10
  19. data/tracks/coldfusion/config/maintainers.json +8 -1
  20. data/tracks/coldfusion/docs/ABOUT.md +8 -0
  21. data/tracks/coldfusion/docs/EXERCISE_README_INSERT.md +15 -0
  22. data/tracks/coldfusion/docs/INSTALLATION.md +35 -0
  23. data/tracks/coldfusion/docs/LEARNING.md +37 -0
  24. data/tracks/coldfusion/docs/RESOURCES.md +29 -0
  25. data/tracks/coldfusion/docs/SNIPPET.txt +8 -0
  26. data/tracks/coldfusion/docs/TESTS.md +19 -0
  27. data/tracks/coldfusion/exercises/acronym/.meta/HINTS.md +0 -0
  28. data/tracks/coldfusion/exercises/acronym/Acronym.cfc +13 -0
  29. data/tracks/coldfusion/exercises/acronym/AcronymTest.cfc +43 -0
  30. data/tracks/coldfusion/exercises/acronym/Solution.cfc +22 -0
  31. data/tracks/coldfusion/exercises/acronym/SolutionTest.cfc +7 -0
  32. data/tracks/coldfusion/exercises/acronym/TestRunner.cfc +103 -0
  33. data/tracks/coldfusion/exercises/acronym/box.json +8 -0
  34. data/tracks/coldfusion/exercises/acronym/index.cfm +37 -0
  35. data/tracks/coldfusion/exercises/atbash-cipher/.meta/HINTS.md +0 -0
  36. data/tracks/coldfusion/exercises/atbash-cipher/AtbashCipher.cfc +14 -0
  37. data/tracks/coldfusion/exercises/atbash-cipher/AtbashCipherTest.cfc +71 -0
  38. data/tracks/coldfusion/exercises/atbash-cipher/Solution.cfc +56 -0
  39. data/tracks/coldfusion/exercises/atbash-cipher/SolutionTest.cfc +7 -0
  40. data/tracks/coldfusion/exercises/atbash-cipher/TestRunner.cfc +103 -0
  41. data/tracks/coldfusion/exercises/atbash-cipher/box.json +8 -0
  42. data/tracks/coldfusion/exercises/atbash-cipher/index.cfm +37 -0
  43. data/tracks/coldfusion/exercises/diamond/.meta/HINTS.md +0 -0
  44. data/tracks/coldfusion/exercises/diamond/Diamond.cfc +13 -0
  45. data/tracks/coldfusion/exercises/diamond/DiamondTest.cfc +35 -0
  46. data/tracks/coldfusion/exercises/diamond/Solution.cfc +35 -0
  47. data/tracks/coldfusion/exercises/diamond/SolutionTest.cfc +7 -0
  48. data/tracks/coldfusion/exercises/diamond/TestRunner.cfc +103 -0
  49. data/tracks/coldfusion/exercises/diamond/box.json +8 -0
  50. data/tracks/coldfusion/exercises/diamond/index.cfm +37 -0
  51. data/tracks/coldfusion/exercises/difference-of-squares/.meta/HINTS.md +0 -0
  52. data/tracks/coldfusion/exercises/difference-of-squares/DifferenceOfSquares.cfc +18 -0
  53. data/tracks/coldfusion/exercises/difference-of-squares/DifferenceOfSquaresTest.cfc +63 -0
  54. data/tracks/coldfusion/exercises/difference-of-squares/Solution.cfc +28 -0
  55. data/tracks/coldfusion/exercises/difference-of-squares/SolutionTest.cfc +7 -0
  56. data/tracks/coldfusion/exercises/difference-of-squares/TestRunner.cfc +103 -0
  57. data/tracks/coldfusion/exercises/difference-of-squares/box.json +8 -0
  58. data/tracks/coldfusion/exercises/difference-of-squares/index.cfm +37 -0
  59. data/tracks/coldfusion/exercises/flatten-array/.meta/HINTS.md +0 -0
  60. data/tracks/coldfusion/exercises/flatten-array/FlattenArray.cfc +13 -0
  61. data/tracks/coldfusion/exercises/flatten-array/FlattenArrayTest.cfc +42 -0
  62. data/tracks/coldfusion/exercises/flatten-array/Solution.cfc +26 -0
  63. data/tracks/coldfusion/exercises/flatten-array/SolutionTest.cfc +7 -0
  64. data/tracks/coldfusion/exercises/flatten-array/TestRunner.cfc +103 -0
  65. data/tracks/coldfusion/exercises/flatten-array/box.json +8 -0
  66. data/tracks/coldfusion/exercises/flatten-array/index.cfm +37 -0
  67. data/tracks/coldfusion/exercises/gigasecond/.meta/HINTS.md +0 -0
  68. data/tracks/coldfusion/exercises/gigasecond/Gigasecond.cfc +13 -0
  69. data/tracks/coldfusion/exercises/gigasecond/GigasecondTest.cfc +39 -0
  70. data/tracks/coldfusion/exercises/gigasecond/Solution.cfc +16 -0
  71. data/tracks/coldfusion/exercises/gigasecond/SolutionTest.cfc +7 -0
  72. data/tracks/coldfusion/exercises/gigasecond/TestRunner.cfc +103 -0
  73. data/tracks/coldfusion/exercises/gigasecond/box.json +8 -0
  74. data/tracks/coldfusion/exercises/gigasecond/index.cfm +37 -0
  75. data/tracks/coldfusion/exercises/grains/.meta/HINTS.md +0 -0
  76. data/tracks/coldfusion/exercises/grains/Grains.cfc +14 -0
  77. data/tracks/coldfusion/exercises/grains/GrainsTest.cfc +63 -0
  78. data/tracks/coldfusion/exercises/grains/Solution.cfc +22 -0
  79. data/tracks/coldfusion/exercises/grains/SolutionTest.cfc +7 -0
  80. data/tracks/coldfusion/exercises/grains/TestRunner.cfc +103 -0
  81. data/tracks/coldfusion/exercises/grains/box.json +8 -0
  82. data/tracks/coldfusion/exercises/grains/index.cfm +37 -0
  83. data/tracks/coldfusion/exercises/hamming/.meta/HINTS.md +0 -0
  84. data/tracks/coldfusion/exercises/hamming/Hamming.cfc +13 -0
  85. data/tracks/coldfusion/exercises/hamming/HammingTest.cfc +75 -0
  86. data/tracks/coldfusion/exercises/hamming/Solution.cfc +25 -0
  87. data/tracks/coldfusion/exercises/hamming/SolutionTest.cfc +7 -0
  88. data/tracks/coldfusion/exercises/hamming/TestRunner.cfc +103 -0
  89. data/tracks/coldfusion/exercises/hamming/box.json +8 -0
  90. data/tracks/coldfusion/exercises/hamming/index.cfm +37 -0
  91. data/tracks/coldfusion/exercises/hello-world/HelloWorld.cfc +13 -0
  92. data/tracks/coldfusion/exercises/hello-world/HelloWorldTest.cfc +18 -0
  93. data/tracks/coldfusion/exercises/hello-world/Solution.cfc +13 -0
  94. data/tracks/coldfusion/exercises/hello-world/SolutionTest.cfc +7 -0
  95. data/tracks/coldfusion/exercises/hello-world/TestRunner.cfc +103 -0
  96. data/tracks/coldfusion/exercises/hello-world/box.json +8 -0
  97. data/tracks/coldfusion/exercises/hello-world/index.cfm +37 -0
  98. data/tracks/coldfusion/exercises/isogram/.meta/HINTS.md +0 -0
  99. data/tracks/coldfusion/exercises/isogram/Isogram.cfc +13 -0
  100. data/tracks/coldfusion/exercises/isogram/IsogramTest.cfc +55 -0
  101. data/tracks/coldfusion/exercises/isogram/Solution.cfc +23 -0
  102. data/tracks/coldfusion/exercises/isogram/SolutionTest.cfc +7 -0
  103. data/tracks/coldfusion/exercises/isogram/TestRunner.cfc +103 -0
  104. data/tracks/coldfusion/exercises/isogram/box.json +8 -0
  105. data/tracks/coldfusion/exercises/isogram/index.cfm +37 -0
  106. data/tracks/coldfusion/exercises/largest-series-product/.meta/HINTS.md +0 -0
  107. data/tracks/coldfusion/exercises/largest-series-product/LargestSeriesProduct.cfc +13 -0
  108. data/tracks/coldfusion/exercises/largest-series-product/LargestSeriesProductTest.cfc +75 -0
  109. data/tracks/coldfusion/exercises/largest-series-product/Solution.cfc +41 -0
  110. data/tracks/coldfusion/exercises/largest-series-product/SolutionTest.cfc +7 -0
  111. data/tracks/coldfusion/exercises/largest-series-product/TestRunner.cfc +103 -0
  112. data/tracks/coldfusion/exercises/largest-series-product/box.json +8 -0
  113. data/tracks/coldfusion/exercises/largest-series-product/index.cfm +37 -0
  114. data/tracks/coldfusion/exercises/leap/Leap.cfc +15 -0
  115. data/tracks/coldfusion/exercises/leap/LeapTest.cfc +39 -0
  116. data/tracks/coldfusion/exercises/leap/Solution.cfc +19 -0
  117. data/tracks/coldfusion/exercises/leap/SolutionTest.cfc +7 -0
  118. data/tracks/coldfusion/exercises/leap/TestRunner.cfc +103 -0
  119. data/tracks/coldfusion/exercises/leap/box.json +8 -0
  120. data/tracks/coldfusion/exercises/leap/index.cfm +37 -0
  121. data/tracks/coldfusion/exercises/luhn/.meta/HINTS.md +0 -0
  122. data/tracks/coldfusion/exercises/luhn/Luhn.cfc +13 -0
  123. data/tracks/coldfusion/exercises/luhn/LuhnTest.cfc +67 -0
  124. data/tracks/coldfusion/exercises/luhn/Solution.cfc +38 -0
  125. data/tracks/coldfusion/exercises/luhn/SolutionTest.cfc +7 -0
  126. data/tracks/coldfusion/exercises/luhn/TestRunner.cfc +103 -0
  127. data/tracks/coldfusion/exercises/luhn/box.json +8 -0
  128. data/tracks/coldfusion/exercises/luhn/index.cfm +37 -0
  129. data/tracks/coldfusion/exercises/nth-prime/.meta/HINTS.md +0 -0
  130. data/tracks/coldfusion/exercises/nth-prime/NthPrime.cfc +13 -0
  131. data/tracks/coldfusion/exercises/nth-prime/NthPrimeTest.cfc +35 -0
  132. data/tracks/coldfusion/exercises/nth-prime/Solution.cfc +33 -0
  133. data/tracks/coldfusion/exercises/nth-prime/SolutionTest.cfc +7 -0
  134. data/tracks/coldfusion/exercises/nth-prime/TestRunner.cfc +103 -0
  135. data/tracks/coldfusion/exercises/nth-prime/box.json +8 -0
  136. data/tracks/coldfusion/exercises/nth-prime/index.cfm +37 -0
  137. data/tracks/coldfusion/exercises/pangram/.meta/HINTS.md +0 -0
  138. data/tracks/coldfusion/exercises/pangram/Pangram.cfc +13 -0
  139. data/tracks/coldfusion/exercises/pangram/PangramTest.cfc +55 -0
  140. data/tracks/coldfusion/exercises/pangram/Solution.cfc +21 -0
  141. data/tracks/coldfusion/exercises/pangram/SolutionTest.cfc +7 -0
  142. data/tracks/coldfusion/exercises/pangram/TestRunner.cfc +103 -0
  143. data/tracks/coldfusion/exercises/pangram/box.json +8 -0
  144. data/tracks/coldfusion/exercises/pangram/index.cfm +37 -0
  145. data/tracks/coldfusion/exercises/pig-latin/.meta/HINTS.md +0 -0
  146. data/tracks/coldfusion/exercises/pig-latin/PigLatin.cfc +13 -0
  147. data/tracks/coldfusion/exercises/pig-latin/PigLatinTest.cfc +115 -0
  148. data/tracks/coldfusion/exercises/pig-latin/Solution.cfc +30 -0
  149. data/tracks/coldfusion/exercises/pig-latin/SolutionTest.cfc +7 -0
  150. data/tracks/coldfusion/exercises/pig-latin/TestRunner.cfc +103 -0
  151. data/tracks/coldfusion/exercises/pig-latin/box.json +8 -0
  152. data/tracks/coldfusion/exercises/pig-latin/index.cfm +37 -0
  153. data/tracks/coldfusion/exercises/raindrops/.meta/HINTS.md +0 -0
  154. data/tracks/coldfusion/exercises/raindrops/Raindrops.cfc +13 -0
  155. data/tracks/coldfusion/exercises/raindrops/RaindropsTest.cfc +87 -0
  156. data/tracks/coldfusion/exercises/raindrops/Solution.cfc +33 -0
  157. data/tracks/coldfusion/exercises/raindrops/SolutionTest.cfc +7 -0
  158. data/tracks/coldfusion/exercises/raindrops/TestRunner.cfc +103 -0
  159. data/tracks/coldfusion/exercises/raindrops/box.json +8 -0
  160. data/tracks/coldfusion/exercises/raindrops/index.cfm +37 -0
  161. data/tracks/coldfusion/exercises/rna-transcription/.meta/HINTS.md +0 -0
  162. data/tracks/coldfusion/exercises/rna-transcription/RnaTranscription.cfc +13 -0
  163. data/tracks/coldfusion/exercises/rna-transcription/RnaTranscriptionTest.cfc +47 -0
  164. data/tracks/coldfusion/exercises/rna-transcription/Solution.cfc +35 -0
  165. data/tracks/coldfusion/exercises/rna-transcription/SolutionTest.cfc +7 -0
  166. data/tracks/coldfusion/exercises/rna-transcription/TestRunner.cfc +103 -0
  167. data/tracks/coldfusion/exercises/rna-transcription/box.json +8 -0
  168. data/tracks/coldfusion/exercises/rna-transcription/index.cfm +37 -0
  169. data/tracks/coldfusion/exercises/saddle-points/.meta/HINTS.md +0 -0
  170. data/tracks/coldfusion/exercises/saddle-points/SaddlePoints.cfc +13 -0
  171. data/tracks/coldfusion/exercises/saddle-points/SaddlePointsTest.cfc +35 -0
  172. data/tracks/coldfusion/exercises/saddle-points/Solution.cfc +59 -0
  173. data/tracks/coldfusion/exercises/saddle-points/SolutionTest.cfc +7 -0
  174. data/tracks/coldfusion/exercises/saddle-points/TestRunner.cfc +103 -0
  175. data/tracks/coldfusion/exercises/saddle-points/box.json +8 -0
  176. data/tracks/coldfusion/exercises/saddle-points/index.cfm +37 -0
  177. data/tracks/coldfusion/exercises/scrabble-score/.meta/HINTS.md +0 -0
  178. data/tracks/coldfusion/exercises/scrabble-score/ScrabbleScore.cfc +13 -0
  179. data/tracks/coldfusion/exercises/scrabble-score/ScrabbleScoreTest.cfc +59 -0
  180. data/tracks/coldfusion/exercises/scrabble-score/Solution.cfc +50 -0
  181. data/tracks/coldfusion/exercises/scrabble-score/SolutionTest.cfc +7 -0
  182. data/tracks/coldfusion/exercises/scrabble-score/TestRunner.cfc +103 -0
  183. data/tracks/coldfusion/exercises/scrabble-score/box.json +8 -0
  184. data/tracks/coldfusion/exercises/scrabble-score/index.cfm +37 -0
  185. data/tracks/coldfusion/exercises/secret-handshake/.meta/HINTS.md +0 -0
  186. data/tracks/coldfusion/exercises/secret-handshake/SecretHandshake.cfc +13 -0
  187. data/tracks/coldfusion/exercises/secret-handshake/SecretHandshakeTest.cfc +63 -0
  188. data/tracks/coldfusion/exercises/secret-handshake/Solution.cfc +31 -0
  189. data/tracks/coldfusion/exercises/secret-handshake/SolutionTest.cfc +7 -0
  190. data/tracks/coldfusion/exercises/secret-handshake/TestRunner.cfc +103 -0
  191. data/tracks/coldfusion/exercises/secret-handshake/box.json +8 -0
  192. data/tracks/coldfusion/exercises/secret-handshake/index.cfm +37 -0
  193. data/tracks/coldfusion/exercises/space-age/.meta/HINTS.md +0 -0
  194. data/tracks/coldfusion/exercises/space-age/Solution.cfc +28 -0
  195. data/tracks/coldfusion/exercises/space-age/SolutionTest.cfc +7 -0
  196. data/tracks/coldfusion/exercises/space-age/SpaceAge.cfc +13 -0
  197. data/tracks/coldfusion/exercises/space-age/SpaceAgeTest.cfc +47 -0
  198. data/tracks/coldfusion/exercises/space-age/TestRunner.cfc +103 -0
  199. data/tracks/coldfusion/exercises/space-age/box.json +8 -0
  200. data/tracks/coldfusion/exercises/space-age/index.cfm +37 -0
  201. data/tracks/coldfusion/exercises/sum-of-multiples/.meta/HINTS.md +0 -0
  202. data/tracks/coldfusion/exercises/sum-of-multiples/Solution.cfc +27 -0
  203. data/tracks/coldfusion/exercises/sum-of-multiples/SolutionTest.cfc +7 -0
  204. data/tracks/coldfusion/exercises/sum-of-multiples/SumOfMultiples.cfc +13 -0
  205. data/tracks/coldfusion/exercises/sum-of-multiples/SumOfMultiplesTest.cfc +63 -0
  206. data/tracks/coldfusion/exercises/sum-of-multiples/TestRunner.cfc +103 -0
  207. data/tracks/coldfusion/exercises/sum-of-multiples/box.json +8 -0
  208. data/tracks/coldfusion/exercises/sum-of-multiples/index.cfm +37 -0
  209. data/tracks/coldfusion/exercises/triangle/.meta/HINTS.md +0 -0
  210. data/tracks/coldfusion/exercises/triangle/Solution.cfc +53 -0
  211. data/tracks/coldfusion/exercises/triangle/SolutionTest.cfc +7 -0
  212. data/tracks/coldfusion/exercises/triangle/TestRunner.cfc +103 -0
  213. data/tracks/coldfusion/exercises/triangle/Triangle.cfc +18 -0
  214. data/tracks/coldfusion/exercises/triangle/TriangleTest.cfc +95 -0
  215. data/tracks/coldfusion/exercises/triangle/box.json +8 -0
  216. data/tracks/coldfusion/exercises/triangle/index.cfm +37 -0
  217. data/tracks/coldfusion/tasks/GenerateTests.cfc +179 -0
  218. data/tracks/coldfusion/tasks/ScaffoldExercise.cfc +85 -0
  219. data/tracks/coldfusion/tasks/TestAllSolutions.cfc +24 -0
  220. data/tracks/coldfusion/tasks/exercise_template/.meta/HINTS.md +0 -0
  221. data/tracks/coldfusion/tasks/exercise_template/@@name@@.cfc +13 -0
  222. data/tracks/coldfusion/tasks/exercise_template/@@name@@Test.cfc +15 -0
  223. data/tracks/coldfusion/tasks/exercise_template/Solution.cfc +6 -0
  224. data/tracks/coldfusion/tasks/exercise_template/SolutionTest.cfc +7 -0
  225. data/tracks/coldfusion/tasks/exercise_template/TestRunner.cfc +103 -0
  226. data/tracks/coldfusion/tasks/exercise_template/box.json +8 -0
  227. data/tracks/coldfusion/tasks/exercise_template/index.cfm +37 -0
  228. data/tracks/common-lisp/config.json +12 -0
  229. data/tracks/common-lisp/exercises/collatz-conjecture/README.md +84 -0
  230. data/tracks/common-lisp/exercises/collatz-conjecture/collatz-conjecture-test.lisp +31 -0
  231. data/tracks/common-lisp/exercises/collatz-conjecture/collatz-conjecture.lisp +7 -0
  232. data/tracks/common-lisp/exercises/collatz-conjecture/example.lisp +14 -0
  233. data/tracks/csharp/exercises/clock/Clock.cs +20 -4
  234. data/tracks/csharp/exercises/clock/ClockTest.cs +290 -55
  235. data/tracks/csharp/exercises/clock/Example.cs +11 -8
  236. data/tracks/csharp/generators/Exercises/Clock.cs +75 -0
  237. data/tracks/csharp/generators/Output/FormattingExtensions.cs +0 -1
  238. data/tracks/csharp/generators/Program.cs +2 -1
  239. data/tracks/haskell/config.json +10 -0
  240. data/tracks/haskell/exercises/collatz-conjecture/README.md +87 -0
  241. data/tracks/haskell/exercises/collatz-conjecture/examples/success-standard/package.yaml +16 -0
  242. data/tracks/haskell/exercises/collatz-conjecture/examples/success-standard/src/CollatzConjecture.hs +9 -0
  243. data/tracks/haskell/exercises/collatz-conjecture/package.yaml +20 -0
  244. data/tracks/haskell/exercises/collatz-conjecture/src/CollatzConjecture.hs +4 -0
  245. data/tracks/haskell/exercises/collatz-conjecture/stack.yaml +1 -0
  246. data/tracks/haskell/exercises/collatz-conjecture/test/Tests.hs +52 -0
  247. data/tracks/idris/docs/SNIPPET.txt +10 -0
  248. data/tracks/rust/README.md +83 -2
  249. data/tracks/rust/config.json +24 -0
  250. data/tracks/rust/exercises/perfect-numbers/.gitignore +7 -0
  251. data/tracks/rust/exercises/perfect-numbers/Cargo.toml +5 -0
  252. data/tracks/rust/exercises/perfect-numbers/README.md +56 -0
  253. data/tracks/rust/exercises/perfect-numbers/example.rs +20 -0
  254. data/tracks/rust/exercises/perfect-numbers/src/lib.rs +0 -0
  255. data/tracks/rust/exercises/perfect-numbers/tests/perfect-numbers.rs +33 -0
  256. data/tracks/rust/exercises/poker/.gitignore +7 -0
  257. data/tracks/rust/exercises/poker/.meta/hints.md +8 -0
  258. data/tracks/rust/exercises/poker/Cargo-example.toml +8 -0
  259. data/tracks/rust/exercises/poker/Cargo.toml +6 -0
  260. data/tracks/rust/exercises/poker/README.md +54 -0
  261. data/tracks/rust/exercises/poker/example.rs +341 -0
  262. data/tracks/rust/exercises/poker/src/lib.rs +7 -0
  263. data/tracks/rust/exercises/poker/tests/poker.rs +298 -0
  264. metadata +242 -5
  265. data/tracks/coldfusion/exercises/leap/example.cfc +0 -11
  266. data/tracks/coldfusion/exercises/leap/leap.cfc +0 -5
  267. data/tracks/coldfusion/exercises/leap/leap_tests.cfc +0 -35
@@ -0,0 +1,8 @@
1
+ {
2
+ "dependencies":{
3
+ "testbox":"^2.5.0+107"
4
+ },
5
+ "installPaths":{
6
+ "testbox":"testbox"
7
+ }
8
+ }
@@ -0,0 +1,37 @@
1
+ <!---
2
+
3
+ This file will only be used if you want to start up a web server in this directory. You can do so by running:
4
+
5
+ $> box
6
+ CommandBox> install
7
+ CommandBox> server start
8
+
9
+ However, this is not necessary unless you really just want to use the HTML reporters on TestBox.
10
+ Ideally, you'll skip the need for this file entirely and just run the tests directly frm the CLI like this:
11
+
12
+ CommandBox> task run TestRunner
13
+
14
+ --->
15
+ <cfsetting showDebugOutput="false">
16
+ <cfparam name="url.reporter" default="simple">
17
+ <cfscript>
18
+ // get a list of all CFCs in this folder whose name looks like "XXXTest.cfc"
19
+ // And turn it into compnent path relative to the web root
20
+ url.bundles = directoryList(
21
+ path=expandPath( '/' ),
22
+ filter='*Test.cfc' )
23
+ .map( function( path ) {
24
+ return path
25
+ .replaceNoCase( expandPath( '/' ), '' )
26
+ .left( -4 )
27
+ } )
28
+ .toList();
29
+ </cfscript>
30
+
31
+ <!--- Ensure TestBox --->
32
+ <cfif fileExists( "/testbox/system/runners/HTMLRunner.cfm" )>
33
+ <!--- Include the TestBox HTML Runner --->
34
+ <cfinclude template="/testbox/system/runners/HTMLRunner.cfm">
35
+ <cfelse>
36
+ Oops, you don't have TestBox installed yet! Please run <b>box install</b> from the root of your excercise folder and refresh this page.
37
+ </cfif>
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Here is an example solution for the Triangle exercise
3
+ */
4
+ component {
5
+
6
+ function equilateral( array sides ) {
7
+ // Is triangle and all 3 sides the same
8
+ return isTriangle( sides ) && countSides( sides ) == 1;
9
+ }
10
+
11
+ function isosceles( array sides ) {
12
+ // Is triangle and at least two sides the same
13
+ return isTriangle( sides ) && countSides( sides ) < 3;
14
+ }
15
+
16
+ function scalene( array sides ) {
17
+ // Is triangle and all 3 sides different
18
+ return isTriangle( sides ) && countSides( sides ) == 3;
19
+ }
20
+
21
+ private function countSides( array sides ) {
22
+ var distinctSides = {};
23
+
24
+ // Keep track of distinct sides
25
+ sides.each( function( side ){
26
+ distinctSides[ side ] = true;
27
+ } );
28
+
29
+ // Count 'em up
30
+ return distinctSides.count();
31
+ }
32
+
33
+ private function isTriangle( array sides ) {
34
+ // Any sides of 0 are invalid
35
+ if( sides[ 1 ] == 0 || sides[ 2 ] == 0 || sides[ 3 ] == 0 ) {
36
+ return false;
37
+ }
38
+ // sides 1 and 2 must be at least the size of side 3
39
+ if( sides[ 1 ] + sides[ 2 ] < sides[ 3 ] ) {
40
+ return false;
41
+ }
42
+ // sides 1 and 3 must be at least the size of side 2
43
+ if( sides[ 1 ] + sides[ 3 ] < sides[ 2 ] ) {
44
+ return false;
45
+ }
46
+ // sides 2 and 3 must be at least the size of side 1
47
+ if( sides[ 2 ] + sides[ 3 ] < sides[ 1 ] ) {
48
+ return false;
49
+ }
50
+ // If we made it here, it's a triangle!
51
+ return true;
52
+ }
53
+ }
@@ -0,0 +1,7 @@
1
+ component extends="TriangleTest" {
2
+
3
+ function beforeAll(){
4
+ SUT = createObject( 'Solution' );
5
+ }
6
+
7
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * I am a CommandBox task runner which you can use to test your implementation of this exercise against the
3
+ * provided test suite. To use me, open the CommandBox CLI and run this:
4
+ *
5
+ * CommandBox> task run TestRunner
6
+ *
7
+ * To start up a test watcher that will automatically rerun the test suite every time you save a file change, run this:
8
+ *
9
+ * CommandBox> task run TestRunner --watcher
10
+ *
11
+ */
12
+ component {
13
+
14
+ /**
15
+ * @solution Runs the tests against the solution
16
+ * @watcher Start up a file watch that re-runs the tests on file changes. Use Ctrl-C to stop
17
+ */
18
+ function run( boolean solution=false, boolean watcher=false ) {
19
+
20
+ ensureTestBox();
21
+
22
+ if( watcher ) {
23
+
24
+ // Tabula rasa
25
+ command( 'cls' ).run();
26
+
27
+ // Start watcher
28
+ watch()
29
+ .paths( '*.cfc' )
30
+ .inDirectory( getCWD() )
31
+ .withDelay( 500 )
32
+ .onChange( function() {
33
+
34
+ // Clear the screen
35
+ command( 'cls' )
36
+ .run();
37
+
38
+ // This is neccessary so changes to tests get picked up right away.
39
+ pagePoolClear();
40
+
41
+ runTests( solution );
42
+
43
+ } )
44
+ .start();
45
+
46
+ } else {
47
+ runTests( solution );
48
+ }
49
+
50
+ }
51
+
52
+ /**
53
+ * Make sure the TestBox framework is installed
54
+ */
55
+ private function ensureTestBox() {
56
+ var excerciseRoot = getCWD();
57
+ var testBoxRoot = excerciseRoot & '/testbox';
58
+
59
+ if( !directoryExists( testBoxRoot ) ) {
60
+
61
+ print.boldYellowLine( 'Installing some missing dependencies for you!' ).toConsole();
62
+ command( 'install' )
63
+ .inWorkingDirectory( excerciseRoot )
64
+ .run();
65
+ }
66
+
67
+ // Bootstrap TestBox framework
68
+ filesystemUtil.createMapping( '/testbox', testBoxRoot );
69
+ }
70
+
71
+ /**
72
+ * Invoke TestBox to run the test suite
73
+ */
74
+ private function runTests( boolean solution=false ) {
75
+
76
+ // Create TestBox and run the tests
77
+ testData = new testbox.system.TestBox()
78
+ .runRaw( directory = {
79
+ // Find all CFCs...
80
+ mapping = filesystemUtil.makePathRelative( getCWD() ),
81
+ // ... in this directory ...
82
+ recurse = false,
83
+ // ... whose name ends in "test"
84
+ filter = function( path ) {
85
+ return path.reFind( ( solution ? 'Solution' : '' ) & 'Test.cfc$' );
86
+ }
87
+ } )
88
+ .getMemento();
89
+
90
+ // Print out the results with ANSI formatting for the CLI
91
+ getInstance( 'CLIRenderer@testbox-commands' )
92
+ .render( print, testData, true );
93
+
94
+ print.toConsole();
95
+
96
+ // Set proper exit code
97
+ if( testData.totalFail || testData.totalError ) {
98
+ setExitCode( 1 );
99
+ }
100
+ }
101
+
102
+ }
103
+
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Your implmentation of the Triangle exercise
3
+ */
4
+ component {
5
+
6
+ function equilateral( array sides ) {
7
+ // Implement me here
8
+ }
9
+
10
+ function isosceles( array sides ) {
11
+ // Implement me here
12
+ }
13
+
14
+ function scalene( array sides ) {
15
+ // Implement me here
16
+ }
17
+
18
+ }
@@ -0,0 +1,95 @@
1
+ component extends="testbox.system.BaseSpec" {
2
+
3
+ function beforeAll(){
4
+ SUT = createObject( 'Triangle' );
5
+ }
6
+
7
+ function run(){
8
+
9
+ describe( "My Triangle class", function(){
10
+
11
+ describe( 'returns true if the triangle is equilateral', function(){
12
+
13
+ it( 'true if all sides are equal', function(){
14
+ expect( SUT.equilateral( sides=[2, 2, 2] ) ).toBeTrue();
15
+ });
16
+
17
+ it( 'false if any side is unequal', function(){
18
+ expect( SUT.equilateral( sides=[2, 3, 2] ) ).toBeFalse();
19
+ });
20
+
21
+ it( 'false if no sides are equal', function(){
22
+ expect( SUT.equilateral( sides=[5, 4, 6] ) ).toBeFalse();
23
+ });
24
+
25
+ it( 'All zero sides are illegal, so the triangle is not equilateral', function(){
26
+ expect( SUT.equilateral( sides=[0, 0, 0] ) ).toBeFalse();
27
+ });
28
+
29
+ it( 'sides may be floats', function(){
30
+ expect( SUT.equilateral( sides=[0.5, 0.5, 0.5] ) ).toBeTrue();
31
+ });
32
+
33
+ });
34
+
35
+ describe( 'returns true if the triangle is isosceles', function(){
36
+
37
+ it( 'true if last two sides are equal', function(){
38
+ expect( SUT.isosceles( sides=[3, 4, 4] ) ).toBeTrue();
39
+ });
40
+
41
+ it( 'true if first two sides are equal', function(){
42
+ expect( SUT.isosceles( sides=[4, 4, 3] ) ).toBeTrue();
43
+ });
44
+
45
+ it( 'true if first and last sides are equal', function(){
46
+ expect( SUT.isosceles( sides=[4, 3, 4] ) ).toBeTrue();
47
+ });
48
+
49
+ it( 'equilateral triangles are also isosceles', function(){
50
+ expect( SUT.isosceles( sides=[4, 4, 4] ) ).toBeTrue();
51
+ });
52
+
53
+ it( 'false if no sides are equal', function(){
54
+ expect( SUT.isosceles( sides=[2, 3, 4] ) ).toBeFalse();
55
+ });
56
+
57
+ it( 'Sides that violate triangle inequality are not isosceles, even if two are equal', function(){
58
+ expect( SUT.isosceles( sides=[1, 1, 3] ) ).toBeFalse();
59
+ });
60
+
61
+ it( 'sides may be floats', function(){
62
+ expect( SUT.isosceles( sides=[0.5, 0.4, 0.5] ) ).toBeTrue();
63
+ });
64
+
65
+ });
66
+
67
+ describe( 'returns true if the triangle is scalene', function(){
68
+
69
+ it( 'true if no sides are equal', function(){
70
+ expect( SUT.scalene( sides=[5, 4, 6] ) ).toBeTrue();
71
+ });
72
+
73
+ it( 'false if all sides are equal', function(){
74
+ expect( SUT.scalene( sides=[4, 4, 4] ) ).toBeFalse();
75
+ });
76
+
77
+ it( 'false if two sides are equal', function(){
78
+ expect( SUT.scalene( sides=[4, 4, 3] ) ).toBeFalse();
79
+ });
80
+
81
+ it( 'Sides that violate triangle inequality are not scalene, even if they are all different', function(){
82
+ expect( SUT.scalene( sides=[7, 3, 2] ) ).toBeFalse();
83
+ });
84
+
85
+ it( 'sides may be floats', function(){
86
+ expect( SUT.scalene( sides=[0.5, 0.4, 0.6] ) ).toBeTrue();
87
+ });
88
+
89
+ });
90
+
91
+ });
92
+
93
+ }
94
+
95
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "dependencies":{
3
+ "testbox":"^2.5.0+107"
4
+ },
5
+ "installPaths":{
6
+ "testbox":"testbox"
7
+ }
8
+ }
@@ -0,0 +1,37 @@
1
+ <!---
2
+
3
+ This file will only be used if you want to start up a web server in this directory. You can do so by running:
4
+
5
+ $> box
6
+ CommandBox> install
7
+ CommandBox> server start
8
+
9
+ However, this is not necessary unless you really just want to use the HTML reporters on TestBox.
10
+ Ideally, you'll skip the need for this file entirely and just run the tests directly frm the CLI like this:
11
+
12
+ CommandBox> task run TestRunner
13
+
14
+ --->
15
+ <cfsetting showDebugOutput="false">
16
+ <cfparam name="url.reporter" default="simple">
17
+ <cfscript>
18
+ // get a list of all CFCs in this folder whose name looks like "XXXTest.cfc"
19
+ // And turn it into compnent path relative to the web root
20
+ url.bundles = directoryList(
21
+ path=expandPath( '/' ),
22
+ filter='*Test.cfc' )
23
+ .map( function( path ) {
24
+ return path
25
+ .replaceNoCase( expandPath( '/' ), '' )
26
+ .left( -4 )
27
+ } )
28
+ .toList();
29
+ </cfscript>
30
+
31
+ <!--- Ensure TestBox --->
32
+ <cfif fileExists( "/testbox/system/runners/HTMLRunner.cfm" )>
33
+ <!--- Include the TestBox HTML Runner --->
34
+ <cfinclude template="/testbox/system/runners/HTMLRunner.cfm">
35
+ <cfelse>
36
+ Oops, you don't have TestBox installed yet! Please run <b>box install</b> from the root of your excercise folder and refresh this page.
37
+ </cfif>
@@ -0,0 +1,179 @@
1
+ /**
2
+ * I scaffold a new exercise from the template.
3
+ */
4
+ component {
5
+
6
+ function run(
7
+ slug,
8
+ boolean all=false
9
+ ) {
10
+ var repoRootPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../' );
11
+ var problemSpecsPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../../problem-specifications' );
12
+
13
+ if( !directoryExists( problemSpecsPath ) ){
14
+ error( 'Cannot find [problem-specifications] repo. It needs to be git cloned to [#problemSpecsPath#]' );
15
+ }
16
+
17
+ if( all ) {
18
+
19
+ // Get an array of all the excercise names
20
+ var exercises = directoryList( expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../exercises' ) )
21
+ .map( function( path ) {
22
+ return path.listLast( '/\' );
23
+ } );
24
+
25
+ } else {
26
+
27
+ // Acquire slug
28
+ if( isNull( arguments.slug ) ) {
29
+ arguments.slug = ask( 'Exercise slug as defined by Excercism. Ex: "hello-world": ' );
30
+ }
31
+ var exercises = [ slug ];
32
+
33
+ }
34
+
35
+ exercises.each( function( slug ) {
36
+
37
+ try {
38
+
39
+ // Slug of hello-world defaults to name of HelloWorld
40
+ var exerciseName = arguments.slug
41
+ .listToArray( '-' )
42
+ .map( function( i ){
43
+ return i.left( 1 ).uCase() & i.right( -1 ).lCase();
44
+ } )
45
+ .toList( '' );
46
+
47
+ var exercisePath = problemSpecsPath & '/exercises/' & slug;
48
+ if( !directoryExists( exercisePath ) ){
49
+ error( 'Cannot find exercise [#slug#] in problem-specifications repo. Tests not generated.' );
50
+ }
51
+
52
+ var canonicalDataPath = exercisePath & '/canonical-data.json';
53
+ if( !fileExists( canonicalDataPath ) ){
54
+ error( 'Cannot find [canonical-data.json] for this slug. No tests will be generated' );
55
+ }
56
+
57
+ var canonicalData = deserializeJSON( fileRead( canonicalDataPath ) );
58
+ var testCases = generateCases( canonicalData.cases );
59
+
60
+ var testStub = fileRead( repoRootPath & '/tasks/exercise_template/@@name@@Test.cfc' );
61
+ testStub = testStub.replace( '@@name@@', exerciseName, 'all' );
62
+ testStub = testStub.replace( '@@testCases@@', testCases, 'all' );
63
+ var targetExercisePath = repoRootPath & 'exercises/' & slug;
64
+ var newTestPath = targetExercisePath & '/' & exerciseName & 'Test.cfc';
65
+
66
+ if( !directoryExists( targetExercisePath ) ) {
67
+ error( 'Target exercise does not exist! [#targetExercisePath#]' );
68
+ }
69
+
70
+ fileWrite( newTestPath, testStub );
71
+
72
+ print.greenLine( 'Test generated!' )
73
+ .indentedYellowLine( newTestPath )
74
+ .toConsole();
75
+ } catch( 'commandException' var e ) {
76
+ print.boldRedLine( e.message )
77
+ .line();
78
+ }
79
+
80
+ } ); // End exercises.each()
81
+ }
82
+
83
+ private function generateCases( cases, level=1 ) {
84
+ var CRLF = chr( 13 ) & chr( 10 );
85
+ var testCases = ''
86
+
87
+ cases.each( function( case ) {
88
+
89
+ // Nested spec
90
+ if( case.keyExists( 'cases' ) ) {
91
+
92
+ testCases &= "#CRLF##repeatString( chr( 9 ), level )# describe( #generateDescription( case.description )#, function(){
93
+ #generateCases( case.cases, level+1 )#
94
+ #repeatString( chr( 9 ), level )# });#CRLF#";
95
+
96
+ } else {
97
+ case.expected = case.expected ?: '__NULL__';
98
+ // Don't adjust whitespace
99
+ testCases &= "#CRLF##repeatString( chr( 9 ), level )# it( #generateDescription( case.description )#, function(){#CRLF#";
100
+ // Special check for when error should be tested
101
+ if( isStruct( case.expected ) && case.expected.keyExists( 'error' ) ) {
102
+ testCases &= "#repeatString( chr( 9 ), level )# expect( function(){ SUT.#case.property#(#generateInput( case )#); } ).#generateExpectation( case.expected )#;#CRLF#";
103
+ // "normal" expectation
104
+ } else {
105
+ testCases &= "#repeatString( chr( 9 ), level )# expect( SUT.#case.property#(#generateInput( case )#) ).#generateExpectation( case.expected )#;#CRLF#";
106
+ }
107
+ testCases &= "#repeatString( chr( 9 ), level )# });#CRLF#";
108
+ }
109
+
110
+ } );
111
+
112
+ return testCases;
113
+ }
114
+
115
+ private function generateDescription( description ) {
116
+ return escapeString( description );
117
+ }
118
+
119
+ private function generateInput( case ) {
120
+ var thisInput = '';
121
+ for( var key in case ) {
122
+ if( !listFindNoCase( 'description,property,expected,cases,comments', key ) && !isNull( case[ key ] ) ) {
123
+ thisInput = thisInput.listAppend( "#key#=#escapeString( case[ key ] )#" );
124
+ }
125
+ }
126
+ if( thisInput.len() ) {
127
+ return ' ' & thisInput.listChangeDelims( ', ', ',' ) & ' ';
128
+ } else {
129
+ return thisInput;
130
+ }
131
+ }
132
+
133
+ private function generateExpectation( expected ) {
134
+ if( isSimpleValue( expected ) && compareNoCase( expected, 'true' ) == 0 ) {
135
+ return 'toBeTrue()';
136
+ } else if( isSimpleValue( expected ) && compareNoCase( expected, 'false' ) == 0 ) {
137
+ return 'toBeFalse()';
138
+ } else if( isSimpleValue( expected) && expected == '__NULL__' ) {
139
+ return 'toBeNull()';
140
+ } else if( isStruct( expected ) && expected.keyExists( 'error' ) ) {
141
+ return 'toThrow( message=#escapeString( expected.error )# )';
142
+ } else {
143
+ return "toBe( #escapeString( expected )# )";
144
+ }
145
+
146
+ }
147
+
148
+ private function escapeString( myString ) {
149
+ if( isSimpleValue( myString ) ) {
150
+ myString = replace( myString, "'", "''", "all" );
151
+ myString = replace( myString, '##', '####', 'all' );
152
+ myString = replace( myString, chr( 13 ), '##chr( 13 )##', 'all' );
153
+ myString = replace( myString, chr( 10 ), '##chr( 10 )##', 'all' );
154
+ return "'" & myString & "'";
155
+ } else {
156
+ return convertJSONEscapesToCFML( serializeJSON( myString ) );
157
+ }
158
+ }
159
+
160
+
161
+ // A complex value serialized as JSON differs from CFML struct literals in that
162
+ // double quotes are \" instead of "". Any escaped double quotes must be converted
163
+ // to the CFML version to work as an object literal.
164
+ private function convertJSONEscapesToCFML( required string arg ) {
165
+ arguments.arg = replaceNoCase( arguments.arg, '\\', '__double_backslash_', 'all' );
166
+ arguments.arg = replaceNoCase( arguments.arg, '\/', '/', 'all' );
167
+ arguments.arg = replaceNoCase( arguments.arg, '\"', '""', 'all' );
168
+ arguments.arg = replaceNoCase( arguments.arg, '\t', ' ', 'all' );
169
+ arguments.arg = replaceNoCase( arguments.arg, '\n', chr(13)&chr(10), 'all' );
170
+ arguments.arg = replaceNoCase( arguments.arg, '\r', chr(13), 'all' );
171
+ arguments.arg = replaceNoCase( arguments.arg, '\f', chr(12), 'all' );
172
+ arguments.arg = replaceNoCase( arguments.arg, '\b', chr(8), 'all' );
173
+ // This doesn't work-- I'd need to do it in a loop and replace each one individually. Meh...
174
+ // arguments.arg = reReplaceNoCase( arguments.arg, '\\u([0-9a-f]{4})', chr( inputBaseN( '\1', 16 ) ), 'all' );
175
+ arguments.arg = replaceNoCase( arguments.arg, '__double_backslash_', '\', 'all' );
176
+ return arguments.arg;
177
+ }
178
+
179
+ }