trackler 2.2.1.52 → 2.2.1.53

Sign up to get free protection for your applications and to get access to all the features.
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
+