• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.tradefed.result.resultdb;
17 
18 import java.nio.charset.StandardCharsets;
19 
20 /** Utility class for ResultDB reporter. */
21 public final class ResultDBUtil {
22 
23     /** Converts a byte array to a hexadecimal string. */
bytesToHex(byte[] bytes)24     public static String bytesToHex(byte[] bytes) {
25         StringBuilder sb = new StringBuilder();
26         for (byte b : bytes) {
27             sb.append(String.format("%02x", b));
28         }
29         return sb.toString();
30     }
31 
32     /**
33      * Truncates the string to the given max bytes, avoiding breaking up a multi-byte character.
34      *
35      * @param input the string to truncate
36      * @param maxBytes the maximum number of bytes (in utf-8 encoding) to truncate to
37      * @return the truncated string
38      */
truncateString(String input, int maxBytes)39     public static String truncateString(String input, int maxBytes) {
40         byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
41         if (bytes.length <= maxBytes) {
42             return input;
43         }
44 
45         int byteCount = 0;
46         StringBuilder result = new StringBuilder();
47 
48         for (int i = 0; i < input.length(); ) {
49             int codePoint = input.codePointAt(i);
50             byte[] codePointBytes =
51                     new String(Character.toChars(codePoint)).getBytes(StandardCharsets.UTF_8);
52 
53             if (byteCount + codePointBytes.length <= maxBytes) {
54                 result.append(Character.toChars(codePoint));
55                 byteCount += codePointBytes.length;
56                 i += Character.charCount(codePoint); // Move to the next code point
57             } else {
58                 break;
59             }
60         }
61         return result.toString();
62     }
63 
64     /**
65      * Ensure the key is valid for ResultDB.
66      *
67      * <p>The key must match the regex: ^[a-z][a-z0-9_]*(/[a-z][a-z0-9_]*)*$
68      */
makeValidKey(String key)69     public static String makeValidKey(String key) {
70         if (key == null || key.isEmpty()) {
71             return "empty_key";
72         }
73 
74         StringBuilder validKeyBuilder = new StringBuilder();
75         for (char c : key.toCharArray()) {
76             if (c >= 'a' && c <= 'z') {
77                 validKeyBuilder.append(c);
78             } else if (c >= '0' && c <= '9') {
79                 validKeyBuilder.append(c);
80             } else if (c >= 'A' && c <= 'Z') {
81                 validKeyBuilder.append((char) (c - 'A' + 'a'));
82             } else {
83                 validKeyBuilder.append('_');
84             }
85         }
86         String validKey = validKeyBuilder.toString();
87         if (!validKey.isEmpty() && validKey.charAt(0) >= '0' && validKey.charAt(0) <= '9') {
88             validKey = "num_" + validKey;
89         }
90         return validKey;
91     }
92 }
93