forked from exercism/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcircular-buffer.jl
220 lines (196 loc) · 6.54 KB
/
circular-buffer.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# See default_template.jl.
using GeneratorUtils
using DataStructures: OrderedDict
using JSON
# Modify as desired.
const IO_IN = stdin
const IO_OUT = stdout
function parse_operations(operations)
out = IOBuffer()
for op in operations
op_name = op["operation"]
if op_name == "read"
if op["should_succeed"]
s = "@test popfirst!(cb) == $(op["expected"])"
else
s = "@test_throws BoundsError popfirst!(cb)"
end
elseif op_name == "write"
item = op["item"]
if op["should_succeed"]
s = "@test push!(cb, $item) === cb"
else
s = "@test_throws BoundsError push!(cb, $item)"
end
elseif op_name == "overwrite"
s = "@test push!(cb, $(op["item"]); overwrite=true) === cb"
elseif op_name == "clear"
s = "@test empty!(cb) === cb"
else
throw(ArgumentError("Unrecognized operation `$op_name`."))
end
write(out, s, '\n')
end
out.size -= 1 # remove last newline
return String(take!(out))
end
function print_custom_tests(io::IO)
println(
io,
"""
@testset "overwrite=true and overwrite=false" begin
cb = CircularBuffer{Int}(2)
@test empty!(cb) === cb
@test push!(cb, 1; overwrite=true) === cb
@test push!(cb, 2; overwrite=true) === cb
@test_throws BoundsError push!(cb, 3; overwrite=false)
@test push!(cb, 4; overwrite=true) === cb
@test popfirst!(cb) == 2
@test popfirst!(cb) == 4
@test_throws BoundsError popfirst!(cb)
end
@testset "type parameter" begin
cb = CircularBuffer{Int}(1)
@test_throws Exception push!(cb, "0")
cb = CircularBuffer{String}(1)
@test_throws Exception push!(cb, 0)
@test push!(cb, "0") === cb
@test popfirst!(cb) == "0"
end
"""
)
end
function print_bonus_tests(io::IO)
println(
io,
"""
# Uncomment the following line to enable bonus tests.
# enable_bonus_tests = true
if @isdefined(enable_bonus_tests) && enable_bonus_tests
println("\\nBonus tests enabled.\\n")
@testset "is subtype of AbstractVector" begin
@test CircularBuffer <: AbstractVector
end
# Copied from DataStructures.jl and slightly modified.
@testset "Bonus test set taken from DataStructures.jl (CircularBuffer)" begin
@testset "Core Functionality" begin
cb = CircularBuffer{Int}(5)
@testset "When empty" begin
@test length(cb) == 0
@test capacity(cb) == 5
@test_throws BoundsError first(cb)
@test_throws BoundsError last(cb)
@test isempty(cb) == true
@test isfull(cb) == false
@test eltype(cb) == Int
@test eltype(typeof(cb)) == Int
end
@testset "With 1 element" begin
push!(cb, 1)
@test length(cb) == 1
@test capacity(cb) == 5
@test isfull(cb) == false
@test first(cb) == last(cb)
end
@testset "Appending many elements" begin
append!(cb, 2:8; overwrite=true)
@test length(cb) == capacity(cb)
@test size(cb) == (length(cb),)
@test isempty(cb) == false
@test isfull(cb) == true
@test convert(Array, cb) == Int[4,5,6,7,8]
end
@testset "getindex" begin
@test cb[1] == 4
@test cb[2] == 5
@test cb[3] == 6
@test cb[4] == 7
@test cb[5] == 8
@test_throws BoundsError cb[6]
@test_throws BoundsError cb[3:6]
@test cb[3:4] == Int[6,7]
@test cb[[1,5]] == Int[4,8]
@test first(cb) == 4
@test last(cb) == 8
end
@testset "setindex" begin
cb[3] = 999
@test convert(Array, cb) == Int[4,5,999,7,8]
end
end
@testset "pushfirst" begin
cb = CircularBuffer{Int}(5) # New, empty one for full test coverage
for i in -5:5
pushfirst!(cb, i; overwrite=true)
end
arr = convert(Array, cb)
@test arr == Int[5, 4, 3, 2, 1]
for (idx, n) in enumerate(5:1)
@test arr[idx] == n
end
end
@testset "Issue 429" begin
cb = CircularBuffer{Int}(5)
map(x -> pushfirst!(cb, x; overwrite=true), 1:8)
pop!(cb)
pushfirst!(cb, 9)
arr = convert(Array, cb)
@test arr == Int[9, 8, 7, 6, 5]
end
@testset "Issue 379" begin
cb = CircularBuffer{Int}(5)
pushfirst!(cb, 1)
@test cb == [1]
pushfirst!(cb, 2)
@test cb == [2, 1]
end
@testset "empty!" begin
cb = CircularBuffer{Int}(5)
push!(cb, 13)
empty!(cb)
@test length(cb) == 0
end
@testset "pop!" begin
cb = CircularBuffer{Int}(5)
for i in 0:5 # one extra to force wraparound
push!(cb, i; overwrite=true)
end
for j in 5:-1:1
@test pop!(cb) == j
@test convert(Array, cb) == collect(1:j-1)
end
@test isempty(cb)
@test_throws BoundsError pop!(cb)
end
@testset "popfirst!" begin
cb = CircularBuffer{Int}(5)
for i in 0:5 # one extra to force wraparound
push!(cb, i; overwrite=true)
end
for j in 1:5
@test popfirst!(cb) == j
@test convert(Array, cb) == collect(j+1:5)
end
@test isempty(cb)
@test_throws BoundsError popfirst!(cb)
end
end
end
"""
)
end # print_bonus_tests
function main()
canonical_data = tighten(JSON.parse(IO_IN; dicttype=OrderedDict))
for case in canonical_data["cases"]
input = case["input"]
override!(
case;
setup="cb = CircularBuffer{Int}($(input["capacity"]))",
test=parse_operations(input["operations"]),
)
end
print_runtests(IO_OUT, canonical_data)
print_custom_tests(IO_OUT)
print_bonus_tests(IO_OUT)
end
main()