| ... | @@ -50,7 +50,7 @@ pub fn create(builder: *Builder, source: build.FileSource, obj_format: std.Targe | ... | @@ -50,7 +50,7 @@ pub fn create(builder: *Builder, source: build.FileSource, obj_format: std.Targe |
| 50 | /// For example, if the two extracted values were saved as `vmaddr` and `entryoff` respectively | 50 | /// For example, if the two extracted values were saved as `vmaddr` and `entryoff` respectively |
| 51 | /// they could then be added with this simple program `vmaddr entryoff +`. | 51 | /// they could then be added with this simple program `vmaddr entryoff +`. |
| 52 | const Action = struct { | 52 | const Action = struct { |
| 53 | tag: enum { match, compute_cmp }, | 53 | tag: enum { match, not_present, compute_cmp }, |
| 54 | phrase: []const u8, | 54 | phrase: []const u8, |
| 55 | expected: ?ComputeCompareExpected = null, | 55 | expected: ?ComputeCompareExpected = null, |
| 56 | | 56 | |
| ... | @@ -63,7 +63,7 @@ const Action = struct { | ... | @@ -63,7 +63,7 @@ const Action = struct { |
| 63 | /// name {*}libobjc{*}.dylib => will match `name` followed by a token which contains `libobjc` and `.dylib` | 63 | /// name {*}libobjc{*}.dylib => will match `name` followed by a token which contains `libobjc` and `.dylib` |
| 64 | /// in that order with other letters in between | 64 | /// in that order with other letters in between |
| 65 | fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool { | 65 | fn match(act: Action, haystack: []const u8, global_vars: anytype) !bool { |
| 66 | assert(act.tag == .match); | 66 | assert(act.tag == .match or act.tag == .not_present); |
| 67 | | 67 | |
| 68 | var candidate_var: ?struct { name: []const u8, value: u64 } = null; | 68 | var candidate_var: ?struct { name: []const u8, value: u64 } = null; |
| 69 | var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " "); | 69 | var hay_it = mem.tokenize(u8, mem.trim(u8, haystack, " "), " "); |
| ... | @@ -202,6 +202,13 @@ const Check = struct { | ... | @@ -202,6 +202,13 @@ const Check = struct { |
| 202 | }) catch unreachable; | 202 | }) catch unreachable; |
| 203 | } | 203 | } |
| 204 | | 204 | |
| | 205 | fn notPresent(self: *Check, phrase: []const u8) void { |
| | 206 | self.actions.append(.{ |
| | 207 | .tag = .not_present, |
| | 208 | .phrase = self.builder.dupe(phrase), |
| | 209 | }) catch unreachable; |
| | 210 | } |
| | 211 | |
| 205 | fn computeCmp(self: *Check, phrase: []const u8, expected: ComputeCompareExpected) void { | 212 | fn computeCmp(self: *Check, phrase: []const u8, expected: ComputeCompareExpected) void { |
| 206 | self.actions.append(.{ | 213 | self.actions.append(.{ |
| 207 | .tag = .compute_cmp, | 214 | .tag = .compute_cmp, |
| ... | @@ -226,6 +233,15 @@ pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void { | ... | @@ -226,6 +233,15 @@ pub fn checkNext(self: *CheckObjectStep, phrase: []const u8) void { |
| 226 | last.match(phrase); | 233 | last.match(phrase); |
| 227 | } | 234 | } |
| 228 | | 235 | |
| | 236 | /// Adds another searched phrase to the latest created Check with `CheckObjectStep.checkStart(...)` |
| | 237 | /// however ensures there is no matching phrase in the output. |
| | 238 | /// Asserts at least one check already exists. |
| | 239 | pub fn checkNotPresent(self: *CheckObjectStep, phrase: []const u8) void { |
| | 240 | assert(self.checks.items.len > 0); |
| | 241 | const last = &self.checks.items[self.checks.items.len - 1]; |
| | 242 | last.notPresent(phrase); |
| | 243 | } |
| | 244 | |
| 229 | /// Creates a new check checking specifically symbol table parsed and dumped from the object | 245 | /// Creates a new check checking specifically symbol table parsed and dumped from the object |
| 230 | /// file. | 246 | /// file. |
| 231 | /// Issuing this check will force parsing and dumping of the symbol table. | 247 | /// Issuing this check will force parsing and dumping of the symbol table. |
| ... | @@ -293,6 +309,21 @@ fn make(step: *Step) !void { | ... | @@ -293,6 +309,21 @@ fn make(step: *Step) !void { |
| 293 | return error.TestFailed; | 309 | return error.TestFailed; |
| 294 | } | 310 | } |
| 295 | }, | 311 | }, |
| | 312 | .not_present => { |
| | 313 | while (it.next()) |line| { |
| | 314 | if (try act.match(line, &vars)) { |
| | 315 | std.debug.print( |
| | 316 | \\ |
| | 317 | \\========= Expected not to find: =================== |
| | 318 | \\{s} |
| | 319 | \\========= But parsed file does contain it: ======== |
| | 320 | \\{s} |
| | 321 | \\ |
| | 322 | , .{ act.phrase, output }); |
| | 323 | return error.TestFailed; |
| | 324 | } |
| | 325 | } |
| | 326 | }, |
| 296 | .compute_cmp => { | 327 | .compute_cmp => { |
| 297 | const res = act.computeCmp(gpa, vars) catch |err| switch (err) { | 328 | const res = act.computeCmp(gpa, vars) catch |err| switch (err) { |
| 298 | error.UnknownVariable => { | 329 | error.UnknownVariable => { |