api_test.lua 27.6 KB
Newer Older
1
-- Script API Tests
2
-- Test routines for the scripting API
3
4
-- When adding new Lua APIs, tests for them should go here.

5
require("logger")
6

7
8
9
-- global logger
test_log = nil

10
function printf(s,...)
11
    test_log:writef(s,...)
12
13
end

14
15
function request_mode(mode, mode_str)
    while camera.mode ~= mode do
16
        printf("Please switch to %s mode.\n", mode_str, mode)
17
18
19
20
21
22
23
        while camera.mode ~= mode do
            console.show()
            msleep(1000)
        end
    end
end

a1ex's avatar
a1ex committed
24
25
26
27
28
function round(x)
    -- https://scriptinghelpers.org/questions/4850/how-do-i-round-numbers-in-lua-answered
    return x + 0.5 - (x + 0.5) % 1
end

29
30
31
32
33
34
35
36
37
38
function print_table(t)
    test_log:write(string.format("%s = ", t))
    local s,e = xpcall(function()
        test_log:serialize(_G[t])
    end, debug.traceback)
    if s == false then
        test_log:write(e)
    end
end

39
40
41
42
-- used for testing Lua 'strict' mode
declared_var = nil

function strict_tests()
43
    printf("Strict mode tests...\n")
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

    -- this should work
    declared_var = 5
    assert(declared_var == 5)

    -- this should raise error
    local s,e = pcall(function() undeclared_var = 7 end)
    assert(s == false)
    assert(e:find("assign to undeclared variable 'undeclared_var'"))

    -- same here
    local s,e = pcall(function() print(undeclared_var) end)
    assert(s == false)
    assert(e:find("variable 'undeclared_var' is not declared"))

59
60
    printf("Strict mode tests passed.\n")
    printf("\n")
61
62
63
end

function generic_tests()
64
    printf("Generic tests...\n")
65
    print_table("arg")
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    print_table("camera")
    print_table("event")
    print_table("console")
    print_table("lv")
    print_table("lens")
    print_table("display")
    print_table("key")
    print_table("menu")
    print_table("movie")
    print_table("dryos")
    print_table("interval")
    print_table("battery")
    print_table("task")
    print_table("property")
80
81
    printf("Generic tests completed.\n")
    printf("\n")
82
83
end

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
function stdio_test()
    local s,e
    
    -- these should print to console
    -- fixme: they should output this:
    -- Hello, stderr. Hello, stdout. 
    -- Hello again, stdout.
    -- Hello again, stderr.
    io.write("Hello, stdout. ")
    io.stderr:write("Hello, stderr. ")
    io.write("\n")

    io.write("Hello again, stdout.\n")
    io.stderr:write("Hello again, stderr.\n")

    -- not implemented
    -- I expected error, but...
    local inp = io.read("*line")
    print("From stdin:", inp)
end

function copy_test(src, dst)
106
    printf("Copy test: %s -> %s\n", src, dst)
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    
    -- will this copy without errors? we'll see
    -- read source file
    local fin = io.open(src, "rb")
    local data = fin:read("*all")
    fin:close()

    -- save a copy
    local fout = io.open(dst, "w")
    fout:write(data)
    fout:close()

    -- verify
    fin = io.open(dst, "rb")
    local check = fin:read("*all")
    local size = fin:seek("end", 0)
    fin:close()
    assert(data == check)
    assert(size == #data)
    
    -- delete the copy
    assert(dryos.remove(dst) == true)
    
    -- check if it was deleted
alex@thinkpad's avatar
alex@thinkpad committed
131
    assert(io.open(dst, "rb") == nil)
132
133
134
135

    -- it should return false this time
    assert(dryos.remove(dst) == false)

136
    printf("Copy test OK\n")
137
138
139
end

function append_test(file)
140
    printf("Append test: %s\n", file)
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

    local data1 = "Allons enfants de la patrie\n"
    local data2 = "Le jour de gloire est arrivé !\n"
    
    -- make sure the file is not there
    dryos.remove(file)
    
    -- create it
    local fout = io.open(file, "a")
    fout:write(data1)
    fout:close()

    -- verify the contents
    local fin = io.open(file, "r")
    local check = fin:read("*all")
    fin:close()
alex@thinkpad's avatar
alex@thinkpad committed
157
    assert(check == data1)
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

    -- reopen it to append something
    fout = io.open(file, "a")
    fout:write(data2)
    fout:close()

    -- verify the contents
    fin = io.open(file, "r")
    check = fin:read("*all")
    fin:close()
    assert(check == data1 .. data2)

    -- delete it
    assert(dryos.remove(file) == true)
    
    -- check if it was deleted
alex@thinkpad's avatar
alex@thinkpad committed
174
    assert(io.open(file, "rb") == nil)
175

176
    printf("Append test OK\n")
177
178
end

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
function rename_test(src, dst)
    printf("Rename test: %s -> %s\n", src, dst)

    local data = "Millions saw the apple fall, " ..
        "but Newton was the one who asked why."
    
    -- create the source file
    local fout = io.open(src, "w")
    fout:write(data)
    fout:close()

    -- verify the contents
    local fin = io.open(src, "r")
    local check = fin:read("*all")
    fin:close()
    assert(check == data)

    -- rename it
    assert(dryos.rename(src, dst) == true)

    -- verify the contents
    fin = io.open(dst, "r")
    check = fin:read("*all")
    fin:close()
    assert(check == data)
    
    -- check if the source file was deleted
    assert(io.open(src, "rb") == nil)

    -- cleanup: delete the renamed file
    assert(dryos.remove(dst) == true)
    
    -- check if it was deleted
    assert(io.open(dst, "rb") == nil)

    printf("Rename test OK\n")
end

217
function test_io()
alex@thinkpad's avatar
alex@thinkpad committed
218
    printf("Testing file I/O...\n")
219
220
221
    stdio_test()
    copy_test("autoexec.bin", "tmp.bin")
    append_test("tmp.txt")
222
223
    rename_test("apple.txt", "banana.txt")
    rename_test("apple.txt", "ML/banana.txt")
alex@thinkpad's avatar
alex@thinkpad committed
224
225
226

    printf("File I/O tests completed.\n")
    printf("\n")
227
228
end

229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
function taskA()
    printf("Task A started.\n")
    local i
    for i = 1,100 do
        printf("Task A: %d\n", i)
        task.yield(math.random(10,50))
    end
end

function taskB()
    printf("Task B started.\n")
    local i
    for i = 1,100 do
        printf("Task B: %d\n", i)
        task.yield(math.random(10,50))
    end
end

function test_multitasking()
    printf("Testing multitasking...\n")

    task.create(taskA)
    task.create(taskB)
    task.yield(5000)

    printf("Multitasking tests completed.\n")
    printf("\n")
end

258
259
260
261
262
263
264
265
function test_keys()
    printf("Testing half-shutter...\n")
    -- open Canon menu
    key.press(KEY.MENU)
    msleep(1000)
    -- fixme: expose things like QR_MODE, PLAY_MODE, enter_play_mode...
    assert(camera.state == 1)
    key.press(KEY.HALFSHUTTER)
266
    msleep(100)
267
268
269
270
271
272
273
274
275
    assert(key.last == KEY.HALFSHUTTER)
    msleep(1000)
    -- half-shutter should close Canon menu
    assert(camera.state == 0)
    key.press(KEY.UNPRESS_HALFSHUTTER)
    assert(key.last == KEY.UNPRESS_HALFSHUTTER)
    printf("Half-shutter test OK.\n")
    
    -- todo: test other key codes? press/unpress events?
alex@thinkpad's avatar
alex@thinkpad committed
276
    printf("\n")
277
278
end

279
function test_camera_exposure()
alex@thinkpad's avatar
alex@thinkpad committed
280
    printf("Testing exposure settings...\n")
281
282
283
284
285
286
    printf("Camera    : %s (%s) %s\n", camera.model, camera.model_short, camera.firmware)
    printf("Lens      : %s\n", lens.name)
    printf("Shoot mode: %s\n", camera.mode)
    printf("Shutter   : %s (raw %s, %ss, %sms, apex %s)\n", camera.shutter, camera.shutter.raw, camera.shutter.value, camera.shutter.ms, camera.shutter.apex)
    printf("Aperture  : %s (raw %s, f/%s, apex %s)\n", camera.aperture, camera.aperture.raw, camera.aperture.value, camera.aperture.apex)
    printf("Av range  : %s..%s (raw %s..%s, f/%s..f/%s, apex %s..%s)\n",
287
288
289
290
291
        camera.aperture.min, camera.aperture.max,
        camera.aperture.min.raw, camera.aperture.max.raw,
        camera.aperture.min.value, camera.aperture.max.value,
        camera.aperture.min.apex, camera.aperture.max.apex
    )
292
293
294
    printf("ISO       : %s (raw %s, %s, apex %s)\n", camera.iso, camera.iso.raw, camera.iso.value, camera.iso.apex)
    printf("EC        : %s (raw %s, %s EV)\n", camera.ec, camera.ec.raw, camera.ec.value)
    printf("Flash EC  : %s (raw %s, %s EV)\n", camera.flash_ec, camera.flash_ec.raw, camera.flash_ec.value)
295

296
    request_mode(MODE.M, "M")
297
    local old_value = camera.shutter.raw
298
    printf("Setting shutter to random values...\n")
299
    for k = 1,100 do
300
301
        local method = math.random(1,4)
        local d = nil
302
303
        if method == 1 then
            local s = math.random(1,30)
304
305
306
307
308
            if math.random(1,2) == 1 then
                camera.shutter.value = s
            else
                camera.shutter = s
            end
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
            d = math.abs(math.log(camera.shutter.value,2) - math.log(s,2))
        elseif method == 2 then
            local ms = math.random(1,30000)
            camera.shutter.ms = ms
            d = math.abs(math.log(camera.shutter.ms,2) - math.log(ms,2))
        elseif method == 3 then
            local apex = math.random(-5*100,12*100)/100
            camera.shutter.apex = apex
            d = math.abs(camera.shutter.apex - apex)
        elseif method == 4 then
            local raw = math.random(16,152)
            camera.shutter.raw = raw
            d = math.abs(camera.shutter.raw - raw) / 8
        end

        -- difference between requested and actual shutter speed should be max 1.5/8 EV
        -- (most cameras accept 0, 3/8, 4/8, 5/8, 1 EV, the largest gap being 3/8 EV,
        --  and you should always get the nearest valid shutter speed)
        if d > 1.5/8 + 1e-3 then
328
            printf("Error: shutter delta %s EV\n", d)
329
330
331
332
        end

        -- seconds and ms fields should be consistent
        if math.abs(camera.shutter.value - camera.shutter.ms/1000) > 1e-3 then
333
            printf("Error: shutter %ss != %sms\n", camera.shutter.value, camera.shutter.ms)
334
335
336
        end
        
        -- seconds and apex should be consistent
337
        -- see http://dougkerr.net/Pumpkin/articles/APEX.pdf
338
        local expected_apex = math.log(1/camera.shutter.value,2)
339
        if math.abs(expected_apex - camera.shutter.apex) > 0.01 then
340
            printf("Error: shutter %ss != Tv%s, expected %s\n", camera.shutter.value, camera.shutter.apex, expected_apex)
341
342
343
344
345
        end
        
        -- setting shutter to the same value, using any method (s,ms,apex,raw)
        -- should not change anything
        for i,field in pairs{"value","ms","apex","raw"} do
346
347
348
349
350
            local current = {}
            current.apex  = camera.shutter.apex
            current.value = camera.shutter.value
            current.ms    = camera.shutter.ms
            current.raw   = camera.shutter.raw
351
352
353
            
            -- ms is integer, so tests at very low values will fail because of roundoff errors
            -- however, if we have set the shutter in ms from the beginning, it will work fine
354
            if field == "ms" and current.ms < 10 and method ~= 2 then
355
356
357
358
                -- how do you write "continue" in Lua?!
                field = "value"
            end
            
359
            camera.shutter[field] = current[field]
360
            
361
            if camera.shutter.value ~= current.value then
362
                printf("Error: shutter set to %s=%s, got %ss, expected %ss\n", field, current[field], camera.shutter.value, current.value)
363
            end
364
            if camera.shutter.ms ~= current.ms then
365
                printf("Error: shutter set to %s=%s, got %sms, expected %sms\n", field, current[field], camera.shutter.ms, current.ms)
366
            end
367
            if camera.shutter.apex ~= current.apex then
368
                printf("Error: shutter set to %s=%s, got Tv%s, expected Tv%s\n", field, current[field], camera.shutter.apex, current.apex)
369
            end
370
            if camera.shutter.raw ~= current.raw then
371
                printf("Error: shutter set to %s=%s, got %s, expected %s (raw)\n", field, current[field], camera.shutter.raw, current.raw)
372
373
374
            end
        end
    end
375
    camera.shutter.raw = old_value
376

377
    request_mode(MODE.M, "M")
378
    old_value = camera.iso.raw
379
    printf("Setting ISO to random values...\n")
380
    for k = 1,100 do
381
382
        local method = math.random(1,3)
        local d = nil
383
384
        if method == 1 then
            local iso = math.random(100, 6400)
385
386
387
388
389
            if math.random(1,2) == 1 then
                camera.iso.value = iso
            else
                camera.iso = iso
            end
390
391
392
393
394
395
396
397
398
399
400
401
402
            d = math.abs(math.log(camera.iso.value,2) - math.log(iso,2))
        elseif method == 2 then
            local apex = math.random(5*100,11*100)/100
            camera.iso.apex = apex
            d = math.abs(camera.iso.apex - apex)
        elseif method == 3 then
            local raw = math.random(72, 120)
            camera.iso.raw = raw
            d = math.abs(camera.iso.raw - raw) / 8
        end

        -- difference between requested and actual ISO should be max 1/3 EV
        if d > 1/3 then
403
            printf("Error: ISO delta %s EV\n", d)
404
405
406
        end

        -- ISO and Sv (APEX) should be consistent
407
        local expected_apex = math.log(camera.iso.value/3.125, 2)
408
        if math.abs(expected_apex - camera.iso.apex) > 0.2 then
409
            printf("Error: ISO %s != Sv%s, expected %s\n", camera.iso.value, camera.iso.apex, expected_apex)
410
411
412
413
414
        end

        -- setting ISO to the same value, using any method (value,apex,raw)
        -- should not change anything
        for i,field in pairs{"value","apex","raw"} do
415
416
417
418
            local current = {}
            current.apex  = camera.iso.apex
            current.value = camera.iso.value
            current.raw   = camera.iso.raw
419
            
420
            camera.iso[field] = current[field]
421
            
422
            if camera.iso.value ~= current.value then
423
                printf("Error: ISO set to %s=%s, got %s, expected %s\n", field, current[field], camera.iso.value, current.value)
424
            end
425
            if camera.iso.apex ~= current.apex then
426
                printf("Error: ISO set to %s=%s, got Sv%s, expected Sv%s\n", field, current[field], camera.iso.apex, current.apex)
427
            end
428
            if camera.iso.raw ~= current.raw then
429
                printf("Error: ISO set to %s=%s, got %s, expected %s (raw)\n", field, current[field], camera.iso.raw, current.raw)
430
431
432
            end
        end
    end
433
    camera.iso.raw = old_value
434

a1ex's avatar
a1ex committed
435
    if camera.aperture.min.raw == camera.aperture.max.raw then
436
        printf("This lens does not have variable aperture (skipping test).\n")
a1ex's avatar
a1ex committed
437
438
    else
        request_mode(MODE.M, "M")
439
        old_value = camera.aperture.raw
440
        printf("Setting aperture to random values...\n")
a1ex's avatar
a1ex committed
441
        for k = 1,100 do
442
443
444
            local method = math.random(1,3)
            local d = nil
            local extra_tol = 0
a1ex's avatar
a1ex committed
445
446
            if method == 1 then
                local av = math.random(round(camera.aperture.min.value*10), round(camera.aperture.max.value*10)) / 10
447
448
449
450
451
                if math.random(1,2) == 1 then
                    camera.aperture.value = av
                else
                    camera.aperture = av
                end
a1ex's avatar
a1ex committed
452
                d = math.abs(math.log(camera.aperture.value,2) - math.log(av,2)) * 2
453
454
                -- when checking the result, allow a larger difference (0.1 units) - see note below
                extra_tol = math.abs(math.log(av,2) - math.log(av-0.1,2)) * 2
a1ex's avatar
a1ex committed
455
456
457
458
459
460
461
462
463
464
465
            elseif method == 2 then
                local apex = math.random(round(camera.aperture.min.apex*100), round(camera.aperture.max.apex*100)) / 100
                camera.aperture.apex = apex
                d = math.abs(camera.aperture.apex - apex)
            elseif method == 3 then
                local raw = math.random(camera.aperture.min.raw, camera.aperture.max.raw)
                camera.aperture.raw = raw
                d = math.abs(camera.aperture.raw - raw) / 8
            end

            -- difference between requested and actual aperture should be max 1.5/8 EV
466
467
468
            -- note: when using F-numbers, the difference may be larger, because of the rounding done
            -- to match Canon values (e.g. raw 48 would be f/5.66 (f/5.7), instead of Canon's f/5.6)
            if (d > 1.5/8 + extra_tol) then
alex@thinkpad's avatar
alex@thinkpad committed
469
                printf("Error: aperture delta %s EV (expected < %s, %s, method=%d)\n", d, 1.5/8 + extra_tol, camera.aperture, method)
a1ex's avatar
a1ex committed
470
471
472
            end

            -- aperture and Av (APEX) should be consistent
473
            local expected_apex = math.log(camera.aperture.value, 2) * 2
a1ex's avatar
a1ex committed
474
            if math.abs(expected_apex - camera.aperture.apex) > 0.2 then
475
                printf("Error: aperture %s != Av%s, expected %s\n", camera.aperture.value, camera.aperture.apex, expected_apex)
a1ex's avatar
a1ex committed
476
477
478
479
480
            end

            -- setting aperture to the same value, using any method (value,apex,raw)
            -- should not change anything
            for i,field in pairs{"value","apex","raw"} do
481
482
483
484
                local current = {}
                current.apex  = camera.aperture.apex
                current.value = camera.aperture.value
                current.raw   = camera.aperture.raw
a1ex's avatar
a1ex committed
485
                
486
                camera.aperture[field] = current[field]
a1ex's avatar
a1ex committed
487
                
488
                if camera.aperture.value ~= current.value then
489
                    printf("Error: aperture set to %s=%s, got %s, expected %s\n", field, current[field], camera.aperture.value, current.value)
a1ex's avatar
a1ex committed
490
                end
491
                if camera.aperture.apex ~= current.apex then
492
                    printf("Error: aperture set to %s=%s, got Sv%s, expected Sv%s\n", field, current[field], camera.aperture.apex, current.apex)
a1ex's avatar
a1ex committed
493
                end
494
                if camera.aperture.raw ~= current.raw then
495
                    printf("Error: aperture set to %s=%s, got %s, expected %s (raw)\n", field, current[field], camera.aperture.raw, current.raw)
a1ex's avatar
a1ex committed
496
497
498
                end
            end
        end
499
        camera.aperture.raw = old_value
a1ex's avatar
a1ex committed
500
501
    end

502
    request_mode(MODE.AV, "Av")
503
    old_value = camera.ec.raw
504
    printf("Setting EC to random values...\n")
505
    for k = 1,100 do
506
507
        local method = math.random(1,2)
        local d = nil
508
509
        if method == 1 then
            local ec = math.random(-2*100, 2*100) / 100
510
511
512
513
514
            if math.random(1,2) == 1 then
                camera.ec.value = ec
            else
                camera.ec = ec
            end
515
516
517
518
519
520
521
522
523
            d = math.abs(camera.ec.value - ec,2)
        elseif method == 2 then
            local raw = math.random(-16, 16)
            camera.ec.raw = raw
            d = math.abs(camera.ec.raw - raw) / 8
        end

        -- difference between requested and actual EC should be max 1.5/8 EV
        if d > 1.5/8 then
524
            printf("Error: EC delta %s EV\n", d)
525
526
527
        end

        -- EC and raw should be consistent
528
        local expected_ec = camera.ec.raw / 8
529
        if math.abs(expected_ec - camera.ec.value) > 0.001 then
530
            printf("Error: EC raw %s != %s EV, expected %s EV\n", camera.ec.raw, camera.ec.value, expected_ec)
531
532
533
534
535
        end

        -- setting EC to the same value, using any method (value,raw)
        -- should not change anything
        for i,field in pairs{"value","raw"} do
536
537
538
            local current = {}
            current.value = camera.ec.value
            current.raw   = camera.ec.raw
539
            
540
            camera.ec[field] = current[field]
541
            
542
            if camera.ec.value ~= current.value then
543
                printf("Error: EC set to %s=%s, got %s, expected %s EV\n", field, current[field], camera.ec.value, current.value)
544
            end
545
            if camera.ec.raw ~= current.raw then
546
                printf("Error: EC set to %s=%s, got %s, expected %s (raw)\n", field, current[field], camera.ec.raw, current.raw)
547
548
549
            end
        end
    end
550
    camera.ec.raw = old_value
551
552

    -- copy/paste & replace from EC (those two should behave in the same way)
553
    old_value = camera.flash_ec.raw
554
    printf("Setting Flash EC to random values...\n")
555
    for k = 1,100 do
556
557
        local method = math.random(1,2)
        local d = nil
558
559
        if method == 1 then
            local fec = math.random(-2*100, 2*100) / 100
560
561
562
563
564
            if math.random(1,2) == 1 then
                camera.flash_ec.value = fec
            else
                camera.flash_ec = fec
            end
565
566
567
568
569
570
571
572
573
            d = math.abs(camera.flash_ec.value - fec,2)
        elseif method == 2 then
            local raw = math.random(-16, 16)
            camera.flash_ec.raw = raw
            d = math.abs(camera.flash_ec.raw - raw) / 8
        end

        -- difference between requested and actual EC should be max 1.5/8 EV
        if d > 1.5/8 then
574
            printf("Error: FEC delta %s EV\n", d)
575
576
577
        end

        -- EC and raw should be consistent
578
        local expected_fec = camera.flash_ec.raw / 8
579
        if math.abs(expected_fec - camera.flash_ec.value) > 0.001 then
580
            printf("Error: FEC raw %s != %s EV, expected %s EV\n", camera.flash_ec.raw, camera.flash_ec.value, current.expected_fec)
581
582
583
584
585
        end

        -- setting EC to the same value, using any method (value,raw)
        -- should not change anything
        for i,field in pairs{"value","raw"} do
586
587
588
            local current = {}
            current.value = camera.flash_ec.value
            current.raw   = camera.flash_ec.raw
589
            
590
            camera.flash_ec[field] = current[field]
591
            
592
            if camera.flash_ec.value ~= current.value then
593
                printf("Error: FEC set to %s=%s, got %s, expected %s EV\n", field, current[field], camera.flash_ec.value, current.value)
594
            end
595
            if camera.flash_ec.raw ~= current.raw then
596
                printf("Error: FEC set to %s=%s, got %s, expected %s (raw)\n", field, current[field], camera.flash_ec.raw, current.raw)
597
598
599
            end
        end
    end
600
    camera.flash_ec.raw = old_value
601

602
603
    printf("Exposure tests completed.\n")
    printf("\n")
604
605
end

606
function test_camera_take_pics()
alex@thinkpad's avatar
alex@thinkpad committed
607
    printf("Testing picture taking functions...\n")
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
    local initial_file_num

    request_mode(MODE.M, "M")
    camera.shutter = 1/50
    msleep(2000)
    
    printf("Snap simulation test...\n")
    assert(menu.set("Shoot Preferences", "Snap Simulation", 1))
    initial_file_num = dryos.shooting_card.file_number
    camera.shoot()
    assert(dryos.shooting_card.file_number == initial_file_num)
    assert(menu.set("Shoot Preferences", "Snap Simulation", 0))

    msleep(2000)

    printf("Single picture...\n")
    initial_file_num = dryos.shooting_card.file_number
    camera.shoot()
    assert((dryos.shooting_card.file_number - initial_file_num) % 10000 == 1)
    
    msleep(2000)

    printf("Two burst pictures...\n")
    printf("Ideally, the camera should be in some continuous shooting mode (not checked).\n")
    initial_file_num = dryos.shooting_card.file_number
    camera.burst(2)
    assert((dryos.shooting_card.file_number - initial_file_num) % 10000 == 2)

    msleep(2000)

    printf("Bulb picture...\n")
    local t0 = dryos.ms_clock
    initial_file_num = dryos.shooting_card.file_number
    camera.bulb(10)
    local t1 = dryos.ms_clock
    local elapsed = t1 - t0
    printf("Elapsed time: %s\n", elapsed)
    -- we can't measure this time accurately, so we only do a very rough check
alex@thinkpad's avatar
alex@thinkpad committed
646
    assert(elapsed > 9900 and elapsed < 16000)
647
648
649
    assert((dryos.shooting_card.file_number - initial_file_num) % 10000 == 1)

    printf("Picture taking tests completed.\n")
alex@thinkpad's avatar
alex@thinkpad committed
650
    printf("\n")
651
652
end

653
function test_lv()
654
    printf("Testing module 'lv'...\n")
655
    if lv.enabled then
656
        printf("LiveView is running; stopping...\n")
657
658
659
660
661
        lv.stop()
        assert(not lv.enabled, "LiveView did not stop")
        msleep(2000)
    end

662
    printf("Starting LiveView...\n")
663
664
665
666
667
668
    lv.start()
    assert(lv.enabled, "LiveView did not start")

    msleep(2000)
    
    for i,z in pairs{1, 5, 10, 5, 1, 10, 1} do
669
        printf("Setting zoom to x%d...\n", z)
670
671
672
673
674
        lv.zoom = z
        assert(lv.zoom == z, "Could not set zoom in LiveView ")
        lv.wait(5)
    end

675
    printf("Pausing LiveView...\n")
676
677
678
679
680
681
    lv.pause()
    assert(lv.enabled, "LiveView stopped")
    assert(lv.paused, "LiveView could not be paused")

    msleep(2000)

682
    printf("Resuming LiveView...\n")
683
684
685
686
687
688
    lv.resume()
    assert(lv.enabled, "LiveView stopped")
    assert(not lv.paused, "LiveView could not be resumed")

    msleep(2000)

689
    printf("Stopping LiveView...\n")
690
691
692
693
694
695
696
697
    lv.stop()

    assert(not lv.enabled, "LiveView did not stop")
    assert(not lv.paused,  "LiveView is disabled, can't be paused")
    assert(not lv.running, "LiveView is disabled, can't be running")

    msleep(1000)

698
699
    printf("LiveView tests completed.\n")
    printf("\n")
700
701
end

702
function test_lens_focus()
alex@thinkpad's avatar
alex@thinkpad committed
703
704
705
    printf("\n")
    printf("Testing lens focus functionality...\n")
    
706
    if lens.name == "" then
707
        printf("This test requires an electronic lens.\n")
708
709
710
711
712
        assert(not lens.af, "manual lenses can't autofocus")
        return
    end
    
    if not lens.af then
713
714
        printf("Please enable autofocus.\n")
        printf("(or, remove the lens from the camera to skip this test)\n")
715
716
717
718
        while not lens.af and lens.name ~= "" do
            console.show()
            msleep(1000)
        end
719
        msleep(1000)
720
    end
721

722
    if not lv.running then
723
724
725
        printf("Autofocus outside LiveView...\n")
        assert(lens.autofocus())

726
727
728
        lv.start()
        assert(lv.running)
    end
729

730
    if lens.af then
731
        printf("Focus distance: %s\n",  lens.focus_distance)
732

733
734
735
736
737
        printf("Autofocus in LiveView...\n")
        assert(lens.autofocus())

        printf("Focus distance: %s\n",  lens.focus_distance)

738
739
        -- note: focus direction is not consistent
        -- some lenses will focus to infinity, others to macro
740
        printf("Focusing backward...\n")
741
        while lens.focus(-1,3,true) do end
742
        printf("Focus distance: %s\n",  lens.focus_distance)
743

744
745
        msleep(500)
        
746
        for i,step in pairs{3,2,1} do
747
            for j,wait in pairs{true,false} do
748
                printf("Focusing forward with step size %d, wait=%s...\n", step, wait)
749
                local steps_front = 0
750
                while lens.focus(1,step,wait) do
751
                    printf(".")
752
753
                    steps_front = steps_front + 1
                end
754
755
                printf("\n")
                printf("Focus distance: %s\n",  lens.focus_distance)
756
757
758
                
                msleep(500)
                
759
                printf("Focusing backward with step size %d, wait=%s...\n", step, wait)
760
                local steps_back = 0
761
                while lens.focus(-1,step,wait) do
762
                    printf(".")
763
764
                    steps_back = steps_back + 1
                end
765
766
                printf("\n")
                printf("Focus distance: %s\n",  lens.focus_distance)
767

768
                msleep(500)
769

770
                printf("Focus range: %s steps forward, %s steps backward. \n",  steps_front, steps_back)
771
            end
772
        end
773
        printf("Focus test completed.\n")
774
    else
775
        printf("Focus test skipped.\n")
776
    end
777
    printf("\n")
778
779
end

780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
function test_movie()
    printf("\n")
    printf("Testing movie recording...\n")

    -- we must be in photo mode (from previous tests)
    assert(camera.mode ~= MODE.MOVIE)

    -- this should raise error
    local s,e = pcall(movie.start)
    assert(s == false)
    assert(e:find("movie mode"))

    request_mode(MODE.MOVIE, "Movie")

    -- this should also raise error, as we are not exactly in LiveView
    lv.pause()
    local s,e = pcall(movie.start)
    assert(s == false)
    assert(e:find("LiveView"))
    menu.close()
    lv.resume()

    -- this should raise error, because the LiveView button has a special
    -- function in ML menu (so we can't just press it to start recording)
    menu.open()
    local s,e = pcall(movie.start)
    assert(s == false)
    assert(e:find("menu"))
    menu.close()

    -- now it should work
    -- hide the console for a nicer look
    console.hide()
    movie.start()
    assert(movie.recording)
    msleep(1000)
    movie.stop()
    assert(not movie.recording)
    console.show()

    printf("Movie recording tests completed.\n")
    printf("\n")
end

824
825
826
827
828
829
function api_tests()
    menu.close()
    console.clear()
    console.show()
    test_log = logger("LUATEST.LOG")

alex@thinkpad's avatar
alex@thinkpad committed
830
    -- note: each test routine must print a blank line at the end
831
832
833
    strict_tests()
    generic_tests()
    
834
    printf("Module tests...\n")
835
    test_io()
836
    --test_multitasking()
837
    test_keys()
838
    test_lv()
839
    test_lens_focus()
alex@thinkpad's avatar
alex@thinkpad committed
840
841
    test_camera_take_pics()
    test_camera_exposure()
842
    test_movie()
843
    
844
    printf("Done!\n")
845
846
    
    test_log:close()
847
848
849
850
    key.wait()
    console.hide()
end

851
852
853
854
-- check script arguments
assert(#arg == 0)
assert(arg[0] == "API_TEST.LUA" or arg[0] == "api_test.lua")

855
api_tests()