trackler 2.0.3.4 → 2.0.3.5

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/common/exercises/all-your-base/canonical-data.json +21 -21
  3. data/common/exercises/wordy/description.md +24 -38
  4. data/common/exercises/wordy/metadata.yml +1 -1
  5. data/lib/trackler/version.rb +1 -1
  6. data/tracks/c/config.json +10 -0
  7. data/tracks/c/exercises/meetup/makefile +15 -0
  8. data/tracks/c/exercises/meetup/src/example.c +139 -0
  9. data/tracks/c/exercises/meetup/src/example.h +7 -0
  10. data/tracks/c/exercises/meetup/test/test_meetup.c +223 -0
  11. data/tracks/c/exercises/meetup/test/vendor/unity.c +1300 -0
  12. data/tracks/c/exercises/meetup/test/vendor/unity.h +274 -0
  13. data/tracks/c/exercises/meetup/test/vendor/unity_internals.h +701 -0
  14. data/tracks/crystal/config.json +12 -0
  15. data/tracks/crystal/exercises/pascals-triangle/spec/pascals_triangle_spec.cr +30 -0
  16. data/tracks/crystal/exercises/pascals-triangle/src/example.cr +19 -0
  17. data/tracks/crystal/exercises/pascals-triangle/src/pascals_triangle.cr +1 -0
  18. data/tracks/crystal/exercises/run-length-encoding/spec/run_length_encoding_spec.cr +36 -0
  19. data/tracks/crystal/exercises/run-length-encoding/src/example.cr +40 -0
  20. data/tracks/crystal/src/generator/exercises/pascals-triangle.cr +58 -0
  21. data/tracks/crystal/src/generator/exercises/run_length_encoding.cr +42 -0
  22. data/tracks/javascript/config.json +8 -1
  23. data/tracks/javascript/exercises/all-your-base/all-your-base.spec.js +141 -0
  24. data/tracks/javascript/exercises/all-your-base/example.js +59 -0
  25. data/tracks/javascript/exercises/word-count/example.js +5 -5
  26. data/tracks/javascript/exercises/word-count/word-count.spec.js +23 -8
  27. data/tracks/lua/SETUP.md +60 -7
  28. data/tracks/lua/config.json +9 -0
  29. data/tracks/lua/exercises/say/example.lua +4 -4
  30. data/tracks/lua/exercises/variable-length-quantity/example.lua +36 -0
  31. data/tracks/lua/exercises/variable-length-quantity/variable-length-quantity_spec.lua +73 -0
  32. data/tracks/objective-c/.travis.yml +1 -0
  33. data/tracks/objective-c/config.json +8 -0
  34. data/tracks/objective-c/docs/TESTS.md +1 -1
  35. data/tracks/objective-c/exercises/transpose/TransposeExample.h +7 -0
  36. data/tracks/objective-c/exercises/transpose/TransposeExample.m +59 -0
  37. data/tracks/objective-c/exercises/transpose/TransposeTest.m +150 -0
  38. data/tracks/objective-c/xcodeProject/ObjectiveC.xcodeproj/project.pbxproj +18 -0
  39. data/tracks/ocaml/.gitignore +1 -0
  40. data/tracks/ocaml/tools/test-generator/Makefile +3 -0
  41. data/tracks/ocaml/tools/test-generator/src/controller.ml +11 -16
  42. data/tracks/ocaml/tools/test-generator/src/model.ml +4 -0
  43. data/tracks/ocaml/tools/test-generator/src/parser.ml +8 -1
  44. data/tracks/ocaml/tools/test-generator/src/special_cases.ml +5 -0
  45. data/tracks/ocaml/tools/test-generator/templates/all-your-base/template.ml +16 -0
  46. data/tracks/ocaml/tools/test-generator/test/model_test.ml +2 -0
  47. data/tracks/ocaml/tools/test-generator/test/parser_test.ml +8 -0
  48. data/tracks/perl5/docs/RESOURCES.md +57 -0
  49. data/tracks/perl5/exercises/hamming/Example.pm +7 -0
  50. data/tracks/perl5/exercises/hamming/hamming.t +17 -4
  51. data/tracks/perl5/exercises/rna-transcription/rna.t +4 -4
  52. data/tracks/perl6/.gitignore +2 -0
  53. data/tracks/perl6/config.json +5 -0
  54. data/tracks/perl6/exercises/phone-number/Example.pm +30 -0
  55. data/tracks/perl6/exercises/phone-number/cases.json +47 -0
  56. data/tracks/perl6/exercises/phone-number/phone.t +48 -0
  57. data/tracks/purescript/.gitignore +8 -0
  58. data/tracks/purescript/config.json +8 -3
  59. data/tracks/purescript/exercises/hello-world/bower.json +17 -0
  60. data/tracks/purescript/exercises/hello-world/examples/src/HelloWorld.purs +8 -0
  61. data/tracks/purescript/exercises/hello-world/src/HelloWorld.purs +6 -0
  62. data/tracks/purescript/exercises/hello-world/test/Main.purs +18 -0
  63. data/tracks/scala/exercises/leap/HINTS.md +4 -0
  64. data/tracks/scala/exercises/robot-name/HINTS.md +5 -0
  65. data/tracks/swift/docs/INSTALLATION.md +4 -1
  66. data/tracks/swift/exercises/accumulate/AccumulateTest.swift +1 -1
  67. data/tracks/swift/exercises/binary/BinaryExample.swift +4 -1
  68. data/tracks/swift/exercises/crypto-square/CryptoSquareExample.swift +3 -2
  69. data/tracks/swift/exercises/leap/LeapExample.swift +1 -3
  70. data/tracks/swift/exercises/pascals-triangle/PascalsTriangleTest.swift +1 -1
  71. data/tracks/swift/exercises/poker/PokerExample.swift +3 -3
  72. data/tracks/swift/exercises/poker/PokerTest.swift +38 -38
  73. data/tracks/swift/exercises/saddle-points/SaddlePointsTest.swift +1 -1
  74. data/tracks/swift/exercises/scrabble-score/ScrabbleScoreExample.swift +6 -3
  75. data/tracks/swift/exercises/series/SeriesTest.swift +1 -1
  76. data/tracks/swift/exercises/simple-linked-list/SimpleLinkedListExample.swift +2 -2
  77. data/tracks/swift/exercises/space-age/SpaceAgeExample.swift +10 -12
  78. data/tracks/swift/exercises/strain/StrainTest.swift +1 -1
  79. data/tracks/swift/exercises/tournament/TournamentExample.swift +2 -2
  80. data/tracks/swift/exercises/triangle/TriangleExample.swift +7 -3
  81. data/tracks/swift/exercises/wordy/WordyExample.swift +1 -2
  82. metadata +34 -3
  83. data/tracks/purescript/exercises/.keep +0 -0
@@ -4,15 +4,15 @@ function Words() {}
4
4
 
5
5
  Words.prototype.count = function (input) {
6
6
  var counts = {};
7
- var words = input.match(/\S+/g);
7
+ var words = input.toLowerCase()
8
+ .replace(/[,."\/!&@$%\^\*;:{}()¡¿?]/g, ' ')
9
+ .replace(/\s'(\w+)'\s/, ' '+'$1'+' ')
10
+ .match(/\S+/g);
8
11
 
9
12
  words.forEach(function (word) {
10
- var lcWord = word.toLowerCase();
11
- counts[lcWord] = counts.hasOwnProperty(lcWord) ? counts[lcWord] + 1 : 1;
13
+ counts[word] = counts.hasOwnProperty(word) ? counts[word] + 1 : 1;
12
14
  });
13
-
14
15
  return counts;
15
16
  };
16
17
 
17
18
  module.exports = Words;
18
-
@@ -8,19 +8,24 @@ describe('count()', function() {
8
8
  expect(words.count('word')).toEqual(expectedCounts);
9
9
  });
10
10
 
11
- xit('counts one of each', function() {
11
+ xit('counts one of each word', function() {
12
12
  var expectedCounts = { one: 1, of: 1, each: 1 };
13
13
  expect(words.count('one of each')).toEqual(expectedCounts);
14
14
  });
15
15
 
16
- xit('counts multiple occurrences', function() {
16
+ xit('counts multiple occurrences of a word', function() {
17
17
  var expectedCounts = { one: 1, fish: 4, two: 1, red: 1, blue: 1 };
18
18
  expect(words.count('one fish two fish red fish blue fish')).toEqual(expectedCounts);
19
19
  });
20
20
 
21
- xit('includes punctuation', function() {
22
- var expectedCounts = { car: 1, ':': 2, carpet: 1, as: 1, java: 1, 'javascript!!&@$%^&': 1 };
23
- expect(words.count('car : carpet as java : javascript!!&@$%^&')).toEqual(expectedCounts);
21
+ xit('handles cramped lists', function() {
22
+ var expectedCounts = { one: 1, two: 1, three: 1 };
23
+ expect(words.count('one,two,three')).toEqual(expectedCounts);
24
+ });
25
+
26
+ xit('ignores punctuation', function() {
27
+ var expectedCounts = { car: 1, carpet: 1, as: 1, java: 1, javascript: 1 };
28
+ expect(words.count('car : carpet as java: javascript!!&@$%^&')).toEqual(expectedCounts);
24
29
  });
25
30
 
26
31
  xit('includes numbers', function() {
@@ -33,8 +38,18 @@ describe('count()', function() {
33
38
  expect(words.count('go Go GO')).toEqual(expectedCounts);
34
39
  });
35
40
 
41
+ xit('counts words with apostrophes', function() {
42
+ var expectedCounts = { 'first': 1, 'don\'t': 2, 'laugh': 1, 'then': 1, 'cry': 1 };
43
+ expect(words.count('First: don\'t laugh. Then: don\'t cry.')).toEqual(expectedCounts);
44
+ });
45
+
46
+ xit('counts words with quotations', function() {
47
+ var expectedCounts = { 'joe': 1, 'can\'t': 1, 'tell': 1, 'between': 1, 'large': 2, 'and': 1 };
48
+ expect(words.count('Joe can\'t tell between \'large\' and large.')).toEqual(expectedCounts);
49
+ });
50
+
36
51
  xit('counts properly international characters', function() {
37
- var expectedCounts = { '¡hola!': 1, '¿qué': 1, 'tal?': 1, 'привет!': 1 };
52
+ var expectedCounts = { 'hola': 1, 'qué': 1, 'tal': 1, 'привет': 1 };
38
53
  expect(words.count('¡Hola! ¿Qué tal? Привет!')).toEqual(expectedCounts);
39
54
  });
40
55
 
@@ -43,7 +58,7 @@ describe('count()', function() {
43
58
  expect(words.count('hello\nworld')).toEqual(expectedCounts);
44
59
  });
45
60
 
46
- xit('counts tabs', function() {
61
+ xit('counts tabs as white space', function() {
47
62
  var expectedCounts = { hello: 1, world: 1 };
48
63
  expect(words.count('hello\tworld')).toEqual(expectedCounts);
49
64
  });
@@ -59,7 +74,7 @@ describe('count()', function() {
59
74
  });
60
75
 
61
76
  xit('handles properties that exist on Object’s prototype', function() {
62
- var expectedCounts = { reserved: 1, words: 1, like: 1, constructor: 1, and: 1, tostring: 1, 'ok?': 1 };
77
+ var expectedCounts = { reserved: 1, words: 1, like: 1, constructor: 1, and: 1, tostring: 1, ok: 1 };
63
78
  expect(words.count('reserved words like constructor and toString ok?')).toEqual(expectedCounts);
64
79
  });
65
80
  });
data/tracks/lua/SETUP.md CHANGED
@@ -1,17 +1,68 @@
1
1
  ### Getting started
2
- First install lua and [luarocks][2] using [homebrew][1]
2
+ #### MacOS
3
+ First install Lua and [Luarocks][2] using [Homebrew][1]:
3
4
 
4
- $ brew install lua
5
+ ```shell
6
+ $ brew install lua
7
+ ```
5
8
 
6
- Then install [busted][3] testing framework for lua
9
+ Then install the [Busted][3] testing framework for Lua:
7
10
 
8
- $ luarocks install busted
11
+ ```shell
12
+ $ luarocks install busted
13
+ ```
9
14
 
10
- Then run your test
15
+ Then run your tests:
11
16
 
12
- $ busted .
17
+ ```shell
18
+ $ busted .
19
+ ```
13
20
 
14
- Other resources
21
+ #### Ubuntu
22
+ First install Lua and [Luarocks][2] using [Apt][6]:
23
+
24
+ ```shell
25
+ $ sudo apt-get install lua5.3 luarocks
26
+ ```
27
+
28
+ Then install the [Busted][3] testing framework for Lua:
29
+
30
+ ```shell
31
+ $ luarocks install busted
32
+ ```
33
+
34
+ If this fails, you may need to use `sudo`:
35
+
36
+ ```shell
37
+ $ sudo luarocks install busted
38
+ ```
39
+
40
+ Then run your tests:
41
+
42
+ ```shell
43
+ $ busted .
44
+ ```
45
+
46
+ #### Windows
47
+ First install Lua and [Luarocks][2] using [Chocolatey][7]:
48
+
49
+ ```
50
+ C:\> choco install lua
51
+ ```
52
+
53
+ Then install the [Busted][3] testing framework for Lua:
54
+
55
+ ```
56
+ C:\> luarocks install busted
57
+ ```
58
+
59
+ Then run your tests:
60
+
61
+ ```
62
+ C:\> busted .
63
+ ```
64
+
65
+ #### Other resources
15
66
 
16
67
  1. [Lua Style Guide][4]
17
68
  2. [Learn Lua in 15 minutes][5]
@@ -21,3 +72,5 @@ Other resources
21
72
  [3]: http://olivinelabs.com/busted/
22
73
  [4]: https://github.com/Olivine-Labs/lua-style-guide
23
74
  [5]: http://tylerneylon.com/a/learn-lua/
75
+ [6]: https://help.ubuntu.com/lts/serverguide/apt.html
76
+ [7]: http://chocolatey.org/
@@ -54,6 +54,15 @@
54
54
  "topics": [
55
55
  "mathematics"
56
56
  ]
57
+ }, {
58
+ "slug": "variable-length-quantity",
59
+ "difficulty": 6,
60
+ "topics": [
61
+ "control-flow (if-else statements)",
62
+ "control-flow (loops)",
63
+ "bitwise operations",
64
+ "arrays"
65
+ ]
57
66
  }, {
58
67
  "slug": "anagram",
59
68
  "difficulty": 6,
@@ -67,7 +67,7 @@ end
67
67
  return function(n)
68
68
  if n < 0 or n > 999999999999 then return -1 end
69
69
 
70
- local blahs = {}
70
+ local groups = {}
71
71
  local group_index = 0
72
72
 
73
73
  while n > 0 do
@@ -77,16 +77,16 @@ return function(n)
77
77
  if group_name[group_index] then
78
78
  group = group .. ' ' .. group_name[group_index]
79
79
  end
80
- table.insert(blahs, 1, group)
80
+ table.insert(groups, 1, group)
81
81
  end
82
82
 
83
83
  n = n // 1000
84
84
  group_index = group_index + 1
85
85
  end
86
86
 
87
- if #blahs == 0 then
87
+ if #groups == 0 then
88
88
  return 'zero'
89
89
  else
90
- return table.concat(blahs, ' ')
90
+ return table.concat(groups, ' ')
91
91
  end
92
92
  end
@@ -0,0 +1,36 @@
1
+ local function decode(bytes)
2
+ local values = {}
3
+ local n = 0
4
+ for i, byte in ipairs(bytes) do
5
+ n = n << 7
6
+ n = n + (byte & 0x7f)
7
+ if byte & 0x80 == 0 then
8
+ table.insert(values, n)
9
+ n = 0
10
+ end
11
+ assert((i ~= #bytes) or (byte & 0x80 == 0), 'incomplete byte sequence')
12
+ end
13
+ return values
14
+ end
15
+
16
+ local function encode_single(n)
17
+ local bytes = { n & 0x7f }
18
+ n = n >> 7
19
+ while n > 0 do
20
+ table.insert(bytes, 1, n & 0x7f | 0x80)
21
+ n = n >> 7
22
+ end
23
+ return bytes
24
+ end
25
+
26
+ local function encode(values)
27
+ local bytes = {}
28
+ for _, value in ipairs(values) do
29
+ for _, byte in ipairs(encode_single(value)) do
30
+ table.insert(bytes, byte)
31
+ end
32
+ end
33
+ return bytes
34
+ end
35
+
36
+ return { decode = decode, encode = encode }
@@ -0,0 +1,73 @@
1
+ local vlq = require 'variable-length-quantity'
2
+
3
+ describe('variable-length-quantity', function()
4
+ it('should decode single bytes', function()
5
+ assert.are.same({ 0x00 }, vlq.decode({ 0x00 }))
6
+ assert.are.same({ 0x40 }, vlq.decode({ 0x40 }))
7
+ assert.are.same({ 0x7f }, vlq.decode({ 0x7f }))
8
+ end)
9
+
10
+ it('should decode double bytes', function()
11
+ assert.are.same({ 0x80 }, vlq.decode({ 0x81, 0x00 }))
12
+ assert.are.same({ 0x2000 }, vlq.decode({ 0xc0, 0x00 }))
13
+ assert.are.same({ 0x3fff }, vlq.decode({ 0xff, 0x7f }))
14
+ end)
15
+
16
+ it('should decode triple bytes', function()
17
+ assert.are.same({ 0x4000 }, vlq.decode({ 0x81, 0x80, 0x00 }))
18
+ assert.are.same({ 0x100000 }, vlq.decode({ 0xc0, 0x80, 0x00 }))
19
+ assert.are.same({ 0x1fffff }, vlq.decode({ 0xff, 0xff, 0x7f }))
20
+ end)
21
+
22
+ it('should decode quadruple bytes', function()
23
+ assert.are.same({ 0x200000 }, vlq.decode({ 0x81, 0x80, 0x80, 0x00 }))
24
+ assert.are.same({ 0x08000000 }, vlq.decode({ 0xc0, 0x80, 0x80, 0x00 }))
25
+ assert.are.same({ 0x0fffffff }, vlq.decode({ 0xff, 0xff, 0xff, 0x7f }))
26
+ end)
27
+
28
+ it('should decode multiple values', function()
29
+ assert.are.same(
30
+ { 0x2000, 0x123456, 0x0fffffff, 0x00, 0x3fff, 0x4000 },
31
+ vlq.decode({ 0xc0, 0x00, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0x81, 0x80, 0x00 })
32
+ )
33
+ end)
34
+
35
+ it('should encode single bytes', function()
36
+ assert.are.same({ 0x00 }, vlq.encode({ 0x00 }))
37
+ assert.are.same({ 0x40 }, vlq.encode({ 0x40 }))
38
+ assert.are.same({ 0x7f }, vlq.encode({ 0x7f }))
39
+ end)
40
+
41
+ it('should encode double bytes', function()
42
+ assert.are.same({ 0x81, 0x00 }, vlq.encode({ 0x80 }))
43
+ assert.are.same({ 0xc0, 0x00 }, vlq.encode({ 0x2000 }))
44
+ assert.are.same({ 0xff, 0x7f }, vlq.encode({ 0x3fff }))
45
+ end)
46
+
47
+ it('should encode triple bytes', function()
48
+ assert.are.same({ 0x81, 0x80, 0x00 }, vlq.encode({ 0x4000 }))
49
+ assert.are.same({ 0xc0, 0x80, 0x00 }, vlq.encode({ 0x100000 }))
50
+ assert.are.same({ 0xff, 0xff, 0x7f }, vlq.encode({ 0x1fffff }))
51
+ end)
52
+
53
+ it('should encode quadruple bytes', function()
54
+ assert.are.same({ 0x81, 0x80, 0x80, 0x00 }, vlq.encode({ 0x200000 }))
55
+ assert.are.same({ 0xc0, 0x80, 0x80, 0x00 }, vlq.encode({ 0x08000000 }))
56
+ assert.are.same({ 0xff, 0xff, 0xff, 0x7f }, vlq.encode({ 0x0fffffff }))
57
+ end)
58
+
59
+ it('should encode multiple values', function()
60
+ assert.are.same({ 0x40, 0x7f }, vlq.encode({ 0x40, 0x7f }))
61
+ assert.are.same({ 0x81, 0x80, 0x00, 0xc8, 0xe8, 0x56 }, vlq.encode({ 0x4000, 0x123456 }))
62
+ assert.are.same(
63
+ { 0xc0, 0x00, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x00, 0xff, 0x7f, 0x81, 0x80, 0x00 },
64
+ vlq.encode({ 0x2000, 0x123456, 0x0fffffff, 0x00, 0x3fff, 0x4000 })
65
+ )
66
+ end)
67
+
68
+ it('should raise an error when decoding an incomplete byte sequence', function()
69
+ assert.has.error(function()
70
+ vlq.decode({ 0x81, 0x00, 0x80 })
71
+ end, 'incomplete byte sequence')
72
+ end)
73
+ end)
@@ -3,6 +3,7 @@ osx_image: xcode7.3
3
3
  xcode_project: 'xcodeProject/ObjectiveC.xcodeproj'
4
4
  xcode_scheme: 'xobjectivecTest'
5
5
  before_install:
6
+ - gem install bundler
6
7
  - gem install danger
7
8
  - brew cask uninstall oclint
8
9
  - brew tap oclint/formulae
@@ -218,6 +218,14 @@
218
218
  "Searching",
219
219
  "Transforming"
220
220
  ]
221
+ },
222
+ {
223
+ "difficulty": 4,
224
+ "slug": "transpose",
225
+ "topics": [
226
+ "Strings",
227
+ "Transforming"
228
+ ]
221
229
  },
222
230
  {
223
231
  "difficulty": 5,
@@ -42,6 +42,6 @@ Run the tests with:
42
42
  $ objc ExerciseName
43
43
  ```
44
44
 
45
- The objc utility uses the exercise name to find the test file, `ExerciseNameTest.m`, the header file, `ExerciseName.h` and source file `ExerciseNameTest.m`. The files are inserted into a temporary Xcode Project and then `xctool` is used to run the tests for the project.
45
+ The objc utility uses the exercise name to find the test file, `ExerciseNameTest.m`, the header file, `ExerciseName.h` and source file `ExerciseName.m`. The files are inserted into a temporary Xcode Project and then `xctool` is used to run the tests for the project.
46
46
 
47
47
  While `objc` makes it so you never have to launch Xcode to complete these exercises, the error messages and feedback through the command-line are not as clear as through the Xcode user interface.
@@ -0,0 +1,7 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ @interface Transpose : NSObject
4
+
5
+ + (NSArray<NSString *> *)transpose:(NSArray<NSString *> *)input;
6
+
7
+ @end
@@ -0,0 +1,59 @@
1
+ #import "TransposeExample.h"
2
+
3
+ @implementation Transpose
4
+
5
+ + (NSArray<NSString *> *)transpose:(NSArray<NSString *> *)input {
6
+ int maxLength = 0;
7
+
8
+ for (NSString *line in input) {
9
+ if (line.length > maxLength) {
10
+ maxLength = (int)line.length;
11
+ }
12
+ }
13
+
14
+ NSMutableArray<NSString *> *result = [NSMutableArray arrayWithCapacity:maxLength];
15
+
16
+ for (int i = 0; i < maxLength; i++) {
17
+ [result addObject:@""];
18
+
19
+ for (NSString *line in input) {
20
+ NSString *character;
21
+
22
+ if (i < line.length) {
23
+ character = [line substringWithRange:NSMakeRange(i, 1)];
24
+ } else {
25
+ character = @" ";
26
+ }
27
+
28
+ result[i] = [result[i] stringByAppendingString:character];
29
+ }
30
+ }
31
+
32
+ NSMutableArray<NSString *> *trimmedResult = [[NSMutableArray alloc] init];
33
+
34
+ for (NSString *line in result) {
35
+ [trimmedResult addObject:[self stringByTrimmingTrailingWhiteSpace:line]];
36
+ }
37
+
38
+ return trimmedResult;
39
+ }
40
+
41
+ + (NSString *)stringByTrimmingTrailingWhiteSpace:(NSString *)string {
42
+ NSUInteger location = 0;
43
+ NSUInteger length = [string length];
44
+ unichar charBuffer[length];
45
+ [string getCharacters:charBuffer];
46
+
47
+ NSCharacterSet *characterSet = [NSCharacterSet whitespaceCharacterSet];
48
+
49
+ while (length > 0) {
50
+ if (![characterSet characterIsMember:charBuffer[length - 1]]) {
51
+ break;
52
+ }
53
+ length--;
54
+ }
55
+
56
+ return [string substringWithRange:NSMakeRange(location, length - location)];
57
+ }
58
+
59
+ @end
@@ -0,0 +1,150 @@
1
+ #import <XCTest/XCTest.h>
2
+
3
+ #if __has_include("TransposeExample.h")
4
+ # import "TransposeExample.h"
5
+ # else
6
+ # import "Transpose.h"
7
+ #endif
8
+
9
+ @interface TransposeTest : XCTestCase
10
+
11
+ @end
12
+
13
+ @implementation TransposeTest
14
+
15
+ - (void)testEmptyInput {
16
+ XCTAssertEqualObjects([Transpose transpose:@[]], @[]);
17
+ }
18
+
19
+ - (void)testTwoCharactersInARow {
20
+ NSArray<NSString *> *input = @[@"A1"];
21
+ NSArray<NSString *> *expected = @[@"A", @"1"];
22
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
23
+ }
24
+
25
+ - (void)testTwoCharactersInAColumn {
26
+ NSArray<NSString *> *input = @[@"A", @"1"];
27
+ NSArray<NSString *> *expected = @[@"A1"];
28
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
29
+ }
30
+
31
+ - (void)testSimple {
32
+ NSArray<NSString *> *input = @[@"ABC", @"123"];
33
+ NSArray<NSString *> *expected = @[@"A1", @"B2", @"C3"];
34
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
35
+ }
36
+
37
+ - (void)testSingleLine {
38
+ NSArray<NSString *> *input = @[@"Single line."];
39
+ NSArray<NSString *> *expected = @[@"S", @"i", @"n", @"g", @"l", @"e", @"", @"l", @"i", @"n", @"e", @"."];
40
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
41
+ }
42
+
43
+ - (void)testFirstLineLongerThanSecondLine {
44
+ NSArray<NSString *> *input = @[@"The fourth line.", @"The fifth line."];
45
+ NSArray<NSString *> *expected = @[@"TT", @"hh", @"ee", @"", @"ff", @"oi", @"uf", @"rt", @"th", @"h", @" l", @"li", @"in", @"ne", @"e.", @"."];
46
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
47
+ }
48
+
49
+ - (void)testSecondLineLongerThanFirstLine {
50
+ NSArray<NSString *> *input = @[@"The first line.", @"The second line."];
51
+ NSArray<NSString *> *expected = @[@"TT", @"hh", @"ee", @"", @"fs", @"ie", @"rc", @"so", @"tn", @" d", @"l", @"il", @"ni", @"en", @".e", @" ."];
52
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
53
+ }
54
+
55
+ - (void)testSquare {
56
+ NSArray<NSString *> *input = @[@"HEART", @"EMBER", @"ABUSE", @"RESIN", @"TREND"];
57
+ NSArray<NSString *> *expected = @[@"HEART", @"EMBER", @"ABUSE", @"RESIN", @"TREND"];
58
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
59
+ }
60
+
61
+ - (void)testRectangle {
62
+ NSArray<NSString *> *input = @[@"FRACTURE", @"OUTLINED", @"BLOOMING", @"SEPTETTE"];
63
+ NSArray<NSString *> *expected = @[@"FOBS", @"RULE", @"ATOP", @"CLOT", @"TIME", @"UNIT", @"RENT", @"EDGE"];
64
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
65
+ }
66
+
67
+ - (void)testTriangle {
68
+ NSArray<NSString *> *input = @[@"T", @"EE", @"AAA", @"SSSS", @"EEEEE", @"RRRRRR"];
69
+ NSArray<NSString *> *expected = @[@"TEASER", @" EASER", @" ASER", @" SER", @" ER", @" R"];
70
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
71
+ }
72
+
73
+ - (void)testManyLines {
74
+ NSArray<NSString *> *input = @[@"Chor. Two households, both alike in dignity,",
75
+ @"In fair Verona, where we lay our scene,",
76
+ @"From ancient grudge break to new mutiny,",
77
+ @"Where civil blood makes civil hands unclean.",
78
+ @"From forth the fatal loins of these two foes",
79
+ @"A pair of star-cross'd lovers take their life;",
80
+ @"Whose misadventur'd piteous overthrows",
81
+ @"Doth with their death bury their parents' strife.",
82
+ @"The fearful passage of their death-mark'd love,",
83
+ @"And the continuance of their parents' rage,",
84
+ @"Which, but their children's end, naught could remove,",
85
+ @"Is now the two hours' traffic of our stage;",
86
+ @"The which if you with patient ears attend,",
87
+ @"What here shall miss, our toil shall strive to mend."
88
+ ];
89
+
90
+ NSArray<NSString *> *expected = @[
91
+ @"CIFWFAWDTAWITW",
92
+ @"hnrhr hohnhshh",
93
+ @"o oeopotedi ea",
94
+ @"rfmrmash cn t",
95
+ @".a e ie fthow",
96
+ @" ia fr weh,whh",
97
+ @"Trnco miae ie",
98
+ @"w ciroitr btcr",
99
+ @"oVivtfshfcuhhe",
100
+ @" eeih a uote",
101
+ @"hrnl sdtln is",
102
+ @"oot ttvh tttfh",
103
+ @"un bhaeepihw a",
104
+ @"saglernianeoyl",
105
+ @"e,ro -trsui ol",
106
+ @"h uofcu sarhu",
107
+ @"owddarrdan o m",
108
+ @"lhg to'egccuwi",
109
+ @"deemasdaeehris",
110
+ @"sr als t ists",
111
+ @",ebk 'phool'h,",
112
+ @" reldi ffd",
113
+ @"bweso tb rtpo",
114
+ @"oea ileutterau",
115
+ @"t kcnoorhhnatr",
116
+ @"hl isvuyee'fi",
117
+ @" atv es iisfet",
118
+ @"ayoior trr ino",
119
+ @"l lfsoh ecti",
120
+ @"ion vedpn l",
121
+ @"kuehtteieadoe",
122
+ @"erwaharrar,fas",
123
+ @" nekt te rh",
124
+ @"ismdsehphnnosa",
125
+ @"ncuse ra-tau l",
126
+ @" et tormsural",
127
+ @"dniuthwea'g t",
128
+ @"iennwesnr hsts",
129
+ @"g,ycoi tkrttet",
130
+ @"n ,l r s'a anr",
131
+ @"i ef 'dgcgdi",
132
+ @"t aol eoe,v",
133
+ @"y nei sl,u; e",
134
+ @", .sf to l",
135
+ @" e rv d t",
136
+ @" ; ie o",
137
+ @" f, r",
138
+ @" e e m",
139
+ @" . m e",
140
+ @" o n",
141
+ @" v d",
142
+ @" e .",
143
+ @" ,"
144
+ ];
145
+
146
+ XCTAssertEqualObjects([Transpose transpose:input], expected);
147
+ }
148
+
149
+
150
+ @end