3 * Exception for MockLivestatus.
4 * Not expected to be fetched anywhere but in phpunit library
6 class MockLivestatus_Exception
extends Exception
{}
9 * Local helper for MockLivestatus-library.
10 * Handles the stack for resolving livestatus filters on a given object.
12 class MockLivestatus_StateMachine
{
14 * Stack for the state of the state machine
18 * The object to use as source for tests
23 * Initialize the state machine, with an empty stack and a object to work
27 * array with retrieved parameters
29 public function __construct($object) {
30 $this->stack
= array ();
31 $this->object = $object;
35 * Process a "Filter: args" line, and push the reuslt to the stack
38 * "args" part of the filter line
39 * @throws MockLivestatus_Exception
41 public function process_Filter($args) {
42 if (preg_match('/^\s*([a-zA-Z_]+)\s+(!?)([<>=~]+)\s+(.*)$/', $args,
44 $match_var = $matches[1];
45 $match_negate = $matches[2];
46 $match_op = $matches[3];
47 $match_value = $matches[4];
49 if (!isset($this->object[$match_var])) {
50 throw new MockLivestatus_Exception('Unknown field ' . $match_var);
53 $value = $this->object[$match_var];
57 case '=':/* equality */
58 $result = ($match_value == $value);
60 case '~': /* match regular expression (substring match) */
61 $result = (false != preg_match('/' . $match_value . '/', $value));
63 case '=~': /* equality ignoring case */
64 $result = (strtolower($match_value) == strtolower($value));
66 case '~~': /* regular expression ignoring case */
67 $result = (false != preg_match('/' . $match_value . '/i',
70 case '<': /* less than */
71 $result = ($match_value < $value);
73 case '>': /* greater than */
74 $result = ($match_value > $value);
76 case '<=': /* less or equal */
77 $result = ($match_value <= $value);
79 case '>=': /* greater or equal */
80 $result = ($match_value >= $value);
83 throw new MockLivestatus_Exception(
84 'Unknown filter operator ' . $match_op);
87 if ($match_negate == '!') {
91 $this->stack
[] = $result;
93 throw new MockLivestatus_Exception("Malformed filter: " . $args);
97 * Process a "And: N" livestatus filter line, manipulates the stack
101 * "N" part of the filter line, expected to be numeric
102 * @throws MockLivestatus_Exception
104 public function process_And($args) {
106 if (!is_numeric($args)) {
107 throw new MockLivestatus_Exception(
108 "And statement isn't numeric: " . $args);
110 for ($i = 0; $i < intval($args); $i++
) {
111 $val = array_pop($this->stack
);
116 $this->stack
[] = $result;
119 * Process a "Or: N" livestatus filter line, manipulates the stack
123 * "N" part of the filter line, expected to be numeric
124 * @throws MockLivestatus_Exception
126 public function process_Or($args) {
128 if (!is_numeric($args)) {
129 throw new MockLivestatus_Exception(
130 "Or statement isn't numeric: " . $args);
132 for ($i = 0; $i < intval($args); $i++
) {
133 $val = array_pop($this->stack
);
138 $this->stack
[] = $result;
141 * Process a "Negate:" livestatus filter line, negates the top of the stack
144 * empty string (tested to be empty)
145 * @throws MockLivestatus_Exception
147 public function process_Negate($args) {
149 throw new MockLivestatus_Exception(
150 '"Negate:" line with arguments isn\'t allowed');
152 $result = !array_pop($this->stack
);
153 $this->stack
[] = $result;
157 * Get the result from the stack, as anding all the lines that is left.
161 public function get_result() {
162 foreach ($this->stack
as $val) {
172 * A mock replacement for op5Livestatus, which works on the data array passed to
174 * Useful for unit testing
176 class MockLivestatus
{
178 * Storage for the mocked environment.
183 * An array of the previously requested columns
185 public $last_columns = false;
187 * Load the mocked livestatus environment
190 * to be available in the mocked environemnt, indexed by table,
191 * structure as livestatus result (but with names as keys)
193 public function __construct($data) {
198 * Query the mocked livestatus environment.
200 * @param $table Table
202 * @param $filter Filter,
203 * as an array, or multiline string
204 * @param $columns Columns
206 * @param $options Options
208 * @throws MockLivestatus_Exception
209 * @return array, as op5Livestatus returns
211 public function query($table, $filter, $columns, $options = array()) {
213 /* Strip down $filter-var to make sure it's an array */
214 if (is_string($filter))
215 $filter = explode("\n", $filter);
219 $processed_filter = array ();
220 foreach ($filter as $filterline) {
221 if (!empty($filterline)) {
222 $filterop = explode(':', $filterline, 2);
223 if (count($filterop) == 2) {
224 $processed_filter[] = array_map('trim', $filterop);
228 $table_data = $this->data
[$table];
230 $this->last_columns
= $columns;
231 if(is_array($this->last_columns
)) {
232 sort($this->last_columns
);
235 if (empty($columns)) {
236 $columns = array_keys($table_data[0]);
238 if (!is_array($columns)) {
239 throw new MockLivestatus_Exception(
240 'Unknown column definition: ' . var_dump($columns, false));
244 foreach ($table_data as $obj) {
245 $filter_sm = new MockLivestatus_StateMachine($obj);
246 foreach ($processed_filter as $fop) {
247 $filter_sm->{'process_' . $fop[0]}($fop[1]);
249 if ($filter_sm->get_result()) {
250 $this_obj = array ();
251 foreach ($columns as $col) {
252 if (array_key_exists($col, $obj)) {
253 $this_obj[] = $obj[$col];
255 throw new MockLivestatus_Exception(
256 'Unknown column ' . $col . ' for table ' . $table);
259 $objects[] = $this_obj;
263 return array ($columns,$objects,count($objects));