1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // This is a test of using pw_tokenizer in C99. It can be compiled outside of
16 // the GN build by adding a main() function that calls RunTestAndReturnPassed()
17 // and invoking the compiler as follows:
18 /*
19 gcc -std=c99 -Wall -Wextra \
20 -Ipw_assert/public \
21 -Ipw_assert/print_and_abort_check_public_overrides \
22 -Ipw_containers/public \
23 -Ipw_polyfill/public \
24 -Ipw_preprocessor/public \
25 -Ipw_tokenizer/public \
26 -Ipw_varint/public \
27 pw_tokenizer/tokenize_c99_test.c \
28 pw_varint/varint_c.c \
29 pw_containers/inline_var_len_entry_queue.c
30 */
31
32 #include <inttypes.h>
33 #include <stdarg.h>
34 #include <stdint.h>
35 #include <string.h>
36
37 #include "pw_containers/inline_var_len_entry_queue.h"
38 #include "pw_tokenizer/encode_args.h"
39 #include "pw_tokenizer/tokenize.h"
40 #include "pw_varint/varint.h"
41
42 static_assert(__STDC_VERSION__ == 199901L,
43 "This test should be compiled with -std=c99.");
44
45 PW_VARIABLE_LENGTH_ENTRY_QUEUE_DECLARE(buffer, 256);
46
47 // Encodes a tokenized message with any number of int arguments.
TokenizeIntegersOnly(uint32_t token,int arg_count,...)48 static void TokenizeIntegersOnly(uint32_t token, int arg_count, ...) {
49 va_list args;
50 va_start(args, arg_count);
51
52 // Encode the tokenized log to a temporary buffer.
53 uint8_t encoded[32];
54 memcpy(encoded, &token, sizeof(token));
55
56 size_t index = sizeof(token);
57
58 for (int i = 0; i < arg_count; ++i) {
59 // Encode each int argument.
60 int argument = va_arg(args, uint32_t);
61
62 // Encode the argument to the buffer
63 index += pw_tokenizer_EncodeInt(
64 argument, &encoded[index], sizeof(encoded) - index);
65 }
66
67 // Write the encoded log to the ring buffer
68 pw_InlineVarLenEntryQueue_PushOverwrite(buffer, encoded, index);
69
70 va_end(args);
71 }
72
73 // Tokenization macro that only handles int arguments.
74 #define TOKENIZE_INTS(format, ...) \
75 do { \
76 PW_TOKENIZE_FORMAT_STRING_ANY_ARG_COUNT( \
77 "tokenize_c99_test", UINT32_MAX, format, __VA_ARGS__); \
78 TokenizeIntegersOnly(_pw_tokenizer_token, \
79 PW_FUNCTION_ARG_COUNT(__VA_ARGS__) \
80 PW_COMMA_ARGS(__VA_ARGS__)); \
81 } while (0)
82
83 // C version of the ASSERT_EQ macro that returns a string version of the failing
84 // line.
85 #define ASSERT_EQ(lhs, rhs) \
86 if ((lhs) != (rhs)) { \
87 return FILE_LINE ": ASSERT_EQ(" #lhs ", " #rhs ") failed!"; \
88 }
89
90 #define FILE_LINE __FILE__ ":" STRINGIFY(__LINE__)
91 #define STRINGIFY(x) _STRINGIFY(x)
92 #define _STRINGIFY(x) #x
93
94 // This test tokenize a few strings with arguments and checks the contents.
95 // It is called from tokenize_c99_test_entry_point.cc.
RunTestAndReturnPassed(void)96 const char* RunTestAndReturnPassed(void) {
97 TOKENIZE_INTS("Tokenize this with no arguments!");
98 TOKENIZE_INTS("One arg, one byte: %x", -1);
99 TOKENIZE_INTS("One arg, 5 bytes: %ld", (long)INT32_MAX);
100 TOKENIZE_INTS("Three args, 4 bytes: %d %d %d", 1, 63, 128);
101
102 ASSERT_EQ(pw_InlineVarLenEntryQueue_Size(buffer), 4u);
103
104 pw_InlineVarLenEntryQueue_Iterator it =
105 pw_InlineVarLenEntryQueue_Begin(buffer);
106 pw_InlineVarLenEntryQueue_Entry entry =
107 pw_InlineVarLenEntryQueue_GetEntry(&it);
108
109 ASSERT_EQ(entry.size_1, sizeof(uint32_t) + 0);
110 ASSERT_EQ(entry.size_2, 0u);
111
112 pw_InlineVarLenEntryQueue_Iterator_Advance(&it);
113 entry = pw_InlineVarLenEntryQueue_GetEntry(&it);
114 ASSERT_EQ(entry.size_1, sizeof(uint32_t) + 1);
115 ASSERT_EQ(entry.size_2, 0u);
116
117 pw_InlineVarLenEntryQueue_Iterator_Advance(&it);
118 entry = pw_InlineVarLenEntryQueue_GetEntry(&it);
119 ASSERT_EQ(entry.size_1, sizeof(uint32_t) + 5);
120 ASSERT_EQ(entry.size_2, 0u);
121
122 pw_InlineVarLenEntryQueue_Iterator_Advance(&it);
123 entry = pw_InlineVarLenEntryQueue_GetEntry(&it);
124 ASSERT_EQ(entry.size_1, sizeof(uint32_t) + 4);
125 ASSERT_EQ(entry.size_2, 0u);
126
127 pw_InlineVarLenEntryQueue_Iterator_Advance(&it);
128 pw_InlineVarLenEntryQueue_Iterator end =
129 pw_InlineVarLenEntryQueue_End(buffer);
130 ASSERT_EQ(pw_InlineVarLenEntryQueue_Iterator_Equal(&it, &end), true);
131
132 return "passed";
133 }
134