| ... | ... | @@ -114,7 +114,37 @@ pub const TestContext = struct { |
| 114 | 114 | }) catch unreachable; |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | | pub fn addError(self: *ZIRCase, src: [:0]const u8, errors: []const []const u8) void {} |
| 117 | pub fn addError(self: *ZIRCase, src: [:0]const u8, errors: []const []const u8) void { |
| 118 | var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable; |
| 119 | for (errors) |e, i| { |
| 120 | var cur = e[1..]; |
| 121 | var line_index = std.mem.indexOf(u8, cur, ":"); |
| 122 | if (line_index == null) { |
| 123 | std.debug.panic("Invalid test: error must be specified as ':line:column: error: msg', found '{}'", .{e}); |
| 124 | } |
| 125 | const line = std.fmt.parseInt(u32, cur[0..line_index.?], 10) catch @panic("Unable to parse line number"); |
| 126 | cur = cur[line_index.? + 1 ..]; |
| 127 | const column_index = std.mem.indexOf(u8, cur, ":"); |
| 128 | if (column_index == null) { |
| 129 | std.debug.panic("Invalid test: error must be specified as ':line:column: error: msg', found '{}'", .{e}); |
| 130 | } |
| 131 | const column = std.fmt.parseInt(u32, cur[0..column_index.?], 10) catch @panic("Unable to parse column number"); |
| 132 | cur = cur[column_index.? + 2 ..]; |
| 133 | std.debug.assert(std.mem.eql(u8, cur[0..7], "error: ")); |
| 134 | const msg = cur[7..]; |
| 135 | |
| 136 | if (line == 0 or column == 0) { |
| 137 | @panic("Invalid test: error line and column must be specified starting at one!"); |
| 138 | } |
| 139 | |
| 140 | array[i] = .{ |
| 141 | .msg = msg, |
| 142 | .line = line - 1, |
| 143 | .column = column - 1, |
| 144 | }; |
| 145 | } |
| 146 | self.updates.append(.{ .src = src, .case = .{ .Error = array } }) catch unreachable; |
| 147 | } |
| 118 | 148 | }; |
| 119 | 149 | |
| 120 | 150 | pub fn addZIRMulti( |
| ... | ... | @@ -161,42 +191,7 @@ pub const TestContext = struct { |
| 161 | 191 | cross_target: std.zig.CrossTarget, |
| 162 | 192 | src: [:0]const u8, |
| 163 | 193 | expected_errors: []const []const u8, |
| 164 | | ) void { |
| 165 | | var array = std.ArrayList(ErrorMsg).init(ctx.zir_error_cases.allocator); |
| 166 | | for (expected_errors) |e| { |
| 167 | | var cur = e; |
| 168 | | var line_index = std.mem.indexOf(u8, cur, ":"); |
| 169 | | if (line_index == null) { |
| 170 | | std.debug.panic("Invalid test: error must be specified as 'line:column: error: msg', found '{}'", .{e}); |
| 171 | | } |
| 172 | | const line = std.fmt.parseInt(u32, cur[0..line_index.?], 10) catch @panic("Unable to parse line number"); |
| 173 | | cur = cur[line_index.? + 1 ..]; |
| 174 | | const column_index = std.mem.indexOf(u8, cur, ":"); |
| 175 | | if (column_index == null) { |
| 176 | | std.debug.panic("Invalid test: error must be specified as 'line:column: error: msg', found '{}'", .{e}); |
| 177 | | } |
| 178 | | const column = std.fmt.parseInt(u32, cur[0..column_index.?], 10) catch @panic("Unable to parse column number"); |
| 179 | | cur = cur[column_index.? + 2 ..]; |
| 180 | | std.debug.assert(std.mem.eql(u8, cur[0..7], "error: ")); |
| 181 | | const msg = cur[7..]; |
| 182 | | |
| 183 | | if (line == 0 or column == 0) { |
| 184 | | @panic("Invalid test: error line and column must be specified starting at one!"); |
| 185 | | } |
| 186 | | |
| 187 | | array.append(.{ |
| 188 | | .msg = msg, |
| 189 | | .line = line - 1, |
| 190 | | .column = column - 1, |
| 191 | | }) catch unreachable; |
| 192 | | } |
| 193 | | ctx.zir_error_cases.append(.{ |
| 194 | | .name = name, |
| 195 | | .src = src, |
| 196 | | .expected_errors = array.toOwnedSlice(), |
| 197 | | .cross_target = cross_target, |
| 198 | | }) catch unreachable; |
| 199 | | } |
| 194 | ) void {} |
| 200 | 195 | |
| 201 | 196 | fn init(self: *TestContext) !void { |
| 202 | 197 | const allocator = std.heap.page_allocator; |
| ... | ... | @@ -214,6 +209,11 @@ pub const TestContext = struct { |
| 214 | 209 | } |
| 215 | 210 | self.zir_error_cases.deinit(); |
| 216 | 211 | for (self.zir_cases.items) |c| { |
| 212 | for (c.updates.items) |u| { |
| 213 | if (u.case == .Error) { |
| 214 | c.updates.allocator.free(u.case.Error); |
| 215 | } |
| 216 | } |
| 217 | 217 | c.updates.deinit(); |
| 218 | 218 | } |
| 219 | 219 | self.zir_cases.deinit(); |
| ... | ... | @@ -268,11 +268,11 @@ pub const TestContext = struct { |
| 268 | 268 | // TODO: support tests for object file building, and library builds |
| 269 | 269 | // and linking. This will require a rework to support multi-file |
| 270 | 270 | // tests. |
| 271 | | .output_mode = .Exe, |
| 271 | .output_mode = .Obj, |
| 272 | 272 | // TODO: support testing optimizations |
| 273 | 273 | .optimize_mode = .Debug, |
| 274 | 274 | .bin_file_dir = tmp.dir, |
| 275 | | .bin_file_path = "test_case", |
| 275 | .bin_file_path = "test_case.o", |
| 276 | 276 | .root_pkg = root_pkg, |
| 277 | 277 | }); |
| 278 | 278 | defer module.deinit(); |
| ... | ... | @@ -312,6 +312,35 @@ pub const TestContext = struct { |
| 312 | 312 | |
| 313 | 313 | std.testing.expectEqualSlices(u8, expected_output, out_zir.items); |
| 314 | 314 | }, |
| 315 | .Error => |e| { |
| 316 | var handled_errors = try allocator.alloc(bool, e.len); |
| 317 | defer allocator.free(handled_errors); |
| 318 | for (handled_errors) |*h| { |
| 319 | h.* = false; |
| 320 | } |
| 321 | var all_errors = try module.getAllErrorsAlloc(); |
| 322 | defer all_errors.deinit(allocator); |
| 323 | for (all_errors.list) |a| { |
| 324 | for (e) |ex, i| { |
| 325 | if (a.line == ex.line and a.column == ex.column and std.mem.eql(u8, ex.msg, a.msg)) { |
| 326 | handled_errors[i] = true; |
| 327 | break; |
| 328 | } |
| 329 | } else { |
| 330 | std.debug.warn("{}\nUnexpected error:\n================\n{}:{}: {}\n================\nTest failed.\n", .{ case.name, a.line + 1, a.column + 1, a.msg }); |
| 331 | std.process.exit(1); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | for (handled_errors) |h, i| { |
| 336 | if (!h) { |
| 337 | const er = e[i]; |
| 338 | std.debug.warn("{}\nDid not receive error:\n================\n{}:{}: {}\n================\nTest failed.\n", .{ case.name, er.line, er.column, er.msg }); |
| 339 | std.process.exit(1); |
| 340 | } |
| 341 | } |
| 342 | }, |
| 343 | |
| 315 | 344 | else => return error.unimplemented, |
| 316 | 345 | } |
| 317 | 346 | } |
| ... | ... | @@ -423,10 +452,7 @@ pub const TestContext = struct { |
| 423 | 452 | |
| 424 | 453 | var module_node = prg_node.start("parse/analysis/codegen", null); |
| 425 | 454 | module_node.activate(); |
| 426 | | const failed = f: { |
| 427 | | module.update() catch break :f true; |
| 428 | | break :f false; |
| 429 | | }; |
| 455 | try module.update(); |
| 430 | 456 | module_node.end(); |
| 431 | 457 | var err: ?anyerror = null; |
| 432 | 458 | |