1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2021-2024 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18# This file defines the CTS test metadata format 19# The entrypoint is the 'find_all_metas' function 20 21import re 22from unittest import TestCase 23from typing import Tuple, List, Dict 24 25import yaml 26 27from runner.plugins.ets.utils.constants import META_END_PATTERN, META_END_STRING, META_START_PATTERN, META_START_STRING 28 29ParsedMeta = Dict 30MetaInText = Tuple[int, int, ParsedMeta] 31 32 33class InvalidMetaException(Exception): 34 def __init__(self, msg: str) -> None: 35 super().__init__() 36 self.message = msg 37 38 39def find_all_metas(text: str) -> List[MetaInText]: 40 """ 41 Given a text of the whole test, this function: 42 1) Find all metas in this text 43 2) Parses each meta and verifies its correctness 44 Returns a list of tuples (start: int, end: int, meta: ParsedMeta), 45 where 'start' and 'end' are indices in 'text' such that text[start:end] == "/*---" + strMeta + "---*/" 46 and 'meta' is the parsed meta 47 48 Raised: InvalidMetaException 49 """ 50 result = [] 51 52 start_indices = [m.start() for m in re.finditer(META_START_PATTERN, text)] 53 end_indices = [m.end() for m in re.finditer(META_END_PATTERN, text)] 54 55 if len(start_indices) != len(end_indices) or len(start_indices) == 0: 56 raise InvalidMetaException("Invalid meta or meta doesn't exist") 57 58 meta_bounds = list(zip(start_indices, end_indices)) 59 60 # verify meta bounds 61 for i in range(1, len(meta_bounds)): 62 prev_start, prev_end = meta_bounds[i - 1] 63 start, end = meta_bounds[i] 64 if not prev_start < prev_end < start < end: 65 raise InvalidMetaException("Invalid meta") 66 67 for start, end in meta_bounds: 68 meta = __parse_meta(text[start:end]) 69 result.append((start, end, meta)) 70 71 return result 72 73 74def __parse_meta(meta: str) -> Dict: 75 """ 76 Given a meta, a string that starts with '/*---', ends with '---*/' and contains a valid YAML in between, 77 this function parses that meta and validating it. 78 """ 79 test = TestCase() 80 test.assertTrue(len(meta) > len(META_START_STRING) + len(META_END_STRING)) 81 test.assertTrue(meta.startswith(META_START_STRING) and meta.endswith(META_END_STRING)) 82 83 yaml_string = meta[len(META_START_STRING):-len(META_END_STRING)] 84 try: 85 data = yaml.safe_load(yaml_string) 86 if isinstance(data, dict): 87 return data 88 test.assertTrue(isinstance(data, dict), "Invalid data format") 89 return {} 90 except Exception as common_exp: 91 raise InvalidMetaException(str(common_exp)) from common_exp 92