1 /*
2  * Copyright (c) 2021 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "mock_backend.h"
8 #include <zephyr/ztest.h>
9 #include <zephyr/logging/log_core.h>
10 
mock_log_backend_reset(const struct log_backend * backend)11 void mock_log_backend_reset(const struct log_backend *backend)
12 {
13 	struct mock_log_backend *mock = backend->cb->ctx;
14 
15 	mock->msg_rec_idx = 0;
16 	mock->msg_proc_idx = 0;
17 	mock->do_check = true;
18 	mock->exp_drop_cnt = 0;
19 	mock->drop_cnt = 0;
20 	mock->panic = false;
21 }
22 
mock_log_backend_check_enable(const struct log_backend * backend)23 void mock_log_backend_check_enable(const struct log_backend *backend)
24 {
25 	struct mock_log_backend *mock = backend->cb->ctx;
26 
27 	mock->do_check = true;
28 }
29 
mock_log_backend_check_disable(const struct log_backend * backend)30 void mock_log_backend_check_disable(const struct log_backend *backend)
31 {
32 	struct mock_log_backend *mock = backend->cb->ctx;
33 
34 	mock->do_check = false;
35 }
36 
mock_log_backend_dummy_record(const struct log_backend * backend,int cnt)37 void mock_log_backend_dummy_record(const struct log_backend *backend, int cnt)
38 {
39 	struct mock_log_backend *mock = backend->cb->ctx;
40 
41 	for (int i = 0; i < cnt; i++) {
42 		mock->exp_msgs[mock->msg_rec_idx + i].check = false;
43 	}
44 
45 	mock->msg_rec_idx += cnt;
46 }
47 
mock_log_backend_drop_record(const struct log_backend * backend,int cnt)48 void mock_log_backend_drop_record(const struct log_backend *backend, int cnt)
49 {
50 	struct mock_log_backend *mock = backend->cb->ctx;
51 
52 	mock->exp_drop_cnt = cnt;
53 }
54 
mock_log_backend_generic_record(const struct log_backend * backend,uint16_t source_id,uint16_t domain_id,uint8_t level,log_timestamp_t timestamp,const char * str,uint8_t * data,uint32_t data_len)55 void mock_log_backend_generic_record(const struct log_backend *backend,
56 				     uint16_t source_id,
57 				     uint16_t domain_id,
58 				     uint8_t level,
59 				     log_timestamp_t timestamp,
60 				     const char *str,
61 				     uint8_t *data,
62 				     uint32_t data_len)
63 {
64 	if (backend->cb == NULL) {
65 		return;
66 	}
67 
68 	if (IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY) && timestamp != (log_timestamp_t)UINT32_MAX) {
69 		return;
70 	}
71 
72 	struct mock_log_backend *mock = backend->cb->ctx;
73 	struct mock_log_backend_msg *exp = &mock->exp_msgs[mock->msg_rec_idx];
74 
75 	exp->check = true;
76 	exp->timestamp = timestamp;
77 	exp->source_id = source_id;
78 	exp->domain_id = domain_id;
79 	exp->level = level;
80 
81 	int len = strlen(str);
82 
83 	__ASSERT_NO_MSG(len < sizeof(exp->str));
84 
85 	memcpy(exp->str, str, len);
86 	exp->str[len] = 0;
87 
88 	if (data_len <= sizeof(exp->data)) {
89 		memcpy(exp->data, data, data_len);
90 	}
91 	exp->data_len = data_len;
92 
93 	mock->msg_rec_idx++;
94 }
95 
mock_log_backend_validate(const struct log_backend * backend,bool panic)96 void mock_log_backend_validate(const struct log_backend *backend, bool panic)
97 {
98 	struct mock_log_backend *mock = backend->cb->ctx;
99 
100 	zassert_equal(mock->exp_drop_cnt, mock->drop_cnt,
101 		      "Got: %u, Expected: %u", mock->drop_cnt, mock->exp_drop_cnt);
102 	zassert_equal(mock->msg_rec_idx, mock->msg_proc_idx,
103 			"%p Recored:%d, Got: %d", mock, mock->msg_rec_idx, mock->msg_proc_idx);
104 	zassert_equal(mock->panic, panic);
105 
106 #if defined(CONFIG_LOG_MODE_DEFERRED) && \
107 	defined(CONFIG_LOG_PROCESS_THREAD)
108 	zassert_true(mock->evt_notified);
109 #endif
110 }
111 
112 struct test_str {
113 	char *str;
114 	int cnt;
115 };
116 
out(int c,void * ctx)117 static int out(int c, void *ctx)
118 {
119 	struct test_str *s = ctx;
120 
121 	s->str[s->cnt++] = (char)c;
122 
123 	return c;
124 }
125 
process(const struct log_backend * const backend,union log_msg_generic * msg)126 static void process(const struct log_backend *const backend,
127 		union log_msg_generic *msg)
128 {
129 	struct mock_log_backend *mock = backend->cb->ctx;
130 	struct mock_log_backend_msg *exp = &mock->exp_msgs[mock->msg_proc_idx];
131 
132 	if (!mock->do_check) {
133 		return;
134 	}
135 
136 	mock->msg_proc_idx++;
137 
138 	if (!exp->check) {
139 		return;
140 	}
141 
142 	zassert_equal(msg->log.hdr.timestamp, exp->timestamp,
143 #ifdef CONFIG_LOG_TIMESTAMP_64BIT
144 		      "Got: %llu, expected: %llu",
145 #else
146 		      "Got: %u, expected: %u",
147 #endif
148 		      msg->log.hdr.timestamp, exp->timestamp);
149 	zassert_equal(msg->log.hdr.desc.level, exp->level);
150 	zassert_equal(msg->log.hdr.desc.domain, exp->domain_id);
151 
152 	uint32_t source_id;
153 	const void *source = msg->log.hdr.source;
154 
155 	if (exp->level == LOG_LEVEL_INTERNAL_RAW_STRING) {
156 		source_id = (uintptr_t)source;
157 	} else if (source == NULL) {
158 		source_id = 0;
159 	} else {
160 		source_id = IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ?
161 		    log_dynamic_source_id((struct log_source_dynamic_data *)source) :
162 		    log_const_source_id((const struct log_source_const_data *)source);
163 	}
164 
165 	zassert_equal(source_id, exp->source_id, "source_id:%p (exp: %d)",
166 		      source_id, exp->source_id);
167 
168 	size_t len;
169 	uint8_t *data;
170 	struct cbprintf_package_desc *package_desc;
171 
172 	data = log_msg_get_data(&msg->log, &len);
173 
174 	zassert_equal(exp->data_len, len);
175 	if (exp->data_len <= sizeof(exp->data)) {
176 		zassert_equal(memcmp(data, exp->data, len), 0);
177 	}
178 
179 	char str[128];
180 	struct test_str s = { .str = str };
181 
182 	data = log_msg_get_package(&msg->log, &len);
183 	package_desc = (struct cbprintf_package_desc *)data;
184 
185 	if (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC)) {
186 		/* If RO string locations are appended there is always at least 1: format string. */
187 		zassert_true(package_desc->ro_str_cnt > 0);
188 	} else {
189 		zassert_equal(package_desc->ro_str_cnt, 0);
190 	}
191 
192 	len = cbpprintf(out, &s, data);
193 	if (len > 0) {
194 		str[len] = '\0';
195 	}
196 
197 	zassert_equal(strcmp(str, exp->str), 0, "Got \"%s\", Expected:\"%s\"",
198 			str, exp->str);
199 }
200 
mock_init(struct log_backend const * const backend)201 static void mock_init(struct log_backend const *const backend)
202 {
203 
204 }
205 
panic(struct log_backend const * const backend)206 static void panic(struct log_backend const *const backend)
207 {
208 	struct mock_log_backend *mock = backend->cb->ctx;
209 
210 	mock->panic = true;
211 }
212 
dropped(const struct log_backend * const backend,uint32_t cnt)213 static void dropped(const struct log_backend *const backend, uint32_t cnt)
214 {
215 	struct mock_log_backend *mock = backend->cb->ctx;
216 
217 	mock->drop_cnt += cnt;
218 }
219 
220 
221 #if defined(CONFIG_LOG_MODE_DEFERRED) && \
222 	defined(CONFIG_LOG_PROCESS_THREAD)
notify(const struct log_backend * const backend,enum log_backend_evt event,union log_backend_evt_arg * arg)223 static void notify(const struct log_backend *const backend,
224 		   enum log_backend_evt event,
225 		   union log_backend_evt_arg *arg)
226 {
227 	struct mock_log_backend *mock = backend->cb->ctx;
228 
229 	mock->evt_notified = true;
230 }
231 #endif
232 
233 const struct log_backend_api mock_log_backend_api = {
234 	.process = process,
235 	.panic = panic,
236 	.init = mock_init,
237 	.dropped = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ? NULL : dropped,
238 
239 #if defined(CONFIG_LOG_MODE_DEFERRED) && \
240 	defined(CONFIG_LOG_PROCESS_THREAD)
241 	.notify = notify,
242 #endif
243 };
244