1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ddk/device.h>
6 #include <ddk/driver.h>
7 #include <ddk/binding.h>
8 #include <ddk/protocol/test.h>
9 #include <lib/zx/socket.h>
10 
11 #include <unittest/unittest.h>
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <limits.h>
17 
18 extern test_case_element* test_case_ddktl_device;
19 extern test_case_element* test_case_ddktl_ethernet_device;
20 
21 namespace {
22 
ddktl_test_output_func(const char * line,int len,void * arg)23 void ddktl_test_output_func(const char* line, int len, void* arg) {
24     zx_handle_t h = *static_cast<zx_handle_t*>(arg);
25     zx::socket s(h);
26     // len is not actually the number of bytes to output
27     s.write(0u, line, strlen(line), nullptr);
28     // we don't on the socket so release it before it goes out of scope
29     h = s.release();
30 }
31 
update_test_report(bool success,test_report_t * report)32 static void inline update_test_report(bool success, test_report_t* report) {
33     report->n_tests++;
34     if (success) {
35         report->n_success++;
36     } else {
37         report->n_failed++;
38     }
39 }
40 
ddktl_test_func(void * cookie,test_report_t * report)41 zx_status_t ddktl_test_func(void* cookie, test_report_t* report) {
42     auto dev = static_cast<zx_device_t*>(cookie);
43 
44     test_protocol_t proto;
45     auto status =
46         device_get_protocol(dev, ZX_PROTOCOL_TEST, reinterpret_cast<void*>(&proto));
47     if (status != ZX_OK) {
48         return status;
49     }
50 
51     zx_handle_t output;
52     proto.ops->get_output_socket(proto.ctx, &output);
53     if (output != ZX_HANDLE_INVALID) {
54         unittest_set_output_function(ddktl_test_output_func, &output);
55     }
56 
57     memset(report, 0, sizeof(*report));
58     update_test_report(unittest_run_one_test(test_case_ddktl_device, TEST_ALL), report);
59     update_test_report(unittest_run_one_test(test_case_ddktl_ethernet_device, TEST_ALL), report);
60     unittest_restore_output_function();
61     zx_handle_close(output);
62     return report->n_failed == 0 ? ZX_OK : ZX_ERR_INTERNAL;
63 }
64 
65 }  // namespace
66 
ddktl_test_bind(void * ctx,zx_device_t * parent)67 extern "C" zx_status_t ddktl_test_bind(void* ctx, zx_device_t* parent) {
68     test_protocol_t proto;
69     auto status =
70         device_get_protocol(parent, ZX_PROTOCOL_TEST, reinterpret_cast<void*>(&proto));
71     if (status != ZX_OK) {
72         return status;
73     }
74 
75     const test_func_t test = {ddktl_test_func, parent};
76     proto.ops->set_test_func(proto.ctx, &test);
77 
78     return ZX_OK;
79 }
80