Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src-electron/db/query-bitmap.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ SELECT
FROM BITMAP
INNER JOIN DATA_TYPE ON
BITMAP.BITMAP_ID = DATA_TYPE.DATA_TYPE_ID
WHERE PACKAGE_REF = ? ORDER BY NAME`,
WHERE DATA_TYPE.PACKAGE_REF = ?
ORDER BY DATA_TYPE.NAME,
(SELECT MIN(COALESCE(CLUSTER.NAME, ''))
FROM DATA_TYPE_CLUSTER
INNER JOIN CLUSTER ON DATA_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE DATA_TYPE_CLUSTER.DATA_TYPE_REF = BITMAP.BITMAP_ID)`,
[packageId]
)
return rows.map(dbMapping.map.bitmap)
Expand Down
6 changes: 5 additions & 1 deletion src-electron/db/query-enum.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ INNER JOIN DATA_TYPE ON
ENUM.ENUM_ID = DATA_TYPE.DATA_TYPE_ID
WHERE
DATA_TYPE.PACKAGE_REF = ?
ORDER BY DATA_TYPE.NAME`,
ORDER BY DATA_TYPE.NAME,
(SELECT MIN(COALESCE(CLUSTER.NAME, ''))
FROM DATA_TYPE_CLUSTER
INNER JOIN CLUSTER ON DATA_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE DATA_TYPE_CLUSTER.DATA_TYPE_REF = ENUM.ENUM_ID)`,
[packageId]
)
.then((rows) => rows.map(dbMapping.map.enum))
Expand Down
8 changes: 7 additions & 1 deletion src-electron/db/query-number.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,13 @@ async function selectAllNumbers(db, packageId) {
NUMBER.SIZE AS SIZE
FROM NUMBER
INNER JOIN DATA_TYPE ON NUMBER.NUMBER_ID = DATA_TYPE.DATA_TYPE_ID
WHERE PACKAGE_REF = ?`,
WHERE
DATA_TYPE.PACKAGE_REF = ?
ORDER BY DATA_TYPE.NAME,
(SELECT MIN(COALESCE(CLUSTER.NAME, ''))
FROM DATA_TYPE_CLUSTER
INNER JOIN CLUSTER ON DATA_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE DATA_TYPE_CLUSTER.DATA_TYPE_REF = NUMBER.NUMBER_ID)`,
[packageId]
)
.then((rows) => rows.map(dbMapping.map.number))
Expand Down
8 changes: 7 additions & 1 deletion src-electron/db/query-string.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,13 @@ async function selectAllStrings(db, packageId) {
FROM STRING
INNER JOIN DATA_TYPE
ON STRING.STRING_ID = DATA_TYPE.DATA_TYPE_ID
WHERE PACKAGE_REF = ?`,
WHERE
DATA_TYPE.PACKAGE_REF = ?
ORDER BY DATA_TYPE.NAME,
(SELECT MIN(COALESCE(CLUSTER.NAME, ''))
FROM DATA_TYPE_CLUSTER
INNER JOIN CLUSTER ON DATA_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE DATA_TYPE_CLUSTER.DATA_TYPE_REF = STRING.STRING_ID)`,
[packageId]
)
.then((rows) => rows.map(dbMapping.map.string))
Expand Down
9 changes: 6 additions & 3 deletions src-electron/db/query-struct.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ async function selectAllStructs(db, packageId) {
ON
STRUCT.STRUCT_ID = DATA_TYPE.DATA_TYPE_ID
WHERE
PACKAGE_REF = ?
ORDER BY
NAME`,
DATA_TYPE.PACKAGE_REF = ?
ORDER BY DATA_TYPE.NAME,
(SELECT MIN(COALESCE(CLUSTER.NAME, ''))
FROM DATA_TYPE_CLUSTER
INNER JOIN CLUSTER ON DATA_TYPE_CLUSTER.CLUSTER_REF = CLUSTER.CLUSTER_ID
WHERE DATA_TYPE_CLUSTER.DATA_TYPE_REF = STRUCT.STRUCT_ID)`,
[packageId]
)
return rows.map(dbMapping.map.struct)
Expand Down
127 changes: 127 additions & 0 deletions test/zcl-loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,130 @@ test(
},
testUtil.timeout.long()
)

test(
'test enum deduplication: same enum shared across clusters should appear only once',
async () => {
let db = await dbApi.initRamDatabase()
try {
await dbApi.loadSchema(db, env.schemaFile(), env.zapVersion())
let ctx = await zclLoader.loadZcl(db, env.builtinMatterZclMetafile())
let packageId = ctx.packageId

// Test with actual Matter data - StatusEnum is shared across multiple clusters
let allEnums = await queryZcl.selectAllEnums(db, packageId)
let statusEnums = allEnums.filter((e) => e.name === 'TestSameStatusEnum')

// Should have only one StatusEnum despite being used in multiple clusters
expect(statusEnums.length).toBe(1)

// Verify it has multiple cluster associations
expect(statusEnums[0].enumClusterCount).toBeGreaterThan(1)

// Verify the enum is actually shared by checking cluster associations
let enumClusters = await queryZcl.selectEnumClusters(
db,
statusEnums[0].id
)
expect(enumClusters.length).toBeGreaterThan(1)
} finally {
await dbApi.closeDatabase(db)
}
},
testUtil.timeout.medium()
)

test(
'test enum distinction: different enums with same name in different clusters should appear separately',
async () => {
let db = await dbApi.initRamDatabase()
try {
await dbApi.loadSchema(db, env.schemaFile(), env.zapVersion())
let ctx = await zclLoader.loadZcl(db, env.builtinMatterZclMetafile())
let packageId = ctx.packageId

// Test: selectAllEnums should return both enums separately
let allEnums = await queryZcl.selectAllEnums(db, packageId)
let testStatusEnums = allEnums.filter((e) => e.name === 'TestStatusEnum')

expect(testStatusEnums.length).toBe(2) // Should appear separately
expect(testStatusEnums[0].id).not.toBe(testStatusEnums[1].id) // Different ENUM_IDs
expect(testStatusEnums[0].enumClusterCount).toBe(1) // Each associated with 1 cluster
expect(testStatusEnums[1].enumClusterCount).toBe(1)

// Verify the enums have different items by checking via enum items
let enum1Items = await queryZcl.selectAllEnumItemsById(
db,
testStatusEnums[0].id
)
let enum2Items = await queryZcl.selectAllEnumItemsById(
db,
testStatusEnums[1].id
)

// One enum has 2 items, other has 3 items - proves they're different
let itemCounts = [enum1Items.length, enum2Items.length].sort()
expect(itemCounts).toEqual([2, 3])
} finally {
await dbApi.closeDatabase(db)
}
},
testUtil.timeout.medium()
)

test(
'test enum ordering determinism: selectAllEnums should return enums in consistent order',
async () => {
let db = await dbApi.initRamDatabase()
try {
await dbApi.loadSchema(db, env.schemaFile(), env.zapVersion())
let ctx = await zclLoader.loadZcl(db, env.builtinMatterZclMetafile())
let packageId = ctx.packageId

// Call selectAllEnums once
let allEnums = await queryZcl.selectAllEnums(db, packageId)

// Get all TestStatusEnum instances
let testStatusEnums = allEnums.filter((e) => e.name === 'TestStatusEnum')

if (testStatusEnums.length > 1) {
// Find Administrator Commissioning and Application Basic cluster enums
let adminCommEnum = null
let appBasicEnum = null

for (let testEnum of testStatusEnums) {
let enumClusters = await queryZcl.selectEnumClusters(db, testEnum.id)
if (enumClusters.some((c) => c.code === 0x003c)) {
// Administrator Commissioning
adminCommEnum = testEnum
}
if (enumClusters.some((c) => c.code === 0x050d)) {
// Application Basic
appBasicEnum = testEnum
}
}

if (adminCommEnum && appBasicEnum) {
let adminPosition = allEnums.indexOf(adminCommEnum)
let appBasicPosition = allEnums.indexOf(appBasicEnum)

// Administrator Commissioning TestStatusEnum should always appear before Application Basic TestStatusEnum
expect(adminPosition).toBeLessThan(appBasicPosition)
}
}

// Get all TestStatusEnumAcrossClusters instances
let TestStatusEnumAcrossClusters = allEnums.filter(
(e) => e.name === 'TestStatusEnumAcrossClusters'
)
// Making sure selectAllEnums is returning the enums appropriately ordered by enum name and cluster name
expect(TestStatusEnumAcrossClusters.length).toBe(3)
expect(TestStatusEnumAcrossClusters[0].enumClusterCount).toBe(0) // TestStatusEnumAcrossClusters defined in actions-cluster.xml
expect(TestStatusEnumAcrossClusters[1].enumClusterCount).toBe(2) // TestStatusEnumAcrossClusters defined in administrator-commissioning-cluster.xml
expect(TestStatusEnumAcrossClusters[2].enumClusterCount).toBe(3) // TestStatusEnumAcrossClusters defined in application-basic-cluster.xml
} finally {
await dbApi.closeDatabase(db)
}
},
testUtil.timeout.medium()
)
3 changes: 3 additions & 0 deletions zcl-builtin/matter/data-model/chip/actions-cluster.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ limitations under the License.
<item value="1" name="room"/>
<item value="2" name="zone"/>
</enum>
<enum name="TestStatusEnumAcrossClusters" type="ENUM8">
<item name="TestStatusEnumItem1" value="0x02"/>
</enum>

<struct name="ActionStruct">
<cluster code="0x0025"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,23 @@ limitations under the License.
<item name="EnhancedWindowOpen" value="0x01"/>
<item name="BasicWindowOpen" value="0x02"/>
</enum>
<enum name="TestStatusEnum" type="ENUM8">
<cluster code="0x003c"/>
<item name="TestStatusEnumItem1" value="0x00"/>
<item name="TestStatusEnumItem2" value="0x01"/>
</enum>
<enum name="TestSameStatusEnum" type="ENUM8">
<cluster code="0x003c"/>
<cluster code="0x050d"/>
<item name="TestStatusEnumItem1" value="0x00"/>
<item name="TestStatusEnumItem2" value="0x01"/>
</enum>
<enum name="TestStatusEnumAcrossClusters" type="ENUM8">
<cluster code="0x003c"/>
<cluster code="0x0025"/>
<item name="TestStatusEnumItem1" value="0x00"/>
<item name="TestStatusEnumItem2" value="0x01"/>
</enum>

<cluster>
<name>Administrator Commissioning</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,17 @@ limitations under the License.
<item name="ActiveHidden" value="0x02"/>
<item name="ActiveVisibleNotFocus" value="0x03"/>
</enum>
<enum name="TestStatusEnum" type="ENUM8">
<cluster code="0x050d"/>
<item name="TestStatusEnumItem3" value="0x00"/>
<item name="TestStatusEnumItem4" value="0x01"/>
<item name="TestStatusEnumItem5" value="0x02"/>
</enum>
<enum name="TestStatusEnumAcrossClusters" type="ENUM8">
<cluster code="0x050c"/>
<cluster code="0x050d"/>
<cluster code="0x050b"/>
<item name="TestStatusEnumItem1" value="0x00"/>
<item name="TestStatusEnumItem2" value="0x01"/>
</enum>
</configurator>