1 module during.tests.api;
2 
3 import during;
4 
5 version (D_Exceptions) import std.exception : assertThrown;
6 import std.range;
7 
8 @("Submission variants")
9 unittest
10 {
11     Uring io;
12     auto res = io.setup();
13     assert(res >= 0, "Error initializing IO");
14 
15     SubmissionEntry entry;
16     entry.opcode = Operation.NOP;
17     entry.user_data = 1;
18 
19     struct MyOp
20     {
21         Operation opcode = Operation.NOP;
22         ulong user_data;
23     }
24 
25     // chain operations
26     io
27         .put(entry)
28         .put(MyOp(Operation.NOP, 2))
29         .putWith!((ref SubmissionEntry e) { e.prepNop(); e.user_data = 42; })
30         .submit(1); // submit operations and wait for at least 1 completed
31 
32     // check completions
33     assert(!io.empty);
34     assert(io.front.user_data == 1);
35     io.popFront();
36     io.wait(2);
37     assert(io.front.user_data == 2);
38     io.popFront();
39     assert(!io.empty);
40     assert(io.front.user_data == 42);
41     io.popFront();
42     assert(io.empty);
43 }
44 
45 @("Limits")
46 unittest
47 {
48     struct Nop { Operation opcode = Operation.NOP; }
49 
50     Uring io;
51     auto res = io.setup(16);
52     assert(res >= 0, "Error initializing IO");
53     assert(io.empty);
54     assert(!io.length);
55     assert(!io.full);
56     assert(io.capacity == 16);
57     assert(io.params.sq_entries == 16);
58     assert(io.params.cq_entries == 32);
59 
60     // fill submission queue
61     foreach (_; 0..16) io.put(Nop());
62     assert(io.capacity == 0);
63     assert(io.full);
64     assert(io.empty);
65     assert(!io.length);
66     assert(!io.overflow);
67     assert(!io.dropped);
68     version(D_Exceptions) assertThrown!Throwable(io.put(Nop()));
69 
70     io.submit(0); // submit them all
71     assert(io.capacity == 16);
72     assert(!io.full);
73     assert(!io.dropped);
74 
75     io.wait(10);
76     assert(io.capacity == 16);
77     assert(!io.full);
78     assert(!io.dropped);
79     assert(!io.empty);
80     assert(io.length == 16);
81     assert(!io.overflow);
82     io.popFront();
83     assert(io.length == 15);
84 
85     // fill up completion queue
86     foreach (_; 0..16) io.put(Nop());
87     io.submit(16); // submit them and wait for all
88     assert(io.length == 31);
89     assert(!io.overflow); // still no overflow
90 
91     // cause overflow
92     foreach (_; 0..2) io.put(Nop());
93     io.submit(2);
94     assert(io.length == 32);
95     assert(io.overflow == 1); // oops
96 
97     io.drop(32);
98     assert(io.empty);
99     assert(io.length == 0);
100 
101     // put there another batch
102     foreach (_; 0..16) io.put(Nop());
103     io.submit(0);
104     io.wait(16);
105     assert(io.length == 16);
106     assert(io.overflow == 1);
107 }
108 
109 @("Range interface")
110 unittest
111 {
112     import std.algorithm : copy, equal, map;
113 
114     Uring io;
115     auto res = io.setup(16);
116     assert(res >= 0, "Error initializing IO");
117 
118     struct MyOp { Operation opcode; ulong user_data; }
119     static assert(isOutputRange!(Uring, MyOp));
120 
121     // add 32 entries (in 2 batches as we have capacity only for 16 entries)
122     iota(0, 16).map!(a => MyOp(Operation.NOP, a)).copy(io);
123     assert(io.capacity == 0);
124     assert(io.full);
125     res = io.submit(0); // just submit
126     assert(res == 16);
127     iota(16, 32).map!(a => MyOp(Operation.NOP, a)).copy(io);
128     res = io.submit(32); // submit and wait
129     assert(res == 16);
130     assert(!io.empty);
131     assert(io.length == 32);
132     assert(io.map!(c => c.user_data).equal(iota(0, 32)));
133 }