about summary refs log blame commit diff stats
path: root/012transform.cc
blob: 758a286c00fbf256d0d974e6d5d97bc8f213cd77 (plain) (tree)
span class="p">) { if (!Passed) return false; if (!Trace_stream) return false; vector<string> expected_lines = split(expected, "\n"); int curr_expected_line = 0; while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) ++curr_expected_line; if (curr_expected_line == SIZE(expected_lines)) return true; string label, contents; split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { if (label != p->label) continue; if (contents != trim(p->contents)) continue; ++curr_expected_line; while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) ++curr_expected_line; if (curr_expected_line == SIZE(expected_lines)) return true; split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); } if (line_exists_anywhere(label, contents)) { cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): line [" << label << ": " << contents << "] out of order in trace:\n"; DUMP(""); } else { cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; DUMP(label); } Passed = false; return false; } bool trace_doesnt_contain(string expected) { vector<string> tmp = split_first(expected, ": "); if (SIZE(tmp) == 1) { raise << expected << ": missing label or contents in trace line\n" << end(); assert(false); } return trace_count(tmp.at(0), tmp.at(1)) == 0; } int trace_count(string label) { return trace_count(label, ""); } int trace_count(string label, string line) { if (!Trace_stream) return 0; long result = 0; for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { if (label == p->label) { if (line == "" || trim(line) == trim(p->contents)) ++result; } } return result; } int trace_count_prefix(string label, string prefix) { if (!Trace_stream) return 0; long result = 0; for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { if (label == p->label) { if (starts_with(trim(p->contents), trim(prefix))) ++result; } } return result; } void split_label_contents(const string& s, string* label, string* contents) { static const string delim(": "); size_t pos = s.find(delim); if (pos == string::npos) { *label = ""; *contents = trim(s); } else { *label = trim(s.substr(0, pos)); *contents = trim(s.substr(pos+SIZE(delim))); } } bool line_exists_anywhere(const string& label, const string& contents) { for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { if (label != p->label) continue; if (contents == trim(p->contents)) return true; } return false; } vector<string> split(string s, string delim) { vector<string> result; size_t begin=0, end=s.find(delim); while (true) { if (end == string::npos) { result.push_back(string(s, begin, string::npos)); break; } result.push_back(string(s, begin, end-begin)); begin = end+SIZE(delim); end = s.find(delim, begin); } return result; } vector<string> split_first(string s, string delim) { vector<string> result; size_t end=s.find(delim); result.push_back(string(s, 0, end)); if (end != string::npos) result.push_back(string(s, end+SIZE(delim), string::npos)); return result; } //:: == Helpers for debugging using traces :(before "End Includes") // To debug why a test is failing, dump its trace using '?'. #define DUMP(label) if (Trace_stream) cerr << Trace_stream->readable_contents(label); // To add temporary prints to the trace, use 'dbg'. // `git log` should never show any calls to 'dbg'. #define dbg trace(0, "a") //: Dump the entire trace to file where it can be browsed offline. //: Dump the trace as it happens; that way you get something even if the //: program crashes. :(before "End Globals") ofstream Trace_file; :(before "End Commandline Options(*arg)") else if (is_equal(*arg, "--trace")) { Trace_stream = new trace_stream; cerr << "saving trace to 'last_run'\n"; Trace_file.open("last_run"); // Add a dummy line up top; otherwise the `browse_trace` tool currently has // no way to expand any lines above an error. Trace_file << " 0 dummy: start\n"; } :(before "End trace Commit") if (Trace_file) { Trace_file << std::setw(4) << t.depth << ' ' << t.label << ": " << t.contents << '\n'; } :(before "End One-time Setup") atexit(cleanup_main); :(code) void cleanup_main() { if (Trace_file) Trace_file.close(); // End cleanup_main } :(before "End trace_stream Methods") string readable_contents(string label) { string trim(const string& s); // prototype ostringstream output; label = trim(label); for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) if (label.empty() || label == p->label) output << std::setw(4) << p->depth << ' ' << p->label << ": " << p->contents << '\n'; return output.str(); } //: Print traces to the screen as they happen. //: Particularly useful when juggling multiple trace streams, like when //: debugging sandboxes. :(before "End Globals") bool Dump_trace = false; :(before "End Commandline Options(*arg)") else if (is_equal(*arg, "--dump")) { Dump_trace = true; } :(before "End Incremental Trace Print Conditions") if (Dump_trace) return true; //: Miscellaneous helpers. :(code) string trim(const string& s) { string::const_iterator first = s.begin(); while (first != s.end() && isspace(*first)) ++first; if (first == s.end()) return ""; string::const_iterator last = --s.end(); while (last != s.begin() && isspace(*last)) --last; ++last; return string(first, last); } :(before "End Includes") #include <vector> using std::vector; #include <list> using std::list; #include <set> using std::set; #include <sstream> using std::istringstream; using std::ostringstream; #include <fstream> using std::ifstream; using std::ofstream;