trackler 2.2.1.52 → 2.2.1.53

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.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trackler/version.rb +1 -1
  3. data/problem-specifications/exercises/leap/canonical-data.json +2 -2
  4. data/tracks/cfml/tasks/FormatConfig.cfc +6 -4
  5. data/tracks/cfml/tasks/GenerateReadme.cfc +197 -0
  6. data/tracks/cfml/tasks/ScaffoldExercise.cfc +6 -0
  7. data/tracks/csharp/config.json +1 -1
  8. data/tracks/delphi/exercises/leap/uLeapTests.pas +1 -1
  9. data/tracks/fsharp/exercises/clock/Clock.fs +1 -1
  10. data/tracks/fsharp/exercises/clock/ClockTest.fs +239 -61
  11. data/tracks/fsharp/exercises/clock/Example.fs +3 -3
  12. data/tracks/fsharp/exercises/dominoes/DominoesTest.fs +29 -26
  13. data/tracks/fsharp/exercises/largest-series-product/LargestSeriesProductTest.fs +30 -15
  14. data/tracks/fsharp/exercises/leap/LeapTest.fs +2 -2
  15. data/tracks/fsharp/exercises/rectangles/Example.fs +1 -1
  16. data/tracks/fsharp/exercises/rectangles/Rectangles.fs +1 -1
  17. data/tracks/fsharp/exercises/rectangles/RectanglesTest.fs +66 -43
  18. data/tracks/fsharp/generators/Generators.fs +85 -1
  19. data/tracks/java/scripts/canonical_data_check.sh +8 -0
  20. data/tracks/kotlin/.gitignore +1 -0
  21. data/tracks/kotlin/exercises/acronym/.meta/version +1 -0
  22. data/tracks/kotlin/exercises/acronym/src/test/kotlin/AcronymTest.kt +9 -10
  23. data/tracks/kotlin/exercises/all-your-base/.meta/version +1 -1
  24. data/tracks/kotlin/exercises/all-your-base/src/test/kotlin/BaseConverterTest.kt +20 -20
  25. data/tracks/kotlin/exercises/allergies/.meta/version +1 -0
  26. data/tracks/kotlin/exercises/allergies/src/test/kotlin/AllergiesTest.kt +19 -72
  27. data/tracks/kotlin/exercises/anagram/.meta/src/reference/kotlin/Anagram.kt +7 -4
  28. data/tracks/kotlin/exercises/anagram/.meta/version +1 -0
  29. data/tracks/kotlin/exercises/anagram/src/test/kotlin/AnagramTest.kt +76 -29
  30. data/tracks/kotlin/exercises/atbash-cipher/.meta/version +1 -0
  31. data/tracks/kotlin/exercises/atbash-cipher/src/test/kotlin/AtbashTest.kt +6 -3
  32. data/tracks/kotlin/exercises/beer-song/.meta/version +1 -0
  33. data/tracks/kotlin/exercises/beer-song/src/test/kotlin/BeerSongTest.kt +21 -46
  34. data/tracks/kotlin/exercises/binary-search/.meta/version +1 -0
  35. data/tracks/kotlin/exercises/binary-search/src/test/kotlin/BinarySearchTest.kt +30 -19
  36. data/tracks/kotlin/exercises/bob/.meta/src/reference/kotlin/Bob.kt +8 -7
  37. data/tracks/kotlin/exercises/bob/.meta/version +1 -0
  38. data/tracks/kotlin/exercises/bob/src/test/kotlin/BobTest.kt +57 -15
  39. data/tracks/kotlin/exercises/bracket-push/.meta/version +1 -0
  40. data/tracks/kotlin/exercises/bracket-push/src/test/kotlin/BracketPushTest.kt +3 -1
  41. data/tracks/kotlin/exercises/collatz-conjecture/.meta/version +1 -1
  42. data/tracks/kotlin/exercises/difference-of-squares/.meta/version +1 -0
  43. data/tracks/kotlin/exercises/difference-of-squares/src/test/kotlin/SquaresTest.kt +10 -23
  44. data/tracks/kotlin/exercises/etl/.meta/src/reference/kotlin/ETL.kt +7 -1
  45. data/tracks/kotlin/exercises/etl/.meta/version +1 -0
  46. data/tracks/kotlin/exercises/etl/src/test/kotlin/ETLTest.kt +10 -10
  47. data/tracks/kotlin/exercises/flatten-array/.meta/version +1 -0
  48. data/tracks/kotlin/exercises/flatten-array/src/test/kotlin/FlattenerTest.kt +8 -16
  49. data/tracks/kotlin/exercises/gigasecond/.meta/version +1 -0
  50. data/tracks/kotlin/exercises/gigasecond/src/test/kotlin/GigasecondTest.kt +1 -1
  51. data/tracks/kotlin/exercises/hamming/.meta/src/reference/kotlin/Hamming.kt +1 -1
  52. data/tracks/kotlin/exercises/hamming/.meta/version +1 -1
  53. data/tracks/kotlin/exercises/hamming/src/test/kotlin/HammingTest.kt +4 -4
  54. data/tracks/kotlin/exercises/hello-world/.meta/version +1 -0
  55. data/tracks/kotlin/exercises/hello-world/src/test/kotlin/HelloWorldTest.kt +1 -1
  56. data/tracks/kotlin/exercises/isogram/.meta/version +1 -0
  57. data/tracks/kotlin/exercises/isogram/src/test/kotlin/IsogramTest.kt +5 -8
  58. data/tracks/kotlin/exercises/largest-series-product/.meta/src/reference/kotlin/Series.kt +2 -3
  59. data/tracks/kotlin/exercises/largest-series-product/.meta/version +1 -0
  60. data/tracks/kotlin/exercises/largest-series-product/src/test/kotlin/SeriesTest.kt +97 -0
  61. data/tracks/kotlin/exercises/leap/.meta/version +1 -0
  62. data/tracks/kotlin/exercises/leap/src/test/kotlin/LeapTest.kt +8 -26
  63. data/tracks/kotlin/exercises/list-ops/.meta/version +1 -1
  64. data/tracks/kotlin/exercises/luhn/.meta/version +1 -0
  65. data/tracks/kotlin/exercises/luhn/src/test/kotlin/LuhnTest.kt +0 -3
  66. data/tracks/kotlin/exercises/nth-prime/.meta/version +1 -0
  67. data/tracks/kotlin/exercises/nth-prime/src/test/kotlin/PrimeTest.kt +0 -2
  68. data/tracks/kotlin/exercises/nucleotide-count/.meta/src/reference/kotlin/{DNA.kt → Dna.kt} +3 -8
  69. data/tracks/kotlin/exercises/nucleotide-count/.meta/version +1 -0
  70. data/tracks/kotlin/exercises/nucleotide-count/src/test/kotlin/DnaTest.kt +48 -0
  71. data/tracks/kotlin/exercises/pangram/.meta/src/reference/kotlin/{Pangrams.kt → Pangram.kt} +1 -1
  72. data/tracks/kotlin/exercises/pangram/.meta/version +1 -1
  73. data/tracks/kotlin/exercises/pangram/src/test/kotlin/PangramTest.kt +15 -9
  74. data/tracks/kotlin/exercises/pascals-triangle/.meta/version +1 -0
  75. data/tracks/kotlin/exercises/pascals-triangle/src/test/kotlin/PascalsTriangleTest.kt +32 -14
  76. data/tracks/kotlin/exercises/perfect-numbers/.meta/src/reference/kotlin/NaturalNumber.kt +1 -1
  77. data/tracks/kotlin/exercises/perfect-numbers/.meta/version +1 -0
  78. data/tracks/kotlin/exercises/perfect-numbers/src/test/kotlin/{PerfectNumbersTest.kt → NaturalNumberTest.kt} +25 -7
  79. data/tracks/kotlin/exercises/phone-number/.meta/src/reference/kotlin/PhoneNumber.kt +15 -7
  80. data/tracks/kotlin/exercises/phone-number/.meta/version +1 -0
  81. data/tracks/kotlin/exercises/phone-number/src/test/kotlin/PhoneNumberTest.kt +46 -29
  82. data/tracks/kotlin/exercises/pig-latin/.meta/src/reference/kotlin/PigLatin.kt +2 -2
  83. data/tracks/kotlin/exercises/pig-latin/.meta/version +1 -0
  84. data/tracks/kotlin/exercises/pig-latin/src/test/kotlin/PigLatinTest.kt +21 -10
  85. data/tracks/kotlin/exercises/raindrops/.meta/version +1 -0
  86. data/tracks/kotlin/exercises/raindrops/src/test/kotlin/RaindropsTest.kt +19 -26
  87. data/tracks/kotlin/exercises/react/.meta/version +1 -0
  88. data/tracks/kotlin/exercises/react/src/test/kotlin/ReactTest.kt +11 -4
  89. data/tracks/kotlin/exercises/robot-simulator/.meta/version +1 -1
  90. data/tracks/kotlin/exercises/roman-numerals/.meta/version +1 -0
  91. data/tracks/kotlin/exercises/roman-numerals/src/test/kotlin/RomanNumeralTest.kt +1 -2
  92. data/tracks/kotlin/exercises/rotational-cipher/.meta/version +1 -1
  93. data/tracks/kotlin/exercises/rotational-cipher/src/test/kotlin/RotationalCipherTest.kt +7 -7
  94. data/tracks/kotlin/exercises/scrabble-score/.meta/src/reference/kotlin/{Scrabble.kt → ScrabbleScore.kt} +1 -1
  95. data/tracks/kotlin/exercises/scrabble-score/.meta/version +1 -0
  96. data/tracks/kotlin/exercises/scrabble-score/src/test/kotlin/ScrabbleScoreTest.kt +9 -7
  97. data/tracks/kotlin/exercises/sieve/.meta/version +1 -0
  98. data/tracks/kotlin/exercises/sieve/src/test/kotlin/SieveTest.kt +8 -0
  99. data/tracks/kotlin/exercises/space-age/.meta/version +1 -0
  100. data/tracks/kotlin/exercises/space-age/src/test/kotlin/SpaceAgeTest.kt +1 -16
  101. data/tracks/kotlin/exercises/sum-of-multiples/.meta/version +1 -0
  102. data/tracks/kotlin/exercises/sum-of-multiples/src/test/kotlin/SumOfMultiplesTest.kt +7 -7
  103. data/tracks/kotlin/exercises/triangle/.meta/version +1 -0
  104. data/tracks/kotlin/exercises/two-fer/.meta/version +1 -0
  105. data/tracks/kotlin/exercises/two-fer/src/test/kotlin/TwoferTest.kt +0 -1
  106. data/tracks/kotlin/exercises/word-count/.meta/src/reference/kotlin/WordCount.kt +6 -2
  107. data/tracks/kotlin/exercises/word-count/.meta/version +1 -0
  108. data/tracks/kotlin/exercises/word-count/src/test/kotlin/WordCountTest.kt +31 -9
  109. data/tracks/kotlin/scripts/canonical_data_check.sh +8 -0
  110. data/tracks/perl6/exercises/leap/leap.t +2 -2
  111. data/tracks/php/config.json +16 -0
  112. data/tracks/php/exercises/crypto-square/crypto-square_test.php +50 -0
  113. data/tracks/php/exercises/crypto-square/example.php +32 -0
  114. data/tracks/php/exercises/meetup/README.md +21 -0
  115. data/tracks/php/exercises/meetup/example.php +19 -0
  116. data/tracks/php/exercises/meetup/meetup_test.php +577 -0
  117. data/tracks/python/README.md +7 -5
  118. data/tracks/python/config.json +36 -27
  119. data/tracks/python/docs/TESTS.md +36 -12
  120. data/tracks/python/exercises/complex-numbers/complex_numbers_test.py +1 -1
  121. data/tracks/python/exercises/diffie-hellman/.meta/hints.md +16 -0
  122. data/tracks/python/exercises/diffie-hellman/README.md +15 -2
  123. data/tracks/python/exercises/error-handling/README.md +23 -0
  124. data/tracks/python/exercises/error-handling/error_handling.py +14 -0
  125. data/tracks/python/exercises/error-handling/error_handling_test.py +66 -0
  126. data/tracks/python/exercises/error-handling/example.py +21 -0
  127. data/tracks/python/exercises/forth/forth_test.py +1 -1
  128. data/tracks/python/exercises/isogram/isogram_test.py +5 -3
  129. data/tracks/python/exercises/leap/leap_test.py +2 -2
  130. data/tracks/python/exercises/rotational-cipher/rotational_cipher_test.py +4 -4
  131. data/tracks/python/exercises/simple-cipher/.meta/hints.md +16 -0
  132. data/tracks/python/exercises/simple-cipher/README.md +17 -0
  133. data/tracks/python/exercises/sum-of-multiples/sum_of_multiples_test.py +4 -1
  134. data/tracks/python/exercises/twelve-days/example.py +3 -3
  135. data/tracks/python/exercises/twelve-days/twelve_days.py +2 -2
  136. metadata +53 -9
  137. data/tracks/kotlin/exercises/largest-series-product/src/test/kotlin/SeriesInvalidInputTest.kt +0 -30
  138. data/tracks/kotlin/exercises/largest-series-product/src/test/kotlin/SeriesValidInputTest.kt +0 -34
  139. data/tracks/kotlin/exercises/nucleotide-count/src/test/kotlin/NucleotideTest.kt +0 -87
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ba58003417ff7756c00e61bca5725599d51f36a
4
- data.tar.gz: b224d56deaee8862e20e456a5431c77c84761ce7
3
+ metadata.gz: 95152d34553c950841be6dbe52afef273a56ab43
4
+ data.tar.gz: 4d2c405d864d1c9fef3295f2cc30b316fdbc30f2
5
5
  SHA512:
6
- metadata.gz: 228596af71741d35e867a78201c19b7497a186a65c85b4cf1656de33d81d722f0bff10436e7cdf4eb6c9841eb0c6bde13440fb05bcf34257ed59904e2397dd5e
7
- data.tar.gz: 2c111f16d5aba64c6f455ef360626fef978c6b3341fa616a54778e112000f2e6eaa5ff78141d643151a74c7742041422d70f30086c92672ec66a38af90203cb7
6
+ metadata.gz: ebdadfa92b814621a979f0dbdb8060f3d1a952e000a93cea60b4a71cef0435ca67723bfd2ec5f8ad109acd826b3024d7890283cbad44f2fda01e065f8f6b805b
7
+ data.tar.gz: d8fa0417ab4cc2173f02b5fa5aa90975d5b62cdc8a2c1f8d965fbdfe458b05371273ad47ffb337eb3855d4a331f33a873568a3197513e05480e285c09ef2ee9b
@@ -1,3 +1,3 @@
1
1
  module Trackler
2
- VERSION = "2.2.1.52"
2
+ VERSION = "2.2.1.53"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "exercise": "leap",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "cases": [
5
5
  {
6
6
  "description": "year not divisible by 4: common year",
@@ -11,7 +11,7 @@
11
11
  {
12
12
  "description": "year divisible by 4, not divisible by 100: leap year",
13
13
  "property": "leapYear",
14
- "input": 2020,
14
+ "input": 1996,
15
15
  "expected": true
16
16
  },
17
17
  {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * This is a simple task runner that formats the JSON config file. This should only be neccessary if yoiu've edited it by
2
+ * This is a simple task runner that formats the JSON config file. This should only be neccessary if you've edited it by
3
3
  * hand and want to get it back into the proper format as far as spacing and indentation goes. This follows the same format as `configlet fmt`
4
4
  */
5
5
  component {
@@ -9,17 +9,19 @@ component {
9
9
  var repoRootPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../' );
10
10
  // Read in the current JSON config file
11
11
  var configJSONRaw = fileRead( repoRootPath & '/config.json' );
12
- var configJSON = deserializeJSON( configJSONRaw );
13
12
 
14
- var newConfigJSONRaw = formatterUtil.formatJSON( json=configJSON, indent=' ' , lineEnding=chr( 10 ), spaceAfterColon=true );
13
+ // Format JSON file to spec
14
+ var newConfigJSONRaw = formatterUtil.formatJSON( json=configJSONRaw, indent=' ' , lineEnding=chr( 10 ), spaceAfterColon=true );
15
15
 
16
+ // Only save if it's different to avoid touching the file needlessly
16
17
  if( newConfigJSONRaw != configJSONRaw ) {
18
+
17
19
  // Write it back out with the proper formatting styles applied
18
20
  fileWrite( repoRootPath & '/config.json', newConfigJSONRaw );
19
21
 
20
22
  print.greenLine( 'Config file [#repoRootPath#config.json] formatted!' );
21
23
  } else {
22
- print.whiteLine( 'Config file [#repoRootPath#config.json] is already formatted!' );
24
+ print.whiteLine( 'Config file [#repoRootPath#config.json] is already formatted! No Chanages needed.' );
23
25
  }
24
26
  }
25
27
 
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Generate README.md files for exercises
3
+ */
4
+ component {
5
+
6
+ /**
7
+ * Run the task to generate read me files
8
+ */
9
+ function run(
10
+ slug,
11
+ boolean all=false,
12
+ boolean force=false
13
+ ){
14
+
15
+ /* Init global variables */
16
+ repoRootPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../' );
17
+ problemSpecsPath = expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../../problem-specifications' );
18
+ trackReadmeInsert= fileRead( repoRootPath & "docs/EXERCISE_README_INSERT.md" );
19
+ overwriteExistingFiles = arguments.force;
20
+
21
+ if( !directoryExists( problemSpecsPath ) ){
22
+ error( 'Cannot find [problem-specifications] repo. It needs to be git cloned to [#problemSpecsPath#]' );
23
+ }
24
+
25
+ if( all ) {
26
+
27
+ // Get an array of all the excercise names
28
+ var exercises = directoryList( expandPath( getDirectoryFromPath( getCurrentTemplatePath() ) & '../exercises' ) )
29
+ .map( function( path ) {
30
+ return path.listLast( '/\' );
31
+ } );
32
+
33
+ } else {
34
+
35
+ // Acquire slug
36
+ if( isNull( arguments.slug ) ) {
37
+ arguments.slug = ask( 'Exercise slug as defined by Excercism. Ex: "hello-world": ' );
38
+ }
39
+ var exercises = [ slug ];
40
+
41
+ }
42
+
43
+ exercises.each( function( slug ) {
44
+
45
+ generateReadme( arguments.slug );
46
+
47
+ } ); // End exercises.each()
48
+
49
+ }
50
+
51
+ private function generateReadme( required string slug ) {
52
+
53
+ var readmeContent = "";
54
+ var readMeFile = repoRootPath & "/exercises/" & arguments.slug & "/README.md";
55
+
56
+ if ( !fileExists(readMeFile) || overwriteExistingFiles) {
57
+
58
+ var spec = getSpec( arguments.slug );
59
+
60
+ readmeContent = "## #spec.name#" & chr( 10 ) & chr( 10 );
61
+ readmeContent = readmeContent & spec.description & chr( 10 );
62
+ readmeContent = readmeContent & getHints( arguments.slug ) & chr( 10 );
63
+ readmeContent = readmeContent & trackReadmeInsert & chr( 10 );
64
+ readmeContent = readmeContent & spec.credits & chr( 10 );
65
+ readmeContent = readmeContent & "#### Submitting Incomplete Solutions#chr( 10 )#It's possible to submit an incomplete solution so you can see how others have completed the exercise.#chr( 10 )#";
66
+
67
+ /* Write the file */
68
+ fileWrite( readMeFile , readmeContent );
69
+
70
+ print.greenLine( 'Readme generated!' )
71
+ .indentedYellowLine( readMeFile )
72
+ .toConsole();
73
+ }
74
+ else {
75
+ print.redLine("README.md already exists! Use the overwrite=true to overwrite the file.")
76
+ .indentedYellowLine( readMeFile )
77
+ .toConsole();
78
+ }
79
+
80
+ }
81
+
82
+ /**
83
+ *
84
+ * Get the optional .meta/hint.md content
85
+ *
86
+ */
87
+ private function getHints( required string slug ) {
88
+
89
+ var hintsFilePath = repoRootPath & "/exercises/" & arguments.slug & "/.meta/hints.md";
90
+ var hints = fileExists( hintsFilePath ) ? fileRead( hintsFilePath ) : "";
91
+
92
+ return hints;
93
+ }
94
+
95
+ private function getSpec( required string slug ) {
96
+
97
+ var spec = getExerciseMetadata( arguments.slug );
98
+
99
+ /* Use title from metadata.yml if provided else we must use the slug */
100
+ if ( len( spec.title )) {
101
+ spec.name = spec.title;
102
+ }
103
+ else {
104
+ spec.name = titleCaseSlug( arguments.slug );
105
+ }
106
+
107
+ spec.credits = getCredits( spec );
108
+ spec.description = getDescription( arguments.slug );
109
+
110
+ return spec;
111
+ }
112
+
113
+ /**
114
+ *
115
+ * Get the exercise description
116
+ *
117
+ */
118
+ private function getDescription( required string slug ) {
119
+
120
+ var descriptionFilePath = problemSpecsPath & "/exercises/" & arguments.slug & "/description.md";
121
+
122
+ return fileExists( descriptionFilePath ) ? trim( fileRead( descriptionFilePath ) ) : "";
123
+ }
124
+
125
+ /**
126
+ *
127
+ * Get the content for exercise credits
128
+ *
129
+ */
130
+ private function getCredits( required struct spec ) {
131
+
132
+ if ( spec.source_url == "" ) {
133
+ var credits = spec.source;
134
+ }
135
+ else if ( spec.source == "") {
136
+ var credits = "[#spec.source_url#](#spec.source_url#)";
137
+ }
138
+ else {
139
+ var credits = "#spec.source# [#spec.source_url#](#spec.source_url#)";
140
+ }
141
+
142
+ if ( len( credits ) ) {
143
+ credits = "#### Source" & chr( 10 ) & chr( 10 ) & credits & chr( 10 );
144
+ }
145
+
146
+ return credits;
147
+ }
148
+
149
+ /**
150
+ *
151
+ * Convert exercise slug to a title
152
+ *
153
+ */
154
+ private function titleCaseSlug( required string slug ) {
155
+ return trim( reReplace( arguments.slug, "(\b|-)([a-zA-Z])", " \u\2", "all" ) );
156
+ }
157
+
158
+ /**
159
+ *
160
+ * Get exercise metadata from metadata.yml in the problem-specifications
161
+ *
162
+ */
163
+ private struct function getExerciseMetadata( required string slug ) {
164
+
165
+ var metadataFilePath = problemSpecsPath & "/exercises/" & arguments.slug & "/metadata.yml";
166
+ var content = fileRead(metadataFilePath);
167
+ var metadata = {};
168
+
169
+ /* Get the title if provided in metadata.yml */
170
+ metadata.title = parseMetadata( "title", content );
171
+
172
+ /* Get the source of the exercise if provided in metadata.yml */
173
+ metadata.source = parseMetadata( "source", content );
174
+
175
+ /* Get the source url if provided in metadata.yml */
176
+ metadata.source_url = parseMetadata( "source_url", content );
177
+
178
+ return metadata;
179
+ }
180
+
181
+ /**
182
+ *
183
+ * Parse metadata from metadata.yml content
184
+ *
185
+ */
186
+ private string function parseMetadata( required string key, required string content ) {
187
+ var result = "";
188
+
189
+ var matches = reFindNoCase( "#arguments.key#: ""(.*?)""", content, 1, true );
190
+ if ( matches.pos.len() == 2 ) {
191
+ result = mid( content, matches.pos[2], matches.len[2]);
192
+ }
193
+
194
+ return result;
195
+ }
196
+
197
+ }
@@ -79,6 +79,12 @@ component {
79
79
  .params( 'GenerateTests', 'run', slug )
80
80
  .inWorkingDirectory( repoRootPath & '/tasks' )
81
81
  .run();
82
+
83
+ // Generate README.md
84
+ command( 'task run' )
85
+ .params( 'GenerateReadme', 'run', slug )
86
+ .inWorkingDirectory( repoRootPath & '/tasks' )
87
+ .run();
82
88
 
83
89
  }
84
90
 
@@ -64,7 +64,7 @@
64
64
  "optional_values",
65
65
  "strings"
66
66
  ],
67
- "unlocked_by": "null",
67
+ "unlocked_by": null,
68
68
  "uuid": "57f02d0e-7b75-473b-892d-26a7d980c4ce"
69
69
  },
70
70
  {
@@ -36,7 +36,7 @@ end;
36
36
 
37
37
  procedure YearTest.year_divisible_by_4_not_divisible_by_100_leap_year;
38
38
  begin
39
- assert.IsTrue(TYear.IsLeap(2020), 'Expected ''true'', 2020 is a leap year.');
39
+ assert.IsTrue(TYear.IsLeap(1996), 'Expected ''true'', 1996 is a leap year.');
40
40
  end;
41
41
 
42
42
  procedure YearTest.year_divisible_by_100_not_divisible_by_400_common_year;
@@ -1,6 +1,6 @@
1
1
  module Clock
2
2
 
3
- let mkClock hours minutes = failwith "You need to implement this function."
3
+ let create hours minutes = failwith "You need to implement this function."
4
4
 
5
5
  let add minutes clock = failwith "You need to implement this function."
6
6
 
@@ -1,96 +1,274 @@
1
+ // This file was auto-generated based on version 1.0.1 of the canonical data.
2
+
1
3
  module ClockTest
2
4
 
3
- open System
4
- open Xunit
5
5
  open FsUnit.Xunit
6
+ open Xunit
7
+
6
8
  open Clock
7
9
 
8
10
  [<Fact>]
9
- let ``Prints 8 o'clock`` () =
10
- let clock = mkClock 8 0
11
+ let ``On the hour`` () =
12
+ let clock = create 8 0
11
13
  display clock |> should equal "08:00"
12
14
 
13
- [<Fact(Skip = "Remove to run test")>]
14
- let ``Prints 9 o'clock`` () =
15
- let clock = mkClock 9 0
16
- display clock |> should equal "09:00"
17
-
18
- [<Fact(Skip = "Remove to run test")>]
19
- let ``Can print single-digit minutes`` () =
20
- let clock = mkClock 11 9
15
+ [<Fact(Skip = "Remove to run test")>]
16
+ let ``Past the hour`` () =
17
+ let clock = create 11 9
21
18
  display clock |> should equal "11:09"
22
19
 
23
20
  [<Fact(Skip = "Remove to run test")>]
24
- let ``Can print double-digit minutes`` () =
25
- let clock = mkClock 11 19
26
- display clock |> should equal "11:19"
21
+ let ``Midnight is zero hours`` () =
22
+ let clock = create 24 0
23
+ display clock |> should equal "00:00"
27
24
 
28
25
  [<Fact(Skip = "Remove to run test")>]
29
- let ``Can add minutes`` () =
30
- let clock = mkClock 10 0
31
- let added = clock |> add 3
32
- display added |> should equal "10:03"
26
+ let ``Hour rolls over`` () =
27
+ let clock = create 25 0
28
+ display clock |> should equal "01:00"
33
29
 
34
30
  [<Fact(Skip = "Remove to run test")>]
35
- let ``Can add over an hour`` () =
36
- let clock = mkClock 10 0
37
- let added = clock |> add 63
38
- display added |> should equal "11:03"
31
+ let ``Hour rolls over continuously`` () =
32
+ let clock = create 100 0
33
+ display clock |> should equal "04:00"
39
34
 
40
35
  [<Fact(Skip = "Remove to run test")>]
41
- let ``Can add over more than one day`` () =
42
- let clock = mkClock 10 0
43
- let added = clock |> add 7224
44
- display added |> should equal "10:24"
36
+ let ``Sixty minutes is next hour`` () =
37
+ let clock = create 1 60
38
+ display clock |> should equal "02:00"
45
39
 
46
40
  [<Fact(Skip = "Remove to run test")>]
47
- let ``Can subtract minutes`` () =
48
- let clock = mkClock 10 3
49
- let subtracted = clock |> subtract 3
50
- display subtracted |> should equal "10:00"
41
+ let ``Minutes roll over`` () =
42
+ let clock = create 0 160
43
+ display clock |> should equal "02:40"
51
44
 
52
45
  [<Fact(Skip = "Remove to run test")>]
53
- let ``Can subtract to previous hour`` () =
54
- let clock = mkClock 10 3
55
- let subtracted = clock |> subtract 30
56
- display subtracted |> should equal "09:33"
46
+ let ``Minutes roll over continuously`` () =
47
+ let clock = create 0 1723
48
+ display clock |> should equal "04:43"
57
49
 
58
50
  [<Fact(Skip = "Remove to run test")>]
59
- let ``Can subtract over an hour`` () =
60
- let clock = mkClock 10 3
61
- let subtracted = clock |> subtract 70
62
- display subtracted |> should equal "08:53"
51
+ let ``Hour and minutes roll over`` () =
52
+ let clock = create 25 160
53
+ display clock |> should equal "03:40"
63
54
 
64
55
  [<Fact(Skip = "Remove to run test")>]
65
- let ``Wraps around midnight`` () =
66
- let clock = mkClock 23 59
67
- let added = clock |> add 2
68
- display added |> should equal "00:01"
56
+ let ``Hour and minutes roll over continuously`` () =
57
+ let clock = create 201 3001
58
+ display clock |> should equal "11:01"
69
59
 
70
60
  [<Fact(Skip = "Remove to run test")>]
71
- let ``Wraps around midnight backwards`` () =
72
- let clock = mkClock 0 1
73
- let subtracted = clock |> subtract 2
74
- display subtracted |> should equal "23:59"
61
+ let ``Hour and minutes roll over to exactly midnight`` () =
62
+ let clock = create 72 8640
63
+ display clock |> should equal "00:00"
75
64
 
76
65
  [<Fact(Skip = "Remove to run test")>]
77
- let ``Midnight is zero hundred hours`` () =
78
- let clock = mkClock 24 0
79
- display clock |> should equal "00:00"
66
+ let ``Negative hour`` () =
67
+ let clock = create -1 15
68
+ display clock |> should equal "23:15"
80
69
 
81
70
  [<Fact(Skip = "Remove to run test")>]
82
- let ``Sixty minutes is next hour`` () =
83
- let clock = mkClock 1 60
84
- display clock |> should equal "02:00"
71
+ let ``Negative hour rolls over`` () =
72
+ let clock = create -25 0
73
+ display clock |> should equal "23:00"
74
+
75
+ [<Fact(Skip = "Remove to run test")>]
76
+ let ``Negative hour rolls over continuously`` () =
77
+ let clock = create -91 0
78
+ display clock |> should equal "05:00"
79
+
80
+ [<Fact(Skip = "Remove to run test")>]
81
+ let ``Negative minutes`` () =
82
+ let clock = create 1 -40
83
+ display clock |> should equal "00:20"
84
+
85
+ [<Fact(Skip = "Remove to run test")>]
86
+ let ``Negative minutes roll over`` () =
87
+ let clock = create 1 -160
88
+ display clock |> should equal "22:20"
89
+
90
+ [<Fact(Skip = "Remove to run test")>]
91
+ let ``Negative minutes roll over continuously`` () =
92
+ let clock = create 1 -4820
93
+ display clock |> should equal "16:40"
94
+
95
+ [<Fact(Skip = "Remove to run test")>]
96
+ let ``Negative hour and minutes both roll over`` () =
97
+ let clock = create -25 -160
98
+ display clock |> should equal "20:20"
99
+
100
+ [<Fact(Skip = "Remove to run test")>]
101
+ let ``Negative hour and minutes both roll over continuously`` () =
102
+ let clock = create -121 -5810
103
+ display clock |> should equal "22:10"
104
+
105
+ [<Fact(Skip = "Remove to run test")>]
106
+ let ``Add minutes`` () =
107
+ let clock = create 10 0
108
+ add 3 clock |> display |> should equal "10:03"
109
+
110
+ [<Fact(Skip = "Remove to run test")>]
111
+ let ``Add no minutes`` () =
112
+ let clock = create 6 41
113
+ add 0 clock |> display |> should equal "06:41"
114
+
115
+ [<Fact(Skip = "Remove to run test")>]
116
+ let ``Add to next hour`` () =
117
+ let clock = create 0 45
118
+ add 40 clock |> display |> should equal "01:25"
119
+
120
+ [<Fact(Skip = "Remove to run test")>]
121
+ let ``Add more than one hour`` () =
122
+ let clock = create 10 0
123
+ add 61 clock |> display |> should equal "11:01"
124
+
125
+ [<Fact(Skip = "Remove to run test")>]
126
+ let ``Add more than two hours with carry`` () =
127
+ let clock = create 0 45
128
+ add 160 clock |> display |> should equal "03:25"
129
+
130
+ [<Fact(Skip = "Remove to run test")>]
131
+ let ``Add across midnight`` () =
132
+ let clock = create 23 59
133
+ add 2 clock |> display |> should equal "00:01"
134
+
135
+ [<Fact(Skip = "Remove to run test")>]
136
+ let ``Add more than one day (1500 min = 25 hrs)`` () =
137
+ let clock = create 5 32
138
+ add 1500 clock |> display |> should equal "06:32"
139
+
140
+ [<Fact(Skip = "Remove to run test")>]
141
+ let ``Add more than two days`` () =
142
+ let clock = create 1 1
143
+ add 3500 clock |> display |> should equal "11:21"
144
+
145
+ [<Fact(Skip = "Remove to run test")>]
146
+ let ``Subtract minutes`` () =
147
+ let clock = create 10 3
148
+ add -3 clock |> display |> should equal "10:00"
149
+
150
+ [<Fact(Skip = "Remove to run test")>]
151
+ let ``Subtract to previous hour`` () =
152
+ let clock = create 10 3
153
+ add -30 clock |> display |> should equal "09:33"
154
+
155
+ [<Fact(Skip = "Remove to run test")>]
156
+ let ``Subtract more than an hour`` () =
157
+ let clock = create 10 3
158
+ add -70 clock |> display |> should equal "08:53"
159
+
160
+ [<Fact(Skip = "Remove to run test")>]
161
+ let ``Subtract across midnight`` () =
162
+ let clock = create 0 3
163
+ add -4 clock |> display |> should equal "23:59"
164
+
165
+ [<Fact(Skip = "Remove to run test")>]
166
+ let ``Subtract more than two hours`` () =
167
+ let clock = create 0 0
168
+ add -160 clock |> display |> should equal "21:20"
169
+
170
+ [<Fact(Skip = "Remove to run test")>]
171
+ let ``Subtract more than two hours with borrow`` () =
172
+ let clock = create 6 15
173
+ add -160 clock |> display |> should equal "03:35"
174
+
175
+ [<Fact(Skip = "Remove to run test")>]
176
+ let ``Subtract more than one day (1500 min = 25 hrs)`` () =
177
+ let clock = create 5 32
178
+ add -1500 clock |> display |> should equal "04:32"
179
+
180
+ [<Fact(Skip = "Remove to run test")>]
181
+ let ``Subtract more than two days`` () =
182
+ let clock = create 2 20
183
+ add -3000 clock |> display |> should equal "00:20"
184
+
185
+ [<Fact(Skip = "Remove to run test")>]
186
+ let ``Clocks with same time`` () =
187
+ let clock1 = create 15 37
188
+ let clock2 = create 15 37
189
+ clock1 = clock2 |> should equal true
190
+
191
+ [<Fact(Skip = "Remove to run test")>]
192
+ let ``Clocks a minute apart`` () =
193
+ let clock1 = create 15 36
194
+ let clock2 = create 15 37
195
+ clock1 = clock2 |> should equal false
196
+
197
+ [<Fact(Skip = "Remove to run test")>]
198
+ let ``Clocks an hour apart`` () =
199
+ let clock1 = create 14 37
200
+ let clock2 = create 15 37
201
+ clock1 = clock2 |> should equal false
85
202
 
86
203
  [<Fact(Skip = "Remove to run test")>]
87
- let ``Clocks with same time are equal`` () =
88
- let clock1 = mkClock 14 30
89
- let clock2 = mkClock 14 30
90
- clock1 |> should equal clock2
204
+ let ``Clocks with hour overflow`` () =
205
+ let clock1 = create 10 37
206
+ let clock2 = create 34 37
207
+ clock1 = clock2 |> should equal true
91
208
 
92
209
  [<Fact(Skip = "Remove to run test")>]
93
- let ``Overflown clocks with same time are equal`` () =
94
- let clock1 = mkClock 14 30
95
- let clock2 = mkClock 38 30
96
- clock1 |> should equal clock2
210
+ let ``Clocks with hour overflow by several days`` () =
211
+ let clock1 = create 3 11
212
+ let clock2 = create 99 11
213
+ clock1 = clock2 |> should equal true
214
+
215
+ [<Fact(Skip = "Remove to run test")>]
216
+ let ``Clocks with negative hour`` () =
217
+ let clock1 = create 22 40
218
+ let clock2 = create -2 40
219
+ clock1 = clock2 |> should equal true
220
+
221
+ [<Fact(Skip = "Remove to run test")>]
222
+ let ``Clocks with negative hour that wraps`` () =
223
+ let clock1 = create 17 3
224
+ let clock2 = create -31 3
225
+ clock1 = clock2 |> should equal true
226
+
227
+ [<Fact(Skip = "Remove to run test")>]
228
+ let ``Clocks with negative hour that wraps multiple times`` () =
229
+ let clock1 = create 13 49
230
+ let clock2 = create -83 49
231
+ clock1 = clock2 |> should equal true
232
+
233
+ [<Fact(Skip = "Remove to run test")>]
234
+ let ``Clocks with minute overflow`` () =
235
+ let clock1 = create 0 1
236
+ let clock2 = create 0 1441
237
+ clock1 = clock2 |> should equal true
238
+
239
+ [<Fact(Skip = "Remove to run test")>]
240
+ let ``Clocks with minute overflow by several days`` () =
241
+ let clock1 = create 2 2
242
+ let clock2 = create 2 4322
243
+ clock1 = clock2 |> should equal true
244
+
245
+ [<Fact(Skip = "Remove to run test")>]
246
+ let ``Clocks with negative minute`` () =
247
+ let clock1 = create 2 40
248
+ let clock2 = create 3 -20
249
+ clock1 = clock2 |> should equal true
250
+
251
+ [<Fact(Skip = "Remove to run test")>]
252
+ let ``Clocks with negative minute that wraps`` () =
253
+ let clock1 = create 4 10
254
+ let clock2 = create 5 -1490
255
+ clock1 = clock2 |> should equal true
256
+
257
+ [<Fact(Skip = "Remove to run test")>]
258
+ let ``Clocks with negative minute that wraps multiple times`` () =
259
+ let clock1 = create 6 15
260
+ let clock2 = create 6 -4305
261
+ clock1 = clock2 |> should equal true
262
+
263
+ [<Fact(Skip = "Remove to run test")>]
264
+ let ``Clocks with negative hours and minutes`` () =
265
+ let clock1 = create 7 32
266
+ let clock2 = create -12 -268
267
+ clock1 = clock2 |> should equal true
268
+
269
+ [<Fact(Skip = "Remove to run test")>]
270
+ let ``Clocks with negative hours and minutes that wrap`` () =
271
+ let clock1 = create 18 7
272
+ let clock2 = create -54 -11513
273
+ clock1 = clock2 |> should equal true
274
+