firmware  v0.1.2
Chromation Spectrometer Dev-Kit
Mock.c
1 #include "Mock.h"
2 #include <stdlib.h> // malloc, free
3 #include <stdio.h> // printf
4 
5 struct Mock_s {
6  GString *fail_msg;
7  GList *expected_calls; // The GList must be initialized to NULL.
8  GList *actual_calls; // The GList must be initialized to NULL.
9 };
10 Mock_s * Mock_new(void)
11 { // Initialize all pointer members!
12  Mock_s *out = (Mock_s *)malloc(sizeof(Mock_s));
13  out->fail_msg = g_string_new(
14  "No failures recorded. This message should never print."
15  );
16  out->expected_calls = NULL;
17  out->actual_calls = NULL;
18  return out;
19 }
20 void Mock_destroy(Mock_s *self)
21 { // Deallocate this mock struct.
22  g_list_free_full( // Deallocate each GList struct and free the
23  self->expected_calls, // RecordedCall that each data member points to.
24  (GDestroyNotify)RecordedCall_destroy);
25  g_list_free_full(
26  self->actual_calls,
27  (GDestroyNotify)RecordedCall_destroy);
28  g_string_free( // Deallocate the GString struct
29  self->fail_msg, true); // and the message string it points to.
30  free(self); // Tabled: I cannot tell if this is deallocating the Mock_s.
31 }
32 void RecordExpectedCall(Mock_s *self, RecordedCall *func_call)
33 { // Record a function call in the list of expected calls.
34  self->expected_calls = g_list_append(
35  self->expected_calls,
36  (RecordedCall *)func_call
37  );
38 }
39 void RecordActualCall(Mock_s *self, RecordedCall *func_call)
40 { // Record a function call in the list of actual calls.
41  self->actual_calls = g_list_append(
42  self->actual_calls,
43  (RecordedCall *)func_call
44  );
45 }
46 void RecordArg(RecordedCall *self, RecordedArg *input_arg)
47 {
48  self->inputs = g_list_append(
49  self->inputs,
50  (RecordedArg *)input_arg
51  );
52 }
53 
54 /* =====[ New functionality I added 2018 August ]===== */
55 char const * ListAllCalls(Mock_s *self)
56 {
57  // Alternate to `WhyDidItFail`.
58  /* GList *expected_calls = self->expected_calls; */
59  /* GList *actual_calls = self->actual_calls; */
60  /* uint8_t num_expected_calls = g_list_length(expected_calls); */
61  /* uint8_t num_actual_calls = g_list_length(actual_calls); */
62  GList *expected_calls = self->expected_calls;
63  GList *actual_calls = self->actual_calls;
64  g_string_append_printf( self->fail_msg,
65  "**Calls expected**:"
66  );
67  while (expected_calls != NULL) {
68  RecordedCall *this_call = (RecordedCall *)expected_calls->data;
69  g_string_append_printf( self->fail_msg, " `%s()`", this_call->name);
70  expected_calls = expected_calls->next;
71  }
72  g_string_append_printf( self->fail_msg,
73  "**Calls made**:"
74  );
75  while (actual_calls != NULL) {
76  RecordedCall *this_call = (RecordedCall *)actual_calls->data;
77  g_string_append_printf( self->fail_msg, " `%s()`", this_call->name);
78  actual_calls = actual_calls->next;
79  }
80  return self->fail_msg->str;
81 }
82 /* =====[ New functionality I added 2019 October ]===== */
83 /* bool AssertCall( */
84 /* Mock_s *self, */
85 /* uint8_t n, */
86 /* char * name */
87 /* ) */
88 bool SilentAssertCall(
89  Mock_s *self,
90  uint16_t n,
91  char const * name
92  )
93 {
94  bool call_n_matches_name = false;
95  // Walk the list of calls to get to the nth call.
96  uint16_t this_call_num = 0;
97  GList *actual_calls = self->actual_calls;
98  while( (actual_calls != NULL) && (++this_call_num < n)){
99  actual_calls = actual_calls->next;
100  }
101  if (actual_calls != NULL)
102  {
103  RecordedCall *nth_call = (RecordedCall *)actual_calls->data;
104  if (0 == g_strcmp0(name, nth_call->name))
105  {
106  call_n_matches_name = true;
107  }
108  }
109  return call_n_matches_name;
110 }
111 bool AssertCall(
112  Mock_s *self,
113  uint16_t n,
114  char const * name
115  )
116 {
117  /* printf("\nChecking if call %d is named %s.\n",n,name); */
118  printf("\n- Call %d is named %s? ",n,name);
119  /* Return true if call `n` is named `name`. */
120  /* Return false otherwise. */
121  bool call_n_matches_name = false;
122  /* First call is n=1. */
123  /* uint8_t this_call_num = 0; // iterate call number starting with call 1 */
124  uint16_t this_call_num = 0; // iterate call number starting with call 1
125  /* Work with the list of *actual* calls in the `mock` struct. */
126  GList *actual_calls = self->actual_calls;
127  while( (actual_calls != NULL) && (++this_call_num < n)){
128  actual_calls = actual_calls->next;
129  }
130  if (actual_calls == NULL)
131  {
132  printf("Error: less than %d calls.\n", n);
133  }
134  else
135  {
136  RecordedCall *nth_call = (RecordedCall *)actual_calls->data;
137  /* printf("- Call %d is %s.\n", this_call_num, nth_call->name); */
138  // I found an instance where the simple `==` does not work.
139  // I'm not sure what's different about this instance.
140  /* printf("- Result of `==`?: %d\n", (nth_call->name == name)); */
141  /* if (nth_call->name == name) call_n_matches_name = true; */
142  // So use `g_strcmp0` instead. That works for this corner case.
143  /* printf("- If they match, g_strcmp0 returns 0: %d\n", g_strcmp0(name, nth_call->name)); */
144  if (0 == g_strcmp0(name, nth_call->name))
145  {
146  call_n_matches_name = true;
147  printf("Yes.\n");
148  }
149  else
150  {
151  printf("\n - No, call %d is %s.\n", this_call_num, nth_call->name);
152  }
153  printf("\n");
154  }
155  return call_n_matches_name;
156 }
157 bool AssertArg(
158  Mock_s *self,
159  uint16_t call_n,
160  uint8_t arg_k,
161  void *p_assert_val
162  )
163 {
164  // Return true if nth call, kth arg matches value pointed to by `p_assert_val`.
165  // Return false otherwise.
166  // ~Client passes definition of `match_arg`.~
167  // CheckArg is a built-in method for a RecordedArg struct.
168  // This determines the data type pointed to by input `p_assert_val`.
169  /* printf("\nChecking value of arg %d in call %d.\n",arg_k,call_n); */
170  printf("\n- Value passed to call %d, arg %d? ",call_n,arg_k);
171  bool arg_k_matches_value = false;
172  /* First call is n=1. */
173  uint8_t this_call_num = 0; // iterate call number starting with call 1
174  /* Work with the list of *actual* calls in the `mock` struct. */
175  GList *actual_calls = self->actual_calls;
176  while( (actual_calls != NULL) && (++this_call_num < call_n)){
177  actual_calls = actual_calls->next;
178  }
179  if (actual_calls == NULL)
180  {
181  printf("Error: less than %d calls.\n", call_n);
182  }
183  else
184  {
185  RecordedCall *nth_call = (RecordedCall *)actual_calls->data;
186  GList *inputs = nth_call->inputs;
187  // Walk the inputs to get to the kth arg.
188  /* First arg is k=1. */
189  uint8_t this_arg_num = 0; // iterate arg number starting with arg 1
190  while( (inputs != NULL) && (++this_arg_num < arg_k)){
191  inputs = inputs->next;
192  }
193  if (inputs == NULL)
194  {
195  printf("Error: call %d has less than %d args.\n", this_call_num, arg_k);
196  }
197  else
198  {
199  printf("\n");
200  RecordedArg *kth_arg = (RecordedArg *)inputs->data;
201  // TODO: how do I print the expected arg type and arg value?
202  // Return true/false if expected and actual args have:
203  // - matching types
204  // - matching values
205  arg_k_matches_value = kth_arg->CheckArg(kth_arg, p_assert_val);
206  // print message: call number, arg number, arg value
207  GString *printed_arg = g_string_new(" ");
208  kth_arg->Print(printed_arg, kth_arg); // print value to GString
209  /* printf("Call %d, ", this_call_num); */
210  /* printf("arg %d, ", this_arg_num); */
211  /* printf("has value %s.\n", printed_arg->str); */
212  printf(" - %s is arg %d to call %s.\n", printed_arg->str, arg_k, nth_call->name);
213  }
214  printf("\n");
215  }
216  return arg_k_matches_value;
217 }
218 // TODO: eliminate this
219 // AssertArgPointsToValue is bullshit.
220 // It stores the pointer but does not store the values pointed to.
221 // The values pointed to are only in memory while the FUT is on the stack frame.
222 // After the FUT returns, the values pointed to are unprotected.
223 // Sometimes they are untouched and dereferencing the pointer works.
224 // Sometimes not, and dereferencing the pointer returns unexpected values,
225 // thought it never results in a seg fault.
226 // AssertArgPointsToValue is only valid to use in the case where the arg points
227 // to a global. It is invalid to use if the arg points to a variable local to
228 // the FUT.
229 bool AssertArgPointsToValue(
230  Mock_s *self,
231  uint8_t call_n,
232  uint8_t arg_k,
233  void *pp_assert_val
234  )
235 {
236  // Return true if nth call, kth arg points to a value equal to the value
237  // pointed to by `p_assert_val`. Return false otherwise.
238  // Note `pp_assert_val` is a pointer *to a pointer* to a value. It gets
239  // dereferenced *twice*. Example: check if kth arg points to value 0x01:
240  // uint8_t argv=0x01; uint8_t *pargv=&argv;
241  // Then pass `&pargv` as the argument for pp_assert_val.
242  // ---- START SECTION: IDENTICAL TO AssertArg()
243  // CheckArg is a built-in method for a RecordedArg struct.
244  // This determines the data type pointed to by input `pp_assert_val`.
245  /* printf("\nChecking value of arg %d in call %d.\n",arg_k,call_n); */
246  printf("Value at address passed to call %d, arg %d? ",call_n,arg_k);
247  bool arg_k_matches_value = false;
248  /* First call is n=1. */
249  uint8_t this_call_num = 0; // iterate call number starting with call 1
250  /* Work with the list of *actual* calls in the `mock` struct. */
251  GList *actual_calls = self->actual_calls;
252  while( (actual_calls != NULL) && (++this_call_num < call_n)){
253  actual_calls = actual_calls->next;
254  }
255  if (actual_calls == NULL)
256  {
257  printf("Error: less than %d calls.\n", call_n);
258  }
259  else
260  {
261  RecordedCall *nth_call = (RecordedCall *)actual_calls->data;
262  GList *inputs = nth_call->inputs;
263  // Walk the inputs to get to the kth arg.
264  /* First arg is k=1. */
265  uint8_t this_arg_num = 0; // iterate arg number starting with arg 1
266  while( (inputs != NULL) && (++this_arg_num < arg_k)){
267  inputs = inputs->next;
268  }
269  if (inputs == NULL)
270  {
271  printf("Error: call %d has less than %d args.\n", this_call_num, arg_k);
272  }
273  else
274  {
275  RecordedArg *kth_arg = (RecordedArg *)inputs->data;
276  // TODO: how do I print the expected arg type and arg value?
277  // Return true/false if expected and actual args have:
278  // - matching types
279  // - matching values
280  // ---- END SECTION: IDENTICAL TO AssertArg()
281  // The change from AssertArg:
282  // Replace CheckArg with CheckValArgPointsTo
283  // This dereferences the kth_arg and does an additional dereference to the pp_assert_val so that the values are compared, not the pointers.
284  arg_k_matches_value = kth_arg->CheckValArgPointsTo(kth_arg, pp_assert_val);
285  // ---- THE REST IS IDENTICAL TO AssertArg()
286  // print message: call number, arg number, arg value
287  GString *printed_arg = g_string_new(" ");
288  kth_arg->Print(printed_arg, kth_arg); // print value to GString
289  /* printf("Call %d, ", this_call_num); */
290  /* printf("arg %d, ", this_arg_num); */
291  /* printf("has value %s.\n", printed_arg->str); */
292  printf("%s.\n", printed_arg->str);
293  }
294  }
295  return arg_k_matches_value;
296 }
297 uint16_t NumberOfActualCalls(Mock_s *self)
298 {
299  // Return the number of actual calls recorded in the `Mock_s`.
300  GList *actual_calls = self->actual_calls;
301  uint16_t num_actual_calls = g_list_length(actual_calls);
302  return num_actual_calls;
303 }
304 //=====[ Examples using Mock to implement mock-c functionalty ]=====
305 static void PrintAllInputs(GList *inputs)
306 {
307  GString *printed_arg = g_string_new(
308  "Error: `RecordedArg->Print` should have overwritten this message."
309  );
310  while (inputs != NULL)
311  {
312  RecordedArg *this_arg = (RecordedArg *)inputs->data;
313  (this_arg->Print(printed_arg, this_arg)); // print to the GString
314  printf(", %s", printed_arg->str); // print to stdout
315  //printf(", %s", ((AnyType_s *)inputs->data)->printed->str);
316  inputs = inputs->next;
317  }
318  printf("\n");
319  g_string_free(printed_arg, true);
320 }
321 void PrintAllCalls(Mock_s *self) // Example
322 {
323  GList *expected_calls = self->expected_calls;
324  GList *actual_calls = self->actual_calls;
325  uint8_t num_expected_calls = g_list_length(expected_calls);
326  uint8_t num_actual_calls = g_list_length(actual_calls);
327  //while (expected_calls != NULL && actual_calls != NULL)
328  printf("\n- Expected %d calls:\n", num_expected_calls);
329  while (expected_calls != NULL) {
330  RecordedCall *this_call = (RecordedCall *)expected_calls->data;
331  printf(" - \"%s\"", this_call->name);
332  PrintAllInputs(this_call->inputs);
333  expected_calls = expected_calls->next;
334  }
335  printf("- Received %d calls:\n", num_actual_calls);
336  while (actual_calls != NULL) {
337  RecordedCall *this_call = (RecordedCall *)actual_calls->data;
338  printf( " - \"%s\"", this_call->name);
339  PrintAllInputs(this_call->inputs);
340  actual_calls = actual_calls->next;
341  }
342 }
343 
344 //=====[ Extending old mock-c ]=====
345 static bool Each_call_has_the_correct_number_of_inputs(Mock_s *self);
346 static void print_first_call_with_wrong_number_of_inputs(Mock_s *self);
347 static uint8_t NumberOfArgs(RecordedCall *self);
348 //=====[ Copied from old mock-c ]=====
349 static bool Call_lists_are_the_same_length(Mock_s *self);
350 static bool EachCallMatches(Mock_s *self);
351 static void print_number_of_expected_and_actual_calls(Mock_s *self);
352 static void print_first_unexpected_call(Mock_s *self);
353 static void print_first_missed_call(Mock_s *self);
354 static void print_all_wrong_calls(Mock_s *self);
355 
356 bool RanAsHoped(Mock_s *self)
357 {
358  // Initialize message
359  /* g_string_printf( self->fail_msg, "Why it failed: "); */
360  g_string_printf( self->fail_msg, " ");
361 
362  if (!Call_lists_are_the_same_length(self))
363  {
364  print_number_of_expected_and_actual_calls(self);
365  print_first_unexpected_call(self);
366  print_first_missed_call(self);
367  }
368  if (!Each_call_has_the_correct_number_of_inputs(self))
369  print_first_call_with_wrong_number_of_inputs(self);
370  if (!EachCallMatches(self))
371  print_all_wrong_calls(self);
372  return (
373  Call_lists_are_the_same_length(self) &&
374  Each_call_has_the_correct_number_of_inputs(self) &&
375  EachCallMatches(self)
376  );
377 }
378 char const * WhyDidItFail(Mock_s *self)
379 {
380  return self->fail_msg->str;
381 }
382 
383 static bool Call_lists_are_the_same_length(Mock_s *self)
384 {
385  return (
386  g_list_length(self->expected_calls)
387  ==
388  g_list_length(self->actual_calls)
389  );
390 }
391 static bool Each_call_has_the_correct_number_of_inputs(Mock_s *self)
392 {
393  GList *expected_calls = self->expected_calls;
394  GList *actual_calls = self->actual_calls;
395  while (expected_calls != NULL && actual_calls != NULL)
396  {
397  RecordedCall *this_expected_call = (RecordedCall *)expected_calls->data;
398  RecordedCall *this_actual_call = (RecordedCall *)actual_calls->data;
399  if (NumberOfArgs(this_expected_call) != NumberOfArgs(this_actual_call))
400  return false;
401 
402  expected_calls = expected_calls->next;
403  actual_calls = actual_calls->next;
404  }
405  return true;
406 }
407 static bool CallNamesMatch(char const *expected_name, char const *actual_name)
408 {
409  int names_do_not_match = g_strcmp0(expected_name, actual_name);
410  return names_do_not_match ? false : true;
411 }
412 
413 static bool RecordedArgsMatch(RecordedArg *expected_arg, RecordedArg *actual_arg)
414 {
415  //if (match functions are not the same then the types do not even match)
416  if (expected_arg->Match != actual_arg->Match) return false;
417  //use the match function to return true if they match
418  return expected_arg->Match(expected_arg, actual_arg);
419 }
420 static bool CallInputsMatch(GList *expected_inputs, GList *actual_inputs)
421 {
422  while (expected_inputs != NULL && actual_inputs != NULL)
423  {
424  RecordedArg *this_expected_arg = (RecordedArg *)expected_inputs->data;
425  RecordedArg *this_actual_arg = (RecordedArg *)actual_inputs->data;
426  if (!RecordedArgsMatch(
427  this_expected_arg,
428  this_actual_arg)) return false;
429 
430  expected_inputs = expected_inputs->next;
431  actual_inputs = actual_inputs->next;
432  }
433  return true;
434 
435 }
436 static bool EachCallMatches(Mock_s *self)
437 {
438  GList *expected_calls = self->expected_calls;
439  GList *actual_calls = self->actual_calls;
440  while (expected_calls != NULL && actual_calls != NULL)
441  {
442  RecordedCall *this_expected_call = (RecordedCall *)expected_calls->data;
443  RecordedCall *this_actual_call = (RecordedCall *)actual_calls->data;
444  if (!CallNamesMatch(
445  this_expected_call->name,
446  this_actual_call->name)) return false;
447  if (!CallInputsMatch(
448  this_expected_call->inputs,
449  this_actual_call->inputs)) return false;
450 
451  expected_calls = expected_calls->next;
452  actual_calls = actual_calls->next;
453  }
454  return true;
455 }
456 static void print_number_of_expected_and_actual_calls(Mock_s *self)
457 {
458  GList *expected_calls = self->expected_calls;
459  GList *actual_calls = self->actual_calls;
460  uint8_t num_expected_calls = g_list_length(expected_calls);
461  uint8_t num_actual_calls = g_list_length(actual_calls);
462  g_string_append_printf( self->fail_msg,
463  "Expected %d calls, received %d calls. ",
464  num_expected_calls, num_actual_calls
465  );
466 }
467 static uint8_t NumberOfArgs(RecordedCall *self) {
468  return g_list_length(self->inputs);
469 }
470 static void print_first_call_with_wrong_number_of_inputs(Mock_s *self)
471 {
472  GList *expected_calls = self->expected_calls;
473  GList *actual_calls = self->actual_calls;
474  int call_number = 1;
475  while (expected_calls != NULL && actual_calls != NULL)
476  {
477  RecordedCall *this_expected_call = (RecordedCall *)expected_calls->data;
478  RecordedCall *this_actual_call = (RecordedCall *)actual_calls->data;
479  if (NumberOfArgs(this_expected_call) != NumberOfArgs(this_actual_call))
480  g_string_append_printf( self->fail_msg,
481  "Wrong number of args in call #%d '%s', expected %d, was %d. ",
482  call_number,
483  this_expected_call->name,
484  NumberOfArgs(this_expected_call),
485  NumberOfArgs(this_actual_call)
486  );
487  call_number++;
488  expected_calls = expected_calls->next;
489  actual_calls = actual_calls->next;
490  }
491 }
492 static void print_first_unexpected_call(Mock_s *self)
493 { // Calls made by the function under test, not expected by the test.
494  GList *expected_calls = self->expected_calls;
495  GList *actual_calls = self->actual_calls;
496  uint8_t num_expected_calls = g_list_length(expected_calls);
497  uint8_t num_actual_calls = g_list_length(actual_calls);
498  if (num_expected_calls < num_actual_calls)
499  g_string_append_printf( self->fail_msg,
500  "First unexpected call: received #%d:'%s'. ",
501  num_expected_calls + 1,
502  ((RecordedCall *)g_list_nth_data(
503  actual_calls, num_expected_calls)
504  )->name
505  );
506 }
507 static void print_first_missed_call(Mock_s *self)
508 { // Calls expected by the test, not made by the function under test.
509  GList *expected_calls = self->expected_calls;
510  GList *actual_calls = self->actual_calls;
511  uint8_t num_expected_calls = g_list_length(expected_calls);
512  uint8_t num_actual_calls = g_list_length(actual_calls);
513  if (num_expected_calls > num_actual_calls)
514  g_string_append_printf( self->fail_msg,
515  "First missed call: expected #%d:'%s'. ",
516  num_actual_calls + 1,
517  ((RecordedCall *)g_list_nth_data(
518  expected_calls, num_actual_calls)
519  )->name
520  //(gchar *)g_list_nth_data(
521  // expected_calls,
522  // num_actual_calls
523  // )
524  );
525 }
526 static void PrintExpectedAndActualNames( GString *fail_msg,
527  uint8_t call_number, char const *expected_name, char const *actual_name)
528 {
529  g_string_append_printf( fail_msg,
530  "Call #%d: expected '%s', was '%s'. ",
531  call_number, expected_name, actual_name);
532 }
533 static void PrintExpectedAndActualInputs(GString *fail_msg,
534  uint8_t call_number, char const *expected_name, GList *expected_inputs, GList *actual_inputs)
535 { // loop through the inputs and print the non-matching
536  GString *printed_expected_arg = g_string_new(
537  "Error: `RecordedArg->Print` should have overwritten this message."
538  );
539  GString *printed_actual_arg = g_string_new(
540  "Error: `RecordedArg->Print` should have overwritten this message."
541  );
542  while (expected_inputs != NULL && actual_inputs != NULL)
543  {
544  RecordedArg *this_expected_arg = (RecordedArg *)expected_inputs->data;
545  RecordedArg *this_actual_arg = (RecordedArg *)actual_inputs->data;
546  if (!RecordedArgsMatch(
547  this_expected_arg,
548  this_actual_arg))
549  {//print them;
550  this_expected_arg->Print( // print to the GString
551  printed_expected_arg, this_expected_arg);
552  this_actual_arg->Print( // print to the GString
553  printed_actual_arg, this_actual_arg);
554  g_string_append_printf(fail_msg,
555  "Call #%d: '%s' expected input '%s', but was '%s'. ",
556  call_number, expected_name,
557  printed_expected_arg->str,
558  printed_actual_arg->str);
559  }
560  expected_inputs = expected_inputs->next;
561  actual_inputs = actual_inputs->next;
562  }
563  g_string_free(printed_expected_arg, true);
564  g_string_free(printed_actual_arg, true);
565 }
566 static void print_all_wrong_calls(Mock_s *self)
567 {
568  uint8_t call_number = 1;
569  GList *expected_calls = self->expected_calls;
570  GList *actual_calls = self->actual_calls;
571  while (expected_calls!=NULL && actual_calls!=NULL)
572  {
573  RecordedCall *this_expected_call = (RecordedCall *)expected_calls->data;
574  RecordedCall *this_actual_call = (RecordedCall *)actual_calls->data;
575  if (!CallNamesMatch(
576  this_expected_call->name,
577  this_actual_call->name)
578  ) PrintExpectedAndActualNames(
579  self->fail_msg,
580  call_number,
581  this_expected_call->name,
582  this_actual_call->name);
583  if (!CallInputsMatch(
584  this_expected_call->inputs,
585  this_actual_call->inputs)
586  ) PrintExpectedAndActualInputs(
587  self->fail_msg,
588  call_number, this_expected_call->name,
589  this_expected_call->inputs,
590  this_actual_call->inputs);
591 
592  expected_calls = expected_calls->next;
593  actual_calls = actual_calls->next;
594  call_number++;
595  }
596 }
Definition: Mock.c:5