trackler 2.2.1.40 → 2.2.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/dot-dsl/metadata.yml +1 -0
- data/problem-specifications/exercises/etl/metadata.yml +1 -0
- data/problem-specifications/exercises/isogram/canonical-data.json +3 -3
- data/problem-specifications/exercises/ocr-numbers/metadata.yml +1 -0
- data/problem-specifications/exercises/pascals-triangle/metadata.yml +1 -0
- data/problem-specifications/exercises/pov/metadata.yml +1 -0
- data/problem-specifications/exercises/rna-transcription/metadata.yml +1 -0
- data/problem-specifications/exercises/sgf-parsing/metadata.yml +1 -0
- data/tracks/c/exercises/all-your-base/src/example.c +14 -14
- data/tracks/c/exercises/all-your-base/src/example.h +2 -2
- data/tracks/ceylon/exercises/hamming/source/hamming/HammingTest.ceylon +1 -1
- data/tracks/ceylon/exercises/rna-transcription/source/rnatranscription/{RNAtest.ceylon → RNATest.ceylon} +0 -0
- data/tracks/cfml/.git +1 -0
- data/tracks/cfml/.gitignore +5 -0
- data/tracks/cfml/.travis.yml +18 -0
- data/tracks/cfml/CONTRIBUTING.md +10 -0
- data/tracks/cfml/LICENSE +21 -0
- data/tracks/cfml/README.md +92 -0
- data/tracks/cfml/bin/fetch-configlet +32 -0
- data/tracks/cfml/config/exercise_readme.go.tmpl +16 -0
- data/tracks/cfml/config/maintainers.json +13 -0
- data/tracks/cfml/config.json +223 -0
- data/tracks/cfml/docs/ABOUT.md +10 -0
- data/tracks/cfml/docs/EXERCISE_README_INSERT.md +15 -0
- data/tracks/cfml/docs/INSTALLATION.md +35 -0
- data/tracks/cfml/docs/LEARNING.md +37 -0
- data/tracks/cfml/docs/RESOURCES.md +29 -0
- data/tracks/cfml/docs/SNIPPET.txt +8 -0
- data/tracks/cfml/docs/TESTS.md +13 -0
- data/tracks/cfml/exercises/acronym/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/acronym/Acronym.cfc +13 -0
- data/tracks/cfml/exercises/acronym/AcronymTest.cfc +43 -0
- data/tracks/cfml/exercises/acronym/Solution.cfc +22 -0
- data/tracks/cfml/exercises/acronym/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/acronym/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/acronym/box.json +8 -0
- data/tracks/cfml/exercises/acronym/index.cfm +37 -0
- data/tracks/cfml/exercises/atbash-cipher/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/atbash-cipher/AtbashCipher.cfc +14 -0
- data/tracks/cfml/exercises/atbash-cipher/AtbashCipherTest.cfc +71 -0
- data/tracks/cfml/exercises/atbash-cipher/Solution.cfc +56 -0
- data/tracks/cfml/exercises/atbash-cipher/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/atbash-cipher/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/atbash-cipher/box.json +8 -0
- data/tracks/cfml/exercises/atbash-cipher/index.cfm +37 -0
- data/tracks/cfml/exercises/bob/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/bob/Bob.cfc +13 -0
- data/tracks/cfml/exercises/bob/BobTest.cfc +115 -0
- data/tracks/cfml/exercises/bob/Solution.cfc +27 -0
- data/tracks/cfml/exercises/bob/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/bob/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/bob/box.json +8 -0
- data/tracks/cfml/exercises/bob/index.cfm +37 -0
- data/tracks/cfml/exercises/diamond/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/diamond/Diamond.cfc +13 -0
- data/tracks/cfml/exercises/diamond/DiamondTest.cfc +35 -0
- data/tracks/cfml/exercises/diamond/Solution.cfc +35 -0
- data/tracks/cfml/exercises/diamond/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/diamond/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/diamond/box.json +8 -0
- data/tracks/cfml/exercises/diamond/index.cfm +37 -0
- data/tracks/cfml/exercises/difference-of-squares/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/difference-of-squares/DifferenceOfSquares.cfc +18 -0
- data/tracks/cfml/exercises/difference-of-squares/DifferenceOfSquaresTest.cfc +63 -0
- data/tracks/cfml/exercises/difference-of-squares/Solution.cfc +28 -0
- data/tracks/cfml/exercises/difference-of-squares/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/difference-of-squares/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/difference-of-squares/box.json +8 -0
- data/tracks/cfml/exercises/difference-of-squares/index.cfm +37 -0
- data/tracks/cfml/exercises/flatten-array/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/flatten-array/FlattenArray.cfc +13 -0
- data/tracks/cfml/exercises/flatten-array/FlattenArrayTest.cfc +42 -0
- data/tracks/cfml/exercises/flatten-array/Solution.cfc +26 -0
- data/tracks/cfml/exercises/flatten-array/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/flatten-array/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/flatten-array/box.json +8 -0
- data/tracks/cfml/exercises/flatten-array/index.cfm +37 -0
- data/tracks/cfml/exercises/gigasecond/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/gigasecond/Gigasecond.cfc +13 -0
- data/tracks/cfml/exercises/gigasecond/GigasecondTest.cfc +39 -0
- data/tracks/cfml/exercises/gigasecond/Solution.cfc +16 -0
- data/tracks/cfml/exercises/gigasecond/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/gigasecond/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/gigasecond/box.json +8 -0
- data/tracks/cfml/exercises/gigasecond/index.cfm +37 -0
- data/tracks/cfml/exercises/grains/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/grains/Grains.cfc +14 -0
- data/tracks/cfml/exercises/grains/GrainsTest.cfc +63 -0
- data/tracks/cfml/exercises/grains/Solution.cfc +22 -0
- data/tracks/cfml/exercises/grains/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/grains/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/grains/box.json +8 -0
- data/tracks/cfml/exercises/grains/index.cfm +37 -0
- data/tracks/cfml/exercises/hamming/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/hamming/Hamming.cfc +13 -0
- data/tracks/cfml/exercises/hamming/HammingTest.cfc +75 -0
- data/tracks/cfml/exercises/hamming/Solution.cfc +25 -0
- data/tracks/cfml/exercises/hamming/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/hamming/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/hamming/box.json +8 -0
- data/tracks/cfml/exercises/hamming/index.cfm +37 -0
- data/tracks/cfml/exercises/hello-world/HelloWorld.cfc +13 -0
- data/tracks/cfml/exercises/hello-world/HelloWorldTest.cfc +18 -0
- data/tracks/cfml/exercises/hello-world/Solution.cfc +13 -0
- data/tracks/cfml/exercises/hello-world/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/hello-world/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/hello-world/box.json +8 -0
- data/tracks/cfml/exercises/hello-world/index.cfm +37 -0
- data/tracks/cfml/exercises/isogram/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/isogram/Isogram.cfc +13 -0
- data/tracks/cfml/exercises/isogram/IsogramTest.cfc +55 -0
- data/tracks/cfml/exercises/isogram/Solution.cfc +23 -0
- data/tracks/cfml/exercises/isogram/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/isogram/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/isogram/box.json +8 -0
- data/tracks/cfml/exercises/isogram/index.cfm +37 -0
- data/tracks/cfml/exercises/largest-series-product/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/largest-series-product/LargestSeriesProduct.cfc +13 -0
- data/tracks/cfml/exercises/largest-series-product/LargestSeriesProductTest.cfc +75 -0
- data/tracks/cfml/exercises/largest-series-product/Solution.cfc +41 -0
- data/tracks/cfml/exercises/largest-series-product/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/largest-series-product/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/largest-series-product/box.json +8 -0
- data/tracks/cfml/exercises/largest-series-product/index.cfm +37 -0
- data/tracks/cfml/exercises/leap/Leap.cfc +15 -0
- data/tracks/cfml/exercises/leap/LeapTest.cfc +39 -0
- data/tracks/cfml/exercises/leap/README.md +33 -0
- data/tracks/cfml/exercises/leap/Solution.cfc +19 -0
- data/tracks/cfml/exercises/leap/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/leap/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/leap/box.json +8 -0
- data/tracks/cfml/exercises/leap/index.cfm +37 -0
- data/tracks/cfml/exercises/luhn/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/luhn/Luhn.cfc +13 -0
- data/tracks/cfml/exercises/luhn/LuhnTest.cfc +67 -0
- data/tracks/cfml/exercises/luhn/Solution.cfc +38 -0
- data/tracks/cfml/exercises/luhn/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/luhn/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/luhn/box.json +8 -0
- data/tracks/cfml/exercises/luhn/index.cfm +37 -0
- data/tracks/cfml/exercises/nth-prime/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/nth-prime/NthPrime.cfc +13 -0
- data/tracks/cfml/exercises/nth-prime/NthPrimeTest.cfc +35 -0
- data/tracks/cfml/exercises/nth-prime/Solution.cfc +33 -0
- data/tracks/cfml/exercises/nth-prime/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/nth-prime/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/nth-prime/box.json +8 -0
- data/tracks/cfml/exercises/nth-prime/index.cfm +37 -0
- data/tracks/cfml/exercises/pangram/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/pangram/Pangram.cfc +13 -0
- data/tracks/cfml/exercises/pangram/PangramTest.cfc +55 -0
- data/tracks/cfml/exercises/pangram/Solution.cfc +21 -0
- data/tracks/cfml/exercises/pangram/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/pangram/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/pangram/box.json +8 -0
- data/tracks/cfml/exercises/pangram/index.cfm +37 -0
- data/tracks/cfml/exercises/pig-latin/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/pig-latin/PigLatin.cfc +13 -0
- data/tracks/cfml/exercises/pig-latin/PigLatinTest.cfc +115 -0
- data/tracks/cfml/exercises/pig-latin/Solution.cfc +30 -0
- data/tracks/cfml/exercises/pig-latin/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/pig-latin/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/pig-latin/box.json +8 -0
- data/tracks/cfml/exercises/pig-latin/index.cfm +37 -0
- data/tracks/cfml/exercises/raindrops/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/raindrops/Raindrops.cfc +13 -0
- data/tracks/cfml/exercises/raindrops/RaindropsTest.cfc +87 -0
- data/tracks/cfml/exercises/raindrops/Solution.cfc +33 -0
- data/tracks/cfml/exercises/raindrops/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/raindrops/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/raindrops/box.json +8 -0
- data/tracks/cfml/exercises/raindrops/index.cfm +37 -0
- data/tracks/cfml/exercises/rna-transcription/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/rna-transcription/RnaTranscription.cfc +13 -0
- data/tracks/cfml/exercises/rna-transcription/RnaTranscriptionTest.cfc +47 -0
- data/tracks/cfml/exercises/rna-transcription/Solution.cfc +35 -0
- data/tracks/cfml/exercises/rna-transcription/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/rna-transcription/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/rna-transcription/box.json +8 -0
- data/tracks/cfml/exercises/rna-transcription/index.cfm +37 -0
- data/tracks/cfml/exercises/saddle-points/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/saddle-points/SaddlePoints.cfc +13 -0
- data/tracks/cfml/exercises/saddle-points/SaddlePointsTest.cfc +35 -0
- data/tracks/cfml/exercises/saddle-points/Solution.cfc +59 -0
- data/tracks/cfml/exercises/saddle-points/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/saddle-points/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/saddle-points/box.json +8 -0
- data/tracks/cfml/exercises/saddle-points/index.cfm +37 -0
- data/tracks/cfml/exercises/scrabble-score/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/scrabble-score/ScrabbleScore.cfc +13 -0
- data/tracks/cfml/exercises/scrabble-score/ScrabbleScoreTest.cfc +59 -0
- data/tracks/cfml/exercises/scrabble-score/Solution.cfc +50 -0
- data/tracks/cfml/exercises/scrabble-score/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/scrabble-score/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/scrabble-score/box.json +8 -0
- data/tracks/cfml/exercises/scrabble-score/index.cfm +37 -0
- data/tracks/cfml/exercises/secret-handshake/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/secret-handshake/SecretHandshake.cfc +13 -0
- data/tracks/cfml/exercises/secret-handshake/SecretHandshakeTest.cfc +63 -0
- data/tracks/cfml/exercises/secret-handshake/Solution.cfc +31 -0
- data/tracks/cfml/exercises/secret-handshake/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/secret-handshake/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/secret-handshake/box.json +8 -0
- data/tracks/cfml/exercises/secret-handshake/index.cfm +37 -0
- data/tracks/cfml/exercises/space-age/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/space-age/Solution.cfc +28 -0
- data/tracks/cfml/exercises/space-age/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/space-age/SpaceAge.cfc +13 -0
- data/tracks/cfml/exercises/space-age/SpaceAgeTest.cfc +47 -0
- data/tracks/cfml/exercises/space-age/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/space-age/box.json +8 -0
- data/tracks/cfml/exercises/space-age/index.cfm +37 -0
- data/tracks/cfml/exercises/sum-of-multiples/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/sum-of-multiples/Solution.cfc +27 -0
- data/tracks/cfml/exercises/sum-of-multiples/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/sum-of-multiples/SumOfMultiples.cfc +13 -0
- data/tracks/cfml/exercises/sum-of-multiples/SumOfMultiplesTest.cfc +63 -0
- data/tracks/cfml/exercises/sum-of-multiples/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/sum-of-multiples/box.json +8 -0
- data/tracks/cfml/exercises/sum-of-multiples/index.cfm +37 -0
- data/tracks/cfml/exercises/triangle/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/triangle/Solution.cfc +53 -0
- data/tracks/cfml/exercises/triangle/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/triangle/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/triangle/Triangle.cfc +18 -0
- data/tracks/cfml/exercises/triangle/TriangleTest.cfc +95 -0
- data/tracks/cfml/exercises/triangle/box.json +8 -0
- data/tracks/cfml/exercises/triangle/index.cfm +37 -0
- data/tracks/cfml/exercises/word-count/.meta/HINTS.md +0 -0
- data/tracks/cfml/exercises/word-count/Solution.cfc +22 -0
- data/tracks/cfml/exercises/word-count/SolutionTest.cfc +7 -0
- data/tracks/cfml/exercises/word-count/TestRunner.cfc +103 -0
- data/tracks/cfml/exercises/word-count/WordCount.cfc +13 -0
- data/tracks/cfml/exercises/word-count/WordCountTest.cfc +55 -0
- data/tracks/cfml/exercises/word-count/box.json +8 -0
- data/tracks/cfml/exercises/word-count/index.cfm +37 -0
- data/tracks/cfml/img/icon.png +0 -0
- data/tracks/cfml/tasks/GenerateTests.cfc +179 -0
- data/tracks/cfml/tasks/ScaffoldExercise.cfc +85 -0
- data/tracks/cfml/tasks/TestAllSolutions.cfc +24 -0
- data/tracks/cfml/tasks/exercise_template/.meta/HINTS.md +0 -0
- data/tracks/cfml/tasks/exercise_template/@@name@@.cfc +13 -0
- data/tracks/cfml/tasks/exercise_template/@@name@@Test.cfc +15 -0
- data/tracks/cfml/tasks/exercise_template/Solution.cfc +6 -0
- data/tracks/cfml/tasks/exercise_template/SolutionTest.cfc +7 -0
- data/tracks/cfml/tasks/exercise_template/TestRunner.cfc +103 -0
- data/tracks/cfml/tasks/exercise_template/box.json +8 -0
- data/tracks/cfml/tasks/exercise_template/index.cfm +37 -0
- data/tracks/coldfusion/docs/ABOUT.md +8 -6
- data/tracks/csharp/docs/GENERATORS.md +7 -0
- data/tracks/csharp/exercises/clock/ClockTest.cs +15 -15
- data/tracks/csharp/exercises/nucleotide-count/Example.cs +10 -11
- data/tracks/csharp/exercises/nucleotide-count/NucleotideCount.cs +2 -7
- data/tracks/csharp/exercises/nucleotide-count/NucleotideCountTest.cs +37 -47
- data/tracks/csharp/exercises/pig-latin/Example.cs +1 -1
- data/tracks/csharp/exercises/pig-latin/PigLatinTest.cs +19 -7
- data/tracks/csharp/exercises/sum-of-multiples/SumOfMultiplesTest.cs +7 -1
- data/tracks/csharp/exercises/tournament/Example.cs +1 -1
- data/tracks/csharp/exercises/tournament/TournamentTest.cs +151 -68
- data/tracks/csharp/exercises/triangle/Example.cs +26 -8
- data/tracks/csharp/exercises/triangle/Triangle.cs +16 -1
- data/tracks/csharp/exercises/triangle/TriangleTest.cs +44 -30
- data/tracks/csharp/generators/Exercise.cs +6 -1
- data/tracks/csharp/generators/Exercises/Clock.cs +17 -1
- data/tracks/csharp/generators/Exercises/NucleotideCount.cs +61 -0
- data/tracks/csharp/generators/Exercises/Tournament.cs +66 -0
- data/tracks/csharp/generators/Exercises/Triangle.cs +36 -0
- data/tracks/dart/config.json +15 -2
- data/tracks/dart/exercises/raindrops/lib/example.dart +23 -0
- data/tracks/dart/exercises/raindrops/lib/raindrops.dart +3 -0
- data/tracks/dart/exercises/raindrops/pubspec.lock +281 -0
- data/tracks/dart/exercises/raindrops/pubspec.yaml +3 -0
- data/tracks/dart/exercises/raindrops/test/raindrops_test.dart +94 -0
- data/tracks/delphi/exercises/pig-latin/uPigLatinExample.pas +1 -25
- data/tracks/haskell/config.json +9 -0
- data/tracks/haskell/exercises/acronym/README.md +0 -1
- data/tracks/haskell/exercises/all-your-base/README.md +1 -1
- data/tracks/haskell/exercises/allergies/README.md +0 -1
- data/tracks/haskell/exercises/alphametics/README.md +2 -2
- data/tracks/haskell/exercises/atbash-cipher/README.md +2 -1
- data/tracks/haskell/exercises/beer-song/README.md +1 -1
- data/tracks/haskell/exercises/binary/README.md +2 -0
- data/tracks/haskell/exercises/bowling/README.md +20 -6
- data/tracks/haskell/exercises/collatz-conjecture/README.md +1 -1
- data/tracks/haskell/exercises/connect/README.md +1 -1
- data/tracks/haskell/exercises/crypto-square/README.md +4 -4
- data/tracks/haskell/exercises/diamond/README.md +113 -0
- data/tracks/haskell/exercises/diamond/examples/success-standard/package.yaml +16 -0
- data/tracks/haskell/exercises/diamond/examples/success-standard/src/Diamond.hs +16 -0
- data/tracks/haskell/exercises/diamond/package.yaml +20 -0
- data/tracks/haskell/exercises/diamond/src/Diamond.hs +4 -0
- data/tracks/haskell/exercises/diamond/stack.yaml +1 -0
- data/tracks/haskell/exercises/diamond/test/Tests.hs +109 -0
- data/tracks/haskell/exercises/etl/README.md +3 -1
- data/tracks/haskell/exercises/food-chain/README.md +1 -1
- data/tracks/haskell/exercises/go-counting/README.md +1 -1
- data/tracks/haskell/exercises/grade-school/README.md +0 -1
- data/tracks/haskell/exercises/grains/README.md +0 -1
- data/tracks/haskell/exercises/house/README.md +1 -2
- data/tracks/haskell/exercises/isogram/README.md +2 -1
- data/tracks/haskell/exercises/kindergarten-garden/README.md +3 -3
- data/tracks/haskell/exercises/leap/README.md +1 -1
- data/tracks/haskell/exercises/linked-list/README.md +10 -10
- data/tracks/haskell/exercises/luhn/README.md +7 -7
- data/tracks/haskell/exercises/matrix/README.md +6 -4
- data/tracks/haskell/exercises/meetup/README.md +1 -2
- data/tracks/haskell/exercises/nucleotide-count/README.md +8 -22
- data/tracks/haskell/exercises/ocr-numbers/README.md +6 -6
- data/tracks/haskell/exercises/octal/README.md +6 -2
- data/tracks/haskell/exercises/palindrome-products/README.md +12 -6
- data/tracks/haskell/exercises/pangram/README.md +1 -1
- data/tracks/haskell/exercises/pascals-triangle/README.md +2 -2
- data/tracks/haskell/exercises/phone-number/README.md +3 -2
- data/tracks/haskell/exercises/pov/README.md +3 -3
- data/tracks/haskell/exercises/pythagorean-triplet/README.md +3 -3
- data/tracks/haskell/exercises/queen-attack/README.md +1 -1
- data/tracks/haskell/exercises/rna-transcription/README.md +1 -1
- data/tracks/haskell/exercises/roman-numerals/README.md +1 -1
- data/tracks/haskell/exercises/run-length-encoding/README.md +4 -4
- data/tracks/haskell/exercises/saddle-points/README.md +1 -1
- data/tracks/haskell/exercises/scrabble-score/README.md +3 -1
- data/tracks/haskell/exercises/secret-handshake/README.md +1 -1
- data/tracks/haskell/exercises/sgf-parsing/README.md +4 -4
- data/tracks/haskell/exercises/simple-cipher/README.md +1 -1
- data/tracks/haskell/exercises/spiral-matrix/README.md +2 -2
- data/tracks/haskell/exercises/triangle/README.md +9 -6
- data/tracks/haskell/exercises/trinary/README.md +1 -1
- data/tracks/haskell/exercises/word-count/README.md +1 -2
- data/tracks/haskell/exercises/wordy/README.md +0 -5
- data/tracks/java/config.json +56 -9
- data/tracks/java/exercises/binary-search-tree/src/test/java/BSTTest.java +4 -4
- data/tracks/javascript/exercises/two-bucket/example.js +66 -69
- data/tracks/javascript/exercises/two-bucket/two-bucket.spec.js +18 -18
- data/tracks/julia/config.json +1 -0
- data/tracks/julia/docs/ABOUT.md +3 -8
- data/tracks/prolog/README.md +1 -1
- data/tracks/purescript/.travis.yml +1 -0
- data/tracks/purescript/README.md +9 -0
- data/tracks/purescript/bin/check-bower.sh +42 -0
- data/tracks/purescript/bin/test-separate.sh +46 -0
- data/tracks/python/README.md +2 -2
- data/tracks/python/exercises/all-your-base/all_your_base.py +2 -0
- data/tracks/python/exercises/atbash-cipher/atbash_cipher.py +2 -2
- data/tracks/python/exercises/complex-numbers/complex_numbers_test.py +2 -2
- data/tracks/python/exercises/complex-numbers/example.py +2 -2
- data/tracks/python/exercises/gigasecond/gigasecond.py +1 -1
- data/tracks/python/exercises/hamming/hamming.py +1 -1
- data/tracks/python/exercises/hexadecimal/hexadecimal.py +1 -1
- data/tracks/python/exercises/leap/leap.py +1 -1
- data/tracks/python/exercises/meetup/meetup.py +1 -1
- data/tracks/python/exercises/phone-number/example.py +4 -2
- data/tracks/python/exercises/phone-number/phone_number_test.py +47 -16
- data/tracks/python/exercises/pig-latin/pig_latin.py +1 -1
- data/tracks/python/exercises/scrabble-score/scrabble_score.py +1 -1
- data/tracks/python/exercises/wordy/wordy.py +1 -1
- data/tracks/scala/exercises/meetup/example.scala +29 -10
- data/tracks/scala/exercises/meetup/src/main/scala/Meetup.scala +23 -0
- data/tracks/scala/exercises/meetup/src/test/scala/MeetupTest.scala +273 -183
- data/tracks/sml/config.json +13 -0
- data/tracks/sml/exercises/anagram/README.md +21 -5
- data/tracks/sml/exercises/anagram/anagram.sml +2 -6
- data/tracks/sml/exercises/anagram/example.sml +29 -24
- data/tracks/sml/exercises/anagram/test.sml +56 -50
- data/tracks/sml/exercises/anagram/testlib.sml +159 -0
- data/tracks/sml/exercises/diamond/README.md +89 -0
- data/tracks/sml/exercises/diamond/diamond.sml +2 -0
- data/tracks/sml/exercises/diamond/example.sml +25 -0
- data/tracks/sml/exercises/diamond/test.sml +27 -0
- data/tracks/sml/exercises/diamond/testlib.sml +159 -0
- data/tracks/sml/exercises/raindrops/raindrops.sml +2 -2
- data/tracks/sml/exercises/raindrops/test.sml +66 -95
- data/tracks/sml/exercises/raindrops/testlib.sml +159 -0
- metadata +265 -3
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* I scaffold a new exercise from the template.
|
|
3
|
+
*/
|
|
4
|
+
component {
|
|
5
|
+
|
|
6
|
+
function run(
|
|
7
|
+
slug,
|
|
8
|
+
difficulty,
|
|
9
|
+
uuid=createGUID()
|
|
10
|
+
) {
|
|
11
|
+
var repoRootPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../' );
|
|
12
|
+
|
|
13
|
+
// Acquire slug
|
|
14
|
+
if( isNull( arguments.slug ) ) {
|
|
15
|
+
arguments.slug = ask( 'Exercise slug as defined by Excercism. Ex: "hello-world": ' );
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Slug of hello-world defaults to name of HelloWorld
|
|
19
|
+
var exerciseName = arguments.slug
|
|
20
|
+
.listToArray( '-' )
|
|
21
|
+
.map( function( i ){
|
|
22
|
+
return i.left( 1 ).uCase() & i.right( -1 ).lCase();
|
|
23
|
+
} )
|
|
24
|
+
.toList( '' );
|
|
25
|
+
|
|
26
|
+
// Acquire diffculty
|
|
27
|
+
if( isNull( arguments.difficulty ) ) {
|
|
28
|
+
arguments.difficulty = ask( message='Difficulty: ', defaultResponse=1 );
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Validation to prevent duplicate runs
|
|
32
|
+
var exerciseDirectory = repoRootPath & 'exercises/' & arguments.slug;
|
|
33
|
+
if( directoryExists( exerciseDirectory ) ) {
|
|
34
|
+
error( 'An exercise named [#arguments.slug#] already exists!' );
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Add this exercise to config.json
|
|
38
|
+
var configJSON = deserializeJSON( fileRead( repoRootPath & '/config.json' ) );
|
|
39
|
+
configJSON.exercises.append( {
|
|
40
|
+
"uuid": arguments.uuid,
|
|
41
|
+
"difficulty": arguments.difficulty+0,
|
|
42
|
+
"slug": arguments.slug,
|
|
43
|
+
"topics": []
|
|
44
|
+
} );
|
|
45
|
+
fileWrite( repoRootPath & '/config.json', formatterUtil.formatJSON( json=configJSON, indent=' ' , lineEnding=chr( 10 ) ) );
|
|
46
|
+
|
|
47
|
+
// Create exercise scaffold
|
|
48
|
+
directoryCreate( exerciseDirectory );
|
|
49
|
+
directoryCopy( repoRootPath & '/tasks/exercise_template', exerciseDirectory, true );
|
|
50
|
+
|
|
51
|
+
// Perform Token replacements
|
|
52
|
+
command( 'tokenReplace' )
|
|
53
|
+
.params( '**', '@@name@@', exerciseName )
|
|
54
|
+
.inWorkingDirectory( exerciseDirectory )
|
|
55
|
+
.run();
|
|
56
|
+
|
|
57
|
+
directoryList( exerciseDirectory, true )
|
|
58
|
+
.each( function( path ){
|
|
59
|
+
if( path.findNoCase( '@@name@@' ) ) {
|
|
60
|
+
fileMove( path, path.replaceNoCase( '@@name@@', exerciseName, 'all' ) );
|
|
61
|
+
}
|
|
62
|
+
} );
|
|
63
|
+
|
|
64
|
+
print.boldGreenLine( 'New exercise created!' )
|
|
65
|
+
.line()
|
|
66
|
+
.greenLine( 'The exercise is located here: ' )
|
|
67
|
+
.indentedYellowLine( exerciseDirectory )
|
|
68
|
+
.line()
|
|
69
|
+
.greenLine( 'Create a sample solution here: ' )
|
|
70
|
+
.indentedYellowLine( exerciseDirectory & '/Solution.cfc' )
|
|
71
|
+
.line()
|
|
72
|
+
.greenLine( 'Test your solution with this command: ' )
|
|
73
|
+
.indentedYellowLine( 'box task run TestRunner --:solution' )
|
|
74
|
+
.line()
|
|
75
|
+
.toConsole();
|
|
76
|
+
|
|
77
|
+
// Generate test suite
|
|
78
|
+
command( 'task run' )
|
|
79
|
+
.params( 'GenerateTests', 'run', slug )
|
|
80
|
+
.inWorkingDirectory( repoRootPath & '/tasks' )
|
|
81
|
+
.run();
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* I test all the solutions in each exercise to make sure they all pass.
|
|
3
|
+
*/
|
|
4
|
+
component {
|
|
5
|
+
|
|
6
|
+
function run() {
|
|
7
|
+
// Get an array of all the excercise names
|
|
8
|
+
var exercises = directoryList( expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../exercises' ) );
|
|
9
|
+
|
|
10
|
+
// If there's a testrunner task in them, run it. If any of the tasks fail, the exit code will come back as 1
|
|
11
|
+
exercises.each( function( path ) {
|
|
12
|
+
if( fileExists( path & '/TestRunner.cfc' ) ) {
|
|
13
|
+
command( 'task run' )
|
|
14
|
+
.params( 'TestRunner' )
|
|
15
|
+
// Specifically as the task runners to run the SolutionTest
|
|
16
|
+
.flags( ':solution' )
|
|
17
|
+
.inWorkingDirectory( path )
|
|
18
|
+
.run();
|
|
19
|
+
}
|
|
20
|
+
} );
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
File without changes
|
|
@@ -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,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>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
ColdFusion (CFML) is a JVM scripting language whose syntax is similar to C or JavaScript.
|
|
2
|
-
|
|
3
|
-
CF
|
|
4
|
-
|
|
5
|
-
CF can also leverage any Java project by dropping the jars in project and directly instantiating Java objects in your code. You can learn more about basic syntax and first class data types in this guide: [Modern ColdFusion (CFML) in 100 Minutes](https://www.gitbook.com/book/ortus/modern-coldfusion-cfml-in-100-minutes/details)
|
|
6
|
-
|
|
1
|
+
ColdFusion (CFML) is a JVM scripting language whose syntax is similar to C or JavaScript.
|
|
2
|
+
It JIT compiles to byte code that runs on the JVM but is dynamic and loosely typed, making it fast and easy to develop in.
|
|
3
|
+
CF is a multi-paradigmed language, supporting classical OO and functional programming.
|
|
7
4
|
|
|
5
|
+
CFML also has a built-in tag-based templating language that makes it ideal for web apps.
|
|
6
|
+
It runs in a J2EE container with many bundled libraries that make it very productive without the need to install many packages.
|
|
7
|
+
CFML has native support for zip files, PDF and Excel generation, E-mails, FTP, HTTP, S3 file systems, ESAPI security libraries, JDBC drivers, JSON and REST APIs.
|
|
8
8
|
|
|
9
|
+
CFML can also leverage any Java project by dropping the jars in project and directly instantiating Java objects in your code.
|
|
10
|
+
You can learn more about basic syntax and first class data types in this guide: [Modern ColdFusion (CFML) in 100 Minutes](https://www.gitbook.com/book/ortus/modern-coldfusion-cfml-in-100-minutes/details)
|
|
@@ -82,6 +82,13 @@ An example of this is the [RunLengthEncoding](https://github.com/exercism/csharp
|
|
|
82
82
|
|
|
83
83
|
Here the **Assert** is being overridden. The assert needs to call additional functions, but only if the property is `consistency`. Otherwise, render the assert as usual.
|
|
84
84
|
|
|
85
|
+
### string[] RenderAdditionalMethods()
|
|
86
|
+
Allow additional methods to be added to the test suite.
|
|
87
|
+
|
|
88
|
+
There may exist cases where a suite of unit tests will need to reuse the same logic in each of the tests. Rather than duplicating code, this method allows you to provide helper methods for the tests.
|
|
89
|
+
|
|
90
|
+
Additional methods added using this override will be added to the bottom of the test suite.
|
|
91
|
+
|
|
85
92
|
## Updating Existing Files
|
|
86
93
|
It is possible that an existing exercise does not match the canonical data. It is OK to update the exercise stub and/or the exercise example to follow the canonical data! An example might be that an exercise is named SumOfMultiples, but the SumOfMultiples.cs and Example.cs files both use `Multiples` as the name of the class.
|
|
87
94
|
|
|
@@ -253,104 +253,104 @@ public class ClockTest
|
|
|
253
253
|
public void Clocks_with_same_time()
|
|
254
254
|
{
|
|
255
255
|
var sut = new Clock(15, 37);
|
|
256
|
-
Assert.
|
|
256
|
+
Assert.Equal(new Clock(15, 37), sut);
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
[Fact(Skip = "Remove to run test")]
|
|
260
260
|
public void Clocks_a_minute_apart()
|
|
261
261
|
{
|
|
262
262
|
var sut = new Clock(15, 36);
|
|
263
|
-
Assert.
|
|
263
|
+
Assert.NotEqual(new Clock(15, 37), sut);
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
[Fact(Skip = "Remove to run test")]
|
|
267
267
|
public void Clocks_an_hour_apart()
|
|
268
268
|
{
|
|
269
269
|
var sut = new Clock(14, 37);
|
|
270
|
-
Assert.
|
|
270
|
+
Assert.NotEqual(new Clock(15, 37), sut);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
[Fact(Skip = "Remove to run test")]
|
|
274
274
|
public void Clocks_with_hour_overflow()
|
|
275
275
|
{
|
|
276
276
|
var sut = new Clock(10, 37);
|
|
277
|
-
Assert.
|
|
277
|
+
Assert.Equal(new Clock(34, 37), sut);
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
[Fact(Skip = "Remove to run test")]
|
|
281
281
|
public void Clocks_with_hour_overflow_by_several_days()
|
|
282
282
|
{
|
|
283
283
|
var sut = new Clock(3, 11);
|
|
284
|
-
Assert.
|
|
284
|
+
Assert.Equal(new Clock(99, 11), sut);
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
[Fact(Skip = "Remove to run test")]
|
|
288
288
|
public void Clocks_with_negative_hour()
|
|
289
289
|
{
|
|
290
290
|
var sut = new Clock(22, 40);
|
|
291
|
-
Assert.
|
|
291
|
+
Assert.Equal(new Clock(-2, 40), sut);
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
[Fact(Skip = "Remove to run test")]
|
|
295
295
|
public void Clocks_with_negative_hour_that_wraps()
|
|
296
296
|
{
|
|
297
297
|
var sut = new Clock(17, 3);
|
|
298
|
-
Assert.
|
|
298
|
+
Assert.Equal(new Clock(-31, 3), sut);
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
[Fact(Skip = "Remove to run test")]
|
|
302
302
|
public void Clocks_with_negative_hour_that_wraps_multiple_times()
|
|
303
303
|
{
|
|
304
304
|
var sut = new Clock(13, 49);
|
|
305
|
-
Assert.
|
|
305
|
+
Assert.Equal(new Clock(-83, 49), sut);
|
|
306
306
|
}
|
|
307
307
|
|
|
308
308
|
[Fact(Skip = "Remove to run test")]
|
|
309
309
|
public void Clocks_with_minute_overflow()
|
|
310
310
|
{
|
|
311
311
|
var sut = new Clock(0, 1);
|
|
312
|
-
Assert.
|
|
312
|
+
Assert.Equal(new Clock(0, 1441), sut);
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
[Fact(Skip = "Remove to run test")]
|
|
316
316
|
public void Clocks_with_minute_overflow_by_several_days()
|
|
317
317
|
{
|
|
318
318
|
var sut = new Clock(2, 2);
|
|
319
|
-
Assert.
|
|
319
|
+
Assert.Equal(new Clock(2, 4322), sut);
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
[Fact(Skip = "Remove to run test")]
|
|
323
323
|
public void Clocks_with_negative_minute()
|
|
324
324
|
{
|
|
325
325
|
var sut = new Clock(2, 40);
|
|
326
|
-
Assert.
|
|
326
|
+
Assert.Equal(new Clock(3, -20), sut);
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
[Fact(Skip = "Remove to run test")]
|
|
330
330
|
public void Clocks_with_negative_minute_that_wraps()
|
|
331
331
|
{
|
|
332
332
|
var sut = new Clock(4, 10);
|
|
333
|
-
Assert.
|
|
333
|
+
Assert.Equal(new Clock(5, -1490), sut);
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
[Fact(Skip = "Remove to run test")]
|
|
337
337
|
public void Clocks_with_negative_minute_that_wraps_multiple_times()
|
|
338
338
|
{
|
|
339
339
|
var sut = new Clock(6, 15);
|
|
340
|
-
Assert.
|
|
340
|
+
Assert.Equal(new Clock(6, -4305), sut);
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
[Fact(Skip = "Remove to run test")]
|
|
344
344
|
public void Clocks_with_negative_hours_and_minutes()
|
|
345
345
|
{
|
|
346
346
|
var sut = new Clock(7, 32);
|
|
347
|
-
Assert.
|
|
347
|
+
Assert.Equal(new Clock(-12, -268), sut);
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
[Fact(Skip = "Remove to run test")]
|
|
351
351
|
public void Clocks_with_negative_hours_and_minutes_that_wrap()
|
|
352
352
|
{
|
|
353
353
|
var sut = new Clock(18, 7);
|
|
354
|
-
Assert.
|
|
354
|
+
Assert.Equal(new Clock(-54, -11513), sut);
|
|
355
355
|
}
|
|
356
356
|
}
|