mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
🧪 test: add focused unit tests for permissionBitSupersets
The helper is the single point of correctness for every ACL read path
(every query uses `permBits: { $in: permissionBitSupersets(X) }`), so it
warrants direct coverage independent of the higher-level parity and
behavior specs. Six cases added:
* `requiredBits=0` returns all 16 values
* `requiredBits=15` returns `[15]` only
* every returned value is a bitwise superset of `requiredBits`
* full parity against the `$bitsAllSet` definition for every
`required` in 0..15
* memoization: repeat calls return the same frozen reference
* frozen result throws `TypeError` on mutation attempts
Refs #12729.
This commit is contained in:
parent
754ade8e0e
commit
114559bce1
1 changed files with 75 additions and 1 deletions
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from 'librechat-data-provider';
|
||||
import { MongoMemoryServer } from 'mongodb-memory-server';
|
||||
import type * as t from '~/types';
|
||||
import { createAclEntryMethods } from './aclEntry';
|
||||
import { createAclEntryMethods, permissionBitSupersets } from './aclEntry';
|
||||
import aclEntrySchema from '~/schema/aclEntry';
|
||||
|
||||
let mongoServer: MongoMemoryServer;
|
||||
|
|
@ -1541,4 +1541,78 @@ describe('AclEntry Model Tests', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Focused unit tests for the `permissionBitSupersets` helper. The helper is
|
||||
* the single point of correctness for every ACL read path (every query uses
|
||||
* `permBits: { $in: permissionBitSupersets(X) }`), so it warrants direct
|
||||
* coverage independent of the higher-level parity and behavior specs.
|
||||
*/
|
||||
describe('permissionBitSupersets', () => {
|
||||
test('requiredBits=0 matches every permBits value in [0, 15]', () => {
|
||||
const result = permissionBitSupersets(0);
|
||||
expect(result).toHaveLength(16);
|
||||
expect([...result].sort((a, b) => a - b)).toEqual([
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
]);
|
||||
});
|
||||
|
||||
test('requiredBits=15 (all four bits) matches only [15]', () => {
|
||||
const result = permissionBitSupersets(
|
||||
PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE,
|
||||
);
|
||||
expect([...result]).toEqual([15]);
|
||||
});
|
||||
|
||||
test('every returned value is a bitwise superset of requiredBits', () => {
|
||||
for (const required of [
|
||||
PermissionBits.VIEW,
|
||||
PermissionBits.EDIT,
|
||||
PermissionBits.DELETE,
|
||||
PermissionBits.SHARE,
|
||||
PermissionBits.VIEW | PermissionBits.EDIT,
|
||||
PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE,
|
||||
]) {
|
||||
const result = permissionBitSupersets(required);
|
||||
for (const v of result) {
|
||||
expect((v & required) === required).toBe(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('returns exactly the values satisfying $bitsAllSet semantics', () => {
|
||||
/**
|
||||
* Parity check against the literal definition: for every required mask,
|
||||
* the returned set must equal the set of all v in [0,15] whose bits
|
||||
* include `required`.
|
||||
*/
|
||||
for (let required = 0; required <= 15; required++) {
|
||||
const expected: number[] = [];
|
||||
for (let v = 0; v <= 15; v++) {
|
||||
if ((v & required) === required) {
|
||||
expected.push(v);
|
||||
}
|
||||
}
|
||||
expect([...permissionBitSupersets(required)].sort((a, b) => a - b)).toEqual(expected);
|
||||
}
|
||||
});
|
||||
|
||||
test('memoizes: repeat calls return the same frozen reference', () => {
|
||||
const first = permissionBitSupersets(PermissionBits.SHARE);
|
||||
const second = permissionBitSupersets(PermissionBits.SHARE);
|
||||
expect(second).toBe(first);
|
||||
expect(Object.isFrozen(first)).toBe(true);
|
||||
});
|
||||
|
||||
test('frozen result throws on mutation attempts in strict mode', () => {
|
||||
const result = permissionBitSupersets(PermissionBits.VIEW);
|
||||
/**
|
||||
* `Object.freeze` in strict mode (TypeScript compiles to strict) causes
|
||||
* mutation attempts to throw rather than silently corrupt the cache.
|
||||
*/
|
||||
expect(() => {
|
||||
(result as number[]).push(99);
|
||||
}).toThrow(TypeError);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue