| 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); |
| 3 | const testing = std.testing; |
| 4 | const math = std.math; |
| 5 | |
| 6 | const helpers = @import("helpers"); |
| 7 | |
| 8 | const cast = helpers.cast; |
| 9 | |
| 10 | test cast { |
| 11 | var i = @as(i64, 10); |
| 12 | |
| 13 | try testing.expect(cast(*u8, 16) == @as(*u8, @ptrFromInt(16))); |
| 14 | try testing.expect(cast(*u64, &i).* == @as(u64, 10)); |
| 15 | try testing.expect(cast(*i64, @as(?*align(1) i64, &i)) == &i); |
| 16 | |
| 17 | try testing.expect(cast(?*u8, 2) == @as(*u8, @ptrFromInt(2))); |
| 18 | try testing.expect(cast(?*i64, @as(*align(1) i64, &i)) == &i); |
| 19 | try testing.expect(cast(?*i64, @as(?*align(1) i64, &i)) == &i); |
| 20 | |
| 21 | try testing.expectEqual(@as(u32, 4), cast(u32, @as(*u32, @ptrFromInt(4)))); |
| 22 | try testing.expectEqual(@as(u32, 4), cast(u32, @as(?*u32, @ptrFromInt(4)))); |
| 23 | try testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10))); |
| 24 | |
| 25 | try testing.expectEqual(@as(i32, @bitCast(@as(u32, 0x8000_0000))), cast(i32, @as(u32, 0x8000_0000))); |
| 26 | |
| 27 | try testing.expectEqual(@as(*u8, @ptrFromInt(2)), cast(*u8, @as(*const u8, @ptrFromInt(2)))); |
| 28 | try testing.expectEqual(@as(*u8, @ptrFromInt(2)), cast(*u8, @as(*volatile u8, @ptrFromInt(2)))); |
| 29 | |
| 30 | try testing.expectEqual(@as(?*anyopaque, @ptrFromInt(2)), cast(?*anyopaque, @as(*u8, @ptrFromInt(2)))); |
| 31 | |
| 32 | var foo: c_int = -1; |
| 33 | _ = &foo; |
| 34 | try testing.expect(cast(*anyopaque, -1) == @as(*anyopaque, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))))); |
| 35 | try testing.expect(cast(*anyopaque, foo) == @as(*anyopaque, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))))); |
| 36 | try testing.expect(cast(?*anyopaque, -1) == @as(?*anyopaque, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))))); |
| 37 | try testing.expect(cast(?*anyopaque, foo) == @as(?*anyopaque, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))))); |
| 38 | |
| 39 | const FnPtr = ?*align(1) const fn (*anyopaque) void; |
| 40 | try testing.expect(cast(FnPtr, 0) == @as(FnPtr, @ptrFromInt(@as(usize, 0)))); |
| 41 | try testing.expect(cast(FnPtr, foo) == @as(FnPtr, @ptrFromInt(@as(usize, @bitCast(@as(isize, -1)))))); |
| 42 | |
| 43 | const complexFunction = struct { |
| 44 | fn f(_: ?*anyopaque, _: c_uint, _: ?*const fn (?*anyopaque) callconv(.c) c_uint, _: ?*anyopaque, _: c_uint, _: [*c]c_uint) callconv(.c) usize { |
| 45 | return 0; |
| 46 | } |
| 47 | }.f; |
| 48 | |
| 49 | const SDL_FunctionPointer = ?*const fn () callconv(.c) void; |
| 50 | const fn_ptr = cast(SDL_FunctionPointer, complexFunction); |
| 51 | try testing.expect(fn_ptr != null); |
| 52 | } |
| 53 | |
| 54 | const sizeof = helpers.sizeof; |
| 55 | |
| 56 | test sizeof { |
| 57 | const S = extern struct { a: u32 }; |
| 58 | |
| 59 | const ptr_size = @sizeOf(*anyopaque); |
| 60 | |
| 61 | try testing.expect(sizeof(u32) == 4); |
| 62 | try testing.expect(sizeof(@as(u32, 2)) == 4); |
| 63 | try testing.expect(sizeof(2) == @sizeOf(c_int)); |
| 64 | |
| 65 | try testing.expect(sizeof(2.0) == @sizeOf(f64)); |
| 66 | |
| 67 | try testing.expect(sizeof(S) == 4); |
| 68 | |
| 69 | try testing.expect(sizeof([_]u32{ 4, 5, 6 }) == 12); |
| 70 | try testing.expect(sizeof([3]u32) == 12); |
| 71 | try testing.expect(sizeof([3:0]u32) == 16); |
| 72 | try testing.expect(sizeof(&[_]u32{ 4, 5, 6 }) == ptr_size); |
| 73 | |
| 74 | try testing.expect(sizeof(*u32) == ptr_size); |
| 75 | try testing.expect(sizeof([*]u32) == ptr_size); |
| 76 | try testing.expect(sizeof([*c]u32) == ptr_size); |
| 77 | try testing.expect(sizeof(?*u32) == ptr_size); |
| 78 | try testing.expect(sizeof(?[*]u32) == ptr_size); |
| 79 | try testing.expect(sizeof(*anyopaque) == ptr_size); |
| 80 | try testing.expect(sizeof(*void) == ptr_size); |
| 81 | try testing.expect(sizeof(null) == ptr_size); |
| 82 | |
| 83 | try testing.expect(sizeof("foobar") == 7); |
| 84 | try testing.expect(sizeof(&[_:0]u16{ 'f', 'o', 'o', 'b', 'a', 'r' }) == 14); |
| 85 | try testing.expect(sizeof(*const [4:0]u8) == 5); |
| 86 | try testing.expect(sizeof(*[4:0]u8) == ptr_size); |
| 87 | try testing.expect(sizeof([*]const [4:0]u8) == ptr_size); |
| 88 | try testing.expect(sizeof(*const *const [4:0]u8) == ptr_size); |
| 89 | try testing.expect(sizeof(*const [4]u8) == ptr_size); |
| 90 | |
| 91 | if (false) { // TODO |
| 92 | try testing.expect(sizeof(&sizeof) == @sizeOf(@TypeOf(&sizeof))); |
| 93 | try testing.expect(sizeof(sizeof) == 1); |
| 94 | } |
| 95 | |
| 96 | try testing.expect(sizeof(void) == 1); |
| 97 | try testing.expect(sizeof(anyopaque) == 1); |
| 98 | } |
| 99 | |
| 100 | const promoteIntLiteral = helpers.promoteIntLiteral; |
| 101 | |
| 102 | test promoteIntLiteral { |
| 103 | const signed_hex = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .hex); |
| 104 | try testing.expectEqual(c_uint, @TypeOf(signed_hex)); |
| 105 | |
| 106 | if (math.maxInt(c_longlong) == math.maxInt(c_int)) return; |
| 107 | |
| 108 | const signed_decimal = promoteIntLiteral(c_int, math.maxInt(c_int) + 1, .decimal); |
| 109 | const unsigned = promoteIntLiteral(c_uint, math.maxInt(c_uint) + 1, .hex); |
| 110 | |
| 111 | if (math.maxInt(c_long) > math.maxInt(c_int)) { |
| 112 | try testing.expectEqual(c_long, @TypeOf(signed_decimal)); |
| 113 | try testing.expectEqual(c_ulong, @TypeOf(unsigned)); |
| 114 | } else { |
| 115 | try testing.expectEqual(c_longlong, @TypeOf(signed_decimal)); |
| 116 | try testing.expectEqual(c_ulonglong, @TypeOf(unsigned)); |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | const shuffleVectorIndex = helpers.shuffleVectorIndex; |
| 121 | |
| 122 | test shuffleVectorIndex { |
| 123 | const vector_len: usize = 4; |
| 124 | |
| 125 | _ = shuffleVectorIndex(-1, vector_len); |
| 126 | |
| 127 | try testing.expect(shuffleVectorIndex(0, vector_len) == 0); |
| 128 | try testing.expect(shuffleVectorIndex(1, vector_len) == 1); |
| 129 | try testing.expect(shuffleVectorIndex(2, vector_len) == 2); |
| 130 | try testing.expect(shuffleVectorIndex(3, vector_len) == 3); |
| 131 | |
| 132 | try testing.expect(shuffleVectorIndex(4, vector_len) == -1); |
| 133 | try testing.expect(shuffleVectorIndex(5, vector_len) == -2); |
| 134 | try testing.expect(shuffleVectorIndex(6, vector_len) == -3); |
| 135 | try testing.expect(shuffleVectorIndex(7, vector_len) == -4); |
| 136 | } |
| 137 | |
| 138 | const FlexibleArrayType = helpers.FlexibleArrayType; |
| 139 | |
| 140 | test FlexibleArrayType { |
| 141 | const Container = extern struct { |
| 142 | size: usize, |
| 143 | }; |
| 144 | |
| 145 | try testing.expectEqual(FlexibleArrayType(*Container, c_int), [*c]c_int); |
| 146 | try testing.expectEqual(FlexibleArrayType(*const Container, c_int), [*c]const c_int); |
| 147 | try testing.expectEqual(FlexibleArrayType(*volatile Container, c_int), [*c]volatile c_int); |
| 148 | try testing.expectEqual(FlexibleArrayType(*const volatile Container, c_int), [*c]const volatile c_int); |
| 149 | } |
| 150 | |
| 151 | const signedRemainder = helpers.signedRemainder; |
| 152 | |
| 153 | test signedRemainder { |
| 154 | // TODO add test |
| 155 | return error.SkipZigTest; |
| 156 | } |
| 157 | |
| 158 | const ArithmeticConversion = helpers.ArithmeticConversion; |
| 159 | |
| 160 | test ArithmeticConversion { |
| 161 | // Promotions not necessarily the same for other platforms |
| 162 | if (builtin.target.cpu.arch != .x86_64 or builtin.target.os.tag != .linux) return error.SkipZigTest; |
| 163 | |
| 164 | const Test = struct { |
| 165 | /// Order of operands should not matter for arithmetic conversions |
| 166 | fn checkPromotion(comptime A: type, comptime B: type, comptime Expected: type) !void { |
| 167 | try std.testing.expect(ArithmeticConversion(A, B) == Expected); |
| 168 | try std.testing.expect(ArithmeticConversion(B, A) == Expected); |
| 169 | } |
| 170 | }; |
| 171 | |
| 172 | try Test.checkPromotion(c_longdouble, c_int, c_longdouble); |
| 173 | try Test.checkPromotion(c_int, f64, f64); |
| 174 | try Test.checkPromotion(f32, bool, f32); |
| 175 | |
| 176 | try Test.checkPromotion(bool, c_short, c_int); |
| 177 | try Test.checkPromotion(c_int, c_int, c_int); |
| 178 | try Test.checkPromotion(c_short, c_int, c_int); |
| 179 | |
| 180 | try Test.checkPromotion(c_int, c_long, c_long); |
| 181 | |
| 182 | try Test.checkPromotion(c_ulonglong, c_uint, c_ulonglong); |
| 183 | |
| 184 | try Test.checkPromotion(c_uint, c_int, c_uint); |
| 185 | |
| 186 | try Test.checkPromotion(c_uint, c_long, c_long); |
| 187 | |
| 188 | try Test.checkPromotion(c_ulong, c_longlong, c_ulonglong); |
| 189 | |
| 190 | // stdint.h |
| 191 | try Test.checkPromotion(u8, i8, c_int); |
| 192 | try Test.checkPromotion(u16, i16, c_int); |
| 193 | try Test.checkPromotion(i32, c_int, c_int); |
| 194 | try Test.checkPromotion(u32, c_int, c_uint); |
| 195 | try Test.checkPromotion(i64, c_int, c_long); |
| 196 | try Test.checkPromotion(u64, c_int, c_ulong); |
| 197 | try Test.checkPromotion(isize, c_int, c_long); |
| 198 | try Test.checkPromotion(usize, c_int, c_ulong); |
| 199 | } |
| 200 | |
| 201 | const F_SUFFIX = helpers.F_SUFFIX; |
| 202 | |
| 203 | test F_SUFFIX { |
| 204 | try testing.expect(@TypeOf(F_SUFFIX(1)) == f32); |
| 205 | } |
| 206 | |
| 207 | const U_SUFFIX = helpers.U_SUFFIX; |
| 208 | |
| 209 | test U_SUFFIX { |
| 210 | try testing.expect(@TypeOf(U_SUFFIX(1)) == c_uint); |
| 211 | if (math.maxInt(c_ulong) > math.maxInt(c_uint)) { |
| 212 | try testing.expect(@TypeOf(U_SUFFIX(math.maxInt(c_uint) + 1)) == c_ulong); |
| 213 | } |
| 214 | if (math.maxInt(c_ulonglong) > math.maxInt(c_ulong)) { |
| 215 | try testing.expect(@TypeOf(U_SUFFIX(math.maxInt(c_ulong) + 1)) == c_ulonglong); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | const L_SUFFIX = helpers.L_SUFFIX; |
| 220 | |
| 221 | test L_SUFFIX { |
| 222 | try testing.expect(@TypeOf(L_SUFFIX(1)) == c_long); |
| 223 | if (math.maxInt(c_long) > math.maxInt(c_int)) { |
| 224 | try testing.expect(@TypeOf(L_SUFFIX(math.maxInt(c_int) + 1)) == c_long); |
| 225 | } |
| 226 | if (math.maxInt(c_longlong) > math.maxInt(c_long)) { |
| 227 | try testing.expect(@TypeOf(L_SUFFIX(math.maxInt(c_long) + 1)) == c_longlong); |
| 228 | } |
| 229 | } |
| 230 | const UL_SUFFIX = helpers.UL_SUFFIX; |
| 231 | |
| 232 | test UL_SUFFIX { |
| 233 | try testing.expect(@TypeOf(UL_SUFFIX(1)) == c_ulong); |
| 234 | if (math.maxInt(c_ulonglong) > math.maxInt(c_ulong)) { |
| 235 | try testing.expect(@TypeOf(UL_SUFFIX(math.maxInt(c_ulong) + 1)) == c_ulonglong); |
| 236 | } |
| 237 | } |
| 238 | const LL_SUFFIX = helpers.LL_SUFFIX; |
| 239 | |
| 240 | test LL_SUFFIX { |
| 241 | try testing.expect(@TypeOf(LL_SUFFIX(1)) == c_longlong); |
| 242 | } |
| 243 | const ULL_SUFFIX = helpers.ULL_SUFFIX; |
| 244 | |
| 245 | test ULL_SUFFIX { |
| 246 | try testing.expect(@TypeOf(ULL_SUFFIX(1)) == c_ulonglong); |
| 247 | } |
| 248 | |
| 249 | test "Extended C ABI casting" { |
| 250 | if (math.maxInt(c_long) > math.maxInt(c_char)) { |
| 251 | try testing.expect(@TypeOf(L_SUFFIX(@as(c_char, math.maxInt(c_char) - 1))) == c_long); // c_char |
| 252 | } |
| 253 | if (math.maxInt(c_long) > math.maxInt(c_short)) { |
| 254 | try testing.expect(@TypeOf(L_SUFFIX(@as(c_short, math.maxInt(c_short) - 1))) == c_long); // c_short |
| 255 | } |
| 256 | |
| 257 | if (math.maxInt(c_long) > math.maxInt(c_ushort)) { |
| 258 | try testing.expect(@TypeOf(L_SUFFIX(@as(c_ushort, math.maxInt(c_ushort) - 1))) == c_long); //c_ushort |
| 259 | } |
| 260 | |
| 261 | if (math.maxInt(c_long) > math.maxInt(c_int)) { |
| 262 | try testing.expect(@TypeOf(L_SUFFIX(@as(c_int, math.maxInt(c_int) - 1))) == c_long); // c_int |
| 263 | } |
| 264 | |
| 265 | if (math.maxInt(c_long) > math.maxInt(c_uint)) { |
| 266 | try testing.expect(@TypeOf(L_SUFFIX(@as(c_uint, math.maxInt(c_uint) - 1))) == c_long); // c_uint |
| 267 | try testing.expect(@TypeOf(L_SUFFIX(math.maxInt(c_uint) + 1)) == c_long); // comptime_int -> c_long |
| 268 | } |
| 269 | |
| 270 | if (math.maxInt(c_longlong) > math.maxInt(c_long)) { |
| 271 | try testing.expect(@TypeOf(L_SUFFIX(@as(c_long, math.maxInt(c_long) - 1))) == c_long); // c_long |
| 272 | try testing.expect(@TypeOf(L_SUFFIX(math.maxInt(c_long) + 1)) == c_longlong); // comptime_int -> c_longlong |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | const WL_CONTAINER_OF = helpers.WL_CONTAINER_OF; |
| 277 | |
| 278 | test WL_CONTAINER_OF { |
| 279 | const S = struct { |
| 280 | a: u32 = 0, |
| 281 | b: u32 = 0, |
| 282 | }; |
| 283 | const x = S{}; |
| 284 | const y = S{}; |
| 285 | const ptr = WL_CONTAINER_OF(&x.b, &y, "b"); |
| 286 | try testing.expectEqual(&x, ptr); |
| 287 | } |
| 288 | |
| 289 | const CAST_OR_CALL = helpers.CAST_OR_CALL; |
| 290 | |
| 291 | test "CAST_OR_CALL casting" { |
| 292 | const arg: c_int = 1000; |
| 293 | const casted = CAST_OR_CALL(u8, arg); |
| 294 | try testing.expectEqual(cast(u8, arg), casted); |
| 295 | |
| 296 | const S = struct { |
| 297 | x: u32 = 0, |
| 298 | }; |
| 299 | var s: S = .{}; |
| 300 | const casted_ptr = CAST_OR_CALL(*u8, &s); |
| 301 | try testing.expectEqual(cast(*u8, &s), casted_ptr); |
| 302 | } |
| 303 | |
| 304 | test "CAST_OR_CALL calling" { |
| 305 | const Helper = struct { |
| 306 | var last_val: bool = false; |
| 307 | fn returnsVoid(val: bool) void { |
| 308 | last_val = val; |
| 309 | } |
| 310 | fn returnsBool(f: f32) bool { |
| 311 | return f > 0; |
| 312 | } |
| 313 | fn identity(self: c_uint) c_uint { |
| 314 | return self; |
| 315 | } |
| 316 | }; |
| 317 | |
| 318 | CAST_OR_CALL(Helper.returnsVoid, true); |
| 319 | try testing.expectEqual(true, Helper.last_val); |
| 320 | CAST_OR_CALL(Helper.returnsVoid, false); |
| 321 | try testing.expectEqual(false, Helper.last_val); |
| 322 | |
| 323 | try testing.expectEqual(Helper.returnsBool(1), CAST_OR_CALL(Helper.returnsBool, @as(f32, 1))); |
| 324 | try testing.expectEqual(Helper.returnsBool(-1), CAST_OR_CALL(Helper.returnsBool, @as(f32, -1))); |
| 325 | |
| 326 | try testing.expectEqual(Helper.identity(@as(c_uint, 100)), CAST_OR_CALL(Helper.identity, @as(c_uint, 100))); |
| 327 | } |