Skip to content

Commit d444d98

Browse files
authored
Merge pull request #85 from tayloraswift/adopt-swift-testing
Adopt swift testing
2 parents 4e3ed28 + f296c24 commit d444d98

26 files changed

+1167
-1529
lines changed
File renamed without changes.

Package.swift

+9-11
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ let package:Package = .init(name: "swift-png",
1313
dependencies: [
1414
.package(url: "https://github.com/tayloraswift/swift-hash", .upToNextMinor(
1515
from: "0.7.1")),
16-
.package(url: "https://github.com/tayloraswift/swift-grammar", .upToNextMinor(
17-
from: "0.4.0")),
1816
],
1917
targets: [
2018
.target(name: "LZ77",
@@ -32,29 +30,29 @@ let package:Package = .init(name: "swift-png",
3230
.target(name: "PNG"),
3331
]),
3432

35-
.executableTarget(name: "LZ77Tests",
33+
.testTarget(name: "LZ77Tests",
3634
dependencies: [
3735
.target(name: "LZ77"),
38-
.product(name: "Testing_", package: "swift-grammar"),
3936
],
37+
path: "Sources/LZ77Tests",
4038
swiftSettings: [
4139
.define("DEBUG", .when(configuration: .debug))
4240
]),
4341

44-
.executableTarget(name: "PNGTests",
42+
.testTarget(name: "PNGTests",
4543
dependencies: [
4644
.target(name: "PNG"),
47-
.product(name: "Testing_", package: "swift-grammar"),
4845
],
46+
path: "Sources/PNGTests",
4947
swiftSettings: [
5048
.define("DEBUG", .when(configuration: .debug))
5149
]),
5250

53-
.executableTarget(name: "PNGIntegrationTests",
51+
.testTarget(name: "PNGIntegrationTests",
5452
dependencies: [
5553
.target(name: "PNG"),
56-
.product(name: "Testing_", package: "swift-grammar"),
5754
],
55+
path: "Sources/PNGIntegrationTests",
5856
exclude: [
5957
"PngSuite.LICENSE",
6058
"PngSuite.README",
@@ -63,11 +61,11 @@ let package:Package = .init(name: "swift-png",
6361
"RGBA/",
6462
]),
6563

66-
.executableTarget(name: "PNGCompressionTests",
64+
.testTarget(name: "PNGCompressionTests",
6765
dependencies: [
6866
.target(name: "PNG"),
69-
.product(name: "Testing_", package: "swift-grammar"),
70-
]),
67+
],
68+
path: "Sources/PNGCompressionTests"),
7169

7270
.executableTarget(name: "PNGCompressionBenchmarks",
7371
dependencies: [

Scripts/TestAll

+3-5
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ swift --version
44
swift build
55
swift build -c release
66
# Debug-only tests
7-
swift run -c debug LZ77Tests
8-
swift run -c debug PNGTests
7+
swift test -c debug --filter LZ77Tests
8+
swift test -c debug --filter PNGTests
99
# All tests
10-
for f in .build/release/*Tests; do
11-
$f
12-
done
10+
swift test -c release --no-parallel

Sources/LZ77Tests/Bitstreams.swift

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#if DEBUG
2+
@testable
3+
import LZ77
4+
import Testing
5+
6+
@Suite
7+
enum CompressionInternals
8+
{
9+
@Test
10+
static func BitstreamDecoding()
11+
{
12+
var bits:LZ77.InflatorIn = [
13+
0b1001_1110,
14+
0b1111_0110,
15+
0b0010_0011,
16+
]
17+
#expect(bits[ 0] == 0b1111_0110_1001_1110)
18+
#expect(bits[ 1] == 0b1_1111_0110_1001_111)
19+
#expect(bits[ 2] == 0b11_1111_0110_1001_11)
20+
#expect(bits[ 3] == 0b011_1111_0110_1001_1)
21+
#expect(bits[ 4] == 0b0011_1111_0110_1001)
22+
#expect(bits[ 5] == 0b0_0011_1111_0110_100)
23+
#expect(bits[ 6] == 0b10_0011_1111_0110_10)
24+
#expect(bits[ 7] == 0b010_0011_1111_0110_1)
25+
#expect(bits[ 8] == 0b0010_0011_1111_0110)
26+
#expect(bits[ 9] == 0b0_0010_0011_1111_011)
27+
#expect(bits[23] == 0b0000_0000_0000_0000)
28+
29+
#expect(bits[0, count: 4, as: Int.self] == 0b1110)
30+
#expect(bits[1, count: 4, as: Int.self] == 0b1_111)
31+
#expect(bits[1, count: 6, as: Int.self] == 0b001_111)
32+
#expect(bits[2, count: 6, as: Int.self] == 0b1001_11)
33+
#expect(bits[2, count: 16, as: Int.self] == 0b11_1111_0110_1001_11)
34+
35+
// test rebase
36+
// { 0010_0011, 1111_0110, 1001_1110 }
37+
// ^
38+
// b = 20
39+
// ->
40+
// { 0001_1000, 1010_1101, 0010_0011 }
41+
// ^
42+
// b = 4
43+
var b:Int = 20
44+
45+
bits.rebase([0b1010_1101, 0b0001_1000], pointer: &b)
46+
47+
#expect(bits[b ] == 0b1000_1010_1101_0010)
48+
#expect(bits[b + 1] == 0b1_1000_1010_1101_001)
49+
50+
// test rebase
51+
// { 0001_1000, 1010_1101, 0010_0011 }
52+
// ^
53+
// b = 4
54+
// { 1111_1100, 0011_1111, 0001_1000, 1010_1101, 0010_0011 }
55+
bits.rebase([0b0011_1111, 0b1111_1100], pointer: &b)
56+
57+
#expect(bits[b ] == 0b1000_1010_1101_0010)
58+
#expect(bits[b + 8] == 0b1111_0001_1000_1010)
59+
}
60+
@Test
61+
static func BitstreamEncoding()
62+
{
63+
var bits:LZ77.DeflatorOut = .init(hint: 4)
64+
65+
bits.append(0b11, count: 2)
66+
bits.append(0b01_10, count: 4)
67+
68+
bits.append(0b0110, count: 0)
69+
70+
bits.append(0b1_1111_11, count: 7)
71+
bits.append(0b1010_1010_1010_101, count: 15)
72+
bits.append(0b000, count: 3)
73+
bits.append(0b0_1101_1, count: 6)
74+
bits.append(0b1_0000_0000_111, count: 12)
75+
76+
var encoded:[UInt8] = []
77+
78+
while let chunk:[UInt8] = bits.pop()
79+
{
80+
encoded.append(contentsOf: chunk)
81+
}
82+
83+
encoded.append(contentsOf: bits.pull())
84+
85+
#expect(encoded == [
86+
0b1101_1011,
87+
0b1011_1111,
88+
0b1010_1010,
89+
0b1000_1010,
90+
0b1110_1101,
91+
0b0000_0000,
92+
0b0000_0001
93+
])
94+
}
95+
96+
@Test
97+
static func Matching()
98+
{
99+
let segments:[[UInt8]] = [
100+
[1, 2, 3, 3, 1, 2, 3, 3, 1, 2, 3, 1, 2, 2, 2, 2, 2, 2, 0, 1, 2],
101+
[2, 2, 2, 2, 0, 1, 2, 2, 0, 0, 0, 0, 2, 3, 2, 1, 2, 3, 3, 1, 5],
102+
[1, 1, 3, 3, 1, 2, 3, 1, 2, 4, 4, 2, 1]
103+
]
104+
var input:LZ77.DeflatorIn<LZ77.MRC32> = .init()
105+
var window:LZ77.DeflatorWindow = .init(exponent: 4)
106+
var output:[[UInt8]] = []
107+
for (s, segment):(Int, [UInt8]) in segments.enumerated()
108+
{
109+
input.enqueue(contentsOf: segment[...])
110+
111+
let lookahead:Int = (s == segments.count - 1 ? 0 : 10)
112+
while window.endIndex < 0, input.count > lookahead
113+
{
114+
window.initialize(with: input.dequeue())
115+
}
116+
while input.count > lookahead
117+
{
118+
let head:(index:Int, next:UInt16?) = window.update(with: input.dequeue())
119+
if let match:(run:Int, distance:Int) = window.match(from: head,
120+
lookahead: input,
121+
attempts: .max,
122+
goal: .max)
123+
{
124+
var run:[UInt8] = [window.literal]
125+
for _:Int in 1 ..< match.run
126+
{
127+
window.update(with: input.dequeue())
128+
run.append(window.literal)
129+
}
130+
output.append(run)
131+
}
132+
else
133+
{
134+
output.append([window.literal])
135+
}
136+
}
137+
138+
guard s == segments.count - 1
139+
else
140+
{
141+
continue
142+
}
143+
144+
// epilogue: get the matches still sitting in the pipeline
145+
let epilogue:Int = -3 - min(0, window.endIndex)
146+
while input.count > epilogue
147+
{
148+
window.update(with: input.dequeue())
149+
output.append([window.literal])
150+
}
151+
}
152+
#expect(output == [
153+
[1],
154+
[2],
155+
[3],
156+
[3],
157+
[1, 2, 3, 3, 1, 2, 3],
158+
[1],
159+
[2], [2], [2], [2], [2], [2],
160+
[0],
161+
[1, 2, 2, 2, 2, 2],
162+
[0],
163+
[1],
164+
[2], [2],
165+
[0], [0], [0], [0],
166+
[2],
167+
[3],
168+
[2],
169+
[1],
170+
[2],
171+
[3], [3],
172+
[1],
173+
[5],
174+
[1], [1],
175+
[3], [3],
176+
[1],
177+
[2],
178+
[3],
179+
[1],
180+
[2],
181+
[4], [4],
182+
[2],
183+
[1]
184+
])
185+
}
186+
}
187+
#endif

Sources/LZ77Tests/Compression.swift

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import LZ77
2+
import Testing
3+
4+
@Suite
5+
enum Compression
6+
{
7+
@Test(arguments: [4, 7, 9], [5, 15, 100, 200, 2000, 5000])
8+
static func LZ77(_ level:Int, _ count:Int) throws
9+
{
10+
let input:[UInt8] = (0 ..< count).map{ _ in .random(in: .min ... .max) }
11+
12+
var deflator:LZ77.Deflator = .init(level: level, exponent: 8, hint: 16)
13+
deflator.push(input[...], last: true)
14+
15+
var compressed:[UInt8] = []
16+
while let part:[UInt8] = deflator.pull()
17+
{
18+
compressed += part
19+
}
20+
21+
var inflator:LZ77.Inflator = .init()
22+
try inflator.push(compressed[...])
23+
24+
let output:[UInt8] = inflator.pull()
25+
26+
#expect(input == output)
27+
}
28+
29+
@Test(arguments: [5, 15, 100, 200, 2000, 5000])
30+
static func Gzip(_ count:Int) throws
31+
{
32+
let input:[UInt8] = (0 ..< count).map{ _ in .random(in: .min ... .max) }
33+
34+
var deflator:Gzip.Deflator = .init(level: 7, exponent: 15, hint: 64 << 10)
35+
deflator.push(input[...], last: true)
36+
37+
var compressed:[UInt8] = []
38+
while let part:[UInt8] = deflator.pull()
39+
{
40+
compressed += part
41+
}
42+
43+
var inflator:Gzip.Inflator = .init()
44+
try inflator.push(compressed[...])
45+
46+
let output:[UInt8] = inflator.pull()
47+
48+
#expect(input == output)
49+
}
50+
}
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import LZ77
2+
import Testing
3+
4+
@Suite
5+
enum CompressionMicro
6+
{
7+
@Test(arguments: [[], [1], [2, 3], [4, 5, 6]])
8+
static func Roundtrip(_ bytes:[UInt8]) throws
9+
{
10+
let archive:[UInt8] = Gzip.archive(bytes: bytes[...], level: 10)
11+
#expect(try Gzip.extract(from: archive[...]) == bytes)
12+
}
13+
14+
@Test
15+
static func InParts() throws
16+
{
17+
var deflator:Gzip.Deflator = .init(level: 13, exponent: 15)
18+
deflator.push([1], last: false)
19+
deflator.push([2], last: true)
20+
21+
var archive:[UInt8] = []
22+
while let part:[UInt8] = deflator.pull()
23+
{
24+
archive += part
25+
}
26+
27+
#expect(try Gzip.extract(from: archive[...]) == [1, 2])
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#if DEBUG
2+
@testable
3+
import LZ77
4+
import Testing
5+
6+
@Suite
7+
enum HardwareAcceleration
8+
{
9+
@Test
10+
static func DictionarySemantics()
11+
{
12+
let dictionary:F14.HashTable = .init(exponent: 10)
13+
14+
#expect(nil == dictionary.update(key: 0, value: 1))
15+
#expect(nil == dictionary.update(key: 1, value: 2))
16+
#expect(dictionary.update(key: 0, value: 3) == 1)
17+
#expect(nil == dictionary.update(key: 2, value: 4))
18+
#expect(nil != dictionary.remove(key: 1, value: 5))
19+
#expect(dictionary.update(key: 1, value: 6) == 2)
20+
#expect(nil != dictionary.remove(key: 1, value: 6))
21+
#expect(nil == dictionary.update(key: 1, value: 7))
22+
23+
var a:F14.HashTable = .init(exponent: 15),
24+
b:[UInt32: UInt16] = [:]
25+
for i:UInt16 in ((0 ... .max).map{ $0 & 0x00ff })
26+
{
27+
let key:UInt32 = .random(in: 0 ... 1000)
28+
29+
#expect(a.update(key: key, value: i) == b.updateValue(i, forKey: key))
30+
}
31+
for i:UInt16 in ((0 ... .max).map{ $0 & 0x00ff })
32+
{
33+
let key:UInt32 = .random(in: 0 ... 1000)
34+
35+
if b[key] == i
36+
{
37+
b[key] = nil
38+
}
39+
40+
a.remove(key: key, value: i)
41+
}
42+
for i:UInt16 in ((0 ... .max).map{ $0 & 0x00ff })
43+
{
44+
let key:UInt32 = .random(in: 0 ... 1000)
45+
46+
#expect(a.update(key: key, value: i) == b.updateValue(i, forKey: key))
47+
}
48+
}
49+
}
50+
#endif

0 commit comments

Comments
 (0)