| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of the Falcon Player (FPP) and is Copyright (C) | ||
| 3 | * 2013-2022 by the Falcon Player Developers. | ||
| 4 | * | ||
| 5 | * The Falcon Player (FPP) is free software, and is covered under | ||
| 6 | * multiple Open Source licenses. Please see the included 'LICENSES' | ||
| 7 | * file for descriptions of what files are covered by each license. | ||
| 8 | * | ||
| 9 | * This source file is covered under the LGPL v2.1 as described in the | ||
| 10 | * included LICENSE.LGPL file. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include "fpp-pch.h" | ||
| 14 | |||
| 15 | #include "fpp-json.h" | ||
| 16 | #include "fpphttp.h" // drogon/HTTP helpers used here; no longer pulled transitively (see fpphttp_types.h) | ||
| 17 | #include "fpphttp_clientip.h" // getEffectiveClientIP() - FPP-internal, not in the plugin API | ||
| 18 | |||
| 19 | #include "../common.h" | ||
| 20 | #include "../log.h" | ||
| 21 | #include <unistd.h> // usleep -- needed directly for NOPCH builds | ||
| 22 | |||
| 23 | #include "ChannelTester.h" | ||
| 24 | #include "channeloutput/ChannelOutputSetup.h" | ||
| 25 | #include "channeloutput/channeloutputthread.h" | ||
| 26 | #include "commands/Commands.h" | ||
| 27 | |||
| 28 | // Test Patterns | ||
| 29 | #include "OutputTester.h" | ||
| 30 | #include "RGBChase.h" | ||
| 31 | #include "RGBCycle.h" | ||
| 32 | #include "RGBFill.h" | ||
| 33 | #include "SingleChase.h" | ||
| 34 | |||
| 35 | ChannelTester ChannelTester::INSTANCE; | ||
| 36 | |||
| 37 | /* | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | 2346 | ChannelTester::ChannelTester() : | |
| 41 | 2346 | m_testPattern(NULL) { | |
| 42 |
1/2✓ Branch 0 taken 2346 times.
✗ Branch 1 not taken.
|
2346 | LogExcess(VB_CHANNELOUT, "ChannelTester::ChannelTester()\n"); |
| 43 | 2346 | } | |
| 44 | |||
| 45 | /* | ||
| 46 | * | ||
| 47 | */ | ||
| 48 | 916 | ChannelTester::~ChannelTester() { | |
| 49 | 916 | LogExcess(VB_CHANNELOUT, "ChannelTester::~ChannelTester()\n"); | |
| 50 | |||
| 51 | 916 | std::lock_guard<std::mutex> lock(m_testLock); | |
| 52 | |||
| 53 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 458 times.
|
916 | if (m_testPattern) { |
| 54 | ✗ | delete m_testPattern; | |
| 55 | ✗ | m_testPattern = NULL; | |
| 56 | } | ||
| 57 | 916 | } | |
| 58 | |||
| 59 | class StopTestingCommand : public Command { | ||
| 60 | public: | ||
| 61 | 1887 | StopTestingCommand() : | |
| 62 |
2/4✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
|
3774 | Command("Test Stop") { |
| 63 | 1887 | } | |
| 64 | 7468 | virtual ~StopTestingCommand() {} | |
| 65 | |||
| 66 | 119 | virtual std::unique_ptr<Result> run(const std::vector<std::string>& args) { | |
| 67 |
1/2✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
|
119 | Json::Value config; |
| 68 |
2/4✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
|
119 | config["enabled"] = 0; |
| 69 |
1/2✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
|
119 | ChannelTester::INSTANCE.SetupTest(config); |
| 70 |
1/2✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
|
238 | return std::make_unique<Result>("Stopped"); |
| 71 | 119 | } | |
| 72 | }; | ||
| 73 | class StartTestingCommand : public Command { | ||
| 74 | public: | ||
| 75 | 1887 | StartTestingCommand() : | |
| 76 |
2/4✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
|
3774 | Command("Test Start") { |
| 77 |
6/12✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1887 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1887 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1887 times.
✗ Branch 11 not taken.
|
11322 | args.push_back(CommandArg("UpdateInterval", "int", "Update Interval (ms)").setDefaultValue("1000").setRange(100, 10000)); |
| 78 |
7/14✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1887 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1887 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1887 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1887 times.
✗ Branch 13 not taken.
|
15096 | args.push_back(CommandArg("TestPattern", "subcommand", "Test Pattern").setContentListUrl("api/fppd/testing/tests/")); |
| 79 | 1887 | } | |
| 80 | 7468 | virtual ~StartTestingCommand() {} | |
| 81 | |||
| 82 | 96 | std::string mapSubMode(const std::string& m) { | |
| 83 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (m == "R-G-B-All") { |
| 84 | ✗ | return "RGBA"; | |
| 85 | } | ||
| 86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (m == "R-G-B-None") { |
| 87 | ✗ | return "RGBN"; | |
| 88 | } | ||
| 89 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (m == "R-G-B-All-None") { |
| 90 | ✗ | return "RGBAN"; | |
| 91 | } | ||
| 92 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 94 times.
|
96 | if (m == "R-G-B-W") { |
| 93 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | return "RGBW"; |
| 94 | } | ||
| 95 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (m == "R-G-B-W-All") { |
| 96 | ✗ | return "RGBWA"; | |
| 97 | } | ||
| 98 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (m == "R-G-B-W-None") { |
| 99 | ✗ | return "RGBWN"; | |
| 100 | } | ||
| 101 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (m == "R-G-B-W-All-None") { |
| 102 | ✗ | return "RGBWAN"; | |
| 103 | } | ||
| 104 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
188 | return "RGB"; |
| 105 | } | ||
| 106 | 96 | std::string mapPattern(const std::string& m) { | |
| 107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (m == "R-G-B-All") { |
| 108 | ✗ | return "FF000000FF000000FFFFFFFF"; | |
| 109 | } | ||
| 110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (m == "R-G-B-None") { |
| 111 | ✗ | return "FF000000FF000000FF000000"; | |
| 112 | } | ||
| 113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
|
96 | if (m == "R-G-B-All-None") { |
| 114 | ✗ | return "FF000000FF000000FFFFFFFF000000"; | |
| 115 | } | ||
| 116 | // RGBW patterns use 4-channel (8 hex digit) groups: R, G, B, W, All, None | ||
| 117 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 94 times.
|
96 | if (m == "R-G-B-W") { |
| 118 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | return "FF00000000FF00000000FF00000000FF"; |
| 119 | } | ||
| 120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (m == "R-G-B-W-All") { |
| 121 | ✗ | return "FF00000000FF00000000FF00000000FFFFFFFFFF"; | |
| 122 | } | ||
| 123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (m == "R-G-B-W-None") { |
| 124 | ✗ | return "FF00000000FF00000000FF00000000FF00000000"; | |
| 125 | } | ||
| 126 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
|
94 | if (m == "R-G-B-W-All-None") { |
| 127 | ✗ | return "FF00000000FF00000000FF00000000FFFFFFFFFF00000000"; | |
| 128 | } | ||
| 129 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
188 | return "FF000000FF000000FF"; |
| 130 | } | ||
| 131 | // Number of channels per pixel implied by the chase/cycle type (4 for RGBW patterns, 3 otherwise) | ||
| 132 | 96 | int mapChannelsPerNode(const std::string& m) { | |
| 133 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 94 times.
|
96 | return (m.find("W") != std::string::npos) ? 4 : 3; |
| 134 | } | ||
| 135 | |||
| 136 | 188 | virtual std::unique_ptr<Result> run(const std::vector<std::string>& args) { | |
| 137 | // printf("Run test:\n"); | ||
| 138 | // for (auto& a : args) { | ||
| 139 | // printf("%s\n", a.c_str()); | ||
| 140 | // } | ||
| 141 | // The two CommandArgs declared above are only the fixed head of this | ||
| 142 | // command's argument list; the rest come from the "subcommand" arg, | ||
| 143 | // whose shape render_GET() publishes per test pattern (a channel | ||
| 144 | // range plus at least one pattern-specific value, so four in total, | ||
| 145 | // five for "Single Channel Chase"). Nothing between here and the | ||
| 146 | // caller knows that, so an under-supplied call - "Test Start" with | ||
| 147 | // just an interval and a pattern name, as arrived from an API client - | ||
| 148 | // used to index args[3] off the end of the vector and read a | ||
| 149 | // std::string out of unrelated memory. | ||
| 150 | // | ||
| 151 | // The interval is parsed with atoi() rather than std::stoi() for the | ||
| 152 | // same reason: an empty or non-numeric value is reachable from the | ||
| 153 | // API, and stoi() throws where nothing catches it. The remaining | ||
| 154 | // std::stoi/stoul/substr reads below can still throw on a malformed | ||
| 155 | // argument value - that is a separate defect from this one. | ||
| 156 |
4/6✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 183 times.
|
188 | size_t needed = (args.size() > 1 && args[1] == "Single Channel Chase") ? 5 : 4; |
| 157 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 187 times.
|
188 | if (args.size() < needed) { |
| 158 | // Built by appending rather than as one operator+ chain: GCC 12-14 | ||
| 159 | // cannot bound std::to_string() in a chain and mis-reports the | ||
| 160 | // temporary's small-string buffer as overflowed (-Wstringop-overflow). | ||
| 161 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | std::string msg = "Test Start needs "; |
| 162 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | msg += std::to_string(needed); |
| 163 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | msg += " arguments, found "; |
| 164 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | msg += std::to_string(args.size()); |
| 165 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return std::make_unique<ErrorResult>(msg); |
| 166 | 1 | } | |
| 167 |
1/2✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
|
187 | Json::Value config; |
| 168 |
2/4✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
|
187 | config["enabled"] = 1; |
| 169 |
2/4✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
|
187 | config["cycleMS"] = atoi(args[0].c_str()); |
| 170 |
1/2✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
|
187 | std::string effect = args[1]; |
| 171 |
2/4✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
|
187 | config["colorPattern"] = ""; |
| 172 |
3/4✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 158 times.
|
187 | if (effect == "RGB Chase") { |
| 173 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
|
29 | config["mode"] = "RGBChase"; |
| 174 |
5/10✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 29 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 29 times.
✗ Branch 9 not taken.
|
49 | config["subMode"] = std::string("RGBChase-") + mapSubMode(args[3]); |
| 175 |
3/6✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
|
29 | config["colorPattern"] = mapPattern(args[3]); |
| 176 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
|
29 | config["channelsPerNode"] = mapChannelsPerNode(args[3]); |
| 177 |
3/4✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 91 times.
|
158 | } else if (effect == "RGB Cycle") { |
| 178 |
2/4✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
|
67 | config["mode"] = "RGBCycle"; |
| 179 |
5/10✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 67 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 67 times.
✗ Branch 9 not taken.
|
191 | config["subMode"] = std::string("RGBCycle-") + mapSubMode(args[3]); |
| 180 |
3/6✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 67 times.
✗ Branch 5 not taken.
|
67 | config["colorPattern"] = mapPattern(args[3]); |
| 181 |
2/4✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
|
67 | config["channelsPerNode"] = mapChannelsPerNode(args[3]); |
| 182 |
3/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 89 times.
|
91 | } else if (effect == "Custom Chase") { |
| 183 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | config["mode"] = "RGBChase"; |
| 184 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | config["subMode"] = "RGBChase-RGBCustom"; |
| 185 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | config["colorPattern"] = args[3]; |
| 186 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (args.size() > 4) { |
| 187 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | config["channelsPerNode"] = std::stoi(args[4], nullptr, 10); |
| 188 | } | ||
| 189 |
2/4✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 89 times.
|
89 | } else if (effect == "Custom Cycle") { |
| 190 | ✗ | config["mode"] = "RGBCycle"; | |
| 191 | ✗ | config["subMode"] = "RGBCycle-RGBCustom"; | |
| 192 | ✗ | config["colorPattern"] = args[3]; | |
| 193 | ✗ | if (args.size() > 4) { | |
| 194 | ✗ | config["channelsPerNode"] = std::stoi(args[4], nullptr, 10); | |
| 195 | } | ||
| 196 |
3/4✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 40 times.
|
89 | } else if (effect == "RGB Single Color") { |
| 197 |
2/4✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
|
49 | config["mode"] = "RGBFill"; |
| 198 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1 times.
|
49 | std::string hexStr = args[3].substr(1); // Remove # prefix |
| 199 | // 8 hex digits (RGBW) can exceed INT_MAX, so parse as unsigned | ||
| 200 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1 times.
|
48 | uint32_t v = (uint32_t)std::stoul(hexStr, nullptr, 16); |
| 201 | |||
| 202 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 46 times.
|
47 | if (hexStr.length() == 8) { |
| 203 | // RGBW format (8 hex digits) - 4 channels per pixel | ||
| 204 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | config["channelsPerNode"] = 4; |
| 205 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | config["color4"] = (int)(v & 0xFF); // W |
| 206 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | config["color3"] = (int)((v >> 8) & 0xFF); // B |
| 207 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | config["color2"] = (int)((v >> 16) & 0xFF); // G |
| 208 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | config["color1"] = (int)((v >> 24) & 0xFF); // R |
| 209 | } else { | ||
| 210 | // RGB format (6 hex digits) - 3 channels per pixel | ||
| 211 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | config["channelsPerNode"] = 3; |
| 212 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | config["color3"] = (int)(v & 0xFF); // B |
| 213 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | config["color2"] = (int)((v >> 8) & 0xFF); // G |
| 214 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | config["color1"] = (int)((v >> 16) & 0xFF); // R |
| 215 | } | ||
| 216 |
3/4✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 35 times.
|
88 | } else if (effect == "Single Channel Chase") { |
| 217 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | config["mode"] = "SingleChase"; |
| 218 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | int v = std::stoi(args[3], nullptr, 10); |
| 219 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | config["chaseValue"] = v; |
| 220 |
4/6✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
5 | config["chaseSize"] = std::stoi(args[4], nullptr, 10); |
| 221 |
3/4✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 32 times.
|
35 | } else if (effect == "Single Channel Fill") { |
| 222 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | config["mode"] = "RGBFill"; |
| 223 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | int v = std::stoi(args[3], nullptr, 10); |
| 224 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | config["color1"] = v; |
| 225 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | config["color2"] = v; |
| 226 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | config["color3"] = v; |
| 227 |
3/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 1 times.
|
32 | } else if (effect == "Output Specific") { |
| 228 |
2/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
31 | config["mode"] = "Outputs"; |
| 229 |
2/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
31 | config["outputs"] = args[2]; |
| 230 |
1/2✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
|
31 | int v = std::stoi(args[3], nullptr, 10); |
| 231 |
2/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
31 | config["type"] = v; |
| 232 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30 times.
|
31 | if (args.size() > 4) { |
| 233 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | config["config"] = LoadJsonFromString(args[4]); |
| 234 | } | ||
| 235 | } | ||
| 236 |
3/4✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 31 times.
|
183 | if (effect != "Output Specific") { |
| 237 |
7/10✓ Branch 0 taken 152 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 152 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
✓ Branch 7 taken 135 times.
✓ Branch 8 taken 17 times.
✓ Branch 9 taken 135 times.
|
152 | if (args[2] == "" || args[2] == "*") { |
| 238 |
3/6✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
|
17 | config["channelSet"] = "1-" + std::to_string(FPPD_MAX_CHANNELS); |
| 239 | } else { | ||
| 240 |
2/4✓ Branch 0 taken 135 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 135 times.
✗ Branch 3 not taken.
|
135 | config["channelSet"] = args[2]; |
| 241 | } | ||
| 242 | } | ||
| 243 |
2/4✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 183 times.
✗ Branch 3 not taken.
|
183 | config["channelSetType"] = "channelRange"; |
| 244 |
1/2✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
|
183 | ChannelTester::INSTANCE.SetupTest(config); |
| 245 |
1/2✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
|
183 | return std::make_unique<Result>("Started"); |
| 246 | 191 | } | |
| 247 | }; | ||
| 248 | ✗ | void ChannelTester::StopTest() { | |
| 249 | ✗ | Json::Value config; | |
| 250 | ✗ | config["enabled"] = 0; | |
| 251 | ✗ | ChannelTester::INSTANCE.SetupTest(config); | |
| 252 | ✗ | } | |
| 253 | |||
| 254 | 1887 | void ChannelTester::RegisterCommands() { | |
| 255 |
6/12✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1727 times.
✓ Branch 7 taken 160 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1727 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3934 | CommandManager::INSTANCE.addCategorizedCommand(new StartTestingCommand(), "Outputs", 1); |
| 256 |
6/12✓ Branch 0 taken 1887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1887 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1727 times.
✓ Branch 7 taken 160 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1727 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
2207 | CommandManager::INSTANCE.addCategorizedCommand(new StopTestingCommand(), "Outputs", 1); |
| 257 | 1887 | } | |
| 258 | // -------------------------------------------------------------------------- | ||
| 259 | // OpenAPI docs for the /fppd/testing/* endpoints handled below. | ||
| 260 | // -------------------------------------------------------------------------- | ||
| 261 | |||
| 262 | /** | ||
| 263 | * Get the current test-mode configuration. | ||
| 264 | * | ||
| 265 | * @route GET /api/fppd/testing | ||
| 266 | * @response 200 Object with the current test `config`. | ||
| 267 | */ | ||
| 268 | |||
| 269 | /** | ||
| 270 | * List the available test pattern names. | ||
| 271 | * | ||
| 272 | * @route GET /api/fppd/testing/tests | ||
| 273 | * @response 200 Array of test pattern names. | ||
| 274 | * ```json | ||
| 275 | * ["RGB Chase", "RGB Cycle", "Custom Chase", "Custom Cycle", "RGB Single Color", "Single Channel Chase", "Single Channel Fill", "Output Specific"] | ||
| 276 | * ``` | ||
| 277 | */ | ||
| 278 | |||
| 279 | /** | ||
| 280 | * Get the argument definitions for a specific test pattern. | ||
| 281 | * | ||
| 282 | * @route GET /api/fppd/testing/tests/{pattern} | ||
| 283 | * @response 200 Object with an `args` array describing the pattern's inputs. | ||
| 284 | * @response 400 The named test pattern does not exist. | ||
| 285 | */ | ||
| 286 | 114 | HttpResponsePtr ChannelTester::render_GET(const HttpRequestPtr& req) { | |
| 287 |
1/2✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
|
114 | Json::Value result; |
| 288 |
2/4✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
|
114 | auto parts = getPathPieces(req->path()); |
| 289 | 114 | int plen = parts.size(); | |
| 290 | // ex: /fppd/testing/tests/RGB Chase | ||
| 291 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 106 times.
|
114 | if (plen == 2) { |
| 292 |
4/8✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
|
8 | result["config"] = LoadJsonFromString(GetConfig().c_str()); |
| 293 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | result["Status"] = "OK"; |
| 294 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | result["respCode"] = 200; |
| 295 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | result["Message"] = ""; |
| 296 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 95 times.
|
106 | } else if (plen == 3) { |
| 297 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("RGB Chase"); |
| 298 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("RGB Cycle"); |
| 299 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("Custom Chase"); |
| 300 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("Custom Cycle"); |
| 301 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("RGB Single Color"); |
| 302 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("Single Channel Chase"); |
| 303 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("Single Channel Fill"); |
| 304 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | result.append("Output Specific"); |
| 305 |
2/2✓ Branch 0 taken 85 times.
✓ Branch 1 taken 10 times.
|
95 | } else if (plen == 4) { |
| 306 |
1/2✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
|
85 | std::string effect = parts[3]; |
| 307 |
3/4✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 1 times.
|
85 | if (effect != "Output Specific") { |
| 308 |
1/2✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
|
84 | Json::Value vcr; |
| 309 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | vcr["allowBlanks"] = false; |
| 310 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | vcr["contentListUrl"] = "api/models?simple=true"; |
| 311 |
1/2✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
|
84 | std::string rng = GetOutputRangesAsString(false, true); |
| 312 |
3/6✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✗ Branch 5 not taken.
|
84 | vcr["contents"].append(rng.c_str()); |
| 313 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | vcr["description"] = "Channel Range/Model"; |
| 314 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | vcr["name"] = "ChannelRange"; |
| 315 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | vcr["optional"] = false; |
| 316 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | vcr["type"] = "datalist"; |
| 317 |
2/4✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | result["args"].append(vcr); |
| 318 | 84 | } | |
| 319 |
3/4✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 82 times.
|
85 | if (effect == "RGB Chase") { |
| 320 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Json::Value v; |
| 321 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | v["description"] = "Chase Type"; |
| 322 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | v["name"] = "ChaseType"; |
| 323 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | v["optional"] = false; |
| 324 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | v["type"] = "string"; |
| 325 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B"); |
| 326 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B-W"); |
| 327 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B-All"); |
| 328 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B-W-All"); |
| 329 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B-None"); |
| 330 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B-W-None"); |
| 331 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B-All-None"); |
| 332 |
3/6✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
3 | v["contents"].append("R-G-B-W-All-None"); |
| 333 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | result["args"].append(v); |
| 334 |
3/4✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 81 times.
|
85 | } else if (effect == "RGB Cycle") { |
| 335 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v; |
| 336 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["description"] = "Cycle Type"; |
| 337 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["name"] = "CycleType"; |
| 338 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["optional"] = false; |
| 339 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["type"] = "string"; |
| 340 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B"); |
| 341 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B-W"); |
| 342 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B-All"); |
| 343 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B-W-All"); |
| 344 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B-None"); |
| 345 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B-W-None"); |
| 346 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B-All-None"); |
| 347 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | v["contents"].append("R-G-B-W-All-None"); |
| 348 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v); |
| 349 |
3/4✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 80 times.
|
82 | } else if (effect == "Custom Chase") { |
| 350 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v; |
| 351 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["description"] = "Pattern"; |
| 352 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["name"] = "Pattern"; |
| 353 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["optional"] = false; |
| 354 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["type"] = "string"; |
| 355 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["default"] = "FF000000FF000000FF"; |
| 356 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v); |
| 357 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value cpn; |
| 358 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["description"] = "Channels Per Node"; |
| 359 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["name"] = "ChannelsPerNode"; |
| 360 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["optional"] = true; |
| 361 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["type"] = "string"; |
| 362 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | cpn["contents"].append("3"); |
| 363 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | cpn["contents"].append("4"); |
| 364 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["default"] = "3"; |
| 365 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(cpn); |
| 366 |
3/4✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 79 times.
|
81 | } else if (effect == "Custom Cycle") { |
| 367 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v; |
| 368 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["description"] = "Pattern"; |
| 369 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["name"] = "Pattern"; |
| 370 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["optional"] = false; |
| 371 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["type"] = "string"; |
| 372 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["default"] = "FF000000FF000000FF"; |
| 373 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v); |
| 374 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value cpn; |
| 375 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["description"] = "Channels Per Node"; |
| 376 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["name"] = "ChannelsPerNode"; |
| 377 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["optional"] = true; |
| 378 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["type"] = "string"; |
| 379 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | cpn["contents"].append("3"); |
| 380 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | cpn["contents"].append("4"); |
| 381 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | cpn["default"] = "3"; |
| 382 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(cpn); |
| 383 |
3/4✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 78 times.
|
80 | } else if (effect == "RGB Single Color") { |
| 384 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v; |
| 385 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["description"] = "Color"; |
| 386 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["name"] = "Color"; |
| 387 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["optional"] = false; |
| 388 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["type"] = "color"; |
| 389 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["default"] = "#FFFFFF"; |
| 390 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v); |
| 391 |
3/4✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 77 times.
|
79 | } else if (effect == "Single Channel Chase") { |
| 392 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v; |
| 393 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["description"] = "Value"; |
| 394 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["name"] = "Value"; |
| 395 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["optional"] = false; |
| 396 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["type"] = "range"; |
| 397 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["default"] = "255"; |
| 398 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["min"] = 0; |
| 399 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["max"] = 255; |
| 400 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v); |
| 401 | |||
| 402 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v2; |
| 403 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v2["description"] = "Chase Size"; |
| 404 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v2["name"] = "ChaseSize"; |
| 405 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v2["optional"] = false; |
| 406 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v2["type"] = "int"; |
| 407 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v2["default"] = "2"; |
| 408 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v2["min"] = 2; |
| 409 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v2["max"] = 10; |
| 410 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v2); |
| 411 |
3/4✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 76 times.
|
78 | } else if (effect == "Single Channel Fill") { |
| 412 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v; |
| 413 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["description"] = "Value"; |
| 414 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["name"] = "Value"; |
| 415 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["optional"] = false; |
| 416 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["type"] = "range"; |
| 417 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["default"] = "255"; |
| 418 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["min"] = 0; |
| 419 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["max"] = 255; |
| 420 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v); |
| 421 |
3/4✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 75 times.
|
77 | } else if (effect == "Output Specific") { |
| 422 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value vcr; |
| 423 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vcr["allowBlanks"] = false; |
| 424 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | vcr["contents"].append("--ALL--"); |
| 425 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | for (auto& a : GetOutputTypes()) { |
| 426 | ✗ | vcr["contents"].append(a); | |
| 427 | 1 | } | |
| 428 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vcr["default"] = "--ALL--"; |
| 429 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vcr["description"] = "Output Types"; |
| 430 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vcr["name"] = "OutputTypes"; |
| 431 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vcr["optional"] = false; |
| 432 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | vcr["type"] = "string"; |
| 433 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(vcr); |
| 434 | |||
| 435 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | Json::Value v; |
| 436 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["description"] = "Test Type"; |
| 437 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["name"] = "TestType"; |
| 438 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["optional"] = false; |
| 439 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["type"] = "range"; |
| 440 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["default"] = "1"; |
| 441 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["min"] = 1; |
| 442 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | v["max"] = 99; |
| 443 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | result["args"].append(v); |
| 444 | 1 | } else { | |
| 445 |
4/8✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 75 times.
✗ Branch 7 not taken.
|
150 | return makeStringResponse("Test Pattern " + effect + " not found", 400, "text/plain"); |
| 446 | } | ||
| 447 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 75 times.
|
85 | } |
| 448 |
2/4✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
78 | std::string resultStr = SaveJsonToString(result); |
| 449 |
2/4✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
39 | return makeStringResponse(resultStr, 200, "application/json"); |
| 450 | 114 | } | |
| 451 | /** | ||
| 452 | * Activate or deactivate test mode. POST the test configuration JSON (with an | ||
| 453 | * `enabled` flag); an empty/disabled config turns test mode off. | ||
| 454 | * | ||
| 455 | * @route POST /api/fppd/testing | ||
| 456 | * @response 200 Test mode activated or deactivated. | ||
| 457 | */ | ||
| 458 | 26 | HttpResponsePtr ChannelTester::render_POST(const HttpRequestPtr& req) { | |
| 459 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | Json::Value result; |
| 460 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | std::string content = std::string{ getRequestContent(req) }; |
| 461 | // Default 200 rather than the 2000 the Debug-level JSON dumps use: this is | ||
| 462 | // the one Info-level line that could emit a multi-KB entry, and a real test | ||
| 463 | // spec is only a few hundred bytes. TruncateForLog appends the true size, | ||
| 464 | // so nothing is hidden - and the crash ring caps a line at 240 bytes anyway. | ||
| 465 |
3/6✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
26 | LogDebug(VB_COMMAND, "POST /api/fppd/testing from %s: \"%s\"\n", getEffectiveClientIP(req).c_str(), TruncateForLog(content).c_str()); |
| 466 |
5/6✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 17 times.
|
27 | if (ChannelTester::INSTANCE.SetupTest(content)) { |
| 467 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | result["Status"] = "OK"; |
| 468 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | result["respCode"] = 200; |
| 469 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | result["Message"] = "Test Mode Activated"; |
| 470 | } else { | ||
| 471 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | result["Status"] = "OK"; |
| 472 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | result["respCode"] = 200; |
| 473 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | result["Message"] = "Test Mode Deactivated"; |
| 474 | } | ||
| 475 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
50 | std::string resultStr = SaveJsonToString(result); |
| 476 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
50 | return makeStringResponse(resultStr, 200, "application/json"); |
| 477 | 27 | } | |
| 478 | /* | ||
| 479 | * | ||
| 480 | */ | ||
| 481 | 39 | int ChannelTester::SetupTest(const std::string configStr) { | |
| 482 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | LogDebug(VB_CHANNELOUT, "ChannelTester::SetupTest()\n"); |
| 483 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | LogDebug(VB_CHANNELOUT, " %s\n", configStr.c_str()); |
| 484 | |||
| 485 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | Json::Value config; |
| 486 | |||
| 487 |
4/4✓ Branch 0 taken 38 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 27 times.
|
39 | if (!LoadJsonFromString(configStr, config)) { |
| 488 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | LogErr(VB_CHANNELOUT, |
| 489 | "Error parsing Test Pattern config string: '%s'\n", | ||
| 490 | configStr.c_str()); | ||
| 491 | |||
| 492 | 11 | return 0; | |
| 493 | } | ||
| 494 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | return SetupTest(config); |
| 495 | 39 | } | |
| 496 | 329 | int ChannelTester::SetupTest(const Json::Value& config) { | |
| 497 | // The config reaches here straight from the API and the command socket, so | ||
| 498 | // it can be any shape at all. The test patterns read it with jsoncpp | ||
| 499 | // accessors, which throw on a type mismatch (a color sent as "#202020" | ||
| 500 | // rather than an int, say), and the command dispatch above has no handler | ||
| 501 | // for that, so a single malformed request used to abort fppd. | ||
| 502 | try { | ||
| 503 |
1/2✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
|
329 | return SetupTestInternal(config); |
| 504 | ✗ | } catch (const Json::Exception& e) { | |
| 505 | ✗ | LogErr(VB_CHANNELOUT, "Ignoring malformed Test Pattern config: %s\n", e.what()); | |
| 506 | // A pattern that threw part way through Init() must not be left | ||
| 507 | // behind: Testing() only checks that the pointer is set, so it would | ||
| 508 | // be handed to OverlayTestData with its channel data unallocated. | ||
| 509 | // This mirrors the cleanup the Init() failure path below does. | ||
| 510 | ✗ | std::unique_lock<std::mutex> lock(m_testLock); | |
| 511 | ✗ | if (m_testPattern) { | |
| 512 | ✗ | delete m_testPattern; | |
| 513 | ✗ | m_testPattern = nullptr; | |
| 514 | } | ||
| 515 | ✗ | return 0; | |
| 516 | ✗ | } | |
| 517 | } | ||
| 518 | |||
| 519 | 329 | int ChannelTester::SetupTestInternal(const Json::Value& config) { | |
| 520 | // unique_lock (not lock_guard) because this function unlocks and | ||
| 521 | // re-locks mid-function below while waiting for the channel output | ||
| 522 | // loop to clear test data. | ||
| 523 |
1/2✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
|
329 | std::unique_lock<std::mutex> lock(m_testLock); |
| 524 | 329 | int result = 0; | |
| 525 | |||
| 526 |
4/6✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 329 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 195 times.
✓ Branch 5 taken 134 times.
|
658 | if (JsonInt(config, "enabled")) { |
| 527 |
3/6✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 195 times.
✗ Branch 5 not taken.
|
585 | std::string patternName = JsonString(config, "mode"); |
| 528 | |||
| 529 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 191 times.
|
195 | if (m_testPattern) { |
| 530 |
3/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
|
4 | if (patternName != m_testPattern.load()->Name()) { |
| 531 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | delete m_testPattern; |
| 532 | 1 | m_testPattern = NULL; | |
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 |
2/2✓ Branch 0 taken 192 times.
✓ Branch 1 taken 3 times.
|
195 | if (!m_testPattern) { |
| 537 |
3/4✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 186 times.
|
192 | if (patternName == "SingleChase") |
| 538 |
3/8✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
6 | m_testPattern = new TestPatternSingleChase(); |
| 539 |
3/4✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 154 times.
|
186 | else if (patternName == "RGBChase") |
| 540 |
3/8✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
32 | m_testPattern = new TestPatternRGBChase(); |
| 541 |
3/4✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 99 times.
|
154 | else if (patternName == "RGBFill") |
| 542 |
3/8✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 55 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
55 | m_testPattern = new TestPatternRGBFill(); |
| 543 |
3/4✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 32 times.
|
99 | else if (patternName == "RGBCycle") |
| 544 |
3/8✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
67 | m_testPattern = new TestPatternRGBCycle(); |
| 545 |
3/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 1 times.
|
32 | else if (patternName == "Outputs") |
| 546 |
3/8✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
31 | m_testPattern = new OutputTester(); |
| 547 | } | ||
| 548 | |||
| 549 |
2/2✓ Branch 0 taken 194 times.
✓ Branch 1 taken 1 times.
|
195 | if (m_testPattern) { |
| 550 |
2/4✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 194 times.
✗ Branch 3 not taken.
|
194 | result = m_testPattern.load()->Init(config); |
| 551 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 194 times.
|
194 | if (!result) { |
| 552 | ✗ | delete m_testPattern; | |
| 553 | ✗ | m_testPattern = NULL; | |
| 554 | } | ||
| 555 | } | ||
| 556 | 195 | } else { | |
| 557 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 14 times.
|
134 | if (m_testPattern) { |
| 558 | 120 | m_testPattern.load()->DisableTest(); | |
| 559 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | lock.unlock(); |
| 560 | |||
| 561 | // Give the channel output loop time to clear test data | ||
| 562 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | usleep(150000); |
| 563 | |||
| 564 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | lock.lock(); |
| 565 | |||
| 566 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | delete m_testPattern; |
| 567 | 120 | m_testPattern = NULL; | |
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | // Matches the coverage of the original pthread_mutex_unlock() here: | ||
| 572 | // m_configStr is intentionally set outside m_testLock. | ||
| 573 |
1/2✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
|
329 | lock.unlock(); |
| 574 | |||
| 575 | { | ||
| 576 |
1/2✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
|
329 | std::lock_guard<std::mutex> cl(m_configLock); |
| 577 |
2/4✓ Branch 0 taken 329 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 329 times.
✗ Branch 3 not taken.
|
329 | m_configStr = SaveJsonToString(config); |
| 578 | 329 | } | |
| 579 | |||
| 580 | // Ask for output, as an effect or an overlay does when it starts. The | ||
| 581 | // main loop starts the output thread for a test only when it is not | ||
| 582 | // running, and a thread that has just gone idle -- after a Test Stop, say | ||
| 583 | // -- still counts as running for the 2.5 s it waits to be asked, so a | ||
| 584 | // test started then put nothing out until that wait ran out. Outside | ||
| 585 | // m_testLock: the output thread takes it every frame. | ||
| 586 |
2/2✓ Branch 0 taken 194 times.
✓ Branch 1 taken 135 times.
|
329 | if (result) { |
| 587 |
1/2✓ Branch 0 taken 194 times.
✗ Branch 1 not taken.
|
194 | StartChannelOutputThread(); |
| 588 | } | ||
| 589 | 329 | return result; | |
| 590 | 329 | } | |
| 591 | |||
| 592 | /* | ||
| 593 | * | ||
| 594 | */ | ||
| 595 | 30015 | void ChannelTester::OverlayTestData(char* channelData) { | |
| 596 |
1/2✓ Branch 0 taken 30015 times.
✗ Branch 1 not taken.
|
30015 | LogExcess(VB_CHANNELOUT, "ChannelTester::OverlayTestData()\n"); |
| 597 | |||
| 598 | // lock_guard releases the lock on every return path (including the | ||
| 599 | // early return below), matching the coverage of the previous | ||
| 600 | // pthread_mutex_lock()/unlock() pairs. | ||
| 601 |
1/2✓ Branch 0 taken 30015 times.
✗ Branch 1 not taken.
|
30015 | std::lock_guard<std::mutex> lock(m_testLock); |
| 602 | |||
| 603 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30015 times.
|
30015 | if (!m_testPattern) { |
| 604 | ✗ | return; | |
| 605 | } | ||
| 606 | |||
| 607 |
1/2✓ Branch 0 taken 30015 times.
✗ Branch 1 not taken.
|
30015 | m_testPattern.load()->OverlayTestData(channelData); |
| 608 |
1/2✓ Branch 0 taken 30015 times.
✗ Branch 1 not taken.
|
30015 | } |
| 609 | |||
| 610 | /* | ||
| 611 | * | ||
| 612 | */ | ||
| 613 | 535833 | int ChannelTester::Testing(void) { | |
| 614 | // Only whether it is set: the pattern itself is used under m_testLock. | ||
| 615 |
2/2✓ Branch 0 taken 60079 times.
✓ Branch 1 taken 475754 times.
|
535833 | return m_testPattern.load(std::memory_order_relaxed) ? 1 : 0; |
| 616 | } | ||
| 617 | |||
| 618 | /* | ||
| 619 | * | ||
| 620 | */ | ||
| 621 | 11 | std::string ChannelTester::GetConfig(void) { | |
| 622 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
|
11 | if (!m_testPattern) |
| 623 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
12 | return std::string("{ \"enabled\": 0 }"); |
| 624 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | std::lock_guard<std::mutex> cl(m_configLock); |
| 625 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | return m_configStr; |
| 626 | 5 | } | |
| 627 | |||
| 628 | 500 | Json::Value ChannelTester::GetStatusJson(void) { | |
| 629 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | Json::Value result; |
| 630 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
|
500 | if (!m_testPattern) |
| 631 | ✗ | return result; | |
| 632 | 500 | std::string cfg; | |
| 633 | { | ||
| 634 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | std::lock_guard<std::mutex> cl(m_configLock); |
| 635 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | cfg = m_configStr; |
| 636 | 500 | } | |
| 637 |
5/10✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 500 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 500 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 500 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 500 times.
|
500 | if (!LoadJsonFromString(cfg, result) || !result.isObject()) |
| 638 | ✗ | return Json::Value(); | |
| 639 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | result.removeMember("config"); |
| 640 | 500 | return result; | |
| 641 | 500 | } | |
| 642 |