|
| 1 | +/* |
| 2 | + * This Source Code Form is subject to the terms of the Mozilla Public |
| 3 | + * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 4 | + * file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| 5 | + */ |
| 6 | + |
| 7 | +use std::{collections::HashSet, thread}; |
| 8 | + |
| 9 | +use godot::{ |
| 10 | + engine::RenderingServer, |
| 11 | + prelude::{inner::InnerRid, Color, Rid, Vector2}, |
| 12 | +}; |
| 13 | + |
| 14 | +use crate::{itest, suppress_godot_print}; |
| 15 | + |
| 16 | +#[itest] |
| 17 | +fn rid_equiv() { |
| 18 | + let invalid: Rid = Rid::Invalid; |
| 19 | + let valid: Rid = Rid::new((10 << 32) | 20); |
| 20 | + assert!(!InnerRid::from_outer(&invalid).is_valid()); |
| 21 | + assert!(InnerRid::from_outer(&valid).is_valid()); |
| 22 | + |
| 23 | + assert_eq!(InnerRid::from_outer(&invalid).get_id(), 0); |
| 24 | + assert_eq!(InnerRid::from_outer(&valid).get_id(), (10 << 32) | 20); |
| 25 | +} |
| 26 | + |
| 27 | +#[itest] |
| 28 | +fn canvas_set_parent() { |
| 29 | + // This originally caused UB, but still testing it here in case it breaks. |
| 30 | + let mut server = RenderingServer::singleton(); |
| 31 | + let canvas = server.canvas_create(); |
| 32 | + let viewport = server.viewport_create(); |
| 33 | + |
| 34 | + suppress_godot_print(|| server.canvas_item_set_parent(viewport, canvas)); |
| 35 | + suppress_godot_print(|| server.canvas_item_set_parent(viewport, viewport)); |
| 36 | + |
| 37 | + server.free_rid(canvas); |
| 38 | + server.free_rid(viewport); |
| 39 | +} |
| 40 | + |
| 41 | +#[itest] |
| 42 | +fn multi_thread_test() { |
| 43 | + let threads = (0..10) |
| 44 | + .map(|_| { |
| 45 | + thread::spawn(|| { |
| 46 | + let mut server = RenderingServer::singleton(); |
| 47 | + (0..1000).map(|_| server.canvas_item_create()).collect() |
| 48 | + }) |
| 49 | + }) |
| 50 | + .collect::<Vec<_>>(); |
| 51 | + |
| 52 | + let mut rids: Vec<Rid> = vec![]; |
| 53 | + |
| 54 | + for thread in threads.into_iter() { |
| 55 | + rids.append(&mut thread.join().unwrap()); |
| 56 | + } |
| 57 | + |
| 58 | + let set = rids.iter().cloned().collect::<HashSet<_>>(); |
| 59 | + assert_eq!(set.len(), rids.len()); |
| 60 | + |
| 61 | + let mut server = RenderingServer::singleton(); |
| 62 | + |
| 63 | + for rid in rids.iter() { |
| 64 | + server.canvas_item_add_circle(*rid, Vector2::ZERO, 1.0, Color::from_rgb(1.0, 0.0, 0.0)); |
| 65 | + } |
| 66 | + |
| 67 | + for rid in rids.iter() { |
| 68 | + server.free_rid(*rid); |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +/// Check that godot does not crash upon receiving various RIDs that may be edge cases. As it could do in Godot 3. |
| 73 | +#[itest] |
| 74 | +fn strange_rids() { |
| 75 | + let mut server = RenderingServer::singleton(); |
| 76 | + let mut rids: Vec<u64> = vec![ |
| 77 | + // Invalid RID. |
| 78 | + 0, |
| 79 | + // Normal RID, should work without issue. |
| 80 | + 1, |
| 81 | + 10, |
| 82 | + // Testing the boundaries of various ints. |
| 83 | + u8::MAX as u64, |
| 84 | + u16::MAX as u64, |
| 85 | + u32::MAX as u64, |
| 86 | + u64::MAX, |
| 87 | + i8::MIN as u64, |
| 88 | + i8::MAX as u64, |
| 89 | + i16::MIN as u64, |
| 90 | + i16::MAX as u64, |
| 91 | + i32::MIN as u64, |
| 92 | + i32::MAX as u64, |
| 93 | + i64::MIN as u64, |
| 94 | + i64::MAX as u64, |
| 95 | + // Biggest RIDs possible in Godot (ignoring local indices). |
| 96 | + 0xFFFFFFFF << 32, |
| 97 | + 0x7FFFFFFF << 32, |
| 98 | + // Godot's servers treats RIDs as two u32s, so testing what happens round the region where |
| 99 | + // one u32 overflows into the next. |
| 100 | + u32::MAX as u64 + 1, |
| 101 | + u32::MAX as u64 + 2, |
| 102 | + u32::MAX as u64 - 1, |
| 103 | + u32::MAX as u64 - 2, |
| 104 | + // A couple random RIDs. |
| 105 | + 1234567891011121314, |
| 106 | + 14930753991246632225, |
| 107 | + 8079365198791785081, |
| 108 | + 10737267678893224303, |
| 109 | + 12442588258967011829, |
| 110 | + 4275912429544145425, |
| 111 | + ]; |
| 112 | + // Checking every number with exactly 2 bits = 1. |
| 113 | + // An approximation of exhaustively checking every number. |
| 114 | + for i in 0..64 { |
| 115 | + for j in 0..63 { |
| 116 | + if j >= i { |
| 117 | + rids.push((1 << i) | (1 << (j + 1))) |
| 118 | + } else { |
| 119 | + rids.push((1 << i) | (1 << j)) |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + for id in rids.iter() { |
| 125 | + suppress_godot_print(|| server.canvas_item_clear(Rid::new(*id))) |
| 126 | + } |
| 127 | +} |
0 commit comments