summaryrefslogtreecommitdiff
path: root/test/util/UtilTest.mc
blob: c19d6d0862779b02b58a955dca4e17347821a4f5 (plain) (blame)
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
// Author:  cirakg & claude ai
// Summary: Tests for the byte helpers, the 2038-safe clock widening and the job runner.

import Toybox.Lang;
import Toybox.Test;

(:test)
function bytesConversions(logger as Test.Logger) as Boolean {
    return Bytes.toHex(Bytes.fromHex("00FFa5")).equals("00ffa5")
        && Bytes.equal(Bytes.fromUtf8("é"), [0xc3, 0xa9]b)
        && Bytes.fromHex("").size() == 0 && Bytes.toHex([]b).equals("")
        && Bytes.equal(Bytes.concat([1]b, [2, 3]b), [1, 2, 3]b)
        && Bytes.equal(Bytes.uint64BigEndian(1l), [0, 0, 0, 0, 0, 0, 0, 1]b)
        && Bytes.equal(Bytes.uint64BigEndian(-1l), [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]b)
        && Bytes.equal(Bytes.uint64BigEndian(20000000000l / 30), [0, 0, 0, 0, 0x27, 0xbc, 0x86, 0xaa]b)
        && Bytes.equal(Bytes.uint32BigEndian(0x01020304), [1, 2, 3, 4]b);
}

(:test)
function bytesEqualWipeAndXor(logger as Test.Logger) as Boolean {
    var a = [1, 2, 3]b;
    var copy = Bytes.copy(a);
    Bytes.xorInto(copy, [1, 2, 3]b);
    var wiped = [5, 6]b;
    Bytes.wipe(wiped);
    Bytes.wipe(null);
    return Bytes.equal(a, [1, 2, 3]b) && !Bytes.equal(a, [1, 2]b) && !Bytes.equal(a, [1, 2, 4]b)
        && Bytes.equal(copy, [0, 0, 0]b) && Bytes.equal(wiped, [0, 0]b);
}

// After 2038-01-19 the watch's 32-bit clock value is negative; read as
// unsigned it keeps counting up to 2106.
(:test)
function clockWidensTo64Bits(logger as Test.Logger) as Boolean {
    return Clock.toUnsigned(0x7FFFFFFF) == 2147483647l
        && Clock.toUnsigned(0x7FFFFFFF + 1) == 2147483648l
        && Clock.toUnsigned(-1) == 4294967295l
        && Clock.toUnsigned(0) == 0l
        && Clock.nowUnix(0) > 1700000000l
        && Clock.nowUnix(60) - Clock.nowUnix(0) >= 59l;
}

(:test)
module JobFixtures {
    class CountingJob extends Jobs.Job {
        var done as Number = 0;
        var calls as Number = 0;

        function initialize() {
            Job.initialize();
        }

        function step(budget as Number) as Boolean {
            calls++;
            done += budget;
            return done >= 10;
        }
    }
}

(:test)
function jobsRunToCompletion(logger as Test.Logger) as Boolean {
    var job = new JobFixtures.CountingJob();
    Jobs.runToCompletion(job, 3);
    return job.calls == 4 && job.done == 12;
}

(:test)
function bytesUtf8Validation(logger as Test.Logger) as Boolean {
    var valid = [[0x41]b, [0xC3, 0xA9]b, [0xE2, 0x82, 0xAC]b, [0xF0, 0x9F, 0x98, 0x80]b, [0xF4, 0x8F, 0xBF, 0xBF]b];
    var invalid = [
        [0x00]b,                   // NUL
        [0xC0, 0x80]b,             // overlong NUL
        [0xE0, 0x80, 0x80]b,       // overlong
        [0xED, 0xA0, 0x80]b,       // surrogate
        [0xF4, 0x90, 0x80, 0x80]b, // above U+10FFFF
        [0xF5, 0x80, 0x80, 0x80]b, // invalid lead byte
        [0xE2, 0x82]b,             // truncated
        [0x80]b,                   // lone continuation
        [0xC3, 0x28]b              // bad continuation
    ];
    for (var i = 0; i < valid.size(); i++) {
        var text = Bytes.toUtf8(valid[i] as ByteArray);
        if (text == null || !Bytes.equal(Bytes.fromUtf8(text), valid[i] as ByteArray)) {
            logger.error("valid UTF-8 case " + i + " rejected or changed");
            return false;
        }
    }
    for (var i = 0; i < invalid.size(); i++) {
        if (Bytes.toUtf8(invalid[i] as ByteArray) != null) {
            logger.error("invalid UTF-8 case " + i + " accepted");
            return false;
        }
    }
    return true;
}