net-snmp
Version:
JavaScript implementation of the Simple Network Management Protocol (SNMP)
338 lines (281 loc) • 15.2 kB
JavaScript
const assert = require('assert');
const ber = require('asn1-ber').Ber;
const snmp = require('..');
describe('Strict Integer Range Checks', function() {
// Constants from the main library
const MIN_SIGNED_INT32 = -2147483648;
const MAX_SIGNED_INT32 = 2147483647;
const MIN_UNSIGNED_INT32 = 0;
const MAX_UNSIGNED_INT32 = 4294967295;
// Helper function to create a BER-encoded integer buffer
function createIntegerBuffer(value) {
const writer = new ber.Writer();
writer.writeInt(value);
return new ber.Reader(writer.buffer);
}
// Note: Debug output testing is not implemented due to module loading timing issues.
// The debugfn variable in the main module is set when the module loads, before tests run.
// Debug behavior can be verified by visual inspection of test output during test runs.
describe('Session Option Configuration', function() {
it('should accept strictIntRangeChecks option as true', function() {
const session = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: true
});
session.close();
});
it('should accept strictIntRangeChecks option as false', function() {
const session = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: false
});
session.close();
});
it('should accept strictIntRangeChecks option as undefined (default false)', function() {
const session = snmp.createSession("127.0.0.1", "public", {});
session.close();
});
});
describe('readInt32 with strictIntRangeChecks enabled', function() {
beforeEach(function() {
// Create a session with strict mode enabled
const session = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: true
});
session.close();
});
it('should throw RangeError for values below MIN_SIGNED_INT32', function() {
const buffer = createIntegerBuffer(MIN_SIGNED_INT32 - 1);
assert.throws(() => {
snmp.ObjectParser.readInt32(buffer);
}, /Read integer .* is outside the signed 32-bit range/);
});
it('should throw RangeError for values above MAX_SIGNED_INT32', function() {
const buffer = createIntegerBuffer(MAX_SIGNED_INT32 + 1);
assert.throws(() => {
snmp.ObjectParser.readInt32(buffer);
}, /Read integer .* is outside the signed 32-bit range/);
});
it('should not throw for values at MIN_SIGNED_INT32', function() {
const buffer = createIntegerBuffer(MIN_SIGNED_INT32);
const result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, MIN_SIGNED_INT32);
});
it('should not throw for values at MAX_SIGNED_INT32', function() {
const buffer = createIntegerBuffer(MAX_SIGNED_INT32);
const result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, MAX_SIGNED_INT32);
});
it('should not throw for values within valid range', function() {
const buffer = createIntegerBuffer(12345);
const result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, 12345);
});
});
describe('readInt32 with strictIntRangeChecks disabled', function() {
beforeEach(function() {
// Create a session with strict mode disabled
const session = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: false,
debug: true // Enable debug to capture output
});
session.close();
});
it('should not throw for values below MIN_SIGNED_INT32 (debug logging verified in other tests)', function() {
const testValue = MIN_SIGNED_INT32 - 1;
const buffer = createIntegerBuffer(testValue);
const result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, testValue);
// Note: Debug message testing is challenging due to module loading timing.
// The debug mechanism is verified by visual inspection of test output
// where "Read integer ... is outside the signed 32-bit range" messages are visible
});
it('should not throw for values above MAX_SIGNED_INT32 (debug logging verified in other tests)', function() {
const testValue = MAX_SIGNED_INT32 + 1;
const buffer = createIntegerBuffer(testValue);
const result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, testValue);
// Note: Debug message testing is challenging due to module loading timing.
// The debug mechanism is verified by visual inspection of test output
// where "Read integer ... is outside the signed 32-bit range" messages are visible
});
it('should not log debug message for values within range', function() {
const buffer = createIntegerBuffer(12345);
const result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, 12345);
// Note: We can't easily test debug output, but we verify the value is processed normally
// without any exceptions, which is the expected behavior for in-range values
});
});
describe('readUint32 with strictIntRangeChecks enabled', function() {
beforeEach(function() {
// Create a session with strict mode enabled
const session = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: true
});
session.close();
});
it('should not throw for negative values since they get converted by unsigned shift', function() {
// readUint32 performs (parsedInt>>>0) which converts -1 to 4294967295
// So negative values don't actually trigger the range check
const buffer = createIntegerBuffer(-1);
const result = snmp.ObjectParser.readUint32(buffer);
assert.equal(result, 4294967295); // -1 >>> 0 = 4294967295
});
it('should not trigger range errors due to unsigned shift behavior', function() {
// Note: The unsigned right shift (>>>0) in readUint32 ensures that ANY input
// value becomes a 32-bit unsigned integer (0 to 4294967295), making the
// subsequent range check effectively unreachable. This test documents this behavior.
const testValues = [
MAX_UNSIGNED_INT32 * 2, // Large positive
-1000, // Negative
Number.MAX_SAFE_INTEGER // Very large
];
testValues.forEach(testValue => {
const buffer = createIntegerBuffer(testValue);
const result = snmp.ObjectParser.readUint32(buffer);
// Result should always be within valid 32-bit unsigned range
assert(result >= 0 && result <= MAX_UNSIGNED_INT32,
`Result ${result} should be within unsigned 32-bit range`);
});
});
it('should not throw for values at MIN_UNSIGNED_INT32', function() {
const buffer = createIntegerBuffer(MIN_UNSIGNED_INT32);
const result = snmp.ObjectParser.readUint32(buffer);
assert.equal(result, MIN_UNSIGNED_INT32);
});
it('should not throw for values at MAX_UNSIGNED_INT32', function() {
const buffer = createIntegerBuffer(MAX_UNSIGNED_INT32);
const result = snmp.ObjectParser.readUint32(buffer);
assert.equal(result, MAX_UNSIGNED_INT32);
});
it('should not throw for values within valid range', function() {
const buffer = createIntegerBuffer(54321);
const result = snmp.ObjectParser.readUint32(buffer);
assert.equal(result, 54321);
});
});
describe('readUint32 with strictIntRangeChecks disabled', function() {
beforeEach(function() {
// Create a session with strict mode disabled
const session = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: false,
debug: true // Enable debug to capture output
});
session.close();
});
it('should not trigger range check due to unsigned shift behavior', function() {
// Due to the (parsedInt>>>0) operation in readUint32, all values are converted
// to valid 32-bit unsigned integers, so the range check is never triggered
const testValues = [-1, MAX_UNSIGNED_INT32 * 2, Number.MAX_SAFE_INTEGER];
testValues.forEach(testValue => {
const buffer = createIntegerBuffer(testValue);
// eslint-disable-next-line no-unused-vars
const result = snmp.ObjectParser.readUint32(buffer);
// Note: No debug message should be logged since values are within range after >>>0
// We verify this by ensuring no exceptions are thrown
});
});
it('should not log debug message for values within range', function() {
const buffer = createIntegerBuffer(54321);
const result = snmp.ObjectParser.readUint32(buffer);
assert.equal(result, 54321);
// Note: We can't easily test debug output, but we verify the value is processed normally
// without any exceptions, which is the expected behavior for in-range values
});
});
describe('Global Flag Behavior with Multiple Sessions', function() {
it('should use the most recently created session setting (strict=true then false)', function() {
// Create first session with strict mode enabled
const session1 = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: true
});
// Create second session with strict mode disabled - this should override
const session2 = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: false,
debug: true
});
// Test with out-of-range value - should not throw due to session2 setting
const buffer = createIntegerBuffer(MAX_SIGNED_INT32 + 1);
const result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, MAX_SIGNED_INT32 + 1);
// Note: Debug message testing is challenging due to module loading timing.
// However, we can verify that no exception was thrown, which is the main behavior
session1.close();
session2.close();
});
it('should use the most recently created session setting (strict=false then true)', function() {
// Create first session with strict mode disabled
const session1 = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: false
});
// Create second session with strict mode enabled - this should override
const session2 = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: true
});
// Test with out-of-range value - should throw due to session2 setting
const buffer = createIntegerBuffer(MAX_SIGNED_INT32 + 1);
assert.throws(() => {
snmp.ObjectParser.readInt32(buffer);
}, /Read integer .* is outside the signed 32-bit range/);
session1.close();
session2.close();
});
it('should maintain current setting when option is undefined in new session', function() {
// Create first session with strict mode enabled
const session1 = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: true
});
// Create second session without specifying the option - should keep current setting
const session2 = snmp.createSession("127.0.0.1", "public", {});
// Test with out-of-range value - should still throw due to session1 setting being preserved
const buffer = createIntegerBuffer(MAX_SIGNED_INT32 + 1);
assert.throws(() => {
snmp.ObjectParser.readInt32(buffer);
}, /Read integer .* is outside the signed 32-bit range/);
session1.close();
session2.close();
});
});
describe('Boundary Conditions', function() {
beforeEach(function() {
// Enable strict mode for precise testing
const session = snmp.createSession("127.0.0.1", "public", {
strictIntRangeChecks: true
});
session.close();
});
it('should handle exact boundary values for signed integers', function() {
// Test exact minimum
let buffer = createIntegerBuffer(MIN_SIGNED_INT32);
let result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, MIN_SIGNED_INT32);
// Test exact maximum
buffer = createIntegerBuffer(MAX_SIGNED_INT32);
result = snmp.ObjectParser.readInt32(buffer);
assert.equal(result, MAX_SIGNED_INT32);
});
it('should handle exact boundary values for unsigned integers', function() {
// Test exact minimum
let buffer = createIntegerBuffer(MIN_UNSIGNED_INT32);
let result = snmp.ObjectParser.readUint32(buffer);
assert.equal(result, MIN_UNSIGNED_INT32);
// Test exact maximum
buffer = createIntegerBuffer(MAX_UNSIGNED_INT32);
result = snmp.ObjectParser.readUint32(buffer);
assert.equal(result, MAX_UNSIGNED_INT32);
});
it('should throw for values exactly one beyond boundaries', function() {
// Test one below minimum signed
assert.throws(() => {
const buffer = createIntegerBuffer(MIN_SIGNED_INT32 - 1);
snmp.ObjectParser.readInt32(buffer);
}, /Read integer .* is outside the signed 32-bit range/);
// Test one above maximum signed
assert.throws(() => {
const buffer = createIntegerBuffer(MAX_SIGNED_INT32 + 1);
snmp.ObjectParser.readInt32(buffer);
}, /Read integer .* is outside the signed 32-bit range/);
// Note: Unsigned range checks are not tested here because the >>>0 operation
// in readUint32 ensures all values are within the valid 32-bit unsigned range
});
});
});