| /* |
| * |
| * Copyright (c) 2021 Project CHIP Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * This file contains code for supporting variables into the YAML tests suites. |
| */ |
| |
| // Import helpers from zap core |
| const zapPath = '../../../../../third_party/zap/repo/dist/src-electron/'; |
| const zclHelper = require(zapPath + 'generator/helper-zcl.js') |
| const templateUtil = require(zapPath + 'generator/template-util.js') |
| |
| const { getCommands, getAttributes } = require('../simulated-clusters/SimulatedClusters.js'); |
| |
| const knownVariables = { |
| 'nodeId' : { type : 'NODE_ID', defaultValue : 0x12345, isNullable : false }, |
| 'endpoint' : { type : 'ENDPOINT_NO', defaultValue : '', isNullable : false }, |
| 'cluster' : { type : 'CHAR_STRING', defaultValue : '', isNullable : false }, |
| 'timeout' : { type : 'INT16U', defaultValue : "kTimeoutInSeconds", isNullable : false }, |
| }; |
| |
| function throwError(test, errorStr) |
| { |
| console.error('Error in: ' + test.filename + '.yaml for test with label: "' + test.label + '"\n'); |
| console.error(errorStr); |
| throw new Error(); |
| } |
| |
| async function getItems(test, promise, itemName) |
| { |
| return promise.then(items => { |
| const item = items.find(item => item.name.toLowerCase() == itemName.toLowerCase()); |
| if (!item) { |
| const names = items.map(item => item.name); |
| throwError(test, 'Missing ' + itemName + '" in: \n\t* ' + names.join('\n\t* ')); |
| } |
| |
| return item; |
| }); |
| } |
| |
| async function getCommandInformationsFor(context, test, argumentName) |
| { |
| const command = await getItems(test, getCommands(context, test.cluster), test.command); |
| const argument = command.response.arguments.find(item => item.name.toLowerCase() == argumentName.toLowerCase()); |
| return { type : argument.type, chipType : argument.chipType, isNullable : argument.isNullable }; |
| } |
| |
| async function getAttributeInformationsFor(context, test, attributeName) |
| { |
| const attribute = await getItems(test, getAttributes(context, test.cluster), attributeName); |
| return { type : attribute.type, chipType : attribute.chipType, isNullable : attribute.isNullable }; |
| } |
| |
| async function extractVariablesFromConfig(context, suite) |
| { |
| let variables = []; |
| |
| // Ensure that timeout is always set in the config, to enable command-line |
| // control over it. |
| if (!("timeout" in suite.config)) { |
| // Set to the defaultValue, because below for the isKnownVariable case we will use |
| // the actual value as the default value... |
| suite.config.timeout = knownVariables.timeout.defaultValue; |
| } |
| |
| for (const key in suite.config) { |
| let value = {}; |
| |
| const isKnownVariable = key in knownVariables; |
| |
| const target = isKnownVariable ? knownVariables[key] : suite.config[key]; |
| for (const prop in target) { |
| value[prop] = target[prop]; |
| } |
| |
| if (!isKnownVariable && !('defaultValue' in target)) { |
| throw new Error(`${suite.filename}: No default value defined for config '${key}'`); |
| } |
| |
| value.defaultValue = isKnownVariable ? suite.config[key] : suite.config[key].defaultValue; |
| if (Number.isInteger(value.defaultValue) && !Number.isSafeInteger(value.defaultValue)) { |
| throw new Error(`${suite.filename}: Default value defined for config '${ |
| key}' is too large to represent exactly as an integer in YAML. Put quotes around it to treat it as a string.`); |
| } |
| value.chipType = await zclHelper.asUnderlyingZclType.call(context, value.type, { 'hash' : {} }); |
| value.name = key; |
| variables.push(value); |
| } |
| |
| return variables; |
| } |
| |
| async function extractVariablesFromTests(context, suite) |
| { |
| let variables = {}; |
| suite.tests.forEach(test => { |
| test.response.forEach(response => { |
| response.values.filter(value => value.saveAs).forEach(saveAsValue => { |
| const key = saveAsValue.saveAs; |
| if (key in variables) { |
| throwError(test, `Variable with name: ${key} is already registered.`); |
| } |
| |
| if (!test.isCommand && !test.isAttribute) { |
| throwError(test, `Variable support for step ${test} is not supported. Only commands and attributes are supported.`); |
| } |
| |
| variables[key] = { test, name : saveAsValue.name }; |
| }); |
| }); |
| }); |
| |
| const rv = []; |
| for (const [key, { test, name }] of Object.entries(variables)) { |
| let variable = await ( |
| test.isCommand ? getCommandInformationsFor(context, test, name) : getAttributeInformationsFor(context, test, name)); |
| variable.name = key; |
| rv.push(variable); |
| } |
| |
| return rv; |
| } |
| |
| async function Variables(context, suite) |
| { |
| return { |
| config : await extractVariablesFromConfig(context, suite), |
| tests : await extractVariablesFromTests(context, suite), |
| }; |
| } |
| |
| // |
| // Module exports |
| // |
| exports.Variables = Variables; |