1 // Copyright 2018 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 "parent.h"
6 
7 #include <getopt.h>
8 
9 #include <unittest/unittest.h>
10 
11 constexpr char kUsageMessage[] = R"""(
12 Basic functionality test for a nand device.
13 WARNING: Will write to the nand device.
14 
15 Broker unit test:
16   ./nand-test
17 
18   Creates a ram-nand device and runs all the test against it.
19 
20 Existing nand device:
21   ./nand-test --device path_to_device --first-block 100 --num-blocks 10
22 
23   Opens the provided nand device and uses blocks [100, 109] to perform tests.
24   Note that this doesn't verify all the blocks in the given range, just makes
25   sure no block outside of that range is modified.
26 
27 Existing broker device:
28   ./nand-test --device path_to_device --broker --first-block 100 --num-blocks 10
29 
30   Opens the provided broker device and uses blocks [100, 109] to perform tests.
31   Note that this doesn't verify all the blocks in the given range, just makes
32   sure no block outside of that range is modified.
33 
34 --device path_to_device
35   Performs tests over an existing stack.
36 
37 --broker
38   The device to attach to is not a nand device, but a broker.
39 
40 --first-block n
41   The fist block that can be written from an existing device.
42 
43 --num-blocks n
44   The number of blocks that can be written, after first-block.
45 
46 )""";
47 
48 const fuchsia_hardware_nand_Info kDefaultNandInfo = {.page_size = 4096,
49                                                      .pages_per_block = 4,
50                                                      .num_blocks = 5,
51                                                      .ecc_bits = 6,
52                                                      .oob_size = 4,
53                                                      .nand_class = fuchsia_hardware_nand_Class_TEST,
54                                                      .partition_guid = {}};
55 
56 // The test can operate over either a ram-nand, or a real device. The simplest
57 // way to control what's going on is to have a place outside the test framework
58 // that controls where to execute, as "creation / teardown" of the external
59 // device happens at the process level.
60 ParentDevice* g_parent_device_;
61 
main(int argc,char ** argv)62 int main(int argc, char** argv) {
63     ParentDevice::TestConfig config = {};
64     config.info = kDefaultNandInfo;
65 
66     while (true) {
67         struct option options[] = {
68             {"device", required_argument, nullptr, 'd'},
69             {"broker", no_argument, nullptr, 'b'},
70             {"first-block", required_argument, nullptr, 'f'},
71             {"num-blocks", required_argument, nullptr, 'n'},
72             {"help", no_argument, nullptr, 'h'},
73             {"list", no_argument, nullptr, 'l'},
74             {"case", required_argument, nullptr, 'c'},
75             {"test", required_argument, nullptr, 't'},
76             {nullptr, 0, nullptr, 0},
77         };
78         int opt_index;
79         int c = getopt_long(argc, argv, "d:bhlc:t:", options, &opt_index);
80         if (c < 0) {
81             break;
82         }
83         switch (c) {
84         case 'd':
85             config.path = optarg;
86             break;
87         case 'b':
88             config.is_broker = true;
89             break;
90         case 'f':
91             config.first_block = static_cast<uint32_t>(strtoul(optarg, NULL, 0));
92             break;
93         case 'n':
94             config.num_blocks = static_cast<uint32_t>(strtoul(optarg, NULL, 0));
95             break;
96         case 'h':
97             printf("%s\n", kUsageMessage);
98             break;
99         }
100     }
101 
102     if (config.first_block && !config.num_blocks) {
103         printf("num-blocks required when first-block is set\n");
104         return -1;
105     }
106 
107     ParentDevice parent(config);
108     if (!parent.IsValid()) {
109         printf("Unable to open the nand device\n");
110         return -1;
111     }
112 
113     if (config.path && !config.first_block) {
114         printf("About to overwrite device. Press y to confirm.\n");
115         int c = getchar();
116         if (c != 'y') {
117             return -1;
118         }
119     }
120 
121     g_parent_device_ = &parent;
122 
123     return unittest_run_all_tests(argc, argv) ? 0 : -1;
124 }
125