trackler 2.0.8.13 → 2.0.8.14
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/common/exercises/acronym/canonical-data.json +50 -39
- data/common/exercises/all-your-base/canonical-data.json +192 -146
- data/common/exercises/allergies/canonical-data.json +133 -93
- data/common/exercises/anagram/canonical-data.json +128 -106
- data/common/exercises/atbash-cipher/canonical-data.json +92 -74
- data/common/exercises/binary/canonical-data.json +94 -77
- data/common/exercises/bob/canonical-data.json +154 -127
- data/common/exercises/book-store/canonical-data.json +106 -92
- data/common/exercises/change/canonical-data.json +80 -68
- data/common/exercises/grains/canonical-data.json +75 -60
- data/common/exercises/hello-world/canonical-data.json +6 -6
- data/common/exercises/leap/canonical-data.json +28 -22
- data/common/exercises/luhn/canonical-data.json +16 -1
- data/common/exercises/pig-latin/canonical-data.json +93 -75
- data/common/exercises/raindrops/canonical-data.json +112 -92
- data/common/exercises/rna-transcription/canonical-data.json +64 -54
- data/common/exercises/run-length-encoding/canonical-data.json +20 -0
- data/common/exercises/run-length-encoding/description.md +3 -7
- data/common/exercises/say/canonical-data.json +98 -81
- data/common/exercises/scrabble-score/canonical-data.json +13 -0
- data/common/exercises/sieve/canonical-data.json +48 -42
- data/common/exercises/trinary/canonical-data.json +75 -60
- data/common/exercises/word-count/canonical-data.json +116 -54
- data/common/exercises/wordy/canonical-data.json +101 -83
- data/lib/trackler/version.rb +1 -1
- data/tracks/delphi/SETUP.md +10 -1
- data/tracks/delphi/config.json +8 -0
- data/tracks/delphi/docs/TESTS.md +4 -0
- data/tracks/delphi/exercises/hello-world/uTestHelloWorld.pas +49 -27
- data/tracks/delphi/exercises/triangle/Triangle.dpr +60 -0
- data/tracks/delphi/exercises/triangle/uTestTriangle.pas +186 -0
- data/tracks/delphi/exercises/triangle/uTriangleExample.pas +64 -0
- data/tracks/go/exercises/poker/poker_test.go +6 -6
- data/tracks/java/exercises/atbash-cipher/src/test/java/AtbashTest.java +2 -1
- data/tracks/scala/config.json +10 -0
- data/tracks/scala/exercises/variable-length-quantity/HINTS.md +2 -0
- data/tracks/scala/exercises/variable-length-quantity/build.sbt +3 -0
- data/tracks/scala/exercises/variable-length-quantity/example.scala +56 -0
- data/tracks/scala/exercises/variable-length-quantity/src/main/scala/VariableLengthQuantity.scala +0 -0
- data/tracks/scala/exercises/variable-length-quantity/src/test/scala/VariableLengthQuantityTest.scala +162 -0
- data/tracks/scala/testgen/src/main/scala/VariableLengthQuantityTestGenerator.scala +80 -0
- data/tracks/typescript/common/package.json +6 -7
- data/tracks/typescript/common/yarn.lock +422 -380
- data/tracks/typescript/config.json +12 -0
- data/tracks/typescript/exercises/anagram/package.json +6 -7
- data/tracks/typescript/exercises/anagram/yarn.lock +422 -380
- data/tracks/typescript/exercises/beer-song/package.json +6 -7
- data/tracks/typescript/exercises/beer-song/yarn.lock +422 -380
- data/tracks/typescript/exercises/bob/package.json +6 -7
- data/tracks/typescript/exercises/bob/yarn.lock +422 -380
- data/tracks/typescript/exercises/food-chain/package.json +6 -7
- data/tracks/typescript/exercises/food-chain/yarn.lock +422 -380
- data/tracks/typescript/exercises/gigasecond/package.json +6 -7
- data/tracks/typescript/exercises/gigasecond/yarn.lock +422 -380
- data/tracks/typescript/exercises/grade-school/grade-school.example.ts +31 -0
- data/tracks/typescript/exercises/grade-school/grade-school.test.ts +81 -0
- data/tracks/typescript/exercises/grade-school/package.json +36 -0
- data/tracks/typescript/exercises/grade-school/tsconfig.json +21 -0
- data/tracks/typescript/exercises/grade-school/tslint.json +127 -0
- data/tracks/typescript/exercises/grade-school/yarn.lock +2739 -0
- data/tracks/typescript/exercises/hamming/package.json +6 -7
- data/tracks/typescript/exercises/hamming/yarn.lock +422 -380
- data/tracks/typescript/exercises/hello-world/package.json +6 -7
- data/tracks/typescript/exercises/hello-world/yarn.lock +422 -380
- data/tracks/typescript/exercises/leap/package.json +6 -7
- data/tracks/typescript/exercises/leap/yarn.lock +422 -380
- data/tracks/typescript/exercises/pangram/package.json +6 -7
- data/tracks/typescript/exercises/pangram/yarn.lock +422 -380
- data/tracks/typescript/exercises/phone-number/package.json +6 -7
- data/tracks/typescript/exercises/phone-number/yarn.lock +422 -380
- data/tracks/typescript/exercises/rna-transcription/package.json +6 -7
- data/tracks/typescript/exercises/rna-transcription/yarn.lock +422 -380
- data/tracks/typescript/exercises/robot-name/package.json +36 -0
- data/tracks/typescript/exercises/robot-name/robot-name.example.ts +36 -0
- data/tracks/typescript/exercises/robot-name/robot-name.test.ts +86 -0
- data/tracks/typescript/exercises/robot-name/tsconfig.json +21 -0
- data/tracks/typescript/exercises/robot-name/tslint.json +127 -0
- data/tracks/typescript/exercises/robot-name/yarn.lock +2739 -0
- data/tracks/typescript/exercises/say/package.json +6 -7
- data/tracks/typescript/exercises/say/yarn.lock +422 -380
- data/tracks/typescript/exercises/word-count/package.json +6 -7
- data/tracks/typescript/exercises/word-count/yarn.lock +422 -380
- data/tracks/typescript/exercises/wordy/package.json +6 -7
- data/tracks/typescript/exercises/wordy/yarn.lock +422 -380
- metadata +23 -2
@@ -0,0 +1,60 @@
|
|
1
|
+
program Triangle;
|
2
|
+
|
3
|
+
{$IFNDEF TESTINSIGHT}
|
4
|
+
{$APPTYPE CONSOLE}
|
5
|
+
{$ENDIF}{$STRONGLINKTYPES ON}
|
6
|
+
uses
|
7
|
+
System.SysUtils,
|
8
|
+
{$IFDEF TESTINSIGHT}
|
9
|
+
TestInsight.DUnitX,
|
10
|
+
{$ENDIF }
|
11
|
+
DUnitX.Loggers.Console,
|
12
|
+
DUnitX.Loggers.Xml.NUnit,
|
13
|
+
DUnitX.TestFramework,
|
14
|
+
uTestTriangle in 'uTestTriangle.pas',
|
15
|
+
uTriangle in 'uTriangle.pas';
|
16
|
+
|
17
|
+
var
|
18
|
+
runner : ITestRunner;
|
19
|
+
results : IRunResults;
|
20
|
+
logger : ITestLogger;
|
21
|
+
nunitLogger : ITestLogger;
|
22
|
+
begin
|
23
|
+
{$IFDEF TESTINSIGHT}
|
24
|
+
TestInsight.DUnitX.RunRegisteredTests;
|
25
|
+
exit;
|
26
|
+
{$ENDIF}
|
27
|
+
try
|
28
|
+
//Check command line options, will exit if invalid
|
29
|
+
TDUnitX.CheckCommandLine;
|
30
|
+
//Create the test runner
|
31
|
+
runner := TDUnitX.CreateRunner;
|
32
|
+
//Tell the runner to use RTTI to find Fixtures
|
33
|
+
runner.UseRTTI := True;
|
34
|
+
//tell the runner how we will log things
|
35
|
+
//Log to the console window
|
36
|
+
logger := TDUnitXConsoleLogger.Create(true);
|
37
|
+
runner.AddLogger(logger);
|
38
|
+
//Generate an NUnit compatible XML File
|
39
|
+
nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile);
|
40
|
+
runner.AddLogger(nunitLogger);
|
41
|
+
runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests;
|
42
|
+
|
43
|
+
//Run tests
|
44
|
+
results := runner.Execute;
|
45
|
+
if not results.AllPassed then
|
46
|
+
System.ExitCode := EXIT_ERRORS;
|
47
|
+
|
48
|
+
{$IFNDEF CI}
|
49
|
+
//We don't want this happening when running under CI.
|
50
|
+
if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then
|
51
|
+
begin
|
52
|
+
System.Write('Done.. press <Enter> key to quit.');
|
53
|
+
System.Readln;
|
54
|
+
end;
|
55
|
+
{$ENDIF}
|
56
|
+
except
|
57
|
+
on E: Exception do
|
58
|
+
System.Writeln(E.ClassName, ': ', E.Message);
|
59
|
+
end;
|
60
|
+
end.
|
@@ -0,0 +1,186 @@
|
|
1
|
+
unit uTestTriangle;
|
2
|
+
|
3
|
+
interface
|
4
|
+
uses
|
5
|
+
DUnitX.TestFramework;
|
6
|
+
|
7
|
+
type
|
8
|
+
[TestFixture('Equilateral')]
|
9
|
+
EquilateralTests = class(TObject)
|
10
|
+
public
|
11
|
+
[Test]
|
12
|
+
// [Ignore('Comment the "[Ignore]" statement to run the test')]
|
13
|
+
procedure True_if_all_sides_are_equal;
|
14
|
+
|
15
|
+
[Test]
|
16
|
+
[Ignore]
|
17
|
+
procedure False_if_any_side_is_unequal;
|
18
|
+
|
19
|
+
[Test]
|
20
|
+
[Ignore]
|
21
|
+
procedure False_if_no_sides_are_equal;
|
22
|
+
|
23
|
+
[Test]
|
24
|
+
[Ignore]
|
25
|
+
procedure All_zero_sides_are_illegal_so_the_triangle_is_not_equilateral;
|
26
|
+
|
27
|
+
[Test]
|
28
|
+
[Ignore]
|
29
|
+
procedure Sides_may_be_floats;
|
30
|
+
end;
|
31
|
+
|
32
|
+
[TestFixture('Isosceles')]
|
33
|
+
IsoscelesTests = class(TObject)
|
34
|
+
public
|
35
|
+
[Test]
|
36
|
+
[Ignore]
|
37
|
+
procedure True_if_last_two_sides_are_equal;
|
38
|
+
|
39
|
+
[Test]
|
40
|
+
[Ignore]
|
41
|
+
procedure True_if_first_two_sides_are_equal;
|
42
|
+
|
43
|
+
[Test]
|
44
|
+
[Ignore]
|
45
|
+
procedure True_if_first_and_last_sides_are_equal;
|
46
|
+
|
47
|
+
[Test]
|
48
|
+
[Ignore]
|
49
|
+
procedure Equilateral_triangles_are_also_isosceles;
|
50
|
+
|
51
|
+
[Test]
|
52
|
+
[Ignore]
|
53
|
+
procedure False_if_no_sides_are_equal;
|
54
|
+
|
55
|
+
[Test]
|
56
|
+
[Ignore]
|
57
|
+
procedure Sides_that_violate_triangle_inequality_are_not_isosceles_even_if_two_are_equal;
|
58
|
+
|
59
|
+
[Test]
|
60
|
+
[Ignore]
|
61
|
+
procedure Sides_may_be_floats;
|
62
|
+
end;
|
63
|
+
|
64
|
+
[TestFixture('Scalene')]
|
65
|
+
ScaleneTests = class(TObject)
|
66
|
+
public
|
67
|
+
[Test]
|
68
|
+
[Ignore]
|
69
|
+
procedure True_if_no_sides_are_equal;
|
70
|
+
|
71
|
+
[Test]
|
72
|
+
[Ignore]
|
73
|
+
procedure False_if_all_sides_are_equal;
|
74
|
+
|
75
|
+
[Test]
|
76
|
+
[Ignore]
|
77
|
+
procedure False_if_two_sides_are_equal;
|
78
|
+
|
79
|
+
[Test]
|
80
|
+
[Ignore]
|
81
|
+
procedure Sides_that_violate_triangle_inequality_are_not_scalene_even_if_they_are_all_different;
|
82
|
+
|
83
|
+
[Test]
|
84
|
+
[Ignore]
|
85
|
+
procedure Sides_may_be_floats;
|
86
|
+
end;
|
87
|
+
|
88
|
+
implementation
|
89
|
+
uses uTriangle;
|
90
|
+
|
91
|
+
{$region 'EquilateralTests'}
|
92
|
+
procedure EquilateralTests.True_if_all_sides_are_equal;
|
93
|
+
begin
|
94
|
+
Assert.AreEqual(true, Triangle.Sides(Equilateral, 2, 2, 2));
|
95
|
+
end;
|
96
|
+
|
97
|
+
procedure EquilateralTests.False_if_any_side_is_unequal;
|
98
|
+
begin
|
99
|
+
Assert.AreEqual(false, Triangle.Sides(Equilateral, 2, 3, 2));
|
100
|
+
end;
|
101
|
+
|
102
|
+
procedure EquilateralTests.False_if_no_sides_are_equal;
|
103
|
+
begin
|
104
|
+
Assert.AreEqual(false, Triangle.Sides(Equilateral, 5, 4, 6));
|
105
|
+
end;
|
106
|
+
|
107
|
+
procedure EquilateralTests.All_zero_sides_are_illegal_so_the_triangle_is_not_equilateral;
|
108
|
+
begin
|
109
|
+
Assert.AreEqual(false, Triangle.Sides(Equilateral, 0, 0, 0));
|
110
|
+
end;
|
111
|
+
|
112
|
+
procedure EquilateralTests.Sides_may_be_floats;
|
113
|
+
begin
|
114
|
+
Assert.AreEqual(true, Triangle.Sides(Equilateral, 0.5, 0.5, 0.5));
|
115
|
+
end;
|
116
|
+
{$endregion}
|
117
|
+
|
118
|
+
{$region'IsoscelesTests'}
|
119
|
+
procedure IsoscelesTests.True_if_last_two_sides_are_equal;
|
120
|
+
begin
|
121
|
+
Assert.AreEqual(true, Triangle.Sides(Isosceles, 3, 4, 4));
|
122
|
+
end;
|
123
|
+
|
124
|
+
procedure IsoscelesTests.True_if_first_two_sides_are_equal;
|
125
|
+
begin
|
126
|
+
Assert.AreEqual(true, Triangle.Sides(Isosceles, 4, 4, 3));
|
127
|
+
end;
|
128
|
+
|
129
|
+
procedure IsoscelesTests.True_if_first_and_last_sides_are_equal;
|
130
|
+
begin
|
131
|
+
Assert.AreEqual(true, Triangle.Sides(Isosceles, 4, 3, 4));
|
132
|
+
end;
|
133
|
+
|
134
|
+
procedure IsoscelesTests.Equilateral_triangles_are_also_isosceles;
|
135
|
+
begin
|
136
|
+
Assert.AreEqual(true, Triangle.Sides(Isosceles, 4, 4, 4));
|
137
|
+
end;
|
138
|
+
|
139
|
+
procedure IsoscelesTests.False_if_no_sides_are_equal;
|
140
|
+
begin
|
141
|
+
Assert.AreEqual(false, Triangle.Sides(Isosceles, 2, 3, 4));
|
142
|
+
end;
|
143
|
+
|
144
|
+
procedure IsoscelesTests.Sides_that_violate_triangle_inequality_are_not_isosceles_even_if_two_are_equal;
|
145
|
+
begin
|
146
|
+
Assert.AreEqual(false, Triangle.Sides(Isosceles, 1, 1, 3));
|
147
|
+
end;
|
148
|
+
|
149
|
+
procedure IsoscelesTests.Sides_may_be_floats;
|
150
|
+
begin
|
151
|
+
Assert.AreEqual(true, Triangle.Sides(Isosceles, 0.5, 0.4, 0.5));
|
152
|
+
end;
|
153
|
+
{$endregion}
|
154
|
+
|
155
|
+
{$region 'ScaleneTests'}
|
156
|
+
procedure ScaleneTests.True_if_no_sides_are_equal;
|
157
|
+
begin
|
158
|
+
Assert.AreEqual(true, Triangle.Sides(Scalene, 5, 4, 6));
|
159
|
+
end;
|
160
|
+
|
161
|
+
procedure ScaleneTests.False_if_all_sides_are_equal;
|
162
|
+
begin
|
163
|
+
Assert.AreEqual(false, Triangle.Sides(Scalene, 4, 4, 4));
|
164
|
+
end;
|
165
|
+
|
166
|
+
procedure ScaleneTests.False_if_two_sides_are_equal;
|
167
|
+
begin
|
168
|
+
Assert.AreEqual(false, Triangle.Sides(Scalene, 4, 4, 3));
|
169
|
+
end;
|
170
|
+
|
171
|
+
procedure ScaleneTests.Sides_that_violate_triangle_inequality_are_not_scalene_even_if_they_are_all_different;
|
172
|
+
begin
|
173
|
+
Assert.AreEqual(false, Triangle.Sides(Scalene, 7, 3, 2));
|
174
|
+
end;
|
175
|
+
|
176
|
+
procedure ScaleneTests.Sides_may_be_floats;
|
177
|
+
begin
|
178
|
+
Assert.AreEqual(true, Triangle.Sides(Scalene, 0.5, 0.4, 0.6));
|
179
|
+
end;
|
180
|
+
{$endregion}
|
181
|
+
|
182
|
+
initialization
|
183
|
+
TDUnitX.RegisterTestFixture(EquilateralTests);
|
184
|
+
TDUnitX.RegisterTestFixture(IsoscelesTests);
|
185
|
+
TDUnitX.RegisterTestFixture(ScaleneTests);
|
186
|
+
end.
|
@@ -0,0 +1,64 @@
|
|
1
|
+
unit uTriangle;
|
2
|
+
|
3
|
+
interface
|
4
|
+
|
5
|
+
type
|
6
|
+
TriangleKind = (Equilateral, Isosceles, Scalene);
|
7
|
+
|
8
|
+
Triangle = class
|
9
|
+
private
|
10
|
+
class function AllSidesAreZero(aSide1, aSide2, aSide3: double): boolean; static;
|
11
|
+
class function HasImpossibleSides(aSide1, aSide2, aSide3: double): boolean; static;
|
12
|
+
class function ViolatesTriangleInequality(aSide1, aSide2, aSide3: double): boolean; static;
|
13
|
+
class function UniqueSides(aSide1, aSide2, aSide3: double): integer; static;
|
14
|
+
public
|
15
|
+
class function Sides(aIsKind: TriangleKind; aSide1, aSide2, aSide3: double): boolean; static;
|
16
|
+
end;
|
17
|
+
|
18
|
+
implementation
|
19
|
+
uses System.SysUtils;
|
20
|
+
|
21
|
+
class function Triangle.AllSidesAreZero(aSide1, aSide2, aSide3: double): boolean;
|
22
|
+
begin
|
23
|
+
result := (aSide1 = 0) and (aSide2 = 0) and (aSide3 = 0);
|
24
|
+
end;
|
25
|
+
|
26
|
+
class function Triangle.HasImpossibleSides(aSide1, aSide2, aSide3: double): boolean;
|
27
|
+
begin
|
28
|
+
result := (aSide1 < 0) or (aSide2 < 0) or (aSide3 < 0);
|
29
|
+
end;
|
30
|
+
|
31
|
+
class function Triangle.ViolatesTriangleInequality(aSide1, aSide2, aSide3: double): boolean;
|
32
|
+
begin
|
33
|
+
result := (aSide1 + aSide2 <= aSide3) or (aSide1 + aSide3 <= aSide2) or (aSide2 + aSide3 <= aSide1);
|
34
|
+
end;
|
35
|
+
|
36
|
+
class function Triangle.UniqueSides(aSide1, aSide2, aSide3: double): integer;
|
37
|
+
begin
|
38
|
+
result := 1;
|
39
|
+
if (aSide1 <> aSide2) and (aSide1 <> aSide3) then
|
40
|
+
inc(result);
|
41
|
+
if (aSide2 <> aSide1) and (aSide2 <> aSide3) then
|
42
|
+
inc(result);
|
43
|
+
if (aSide3 <> aSide2) and (aSide3 <> aSide1) then
|
44
|
+
inc(result);
|
45
|
+
if result > 3 then
|
46
|
+
result := 3;
|
47
|
+
end;
|
48
|
+
|
49
|
+
class function Triangle.Sides(aIsKind: TriangleKind; aSide1, aSide2, aSide3: double): boolean;
|
50
|
+
var luniqueSides: integer;
|
51
|
+
begin
|
52
|
+
result := false;
|
53
|
+
if not (AllSidesAreZero(aSide1, aSide2, aSide3) or
|
54
|
+
ViolatesTriangleInequality(aSide1, aSide2, aSide3) or
|
55
|
+
HasImpossibleSides(aSide1, aSide2, aSide3)) then
|
56
|
+
begin
|
57
|
+
luniqueSides := UniqueSides(aSide1, aSide2, aSide3);
|
58
|
+
result := ((luniqueSides = 1) and (aIsKind in [Equilateral, Isosceles])) or
|
59
|
+
((luniqueSides = 2) and (aIsKind = Isosceles)) or
|
60
|
+
((aIsKind = Scalene) and (luniqueSides = 3));
|
61
|
+
end;
|
62
|
+
end;
|
63
|
+
|
64
|
+
end.
|
@@ -281,6 +281,12 @@ var invalidTestCases = []struct {
|
|
281
281
|
},
|
282
282
|
}
|
283
283
|
|
284
|
+
func TestTestVersion(t *testing.T) {
|
285
|
+
if testVersion != targetTestVersion {
|
286
|
+
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
284
290
|
func TestBestHandValid(t *testing.T) {
|
285
291
|
for _, tt := range validTestCases {
|
286
292
|
actual, err := BestHand(tt.hands)
|
@@ -304,12 +310,6 @@ func TestBestHandInvalid(t *testing.T) {
|
|
304
310
|
}
|
305
311
|
}
|
306
312
|
|
307
|
-
func TestTestVersion(t *testing.T) {
|
308
|
-
if testVersion != targetTestVersion {
|
309
|
-
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
310
|
-
}
|
311
|
-
}
|
312
|
-
|
313
313
|
func BenchmarkBestHand(b *testing.B) {
|
314
314
|
for i := 0; i < b.N; i++ {
|
315
315
|
for _, tt := range validTestCases {
|
@@ -53,7 +53,8 @@ public class AtbashTest {
|
|
53
53
|
return Arrays.asList(new Object[][] {
|
54
54
|
{ "vcvix rhn", "exercism" },
|
55
55
|
{ "zmlyh gzxov rhlug vmzhg vkkrm thglm v", "anobstacleisoftenasteppingstone" },
|
56
|
-
{ "gvhgr mt123 gvhgr mt", "testing123testing" }
|
56
|
+
{ "gvhgr mt123 gvhgr mt", "testing123testing" },
|
57
|
+
{ "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt", "thequickbrownfoxjumpsoverthelazydog" }
|
57
58
|
});
|
58
59
|
}
|
59
60
|
|
data/tracks/scala/config.json
CHANGED
@@ -700,6 +700,16 @@
|
|
700
700
|
"Control-flow (if-else statements)",
|
701
701
|
"Lists"
|
702
702
|
]
|
703
|
+
},
|
704
|
+
{
|
705
|
+
"slug":"variable-length-quantity",
|
706
|
+
"difficulty":1,
|
707
|
+
"topics":[
|
708
|
+
"Discriminated unions",
|
709
|
+
"Lists",
|
710
|
+
"Algorithms",
|
711
|
+
"Bitwise operations"
|
712
|
+
]
|
703
713
|
}
|
704
714
|
],
|
705
715
|
"deprecated":[
|
@@ -0,0 +1,56 @@
|
|
1
|
+
import scala.annotation.tailrec
|
2
|
+
|
3
|
+
object VariableLengthQuantity {
|
4
|
+
private val sevenBitsMask = 0x7f
|
5
|
+
private val eightBitMask = 0x80
|
6
|
+
|
7
|
+
def encode(n: Int): List[Int] = {
|
8
|
+
@tailrec
|
9
|
+
def encode_internal(n: Int, acc: List[Int]): List[Int] = {
|
10
|
+
if (n == 0) {
|
11
|
+
acc
|
12
|
+
} else {
|
13
|
+
var tmp = n & sevenBitsMask
|
14
|
+
if (acc.nonEmpty) {
|
15
|
+
tmp = tmp | eightBitMask
|
16
|
+
}
|
17
|
+
|
18
|
+
encode_internal(n >>> 7, tmp :: acc)
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
if (n == 0)
|
23
|
+
List(0)
|
24
|
+
else
|
25
|
+
encode_internal(n, List())
|
26
|
+
}
|
27
|
+
|
28
|
+
def encode(nums: List[Int]): List[Int] = {
|
29
|
+
nums.foldRight(List[Int]())((n, acc) => encode(n) ::: acc)
|
30
|
+
}
|
31
|
+
|
32
|
+
def decode(encoded: List[Int]): Either[String, List[Int]] = {
|
33
|
+
@tailrec
|
34
|
+
def decode_internal(encoded: List[Int], tmp: Int, acc: List[Int]): Either[String, List[Int]] = {
|
35
|
+
encoded match {
|
36
|
+
case Nil => if (tmp == 0 && acc.nonEmpty)
|
37
|
+
Right(acc.reverse)
|
38
|
+
else
|
39
|
+
Left("Incomplete sequence")
|
40
|
+
case x::xs =>
|
41
|
+
if ((tmp & 0xfe000000) > 0) {
|
42
|
+
Left("Overflow")
|
43
|
+
} else {
|
44
|
+
val newTmp = (tmp << 7) | (x & sevenBitsMask)
|
45
|
+
if ((x & eightBitMask) == 0) {
|
46
|
+
decode_internal(xs, 0, newTmp :: acc)
|
47
|
+
} else {
|
48
|
+
decode_internal(xs, newTmp, acc)
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
decode_internal(encoded, 0, List())
|
55
|
+
}
|
56
|
+
}
|
data/tracks/scala/exercises/variable-length-quantity/src/main/scala/VariableLengthQuantity.scala
ADDED
File without changes
|
data/tracks/scala/exercises/variable-length-quantity/src/test/scala/VariableLengthQuantityTest.scala
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
import org.scalatest.{FunSuite, Matchers}
|
2
|
+
|
3
|
+
class VariableLengthQuantityTest extends FunSuite with Matchers {
|
4
|
+
|
5
|
+
// Encode a series of integers, producing a series of bytes.
|
6
|
+
test("encode: zero") {
|
7
|
+
val encoded = VariableLengthQuantity.encode(List(0x0))
|
8
|
+
encoded should be (List(0x0))
|
9
|
+
}
|
10
|
+
|
11
|
+
test("encode: arbitrary single byte") {
|
12
|
+
pending
|
13
|
+
val encoded = VariableLengthQuantity.encode(List(0x40))
|
14
|
+
encoded should be (List(0x40))
|
15
|
+
}
|
16
|
+
|
17
|
+
test("encode: largest single byte") {
|
18
|
+
pending
|
19
|
+
val encoded = VariableLengthQuantity.encode(List(0x7f))
|
20
|
+
encoded should be (List(0x7f))
|
21
|
+
}
|
22
|
+
|
23
|
+
test("encode: smallest double byte") {
|
24
|
+
pending
|
25
|
+
val encoded = VariableLengthQuantity.encode(List(0x80))
|
26
|
+
encoded should be (List(0x81, 0x0))
|
27
|
+
}
|
28
|
+
|
29
|
+
test("encode: arbitrary double byte") {
|
30
|
+
pending
|
31
|
+
val encoded = VariableLengthQuantity.encode(List(0x2000))
|
32
|
+
encoded should be (List(0xc0, 0x0))
|
33
|
+
}
|
34
|
+
|
35
|
+
test("encode: largest double byte") {
|
36
|
+
pending
|
37
|
+
val encoded = VariableLengthQuantity.encode(List(0x3fff))
|
38
|
+
encoded should be (List(0xff, 0x7f))
|
39
|
+
}
|
40
|
+
|
41
|
+
test("encode: smallest triple byte") {
|
42
|
+
pending
|
43
|
+
val encoded = VariableLengthQuantity.encode(List(0x4000))
|
44
|
+
encoded should be (List(0x81, 0x80, 0x0))
|
45
|
+
}
|
46
|
+
|
47
|
+
test("encode: arbitrary triple byte") {
|
48
|
+
pending
|
49
|
+
val encoded = VariableLengthQuantity.encode(List(0x100000))
|
50
|
+
encoded should be (List(0xc0, 0x80, 0x0))
|
51
|
+
}
|
52
|
+
|
53
|
+
test("encode: largest triple byte") {
|
54
|
+
pending
|
55
|
+
val encoded = VariableLengthQuantity.encode(List(0x1fffff))
|
56
|
+
encoded should be (List(0xff, 0xff, 0x7f))
|
57
|
+
}
|
58
|
+
|
59
|
+
test("encode: smallest quadruple byte") {
|
60
|
+
pending
|
61
|
+
val encoded = VariableLengthQuantity.encode(List(0x200000))
|
62
|
+
encoded should be (List(0x81, 0x80, 0x80, 0x0))
|
63
|
+
}
|
64
|
+
|
65
|
+
test("encode: arbitrary quadruple byte") {
|
66
|
+
pending
|
67
|
+
val encoded = VariableLengthQuantity.encode(List(0x8000000))
|
68
|
+
encoded should be (List(0xc0, 0x80, 0x80, 0x0))
|
69
|
+
}
|
70
|
+
|
71
|
+
test("encode: largest quadruple byte") {
|
72
|
+
pending
|
73
|
+
val encoded = VariableLengthQuantity.encode(List(0xfffffff))
|
74
|
+
encoded should be (List(0xff, 0xff, 0xff, 0x7f))
|
75
|
+
}
|
76
|
+
|
77
|
+
test("encode: smallest quintuple byte") {
|
78
|
+
pending
|
79
|
+
val encoded = VariableLengthQuantity.encode(List(0x10000000))
|
80
|
+
encoded should be (List(0x81, 0x80, 0x80, 0x80, 0x0))
|
81
|
+
}
|
82
|
+
|
83
|
+
test("encode: arbitrary quintuple byte") {
|
84
|
+
pending
|
85
|
+
val encoded = VariableLengthQuantity.encode(List(0xff000000))
|
86
|
+
encoded should be (List(0x8f, 0xf8, 0x80, 0x80, 0x0))
|
87
|
+
}
|
88
|
+
|
89
|
+
test("encode: maximum 32-bit integer input") {
|
90
|
+
pending
|
91
|
+
val encoded = VariableLengthQuantity.encode(List(0xffffffff))
|
92
|
+
encoded should be (List(0x8f, 0xff, 0xff, 0xff, 0x7f))
|
93
|
+
}
|
94
|
+
|
95
|
+
test("encode: two single-byte values") {
|
96
|
+
pending
|
97
|
+
val encoded = VariableLengthQuantity.encode(List(0x40, 0x7f))
|
98
|
+
encoded should be (List(0x40, 0x7f))
|
99
|
+
}
|
100
|
+
|
101
|
+
test("encode: two multi-byte values") {
|
102
|
+
pending
|
103
|
+
val encoded = VariableLengthQuantity.encode(List(0x4000, 0x123456))
|
104
|
+
encoded should be (List(0x81, 0x80, 0x0, 0xc8, 0xe8, 0x56))
|
105
|
+
}
|
106
|
+
|
107
|
+
test("encode: many multi-byte values") {
|
108
|
+
pending
|
109
|
+
val encoded = VariableLengthQuantity.encode(List(0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000))
|
110
|
+
encoded should be (List(0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0))
|
111
|
+
}
|
112
|
+
|
113
|
+
// Decode a series of bytes, producing a series of integers.
|
114
|
+
test("decode: one byte") {
|
115
|
+
pending
|
116
|
+
val decoded = VariableLengthQuantity.decode(List(0x7f))
|
117
|
+
decoded should be (Right(List(0x7f)))
|
118
|
+
}
|
119
|
+
|
120
|
+
test("decode: two bytes") {
|
121
|
+
pending
|
122
|
+
val decoded = VariableLengthQuantity.decode(List(0xc0, 0x0))
|
123
|
+
decoded should be (Right(List(0x2000)))
|
124
|
+
}
|
125
|
+
|
126
|
+
test("decode: three bytes") {
|
127
|
+
pending
|
128
|
+
val decoded = VariableLengthQuantity.decode(List(0xff, 0xff, 0x7f))
|
129
|
+
decoded should be (Right(List(0x1fffff)))
|
130
|
+
}
|
131
|
+
|
132
|
+
test("decode: four bytes") {
|
133
|
+
pending
|
134
|
+
val decoded = VariableLengthQuantity.decode(List(0x81, 0x80, 0x80, 0x0))
|
135
|
+
decoded should be (Right(List(0x200000)))
|
136
|
+
}
|
137
|
+
|
138
|
+
test("decode: maximum 32-bit integer") {
|
139
|
+
pending
|
140
|
+
val decoded = VariableLengthQuantity.decode(List(0x8f, 0xff, 0xff, 0xff, 0x7f))
|
141
|
+
decoded should be (Right(List(0xffffffff)))
|
142
|
+
}
|
143
|
+
|
144
|
+
test("decode: incomplete sequence causes error") {
|
145
|
+
pending
|
146
|
+
val decoded = VariableLengthQuantity.decode(List(0xff))
|
147
|
+
decoded.isLeft should be (true)
|
148
|
+
}
|
149
|
+
|
150
|
+
test("decode: incomplete sequence causes error, even if value is zero") {
|
151
|
+
pending
|
152
|
+
val decoded = VariableLengthQuantity.decode(List(0x80))
|
153
|
+
decoded.isLeft should be (true)
|
154
|
+
}
|
155
|
+
|
156
|
+
test("decode: multiple values") {
|
157
|
+
pending
|
158
|
+
val decoded = VariableLengthQuantity.decode(List(0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0))
|
159
|
+
decoded should be (Right(List(0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000)))
|
160
|
+
}
|
161
|
+
|
162
|
+
}
|