//: Mu scenarios. This will get long, but these are the tests we want to //: support in this layer. //: You can use variable names in scenarios, but for the most part we'll use //: raw location numbers, because that lets us make assertions on memory. //: Tests should avoid abstraction as far as possible. :(scenarios run_mu_scenario) :(scenario scenario_block) scenario foo [ run [ 1:number <- copy 13 ] memory-should-contain [ 1 <- 13 ] ] # checks are inside scenario :(scenario scenario_multiple_blocks) scenario foo [ run [ 1:number <- copy 13 ] memory-should-contain [ 1 <- 13 ] run [ 2:number <- copy 13 ] memory-should-contain [ 1 <- 13 2 <- 13 ] ] :(scenario scenario_check_memory_and_trace) scenario foo [ run [ 1:number <- copy 13 trace 1, [a], [a b c] ] memory-should-contain [ 1 <- 13 ] trace-should-contain [ a: a b c ] trace-should-not-contain [ a: x y z ] ] //:: Core data structure :(before "End Types") struct scenario { string name; string to_run; }; :(before "End Globals") vector Scenarios; set Scenario_names; //:: Parse the 'scenario' form. //: Simply store the text of the scenario. :(before "End Command Handlers") else if (command == "scenario") { Scenarios.push_back(parse_scenario(in)); } :(code) scenario parse_scenario(istream& in) { scenario result; result.name = next_word(in); if (contains_key(Scenario_names, result.name)) raise_error << "duplicate scenario name: " << result.name << '\n' << end(); Scenario_names.insert(result.name); skip_whitespace_and_comments(in); assert(in.peek() == '['); // scenarios are take special 'code' strings so we need to ignore brackets // inside comments result.to_run = slurp_quoted(in); // delete [] delimiters assert(result.to_run.at(0) == '['); result.to_run.erase(0, 1); assert(result.to_run.at(SIZE(result.to_run)-1) == ']'); result.to_run.erase(SIZE(result.to_run)-1); return result; } :(scenario read_scenario_with_bracket_in_comment) scenario foo [ # ']' in comment 1:number <- copy 0 ] +run: 1:number <- copy 0 :(scenario read_scenario_with_bracket_in_comment_in_nested_string) scenario foo [ 1:address:array:character <- new [# not a comment] ] +run: 1:address:array:character <- new [# not a comment] //:: Run scenarios when we run 'mu test'. //: Treat the text of the scenario as a regular series of instructions. :(before "End Tests") time_t mu_time; time(&mu_time); cerr << "\nMu tests: " << ctime(&mu_time); for (long long int i = 0; i < SIZE(Scenarios); ++i) { //? cerr << i << ": " << Scenarios.at(i).name << '\n'; run_mu_scenario(Scenarios.at(i)); if (Passed) cerr << "."; } //: Convenience: run a single named scenario. :(after "Test Runs") for (long long int i = 0; i < SIZE(Scenarios); ++i) { if (Scenarios.at(i).name == argv[argc-1]) { run_mu_scenario(Scenarios.at(i)); if (Passed) cerr << ".\n"; return 0; } } :(before "End Globals") const scenario* Current_scenario = NULL; :(code) void run_mu_scenario(const scenario& s) { Current_scenario = &s; bool not_already_inside_test = !Trace_stream; //? cerr << s.name << '\n'; if (not_already_inside_test) { Trace_file = s.name; Trace_stream = new trace_stream; setup(); } vector tmp = load("recipe scenario-"+s.name+" [ "+s.to_run+" ]"); bind_special_scenario_names(tmp.at(0)); transform_all(); run(tmp.front()); if (not_already_inside_test && Trace_stream) { teardown(); ofstream fout((Trace_dir+Trace_file).c_str()); fout << Trace_stream->readable_contents(""); fout.close(); delete Trace_stream; Trace_stream = NULL; Trace_file = ""; } Current_scenario = NULL; } //: Watch out for redefinitions of scenario routines. We should never ever be //: doing that, regardless of anything else. :(scenarios run) :(scenario warn_on_redefine_scenario) % Hide_warnings = true; % Disable_redefine_warnings = true; recipe scenario-foo [ 1:number <- copy 34 ] recipe scenario-foo [ 1:number <- copy 35 ] +warn: redefining recipe scenario-foo :(after "bool warn_on_redefine(const string& recipe_name)") if (recipe_name.find("scenario-") == 0) return true; //:: The special instructions we want to support inside scenarios. //: In a compiler for the mu VM these will require more work. //: 'run' interprets a string as a set of instructions :(scenario run) recipe main [ run [ 1:number <- copy 13 ] ] +mem: storing 13 in location 1 :(before "End Primitive Recipe Declarations") RUN, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "run", RUN); :(before "End Primitive Recipe Checks") case RUN: { break; } :(before "End Primitive Recipe Implementations") case RUN: { ostringstream tmp; tmp << "recipe run" << Next_recipe_ordinal << " [ " << current_instruction().ingredients.at(0).name << " ]"; //? cerr << "before load\n"; vector tmp_recipe = load(tmp.str()); //? cerr << "before bind\n"; bind_special_scenario_names(tmp_recipe.at(0)); //? cerr << "before transform\n"; transform_all(); //? cerr << "end\n"; if (Trace_stream) { ++Trace_stream->callstack_depth; trace(9998, "trace") << "run: incrementing callstack depth to " << Trace_stream->callstack_depth << end(); assert(Trace_stream->callstack_depth < 9000); // 9998-101 plus cushion } Current_routine->calls.push_front(call(tmp_recipe.at(0))); continue; // not done with caller; don't increment current_step_index() } // Some variables for fake resources always get special addresses in // scenarios. :(code) void bind_special_scenario_names(recipe_ordinal r) { // Special Scenario Variable Names(r) // End Special Scenario Variable Names(r) } :(scenario run_multiple) recipe main [ run [ 1:number <- copy 13 ] run [ 2:number <- copy 13 ] ] +mem: storing 13 in location 1 +mem: storing 13 in location 2 //: 'memory-should-contain' raises errors if specific locations aren't as expected //: Also includes some special support for checking strings. :(before "End Globals") bool Scenario_testing_scenario = false; :(before "End Setup") Scenario_testing_scenario = false; :(scenario memory_check) % Scenario_testing_scenario = true; % Hide_errors = true; recipe main [ memory-should-contain [ 1 <- 13 ] ] +run: checking location 1 +error: expected location 1 to contain 13 but saw 0 :(before "End Primitive Recipe Declarations") MEMORY_SHOULD_CONTAIN, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "memory-should-contain", MEMORY_SHOULD_CONTAIN); :(before "End Primitive Recipe Checks") case MEMORY_SHOULD_CONTAIN: { break; } :(before "End Primitive Recipe Implementations") case MEMORY_SHOULD_CONTAIN: { if (!Passed) break; check_memory(current_instruction().ingredients.at(0).name); break; } :(code) void check_memory(const string& s) { istringstream in(s); in >> std::noskipws; set locations_checked; while (true) { skip_whitespace_and_comments(in); if (!has_data(in)) break; string lhs = next_word(in); if (!is_integer(lhs)) { check_type(lhs, in); continue; } long long int a
/*
 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
 * See LICENSE file for license details.
 */

#include "dwm.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <X11/keysym.h>

/********** CUSTOMIZE **********/

const char *term[] = { 
	"urxvtc", "-tr", "+sb", "-bg", "black", "-fg", "white", "-fn",
	"-*-terminus-medium-*-*-*-13-*-*-*-*-*-iso10646-*",NULL
};
const char *browse[] = { "firefox", NULL };

static Key key[] = {
	{ Mod1Mask, XK_Return, (void (*)(void *))spawn, term },
	{ Mod1Mask, XK_w, (void (*)(void *))spawn, browse },
	{ Mod1Mask, XK_k, sel, "prev" }, 
	{ Mod1Mask, XK_j, sel, "next" }, 
	{ Mod1Mask, XK_space, toggle, NULL }, 
	{ Mod1Mask, XK_m, max, NULL }, 
	{ Mod1Mask | ShiftMask, XK_c, ckill, NULL }, 
	{ Mod1Mask | ShiftMask, XK_q, quit, NULL },
};

/********** CUSTOMIZE **********/

void
update_keys(void)
{
	unsigned