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 = log_source_id(source);
161 	}
162 
163 	zassert_equal(source_id, exp->source_id, "source_id:%p (exp: %d)",
164 		      source_id, exp->source_id);
165 
166 	size_t len;
167 	uint8_t *data;
168 	struct cbprintf_package_desc *package_desc;
169 
170 	data = log_msg_get_data(&msg->log, &len);
171 
172 	zassert_equal(exp->data_len, len);
173 	if (exp->data_len <= sizeof(exp->data)) {
174 		zassert_equal(memcmp(data, exp->data, len), 0);
175 	}
176 
177 	char str[128];
178 	struct test_str s = { .str = str };
179 
180 	data = log_msg_get_package(&msg->log, &len);
181 	package_desc = (struct cbprintf_package_desc *)data;
182 
183 	if (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC)) {
184 		/* If RO string locations are appended there is always at least 1: format string. */
185 		zassert_true(package_desc->ro_str_cnt > 0);
186 	} else {
187 		zassert_equal(package_desc->ro_str_cnt, 0);
188 	}
189 
190 	len = cbpprintf(out, &s, data);
191 	if (len > 0) {
192 		str[len] = '\0';
193 	}
194 
195 	zassert_equal(strcmp(str, exp->str), 0, "Got \"%s\", Expected:\"%s\"",
196 			str, exp->str);
197 }
198 
mock_init(struct log_backend const * const backend)199 static void mock_init(struct log_backend const *const backend)
200 {
201 
202 }
203 
panic(struct log_backend const * const backend)204 static void panic(struct log_backend const *const backend)
205 {
206 	struct mock_log_backend *mock = backend->cb->ctx;
207 
208 	mock->panic = true;
209 }
210 
dropped(const struct log_backend * const backend,uint32_t cnt)211 static void dropped(const struct log_backend *const backend, uint32_t cnt)
212 {
213 	struct mock_log_backend *mock = backend->cb->ctx;
214 
215 	mock->drop_cnt += cnt;
216 }
217 
218 
219 #if defined(CONFIG_LOG_MODE_DEFERRED) && \
220 	defined(CONFIG_LOG_PROCESS_THREAD)
notify(const struct log_backend * const backend,enum log_backend_evt event,union log_backend_evt_arg * arg)221 static void notify(const struct log_backend *const backend,
222 		   enum log_backend_evt event,
223 		   union log_backend_evt_arg *arg)
224 {
225 	struct mock_log_backend *mock = backend->cb->ctx;
226 
227 	mock->evt_notified = true;
228 }
229 #endif
230 
231 const struct log_backend_api mock_log_backend_api = {
232 	.process = process,
233 	.panic = panic,
234 	.init = mock_init,
235 	.dropped = IS_ENABLED(CONFIG_LOG_MODE_IMMEDIATE) ? NULL : dropped,
236 
237 #if defined(CONFIG_LOG_MODE_DEFERRED) && \
238 	defined(CONFIG_LOG_PROCESS_THREAD)
239 	.notify = notify,
240 #endif
241 };
242