Skip to content

Commit cccfa8a

Browse files
committed
Add test cases for select
1 parent f34fadd commit cccfa8a

File tree

2 files changed

+254
-0
lines changed

2 files changed

+254
-0
lines changed

src/libstd/rt/select.rs

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,231 @@ pub fn select2<TA, A: SelectPort<TA>, TB, B: SelectPort<TB>>(mut a: A, mut b: B)
100100
}
101101
102102
*/
103+
104+
#[cfg(test)]
105+
mod test {
106+
use super::*;
107+
use option::*;
108+
use rt::comm::*;
109+
use rt::test::*;
110+
use vec::*;
111+
use comm::GenericChan;
112+
use task;
113+
use cell::Cell;
114+
115+
#[test] #[ignore(cfg(windows))] #[should_fail]
116+
fn select_doesnt_get_trolled() {
117+
select::<PortOne<()>>([]);
118+
}
119+
120+
/* non-blocking select tests */
121+
122+
#[cfg(test)]
123+
fn select_helper(num_ports: uint, send_on_chans: &[uint]) {
124+
// Unfortunately this does not actually test the block_on early-break
125+
// codepath in select -- racing between the sender and the receiver in
126+
// separate tasks is necessary to get around the optimistic check.
127+
let (ports, chans) = unzip(from_fn(num_ports, |_| oneshot::<()>()));
128+
let mut dead_chans = ~[];
129+
let mut ports = ports;
130+
for chans.consume_iter().enumerate().advance |(i, chan)| {
131+
if send_on_chans.contains(&i) {
132+
chan.send(());
133+
} else {
134+
dead_chans.push(chan);
135+
}
136+
}
137+
let ready_index = select(ports);
138+
assert!(send_on_chans.contains(&ready_index));
139+
assert!(ports.swap_remove(ready_index).recv_ready().is_some());
140+
let _ = dead_chans;
141+
142+
// Same thing with streams instead.
143+
// FIXME(#7971): This should be in a macro but borrowck isn't smart enough.
144+
let (ports, chans) = unzip(from_fn(num_ports, |_| stream::<()>()));
145+
let mut dead_chans = ~[];
146+
let mut ports = ports;
147+
for chans.consume_iter().enumerate().advance |(i, chan)| {
148+
if send_on_chans.contains(&i) {
149+
chan.send(());
150+
} else {
151+
dead_chans.push(chan);
152+
}
153+
}
154+
let ready_index = select(ports);
155+
assert!(send_on_chans.contains(&ready_index));
156+
assert!(ports.swap_remove(ready_index).recv_ready().is_some());
157+
let _ = dead_chans;
158+
}
159+
160+
#[test]
161+
fn select_one() {
162+
do run_in_newsched_task { select_helper(1, [0]) }
163+
}
164+
165+
#[test]
166+
fn select_two() {
167+
// NB. I would like to have a test that tests the first one that is
168+
// ready is the one that's returned, but that can't be reliably tested
169+
// with the randomized behaviour of optimistic_check.
170+
do run_in_newsched_task { select_helper(2, [1]) }
171+
do run_in_newsched_task { select_helper(2, [0]) }
172+
do run_in_newsched_task { select_helper(2, [1,0]) }
173+
}
174+
175+
#[test]
176+
fn select_a_lot() {
177+
do run_in_newsched_task { select_helper(12, [7,8,9]) }
178+
}
179+
180+
#[test]
181+
fn select_stream() {
182+
use util;
183+
use comm::GenericChan;
184+
185+
// Sends 10 buffered packets, and uses select to retrieve them all.
186+
// Puts the port in a different spot in the vector each time.
187+
do run_in_newsched_task {
188+
let (ports, _) = unzip(from_fn(10, |_| stream()));
189+
let (port, chan) = stream();
190+
for 10.times { chan.send(31337); }
191+
let mut ports = ports;
192+
let mut port = Some(port);
193+
let order = [5u,0,4,3,2,6,9,8,7,1];
194+
for order.iter().advance |&index| {
195+
// put the port in the vector at any index
196+
util::swap(port.get_mut_ref(), &mut ports[index]);
197+
assert!(select(ports) == index);
198+
// get it back out
199+
util::swap(port.get_mut_ref(), &mut ports[index]);
200+
// NB. Not recv(), because optimistic_check randomly fails.
201+
let (data, new_port) = port.take_unwrap().recv_ready().unwrap();
202+
assert!(data == 31337);
203+
port = Some(new_port);
204+
}
205+
}
206+
}
207+
208+
#[test]
209+
fn select_unkillable() {
210+
do run_in_newsched_task {
211+
unsafe { do task::unkillable { select_helper(2, [1]) } }
212+
}
213+
}
214+
215+
/* blocking select tests */
216+
217+
#[test]
218+
fn select_blocking() {
219+
select_blocking_helper(true);
220+
select_blocking_helper(false);
221+
222+
fn select_blocking_helper(killable: bool) {
223+
do run_in_newsched_task {
224+
let (p1,_c) = oneshot();
225+
let (p2,c2) = oneshot();
226+
let mut ports = [p1,p2];
227+
228+
let (p3,c3) = oneshot();
229+
let (p4,c4) = oneshot();
230+
231+
let x = Cell::new((c2, p3, c4));
232+
do task::spawn {
233+
let (c2, p3, c4) = x.take();
234+
p3.recv(); // handshake parent
235+
c4.send(()); // normal receive
236+
task::yield();
237+
c2.send(()); // select receive
238+
}
239+
240+
// Try to block before child sends on c2.
241+
c3.send(());
242+
p4.recv();
243+
if killable {
244+
assert!(select(ports) == 1);
245+
} else {
246+
unsafe { do task::unkillable { assert!(select(ports) == 1); } }
247+
}
248+
}
249+
}
250+
}
251+
252+
#[test]
253+
fn select_racing_senders() {
254+
static NUM_CHANS: uint = 10;
255+
256+
select_racing_senders_helper(true, ~[0,1,2,3,4,5,6,7,8,9]);
257+
select_racing_senders_helper(false, ~[0,1,2,3,4,5,6,7,8,9]);
258+
select_racing_senders_helper(true, ~[0,1,2]);
259+
select_racing_senders_helper(false, ~[0,1,2]);
260+
select_racing_senders_helper(true, ~[3,4,5,6]);
261+
select_racing_senders_helper(false, ~[3,4,5,6]);
262+
select_racing_senders_helper(true, ~[7,8,9]);
263+
select_racing_senders_helper(false, ~[7,8,9]);
264+
265+
fn select_racing_senders_helper(killable: bool, send_on_chans: ~[uint]) {
266+
use uint;
267+
use rt::test::spawntask_random;
268+
269+
do run_in_newsched_task {
270+
// A bit of stress, since ordinarily this is just smoke and mirrors.
271+
for 4.times {
272+
let send_on_chans = send_on_chans.clone();
273+
do task::spawn {
274+
let mut ports = ~[];
275+
for uint::range(0, NUM_CHANS) |i| {
276+
let (p,c) = oneshot();
277+
ports.push(p);
278+
if send_on_chans.contains(&i) {
279+
let c = Cell::new(c);
280+
do spawntask_random {
281+
task::yield();
282+
c.take().send(());
283+
}
284+
}
285+
}
286+
// nondeterministic result, but should succeed
287+
if killable {
288+
select(ports);
289+
} else {
290+
unsafe { do task::unkillable { select(ports); } }
291+
}
292+
}
293+
}
294+
}
295+
}
296+
}
297+
298+
#[test] #[ignore(cfg(windows))]
299+
fn select_killed() {
300+
do run_in_newsched_task {
301+
let (success_p, success_c) = oneshot::<bool>();
302+
let success_c = Cell::new(success_c);
303+
do task::try {
304+
unsafe {
305+
let success_c = Cell::new(success_c.take());
306+
do task::unkillable {
307+
let (p,c) = oneshot();
308+
let c = Cell::new(c);
309+
do task::spawn {
310+
let (dead_ps, dead_cs) = unzip(from_fn(5, |_| oneshot::<()>()));
311+
let mut ports = dead_ps;
312+
select(ports); // should get killed; nothing should leak
313+
c.take().send(()); // must not happen
314+
// Make sure dead_cs doesn't get closed until after select.
315+
let _ = dead_cs;
316+
}
317+
do task::spawn {
318+
fail!(); // should kill sibling awake
319+
}
320+
321+
// wait for killed selector to close (NOT send on) its c.
322+
// hope to send 'true'.
323+
success_c.take().send(p.try_recv().is_none());
324+
}
325+
}
326+
};
327+
assert!(success_p.recv());
328+
}
329+
}
330+
}

src/libstd/unstable/sync.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,32 @@ mod tests {
444444
}
445445
}
446446

447+
#[test]
448+
fn arclike_newN() {
449+
// Tests that the many-refcounts-at-once constructors don't leak.
450+
let _ = UnsafeAtomicRcBox::new2(~~"hello");
451+
let x = UnsafeAtomicRcBox::newN(~~"hello", 0);
452+
assert_eq!(x.len(), 0)
453+
let x = UnsafeAtomicRcBox::newN(~~"hello", 1);
454+
assert_eq!(x.len(), 1)
455+
let x = UnsafeAtomicRcBox::newN(~~"hello", 10);
456+
assert_eq!(x.len(), 10)
457+
}
458+
459+
#[test]
460+
fn arclike_cloneN() {
461+
// Tests that the many-refcounts-at-once special-clone doesn't leak.
462+
let x = UnsafeAtomicRcBox::new(~~"hello");
463+
let x = x.cloneN(0);
464+
assert_eq!(x.len(), 0);
465+
let x = UnsafeAtomicRcBox::new(~~"hello");
466+
let x = x.cloneN(1);
467+
assert_eq!(x.len(), 1);
468+
let x = UnsafeAtomicRcBox::new(~~"hello");
469+
let x = x.cloneN(10);
470+
assert_eq!(x.len(), 10);
471+
}
472+
447473
#[test]
448474
fn arclike_unwrap_basic() {
449475
unsafe {

0 commit comments

Comments
 (0)