PR changed-lines coverage: 41.38% (132/319, 0 noise lines excluded) Uncovered changed code (with context): ================================================================================ programs/disks/DisksApp.cpp ================================================================================ --- uncovered block 273-278 --- 271 | .ignore_shell_suspend = false, 272 | .extenders = query_extenders, >> 273 | .delimiters = query_delimiters, >> 274 | .word_break_characters = word_break_characters, >> 275 | .highlighter = {}, >> 276 | }; >> 277 | ReplxxLineReader lr(std::move(reader_options)); >> 278 | lr.enableBracketedPaste(); 279 | 280 | while (true) ================================================================================ programs/keeper-client/KeeperClient.cpp ================================================================================ --- uncovered block 40-80 --- 38 | /// /'it\'s'/d → /it's/d (escaped quote inside single quotes) 39 | String unescapePath(const String & s) >> 40 | { >> 41 | String result; >> 42 | result.reserve(s.size()); >> 43 | char in_quote = 0; >> 44 | for (size_t i = 0; i < s.size(); ++i) >> 45 | { >> 46 | char c = s[i]; >> 47 | if (in_quote) >> 48 | { >> 49 | if (c == '\\' && i + 1 < s.size() >> 50 | && (s[i + 1] == in_quote || s[i + 1] == '\\')) >> 51 | { >> 52 | result += s[i + 1]; >> 53 | ++i; >> 54 | } >> 55 | else if (c == in_quote) >> 56 | { >> 57 | in_quote = 0; >> 58 | } >> 59 | else >> 60 | { >> 61 | result += c; >> 62 | } >> 63 | } >> 64 | else if (c == '\'' || c == '"') >> 65 | { >> 66 | in_quote = c; >> 67 | } >> 68 | else if (c == '\\' && i + 1 < s.size() >> 69 | && (s[i + 1] == ' ' || s[i + 1] == '\\')) >> 70 | { >> 71 | result += s[i + 1]; >> 72 | ++i; >> 73 | } >> 74 | else >> 75 | { >> 76 | result += c; >> 77 | } >> 78 | } >> 79 | return result; >> 80 | } 81 | 82 | } --- uncovered block 119-119 --- 117 | /// For example, if the user typed "ls /foo/b" and pressed Tab, prefix = "ls /foo/b". 118 | std::vector KeeperClient::getCompletions(const String & prefix) const >> 119 | { 120 | /// Determine whether we are completing a command name or a path argument 121 | /// by looking for the first whitespace (end of command word). --- uncovered block 122-123 --- 120 | /// Determine whether we are completing a command name or a path argument 121 | /// by looking for the first whitespace (end of command word). >> 122 | std::string_view word_breaks(WORD_BREAK_CHARACTERS); >> 123 | auto cmd_end = prefix.find_first_of(word_breaks); 124 | 125 | /// No whitespace → still typing the command name. --- uncovered block 126-127 --- 124 | 125 | /// No whitespace → still typing the command name. >> 126 | if (cmd_end == String::npos || cmd_end == 0) >> 127 | return registered_commands_and_four_letter_words; 128 | 129 | /// Find where the path argument starts (first non-whitespace char after command). --- uncovered block 130-132 --- 128 | 129 | /// Find where the path argument starts (first non-whitespace char after command). >> 130 | auto path_start = prefix.find_first_not_of(word_breaks, cmd_end); >> 131 | if (path_start == String::npos) >> 132 | path_start = prefix.size(); 133 | 134 | /// Detect quoted mode by scanning forward from the arguments, tracking --- uncovered block 140-148 --- 138 | /// 139 | /// arg_start tracks the last unescaped word break (argument boundary). >> 140 | char quote_char = 0; >> 141 | size_t arg_start = path_start; >> 142 | for (size_t i = path_start; i < prefix.size(); ++i) >> 143 | { >> 144 | char c = prefix[i]; >> 145 | if (quote_char) >> 146 | { >> 147 | if (c == quote_char) >> 148 | { 149 | /// Check if this quote is escaped by an odd number of preceding backslashes. 150 | /// e.g. \" is escaped (stays in quoted mode), \\" is not (closes the quote). --- uncovered block 151-153 --- 149 | /// Check if this quote is escaped by an odd number of preceding backslashes. 150 | /// e.g. \" is escaped (stays in quoted mode), \\" is not (closes the quote). >> 151 | size_t backslashes = 0; >> 152 | while (backslashes < (i - path_start) && prefix[i - 1 - backslashes] == '\\') >> 153 | ++backslashes; 154 | 155 | if (backslashes % 2 == 0) --- uncovered block 155-161 --- 153 | ++backslashes; 154 | >> 155 | if (backslashes % 2 == 0) >> 156 | quote_char = 0; /// closing quote >> 157 | } >> 158 | } >> 159 | else if (c == '\'' || c == '"') >> 160 | { >> 161 | quote_char = c; 162 | /// Just track that we're inside a quote; arg_start stays at the word break. 163 | } --- uncovered block 163-165 --- 161 | quote_char = c; 162 | /// Just track that we're inside a quote; arg_start stays at the word break. >> 163 | } >> 164 | else if (word_breaks.contains(c)) >> 165 | { 166 | /// Count consecutive backslashes before this character. 167 | /// Odd count means this space is escaped (e.g. `\ `); --- uncovered block 170-172 --- 168 | /// even count means the backslash itself is escaped (e.g. `\\ `) 169 | /// and the space is a genuine word break. >> 170 | size_t backslashes = 0; >> 171 | while (backslashes < (i - path_start) && prefix[i - 1 - backslashes] == '\\') >> 172 | ++backslashes; 173 | 174 | if (backslashes % 2 == 0) --- uncovered block 174-175 --- 172 | ++backslashes; 173 | >> 174 | if (backslashes % 2 == 0) >> 175 | { 176 | /// Unescaped word break — next argument starts after this. 177 | arg_start = i + 1; --- uncovered block 177-180 --- 175 | { 176 | /// Unescaped word break — next argument starts after this. >> 177 | arg_start = i + 1; >> 178 | } >> 179 | } >> 180 | } 181 | 182 | /// Full argument text from arg_start, used for splitting at the last '/'. --- uncovered block 185-185 --- 183 | /// This includes any bare prefix before an opening quote (e.g. "/path/" in 184 | /// "/path/'child"), so parent path resolution sees the complete path. >> 185 | String full_arg = prefix.substr(arg_start); 186 | 187 | /// Compute the offset of replxx's "last_word" within full_completion. --- uncovered block 192-194 --- 190 | /// is '"foo b'. We compute last_word_offset so that our completions return 191 | /// only the suffix that replxx expects to match against last_word. >> 192 | auto last_word_pos = prefix.find_last_of(word_breaks); >> 193 | size_t last_word_start = (last_word_pos == String::npos) ? 0 : last_word_pos + 1; >> 194 | size_t last_word_offset = (last_word_start <= arg_start) ? 0 : (last_word_start - arg_start); 195 | 196 | /// Split the full argument at the last '/' into parent and child portions. --- uncovered block 197-208 --- 195 | 196 | /// Split the full argument at the last '/' into parent and child portions. >> 197 | auto last_slash = full_arg.rfind('/'); >> 198 | String typed_parent_str; >> 199 | String typed_child_str; >> 200 | if (last_slash != String::npos) >> 201 | { >> 202 | typed_parent_str = full_arg.substr(0, last_slash + 1); >> 203 | typed_child_str = full_arg.substr(last_slash + 1); >> 204 | } >> 205 | else >> 206 | { >> 207 | typed_child_str = full_arg; >> 208 | } 209 | 210 | /// Unescape using unescapePath which handles both bare escaping (\ ) and --- uncovered block 212-213 --- 210 | /// Unescape using unescapePath which handles both bare escaping (\ ) and 211 | /// inline quoted segments (/'dir"name'/) in a single pass. >> 212 | String unescaped_parent = unescapePath(typed_parent_str); >> 213 | String unescaped_child_prefix = unescapePath(typed_child_str); 214 | 215 | String parent_path; --- uncovered block 215-219 --- 213 | String unescaped_child_prefix = unescapePath(typed_child_str); 214 | >> 215 | String parent_path; >> 216 | if (unescaped_parent.empty()) >> 217 | parent_path = cwd; >> 218 | else >> 219 | parent_path = getAbsolutePath(unescaped_parent); 220 | 221 | Strings children; --- uncovered block 221-222 --- 219 | parent_path = getAbsolutePath(unescaped_parent); 220 | >> 221 | Strings children; >> 222 | try 223 | { 224 | children = zookeeper->getChildren(parent_path); --- uncovered block 225-226 --- 223 | { 224 | children = zookeeper->getChildren(parent_path); >> 225 | } >> 226 | catch (Coordination::Exception &) {} // NOLINT(bugprone-empty-catch) 227 | 228 | std::vector result; --- uncovered block 228-228 --- 226 | catch (Coordination::Exception &) {} // NOLINT(bugprone-empty-catch) 227 | >> 228 | std::vector result; 229 | 230 | for (const auto & child : children) --- uncovered block 230-234 --- 228 | std::vector result; 229 | >> 230 | for (const auto & child : children) >> 231 | { >> 232 | if (!unescaped_child_prefix.empty() >> 233 | && !child.starts_with(unescaped_child_prefix)) >> 234 | continue; 235 | 236 | /// Build the full completion text for this child. --- uncovered block 243-245 --- 241 | /// In unquoted mode: use formatKeeperNodeName which returns bare or single-quoted 242 | /// form — always round-trippable through the parser. >> 243 | String full_completion; >> 244 | if (quote_char) >> 245 | { 246 | /// If the opening quote landed after the last '/', it's in the child 247 | /// portion and needs to be re-added. Otherwise it's already in typed_parent_str. --- uncovered block 248-251 --- 246 | /// If the opening quote landed after the last '/', it's in the child 247 | /// portion and needs to be re-added. Otherwise it's already in typed_parent_str. >> 248 | bool quote_in_child = !typed_child_str.empty() && typed_child_str[0] == quote_char; >> 249 | full_completion = typed_parent_str; >> 250 | if (quote_in_child) >> 251 | full_completion += quote_char; 252 | 253 | /// Escape the child name for the active quoting context: the active --- uncovered block 256-264 --- 254 | /// quote character and backslashes must be backslash-escaped so the 255 | /// completion round-trips through parseIdentifierOrStringLiteral. >> 256 | for (char c : child) >> 257 | { >> 258 | if (c == quote_char || c == '\\') >> 259 | full_completion += '\\'; >> 260 | full_completion += c; >> 261 | } >> 262 | } >> 263 | else >> 264 | full_completion = typed_parent_str + formatKeeperNodeName(child); 265 | 266 | /// Check if this node has children to decide the suffix: --- uncovered block 269-272 --- 267 | /// - has children → append '/' so the user can Tab-complete the next segment 268 | /// - leaf node → in quoted mode append closing quote, otherwise no suffix >> 269 | String full_path = parent_path; >> 270 | if (!full_path.ends_with('/')) >> 271 | full_path += '/'; >> 272 | full_path += child; 273 | 274 | bool has_children = false; --- uncovered block 274-276 --- 272 | full_path += child; 273 | >> 274 | bool has_children = false; >> 275 | try >> 276 | { 277 | Strings sub = zookeeper->getChildren(full_path); 278 | has_children = !sub.empty(); --- uncovered block 280-280 --- 278 | has_children = !sub.empty(); 279 | } >> 280 | catch (Coordination::Exception &) {} // NOLINT(bugprone-empty-catch) 281 | 282 | if (has_children) --- uncovered block 282-285 --- 280 | catch (Coordination::Exception &) {} // NOLINT(bugprone-empty-catch) 281 | >> 282 | if (has_children) >> 283 | full_completion += '/'; >> 284 | else if (quote_char) >> 285 | full_completion += quote_char; 286 | 287 | /// The completion text is the suffix starting from where replxx's --- uncovered block 289-290 --- 287 | /// The completion text is the suffix starting from where replxx's 288 | /// last_word begins, so that prefix matching works. >> 289 | if (last_word_offset > full_completion.size()) >> 290 | continue; 291 | 292 | String completion = full_completion.substr(last_word_offset); --- uncovered block 292-294 --- 290 | continue; 291 | >> 292 | String completion = full_completion.substr(last_word_offset); >> 293 | result.push_back(std::move(completion)); >> 294 | } 295 | 296 | std::sort(result.begin(), result.end()); --- uncovered block 296-298 --- 294 | } 295 | >> 296 | std::sort(result.begin(), result.end()); >> 297 | return result; >> 298 | } 299 | 300 | --- uncovered block 464-465 --- 462 | if (text.size() == 1 && (text == "y" || text == "Y")) 463 | confirmation_callback(); >> 464 | return true; >> 465 | } 466 | 467 | const char * begin = text.data(); --- uncovered block 484-484 --- 482 | 483 | if (pos->isEnd()) >> 484 | break; 485 | 486 | KeeperParser parser; --- uncovered block 492-495 --- 490 | 491 | if (!parsed || !res) >> 492 | { >> 493 | std::cerr << "Syntax error at position " << (pos->begin - begin) << "\n"; >> 494 | return true; >> 495 | } 496 | 497 | /// Skip trailing whitespace after the parsed command. --- uncovered block 499-499 --- 497 | /// Skip trailing whitespace after the parsed command. 498 | while (!pos->isEnd() && pos->type == TokenType::Whitespace) >> 499 | ++pos; 500 | 501 | /// After a command, the next token must be a semicolon (statement --- uncovered block 555-560 --- 553 | .ignore_shell_suspend = false, 554 | .extenders = query_extenders, >> 555 | .delimiters = query_delimiters, >> 556 | .word_break_characters = WORD_BREAK_CHARACTERS, >> 557 | .highlighter = {}, >> 558 | }; >> 559 | ReplxxLineReader lr(std::move(reader_options)); >> 560 | lr.enableBracketedPaste(); 561 | 562 | while (true) ================================================================================ src/Common/ZooKeeper/KeeperClientCLI/KeeperClient.cpp ================================================================================ --- uncovered block 74-75 --- 72 | 73 | String KeeperClientBase::executeFourLetterCommand(const String & /* command */) >> 74 | { >> 75 | throw Exception(ErrorCodes::NOT_IMPLEMENTED, "4lwc is not implemented"); 76 | } 77 | ================================================================================ src/Common/ZooKeeper/KeeperClientCLI/Parser.cpp ================================================================================ --- uncovered block 31-31 --- 29 | /// by the tokenizer (skip_insignificant mode). Treat as argument boundary. 30 | if (pos->begin > last_end) >> 31 | break; 32 | 33 | /// Quoted segment: parse it inline and append the unquoted content. --- uncovered block 39-39 --- 37 | String segment; 38 | if (!parseIdentifierOrStringLiteral(pos, expected, segment)) >> 39 | break; 40 | result += segment; 41 | last_end = token_end; --- uncovered block 54-57 --- 52 | 53 | if (pos->isEnd()) >> 54 | { >> 55 | result += '\\'; >> 56 | break; >> 57 | } 58 | 59 | /// Explicit whitespace token (skip_insignificant=false) → escaped space. --- uncovered block 77-83 --- 75 | /// space). A larger gap means `\ ...` — one escaped space then a word break. 76 | if (pos->begin > bs_end) >> 77 | { >> 78 | result += ' '; >> 79 | if (pos->begin - bs_end > 1) >> 80 | break; >> 81 | last_end = pos->begin; >> 82 | continue; >> 83 | } 84 | 85 | /// \\ → literal backslash --- uncovered block 97-99 --- 95 | 96 | /// \ → keep backslash as-is >> 97 | result += '\\'; >> 98 | last_end = bs_end; >> 99 | continue; 100 | } 101 | WARNING: Failed to get start time for [Print Uncovered Code] - start time and duration won't be set