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
18extern test_case_element* test_case_ddktl_device;
19extern test_case_element* test_case_ddktl_ethernet_device;
20
21namespace {
22
23void 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
32static 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
41zx_status_t ddktl_test_func(void* cookie, test_report_t* report, const void* arg, size_t arglen) {
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 = proto.ops->get_output_socket(proto.ctx);
52    if (output != ZX_HANDLE_INVALID) {
53        unittest_set_output_function(ddktl_test_output_func, &output);
54    }
55
56    memset(report, 0, sizeof(*report));
57    update_test_report(unittest_run_one_test(test_case_ddktl_device, TEST_ALL), report);
58    update_test_report(unittest_run_one_test(test_case_ddktl_ethernet_device, TEST_ALL), report);
59    return report->n_failed == 0 ? ZX_OK : ZX_ERR_INTERNAL;
60}
61
62}  // namespace
63
64extern "C" zx_status_t ddktl_test_bind(void* ctx, zx_device_t* parent) {
65    test_protocol_t proto;
66    auto status =
67        device_get_protocol(parent, ZX_PROTOCOL_TEST, reinterpret_cast<void*>(&proto));
68    if (status != ZX_OK) {
69        return status;
70    }
71
72    proto.ops->set_test_func(proto.ctx, ddktl_test_func, parent);
73
74    return ZX_OK;
75}
76