blob: 3082083da119366e859ab084431236bc43926de2 [file] [log] [blame]
/**
*
* Copyright (c) 2020 Silicon Labs
*
* 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.
*
*
* @jest-environment node
*/
const fs = require('fs')
const dbApi = require('../src-electron/db/db-api')
const zclLoader = require('../src-electron/zcl/zcl-loader')
const validation = require('../src-electron/validation/validation')
const querySession = require('../src-electron/db/query-session')
const queryConfig = require('../src-electron/db/query-config')
const queryEndpoint = require('../src-electron/db/query-endpoint')
const queryEndpointType = require('../src-electron/db/query-endpoint-type')
const queryZcl = require('../src-electron/db/query-zcl')
const queryDeviceType = require('../src-electron/db/query-device-type')
const testQuery = require('./test-query')
const env = require('../src-electron/util/env')
const types = require('../src-electron/util/types')
const { timeout } = require('./test-util')
let db
let sid
let pkgId
beforeAll(() => {
env.setDevelopmentEnv()
let file = env.sqliteTestFile('validation')
return dbApi
.initDatabaseAndLoadSchema(file, env.schemaFile(), env.zapVersion())
.then((d) => {
db = d
})
}, timeout.medium())
afterAll(() => dbApi.closeDatabase(db), timeout.short())
test(
'Load the static data.',
async () => {
let context = await zclLoader.loadZcl(db, env.builtinSilabsZclMetafile())
pkgId = context.packageId
sid = await testQuery.createSession(
db,
'USER',
'SESSION',
env.builtinSilabsZclMetafile(),
env.builtinTemplateMetafile()
)
},
timeout.medium()
)
test(
'isValidNumberString Functions',
() => {
// Integer
expect(validation.isValidNumberString('5')).toBeTruthy()
expect(validation.isValidNumberString('-5')).toBeTruthy()
expect(validation.isValidNumberString('5.6')).toBeFalsy()
expect(validation.isValidNumberString('-5.6')).toBeFalsy()
expect(validation.isValidNumberString('.0001')).toBeFalsy()
expect(validation.isValidNumberString('-.0001')).toBeFalsy()
expect(validation.isValidNumberString('0x0000')).toBeTruthy()
expect(validation.isValidNumberString('0x0001')).toBeTruthy()
expect(validation.isValidNumberString('0x000G')).toBeFalsy()
// Float
expect(validation.isValidFloat('5')).toBeTruthy()
expect(validation.isValidFloat('-5')).toBeTruthy()
expect(validation.isValidFloat('5.6')).toBeTruthy()
expect(validation.isValidFloat('-5.6')).toBeTruthy()
expect(validation.isValidFloat('.0001')).toBeTruthy()
expect(validation.isValidFloat('-.0001')).toBeTruthy()
expect(validation.isValidFloat('0x0000')).toBeFalsy()
expect(validation.isValidFloat('0x0001')).toBeFalsy()
expect(validation.isValidFloat('0x000G')).toBeFalsy()
expect(validation.isValidFloat('5.6....')).toBeFalsy()
},
timeout.medium()
)
test(
'extractValue Functions',
() => {
//Integer
expect(validation.extractIntegerValue('5') == 5).toBeTruthy()
expect(validation.extractIntegerValue('0x05') == 5).toBeTruthy()
expect(validation.extractIntegerValue('A') == 10).toBeTruthy()
//float
expect(validation.extractFloatValue('0.53') == 0.53).toBeTruthy()
expect(validation.extractFloatValue('.53') == 0.53).toBeTruthy()
// big
expect(
validation.extractBigIntegerValue('0x7FFFFFFFFFFFFF') ==
36028797018963967n
).toBeTruthy()
},
timeout.medium()
)
test('getIntegerFromAttribute function', () => {
//Decimal over hex
//expect(validation.getIntegerFromAttribute(''))
//Convert hex
})
test('Test hex unsigned to signed conversion', () => {
// testing the available bit representation extreme values
//8 bits
expect(validation.unsignedToSignedInteger(0x80, 8) == -128).toBeTruthy()
expect(validation.unsignedToSignedInteger(0x7f, 8) == 127).toBeTruthy()
// 16 bits
expect(validation.unsignedToSignedInteger(0x8000, 16) == -32768).toBeTruthy()
expect(validation.unsignedToSignedInteger(0x7fff, 16) == 32767).toBeTruthy()
// 24 bits
expect(
validation.unsignedToSignedInteger(0x800000, 24) == -8388608
).toBeTruthy()
expect(
validation.unsignedToSignedInteger(0x7fffff, 24) == 8388607
).toBeTruthy()
// 32 bits
expect(
validation.unsignedToSignedInteger(0x80000000n, 32) == -2147483648n
).toBeTruthy()
expect(
validation.unsignedToSignedInteger(0x7fffffffn, 32) == 2147483647n
).toBeTruthy()
// 40 bits
expect(
validation.unsignedToSignedInteger(0x8000000000n, 40) == -549755813888n
).toBeTruthy()
expect(
validation.unsignedToSignedInteger(0x7fffffffffn, 40) == 549755813887n
).toBeTruthy()
// 48 bits
expect(
validation.unsignedToSignedInteger(0x800000000000n, 48) == -140737488355328n
).toBeTruthy()
expect(
validation.unsignedToSignedInteger(0x7fffffffffffn, 48) == 140737488355327n
).toBeTruthy()
// 54 bits
expect(
validation.unsignedToSignedInteger(0x80000000000000n, 56) ==
-36028797018963968n
).toBeTruthy()
expect(
validation.unsignedToSignedInteger(0x7fffffffffffffn, 56) ==
36028797018963967n
).toBeTruthy()
// 64 bits
expect(
validation.unsignedToSignedInteger(0x8000000000000000n, 64) ==
-9223372036854775808n
).toBeTruthy()
expect(
validation.unsignedToSignedInteger(0x7fffffffffffffffn, 64) ==
9223372036854775807n
).toBeTruthy()
})
test(
'Test int bounds',
() => {
//Integer
expect(validation.checkBoundsInteger(50, 25, 60)).toBeTruthy()
expect(!validation.checkBoundsInteger(50, 25, 20)).toBeTruthy()
expect(!validation.checkBoundsInteger(50, 51, 55)).toBeTruthy()
expect(!validation.checkBoundsInteger(30, 'avaa', 2)).toBeTruthy()
expect(!validation.checkBoundsInteger(30, 45, 50)).toBeTruthy()
expect(validation.checkBoundsInteger('asdfa', 40, 50)).toBeFalsy()
expect(validation.checkBoundsInteger(-32, -128, 127)).toBeTruthy()
//Float
expect(validation.checkBoundsFloat(35.0, 25, 50.0))
expect(!validation.checkBoundsFloat(351.0, 25, 50.0))
expect(!validation.checkBoundsFloat(351.0, 355, 5650.0))
},
timeout.medium()
)
test(
'Validate types',
() => {
expect(types.isString('CHAR_STRING'))
expect(types.isString('char_string'))
expect(types.isString('OCTET_STRING'))
expect(types.isString('LONG_CHAR_STRING'))
expect(types.isString('LONG_OCTET_STRING'))
expect(!types.isString('FLOAT_SEMI'))
expect(types.isFloat('FLOAT_SEMI'))
expect(types.isFloat('FLOAT_SINGLE'))
expect(types.isFloat('FLOAT_DOUBLE'))
expect(!types.isFloat('LONG_OCTET_STRING'))
},
timeout.medium()
)
test(
'Integer Test',
async () => {
let attribute =
await queryZcl.selectAttributesByClusterCodeAndManufacturerCode(
db,
pkgId,
3,
null
)
attribute = attribute.filter((e) => {
return e.code === 0
})[0]
const { size, isSigned } = await validation.getIntegerAttributeSize(
db,
sid,
attribute.type
)
//Test Constraints
let minMax = await validation.getBoundsInteger(attribute, size, isSigned)
expect(minMax.min == 0).toBeTruthy()
expect(minMax.max === 0xffff).toBeTruthy()
},
timeout.medium()
)
test(
'validate Attribute Test',
async () => {
let fakeEndpointAttribute = {
defaultValue: '30'
}
let fakeAttribute = {
type: 'int16u',
min: '0x0010',
max: '50'
}
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeTruthy()
// Check for if attribute is out of bounds.
fakeEndpointAttribute.defaultValue = '60'
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeFalsy()
fakeEndpointAttribute.defaultValue = '5'
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeFalsy()
//Check if attribute is actually a number
fakeEndpointAttribute.defaultValue = 'xxxxxx'
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeFalsy()
fakeAttribute = {
type: 'FLOAT_SINGLE',
min: '0.5',
max: '2'
}
fakeEndpointAttribute = {
defaultValue: '1.5'
}
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeTruthy()
//Check out of bounds.
fakeEndpointAttribute = {
defaultValue: '4.5'
}
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeFalsy()
fakeEndpointAttribute = {
defaultValue: '.25'
}
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeFalsy()
//Check if attribute is actually a number
fakeEndpointAttribute.defaultValue = 'xxxxxx'
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeFalsy()
// Expect no issues with strings.
fakeAttribute = {
type: 'CHAR_STRING'
}
fakeEndpointAttribute = {
defaultValue: '30adfadf'
}
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeTruthy()
// check if handle signed numbers
let fakeEndpointAttributeValid = {
defaultValue: '549755813887'
}
let fakeEndpointAttributeInvalid = {
defaultValue: '549755813885'
}
let fakeSignedAttribute = {
type: 'int40s',
min: '0x7FFFFFFFFE',
max: '0x8000000000'
}
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttributeValid,
fakeSignedAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeTruthy()
expect(
(
await validation.validateSpecificAttribute(
fakeEndpointAttributeInvalid,
fakeSignedAttribute,
db,
sid
)
).defaultValue.length == 0
).toBeFalsy()
},
timeout.medium()
)
test('validate Attribute without min/max', async () => {
//Invalid default value
let fakeEndpointAttribute = { defaultValue: '300' }
let fakeAttribute = { type: 'int8u' }
let attributeValidation = await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
expect(attributeValidation.defaultValue.length == 1).toBeTruthy()
expect(
attributeValidation.defaultValue[0].includes('Out of range')
).toBeTruthy()
//Valid default value
fakeEndpointAttribute.defaultValue = '30'
attributeValidation = await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
expect(attributeValidation.defaultValue.length == 0).toBeTruthy()
//Invalid default value for enum16
fakeEndpointAttribute.defaultValue = '66000'
fakeAttribute.type = 'enum16'
attributeValidation = await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
expect(attributeValidation.defaultValue.length == 1).toBeTruthy()
expect(
attributeValidation.defaultValue[0].includes('Out of range')
).toBeTruthy()
//Valid default value for enum16
fakeEndpointAttribute.defaultValue = '65535'
attributeValidation = await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
expect(attributeValidation.defaultValue.length == 0).toBeTruthy()
//Invalid default value for bitmap8
fakeEndpointAttribute.defaultValue = '-2'
fakeAttribute.type = 'bitmap8'
attributeValidation = await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
expect(attributeValidation.defaultValue.length == 1).toBeTruthy()
expect(
attributeValidation.defaultValue[0].includes('Out of range')
).toBeTruthy()
//Valid default value for bitmap8
fakeEndpointAttribute.defaultValue = '255'
attributeValidation = await validation.validateSpecificAttribute(
fakeEndpointAttribute,
fakeAttribute,
db,
sid
)
expect(attributeValidation.defaultValue.length == 0).toBeTruthy()
})
test(
'validate endpoint test',
() => {
//Validate normal operation
let endpoint = {
endpointId: '1',
networkId: '0'
}
expect(
validation.validateSpecificEndpoint(endpoint).endpointId.length == 0
).toBeTruthy()
expect(
validation.validateSpecificEndpoint(endpoint).networkId.length == 0
).toBeTruthy()
//Validate not a number
endpoint = {
endpointId: 'blah',
networkId: 'blah'
}
expect(
validation.validateSpecificEndpoint(endpoint).endpointId.length == 0
).toBeFalsy()
expect(
validation.validateSpecificEndpoint(endpoint).networkId.length == 0
).toBeFalsy()
//Validate 0 not being valid Endpoint ID
endpoint = {
endpointId: '0',
networkId: 'blah'
}
expect(
validation.validateSpecificEndpoint(endpoint).endpointId.length == 0
).toBeFalsy()
//Validate out of bounds on endpointId
endpoint = {
endpointId: '0xFFFFFFFF',
networkId: 'blah'
}
expect(
validation.validateSpecificEndpoint(endpoint).endpointId.length == 0
).toBeFalsy()
},
timeout.medium()
)
describe('Validate endpoint for duplicate endpointIds', () => {
let endpointTypeIdOnOff
let endpointTypeReference
let eptId
let pkgId
beforeAll(async () => {
let ctx = await zclLoader.loadZcl(db, env.builtinSilabsZclMetafile())
pkgId = ctx.packageId
sid = await testQuery.createSession(
db,
'USER',
'SESSION',
env.builtinSilabsZclMetafile(),
env.builtinTemplateMetafile()
)
let rows = await queryDeviceType.selectAllDeviceTypes(db, pkgId)
let haOnOffDeviceTypeArray = rows.filter(
(data) => data.label === 'HA-onoff'
)
let haOnOffDeviceType = haOnOffDeviceTypeArray[0]
let deviceTypeId = haOnOffDeviceType.id
let sessionPartitionInfo =
await querySession.selectSessionPartitionInfoFromDeviceType(
db,
sid,
deviceTypeId
)
let rowId = await queryConfig.insertEndpointType(
db,
sessionPartitionInfo[0],
'testEndpointType',
deviceTypeId,
haOnOffDeviceType.code,
0,
true
)
endpointTypeIdOnOff = rowId
let endpointType = await queryEndpointType.selectEndpointType(db, rowId)
await queryEndpoint.insertEndpoint(
db,
sid,
1,
endpointType.endpointTypeId,
1,
23
)
eptId = await queryEndpoint.insertEndpoint(
db,
sid,
1,
endpointType.endpointTypeId,
1,
23
)
}, timeout.long())
test(
'Test endpoint for duplicates',
() =>
validation
.validateEndpoint(db, eptId)
.then((data) => validation.validateNoDuplicateEndpoints(db, eptId, sid))
.then((hasNoDuplicates) => {
expect(hasNoDuplicates).toBeFalsy()
}),
timeout.medium()
)
})