Skip to content

Commit 1cbffc2

Browse files
committed
feat: add a bunch more unit tests
1 parent c0c1d4d commit 1cbffc2

File tree

2 files changed

+237
-2
lines changed

2 files changed

+237
-2
lines changed

spec/main_spec.lua

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,244 @@
1+
---@diagnostic disable: discard-returns, missing-parameter, param-type-mismatch, missing-fields, assign-type-mismatch
12
describe('fensteraudio', function()
23
local fensteraudio = require('fensteraudio')
34

5+
describe('fensteraudio.samplerate', function()
6+
it('should be an integer and one of the common sample rates', function()
7+
local common_sample_rates = {
8+
[8000] = true,
9+
[11025] = true,
10+
[16000] = true,
11+
[22050] = true,
12+
[32000] = true,
13+
[44100] = true,
14+
[48000] = true,
15+
[88200] = true,
16+
[96000] = true,
17+
[176400] = true,
18+
[192000] = true,
19+
[352800] = true,
20+
[384000] = true,
21+
}
22+
23+
assert.is_number(fensteraudio.samplerate)
24+
assert.is_true(common_sample_rates[fensteraudio.samplerate])
25+
end)
26+
end)
27+
28+
describe('fensteraudio.buffersize', function()
29+
it('should be an integer and a power of 2', function()
30+
assert.is_number(fensteraudio.buffersize)
31+
assert.is_true(fensteraudio.buffersize > 0)
32+
local x = math.log(fensteraudio.buffersize) / math.log(2)
33+
assert.is_true(x == math.floor(x))
34+
end)
35+
end)
36+
437
describe('fensteraudio.open(...)', function()
538
it('should return a audiodevice userdata #needsspeaker', function()
639
local audiodevice = fensteraudio.open()
740
finally(function() audiodevice:close() end)
841
assert.is_userdata(audiodevice)
942
end)
1043
end)
44+
45+
describe('audiodevice:close(...) / fensteraudio.close(...)', function()
46+
it('should throw when no arguments were given when not using as method', function()
47+
assert.has_error(function() fensteraudio.close() end)
48+
end)
49+
50+
it('should throw when audiodevice is not a audiodevice userdata when not using as method', function()
51+
assert.has_error(function() fensteraudio.close(25) end)
52+
assert.has_error(function() fensteraudio.close(2.5) end)
53+
assert.has_error(function() fensteraudio.close('ERROR') end)
54+
assert.has_error(function() fensteraudio.close(true) end)
55+
assert.has_error(function() fensteraudio.close({}) end)
56+
assert.has_error(function() fensteraudio.close(function() end) end)
57+
assert.has_error(function() fensteraudio.close(io.stdout) end)
58+
end)
59+
60+
it('should throw when audiodevice is used after closing #needsspeaker', function()
61+
local audiodevice = fensteraudio.open()
62+
fensteraudio.close(audiodevice)
63+
assert.has_error(function() fensteraudio.close(audiodevice) end)
64+
assert.has_error(function() fensteraudio.available(audiodevice) end)
65+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }) end)
66+
67+
local audiodevice2 = fensteraudio.open()
68+
audiodevice2:close()
69+
assert.has_error(function() audiodevice2:close() end)
70+
assert.has_error(function() audiodevice2:available() end)
71+
assert.has_error(function() audiodevice2:write({ 0 }) end)
72+
end)
73+
end)
74+
75+
describe('audiodevice:available(...) / fensteraudio.available(...)', function()
76+
it('should throw when no arguments were given when not using as method', function()
77+
assert.has_error(function() fensteraudio.available() end)
78+
end)
79+
80+
it('should throw when audiodevice is not a audiodevice userdata when not using as method', function()
81+
assert.has_error(function() fensteraudio.available(25) end)
82+
assert.has_error(function() fensteraudio.available(2.5) end)
83+
assert.has_error(function() fensteraudio.available('ERROR') end)
84+
assert.has_error(function() fensteraudio.available(true) end)
85+
assert.has_error(function() fensteraudio.available({}) end)
86+
assert.has_error(function() fensteraudio.available(function() end) end)
87+
assert.has_error(function() fensteraudio.available(io.stdout) end)
88+
end)
89+
90+
it('should return an integer #needsspeaker', function()
91+
local audiodevice = fensteraudio.open()
92+
finally(function() audiodevice:close() end)
93+
94+
assert.is_number(fensteraudio.available(audiodevice))
95+
assert.is_number(audiodevice:available())
96+
end)
97+
end)
98+
99+
describe('audiodevice:write(...) / fensteraudio.write(...)', function()
100+
it('should throw when no arguments were given when not using as method', function()
101+
assert.has_error(function() fensteraudio.write() end)
102+
end)
103+
104+
it('should throw when audiodevice is not a audiodevice userdata when not using as method', function()
105+
assert.has_error(function() fensteraudio.write(25, { 0 }) end)
106+
assert.has_error(function() fensteraudio.write(2.5, { 0 }) end)
107+
assert.has_error(function() fensteraudio.write('ERROR', { 0 }) end)
108+
assert.has_error(function() fensteraudio.write(true, { 0 }) end)
109+
assert.has_error(function() fensteraudio.write({}, { 0 }) end)
110+
assert.has_error(function() fensteraudio.write(function() end, { 0 }) end)
111+
assert.has_error(function() fensteraudio.write(io.stdout, { 0 }) end)
112+
end)
113+
114+
it('should throw when samples is not a table #needsspeaker', function()
115+
local audiodevice = fensteraudio.open()
116+
finally(function() audiodevice:close() end)
117+
118+
assert.has_error(function() fensteraudio.write(audiodevice, 'ERROR') end)
119+
assert.has_error(function() fensteraudio.write(audiodevice, true) end)
120+
assert.has_error(function() fensteraudio.write(audiodevice, function() end) end)
121+
assert.has_error(function() fensteraudio.write(audiodevice, io.stdout) end)
122+
assert.has_error(function() fensteraudio.write(audiodevice, 0) end)
123+
assert.has_error(function() fensteraudio.write(audiodevice, 2.5) end)
124+
125+
assert.has_error(function() audiodevice:write('ERROR') end)
126+
assert.has_error(function() audiodevice:write(true) end)
127+
assert.has_error(function() audiodevice:write(function() end) end)
128+
assert.has_error(function() audiodevice:write(io.stdout) end)
129+
assert.has_error(function() audiodevice:write(0) end)
130+
assert.has_error(function() audiodevice:write(2.5) end)
131+
end)
132+
133+
it('should throw when one of the samples is not a number #needsspeaker', function()
134+
local audiodevice = fensteraudio.open()
135+
finally(function() audiodevice:close() end)
136+
137+
assert.has_error(function() fensteraudio.write(audiodevice, { 'ERROR' }) end)
138+
assert.has_error(function() fensteraudio.write(audiodevice, { true }) end)
139+
assert.has_error(function() fensteraudio.write(audiodevice, { function() end }) end)
140+
assert.has_error(function() fensteraudio.write(audiodevice, { io.stdout }) end)
141+
assert.has_error(function() fensteraudio.write(audiodevice, { 0, 0, 'zero', 0, 0 }) end)
142+
143+
assert.has_error(function() audiodevice:write({ 'ERROR' }) end)
144+
assert.has_error(function() audiodevice:write({ true }) end)
145+
assert.has_error(function() audiodevice:write({ function() end }) end)
146+
assert.has_error(function() audiodevice:write({ io.stdout }) end)
147+
assert.has_error(function() audiodevice:write({ 0, 0, 'zero', 0, 0 }) end)
148+
end)
149+
150+
it('should throw when samplesend is not an integer #needsspeaker', function()
151+
local audiodevice = fensteraudio.open()
152+
finally(function() audiodevice:close() end)
153+
154+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, 'ERROR') end)
155+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, true) end)
156+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, {}) end)
157+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, function() end) end)
158+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, io.stdout) end)
159+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, 2.5) end)
160+
161+
assert.has_error(function() audiodevice:write({ 0 }, 'ERROR') end)
162+
assert.has_error(function() audiodevice:write({ 0 }, true) end)
163+
assert.has_error(function() audiodevice:write({ 0 }, {}) end)
164+
assert.has_error(function() audiodevice:write({ 0 }, function() end) end)
165+
assert.has_error(function() audiodevice:write({ 0 }, io.stdout) end)
166+
assert.has_error(function() audiodevice:write({ 0 }, 2.5) end)
167+
end)
168+
169+
it('should throw when samples are too many #needsspeaker', function()
170+
local samples = {}
171+
for _ = 1, fensteraudio.buffersize + 1 do
172+
table.insert(samples, 0)
173+
end
174+
175+
local audiodevice = fensteraudio.open()
176+
finally(function() audiodevice:close() end)
177+
178+
assert.has_error(function() fensteraudio.write(audiodevice, samples) end)
179+
180+
assert.has_error(function() audiodevice:write(samples) end)
181+
end)
182+
183+
it('should throw when one of the samples is out of range #needsspeaker', function()
184+
local audiodevice = fensteraudio.open()
185+
finally(function() audiodevice:close() end)
186+
187+
assert.has_error(function() fensteraudio.write(audiodevice, { 0, 1.1, 0 }) end)
188+
assert.has_error(function() fensteraudio.write(audiodevice, { 0, -1.1, 0 }) end)
189+
190+
assert.has_error(function() audiodevice:write({ 0, 1.1, 0 }) end)
191+
assert.has_error(function() audiodevice:write({ 0, -1.1, 0 }) end)
192+
end)
193+
194+
it('should throw when samplesend is out of range #needsspeaker', function()
195+
local audiodevice = fensteraudio.open()
196+
finally(function() audiodevice:close() end)
197+
198+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, -1) end)
199+
assert.has_error(function() fensteraudio.write(audiodevice, { 0 }, 2) end)
200+
201+
assert.has_error(function() audiodevice:write({ 0 }, -1) end)
202+
assert.has_error(function() audiodevice:write({ 0 }, 2) end)
203+
end)
204+
205+
it('should write a sample successfully #needsspeaker', function()
206+
local audiodevice = fensteraudio.open()
207+
finally(function() audiodevice:close() end)
208+
209+
fensteraudio.write(audiodevice, { 0 })
210+
fensteraudio.write(audiodevice, { 0 }, 1)
211+
fensteraudio.write(audiodevice, { 0, 0.1, 0, -0.1, 0 }, 3)
212+
213+
audiodevice:write({ 0 })
214+
audiodevice:write({ 0 }, 1)
215+
audiodevice:write({ 0, 0.1, 0, -0.1, 0 }, 3)
216+
end)
217+
218+
it('should allow metatable objects for samples #needsspeaker', function()
219+
local noise_generator = {}
220+
function noise_generator.new(duration)
221+
local self = setmetatable({}, noise_generator)
222+
self.duration = duration
223+
return self
224+
end
225+
226+
function noise_generator:__len()
227+
return self.duration
228+
end
229+
230+
function noise_generator:__index(_)
231+
return math.random(-1, 1)
232+
end
233+
234+
local noise = noise_generator.new(10)
235+
236+
local audiodevice = fensteraudio.open()
237+
finally(function() audiodevice:close() end)
238+
239+
fensteraudio.write(audiodevice, noise)
240+
241+
audiodevice:write(noise)
242+
end)
243+
end)
11244
end)

src/main.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,15 +215,17 @@ static int audiodevice_write(lua_State *L) {
215215
audiodevice *p_audiodevice = check_open_audiodevice(L);
216216
lua_Integer samples_length = check_samples(L);
217217
lua_Integer samples_end = luaL_optinteger(L, 3, samples_length);
218-
luaL_argcheck(L, samples_end <= samples_length, 3,
219-
"end index must be less than or equal to the samples length");
218+
luaL_argcheck(L, samples_end >= 0 && samples_end <= samples_length, 3,
219+
"end index must be in the range of 0 to less than or equal to the samples length");
220220

221221
// read samples from the table
222222
int is_number;
223223
for (lua_Integer i = 0; i < samples_end; i++) {
224224
lua_geti(L, 2, i + 1);
225225
p_audiodevice->samples[i] = (float)lua_tonumberx(L, -1, &is_number);
226226
luaL_argcheck(L, is_number, 2, "samples must be a table of numbers");
227+
luaL_argcheck(L, p_audiodevice->samples[i] >= -1.0f && p_audiodevice->samples[i] <= 1.0f, 2,
228+
"samples must be in the range of -1.0 to 1.0");
227229
lua_pop(L, 1);
228230
}
229231

0 commit comments

Comments
 (0)