authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-04-28 18:22:57+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-04-28 18:35:01+02:00
logd25f06a71c058aa4ff8bf40749345028bda6e017
tree9d66ea41642f6fd1be8151ccfd2d1aa38ab7647a
parent62625d9d9518644bcf4fa94e1d5c67edde22b91b

test: remove redundant codepaths from test harness


1 files changed, 4 insertions(+), 166 deletions(-)

src/test.zig+4-166
...@@ -904,32 +904,12 @@ pub const TestContext = struct {...@@ -904,32 +904,12 @@ pub const TestContext = struct {
904 incremental,904 incremental,
905 };905 };
906906
907 /// Adds a compile-error test for each file in the provided directory, using the907 /// Adds a test for each file in the provided directory, using the selected strategy.
908 /// selected backend and output mode. If `one_test_case_per_file` is true, a new908 /// Recurses nested directories.
909 /// test case is created for each file. Otherwise, a single test case is used for
910 /// all tests.
911 ///909 ///
912 /// Each file should include a test manifest as a contiguous block of comments at910 /// Each file should include a test manifest as a contiguous block of comments at
913 /// the end of the file. The first line should be the test case name, followed by911 /// the end of the file. The first line should be the test type, followed by a set of
914 /// a blank line, then one expected errors on each line in the form912 /// key-value config values, followed by a blank line, then the expected output.
915 /// `:line:column: error: message`
916 pub fn addErrorCasesFromDir(
917 ctx: *TestContext,
918 name: []const u8,
919 dir: std.fs.Dir,
920 backend: Backend,
921 output_mode: std.builtin.OutputMode,
922 is_test: bool,
923 strategy: Strategy,
924 ) void {
925 var current_file: []const u8 = "none";
926 addErrorCasesFromDirInner(ctx, name, dir, backend, output_mode, is_test, strategy, &current_file) catch |err| {
927 std.debug.panic("test harness failed to process file '{s}': {s}\n", .{
928 current_file, @errorName(err),
929 });
930 };
931 }
932
933 pub fn addTestCasesFromDir(ctx: *TestContext, dir: std.fs.Dir, strategy: Strategy) void {913 pub fn addTestCasesFromDir(ctx: *TestContext, dir: std.fs.Dir, strategy: Strategy) void {
934 var current_file: []const u8 = "none";914 var current_file: []const u8 = "none";
935 ctx.addTestCasesFromDirInner(dir, strategy, &current_file) catch |err| {915 ctx.addTestCasesFromDirInner(dir, strategy, &current_file) catch |err| {
...@@ -1127,148 +1107,6 @@ pub const TestContext = struct {...@@ -1127,148 +1107,6 @@ pub const TestContext = struct {
1127 }1107 }
1128 }1108 }
11291109
1130 fn addErrorCasesFromDirInner(
1131 ctx: *TestContext,
1132 name: []const u8,
1133 dir: std.fs.Dir,
1134 backend: Backend,
1135 output_mode: std.builtin.OutputMode,
1136 is_test: bool,
1137 strategy: Strategy,
1138 /// This is kept up to date with the currently being processed file so
1139 /// that if any errors occur the caller knows it happened during this file.
1140 current_file: *[]const u8,
1141 ) !void {
1142 var opt_case: ?*Case = null;
1143
1144 var it = dir.iterate();
1145 var filenames = std.ArrayList([]const u8).init(ctx.arena);
1146 defer filenames.deinit();
1147
1148 while (try it.next()) |entry| {
1149 if (entry.kind != .File) continue;
1150
1151 // Ignore stuff such as .swp files
1152 switch (Compilation.classifyFileExt(entry.name)) {
1153 .unknown => continue,
1154 else => {},
1155 }
1156 try filenames.append(try ctx.arena.dupe(u8, entry.name));
1157 }
1158
1159 // Sort filenames, so that incremental tests are contiguous and in-order
1160 sortTestFilenames(filenames.items);
1161
1162 var prev_filename: []const u8 = "";
1163 for (filenames.items) |filename| {
1164 current_file.* = filename;
1165
1166 { // First, check if this file is part of an incremental update sequence
1167
1168 // Split filename into "<base_name>.<index>.<file_ext>"
1169 const prev_parts = getTestFileNameParts(prev_filename);
1170 const new_parts = getTestFileNameParts(filename);
1171
1172 // If base_name and file_ext match, these files are in the same test sequence
1173 // and the new one should be the incremented version of the previous test
1174 if (std.mem.eql(u8, prev_parts.base_name, new_parts.base_name) and
1175 std.mem.eql(u8, prev_parts.file_ext, new_parts.file_ext))
1176 {
1177
1178 // This is "foo.X.zig" followed by "foo.Y.zig". Make sure that X = Y + 1
1179 if (prev_parts.test_index == null) return error.InvalidIncrementalTestIndex;
1180 if (new_parts.test_index == null) return error.InvalidIncrementalTestIndex;
1181 if (new_parts.test_index.? != prev_parts.test_index.? + 1) return error.InvalidIncrementalTestIndex;
1182 } else {
1183
1184 // This is not the same test sequence, so the new file must be the first file
1185 // in a new sequence ("*.0.zig") or an independent test file ("*.zig")
1186 if (new_parts.test_index != null and new_parts.test_index.? != 0) return error.InvalidIncrementalTestIndex;
1187
1188 if (strategy == .independent)
1189 opt_case = null; // Generate a new independent test case for this update
1190 }
1191 }
1192 prev_filename = filename;
1193
1194 const max_file_size = 10 * 1024 * 1024;
1195 const src = try dir.readFileAllocOptions(ctx.arena, filename, max_file_size, null, 1, 0);
1196
1197 // The manifest is the last contiguous block of comments in the file
1198 // We scan for the beginning by searching backward for the first non-empty line that does not start with "//"
1199 var manifest_start: ?usize = null;
1200 var manifest_end: usize = src.len;
1201 if (src.len > 0) {
1202 var cursor: usize = src.len - 1;
1203 while (true) {
1204 // Move to beginning of line
1205 while (cursor > 0 and src[cursor - 1] != '\n') cursor -= 1;
1206
1207 if (std.mem.startsWith(u8, src[cursor..], "//")) {
1208 manifest_start = cursor; // Contiguous comment line, include in manifest
1209 } else {
1210 if (manifest_start != null) break; // Encountered non-comment line, end of manifest
1211
1212 // We ignore all-whitespace lines following the comment block, but anything else
1213 // means that there is no manifest present.
1214 if (std.mem.trim(u8, src[cursor..manifest_end], " \r\n\t").len == 0) {
1215 manifest_end = cursor;
1216 } else break; // If it's not whitespace, there is no manifest
1217 }
1218
1219 // Move to previous line
1220 if (cursor != 0) cursor -= 1 else break;
1221 }
1222 }
1223
1224 var errors = std.ArrayList([]const u8).init(ctx.arena);
1225
1226 if (manifest_start) |start| {
1227 // Due to the above processing, we know that this is a contiguous block of comments
1228 // and do not need to re-validate the leading "//" on each line
1229 var manifest_it = std.mem.tokenize(u8, src[start..manifest_end], "\r\n");
1230
1231 // First line is the test case name
1232 const first_line = manifest_it.next() orelse return error.MissingTestCaseName;
1233 const case_name = try std.mem.concat(ctx.arena, u8, &.{ name, ": ", std.mem.trim(u8, first_line[2..], " \t") });
1234
1235 // If the second line is present, it should be blank
1236 if (manifest_it.next()) |second_line| {
1237 if (std.mem.trim(u8, second_line[2..], " \t").len != 0) return error.SecondLineNotBlank;
1238 }
1239
1240 // All following lines are expected error messages
1241 while (manifest_it.next()) |line| try errors.append(try ctx.arena.dupe(u8, std.mem.trim(u8, line[2..], " \t")));
1242
1243 const case = opt_case orelse case: {
1244 ctx.cases.append(TestContext.Case{
1245 .name = name,
1246 .target = .{},
1247 .backend = backend,
1248 .updates = std.ArrayList(TestContext.Update).init(ctx.cases.allocator),
1249 .is_test = is_test,
1250 .output_mode = output_mode,
1251 .files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),
1252 }) catch @panic("out of memory");
1253 const case = &ctx.cases.items[ctx.cases.items.len - 1];
1254 opt_case = case;
1255 break :case case;
1256 };
1257 switch (strategy) {
1258 .independent => {
1259 case.name = case_name;
1260 case.addError(src, errors.items);
1261 },
1262 .incremental => {
1263 case.addErrorNamed(case_name, src, errors.items);
1264 },
1265 }
1266 } else {
1267 return error.MissingManifest;
1268 }
1269 }
1270 }
1271
1272 fn init(gpa: Allocator, arena: Allocator) TestContext {1110 fn init(gpa: Allocator, arena: Allocator) TestContext {
1273 return .{1111 return .{
1274 .cases = std.ArrayList(Case).init(gpa),1112 .cases = std.ArrayList(Case).init(gpa),