1# 2# Copyright (C) 2016 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 17import logging 18import sys 19 20from vts.proto import ComponentSpecificationMessage_pb2 as CompSpecMsg 21 22 23def PyValue2PbEnum(message, pb_spec, py_value): 24 """Converts Python value to VTS VariableSecificationMessage (Enum). 25 26 Args: 27 message: VariableSpecificationMessage is the current and result 28 value message. 29 pb_spec: VariableSpecificationMessage which captures the 30 specification of a target attribute. 31 py_value: Python value provided by a test case. 32 33 Returns: 34 Converted VariableSpecificationMessage if found, None otherwise 35 """ 36 if pb_spec.name: 37 message.name = pb_spec.name 38 message.type = CompSpecMsg.TYPE_ENUM 39 # Look for the enum definition and retrieve the scalar type. 40 scalar_type = pb_spec.enum_value.scalar_type 41 if scalar_type != "": 42 # If the scalar type definition is found, set it and return. 43 setattr(message.scalar_value, scalar_type, py_value) 44 return 45 # Use default scalar_type int32_t for enum definition if the definition 46 # is not found. 47 setattr(message.scalar_value, "int32_t", py_value) 48 49 50def PyValue2PbScalar(message, pb_spec, py_value): 51 """Converts Python value to VTS VariableSecificationMessage (Scalar). 52 53 Args: 54 message: VariableSpecificationMessage is the current and result 55 value message. 56 pb_spec: VariableSpecificationMessage which captures the 57 specification of a target attribute. 58 py_value: Python value provided by a test case. 59 60 Returns: 61 Converted VariableSpecificationMessage if found, None otherwise 62 """ 63 if pb_spec.name: 64 message.name = pb_spec.name 65 message.type = CompSpecMsg.TYPE_SCALAR 66 message.scalar_type = pb_spec.scalar_type 67 setattr(message.scalar_value, pb_spec.scalar_type, py_value) 68 69 70def PyString2PbString(message, pb_spec, py_value): 71 """Converts Python string to VTS VariableSecificationMessage (String). 72 73 Args: 74 message: VariableSpecificationMessage is the current and result 75 value message. 76 pb_spec: VariableSpecificationMessage which captures the 77 specification of a target attribute. 78 py_value: Python value provided by a test case. 79 80 Returns: 81 Converted VariableSpecificationMessage if found, None otherwise 82 """ 83 if pb_spec.name: 84 message.name = pb_spec.name 85 message.type = CompSpecMsg.TYPE_STRING 86 message.string_value.message = py_value 87 message.string_value.length = len(py_value) 88 89 90def PyList2PbVector(message, pb_spec, py_value): 91 """Converts Python list value to VTS VariableSecificationMessage (Vector). 92 93 Args: 94 message: VariableSpecificationMessage is the current and result 95 value message. 96 pb_spec: VariableSpecificationMessage which captures the 97 specification of a target attribute. 98 py_value: Python value provided by a test case. 99 100 Returns: 101 Converted VariableSpecificationMessage if found, None otherwise 102 """ 103 if pb_spec.name: 104 message.name = pb_spec.name 105 message.type = CompSpecMsg.TYPE_VECTOR 106 if len(py_value) == 0: 107 return message 108 109 vector_spec = pb_spec.vector_value[0] 110 for curr_value in py_value: 111 new_vector_message = message.vector_value.add() 112 new_vector_message.CopyFrom(Convert(vector_spec, curr_value)) 113 message.vector_size = len(py_value) 114 return message 115 116 117def FindSubStructType(pb_spec, sub_struct_name): 118 """Finds a specific sub_struct type. 119 120 Args: 121 pb_spec: VariableSpecificationMessage which captures the 122 specification of a target attribute. 123 sub_struct_name: string, the name of a sub struct to look up. 124 125 Returns: 126 VariableSpecificationMessage if found or None otherwise. 127 """ 128 for sub_struct in pb_spec.sub_struct: 129 if sub_struct.name == sub_struct_name: 130 return sub_struct 131 return None 132 133 134def FindSubUnionType(pb_spec, sub_union_name): 135 """Finds a specific sub_union type. 136 137 Args: 138 pb_spec: VariableSpecificationMessage which captures the 139 specification of a target attribute. 140 sub_union_name: string, the name of a sub union to look up. 141 142 Returns: 143 VariableSpecificationMessage if found or None otherwise. 144 """ 145 for sub_union in pb_spec.sub_union: 146 if sub_union.name == sub_union_name: 147 return sub_union 148 return None 149 150 151def PyDict2PbStruct(message, pb_spec, py_value): 152 """Converts Python dict to VTS VariableSecificationMessage (struct). 153 154 Args: 155 pb_spec: VariableSpecificationMessage which captures the 156 specification of a target attribute. 157 py_value: A dictionary that represents a struct. 158 159 Returns: 160 Converted VariableSpecificationMessage if found, None otherwise 161 """ 162 if pb_spec.name: 163 message.name = pb_spec.name 164 message.type = CompSpecMsg.TYPE_STRUCT 165 provided_attrs = set(py_value.keys()) 166 for attr in pb_spec.struct_value: 167 if attr.name in py_value: 168 provided_attrs.remove(attr.name) 169 curr_value = py_value[attr.name] 170 attr_msg = message.struct_value.add() 171 if attr.type == CompSpecMsg.TYPE_ENUM: 172 PyValue2PbEnum(attr_msg, attr, curr_value) 173 elif attr.type == CompSpecMsg.TYPE_SCALAR: 174 PyValue2PbScalar(attr_msg, attr, curr_value) 175 elif attr.type == CompSpecMsg.TYPE_STRING: 176 PyString2PbString(attr_msg, attr, curr_value) 177 elif attr.type == CompSpecMsg.TYPE_VECTOR: 178 PyList2PbVector(attr_msg, attr, curr_value) 179 elif attr.type == CompSpecMsg.TYPE_STRUCT: 180 sub_attr = FindSubStructType(pb_spec, attr.predefined_type) 181 if sub_attr: 182 PyDict2PbStruct(attr_msg, sub_attr, curr_value) 183 else: 184 logging.error("PyDict2PbStruct: substruct not found.") 185 return None 186 elif attr.type == CompSpecMsg.TYPE_UNION: 187 sub_attr = FindSubStructType(pb_spec, attr.predefined_type) 188 if sub_attr: 189 PyDict2PbUnion(attr_msg, sub_attr, curr_value) 190 else: 191 logging.error("PyDict2PbStruct: subunion not found.") 192 return None 193 else: 194 logging.error("PyDict2PbStruct: unsupported type %s", 195 attr.type) 196 return None 197 else: 198 # TODO: instead crash the test, consider to generate default value 199 # in case not provided in the py_value. 200 logging.error("PyDict2PbStruct: attr %s not provided", attr.name) 201 return None 202 if len(provided_attrs) > 0: 203 logging.error("PyDict2PbStruct: provided dictionary included elements" + 204 " not part of the type being converted to: %s", 205 provided_attrs) 206 return None 207 return message 208 209 210def PyDict2PbUnion(message, pb_spec, py_value): 211 """Converts Python dict to VTS VariableSecificationMessage (union). 212 213 Args: 214 pb_spec: VariableSpecificationMessage which captures the 215 specification of a target attribute. 216 py_value: A dictionary that represents a struct. 217 218 Returns: 219 Converted VariableSpecificationMessage if found, None otherwise 220 """ 221 if len(py_value) > 1: 222 logging.error("PyDict2PbUnion: Union only allows specifying " + 223 "at most one field. Current Python dictionary " + 224 "has size %d", len(py_value)) 225 return None 226 227 if pb_spec.name: 228 message.name = pb_spec.name 229 message.type = CompSpecMsg.TYPE_UNION 230 provided_attrs = set(py_value.keys()) 231 for attr in pb_spec.union_value: 232 # Since it is a union type, we stop after finding one field name 233 # that matches, and shouldn't throw an error when name is not found. 234 if attr.name in py_value: 235 provided_attrs.remove(attr.name) 236 curr_value = py_value[attr.name] 237 attr_msg = message.union_value.add() 238 if attr.type == CompSpecMsg.TYPE_ENUM: 239 PyValue2PbEnum(attr_msg, attr, curr_value) 240 elif attr.type == CompSpecMsg.TYPE_SCALAR: 241 PyValue2PbScalar(attr_msg, attr, curr_value) 242 elif attr.type == CompSpecMsg.TYPE_STRING: 243 PyString2PbString(attr_msg, attr, curr_value) 244 elif attr.type == CompSpecMsg.TYPE_VECTOR: 245 PyList2PbVector(attr_msg, attr, curr_value) 246 elif attr.type == CompSpecMsg.TYPE_STRUCT: 247 # TODO: is a nested struct in union stored in sub_union field. 248 sub_attr = FindSubUnionType(pb_spec, attr.predefined_type) 249 if sub_attr: 250 PyDict2PbStruct(attr_msg, sub_attr, curr_value) 251 else: 252 logging.error("PyDict2PbStruct: substruct not found.") 253 return None 254 elif attr.type == CompSpecMsg.TYPE_UNION: 255 sub_attr = FindSubUnionType(pb_spec, attr.predefined_type) 256 if sub_attr: 257 PyDict2PbUnion(attr_msg, sub_attr, curr_value) 258 else: 259 logging.error("PyDict2PbUnion: subunion not found.") 260 return None 261 else: 262 logging.error("PyDict2PbStruct: unsupported type %s", 263 attr.type) 264 return None 265 else: 266 # Add a field, where name field is initialized as an empty string. 267 # In generated driver implementation, driver knows this field is 268 # not used, and skip reading it. 269 message.union_value.add() 270 271 if len(provided_attrs) > 0: 272 logging.error("PyDict2PbUnion: specified field is not in the union " + 273 "definition for union type %s", provided_attrs) 274 return None 275 return message 276 277 278def Convert(pb_spec, py_value): 279 """Converts Python native data structure to VTS VariableSecificationMessage. 280 281 Args: 282 pb_spec: VariableSpecificationMessage which captures the 283 specification of a target attribute. 284 py_value: Python value provided by a test case. 285 286 Returns: 287 Converted VariableSpecificationMessage if found, None otherwise 288 """ 289 if not pb_spec: 290 logging.error("py2pb.Convert: ProtoBuf spec is None", pb_spec) 291 return None 292 293 message = CompSpecMsg.VariableSpecificationMessage() 294 message.name = pb_spec.name 295 296 if isinstance(py_value, CompSpecMsg.VariableSpecificationMessage): 297 message.CopyFrom(py_value) 298 elif pb_spec.type == CompSpecMsg.TYPE_STRUCT: 299 PyDict2PbStruct(message, pb_spec, py_value) 300 elif pb_spec.type == CompSpecMsg.TYPE_UNION: 301 PyDict2PbUnion(message, pb_spec, py_value) 302 elif pb_spec.type == CompSpecMsg.TYPE_ENUM: 303 PyValue2PbEnum(message, pb_spec, py_value) 304 elif pb_spec.type == CompSpecMsg.TYPE_SCALAR: 305 PyValue2PbScalar(message, pb_spec, py_value) 306 elif pb_spec.type == CompSpecMsg.TYPE_STRING: 307 PyString2PbString(message, pb_spec, py_value) 308 elif pb_spec.type == CompSpecMsg.TYPE_VECTOR: 309 PyList2PbVector(message, pb_spec, py_value) 310 else: 311 logging.error("py2pb.Convert: unsupported type %s", 312 pb_spec.type) 313 return None 314 315 return message 316